blob: c1a32f3c2736bd60556576c99301f5a2a658151c [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 Moolenaar73dad1e2016-07-17 22:13:49 +020034
35#ifdef FEAT_FLOAT
36static void f_abs(typval_T *argvars, typval_T *rettv);
37static void f_acos(typval_T *argvars, typval_T *rettv);
38#endif
39static void f_add(typval_T *argvars, typval_T *rettv);
40static void f_and(typval_T *argvars, typval_T *rettv);
41static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020042static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020043static void f_argc(typval_T *argvars, typval_T *rettv);
44static void f_argidx(typval_T *argvars, typval_T *rettv);
45static void f_arglistid(typval_T *argvars, typval_T *rettv);
46static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010047static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010049static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_assert_exception(typval_T *argvars, typval_T *rettv);
51static void f_assert_fails(typval_T *argvars, typval_T *rettv);
52static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020053static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_assert_match(typval_T *argvars, typval_T *rettv);
55static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
56static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010057static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020058static void f_assert_true(typval_T *argvars, typval_T *rettv);
59#ifdef FEAT_FLOAT
60static void f_asin(typval_T *argvars, typval_T *rettv);
61static void f_atan(typval_T *argvars, typval_T *rettv);
62static void f_atan2(typval_T *argvars, typval_T *rettv);
63#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010064#ifdef FEAT_BEVAL
65static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010066# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010067static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010068# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010069#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_browse(typval_T *argvars, typval_T *rettv);
71static void f_browsedir(typval_T *argvars, typval_T *rettv);
72static void f_bufexists(typval_T *argvars, typval_T *rettv);
73static void f_buflisted(typval_T *argvars, typval_T *rettv);
74static void f_bufloaded(typval_T *argvars, typval_T *rettv);
75static void f_bufname(typval_T *argvars, typval_T *rettv);
76static void f_bufnr(typval_T *argvars, typval_T *rettv);
77static void f_bufwinid(typval_T *argvars, typval_T *rettv);
78static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
79static void f_byte2line(typval_T *argvars, typval_T *rettv);
80static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
81static void f_byteidx(typval_T *argvars, typval_T *rettv);
82static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
83static void f_call(typval_T *argvars, typval_T *rettv);
84#ifdef FEAT_FLOAT
85static void f_ceil(typval_T *argvars, typval_T *rettv);
86#endif
87#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010088static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020090static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
92static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
93static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
94static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
95static void f_ch_info(typval_T *argvars, typval_T *rettv);
96static void f_ch_log(typval_T *argvars, typval_T *rettv);
97static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
98static void f_ch_open(typval_T *argvars, typval_T *rettv);
99static void f_ch_read(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100100static void f_ch_readblob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
102static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
103static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
104static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
105static void f_ch_status(typval_T *argvars, typval_T *rettv);
106#endif
107static void f_changenr(typval_T *argvars, typval_T *rettv);
108static void f_char2nr(typval_T *argvars, typval_T *rettv);
109static void f_cindent(typval_T *argvars, typval_T *rettv);
110static void f_clearmatches(typval_T *argvars, typval_T *rettv);
111static void f_col(typval_T *argvars, typval_T *rettv);
112#if defined(FEAT_INS_EXPAND)
113static void f_complete(typval_T *argvars, typval_T *rettv);
114static void f_complete_add(typval_T *argvars, typval_T *rettv);
115static void f_complete_check(typval_T *argvars, typval_T *rettv);
116#endif
117static void f_confirm(typval_T *argvars, typval_T *rettv);
118static void f_copy(typval_T *argvars, typval_T *rettv);
119#ifdef FEAT_FLOAT
120static void f_cos(typval_T *argvars, typval_T *rettv);
121static void f_cosh(typval_T *argvars, typval_T *rettv);
122#endif
123static void f_count(typval_T *argvars, typval_T *rettv);
124static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
125static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100126#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200127static void f_debugbreak(typval_T *argvars, typval_T *rettv);
128#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_deepcopy(typval_T *argvars, typval_T *rettv);
130static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200131static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_did_filetype(typval_T *argvars, typval_T *rettv);
133static void f_diff_filler(typval_T *argvars, typval_T *rettv);
134static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
135static void f_empty(typval_T *argvars, typval_T *rettv);
136static void f_escape(typval_T *argvars, typval_T *rettv);
137static void f_eval(typval_T *argvars, typval_T *rettv);
138static void f_eventhandler(typval_T *argvars, typval_T *rettv);
139static void f_executable(typval_T *argvars, typval_T *rettv);
140static void f_execute(typval_T *argvars, typval_T *rettv);
141static void f_exepath(typval_T *argvars, typval_T *rettv);
142static void f_exists(typval_T *argvars, typval_T *rettv);
143#ifdef FEAT_FLOAT
144static void f_exp(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_expand(typval_T *argvars, typval_T *rettv);
147static void f_extend(typval_T *argvars, typval_T *rettv);
148static void f_feedkeys(typval_T *argvars, typval_T *rettv);
149static void f_filereadable(typval_T *argvars, typval_T *rettv);
150static void f_filewritable(typval_T *argvars, typval_T *rettv);
151static void f_filter(typval_T *argvars, typval_T *rettv);
152static void f_finddir(typval_T *argvars, typval_T *rettv);
153static void f_findfile(typval_T *argvars, typval_T *rettv);
154#ifdef FEAT_FLOAT
155static void f_float2nr(typval_T *argvars, typval_T *rettv);
156static void f_floor(typval_T *argvars, typval_T *rettv);
157static void f_fmod(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_fnameescape(typval_T *argvars, typval_T *rettv);
160static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
161static void f_foldclosed(typval_T *argvars, typval_T *rettv);
162static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
163static void f_foldlevel(typval_T *argvars, typval_T *rettv);
164static void f_foldtext(typval_T *argvars, typval_T *rettv);
165static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
166static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200167static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_function(typval_T *argvars, typval_T *rettv);
169static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
170static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200171static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_getbufline(typval_T *argvars, typval_T *rettv);
173static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100174static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_getchar(typval_T *argvars, typval_T *rettv);
176static void f_getcharmod(typval_T *argvars, typval_T *rettv);
177static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
178static void f_getcmdline(typval_T *argvars, typval_T *rettv);
179#if defined(FEAT_CMDL_COMPL)
180static void f_getcompletion(typval_T *argvars, typval_T *rettv);
181#endif
182static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
183static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
184static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
185static void f_getcwd(typval_T *argvars, typval_T *rettv);
186static void f_getfontname(typval_T *argvars, typval_T *rettv);
187static void f_getfperm(typval_T *argvars, typval_T *rettv);
188static void f_getfsize(typval_T *argvars, typval_T *rettv);
189static void f_getftime(typval_T *argvars, typval_T *rettv);
190static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100191static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200193static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getmatches(typval_T *argvars, typval_T *rettv);
195static void f_getpid(typval_T *argvars, typval_T *rettv);
196static void f_getcurpos(typval_T *argvars, typval_T *rettv);
197static void f_getpos(typval_T *argvars, typval_T *rettv);
198static void f_getqflist(typval_T *argvars, typval_T *rettv);
199static void f_getreg(typval_T *argvars, typval_T *rettv);
200static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200201static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_gettabvar(typval_T *argvars, typval_T *rettv);
203static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100204static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200205static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100206static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_getwinposx(typval_T *argvars, typval_T *rettv);
208static void f_getwinposy(typval_T *argvars, typval_T *rettv);
209static void f_getwinvar(typval_T *argvars, typval_T *rettv);
210static void f_glob(typval_T *argvars, typval_T *rettv);
211static void f_globpath(typval_T *argvars, typval_T *rettv);
212static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
213static void f_has(typval_T *argvars, typval_T *rettv);
214static void f_has_key(typval_T *argvars, typval_T *rettv);
215static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
216static void f_hasmapto(typval_T *argvars, typval_T *rettv);
217static void f_histadd(typval_T *argvars, typval_T *rettv);
218static void f_histdel(typval_T *argvars, typval_T *rettv);
219static void f_histget(typval_T *argvars, typval_T *rettv);
220static void f_histnr(typval_T *argvars, typval_T *rettv);
221static void f_hlID(typval_T *argvars, typval_T *rettv);
222static void f_hlexists(typval_T *argvars, typval_T *rettv);
223static void f_hostname(typval_T *argvars, typval_T *rettv);
224static void f_iconv(typval_T *argvars, typval_T *rettv);
225static void f_indent(typval_T *argvars, typval_T *rettv);
226static void f_index(typval_T *argvars, typval_T *rettv);
227static void f_input(typval_T *argvars, typval_T *rettv);
228static void f_inputdialog(typval_T *argvars, typval_T *rettv);
229static void f_inputlist(typval_T *argvars, typval_T *rettv);
230static void f_inputrestore(typval_T *argvars, typval_T *rettv);
231static void f_inputsave(typval_T *argvars, typval_T *rettv);
232static void f_inputsecret(typval_T *argvars, typval_T *rettv);
233static void f_insert(typval_T *argvars, typval_T *rettv);
234static void f_invert(typval_T *argvars, typval_T *rettv);
235static void f_isdirectory(typval_T *argvars, typval_T *rettv);
236static void f_islocked(typval_T *argvars, typval_T *rettv);
237#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
238static void f_isnan(typval_T *argvars, typval_T *rettv);
239#endif
240static void f_items(typval_T *argvars, typval_T *rettv);
241#ifdef FEAT_JOB_CHANNEL
242static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
243static void f_job_info(typval_T *argvars, typval_T *rettv);
244static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
245static void f_job_start(typval_T *argvars, typval_T *rettv);
246static void f_job_stop(typval_T *argvars, typval_T *rettv);
247static void f_job_status(typval_T *argvars, typval_T *rettv);
248#endif
249static void f_join(typval_T *argvars, typval_T *rettv);
250static void f_js_decode(typval_T *argvars, typval_T *rettv);
251static void f_js_encode(typval_T *argvars, typval_T *rettv);
252static void f_json_decode(typval_T *argvars, typval_T *rettv);
253static void f_json_encode(typval_T *argvars, typval_T *rettv);
254static void f_keys(typval_T *argvars, typval_T *rettv);
255static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
256static void f_len(typval_T *argvars, typval_T *rettv);
257static void f_libcall(typval_T *argvars, typval_T *rettv);
258static void f_libcallnr(typval_T *argvars, typval_T *rettv);
259static void f_line(typval_T *argvars, typval_T *rettv);
260static void f_line2byte(typval_T *argvars, typval_T *rettv);
261static void f_lispindent(typval_T *argvars, typval_T *rettv);
262static void f_localtime(typval_T *argvars, typval_T *rettv);
263#ifdef FEAT_FLOAT
264static void f_log(typval_T *argvars, typval_T *rettv);
265static void f_log10(typval_T *argvars, typval_T *rettv);
266#endif
267#ifdef FEAT_LUA
268static void f_luaeval(typval_T *argvars, typval_T *rettv);
269#endif
270static void f_map(typval_T *argvars, typval_T *rettv);
271static void f_maparg(typval_T *argvars, typval_T *rettv);
272static void f_mapcheck(typval_T *argvars, typval_T *rettv);
273static void f_match(typval_T *argvars, typval_T *rettv);
274static void f_matchadd(typval_T *argvars, typval_T *rettv);
275static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
276static void f_matcharg(typval_T *argvars, typval_T *rettv);
277static void f_matchdelete(typval_T *argvars, typval_T *rettv);
278static void f_matchend(typval_T *argvars, typval_T *rettv);
279static void f_matchlist(typval_T *argvars, typval_T *rettv);
280static void f_matchstr(typval_T *argvars, typval_T *rettv);
281static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
282static void f_max(typval_T *argvars, typval_T *rettv);
283static void f_min(typval_T *argvars, typval_T *rettv);
284#ifdef vim_mkdir
285static void f_mkdir(typval_T *argvars, typval_T *rettv);
286#endif
287static void f_mode(typval_T *argvars, typval_T *rettv);
288#ifdef FEAT_MZSCHEME
289static void f_mzeval(typval_T *argvars, typval_T *rettv);
290#endif
291static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
292static void f_nr2char(typval_T *argvars, typval_T *rettv);
293static void f_or(typval_T *argvars, typval_T *rettv);
294static void f_pathshorten(typval_T *argvars, typval_T *rettv);
295#ifdef FEAT_PERL
296static void f_perleval(typval_T *argvars, typval_T *rettv);
297#endif
298#ifdef FEAT_FLOAT
299static void f_pow(typval_T *argvars, typval_T *rettv);
300#endif
301static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
302static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200303#ifdef FEAT_JOB_CHANNEL
304static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200305static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200306static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
307#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200308static void f_pumvisible(typval_T *argvars, typval_T *rettv);
309#ifdef FEAT_PYTHON3
310static void f_py3eval(typval_T *argvars, typval_T *rettv);
311#endif
312#ifdef FEAT_PYTHON
313static void f_pyeval(typval_T *argvars, typval_T *rettv);
314#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100315#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
316static void f_pyxeval(typval_T *argvars, typval_T *rettv);
317#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200318static void f_range(typval_T *argvars, typval_T *rettv);
319static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200320static void f_reg_executing(typval_T *argvars, typval_T *rettv);
321static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200322static void f_reltime(typval_T *argvars, typval_T *rettv);
323#ifdef FEAT_FLOAT
324static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
325#endif
326static void f_reltimestr(typval_T *argvars, typval_T *rettv);
327static void f_remote_expr(typval_T *argvars, typval_T *rettv);
328static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
329static void f_remote_peek(typval_T *argvars, typval_T *rettv);
330static void f_remote_read(typval_T *argvars, typval_T *rettv);
331static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100332static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200333static void f_remove(typval_T *argvars, typval_T *rettv);
334static void f_rename(typval_T *argvars, typval_T *rettv);
335static void f_repeat(typval_T *argvars, typval_T *rettv);
336static void f_resolve(typval_T *argvars, typval_T *rettv);
337static void f_reverse(typval_T *argvars, typval_T *rettv);
338#ifdef FEAT_FLOAT
339static void f_round(typval_T *argvars, typval_T *rettv);
340#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100341#ifdef FEAT_RUBY
342static void f_rubyeval(typval_T *argvars, typval_T *rettv);
343#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200344static void f_screenattr(typval_T *argvars, typval_T *rettv);
345static void f_screenchar(typval_T *argvars, typval_T *rettv);
346static void f_screencol(typval_T *argvars, typval_T *rettv);
347static void f_screenrow(typval_T *argvars, typval_T *rettv);
348static void f_search(typval_T *argvars, typval_T *rettv);
349static void f_searchdecl(typval_T *argvars, typval_T *rettv);
350static void f_searchpair(typval_T *argvars, typval_T *rettv);
351static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
352static void f_searchpos(typval_T *argvars, typval_T *rettv);
353static void f_server2client(typval_T *argvars, typval_T *rettv);
354static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200355static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200356static void f_setbufvar(typval_T *argvars, typval_T *rettv);
357static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
358static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
359static void f_setfperm(typval_T *argvars, typval_T *rettv);
360static void f_setline(typval_T *argvars, typval_T *rettv);
361static void f_setloclist(typval_T *argvars, typval_T *rettv);
362static void f_setmatches(typval_T *argvars, typval_T *rettv);
363static void f_setpos(typval_T *argvars, typval_T *rettv);
364static void f_setqflist(typval_T *argvars, typval_T *rettv);
365static void f_setreg(typval_T *argvars, typval_T *rettv);
366static void f_settabvar(typval_T *argvars, typval_T *rettv);
367static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100368static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200369static void f_setwinvar(typval_T *argvars, typval_T *rettv);
370#ifdef FEAT_CRYPT
371static void f_sha256(typval_T *argvars, typval_T *rettv);
372#endif /* FEAT_CRYPT */
373static void f_shellescape(typval_T *argvars, typval_T *rettv);
374static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100375#ifdef FEAT_SIGNS
376static void f_sign_define(typval_T *argvars, typval_T *rettv);
377static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
378static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100379static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100380static void f_sign_place(typval_T *argvars, typval_T *rettv);
381static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
382static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
383#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200384static void f_simplify(typval_T *argvars, typval_T *rettv);
385#ifdef FEAT_FLOAT
386static void f_sin(typval_T *argvars, typval_T *rettv);
387static void f_sinh(typval_T *argvars, typval_T *rettv);
388#endif
389static void f_sort(typval_T *argvars, typval_T *rettv);
390static void f_soundfold(typval_T *argvars, typval_T *rettv);
391static void f_spellbadword(typval_T *argvars, typval_T *rettv);
392static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
393static void f_split(typval_T *argvars, typval_T *rettv);
394#ifdef FEAT_FLOAT
395static void f_sqrt(typval_T *argvars, typval_T *rettv);
396static void f_str2float(typval_T *argvars, typval_T *rettv);
397#endif
398static void f_str2nr(typval_T *argvars, typval_T *rettv);
399static void f_strchars(typval_T *argvars, typval_T *rettv);
400#ifdef HAVE_STRFTIME
401static void f_strftime(typval_T *argvars, typval_T *rettv);
402#endif
403static void f_strgetchar(typval_T *argvars, typval_T *rettv);
404static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200405static void f_strlen(typval_T *argvars, typval_T *rettv);
406static void f_strcharpart(typval_T *argvars, typval_T *rettv);
407static void f_strpart(typval_T *argvars, typval_T *rettv);
408static void f_strridx(typval_T *argvars, typval_T *rettv);
409static void f_strtrans(typval_T *argvars, typval_T *rettv);
410static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
411static void f_strwidth(typval_T *argvars, typval_T *rettv);
412static void f_submatch(typval_T *argvars, typval_T *rettv);
413static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200414static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200415static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200416static void f_synID(typval_T *argvars, typval_T *rettv);
417static void f_synIDattr(typval_T *argvars, typval_T *rettv);
418static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
419static void f_synstack(typval_T *argvars, typval_T *rettv);
420static void f_synconcealed(typval_T *argvars, typval_T *rettv);
421static void f_system(typval_T *argvars, typval_T *rettv);
422static void f_systemlist(typval_T *argvars, typval_T *rettv);
423static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
424static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
425static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
426static void f_taglist(typval_T *argvars, typval_T *rettv);
427static void f_tagfiles(typval_T *argvars, typval_T *rettv);
428static void f_tempname(typval_T *argvars, typval_T *rettv);
429static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
430static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200431static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200432static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100433static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100434static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100436static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100437static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200438#ifdef FEAT_JOB_CHANNEL
439static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
440#endif
441static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
442#ifdef FEAT_JOB_CHANNEL
443static void f_test_null_job(typval_T *argvars, typval_T *rettv);
444#endif
445static void f_test_null_list(typval_T *argvars, typval_T *rettv);
446static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
447static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200448#ifdef FEAT_GUI
449static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
450#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200451static void f_test_settime(typval_T *argvars, typval_T *rettv);
452#ifdef FEAT_FLOAT
453static void f_tan(typval_T *argvars, typval_T *rettv);
454static void f_tanh(typval_T *argvars, typval_T *rettv);
455#endif
456#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200457static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200458static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200459static void f_timer_start(typval_T *argvars, typval_T *rettv);
460static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200461static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200462#endif
463static void f_tolower(typval_T *argvars, typval_T *rettv);
464static void f_toupper(typval_T *argvars, typval_T *rettv);
465static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100466static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200467#ifdef FEAT_FLOAT
468static void f_trunc(typval_T *argvars, typval_T *rettv);
469#endif
470static void f_type(typval_T *argvars, typval_T *rettv);
471static void f_undofile(typval_T *argvars, typval_T *rettv);
472static void f_undotree(typval_T *argvars, typval_T *rettv);
473static void f_uniq(typval_T *argvars, typval_T *rettv);
474static void f_values(typval_T *argvars, typval_T *rettv);
475static void f_virtcol(typval_T *argvars, typval_T *rettv);
476static void f_visualmode(typval_T *argvars, typval_T *rettv);
477static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
478static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
479static void f_win_getid(typval_T *argvars, typval_T *rettv);
480static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
481static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
482static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100483static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200484static void f_winbufnr(typval_T *argvars, typval_T *rettv);
485static void f_wincol(typval_T *argvars, typval_T *rettv);
486static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200487static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200488static void f_winline(typval_T *argvars, typval_T *rettv);
489static void f_winnr(typval_T *argvars, typval_T *rettv);
490static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
491static void f_winrestview(typval_T *argvars, typval_T *rettv);
492static void f_winsaveview(typval_T *argvars, typval_T *rettv);
493static void f_winwidth(typval_T *argvars, typval_T *rettv);
494static void f_writefile(typval_T *argvars, typval_T *rettv);
495static void f_wordcount(typval_T *argvars, typval_T *rettv);
496static void f_xor(typval_T *argvars, typval_T *rettv);
497
498/*
499 * Array with names and number of arguments of all internal functions
500 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
501 */
502static struct fst
503{
504 char *f_name; /* function name */
505 char f_min_argc; /* minimal number of arguments */
506 char f_max_argc; /* maximal number of arguments */
507 void (*f_func)(typval_T *args, typval_T *rvar);
508 /* implementation of function */
509} functions[] =
510{
511#ifdef FEAT_FLOAT
512 {"abs", 1, 1, f_abs},
513 {"acos", 1, 1, f_acos}, /* WJMc */
514#endif
515 {"add", 2, 2, f_add},
516 {"and", 2, 2, f_and},
517 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200518 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200519 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520 {"argidx", 0, 0, f_argidx},
521 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200522 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200523#ifdef FEAT_FLOAT
524 {"asin", 1, 1, f_asin}, /* WJMc */
525#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100526 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100528 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200530 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200531 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100532 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533 {"assert_match", 2, 3, f_assert_match},
534 {"assert_notequal", 2, 3, f_assert_notequal},
535 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100536 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537 {"assert_true", 1, 2, f_assert_true},
538#ifdef FEAT_FLOAT
539 {"atan", 1, 1, f_atan},
540 {"atan2", 2, 2, f_atan2},
541#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100542#ifdef FEAT_BEVAL
543 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100544# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100545 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100546# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100547#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200548 {"browse", 4, 4, f_browse},
549 {"browsedir", 2, 2, f_browsedir},
550 {"bufexists", 1, 1, f_bufexists},
551 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
552 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
553 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
554 {"buflisted", 1, 1, f_buflisted},
555 {"bufloaded", 1, 1, f_bufloaded},
556 {"bufname", 1, 1, f_bufname},
557 {"bufnr", 1, 2, f_bufnr},
558 {"bufwinid", 1, 1, f_bufwinid},
559 {"bufwinnr", 1, 1, f_bufwinnr},
560 {"byte2line", 1, 1, f_byte2line},
561 {"byteidx", 2, 2, f_byteidx},
562 {"byteidxcomp", 2, 2, f_byteidxcomp},
563 {"call", 2, 3, f_call},
564#ifdef FEAT_FLOAT
565 {"ceil", 1, 1, f_ceil},
566#endif
567#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100568 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200569 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200570 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200571 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
572 {"ch_evalraw", 2, 3, f_ch_evalraw},
573 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
574 {"ch_getjob", 1, 1, f_ch_getjob},
575 {"ch_info", 1, 1, f_ch_info},
576 {"ch_log", 1, 2, f_ch_log},
577 {"ch_logfile", 1, 2, f_ch_logfile},
578 {"ch_open", 1, 2, f_ch_open},
579 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100580 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200581 {"ch_readraw", 1, 2, f_ch_readraw},
582 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
583 {"ch_sendraw", 2, 3, f_ch_sendraw},
584 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200585 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200586#endif
587 {"changenr", 0, 0, f_changenr},
588 {"char2nr", 1, 2, f_char2nr},
589 {"cindent", 1, 1, f_cindent},
590 {"clearmatches", 0, 0, f_clearmatches},
591 {"col", 1, 1, f_col},
592#if defined(FEAT_INS_EXPAND)
593 {"complete", 2, 2, f_complete},
594 {"complete_add", 1, 1, f_complete_add},
595 {"complete_check", 0, 0, f_complete_check},
596#endif
597 {"confirm", 1, 4, f_confirm},
598 {"copy", 1, 1, f_copy},
599#ifdef FEAT_FLOAT
600 {"cos", 1, 1, f_cos},
601 {"cosh", 1, 1, f_cosh},
602#endif
603 {"count", 2, 4, f_count},
604 {"cscope_connection",0,3, f_cscope_connection},
605 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100606#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200607 {"debugbreak", 1, 1, f_debugbreak},
608#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200609 {"deepcopy", 1, 2, f_deepcopy},
610 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200611 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200612 {"did_filetype", 0, 0, f_did_filetype},
613 {"diff_filler", 1, 1, f_diff_filler},
614 {"diff_hlID", 2, 2, f_diff_hlID},
615 {"empty", 1, 1, f_empty},
616 {"escape", 2, 2, f_escape},
617 {"eval", 1, 1, f_eval},
618 {"eventhandler", 0, 0, f_eventhandler},
619 {"executable", 1, 1, f_executable},
620 {"execute", 1, 2, f_execute},
621 {"exepath", 1, 1, f_exepath},
622 {"exists", 1, 1, f_exists},
623#ifdef FEAT_FLOAT
624 {"exp", 1, 1, f_exp},
625#endif
626 {"expand", 1, 3, f_expand},
627 {"extend", 2, 3, f_extend},
628 {"feedkeys", 1, 2, f_feedkeys},
629 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
630 {"filereadable", 1, 1, f_filereadable},
631 {"filewritable", 1, 1, f_filewritable},
632 {"filter", 2, 2, f_filter},
633 {"finddir", 1, 3, f_finddir},
634 {"findfile", 1, 3, f_findfile},
635#ifdef FEAT_FLOAT
636 {"float2nr", 1, 1, f_float2nr},
637 {"floor", 1, 1, f_floor},
638 {"fmod", 2, 2, f_fmod},
639#endif
640 {"fnameescape", 1, 1, f_fnameescape},
641 {"fnamemodify", 2, 2, f_fnamemodify},
642 {"foldclosed", 1, 1, f_foldclosed},
643 {"foldclosedend", 1, 1, f_foldclosedend},
644 {"foldlevel", 1, 1, f_foldlevel},
645 {"foldtext", 0, 0, f_foldtext},
646 {"foldtextresult", 1, 1, f_foldtextresult},
647 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200648 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649 {"function", 1, 3, f_function},
650 {"garbagecollect", 0, 1, f_garbagecollect},
651 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200652 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"getbufline", 2, 3, f_getbufline},
654 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100655 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200656 {"getchar", 0, 1, f_getchar},
657 {"getcharmod", 0, 0, f_getcharmod},
658 {"getcharsearch", 0, 0, f_getcharsearch},
659 {"getcmdline", 0, 0, f_getcmdline},
660 {"getcmdpos", 0, 0, f_getcmdpos},
661 {"getcmdtype", 0, 0, f_getcmdtype},
662 {"getcmdwintype", 0, 0, f_getcmdwintype},
663#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200664 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200665#endif
666 {"getcurpos", 0, 0, f_getcurpos},
667 {"getcwd", 0, 2, f_getcwd},
668 {"getfontname", 0, 1, f_getfontname},
669 {"getfperm", 1, 1, f_getfperm},
670 {"getfsize", 1, 1, f_getfsize},
671 {"getftime", 1, 1, f_getftime},
672 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100673 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200674 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200675 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200676 {"getmatches", 0, 0, f_getmatches},
677 {"getpid", 0, 0, f_getpid},
678 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200679 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680 {"getreg", 0, 3, f_getreg},
681 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200682 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200683 {"gettabvar", 2, 3, f_gettabvar},
684 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100685 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200686 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100687 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688 {"getwinposx", 0, 0, f_getwinposx},
689 {"getwinposy", 0, 0, f_getwinposy},
690 {"getwinvar", 2, 3, f_getwinvar},
691 {"glob", 1, 4, f_glob},
692 {"glob2regpat", 1, 1, f_glob2regpat},
693 {"globpath", 2, 5, f_globpath},
694 {"has", 1, 1, f_has},
695 {"has_key", 2, 2, f_has_key},
696 {"haslocaldir", 0, 2, f_haslocaldir},
697 {"hasmapto", 1, 3, f_hasmapto},
698 {"highlightID", 1, 1, f_hlID}, /* obsolete */
699 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
700 {"histadd", 2, 2, f_histadd},
701 {"histdel", 1, 2, f_histdel},
702 {"histget", 1, 2, f_histget},
703 {"histnr", 1, 1, f_histnr},
704 {"hlID", 1, 1, f_hlID},
705 {"hlexists", 1, 1, f_hlexists},
706 {"hostname", 0, 0, f_hostname},
707 {"iconv", 3, 3, f_iconv},
708 {"indent", 1, 1, f_indent},
709 {"index", 2, 4, f_index},
710 {"input", 1, 3, f_input},
711 {"inputdialog", 1, 3, f_inputdialog},
712 {"inputlist", 1, 1, f_inputlist},
713 {"inputrestore", 0, 0, f_inputrestore},
714 {"inputsave", 0, 0, f_inputsave},
715 {"inputsecret", 1, 2, f_inputsecret},
716 {"insert", 2, 3, f_insert},
717 {"invert", 1, 1, f_invert},
718 {"isdirectory", 1, 1, f_isdirectory},
719 {"islocked", 1, 1, f_islocked},
720#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
721 {"isnan", 1, 1, f_isnan},
722#endif
723 {"items", 1, 1, f_items},
724#ifdef FEAT_JOB_CHANNEL
725 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200726 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727 {"job_setoptions", 2, 2, f_job_setoptions},
728 {"job_start", 1, 2, f_job_start},
729 {"job_status", 1, 1, f_job_status},
730 {"job_stop", 1, 2, f_job_stop},
731#endif
732 {"join", 1, 2, f_join},
733 {"js_decode", 1, 1, f_js_decode},
734 {"js_encode", 1, 1, f_js_encode},
735 {"json_decode", 1, 1, f_json_decode},
736 {"json_encode", 1, 1, f_json_encode},
737 {"keys", 1, 1, f_keys},
738 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
739 {"len", 1, 1, f_len},
740 {"libcall", 3, 3, f_libcall},
741 {"libcallnr", 3, 3, f_libcallnr},
742 {"line", 1, 1, f_line},
743 {"line2byte", 1, 1, f_line2byte},
744 {"lispindent", 1, 1, f_lispindent},
745 {"localtime", 0, 0, f_localtime},
746#ifdef FEAT_FLOAT
747 {"log", 1, 1, f_log},
748 {"log10", 1, 1, f_log10},
749#endif
750#ifdef FEAT_LUA
751 {"luaeval", 1, 2, f_luaeval},
752#endif
753 {"map", 2, 2, f_map},
754 {"maparg", 1, 4, f_maparg},
755 {"mapcheck", 1, 3, f_mapcheck},
756 {"match", 2, 4, f_match},
757 {"matchadd", 2, 5, f_matchadd},
758 {"matchaddpos", 2, 5, f_matchaddpos},
759 {"matcharg", 1, 1, f_matcharg},
760 {"matchdelete", 1, 1, f_matchdelete},
761 {"matchend", 2, 4, f_matchend},
762 {"matchlist", 2, 4, f_matchlist},
763 {"matchstr", 2, 4, f_matchstr},
764 {"matchstrpos", 2, 4, f_matchstrpos},
765 {"max", 1, 1, f_max},
766 {"min", 1, 1, f_min},
767#ifdef vim_mkdir
768 {"mkdir", 1, 3, f_mkdir},
769#endif
770 {"mode", 0, 1, f_mode},
771#ifdef FEAT_MZSCHEME
772 {"mzeval", 1, 1, f_mzeval},
773#endif
774 {"nextnonblank", 1, 1, f_nextnonblank},
775 {"nr2char", 1, 2, f_nr2char},
776 {"or", 2, 2, f_or},
777 {"pathshorten", 1, 1, f_pathshorten},
778#ifdef FEAT_PERL
779 {"perleval", 1, 1, f_perleval},
780#endif
781#ifdef FEAT_FLOAT
782 {"pow", 2, 2, f_pow},
783#endif
784 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100785 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200786#ifdef FEAT_JOB_CHANNEL
787 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200788 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200789 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
790#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100791#ifdef FEAT_TEXT_PROP
792 {"prop_add", 3, 3, f_prop_add},
793 {"prop_clear", 1, 3, f_prop_clear},
794 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100795 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100796 {"prop_type_add", 2, 2, f_prop_type_add},
797 {"prop_type_change", 2, 2, f_prop_type_change},
798 {"prop_type_delete", 1, 2, f_prop_type_delete},
799 {"prop_type_get", 1, 2, f_prop_type_get},
800 {"prop_type_list", 0, 1, f_prop_type_list},
801#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200802 {"pumvisible", 0, 0, f_pumvisible},
803#ifdef FEAT_PYTHON3
804 {"py3eval", 1, 1, f_py3eval},
805#endif
806#ifdef FEAT_PYTHON
807 {"pyeval", 1, 1, f_pyeval},
808#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100809#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
810 {"pyxeval", 1, 1, f_pyxeval},
811#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200812 {"range", 1, 3, f_range},
813 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200814 {"reg_executing", 0, 0, f_reg_executing},
815 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200816 {"reltime", 0, 2, f_reltime},
817#ifdef FEAT_FLOAT
818 {"reltimefloat", 1, 1, f_reltimefloat},
819#endif
820 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100821 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822 {"remote_foreground", 1, 1, f_remote_foreground},
823 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100824 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100826 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827 {"remove", 2, 3, f_remove},
828 {"rename", 2, 2, f_rename},
829 {"repeat", 2, 2, f_repeat},
830 {"resolve", 1, 1, f_resolve},
831 {"reverse", 1, 1, f_reverse},
832#ifdef FEAT_FLOAT
833 {"round", 1, 1, f_round},
834#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100835#ifdef FEAT_RUBY
836 {"rubyeval", 1, 1, f_rubyeval},
837#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200838 {"screenattr", 2, 2, f_screenattr},
839 {"screenchar", 2, 2, f_screenchar},
840 {"screencol", 0, 0, f_screencol},
841 {"screenrow", 0, 0, f_screenrow},
842 {"search", 1, 4, f_search},
843 {"searchdecl", 1, 3, f_searchdecl},
844 {"searchpair", 3, 7, f_searchpair},
845 {"searchpairpos", 3, 7, f_searchpairpos},
846 {"searchpos", 1, 4, f_searchpos},
847 {"server2client", 2, 2, f_server2client},
848 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200849 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850 {"setbufvar", 3, 3, f_setbufvar},
851 {"setcharsearch", 1, 1, f_setcharsearch},
852 {"setcmdpos", 1, 1, f_setcmdpos},
853 {"setfperm", 2, 2, f_setfperm},
854 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200855 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856 {"setmatches", 1, 1, f_setmatches},
857 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200858 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200859 {"setreg", 2, 3, f_setreg},
860 {"settabvar", 3, 3, f_settabvar},
861 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100862 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200863 {"setwinvar", 3, 3, f_setwinvar},
864#ifdef FEAT_CRYPT
865 {"sha256", 1, 1, f_sha256},
866#endif
867 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100868 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100869#ifdef FEAT_SIGNS
870 {"sign_define", 1, 2, f_sign_define},
871 {"sign_getdefined", 0, 1, f_sign_getdefined},
872 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100873 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100874 {"sign_place", 4, 5, f_sign_place},
875 {"sign_undefine", 0, 1, f_sign_undefine},
876 {"sign_unplace", 1, 2, f_sign_unplace},
877#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200878 {"simplify", 1, 1, f_simplify},
879#ifdef FEAT_FLOAT
880 {"sin", 1, 1, f_sin},
881 {"sinh", 1, 1, f_sinh},
882#endif
883 {"sort", 1, 3, f_sort},
884 {"soundfold", 1, 1, f_soundfold},
885 {"spellbadword", 0, 1, f_spellbadword},
886 {"spellsuggest", 1, 3, f_spellsuggest},
887 {"split", 1, 3, f_split},
888#ifdef FEAT_FLOAT
889 {"sqrt", 1, 1, f_sqrt},
890 {"str2float", 1, 1, f_str2float},
891#endif
892 {"str2nr", 1, 2, f_str2nr},
893 {"strcharpart", 2, 3, f_strcharpart},
894 {"strchars", 1, 2, f_strchars},
895 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
896#ifdef HAVE_STRFTIME
897 {"strftime", 1, 2, f_strftime},
898#endif
899 {"strgetchar", 2, 2, f_strgetchar},
900 {"stridx", 2, 3, f_stridx},
901 {"string", 1, 1, f_string},
902 {"strlen", 1, 1, f_strlen},
903 {"strpart", 2, 3, f_strpart},
904 {"strridx", 2, 3, f_strridx},
905 {"strtrans", 1, 1, f_strtrans},
906 {"strwidth", 1, 1, f_strwidth},
907 {"submatch", 1, 2, f_submatch},
908 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200909 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200910 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200911 {"synID", 3, 3, f_synID},
912 {"synIDattr", 2, 3, f_synIDattr},
913 {"synIDtrans", 1, 1, f_synIDtrans},
914 {"synconcealed", 2, 2, f_synconcealed},
915 {"synstack", 2, 2, f_synstack},
916 {"system", 1, 2, f_system},
917 {"systemlist", 1, 2, f_systemlist},
918 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
919 {"tabpagenr", 0, 1, f_tabpagenr},
920 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
921 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100922 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#ifdef FEAT_FLOAT
924 {"tan", 1, 1, f_tan},
925 {"tanh", 1, 1, f_tanh},
926#endif
927 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200928#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100929 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
930 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100931 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200932 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200933# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
934 {"term_getansicolors", 1, 1, f_term_getansicolors},
935# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200936 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200937 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200938 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200939 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200940 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200941 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200942 {"term_getstatus", 1, 1, f_term_getstatus},
943 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200944 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200945 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200946 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200947 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200948# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
949 {"term_setansicolors", 2, 2, f_term_setansicolors},
950# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100951 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100952 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200953 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200954 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200955 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200956#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200957 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
958 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200959 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200960 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100961 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100962 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200963#ifdef FEAT_JOB_CHANNEL
964 {"test_null_channel", 0, 0, f_test_null_channel},
965#endif
966 {"test_null_dict", 0, 0, f_test_null_dict},
967#ifdef FEAT_JOB_CHANNEL
968 {"test_null_job", 0, 0, f_test_null_job},
969#endif
970 {"test_null_list", 0, 0, f_test_null_list},
971 {"test_null_partial", 0, 0, f_test_null_partial},
972 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200973 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100974 {"test_override", 2, 2, f_test_override},
975 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200976#ifdef FEAT_GUI
977 {"test_scrollbar", 3, 3, f_test_scrollbar},
978#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200979 {"test_settime", 1, 1, f_test_settime},
980#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200981 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200982 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200983 {"timer_start", 2, 3, f_timer_start},
984 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200985 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200986#endif
987 {"tolower", 1, 1, f_tolower},
988 {"toupper", 1, 1, f_toupper},
989 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100990 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200991#ifdef FEAT_FLOAT
992 {"trunc", 1, 1, f_trunc},
993#endif
994 {"type", 1, 1, f_type},
995 {"undofile", 1, 1, f_undofile},
996 {"undotree", 0, 0, f_undotree},
997 {"uniq", 1, 3, f_uniq},
998 {"values", 1, 1, f_values},
999 {"virtcol", 1, 1, f_virtcol},
1000 {"visualmode", 0, 1, f_visualmode},
1001 {"wildmenumode", 0, 0, f_wildmenumode},
1002 {"win_findbuf", 1, 1, f_win_findbuf},
1003 {"win_getid", 0, 2, f_win_getid},
1004 {"win_gotoid", 1, 1, f_win_gotoid},
1005 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1006 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001007 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001008 {"winbufnr", 1, 1, f_winbufnr},
1009 {"wincol", 0, 0, f_wincol},
1010 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001011 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012 {"winline", 0, 0, f_winline},
1013 {"winnr", 0, 1, f_winnr},
1014 {"winrestcmd", 0, 0, f_winrestcmd},
1015 {"winrestview", 1, 1, f_winrestview},
1016 {"winsaveview", 0, 0, f_winsaveview},
1017 {"winwidth", 1, 1, f_winwidth},
1018 {"wordcount", 0, 0, f_wordcount},
1019 {"writefile", 2, 3, f_writefile},
1020 {"xor", 2, 2, f_xor},
1021};
1022
1023#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1024
1025/*
1026 * Function given to ExpandGeneric() to obtain the list of internal
1027 * or user defined function names.
1028 */
1029 char_u *
1030get_function_name(expand_T *xp, int idx)
1031{
1032 static int intidx = -1;
1033 char_u *name;
1034
1035 if (idx == 0)
1036 intidx = -1;
1037 if (intidx < 0)
1038 {
1039 name = get_user_func_name(xp, idx);
1040 if (name != NULL)
1041 return name;
1042 }
1043 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1044 {
1045 STRCPY(IObuff, functions[intidx].f_name);
1046 STRCAT(IObuff, "(");
1047 if (functions[intidx].f_max_argc == 0)
1048 STRCAT(IObuff, ")");
1049 return IObuff;
1050 }
1051
1052 return NULL;
1053}
1054
1055/*
1056 * Function given to ExpandGeneric() to obtain the list of internal or
1057 * user defined variable or function names.
1058 */
1059 char_u *
1060get_expr_name(expand_T *xp, int idx)
1061{
1062 static int intidx = -1;
1063 char_u *name;
1064
1065 if (idx == 0)
1066 intidx = -1;
1067 if (intidx < 0)
1068 {
1069 name = get_function_name(xp, idx);
1070 if (name != NULL)
1071 return name;
1072 }
1073 return get_user_var_name(xp, ++intidx);
1074}
1075
1076#endif /* FEAT_CMDL_COMPL */
1077
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001078/*
1079 * Find internal function in table above.
1080 * Return index, or -1 if not found
1081 */
1082 int
1083find_internal_func(
1084 char_u *name) /* name of the function */
1085{
1086 int first = 0;
1087 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1088 int cmp;
1089 int x;
1090
1091 /*
1092 * Find the function name in the table. Binary search.
1093 */
1094 while (first <= last)
1095 {
1096 x = first + ((unsigned)(last - first) >> 1);
1097 cmp = STRCMP(name, functions[x].f_name);
1098 if (cmp < 0)
1099 last = x - 1;
1100 else if (cmp > 0)
1101 first = x + 1;
1102 else
1103 return x;
1104 }
1105 return -1;
1106}
1107
1108 int
1109call_internal_func(
1110 char_u *name,
1111 int argcount,
1112 typval_T *argvars,
1113 typval_T *rettv)
1114{
1115 int i;
1116
1117 i = find_internal_func(name);
1118 if (i < 0)
1119 return ERROR_UNKNOWN;
1120 if (argcount < functions[i].f_min_argc)
1121 return ERROR_TOOFEW;
1122 if (argcount > functions[i].f_max_argc)
1123 return ERROR_TOOMANY;
1124 argvars[argcount].v_type = VAR_UNKNOWN;
1125 functions[i].f_func(argvars, rettv);
1126 return ERROR_NONE;
1127}
1128
1129/*
1130 * Return TRUE for a non-zero Number and a non-empty String.
1131 */
1132 static int
1133non_zero_arg(typval_T *argvars)
1134{
1135 return ((argvars[0].v_type == VAR_NUMBER
1136 && argvars[0].vval.v_number != 0)
1137 || (argvars[0].v_type == VAR_SPECIAL
1138 && argvars[0].vval.v_number == VVAL_TRUE)
1139 || (argvars[0].v_type == VAR_STRING
1140 && argvars[0].vval.v_string != NULL
1141 && *argvars[0].vval.v_string != NUL));
1142}
1143
1144/*
1145 * Get the lnum from the first argument.
1146 * Also accepts ".", "$", etc., but that only works for the current buffer.
1147 * Returns -1 on error.
1148 */
1149 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001150tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001151{
1152 typval_T rettv;
1153 linenr_T lnum;
1154
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001155 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001156 if (lnum == 0) /* no valid number, try using line() */
1157 {
1158 rettv.v_type = VAR_NUMBER;
1159 f_line(argvars, &rettv);
1160 lnum = (linenr_T)rettv.vval.v_number;
1161 clear_tv(&rettv);
1162 }
1163 return lnum;
1164}
1165
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001166/*
1167 * Get the lnum from the first argument.
1168 * Also accepts "$", then "buf" is used.
1169 * Returns 0 on error.
1170 */
1171 static linenr_T
1172tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1173{
1174 if (argvars[0].v_type == VAR_STRING
1175 && argvars[0].vval.v_string != NULL
1176 && argvars[0].vval.v_string[0] == '$'
1177 && buf != NULL)
1178 return buf->b_ml.ml_line_count;
1179 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1180}
1181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001182#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001183/*
1184 * Get the float value of "argvars[0]" into "f".
1185 * Returns FAIL when the argument is not a Number or Float.
1186 */
1187 static int
1188get_float_arg(typval_T *argvars, float_T *f)
1189{
1190 if (argvars[0].v_type == VAR_FLOAT)
1191 {
1192 *f = argvars[0].vval.v_float;
1193 return OK;
1194 }
1195 if (argvars[0].v_type == VAR_NUMBER)
1196 {
1197 *f = (float_T)argvars[0].vval.v_number;
1198 return OK;
1199 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001200 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001201 return FAIL;
1202}
1203
1204/*
1205 * "abs(expr)" function
1206 */
1207 static void
1208f_abs(typval_T *argvars, typval_T *rettv)
1209{
1210 if (argvars[0].v_type == VAR_FLOAT)
1211 {
1212 rettv->v_type = VAR_FLOAT;
1213 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1214 }
1215 else
1216 {
1217 varnumber_T n;
1218 int error = FALSE;
1219
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001220 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001221 if (error)
1222 rettv->vval.v_number = -1;
1223 else if (n > 0)
1224 rettv->vval.v_number = n;
1225 else
1226 rettv->vval.v_number = -n;
1227 }
1228}
1229
1230/*
1231 * "acos()" function
1232 */
1233 static void
1234f_acos(typval_T *argvars, typval_T *rettv)
1235{
1236 float_T f = 0.0;
1237
1238 rettv->v_type = VAR_FLOAT;
1239 if (get_float_arg(argvars, &f) == OK)
1240 rettv->vval.v_float = acos(f);
1241 else
1242 rettv->vval.v_float = 0.0;
1243}
1244#endif
1245
1246/*
1247 * "add(list, item)" function
1248 */
1249 static void
1250f_add(typval_T *argvars, typval_T *rettv)
1251{
1252 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001253 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254
1255 rettv->vval.v_number = 1; /* Default: Failed */
1256 if (argvars[0].v_type == VAR_LIST)
1257 {
1258 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001259 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001260 (char_u *)N_("add() argument"), TRUE)
1261 && list_append_tv(l, &argvars[1]) == OK)
1262 copy_tv(&argvars[0], rettv);
1263 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001264 else if (argvars[0].v_type == VAR_BLOB)
1265 {
1266 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001267 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001268 (char_u *)N_("add() argument"), TRUE))
1269 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001270 int error = FALSE;
1271 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1272
1273 if (!error)
1274 {
1275 ga_append(&b->bv_ga, (int)n);
1276 copy_tv(&argvars[0], rettv);
1277 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001278 }
1279 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001280 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001281 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001282}
1283
1284/*
1285 * "and(expr, expr)" function
1286 */
1287 static void
1288f_and(typval_T *argvars, typval_T *rettv)
1289{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001290 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1291 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001292}
1293
1294/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001295 * If there is a window for "curbuf", make it the current window.
1296 */
1297 static void
1298find_win_for_curbuf(void)
1299{
1300 wininfo_T *wip;
1301
1302 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1303 {
1304 if (wip->wi_win != NULL)
1305 {
1306 curwin = wip->wi_win;
1307 break;
1308 }
1309 }
1310}
1311
1312/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001313 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001314 */
1315 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001316set_buffer_lines(
1317 buf_T *buf,
1318 linenr_T lnum_arg,
1319 int append,
1320 typval_T *lines,
1321 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001322{
Bram Moolenaarca851592018-06-06 21:04:07 +02001323 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1324 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001325 list_T *l = NULL;
1326 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001327 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001328 linenr_T append_lnum;
1329 buf_T *curbuf_save = NULL;
1330 win_T *curwin_save = NULL;
1331 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001332
Bram Moolenaarca851592018-06-06 21:04:07 +02001333 /* When using the current buffer ml_mfp will be set if needed. Useful when
1334 * setline() is used on startup. For other buffers the buffer must be
1335 * loaded. */
1336 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001337 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001338 rettv->vval.v_number = 1; /* FAIL */
1339 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001340 }
1341
Bram Moolenaarca851592018-06-06 21:04:07 +02001342 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001344 curbuf_save = curbuf;
1345 curwin_save = curwin;
1346 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001347 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001348 }
1349
1350 if (append)
1351 // appendbufline() uses the line number below which we insert
1352 append_lnum = lnum - 1;
1353 else
1354 // setbufline() uses the line number above which we insert, we only
1355 // append if it's below the last line
1356 append_lnum = curbuf->b_ml.ml_line_count;
1357
1358 if (lines->v_type == VAR_LIST)
1359 {
1360 l = lines->vval.v_list;
1361 li = l->lv_first;
1362 }
1363 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001364 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001365
1366 /* default result is zero == OK */
1367 for (;;)
1368 {
1369 if (l != NULL)
1370 {
1371 /* list argument, get next string */
1372 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001373 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001374 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001375 li = li->li_next;
1376 }
1377
Bram Moolenaarca851592018-06-06 21:04:07 +02001378 rettv->vval.v_number = 1; /* FAIL */
1379 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1380 break;
1381
1382 /* When coming here from Insert mode, sync undo, so that this can be
1383 * undone separately from what was previously inserted. */
1384 if (u_sync_once == 2)
1385 {
1386 u_sync_once = 1; /* notify that u_sync() was called */
1387 u_sync(TRUE);
1388 }
1389
1390 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1391 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001392 // Existing line, replace it.
1393 // Removes any existing text properties.
1394 if (u_savesub(lnum) == OK && ml_replace_len(
1395 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001396 {
1397 changed_bytes(lnum, 0);
1398 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1399 check_cursor_col();
1400 rettv->vval.v_number = 0; /* OK */
1401 }
1402 }
1403 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1404 {
1405 /* append the line */
1406 ++added;
1407 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1408 rettv->vval.v_number = 0; /* OK */
1409 }
1410
1411 if (l == NULL) /* only one string argument */
1412 break;
1413 ++lnum;
1414 }
1415
1416 if (added > 0)
1417 {
1418 win_T *wp;
1419 tabpage_T *tp;
1420
1421 appended_lines_mark(append_lnum, added);
1422 FOR_ALL_TAB_WINDOWS(tp, wp)
1423 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1424 wp->w_cursor.lnum += added;
1425 check_cursor_col();
1426
Bram Moolenaarf2732452018-06-03 14:47:35 +02001427#ifdef FEAT_JOB_CHANNEL
1428 if (bt_prompt(curbuf) && (State & INSERT))
1429 // show the line with the prompt
1430 update_topline();
1431#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001432 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001433
1434 if (!is_curbuf)
1435 {
1436 curbuf = curbuf_save;
1437 curwin = curwin_save;
1438 }
1439}
1440
1441/*
1442 * "append(lnum, string/list)" function
1443 */
1444 static void
1445f_append(typval_T *argvars, typval_T *rettv)
1446{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001447 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001448
1449 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1450}
1451
1452/*
1453 * "appendbufline(buf, lnum, string/list)" function
1454 */
1455 static void
1456f_appendbufline(typval_T *argvars, typval_T *rettv)
1457{
1458 linenr_T lnum;
1459 buf_T *buf;
1460
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001461 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001462 if (buf == NULL)
1463 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001464 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001465 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001466 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001467 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1468 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001469}
1470
1471/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001472 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001473 */
1474 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001475f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001476{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001477 win_T *wp;
1478
1479 if (argvars[0].v_type == VAR_UNKNOWN)
1480 // use the current window
1481 rettv->vval.v_number = ARGCOUNT;
1482 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001483 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001484 // use the global argument list
1485 rettv->vval.v_number = GARGCOUNT;
1486 else
1487 {
1488 // use the argument list of the specified window
1489 wp = find_win_by_nr_or_id(&argvars[0]);
1490 if (wp != NULL)
1491 rettv->vval.v_number = WARGCOUNT(wp);
1492 else
1493 rettv->vval.v_number = -1;
1494 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495}
1496
1497/*
1498 * "argidx()" function
1499 */
1500 static void
1501f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1502{
1503 rettv->vval.v_number = curwin->w_arg_idx;
1504}
1505
1506/*
1507 * "arglistid()" function
1508 */
1509 static void
1510f_arglistid(typval_T *argvars, typval_T *rettv)
1511{
1512 win_T *wp;
1513
1514 rettv->vval.v_number = -1;
1515 wp = find_tabwin(&argvars[0], &argvars[1]);
1516 if (wp != NULL)
1517 rettv->vval.v_number = wp->w_alist->id;
1518}
1519
1520/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001521 * Get the argument list for a given window
1522 */
1523 static void
1524get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1525{
1526 int idx;
1527
1528 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1529 for (idx = 0; idx < argcount; ++idx)
1530 list_append_string(rettv->vval.v_list,
1531 alist_name(&arglist[idx]), -1);
1532}
1533
1534/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535 * "argv(nr)" function
1536 */
1537 static void
1538f_argv(typval_T *argvars, typval_T *rettv)
1539{
1540 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001541 aentry_T *arglist = NULL;
1542 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001543
1544 if (argvars[0].v_type != VAR_UNKNOWN)
1545 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001546 if (argvars[1].v_type == VAR_UNKNOWN)
1547 {
1548 arglist = ARGLIST;
1549 argcount = ARGCOUNT;
1550 }
1551 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001552 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001553 {
1554 arglist = GARGLIST;
1555 argcount = GARGCOUNT;
1556 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001557 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001558 {
1559 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1560
1561 if (wp != NULL)
1562 {
1563 /* Use the argument list of the specified window */
1564 arglist = WARGLIST(wp);
1565 argcount = WARGCOUNT(wp);
1566 }
1567 }
1568
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001569 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001570 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001571 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001572 if (arglist != NULL && idx >= 0 && idx < argcount)
1573 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1574 else if (idx == -1)
1575 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001577 else
1578 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001579}
1580
1581/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001582 * "assert_beeps(cmd [, error])" function
1583 */
1584 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001585f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001586{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001587 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001588}
1589
1590/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001591 * "assert_equal(expected, actual[, msg])" function
1592 */
1593 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001594f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001595{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001596 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597}
1598
1599/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001600 * "assert_equalfile(fname-one, fname-two)" function
1601 */
1602 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001603f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001604{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001605 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001606}
1607
1608/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609 * "assert_notequal(expected, actual[, msg])" function
1610 */
1611 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001612f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001613{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001614 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001615}
1616
1617/*
1618 * "assert_exception(string[, msg])" function
1619 */
1620 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001621f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001623 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624}
1625
1626/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001627 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001628 */
1629 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001630f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001631{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001632 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001633}
1634
1635/*
1636 * "assert_false(actual[, msg])" function
1637 */
1638 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001639f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001640{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001641 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001642}
1643
1644/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001645 * "assert_inrange(lower, upper[, msg])" function
1646 */
1647 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001648f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001649{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001650 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001651}
1652
1653/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001654 * "assert_match(pattern, actual[, msg])" function
1655 */
1656 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001657f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001658{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001659 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001660}
1661
1662/*
1663 * "assert_notmatch(pattern, actual[, msg])" function
1664 */
1665 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001666f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001668 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001669}
1670
1671/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001672 * "assert_report(msg)" function
1673 */
1674 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001675f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001676{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001677 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001678}
1679
1680/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 * "assert_true(actual[, msg])" function
1682 */
1683 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001684f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001686 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687}
1688
1689#ifdef FEAT_FLOAT
1690/*
1691 * "asin()" function
1692 */
1693 static void
1694f_asin(typval_T *argvars, typval_T *rettv)
1695{
1696 float_T f = 0.0;
1697
1698 rettv->v_type = VAR_FLOAT;
1699 if (get_float_arg(argvars, &f) == OK)
1700 rettv->vval.v_float = asin(f);
1701 else
1702 rettv->vval.v_float = 0.0;
1703}
1704
1705/*
1706 * "atan()" function
1707 */
1708 static void
1709f_atan(typval_T *argvars, typval_T *rettv)
1710{
1711 float_T f = 0.0;
1712
1713 rettv->v_type = VAR_FLOAT;
1714 if (get_float_arg(argvars, &f) == OK)
1715 rettv->vval.v_float = atan(f);
1716 else
1717 rettv->vval.v_float = 0.0;
1718}
1719
1720/*
1721 * "atan2()" function
1722 */
1723 static void
1724f_atan2(typval_T *argvars, typval_T *rettv)
1725{
1726 float_T fx = 0.0, fy = 0.0;
1727
1728 rettv->v_type = VAR_FLOAT;
1729 if (get_float_arg(argvars, &fx) == OK
1730 && get_float_arg(&argvars[1], &fy) == OK)
1731 rettv->vval.v_float = atan2(fx, fy);
1732 else
1733 rettv->vval.v_float = 0.0;
1734}
1735#endif
1736
1737/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001738 * "balloon_show()" function
1739 */
1740#ifdef FEAT_BEVAL
1741 static void
1742f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1743{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001744 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001745 {
1746 if (argvars[0].v_type == VAR_LIST
1747# ifdef FEAT_GUI
1748 && !gui.in_use
1749# endif
1750 )
1751 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1752 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001753 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001754 }
1755}
1756
Bram Moolenaar669a8282017-11-19 20:13:05 +01001757# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001758 static void
1759f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1760{
1761 if (rettv_list_alloc(rettv) == OK)
1762 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001763 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001764
1765 if (msg != NULL)
1766 {
1767 pumitem_T *array;
1768 int size = split_message(msg, &array);
1769 int i;
1770
1771 /* Skip the first and last item, they are always empty. */
1772 for (i = 1; i < size - 1; ++i)
1773 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001774 while (size > 0)
1775 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001776 vim_free(array);
1777 }
1778 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001779}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001780# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001781#endif
1782
1783/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001784 * "browse(save, title, initdir, default)" function
1785 */
1786 static void
1787f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1788{
1789#ifdef FEAT_BROWSE
1790 int save;
1791 char_u *title;
1792 char_u *initdir;
1793 char_u *defname;
1794 char_u buf[NUMBUFLEN];
1795 char_u buf2[NUMBUFLEN];
1796 int error = FALSE;
1797
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001798 save = (int)tv_get_number_chk(&argvars[0], &error);
1799 title = tv_get_string_chk(&argvars[1]);
1800 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1801 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001802
1803 if (error || title == NULL || initdir == NULL || defname == NULL)
1804 rettv->vval.v_string = NULL;
1805 else
1806 rettv->vval.v_string =
1807 do_browse(save ? BROWSE_SAVE : 0,
1808 title, defname, NULL, initdir, NULL, curbuf);
1809#else
1810 rettv->vval.v_string = NULL;
1811#endif
1812 rettv->v_type = VAR_STRING;
1813}
1814
1815/*
1816 * "browsedir(title, initdir)" function
1817 */
1818 static void
1819f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1820{
1821#ifdef FEAT_BROWSE
1822 char_u *title;
1823 char_u *initdir;
1824 char_u buf[NUMBUFLEN];
1825
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001826 title = tv_get_string_chk(&argvars[0]);
1827 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828
1829 if (title == NULL || initdir == NULL)
1830 rettv->vval.v_string = NULL;
1831 else
1832 rettv->vval.v_string = do_browse(BROWSE_DIR,
1833 title, NULL, NULL, initdir, NULL, curbuf);
1834#else
1835 rettv->vval.v_string = NULL;
1836#endif
1837 rettv->v_type = VAR_STRING;
1838}
1839
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840/*
1841 * Find a buffer by number or exact name.
1842 */
1843 static buf_T *
1844find_buffer(typval_T *avar)
1845{
1846 buf_T *buf = NULL;
1847
1848 if (avar->v_type == VAR_NUMBER)
1849 buf = buflist_findnr((int)avar->vval.v_number);
1850 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1851 {
1852 buf = buflist_findname_exp(avar->vval.v_string);
1853 if (buf == NULL)
1854 {
1855 /* No full path name match, try a match with a URL or a "nofile"
1856 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001857 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001858 if (buf->b_fname != NULL
1859 && (path_with_url(buf->b_fname)
1860#ifdef FEAT_QUICKFIX
1861 || bt_nofile(buf)
1862#endif
1863 )
1864 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1865 break;
1866 }
1867 }
1868 return buf;
1869}
1870
1871/*
1872 * "bufexists(expr)" function
1873 */
1874 static void
1875f_bufexists(typval_T *argvars, typval_T *rettv)
1876{
1877 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1878}
1879
1880/*
1881 * "buflisted(expr)" function
1882 */
1883 static void
1884f_buflisted(typval_T *argvars, typval_T *rettv)
1885{
1886 buf_T *buf;
1887
1888 buf = find_buffer(&argvars[0]);
1889 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1890}
1891
1892/*
1893 * "bufloaded(expr)" function
1894 */
1895 static void
1896f_bufloaded(typval_T *argvars, typval_T *rettv)
1897{
1898 buf_T *buf;
1899
1900 buf = find_buffer(&argvars[0]);
1901 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1902}
1903
1904 buf_T *
1905buflist_find_by_name(char_u *name, int curtab_only)
1906{
1907 int save_magic;
1908 char_u *save_cpo;
1909 buf_T *buf;
1910
1911 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1912 save_magic = p_magic;
1913 p_magic = TRUE;
1914 save_cpo = p_cpo;
1915 p_cpo = (char_u *)"";
1916
1917 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1918 TRUE, FALSE, curtab_only));
1919
1920 p_magic = save_magic;
1921 p_cpo = save_cpo;
1922 return buf;
1923}
1924
1925/*
1926 * Get buffer by number or pattern.
1927 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001928 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001929tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001930{
1931 char_u *name = tv->vval.v_string;
1932 buf_T *buf;
1933
1934 if (tv->v_type == VAR_NUMBER)
1935 return buflist_findnr((int)tv->vval.v_number);
1936 if (tv->v_type != VAR_STRING)
1937 return NULL;
1938 if (name == NULL || *name == NUL)
1939 return curbuf;
1940 if (name[0] == '$' && name[1] == NUL)
1941 return lastbuf;
1942
1943 buf = buflist_find_by_name(name, curtab_only);
1944
1945 /* If not found, try expanding the name, like done for bufexists(). */
1946 if (buf == NULL)
1947 buf = find_buffer(tv);
1948
1949 return buf;
1950}
1951
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001952#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001953/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001954 * Get the buffer from "arg" and give an error and return NULL if it is not
1955 * valid.
1956 */
1957 static buf_T *
1958get_buf_arg(typval_T *arg)
1959{
1960 buf_T *buf;
1961
1962 ++emsg_off;
1963 buf = tv_get_buf(arg, FALSE);
1964 --emsg_off;
1965 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001966 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001967 return buf;
1968}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001969#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001970
1971/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001972 * "bufname(expr)" function
1973 */
1974 static void
1975f_bufname(typval_T *argvars, typval_T *rettv)
1976{
1977 buf_T *buf;
1978
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001979 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001981 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001982 rettv->v_type = VAR_STRING;
1983 if (buf != NULL && buf->b_fname != NULL)
1984 rettv->vval.v_string = vim_strsave(buf->b_fname);
1985 else
1986 rettv->vval.v_string = NULL;
1987 --emsg_off;
1988}
1989
1990/*
1991 * "bufnr(expr)" function
1992 */
1993 static void
1994f_bufnr(typval_T *argvars, typval_T *rettv)
1995{
1996 buf_T *buf;
1997 int error = FALSE;
1998 char_u *name;
1999
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002000 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002001 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002002 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002003 --emsg_off;
2004
2005 /* If the buffer isn't found and the second argument is not zero create a
2006 * new buffer. */
2007 if (buf == NULL
2008 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002009 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002011 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 && !error)
2013 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2014
2015 if (buf != NULL)
2016 rettv->vval.v_number = buf->b_fnum;
2017 else
2018 rettv->vval.v_number = -1;
2019}
2020
2021 static void
2022buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2023{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002024 win_T *wp;
2025 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002026 buf_T *buf;
2027
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002028 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002029 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002030 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002031 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002032 {
2033 ++winnr;
2034 if (wp->w_buffer == buf)
2035 break;
2036 }
2037 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002038 --emsg_off;
2039}
2040
2041/*
2042 * "bufwinid(nr)" function
2043 */
2044 static void
2045f_bufwinid(typval_T *argvars, typval_T *rettv)
2046{
2047 buf_win_common(argvars, rettv, FALSE);
2048}
2049
2050/*
2051 * "bufwinnr(nr)" function
2052 */
2053 static void
2054f_bufwinnr(typval_T *argvars, typval_T *rettv)
2055{
2056 buf_win_common(argvars, rettv, TRUE);
2057}
2058
2059/*
2060 * "byte2line(byte)" function
2061 */
2062 static void
2063f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2064{
2065#ifndef FEAT_BYTEOFF
2066 rettv->vval.v_number = -1;
2067#else
2068 long boff = 0;
2069
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002070 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002071 if (boff < 0)
2072 rettv->vval.v_number = -1;
2073 else
2074 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2075 (linenr_T)0, &boff);
2076#endif
2077}
2078
2079 static void
2080byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2081{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002083 char_u *str;
2084 varnumber_T idx;
2085
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002086 str = tv_get_string_chk(&argvars[0]);
2087 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088 rettv->vval.v_number = -1;
2089 if (str == NULL || idx < 0)
2090 return;
2091
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002092 t = str;
2093 for ( ; idx > 0; idx--)
2094 {
2095 if (*t == NUL) /* EOL reached */
2096 return;
2097 if (enc_utf8 && comp)
2098 t += utf_ptr2len(t);
2099 else
2100 t += (*mb_ptr2len)(t);
2101 }
2102 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002103}
2104
2105/*
2106 * "byteidx()" function
2107 */
2108 static void
2109f_byteidx(typval_T *argvars, typval_T *rettv)
2110{
2111 byteidx(argvars, rettv, FALSE);
2112}
2113
2114/*
2115 * "byteidxcomp()" function
2116 */
2117 static void
2118f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2119{
2120 byteidx(argvars, rettv, TRUE);
2121}
2122
2123/*
2124 * "call(func, arglist [, dict])" function
2125 */
2126 static void
2127f_call(typval_T *argvars, typval_T *rettv)
2128{
2129 char_u *func;
2130 partial_T *partial = NULL;
2131 dict_T *selfdict = NULL;
2132
2133 if (argvars[1].v_type != VAR_LIST)
2134 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002135 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002136 return;
2137 }
2138 if (argvars[1].vval.v_list == NULL)
2139 return;
2140
2141 if (argvars[0].v_type == VAR_FUNC)
2142 func = argvars[0].vval.v_string;
2143 else if (argvars[0].v_type == VAR_PARTIAL)
2144 {
2145 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002146 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147 }
2148 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002149 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002150 if (*func == NUL)
2151 return; /* type error or empty name */
2152
2153 if (argvars[2].v_type != VAR_UNKNOWN)
2154 {
2155 if (argvars[2].v_type != VAR_DICT)
2156 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002157 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 return;
2159 }
2160 selfdict = argvars[2].vval.v_dict;
2161 }
2162
2163 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2164}
2165
2166#ifdef FEAT_FLOAT
2167/*
2168 * "ceil({float})" function
2169 */
2170 static void
2171f_ceil(typval_T *argvars, typval_T *rettv)
2172{
2173 float_T f = 0.0;
2174
2175 rettv->v_type = VAR_FLOAT;
2176 if (get_float_arg(argvars, &f) == OK)
2177 rettv->vval.v_float = ceil(f);
2178 else
2179 rettv->vval.v_float = 0.0;
2180}
2181#endif
2182
2183#ifdef FEAT_JOB_CHANNEL
2184/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002185 * "ch_canread()" function
2186 */
2187 static void
2188f_ch_canread(typval_T *argvars, typval_T *rettv)
2189{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002190 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002191
2192 rettv->vval.v_number = 0;
2193 if (channel != NULL)
2194 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2195 || channel_has_readahead(channel, PART_OUT)
2196 || channel_has_readahead(channel, PART_ERR);
2197}
2198
2199/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002200 * "ch_close()" function
2201 */
2202 static void
2203f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2204{
2205 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2206
2207 if (channel != NULL)
2208 {
2209 channel_close(channel, FALSE);
2210 channel_clear(channel);
2211 }
2212}
2213
2214/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002215 * "ch_close()" function
2216 */
2217 static void
2218f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2219{
2220 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2221
2222 if (channel != NULL)
2223 channel_close_in(channel);
2224}
2225
2226/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002227 * "ch_getbufnr()" function
2228 */
2229 static void
2230f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2231{
2232 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2233
2234 rettv->vval.v_number = -1;
2235 if (channel != NULL)
2236 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002237 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002238 int part;
2239
2240 if (STRCMP(what, "err") == 0)
2241 part = PART_ERR;
2242 else if (STRCMP(what, "out") == 0)
2243 part = PART_OUT;
2244 else if (STRCMP(what, "in") == 0)
2245 part = PART_IN;
2246 else
2247 part = PART_SOCK;
2248 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2249 rettv->vval.v_number =
2250 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2251 }
2252}
2253
2254/*
2255 * "ch_getjob()" function
2256 */
2257 static void
2258f_ch_getjob(typval_T *argvars, typval_T *rettv)
2259{
2260 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2261
2262 if (channel != NULL)
2263 {
2264 rettv->v_type = VAR_JOB;
2265 rettv->vval.v_job = channel->ch_job;
2266 if (channel->ch_job != NULL)
2267 ++channel->ch_job->jv_refcount;
2268 }
2269}
2270
2271/*
2272 * "ch_info()" function
2273 */
2274 static void
2275f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2276{
2277 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2278
2279 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2280 channel_info(channel, rettv->vval.v_dict);
2281}
2282
2283/*
2284 * "ch_log()" function
2285 */
2286 static void
2287f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2288{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002289 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290 channel_T *channel = NULL;
2291
2292 if (argvars[1].v_type != VAR_UNKNOWN)
2293 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2294
Bram Moolenaard5359b22018-04-05 22:44:39 +02002295 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296}
2297
2298/*
2299 * "ch_logfile()" function
2300 */
2301 static void
2302f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2303{
2304 char_u *fname;
2305 char_u *opt = (char_u *)"";
2306 char_u buf[NUMBUFLEN];
2307
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002308 /* Don't open a file in restricted mode. */
2309 if (check_restricted() || check_secure())
2310 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002311 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002312 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002313 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002314 ch_logfile(fname, opt);
2315}
2316
2317/*
2318 * "ch_open()" function
2319 */
2320 static void
2321f_ch_open(typval_T *argvars, typval_T *rettv)
2322{
2323 rettv->v_type = VAR_CHANNEL;
2324 if (check_restricted() || check_secure())
2325 return;
2326 rettv->vval.v_channel = channel_open_func(argvars);
2327}
2328
2329/*
2330 * "ch_read()" function
2331 */
2332 static void
2333f_ch_read(typval_T *argvars, typval_T *rettv)
2334{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002335 common_channel_read(argvars, rettv, FALSE, FALSE);
2336}
2337
2338/*
2339 * "ch_readblob()" function
2340 */
2341 static void
2342f_ch_readblob(typval_T *argvars, typval_T *rettv)
2343{
2344 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345}
2346
2347/*
2348 * "ch_readraw()" function
2349 */
2350 static void
2351f_ch_readraw(typval_T *argvars, typval_T *rettv)
2352{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002353 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002354}
2355
2356/*
2357 * "ch_evalexpr()" function
2358 */
2359 static void
2360f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2361{
2362 ch_expr_common(argvars, rettv, TRUE);
2363}
2364
2365/*
2366 * "ch_sendexpr()" function
2367 */
2368 static void
2369f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2370{
2371 ch_expr_common(argvars, rettv, FALSE);
2372}
2373
2374/*
2375 * "ch_evalraw()" function
2376 */
2377 static void
2378f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2379{
2380 ch_raw_common(argvars, rettv, TRUE);
2381}
2382
2383/*
2384 * "ch_sendraw()" function
2385 */
2386 static void
2387f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2388{
2389 ch_raw_common(argvars, rettv, FALSE);
2390}
2391
2392/*
2393 * "ch_setoptions()" function
2394 */
2395 static void
2396f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2397{
2398 channel_T *channel;
2399 jobopt_T opt;
2400
2401 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2402 if (channel == NULL)
2403 return;
2404 clear_job_options(&opt);
2405 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002406 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002407 channel_set_options(channel, &opt);
2408 free_job_options(&opt);
2409}
2410
2411/*
2412 * "ch_status()" function
2413 */
2414 static void
2415f_ch_status(typval_T *argvars, typval_T *rettv)
2416{
2417 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002418 jobopt_T opt;
2419 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002420
2421 /* return an empty string by default */
2422 rettv->v_type = VAR_STRING;
2423 rettv->vval.v_string = NULL;
2424
2425 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002426
2427 if (argvars[1].v_type != VAR_UNKNOWN)
2428 {
2429 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002430 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002431 && (opt.jo_set & JO_PART))
2432 part = opt.jo_part;
2433 }
2434
2435 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436}
2437#endif
2438
2439/*
2440 * "changenr()" function
2441 */
2442 static void
2443f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2444{
2445 rettv->vval.v_number = curbuf->b_u_seq_cur;
2446}
2447
2448/*
2449 * "char2nr(string)" function
2450 */
2451 static void
2452f_char2nr(typval_T *argvars, typval_T *rettv)
2453{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002454 if (has_mbyte)
2455 {
2456 int utf8 = 0;
2457
2458 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002459 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460
2461 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002462 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002463 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002464 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 }
2466 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002467 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002468}
2469
2470/*
2471 * "cindent(lnum)" function
2472 */
2473 static void
2474f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2475{
2476#ifdef FEAT_CINDENT
2477 pos_T pos;
2478 linenr_T lnum;
2479
2480 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002481 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002482 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2483 {
2484 curwin->w_cursor.lnum = lnum;
2485 rettv->vval.v_number = get_c_indent();
2486 curwin->w_cursor = pos;
2487 }
2488 else
2489#endif
2490 rettv->vval.v_number = -1;
2491}
2492
2493/*
2494 * "clearmatches()" function
2495 */
2496 static void
2497f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2498{
2499#ifdef FEAT_SEARCH_EXTRA
2500 clear_matches(curwin);
2501#endif
2502}
2503
2504/*
2505 * "col(string)" function
2506 */
2507 static void
2508f_col(typval_T *argvars, typval_T *rettv)
2509{
2510 colnr_T col = 0;
2511 pos_T *fp;
2512 int fnum = curbuf->b_fnum;
2513
2514 fp = var2fpos(&argvars[0], FALSE, &fnum);
2515 if (fp != NULL && fnum == curbuf->b_fnum)
2516 {
2517 if (fp->col == MAXCOL)
2518 {
2519 /* '> can be MAXCOL, get the length of the line then */
2520 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2521 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2522 else
2523 col = MAXCOL;
2524 }
2525 else
2526 {
2527 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528 /* col(".") when the cursor is on the NUL at the end of the line
2529 * because of "coladd" can be seen as an extra column. */
2530 if (virtual_active() && fp == &curwin->w_cursor)
2531 {
2532 char_u *p = ml_get_cursor();
2533
2534 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2535 curwin->w_virtcol - curwin->w_cursor.coladd))
2536 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 int l;
2538
2539 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2540 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 }
2542 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 }
2544 }
2545 rettv->vval.v_number = col;
2546}
2547
2548#if defined(FEAT_INS_EXPAND)
2549/*
2550 * "complete()" function
2551 */
2552 static void
2553f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2554{
2555 int startcol;
2556
2557 if ((State & INSERT) == 0)
2558 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002559 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002560 return;
2561 }
2562
2563 /* Check for undo allowed here, because if something was already inserted
2564 * the line was already saved for undo and this check isn't done. */
2565 if (!undo_allowed())
2566 return;
2567
2568 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2569 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002570 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002571 return;
2572 }
2573
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002574 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002575 if (startcol <= 0)
2576 return;
2577
2578 set_completion(startcol - 1, argvars[1].vval.v_list);
2579}
2580
2581/*
2582 * "complete_add()" function
2583 */
2584 static void
2585f_complete_add(typval_T *argvars, typval_T *rettv)
2586{
2587 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2588}
2589
2590/*
2591 * "complete_check()" function
2592 */
2593 static void
2594f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2595{
2596 int saved = RedrawingDisabled;
2597
2598 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002599 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002600 rettv->vval.v_number = compl_interrupted;
2601 RedrawingDisabled = saved;
2602}
2603#endif
2604
2605/*
2606 * "confirm(message, buttons[, default [, type]])" function
2607 */
2608 static void
2609f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2610{
2611#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2612 char_u *message;
2613 char_u *buttons = NULL;
2614 char_u buf[NUMBUFLEN];
2615 char_u buf2[NUMBUFLEN];
2616 int def = 1;
2617 int type = VIM_GENERIC;
2618 char_u *typestr;
2619 int error = FALSE;
2620
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002621 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002622 if (message == NULL)
2623 error = TRUE;
2624 if (argvars[1].v_type != VAR_UNKNOWN)
2625 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002626 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 if (buttons == NULL)
2628 error = TRUE;
2629 if (argvars[2].v_type != VAR_UNKNOWN)
2630 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002631 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632 if (argvars[3].v_type != VAR_UNKNOWN)
2633 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002634 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002635 if (typestr == NULL)
2636 error = TRUE;
2637 else
2638 {
2639 switch (TOUPPER_ASC(*typestr))
2640 {
2641 case 'E': type = VIM_ERROR; break;
2642 case 'Q': type = VIM_QUESTION; break;
2643 case 'I': type = VIM_INFO; break;
2644 case 'W': type = VIM_WARNING; break;
2645 case 'G': type = VIM_GENERIC; break;
2646 }
2647 }
2648 }
2649 }
2650 }
2651
2652 if (buttons == NULL || *buttons == NUL)
2653 buttons = (char_u *)_("&Ok");
2654
2655 if (!error)
2656 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2657 def, NULL, FALSE);
2658#endif
2659}
2660
2661/*
2662 * "copy()" function
2663 */
2664 static void
2665f_copy(typval_T *argvars, typval_T *rettv)
2666{
2667 item_copy(&argvars[0], rettv, FALSE, 0);
2668}
2669
2670#ifdef FEAT_FLOAT
2671/*
2672 * "cos()" function
2673 */
2674 static void
2675f_cos(typval_T *argvars, typval_T *rettv)
2676{
2677 float_T f = 0.0;
2678
2679 rettv->v_type = VAR_FLOAT;
2680 if (get_float_arg(argvars, &f) == OK)
2681 rettv->vval.v_float = cos(f);
2682 else
2683 rettv->vval.v_float = 0.0;
2684}
2685
2686/*
2687 * "cosh()" function
2688 */
2689 static void
2690f_cosh(typval_T *argvars, typval_T *rettv)
2691{
2692 float_T f = 0.0;
2693
2694 rettv->v_type = VAR_FLOAT;
2695 if (get_float_arg(argvars, &f) == OK)
2696 rettv->vval.v_float = cosh(f);
2697 else
2698 rettv->vval.v_float = 0.0;
2699}
2700#endif
2701
2702/*
2703 * "count()" function
2704 */
2705 static void
2706f_count(typval_T *argvars, typval_T *rettv)
2707{
2708 long n = 0;
2709 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002710 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711
Bram Moolenaar9966b212017-07-28 16:46:57 +02002712 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002713 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002714
2715 if (argvars[0].v_type == VAR_STRING)
2716 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002717 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002718 char_u *p = argvars[0].vval.v_string;
2719 char_u *next;
2720
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002721 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002722 {
2723 if (ic)
2724 {
2725 size_t len = STRLEN(expr);
2726
2727 while (*p != NUL)
2728 {
2729 if (MB_STRNICMP(p, expr, len) == 0)
2730 {
2731 ++n;
2732 p += len;
2733 }
2734 else
2735 MB_PTR_ADV(p);
2736 }
2737 }
2738 else
2739 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2740 != NULL)
2741 {
2742 ++n;
2743 p = next + STRLEN(expr);
2744 }
2745 }
2746
2747 }
2748 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002749 {
2750 listitem_T *li;
2751 list_T *l;
2752 long idx;
2753
2754 if ((l = argvars[0].vval.v_list) != NULL)
2755 {
2756 li = l->lv_first;
2757 if (argvars[2].v_type != VAR_UNKNOWN)
2758 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002759 if (argvars[3].v_type != VAR_UNKNOWN)
2760 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002761 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 if (!error)
2763 {
2764 li = list_find(l, idx);
2765 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002766 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002767 }
2768 }
2769 if (error)
2770 li = NULL;
2771 }
2772
2773 for ( ; li != NULL; li = li->li_next)
2774 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2775 ++n;
2776 }
2777 }
2778 else if (argvars[0].v_type == VAR_DICT)
2779 {
2780 int todo;
2781 dict_T *d;
2782 hashitem_T *hi;
2783
2784 if ((d = argvars[0].vval.v_dict) != NULL)
2785 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002786 if (argvars[2].v_type != VAR_UNKNOWN)
2787 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002788 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002789 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002790 }
2791
2792 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2793 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2794 {
2795 if (!HASHITEM_EMPTY(hi))
2796 {
2797 --todo;
2798 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2799 ++n;
2800 }
2801 }
2802 }
2803 }
2804 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002805 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002806 rettv->vval.v_number = n;
2807}
2808
2809/*
2810 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2811 *
2812 * Checks the existence of a cscope connection.
2813 */
2814 static void
2815f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2816{
2817#ifdef FEAT_CSCOPE
2818 int num = 0;
2819 char_u *dbpath = NULL;
2820 char_u *prepend = NULL;
2821 char_u buf[NUMBUFLEN];
2822
2823 if (argvars[0].v_type != VAR_UNKNOWN
2824 && argvars[1].v_type != VAR_UNKNOWN)
2825 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002826 num = (int)tv_get_number(&argvars[0]);
2827 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002828 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002829 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002830 }
2831
2832 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2833#endif
2834}
2835
2836/*
2837 * "cursor(lnum, col)" function, or
2838 * "cursor(list)"
2839 *
2840 * Moves the cursor to the specified line and column.
2841 * Returns 0 when the position could be set, -1 otherwise.
2842 */
2843 static void
2844f_cursor(typval_T *argvars, typval_T *rettv)
2845{
2846 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002847 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848 int set_curswant = TRUE;
2849
2850 rettv->vval.v_number = -1;
2851 if (argvars[1].v_type == VAR_UNKNOWN)
2852 {
2853 pos_T pos;
2854 colnr_T curswant = -1;
2855
2856 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2857 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002858 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002859 return;
2860 }
2861 line = pos.lnum;
2862 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002863 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002864 if (curswant >= 0)
2865 {
2866 curwin->w_curswant = curswant - 1;
2867 set_curswant = FALSE;
2868 }
2869 }
2870 else
2871 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002872 line = tv_get_lnum(argvars);
2873 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002874 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002875 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002877 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878 return; /* type error; errmsg already given */
2879 if (line > 0)
2880 curwin->w_cursor.lnum = line;
2881 if (col > 0)
2882 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002883 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002884
2885 /* Make sure the cursor is in a valid position. */
2886 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002887 /* Correct cursor for multi-byte character. */
2888 if (has_mbyte)
2889 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002890
2891 curwin->w_set_curswant = set_curswant;
2892 rettv->vval.v_number = 0;
2893}
2894
Bram Moolenaar4f974752019-02-17 17:44:42 +01002895#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002896/*
2897 * "debugbreak()" function
2898 */
2899 static void
2900f_debugbreak(typval_T *argvars, typval_T *rettv)
2901{
2902 int pid;
2903
2904 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002905 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002906 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002907 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002908 else
2909 {
2910 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2911
2912 if (hProcess != NULL)
2913 {
2914 DebugBreakProcess(hProcess);
2915 CloseHandle(hProcess);
2916 rettv->vval.v_number = OK;
2917 }
2918 }
2919}
2920#endif
2921
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922/*
2923 * "deepcopy()" function
2924 */
2925 static void
2926f_deepcopy(typval_T *argvars, typval_T *rettv)
2927{
2928 int noref = 0;
2929 int copyID;
2930
2931 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002932 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002934 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002935 else
2936 {
2937 copyID = get_copyID();
2938 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2939 }
2940}
2941
2942/*
2943 * "delete()" function
2944 */
2945 static void
2946f_delete(typval_T *argvars, typval_T *rettv)
2947{
2948 char_u nbuf[NUMBUFLEN];
2949 char_u *name;
2950 char_u *flags;
2951
2952 rettv->vval.v_number = -1;
2953 if (check_restricted() || check_secure())
2954 return;
2955
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002956 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002957 if (name == NULL || *name == NUL)
2958 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002959 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002960 return;
2961 }
2962
2963 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002964 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002965 else
2966 flags = (char_u *)"";
2967
2968 if (*flags == NUL)
2969 /* delete a file */
2970 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2971 else if (STRCMP(flags, "d") == 0)
2972 /* delete an empty directory */
2973 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2974 else if (STRCMP(flags, "rf") == 0)
2975 /* delete a directory recursively */
2976 rettv->vval.v_number = delete_recursive(name);
2977 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002978 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002979}
2980
2981/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002982 * "deletebufline()" function
2983 */
2984 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002985f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002986{
2987 buf_T *buf;
2988 linenr_T first, last;
2989 linenr_T lnum;
2990 long count;
2991 int is_curbuf;
2992 buf_T *curbuf_save = NULL;
2993 win_T *curwin_save = NULL;
2994 tabpage_T *tp;
2995 win_T *wp;
2996
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002997 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002998 if (buf == NULL)
2999 {
3000 rettv->vval.v_number = 1; /* FAIL */
3001 return;
3002 }
3003 is_curbuf = buf == curbuf;
3004
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003005 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003006 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003007 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003008 else
3009 last = first;
3010
3011 if (buf->b_ml.ml_mfp == NULL || first < 1
3012 || first > buf->b_ml.ml_line_count || last < first)
3013 {
3014 rettv->vval.v_number = 1; /* FAIL */
3015 return;
3016 }
3017
3018 if (!is_curbuf)
3019 {
3020 curbuf_save = curbuf;
3021 curwin_save = curwin;
3022 curbuf = buf;
3023 find_win_for_curbuf();
3024 }
3025 if (last > curbuf->b_ml.ml_line_count)
3026 last = curbuf->b_ml.ml_line_count;
3027 count = last - first + 1;
3028
3029 // When coming here from Insert mode, sync undo, so that this can be
3030 // undone separately from what was previously inserted.
3031 if (u_sync_once == 2)
3032 {
3033 u_sync_once = 1; // notify that u_sync() was called
3034 u_sync(TRUE);
3035 }
3036
3037 if (u_save(first - 1, last + 1) == FAIL)
3038 {
3039 rettv->vval.v_number = 1; /* FAIL */
3040 return;
3041 }
3042
3043 for (lnum = first; lnum <= last; ++lnum)
3044 ml_delete(first, TRUE);
3045
3046 FOR_ALL_TAB_WINDOWS(tp, wp)
3047 if (wp->w_buffer == buf)
3048 {
3049 if (wp->w_cursor.lnum > last)
3050 wp->w_cursor.lnum -= count;
3051 else if (wp->w_cursor.lnum> first)
3052 wp->w_cursor.lnum = first;
3053 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3054 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3055 }
3056 check_cursor_col();
3057 deleted_lines_mark(first, count);
3058
3059 if (!is_curbuf)
3060 {
3061 curbuf = curbuf_save;
3062 curwin = curwin_save;
3063 }
3064}
3065
3066/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003067 * "did_filetype()" function
3068 */
3069 static void
3070f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3071{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003072 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073}
3074
3075/*
3076 * "diff_filler()" function
3077 */
3078 static void
3079f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3080{
3081#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003082 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083#endif
3084}
3085
3086/*
3087 * "diff_hlID()" function
3088 */
3089 static void
3090f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3091{
3092#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003093 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003094 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003095 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 static int fnum = 0;
3097 static int change_start = 0;
3098 static int change_end = 0;
3099 static hlf_T hlID = (hlf_T)0;
3100 int filler_lines;
3101 int col;
3102
3103 if (lnum < 0) /* ignore type error in {lnum} arg */
3104 lnum = 0;
3105 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003106 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003107 || fnum != curbuf->b_fnum)
3108 {
3109 /* New line, buffer, change: need to get the values. */
3110 filler_lines = diff_check(curwin, lnum);
3111 if (filler_lines < 0)
3112 {
3113 if (filler_lines == -1)
3114 {
3115 change_start = MAXCOL;
3116 change_end = -1;
3117 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3118 hlID = HLF_ADD; /* added line */
3119 else
3120 hlID = HLF_CHD; /* changed line */
3121 }
3122 else
3123 hlID = HLF_ADD; /* added line */
3124 }
3125 else
3126 hlID = (hlf_T)0;
3127 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003128 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003129 fnum = curbuf->b_fnum;
3130 }
3131
3132 if (hlID == HLF_CHD || hlID == HLF_TXD)
3133 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003134 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003135 if (col >= change_start && col <= change_end)
3136 hlID = HLF_TXD; /* changed text */
3137 else
3138 hlID = HLF_CHD; /* changed line */
3139 }
3140 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3141#endif
3142}
3143
3144/*
3145 * "empty({expr})" function
3146 */
3147 static void
3148f_empty(typval_T *argvars, typval_T *rettv)
3149{
3150 int n = FALSE;
3151
3152 switch (argvars[0].v_type)
3153 {
3154 case VAR_STRING:
3155 case VAR_FUNC:
3156 n = argvars[0].vval.v_string == NULL
3157 || *argvars[0].vval.v_string == NUL;
3158 break;
3159 case VAR_PARTIAL:
3160 n = FALSE;
3161 break;
3162 case VAR_NUMBER:
3163 n = argvars[0].vval.v_number == 0;
3164 break;
3165 case VAR_FLOAT:
3166#ifdef FEAT_FLOAT
3167 n = argvars[0].vval.v_float == 0.0;
3168 break;
3169#endif
3170 case VAR_LIST:
3171 n = argvars[0].vval.v_list == NULL
3172 || argvars[0].vval.v_list->lv_first == NULL;
3173 break;
3174 case VAR_DICT:
3175 n = argvars[0].vval.v_dict == NULL
3176 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3177 break;
3178 case VAR_SPECIAL:
3179 n = argvars[0].vval.v_number != VVAL_TRUE;
3180 break;
3181
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003182 case VAR_BLOB:
3183 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003184 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3185 break;
3186
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003187 case VAR_JOB:
3188#ifdef FEAT_JOB_CHANNEL
3189 n = argvars[0].vval.v_job == NULL
3190 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3191 break;
3192#endif
3193 case VAR_CHANNEL:
3194#ifdef FEAT_JOB_CHANNEL
3195 n = argvars[0].vval.v_channel == NULL
3196 || !channel_is_open(argvars[0].vval.v_channel);
3197 break;
3198#endif
3199 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003200 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003201 n = TRUE;
3202 break;
3203 }
3204
3205 rettv->vval.v_number = n;
3206}
3207
3208/*
3209 * "escape({string}, {chars})" function
3210 */
3211 static void
3212f_escape(typval_T *argvars, typval_T *rettv)
3213{
3214 char_u buf[NUMBUFLEN];
3215
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003216 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3217 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003218 rettv->v_type = VAR_STRING;
3219}
3220
3221/*
3222 * "eval()" function
3223 */
3224 static void
3225f_eval(typval_T *argvars, typval_T *rettv)
3226{
3227 char_u *s, *p;
3228
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003229 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230 if (s != NULL)
3231 s = skipwhite(s);
3232
3233 p = s;
3234 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3235 {
3236 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003237 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 need_clr_eos = FALSE;
3239 rettv->v_type = VAR_NUMBER;
3240 rettv->vval.v_number = 0;
3241 }
3242 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003243 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003244}
3245
3246/*
3247 * "eventhandler()" function
3248 */
3249 static void
3250f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3251{
3252 rettv->vval.v_number = vgetc_busy;
3253}
3254
3255/*
3256 * "executable()" function
3257 */
3258 static void
3259f_executable(typval_T *argvars, typval_T *rettv)
3260{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003261 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003262
3263 /* Check in $PATH and also check directly if there is a directory name. */
3264 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3265 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3266}
3267
3268static garray_T redir_execute_ga;
3269
3270/*
3271 * Append "value[value_len]" to the execute() output.
3272 */
3273 void
3274execute_redir_str(char_u *value, int value_len)
3275{
3276 int len;
3277
3278 if (value_len == -1)
3279 len = (int)STRLEN(value); /* Append the entire string */
3280 else
3281 len = value_len; /* Append only "value_len" characters */
3282 if (ga_grow(&redir_execute_ga, len) == OK)
3283 {
3284 mch_memmove((char *)redir_execute_ga.ga_data
3285 + redir_execute_ga.ga_len, value, len);
3286 redir_execute_ga.ga_len += len;
3287 }
3288}
3289
3290/*
3291 * Get next line from a list.
3292 * Called by do_cmdline() to get the next line.
3293 * Returns allocated string, or NULL for end of function.
3294 */
3295
3296 static char_u *
3297get_list_line(
3298 int c UNUSED,
3299 void *cookie,
3300 int indent UNUSED)
3301{
3302 listitem_T **p = (listitem_T **)cookie;
3303 listitem_T *item = *p;
3304 char_u buf[NUMBUFLEN];
3305 char_u *s;
3306
3307 if (item == NULL)
3308 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003309 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003310 *p = item->li_next;
3311 return s == NULL ? NULL : vim_strsave(s);
3312}
3313
3314/*
3315 * "execute()" function
3316 */
3317 static void
3318f_execute(typval_T *argvars, typval_T *rettv)
3319{
3320 char_u *cmd = NULL;
3321 list_T *list = NULL;
3322 int save_msg_silent = msg_silent;
3323 int save_emsg_silent = emsg_silent;
3324 int save_emsg_noredir = emsg_noredir;
3325 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003326 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003327 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003328 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003329 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003330
3331 rettv->vval.v_string = NULL;
3332 rettv->v_type = VAR_STRING;
3333
3334 if (argvars[0].v_type == VAR_LIST)
3335 {
3336 list = argvars[0].vval.v_list;
3337 if (list == NULL || list->lv_first == NULL)
3338 /* empty list, no commands, empty output */
3339 return;
3340 ++list->lv_refcount;
3341 }
3342 else
3343 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003344 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003345 if (cmd == NULL)
3346 return;
3347 }
3348
3349 if (argvars[1].v_type != VAR_UNKNOWN)
3350 {
3351 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003352 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003353
3354 if (s == NULL)
3355 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003356 if (*s == NUL)
3357 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003358 if (STRNCMP(s, "silent", 6) == 0)
3359 ++msg_silent;
3360 if (STRCMP(s, "silent!") == 0)
3361 {
3362 emsg_silent = TRUE;
3363 emsg_noredir = TRUE;
3364 }
3365 }
3366 else
3367 ++msg_silent;
3368
3369 if (redir_execute)
3370 save_ga = redir_execute_ga;
3371 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3372 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003373 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003374 if (!echo_output)
3375 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376
3377 if (cmd != NULL)
3378 do_cmdline_cmd(cmd);
3379 else
3380 {
3381 listitem_T *item = list->lv_first;
3382
3383 do_cmdline(NULL, get_list_line, (void *)&item,
3384 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3385 --list->lv_refcount;
3386 }
3387
Bram Moolenaard297f352017-01-29 20:31:21 +01003388 /* Need to append a NUL to the result. */
3389 if (ga_grow(&redir_execute_ga, 1) == OK)
3390 {
3391 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3392 rettv->vval.v_string = redir_execute_ga.ga_data;
3393 }
3394 else
3395 {
3396 ga_clear(&redir_execute_ga);
3397 rettv->vval.v_string = NULL;
3398 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003399 msg_silent = save_msg_silent;
3400 emsg_silent = save_emsg_silent;
3401 emsg_noredir = save_emsg_noredir;
3402
3403 redir_execute = save_redir_execute;
3404 if (redir_execute)
3405 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003406 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003407
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003408 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003409 if (echo_output)
3410 // When not working silently: put it in column zero. A following
3411 // "echon" will overwrite the message, unavoidably.
3412 msg_col = 0;
3413 else
3414 // When working silently: Put it back where it was, since nothing
3415 // should have been written.
3416 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003417}
3418
3419/*
3420 * "exepath()" function
3421 */
3422 static void
3423f_exepath(typval_T *argvars, typval_T *rettv)
3424{
3425 char_u *p = NULL;
3426
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003427 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428 rettv->v_type = VAR_STRING;
3429 rettv->vval.v_string = p;
3430}
3431
3432/*
3433 * "exists()" function
3434 */
3435 static void
3436f_exists(typval_T *argvars, typval_T *rettv)
3437{
3438 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003439 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003440
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003441 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003442 if (*p == '$') /* environment variable */
3443 {
3444 /* first try "normal" environment variables (fast) */
3445 if (mch_getenv(p + 1) != NULL)
3446 n = TRUE;
3447 else
3448 {
3449 /* try expanding things like $VIM and ${HOME} */
3450 p = expand_env_save(p);
3451 if (p != NULL && *p != '$')
3452 n = TRUE;
3453 vim_free(p);
3454 }
3455 }
3456 else if (*p == '&' || *p == '+') /* option */
3457 {
3458 n = (get_option_tv(&p, NULL, TRUE) == OK);
3459 if (*skipwhite(p) != NUL)
3460 n = FALSE; /* trailing garbage */
3461 }
3462 else if (*p == '*') /* internal or user defined function */
3463 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003464 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003465 }
3466 else if (*p == ':')
3467 {
3468 n = cmd_exists(p + 1);
3469 }
3470 else if (*p == '#')
3471 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472 if (p[1] == '#')
3473 n = autocmd_supported(p + 2);
3474 else
3475 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003476 }
3477 else /* internal variable */
3478 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003479 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003480 }
3481
3482 rettv->vval.v_number = n;
3483}
3484
3485#ifdef FEAT_FLOAT
3486/*
3487 * "exp()" function
3488 */
3489 static void
3490f_exp(typval_T *argvars, typval_T *rettv)
3491{
3492 float_T f = 0.0;
3493
3494 rettv->v_type = VAR_FLOAT;
3495 if (get_float_arg(argvars, &f) == OK)
3496 rettv->vval.v_float = exp(f);
3497 else
3498 rettv->vval.v_float = 0.0;
3499}
3500#endif
3501
3502/*
3503 * "expand()" function
3504 */
3505 static void
3506f_expand(typval_T *argvars, typval_T *rettv)
3507{
3508 char_u *s;
3509 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003510 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003511 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3512 expand_T xpc;
3513 int error = FALSE;
3514 char_u *result;
3515
3516 rettv->v_type = VAR_STRING;
3517 if (argvars[1].v_type != VAR_UNKNOWN
3518 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003519 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 && !error)
3521 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003522 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003523 }
3524
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003525 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003526 if (*s == '%' || *s == '#' || *s == '<')
3527 {
3528 ++emsg_off;
3529 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3530 --emsg_off;
3531 if (rettv->v_type == VAR_LIST)
3532 {
3533 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3534 list_append_string(rettv->vval.v_list, result, -1);
3535 else
3536 vim_free(result);
3537 }
3538 else
3539 rettv->vval.v_string = result;
3540 }
3541 else
3542 {
3543 /* When the optional second argument is non-zero, don't remove matches
3544 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3545 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003546 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003547 options |= WILD_KEEP_ALL;
3548 if (!error)
3549 {
3550 ExpandInit(&xpc);
3551 xpc.xp_context = EXPAND_FILES;
3552 if (p_wic)
3553 options += WILD_ICASE;
3554 if (rettv->v_type == VAR_STRING)
3555 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3556 options, WILD_ALL);
3557 else if (rettv_list_alloc(rettv) != FAIL)
3558 {
3559 int i;
3560
3561 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3562 for (i = 0; i < xpc.xp_numfiles; i++)
3563 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3564 ExpandCleanup(&xpc);
3565 }
3566 }
3567 else
3568 rettv->vval.v_string = NULL;
3569 }
3570}
3571
3572/*
3573 * "extend(list, list [, idx])" function
3574 * "extend(dict, dict [, action])" function
3575 */
3576 static void
3577f_extend(typval_T *argvars, typval_T *rettv)
3578{
3579 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3580
3581 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3582 {
3583 list_T *l1, *l2;
3584 listitem_T *item;
3585 long before;
3586 int error = FALSE;
3587
3588 l1 = argvars[0].vval.v_list;
3589 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003590 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591 && l2 != NULL)
3592 {
3593 if (argvars[2].v_type != VAR_UNKNOWN)
3594 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003595 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003596 if (error)
3597 return; /* type error; errmsg already given */
3598
3599 if (before == l1->lv_len)
3600 item = NULL;
3601 else
3602 {
3603 item = list_find(l1, before);
3604 if (item == NULL)
3605 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003606 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607 return;
3608 }
3609 }
3610 }
3611 else
3612 item = NULL;
3613 list_extend(l1, l2, item);
3614
3615 copy_tv(&argvars[0], rettv);
3616 }
3617 }
3618 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3619 {
3620 dict_T *d1, *d2;
3621 char_u *action;
3622 int i;
3623
3624 d1 = argvars[0].vval.v_dict;
3625 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003626 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003627 && d2 != NULL)
3628 {
3629 /* Check the third argument. */
3630 if (argvars[2].v_type != VAR_UNKNOWN)
3631 {
3632 static char *(av[]) = {"keep", "force", "error"};
3633
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003634 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635 if (action == NULL)
3636 return; /* type error; errmsg already given */
3637 for (i = 0; i < 3; ++i)
3638 if (STRCMP(action, av[i]) == 0)
3639 break;
3640 if (i == 3)
3641 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003642 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643 return;
3644 }
3645 }
3646 else
3647 action = (char_u *)"force";
3648
3649 dict_extend(d1, d2, action);
3650
3651 copy_tv(&argvars[0], rettv);
3652 }
3653 }
3654 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003655 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656}
3657
3658/*
3659 * "feedkeys()" function
3660 */
3661 static void
3662f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3663{
3664 int remap = TRUE;
3665 int insert = FALSE;
3666 char_u *keys, *flags;
3667 char_u nbuf[NUMBUFLEN];
3668 int typed = FALSE;
3669 int execute = FALSE;
3670 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003671 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003672 char_u *keys_esc;
3673
3674 /* This is not allowed in the sandbox. If the commands would still be
3675 * executed in the sandbox it would be OK, but it probably happens later,
3676 * when "sandbox" is no longer set. */
3677 if (check_secure())
3678 return;
3679
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003680 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681
3682 if (argvars[1].v_type != VAR_UNKNOWN)
3683 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003684 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685 for ( ; *flags != NUL; ++flags)
3686 {
3687 switch (*flags)
3688 {
3689 case 'n': remap = FALSE; break;
3690 case 'm': remap = TRUE; break;
3691 case 't': typed = TRUE; break;
3692 case 'i': insert = TRUE; break;
3693 case 'x': execute = TRUE; break;
3694 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003695 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003696 }
3697 }
3698 }
3699
3700 if (*keys != NUL || execute)
3701 {
3702 /* Need to escape K_SPECIAL and CSI before putting the string in the
3703 * typeahead buffer. */
3704 keys_esc = vim_strsave_escape_csi(keys);
3705 if (keys_esc != NULL)
3706 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003707 if (lowlevel)
3708 {
3709#ifdef USE_INPUT_BUF
3710 add_to_input_buf(keys, (int)STRLEN(keys));
3711#else
3712 emsg(_("E980: lowlevel input not supported"));
3713#endif
3714 }
3715 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003716 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003717 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003718 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003719 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003720#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003721 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003722#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003723 )
3724 typebuf_was_filled = TRUE;
3725 }
3726 vim_free(keys_esc);
3727
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003728 if (execute)
3729 {
3730 int save_msg_scroll = msg_scroll;
3731
3732 /* Avoid a 1 second delay when the keys start Insert mode. */
3733 msg_scroll = FALSE;
3734
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003735 if (!dangerous)
3736 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003737 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003738 if (!dangerous)
3739 --ex_normal_busy;
3740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003741 msg_scroll |= save_msg_scroll;
3742 }
3743 }
3744 }
3745}
3746
3747/*
3748 * "filereadable()" function
3749 */
3750 static void
3751f_filereadable(typval_T *argvars, typval_T *rettv)
3752{
3753 int fd;
3754 char_u *p;
3755 int n;
3756
3757#ifndef O_NONBLOCK
3758# define O_NONBLOCK 0
3759#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003760 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003761 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3762 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3763 {
3764 n = TRUE;
3765 close(fd);
3766 }
3767 else
3768 n = FALSE;
3769
3770 rettv->vval.v_number = n;
3771}
3772
3773/*
3774 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3775 * rights to write into.
3776 */
3777 static void
3778f_filewritable(typval_T *argvars, typval_T *rettv)
3779{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003780 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781}
3782
3783 static void
3784findfilendir(
3785 typval_T *argvars UNUSED,
3786 typval_T *rettv,
3787 int find_what UNUSED)
3788{
3789#ifdef FEAT_SEARCHPATH
3790 char_u *fname;
3791 char_u *fresult = NULL;
3792 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3793 char_u *p;
3794 char_u pathbuf[NUMBUFLEN];
3795 int count = 1;
3796 int first = TRUE;
3797 int error = FALSE;
3798#endif
3799
3800 rettv->vval.v_string = NULL;
3801 rettv->v_type = VAR_STRING;
3802
3803#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003804 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003805
3806 if (argvars[1].v_type != VAR_UNKNOWN)
3807 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003808 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003809 if (p == NULL)
3810 error = TRUE;
3811 else
3812 {
3813 if (*p != NUL)
3814 path = p;
3815
3816 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003817 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003818 }
3819 }
3820
3821 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3822 error = TRUE;
3823
3824 if (*fname != NUL && !error)
3825 {
3826 do
3827 {
3828 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3829 vim_free(fresult);
3830 fresult = find_file_in_path_option(first ? fname : NULL,
3831 first ? (int)STRLEN(fname) : 0,
3832 0, first, path,
3833 find_what,
3834 curbuf->b_ffname,
3835 find_what == FINDFILE_DIR
3836 ? (char_u *)"" : curbuf->b_p_sua);
3837 first = FALSE;
3838
3839 if (fresult != NULL && rettv->v_type == VAR_LIST)
3840 list_append_string(rettv->vval.v_list, fresult, -1);
3841
3842 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3843 }
3844
3845 if (rettv->v_type == VAR_STRING)
3846 rettv->vval.v_string = fresult;
3847#endif
3848}
3849
3850/*
3851 * "filter()" function
3852 */
3853 static void
3854f_filter(typval_T *argvars, typval_T *rettv)
3855{
3856 filter_map(argvars, rettv, FALSE);
3857}
3858
3859/*
3860 * "finddir({fname}[, {path}[, {count}]])" function
3861 */
3862 static void
3863f_finddir(typval_T *argvars, typval_T *rettv)
3864{
3865 findfilendir(argvars, rettv, FINDFILE_DIR);
3866}
3867
3868/*
3869 * "findfile({fname}[, {path}[, {count}]])" function
3870 */
3871 static void
3872f_findfile(typval_T *argvars, typval_T *rettv)
3873{
3874 findfilendir(argvars, rettv, FINDFILE_FILE);
3875}
3876
3877#ifdef FEAT_FLOAT
3878/*
3879 * "float2nr({float})" function
3880 */
3881 static void
3882f_float2nr(typval_T *argvars, typval_T *rettv)
3883{
3884 float_T f = 0.0;
3885
3886 if (get_float_arg(argvars, &f) == OK)
3887 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003888 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003889 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003890 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003891 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003892 else
3893 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003894 }
3895}
3896
3897/*
3898 * "floor({float})" function
3899 */
3900 static void
3901f_floor(typval_T *argvars, typval_T *rettv)
3902{
3903 float_T f = 0.0;
3904
3905 rettv->v_type = VAR_FLOAT;
3906 if (get_float_arg(argvars, &f) == OK)
3907 rettv->vval.v_float = floor(f);
3908 else
3909 rettv->vval.v_float = 0.0;
3910}
3911
3912/*
3913 * "fmod()" function
3914 */
3915 static void
3916f_fmod(typval_T *argvars, typval_T *rettv)
3917{
3918 float_T fx = 0.0, fy = 0.0;
3919
3920 rettv->v_type = VAR_FLOAT;
3921 if (get_float_arg(argvars, &fx) == OK
3922 && get_float_arg(&argvars[1], &fy) == OK)
3923 rettv->vval.v_float = fmod(fx, fy);
3924 else
3925 rettv->vval.v_float = 0.0;
3926}
3927#endif
3928
3929/*
3930 * "fnameescape({string})" function
3931 */
3932 static void
3933f_fnameescape(typval_T *argvars, typval_T *rettv)
3934{
3935 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003936 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003937 rettv->v_type = VAR_STRING;
3938}
3939
3940/*
3941 * "fnamemodify({fname}, {mods})" function
3942 */
3943 static void
3944f_fnamemodify(typval_T *argvars, typval_T *rettv)
3945{
3946 char_u *fname;
3947 char_u *mods;
3948 int usedlen = 0;
3949 int len;
3950 char_u *fbuf = NULL;
3951 char_u buf[NUMBUFLEN];
3952
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003953 fname = tv_get_string_chk(&argvars[0]);
3954 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003955 if (fname == NULL || mods == NULL)
3956 fname = NULL;
3957 else
3958 {
3959 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003960 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003961 }
3962
3963 rettv->v_type = VAR_STRING;
3964 if (fname == NULL)
3965 rettv->vval.v_string = NULL;
3966 else
3967 rettv->vval.v_string = vim_strnsave(fname, len);
3968 vim_free(fbuf);
3969}
3970
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003971/*
3972 * "foldclosed()" function
3973 */
3974 static void
3975foldclosed_both(
3976 typval_T *argvars UNUSED,
3977 typval_T *rettv,
3978 int end UNUSED)
3979{
3980#ifdef FEAT_FOLDING
3981 linenr_T lnum;
3982 linenr_T first, last;
3983
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003984 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003985 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3986 {
3987 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3988 {
3989 if (end)
3990 rettv->vval.v_number = (varnumber_T)last;
3991 else
3992 rettv->vval.v_number = (varnumber_T)first;
3993 return;
3994 }
3995 }
3996#endif
3997 rettv->vval.v_number = -1;
3998}
3999
4000/*
4001 * "foldclosed()" function
4002 */
4003 static void
4004f_foldclosed(typval_T *argvars, typval_T *rettv)
4005{
4006 foldclosed_both(argvars, rettv, FALSE);
4007}
4008
4009/*
4010 * "foldclosedend()" function
4011 */
4012 static void
4013f_foldclosedend(typval_T *argvars, typval_T *rettv)
4014{
4015 foldclosed_both(argvars, rettv, TRUE);
4016}
4017
4018/*
4019 * "foldlevel()" function
4020 */
4021 static void
4022f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4023{
4024#ifdef FEAT_FOLDING
4025 linenr_T lnum;
4026
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004027 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004028 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4029 rettv->vval.v_number = foldLevel(lnum);
4030#endif
4031}
4032
4033/*
4034 * "foldtext()" function
4035 */
4036 static void
4037f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4038{
4039#ifdef FEAT_FOLDING
4040 linenr_T foldstart;
4041 linenr_T foldend;
4042 char_u *dashes;
4043 linenr_T lnum;
4044 char_u *s;
4045 char_u *r;
4046 int len;
4047 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004048 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004049#endif
4050
4051 rettv->v_type = VAR_STRING;
4052 rettv->vval.v_string = NULL;
4053#ifdef FEAT_FOLDING
4054 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4055 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4056 dashes = get_vim_var_str(VV_FOLDDASHES);
4057 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4058 && dashes != NULL)
4059 {
4060 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004061 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004062 if (!linewhite(lnum))
4063 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004064
4065 /* Find interesting text in this line. */
4066 s = skipwhite(ml_get(lnum));
4067 /* skip C comment-start */
4068 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4069 {
4070 s = skipwhite(s + 2);
4071 if (*skipwhite(s) == NUL
4072 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4073 {
4074 s = skipwhite(ml_get(lnum + 1));
4075 if (*s == '*')
4076 s = skipwhite(s + 1);
4077 }
4078 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004079 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004080 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004081 r = alloc((unsigned)(STRLEN(txt)
4082 + STRLEN(dashes) /* for %s */
4083 + 20 /* for %3ld */
4084 + STRLEN(s))); /* concatenated */
4085 if (r != NULL)
4086 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004087 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004088 len = (int)STRLEN(r);
4089 STRCAT(r, s);
4090 /* remove 'foldmarker' and 'commentstring' */
4091 foldtext_cleanup(r + len);
4092 rettv->vval.v_string = r;
4093 }
4094 }
4095#endif
4096}
4097
4098/*
4099 * "foldtextresult(lnum)" function
4100 */
4101 static void
4102f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4103{
4104#ifdef FEAT_FOLDING
4105 linenr_T lnum;
4106 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004107 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004108 foldinfo_T foldinfo;
4109 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004110 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004111#endif
4112
4113 rettv->v_type = VAR_STRING;
4114 rettv->vval.v_string = NULL;
4115#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004116 if (entered)
4117 return; /* reject recursive use */
4118 entered = TRUE;
4119
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004120 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004121 /* treat illegal types and illegal string values for {lnum} the same */
4122 if (lnum < 0)
4123 lnum = 0;
4124 fold_count = foldedCount(curwin, lnum, &foldinfo);
4125 if (fold_count > 0)
4126 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004127 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4128 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004129 if (text == buf)
4130 text = vim_strsave(text);
4131 rettv->vval.v_string = text;
4132 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004133
4134 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004135#endif
4136}
4137
4138/*
4139 * "foreground()" function
4140 */
4141 static void
4142f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4143{
4144#ifdef FEAT_GUI
4145 if (gui.in_use)
4146 gui_mch_set_foreground();
4147#else
Bram Moolenaar4f974752019-02-17 17:44:42 +01004148# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004149 win32_set_foreground();
4150# endif
4151#endif
4152}
4153
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004154 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004155common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156{
4157 char_u *s;
4158 char_u *name;
4159 int use_string = FALSE;
4160 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004161 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004162
4163 if (argvars[0].v_type == VAR_FUNC)
4164 {
4165 /* function(MyFunc, [arg], dict) */
4166 s = argvars[0].vval.v_string;
4167 }
4168 else if (argvars[0].v_type == VAR_PARTIAL
4169 && argvars[0].vval.v_partial != NULL)
4170 {
4171 /* function(dict.MyFunc, [arg]) */
4172 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004173 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004174 }
4175 else
4176 {
4177 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004178 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004179 use_string = TRUE;
4180 }
4181
Bram Moolenaar843b8842016-08-21 14:36:15 +02004182 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004183 {
4184 name = s;
4185 trans_name = trans_function_name(&name, FALSE,
4186 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4187 if (*name != NUL)
4188 s = NULL;
4189 }
4190
Bram Moolenaar843b8842016-08-21 14:36:15 +02004191 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4192 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004193 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004194 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004195 else if (trans_name != NULL && (is_funcref
4196 ? find_func(trans_name) == NULL
4197 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004198 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004199 else
4200 {
4201 int dict_idx = 0;
4202 int arg_idx = 0;
4203 list_T *list = NULL;
4204
4205 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4206 {
4207 char sid_buf[25];
4208 int off = *s == 's' ? 2 : 5;
4209
4210 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4211 * also be called from another script. Using trans_function_name()
4212 * would also work, but some plugins depend on the name being
4213 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004214 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004215 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4216 if (name != NULL)
4217 {
4218 STRCPY(name, sid_buf);
4219 STRCAT(name, s + off);
4220 }
4221 }
4222 else
4223 name = vim_strsave(s);
4224
4225 if (argvars[1].v_type != VAR_UNKNOWN)
4226 {
4227 if (argvars[2].v_type != VAR_UNKNOWN)
4228 {
4229 /* function(name, [args], dict) */
4230 arg_idx = 1;
4231 dict_idx = 2;
4232 }
4233 else if (argvars[1].v_type == VAR_DICT)
4234 /* function(name, dict) */
4235 dict_idx = 1;
4236 else
4237 /* function(name, [args]) */
4238 arg_idx = 1;
4239 if (dict_idx > 0)
4240 {
4241 if (argvars[dict_idx].v_type != VAR_DICT)
4242 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004243 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004244 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004245 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004246 }
4247 if (argvars[dict_idx].vval.v_dict == NULL)
4248 dict_idx = 0;
4249 }
4250 if (arg_idx > 0)
4251 {
4252 if (argvars[arg_idx].v_type != VAR_LIST)
4253 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004254 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004256 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004257 }
4258 list = argvars[arg_idx].vval.v_list;
4259 if (list == NULL || list->lv_len == 0)
4260 arg_idx = 0;
4261 }
4262 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004263 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004264 {
4265 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4266
4267 /* result is a VAR_PARTIAL */
4268 if (pt == NULL)
4269 vim_free(name);
4270 else
4271 {
4272 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4273 {
4274 listitem_T *li;
4275 int i = 0;
4276 int arg_len = 0;
4277 int lv_len = 0;
4278
4279 if (arg_pt != NULL)
4280 arg_len = arg_pt->pt_argc;
4281 if (list != NULL)
4282 lv_len = list->lv_len;
4283 pt->pt_argc = arg_len + lv_len;
4284 pt->pt_argv = (typval_T *)alloc(
4285 sizeof(typval_T) * pt->pt_argc);
4286 if (pt->pt_argv == NULL)
4287 {
4288 vim_free(pt);
4289 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004290 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004291 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004292 for (i = 0; i < arg_len; i++)
4293 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4294 if (lv_len > 0)
4295 for (li = list->lv_first; li != NULL;
4296 li = li->li_next)
4297 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298 }
4299
4300 /* For "function(dict.func, [], dict)" and "func" is a partial
4301 * use "dict". That is backwards compatible. */
4302 if (dict_idx > 0)
4303 {
4304 /* The dict is bound explicitly, pt_auto is FALSE. */
4305 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4306 ++pt->pt_dict->dv_refcount;
4307 }
4308 else if (arg_pt != NULL)
4309 {
4310 /* If the dict was bound automatically the result is also
4311 * bound automatically. */
4312 pt->pt_dict = arg_pt->pt_dict;
4313 pt->pt_auto = arg_pt->pt_auto;
4314 if (pt->pt_dict != NULL)
4315 ++pt->pt_dict->dv_refcount;
4316 }
4317
4318 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004319 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4320 {
4321 pt->pt_func = arg_pt->pt_func;
4322 func_ptr_ref(pt->pt_func);
4323 vim_free(name);
4324 }
4325 else if (is_funcref)
4326 {
4327 pt->pt_func = find_func(trans_name);
4328 func_ptr_ref(pt->pt_func);
4329 vim_free(name);
4330 }
4331 else
4332 {
4333 pt->pt_name = name;
4334 func_ref(name);
4335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004336 }
4337 rettv->v_type = VAR_PARTIAL;
4338 rettv->vval.v_partial = pt;
4339 }
4340 else
4341 {
4342 /* result is a VAR_FUNC */
4343 rettv->v_type = VAR_FUNC;
4344 rettv->vval.v_string = name;
4345 func_ref(name);
4346 }
4347 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004348theend:
4349 vim_free(trans_name);
4350}
4351
4352/*
4353 * "funcref()" function
4354 */
4355 static void
4356f_funcref(typval_T *argvars, typval_T *rettv)
4357{
4358 common_function(argvars, rettv, TRUE);
4359}
4360
4361/*
4362 * "function()" function
4363 */
4364 static void
4365f_function(typval_T *argvars, typval_T *rettv)
4366{
4367 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004368}
4369
4370/*
4371 * "garbagecollect()" function
4372 */
4373 static void
4374f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4375{
4376 /* This is postponed until we are back at the toplevel, because we may be
4377 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4378 want_garbage_collect = TRUE;
4379
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004380 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004381 garbage_collect_at_exit = TRUE;
4382}
4383
4384/*
4385 * "get()" function
4386 */
4387 static void
4388f_get(typval_T *argvars, typval_T *rettv)
4389{
4390 listitem_T *li;
4391 list_T *l;
4392 dictitem_T *di;
4393 dict_T *d;
4394 typval_T *tv = NULL;
4395
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004396 if (argvars[0].v_type == VAR_BLOB)
4397 {
4398 int error = FALSE;
4399 int idx = tv_get_number_chk(&argvars[1], &error);
4400
4401 if (!error)
4402 {
4403 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004404 if (idx < 0)
4405 idx = blob_len(argvars[0].vval.v_blob) + idx;
4406 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4407 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004408 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004409 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004410 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004411 tv = rettv;
4412 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004413 }
4414 }
4415 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416 {
4417 if ((l = argvars[0].vval.v_list) != NULL)
4418 {
4419 int error = FALSE;
4420
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004421 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004422 if (!error && li != NULL)
4423 tv = &li->li_tv;
4424 }
4425 }
4426 else if (argvars[0].v_type == VAR_DICT)
4427 {
4428 if ((d = argvars[0].vval.v_dict) != NULL)
4429 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004430 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004431 if (di != NULL)
4432 tv = &di->di_tv;
4433 }
4434 }
4435 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4436 {
4437 partial_T *pt;
4438 partial_T fref_pt;
4439
4440 if (argvars[0].v_type == VAR_PARTIAL)
4441 pt = argvars[0].vval.v_partial;
4442 else
4443 {
4444 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4445 fref_pt.pt_name = argvars[0].vval.v_string;
4446 pt = &fref_pt;
4447 }
4448
4449 if (pt != NULL)
4450 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004451 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004452 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004453
4454 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4455 {
4456 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004457 n = partial_name(pt);
4458 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459 rettv->vval.v_string = NULL;
4460 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004461 {
4462 rettv->vval.v_string = vim_strsave(n);
4463 if (rettv->v_type == VAR_FUNC)
4464 func_ref(rettv->vval.v_string);
4465 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466 }
4467 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004468 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469 else if (STRCMP(what, "args") == 0)
4470 {
4471 rettv->v_type = VAR_LIST;
4472 if (rettv_list_alloc(rettv) == OK)
4473 {
4474 int i;
4475
4476 for (i = 0; i < pt->pt_argc; ++i)
4477 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4478 }
4479 }
4480 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004481 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004482 return;
4483 }
4484 }
4485 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004486 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487
4488 if (tv == NULL)
4489 {
4490 if (argvars[2].v_type != VAR_UNKNOWN)
4491 copy_tv(&argvars[2], rettv);
4492 }
4493 else
4494 copy_tv(tv, rettv);
4495}
4496
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004497/*
4498 * Returns buffer options, variables and other attributes in a dictionary.
4499 */
4500 static dict_T *
4501get_buffer_info(buf_T *buf)
4502{
4503 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004504 tabpage_T *tp;
4505 win_T *wp;
4506 list_T *windows;
4507
4508 dict = dict_alloc();
4509 if (dict == NULL)
4510 return NULL;
4511
Bram Moolenaare0be1672018-07-08 16:50:37 +02004512 dict_add_number(dict, "bufnr", buf->b_fnum);
4513 dict_add_string(dict, "name", buf->b_ffname);
4514 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4515 : buflist_findlnum(buf));
4516 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4517 dict_add_number(dict, "listed", buf->b_p_bl);
4518 dict_add_number(dict, "changed", bufIsChanged(buf));
4519 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4520 dict_add_number(dict, "hidden",
4521 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004522
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004523 /* Get a reference to buffer variables */
4524 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004525
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004526 /* List of windows displaying this buffer */
4527 windows = list_alloc();
4528 if (windows != NULL)
4529 {
4530 FOR_ALL_TAB_WINDOWS(tp, wp)
4531 if (wp->w_buffer == buf)
4532 list_append_number(windows, (varnumber_T)wp->w_id);
4533 dict_add_list(dict, "windows", windows);
4534 }
4535
4536#ifdef FEAT_SIGNS
4537 if (buf->b_signlist != NULL)
4538 {
4539 /* List of signs placed in this buffer */
4540 list_T *signs = list_alloc();
4541 if (signs != NULL)
4542 {
4543 get_buffer_signs(buf, signs);
4544 dict_add_list(dict, "signs", signs);
4545 }
4546 }
4547#endif
4548
4549 return dict;
4550}
4551
4552/*
4553 * "getbufinfo()" function
4554 */
4555 static void
4556f_getbufinfo(typval_T *argvars, typval_T *rettv)
4557{
4558 buf_T *buf = NULL;
4559 buf_T *argbuf = NULL;
4560 dict_T *d;
4561 int filtered = FALSE;
4562 int sel_buflisted = FALSE;
4563 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004564 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004565
4566 if (rettv_list_alloc(rettv) != OK)
4567 return;
4568
4569 /* List of all the buffers or selected buffers */
4570 if (argvars[0].v_type == VAR_DICT)
4571 {
4572 dict_T *sel_d = argvars[0].vval.v_dict;
4573
4574 if (sel_d != NULL)
4575 {
4576 dictitem_T *di;
4577
4578 filtered = TRUE;
4579
4580 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004581 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004582 sel_buflisted = TRUE;
4583
4584 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004585 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004586 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004587
4588 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004589 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004590 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004591 }
4592 }
4593 else if (argvars[0].v_type != VAR_UNKNOWN)
4594 {
4595 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004596 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004597 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004598 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004599 --emsg_off;
4600 if (argbuf == NULL)
4601 return;
4602 }
4603
4604 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004605 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004606 {
4607 if (argbuf != NULL && argbuf != buf)
4608 continue;
4609 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004610 || (sel_buflisted && !buf->b_p_bl)
4611 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004612 continue;
4613
4614 d = get_buffer_info(buf);
4615 if (d != NULL)
4616 list_append_dict(rettv->vval.v_list, d);
4617 if (argbuf != NULL)
4618 return;
4619 }
4620}
4621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622/*
4623 * Get line or list of lines from buffer "buf" into "rettv".
4624 * Return a range (from start to end) of lines in rettv from the specified
4625 * buffer.
4626 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4627 */
4628 static void
4629get_buffer_lines(
4630 buf_T *buf,
4631 linenr_T start,
4632 linenr_T end,
4633 int retlist,
4634 typval_T *rettv)
4635{
4636 char_u *p;
4637
4638 rettv->v_type = VAR_STRING;
4639 rettv->vval.v_string = NULL;
4640 if (retlist && rettv_list_alloc(rettv) == FAIL)
4641 return;
4642
4643 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4644 return;
4645
4646 if (!retlist)
4647 {
4648 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4649 p = ml_get_buf(buf, start, FALSE);
4650 else
4651 p = (char_u *)"";
4652 rettv->vval.v_string = vim_strsave(p);
4653 }
4654 else
4655 {
4656 if (end < start)
4657 return;
4658
4659 if (start < 1)
4660 start = 1;
4661 if (end > buf->b_ml.ml_line_count)
4662 end = buf->b_ml.ml_line_count;
4663 while (start <= end)
4664 if (list_append_string(rettv->vval.v_list,
4665 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4666 break;
4667 }
4668}
4669
4670/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004671 * "getbufline()" function
4672 */
4673 static void
4674f_getbufline(typval_T *argvars, typval_T *rettv)
4675{
4676 linenr_T lnum;
4677 linenr_T end;
4678 buf_T *buf;
4679
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004680 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004681 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004682 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004683 --emsg_off;
4684
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004685 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686 if (argvars[2].v_type == VAR_UNKNOWN)
4687 end = lnum;
4688 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004689 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004690
4691 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4692}
4693
4694/*
4695 * "getbufvar()" function
4696 */
4697 static void
4698f_getbufvar(typval_T *argvars, typval_T *rettv)
4699{
4700 buf_T *buf;
4701 buf_T *save_curbuf;
4702 char_u *varname;
4703 dictitem_T *v;
4704 int done = FALSE;
4705
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004706 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4707 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004708 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004709 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710
4711 rettv->v_type = VAR_STRING;
4712 rettv->vval.v_string = NULL;
4713
4714 if (buf != NULL && varname != NULL)
4715 {
4716 /* set curbuf to be our buf, temporarily */
4717 save_curbuf = curbuf;
4718 curbuf = buf;
4719
Bram Moolenaar30567352016-08-27 21:25:44 +02004720 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004721 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004722 if (varname[1] == NUL)
4723 {
4724 /* get all buffer-local options in a dict */
4725 dict_T *opts = get_winbuf_options(TRUE);
4726
4727 if (opts != NULL)
4728 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004729 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004730 done = TRUE;
4731 }
4732 }
4733 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4734 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735 done = TRUE;
4736 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 else
4738 {
4739 /* Look up the variable. */
4740 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4741 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4742 'b', varname, FALSE);
4743 if (v != NULL)
4744 {
4745 copy_tv(&v->di_tv, rettv);
4746 done = TRUE;
4747 }
4748 }
4749
4750 /* restore previous notion of curbuf */
4751 curbuf = save_curbuf;
4752 }
4753
4754 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4755 /* use the default value */
4756 copy_tv(&argvars[2], rettv);
4757
4758 --emsg_off;
4759}
4760
4761/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004762 * "getchangelist()" function
4763 */
4764 static void
4765f_getchangelist(typval_T *argvars, typval_T *rettv)
4766{
4767#ifdef FEAT_JUMPLIST
4768 buf_T *buf;
4769 int i;
4770 list_T *l;
4771 dict_T *d;
4772#endif
4773
4774 if (rettv_list_alloc(rettv) != OK)
4775 return;
4776
4777#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004778 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004779 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004780 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004781 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004782 if (buf == NULL)
4783 return;
4784
4785 l = list_alloc();
4786 if (l == NULL)
4787 return;
4788
4789 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4790 return;
4791 /*
4792 * The current window change list index tracks only the position in the
4793 * current buffer change list. For other buffers, use the change list
4794 * length as the current index.
4795 */
4796 list_append_number(rettv->vval.v_list,
4797 (varnumber_T)((buf == curwin->w_buffer)
4798 ? curwin->w_changelistidx : buf->b_changelistlen));
4799
4800 for (i = 0; i < buf->b_changelistlen; ++i)
4801 {
4802 if (buf->b_changelist[i].lnum == 0)
4803 continue;
4804 if ((d = dict_alloc()) == NULL)
4805 return;
4806 if (list_append_dict(l, d) == FAIL)
4807 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004808 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4809 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004810 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004811 }
4812#endif
4813}
4814/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815 * "getchar()" function
4816 */
4817 static void
4818f_getchar(typval_T *argvars, typval_T *rettv)
4819{
4820 varnumber_T n;
4821 int error = FALSE;
Bram Moolenaarf0fab302019-03-05 12:24:10 +01004822 int save_reg_executing = reg_executing;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004823
Bram Moolenaar84d93902018-09-11 20:10:20 +02004824#ifdef MESSAGE_QUEUE
4825 // vpeekc() used to check for messages, but that caused problems, invoking
4826 // a callback where it was not expected. Some plugins use getchar(1) in a
4827 // loop to await a message, therefore make sure we check for messages here.
4828 parse_queued_messages();
4829#endif
4830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004831 /* Position the cursor. Needed after a message that ends in a space. */
4832 windgoto(msg_row, msg_col);
4833
4834 ++no_mapping;
4835 ++allow_keys;
4836 for (;;)
4837 {
4838 if (argvars[0].v_type == VAR_UNKNOWN)
4839 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004840 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004841 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004842 /* getchar(1): only check if char avail */
4843 n = vpeekc_any();
4844 else if (error || vpeekc_any() == NUL)
4845 /* illegal argument or getchar(0) and no char avail: return zero */
4846 n = 0;
4847 else
4848 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004849 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850
4851 if (n == K_IGNORE)
4852 continue;
4853 break;
4854 }
4855 --no_mapping;
4856 --allow_keys;
Bram Moolenaarf0fab302019-03-05 12:24:10 +01004857 reg_executing = save_reg_executing;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004858
4859 set_vim_var_nr(VV_MOUSE_WIN, 0);
4860 set_vim_var_nr(VV_MOUSE_WINID, 0);
4861 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4862 set_vim_var_nr(VV_MOUSE_COL, 0);
4863
4864 rettv->vval.v_number = n;
4865 if (IS_SPECIAL(n) || mod_mask != 0)
4866 {
4867 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4868 int i = 0;
4869
4870 /* Turn a special key into three bytes, plus modifier. */
4871 if (mod_mask != 0)
4872 {
4873 temp[i++] = K_SPECIAL;
4874 temp[i++] = KS_MODIFIER;
4875 temp[i++] = mod_mask;
4876 }
4877 if (IS_SPECIAL(n))
4878 {
4879 temp[i++] = K_SPECIAL;
4880 temp[i++] = K_SECOND(n);
4881 temp[i++] = K_THIRD(n);
4882 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004883 else if (has_mbyte)
4884 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004885 else
4886 temp[i++] = n;
4887 temp[i++] = NUL;
4888 rettv->v_type = VAR_STRING;
4889 rettv->vval.v_string = vim_strsave(temp);
4890
4891#ifdef FEAT_MOUSE
4892 if (is_mouse_key(n))
4893 {
4894 int row = mouse_row;
4895 int col = mouse_col;
4896 win_T *win;
4897 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004898 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004899 int winnr = 1;
4900
4901 if (row >= 0 && col >= 0)
4902 {
4903 /* Find the window at the mouse coordinates and compute the
4904 * text position. */
4905 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004906 if (win == NULL)
4907 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909 for (wp = firstwin; wp != win; wp = wp->w_next)
4910 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4912 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4913 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4914 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4915 }
4916 }
4917#endif
4918 }
4919}
4920
4921/*
4922 * "getcharmod()" function
4923 */
4924 static void
4925f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4926{
4927 rettv->vval.v_number = mod_mask;
4928}
4929
4930/*
4931 * "getcharsearch()" function
4932 */
4933 static void
4934f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4935{
4936 if (rettv_dict_alloc(rettv) != FAIL)
4937 {
4938 dict_T *dict = rettv->vval.v_dict;
4939
Bram Moolenaare0be1672018-07-08 16:50:37 +02004940 dict_add_string(dict, "char", last_csearch());
4941 dict_add_number(dict, "forward", last_csearch_forward());
4942 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004943 }
4944}
4945
4946/*
4947 * "getcmdline()" function
4948 */
4949 static void
4950f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4951{
4952 rettv->v_type = VAR_STRING;
4953 rettv->vval.v_string = get_cmdline_str();
4954}
4955
4956/*
4957 * "getcmdpos()" function
4958 */
4959 static void
4960f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4961{
4962 rettv->vval.v_number = get_cmdline_pos() + 1;
4963}
4964
4965/*
4966 * "getcmdtype()" function
4967 */
4968 static void
4969f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4970{
4971 rettv->v_type = VAR_STRING;
4972 rettv->vval.v_string = alloc(2);
4973 if (rettv->vval.v_string != NULL)
4974 {
4975 rettv->vval.v_string[0] = get_cmdline_type();
4976 rettv->vval.v_string[1] = NUL;
4977 }
4978}
4979
4980/*
4981 * "getcmdwintype()" function
4982 */
4983 static void
4984f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4985{
4986 rettv->v_type = VAR_STRING;
4987 rettv->vval.v_string = NULL;
4988#ifdef FEAT_CMDWIN
4989 rettv->vval.v_string = alloc(2);
4990 if (rettv->vval.v_string != NULL)
4991 {
4992 rettv->vval.v_string[0] = cmdwin_type;
4993 rettv->vval.v_string[1] = NUL;
4994 }
4995#endif
4996}
4997
4998#if defined(FEAT_CMDL_COMPL)
4999/*
5000 * "getcompletion()" function
5001 */
5002 static void
5003f_getcompletion(typval_T *argvars, typval_T *rettv)
5004{
5005 char_u *pat;
5006 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005007 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005008 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5009 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005010
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005011 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005012 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005013
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005014 if (p_wic)
5015 options |= WILD_ICASE;
5016
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005017 /* For filtered results, 'wildignore' is used */
5018 if (!filtered)
5019 options |= WILD_KEEP_ALL;
5020
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005021 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005022 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005023 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005024 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 if (xpc.xp_context == EXPAND_NOTHING)
5026 {
5027 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005028 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005029 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005030 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031 return;
5032 }
5033
5034# if defined(FEAT_MENU)
5035 if (xpc.xp_context == EXPAND_MENUS)
5036 {
5037 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5038 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5039 }
5040# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005041#ifdef FEAT_CSCOPE
5042 if (xpc.xp_context == EXPAND_CSCOPE)
5043 {
5044 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5045 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5046 }
5047#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005048#ifdef FEAT_SIGNS
5049 if (xpc.xp_context == EXPAND_SIGN)
5050 {
5051 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5052 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5053 }
5054#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005055
5056 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5057 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5058 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005059 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060
5061 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5062
5063 for (i = 0; i < xpc.xp_numfiles; i++)
5064 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5065 }
5066 vim_free(pat);
5067 ExpandCleanup(&xpc);
5068}
5069#endif
5070
5071/*
5072 * "getcwd()" function
5073 */
5074 static void
5075f_getcwd(typval_T *argvars, typval_T *rettv)
5076{
5077 win_T *wp = NULL;
5078 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005079 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005080
5081 rettv->v_type = VAR_STRING;
5082 rettv->vval.v_string = NULL;
5083
Bram Moolenaar54591292018-02-09 20:53:59 +01005084 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5085 global = TRUE;
5086 else
5087 wp = find_tabwin(&argvars[0], &argvars[1]);
5088
5089 if (wp != NULL && wp->w_localdir != NULL)
5090 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5091 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005092 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005093 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094 rettv->vval.v_string = vim_strsave(globaldir);
5095 else
5096 {
5097 cwd = alloc(MAXPATHL);
5098 if (cwd != NULL)
5099 {
5100 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5101 rettv->vval.v_string = vim_strsave(cwd);
5102 vim_free(cwd);
5103 }
5104 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005106#ifdef BACKSLASH_IN_FILENAME
5107 if (rettv->vval.v_string != NULL)
5108 slash_adjust(rettv->vval.v_string);
5109#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110}
5111
5112/*
5113 * "getfontname()" function
5114 */
5115 static void
5116f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5117{
5118 rettv->v_type = VAR_STRING;
5119 rettv->vval.v_string = NULL;
5120#ifdef FEAT_GUI
5121 if (gui.in_use)
5122 {
5123 GuiFont font;
5124 char_u *name = NULL;
5125
5126 if (argvars[0].v_type == VAR_UNKNOWN)
5127 {
5128 /* Get the "Normal" font. Either the name saved by
5129 * hl_set_font_name() or from the font ID. */
5130 font = gui.norm_font;
5131 name = hl_get_font_name();
5132 }
5133 else
5134 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005135 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005136 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5137 return;
5138 font = gui_mch_get_font(name, FALSE);
5139 if (font == NOFONT)
5140 return; /* Invalid font name, return empty string. */
5141 }
5142 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5143 if (argvars[0].v_type != VAR_UNKNOWN)
5144 gui_mch_free_font(font);
5145 }
5146#endif
5147}
5148
5149/*
5150 * "getfperm({fname})" function
5151 */
5152 static void
5153f_getfperm(typval_T *argvars, typval_T *rettv)
5154{
5155 char_u *fname;
5156 stat_T st;
5157 char_u *perm = NULL;
5158 char_u flags[] = "rwx";
5159 int i;
5160
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005161 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005162
5163 rettv->v_type = VAR_STRING;
5164 if (mch_stat((char *)fname, &st) >= 0)
5165 {
5166 perm = vim_strsave((char_u *)"---------");
5167 if (perm != NULL)
5168 {
5169 for (i = 0; i < 9; i++)
5170 {
5171 if (st.st_mode & (1 << (8 - i)))
5172 perm[i] = flags[i % 3];
5173 }
5174 }
5175 }
5176 rettv->vval.v_string = perm;
5177}
5178
5179/*
5180 * "getfsize({fname})" function
5181 */
5182 static void
5183f_getfsize(typval_T *argvars, typval_T *rettv)
5184{
5185 char_u *fname;
5186 stat_T st;
5187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005188 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005189
5190 rettv->v_type = VAR_NUMBER;
5191
5192 if (mch_stat((char *)fname, &st) >= 0)
5193 {
5194 if (mch_isdir(fname))
5195 rettv->vval.v_number = 0;
5196 else
5197 {
5198 rettv->vval.v_number = (varnumber_T)st.st_size;
5199
5200 /* non-perfect check for overflow */
5201 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5202 rettv->vval.v_number = -2;
5203 }
5204 }
5205 else
5206 rettv->vval.v_number = -1;
5207}
5208
5209/*
5210 * "getftime({fname})" function
5211 */
5212 static void
5213f_getftime(typval_T *argvars, typval_T *rettv)
5214{
5215 char_u *fname;
5216 stat_T st;
5217
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005218 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005219
5220 if (mch_stat((char *)fname, &st) >= 0)
5221 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5222 else
5223 rettv->vval.v_number = -1;
5224}
5225
5226/*
5227 * "getftype({fname})" function
5228 */
5229 static void
5230f_getftype(typval_T *argvars, typval_T *rettv)
5231{
5232 char_u *fname;
5233 stat_T st;
5234 char_u *type = NULL;
5235 char *t;
5236
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005237 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005238
5239 rettv->v_type = VAR_STRING;
5240 if (mch_lstat((char *)fname, &st) >= 0)
5241 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242 if (S_ISREG(st.st_mode))
5243 t = "file";
5244 else if (S_ISDIR(st.st_mode))
5245 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005246 else if (S_ISLNK(st.st_mode))
5247 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005248 else if (S_ISBLK(st.st_mode))
5249 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005250 else if (S_ISCHR(st.st_mode))
5251 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005252 else if (S_ISFIFO(st.st_mode))
5253 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005254 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005255 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005256 else
5257 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005258 type = vim_strsave((char_u *)t);
5259 }
5260 rettv->vval.v_string = type;
5261}
5262
5263/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005264 * "getjumplist()" function
5265 */
5266 static void
5267f_getjumplist(typval_T *argvars, typval_T *rettv)
5268{
5269#ifdef FEAT_JUMPLIST
5270 win_T *wp;
5271 int i;
5272 list_T *l;
5273 dict_T *d;
5274#endif
5275
5276 if (rettv_list_alloc(rettv) != OK)
5277 return;
5278
5279#ifdef FEAT_JUMPLIST
5280 wp = find_tabwin(&argvars[0], &argvars[1]);
5281 if (wp == NULL)
5282 return;
5283
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005284 cleanup_jumplist(wp, TRUE);
5285
Bram Moolenaar4f505882018-02-10 21:06:32 +01005286 l = list_alloc();
5287 if (l == NULL)
5288 return;
5289
5290 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5291 return;
5292 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5293
5294 for (i = 0; i < wp->w_jumplistlen; ++i)
5295 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005296 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5297 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005298 if ((d = dict_alloc()) == NULL)
5299 return;
5300 if (list_append_dict(l, d) == FAIL)
5301 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005302 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5303 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005304 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005305 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005306 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005307 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005308 }
5309#endif
5310}
5311
5312/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005313 * "getline(lnum, [end])" function
5314 */
5315 static void
5316f_getline(typval_T *argvars, typval_T *rettv)
5317{
5318 linenr_T lnum;
5319 linenr_T end;
5320 int retlist;
5321
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005322 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005323 if (argvars[1].v_type == VAR_UNKNOWN)
5324 {
5325 end = 0;
5326 retlist = FALSE;
5327 }
5328 else
5329 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005330 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005331 retlist = TRUE;
5332 }
5333
5334 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5335}
5336
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005337#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005338 static void
5339get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5340{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005341 if (what_arg->v_type == VAR_UNKNOWN)
5342 {
5343 if (rettv_list_alloc(rettv) == OK)
5344 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005345 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005346 }
5347 else
5348 {
5349 if (rettv_dict_alloc(rettv) == OK)
5350 if (is_qf || (wp != NULL))
5351 {
5352 if (what_arg->v_type == VAR_DICT)
5353 {
5354 dict_T *d = what_arg->vval.v_dict;
5355
5356 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005357 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005358 }
5359 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005360 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005361 }
5362 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005363}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005364#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005365
5366/*
5367 * "getloclist()" function
5368 */
5369 static void
5370f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5371{
5372#ifdef FEAT_QUICKFIX
5373 win_T *wp;
5374
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005375 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005376 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5377#endif
5378}
5379
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005380/*
5381 * "getmatches()" function
5382 */
5383 static void
5384f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5385{
5386#ifdef FEAT_SEARCH_EXTRA
5387 dict_T *dict;
5388 matchitem_T *cur = curwin->w_match_head;
5389 int i;
5390
5391 if (rettv_list_alloc(rettv) == OK)
5392 {
5393 while (cur != NULL)
5394 {
5395 dict = dict_alloc();
5396 if (dict == NULL)
5397 return;
5398 if (cur->match.regprog == NULL)
5399 {
5400 /* match added with matchaddpos() */
5401 for (i = 0; i < MAXPOSMATCH; ++i)
5402 {
5403 llpos_T *llpos;
5404 char buf[6];
5405 list_T *l;
5406
5407 llpos = &cur->pos.pos[i];
5408 if (llpos->lnum == 0)
5409 break;
5410 l = list_alloc();
5411 if (l == NULL)
5412 break;
5413 list_append_number(l, (varnumber_T)llpos->lnum);
5414 if (llpos->col > 0)
5415 {
5416 list_append_number(l, (varnumber_T)llpos->col);
5417 list_append_number(l, (varnumber_T)llpos->len);
5418 }
5419 sprintf(buf, "pos%d", i + 1);
5420 dict_add_list(dict, buf, l);
5421 }
5422 }
5423 else
5424 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005425 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005426 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005427 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5428 dict_add_number(dict, "priority", (long)cur->priority);
5429 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar13505972019-01-24 15:04:48 +01005430# if defined(FEAT_CONCEAL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005431 if (cur->conceal_char)
5432 {
5433 char_u buf[MB_MAXBYTES + 1];
5434
5435 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005436 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005437 }
5438# endif
5439 list_append_dict(rettv->vval.v_list, dict);
5440 cur = cur->next;
5441 }
5442 }
5443#endif
5444}
5445
5446/*
5447 * "getpid()" function
5448 */
5449 static void
5450f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5451{
5452 rettv->vval.v_number = mch_get_pid();
5453}
5454
5455 static void
5456getpos_both(
5457 typval_T *argvars,
5458 typval_T *rettv,
5459 int getcurpos)
5460{
5461 pos_T *fp;
5462 list_T *l;
5463 int fnum = -1;
5464
5465 if (rettv_list_alloc(rettv) == OK)
5466 {
5467 l = rettv->vval.v_list;
5468 if (getcurpos)
5469 fp = &curwin->w_cursor;
5470 else
5471 fp = var2fpos(&argvars[0], TRUE, &fnum);
5472 if (fnum != -1)
5473 list_append_number(l, (varnumber_T)fnum);
5474 else
5475 list_append_number(l, (varnumber_T)0);
5476 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5477 : (varnumber_T)0);
5478 list_append_number(l, (fp != NULL)
5479 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5480 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005481 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005482 (varnumber_T)0);
5483 if (getcurpos)
5484 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005485 int save_set_curswant = curwin->w_set_curswant;
5486 colnr_T save_curswant = curwin->w_curswant;
5487 colnr_T save_virtcol = curwin->w_virtcol;
5488
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489 update_curswant();
5490 list_append_number(l, curwin->w_curswant == MAXCOL ?
5491 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005492
5493 // Do not change "curswant", as it is unexpected that a get
5494 // function has a side effect.
5495 if (save_set_curswant)
5496 {
5497 curwin->w_set_curswant = save_set_curswant;
5498 curwin->w_curswant = save_curswant;
5499 curwin->w_virtcol = save_virtcol;
5500 curwin->w_valid &= ~VALID_VIRTCOL;
5501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502 }
5503 }
5504 else
5505 rettv->vval.v_number = FALSE;
5506}
5507
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005508/*
5509 * "getcurpos()" function
5510 */
5511 static void
5512f_getcurpos(typval_T *argvars, typval_T *rettv)
5513{
5514 getpos_both(argvars, rettv, TRUE);
5515}
5516
5517/*
5518 * "getpos(string)" function
5519 */
5520 static void
5521f_getpos(typval_T *argvars, typval_T *rettv)
5522{
5523 getpos_both(argvars, rettv, FALSE);
5524}
5525
5526/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005527 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005528 */
5529 static void
5530f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5531{
5532#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005533 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005534#endif
5535}
5536
5537/*
5538 * "getreg()" function
5539 */
5540 static void
5541f_getreg(typval_T *argvars, typval_T *rettv)
5542{
5543 char_u *strregname;
5544 int regname;
5545 int arg2 = FALSE;
5546 int return_list = FALSE;
5547 int error = FALSE;
5548
5549 if (argvars[0].v_type != VAR_UNKNOWN)
5550 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005551 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005552 error = strregname == NULL;
5553 if (argvars[1].v_type != VAR_UNKNOWN)
5554 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005555 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005557 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005558 }
5559 }
5560 else
5561 strregname = get_vim_var_str(VV_REG);
5562
5563 if (error)
5564 return;
5565
5566 regname = (strregname == NULL ? '"' : *strregname);
5567 if (regname == 0)
5568 regname = '"';
5569
5570 if (return_list)
5571 {
5572 rettv->v_type = VAR_LIST;
5573 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5574 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5575 if (rettv->vval.v_list == NULL)
5576 (void)rettv_list_alloc(rettv);
5577 else
5578 ++rettv->vval.v_list->lv_refcount;
5579 }
5580 else
5581 {
5582 rettv->v_type = VAR_STRING;
5583 rettv->vval.v_string = get_reg_contents(regname,
5584 arg2 ? GREG_EXPR_SRC : 0);
5585 }
5586}
5587
5588/*
5589 * "getregtype()" function
5590 */
5591 static void
5592f_getregtype(typval_T *argvars, typval_T *rettv)
5593{
5594 char_u *strregname;
5595 int regname;
5596 char_u buf[NUMBUFLEN + 2];
5597 long reglen = 0;
5598
5599 if (argvars[0].v_type != VAR_UNKNOWN)
5600 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005601 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005602 if (strregname == NULL) /* type error; errmsg already given */
5603 {
5604 rettv->v_type = VAR_STRING;
5605 rettv->vval.v_string = NULL;
5606 return;
5607 }
5608 }
5609 else
5610 /* Default to v:register */
5611 strregname = get_vim_var_str(VV_REG);
5612
5613 regname = (strregname == NULL ? '"' : *strregname);
5614 if (regname == 0)
5615 regname = '"';
5616
5617 buf[0] = NUL;
5618 buf[1] = NUL;
5619 switch (get_reg_type(regname, &reglen))
5620 {
5621 case MLINE: buf[0] = 'V'; break;
5622 case MCHAR: buf[0] = 'v'; break;
5623 case MBLOCK:
5624 buf[0] = Ctrl_V;
5625 sprintf((char *)buf + 1, "%ld", reglen + 1);
5626 break;
5627 }
5628 rettv->v_type = VAR_STRING;
5629 rettv->vval.v_string = vim_strsave(buf);
5630}
5631
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632/*
5633 * Returns information (variables, options, etc.) about a tab page
5634 * as a dictionary.
5635 */
5636 static dict_T *
5637get_tabpage_info(tabpage_T *tp, int tp_idx)
5638{
5639 win_T *wp;
5640 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005641 list_T *l;
5642
5643 dict = dict_alloc();
5644 if (dict == NULL)
5645 return NULL;
5646
Bram Moolenaare0be1672018-07-08 16:50:37 +02005647 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005648
5649 l = list_alloc();
5650 if (l != NULL)
5651 {
5652 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5653 wp; wp = wp->w_next)
5654 list_append_number(l, (varnumber_T)wp->w_id);
5655 dict_add_list(dict, "windows", l);
5656 }
5657
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005658 /* Make a reference to tabpage variables */
5659 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005660
5661 return dict;
5662}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005663
5664/*
5665 * "gettabinfo()" function
5666 */
5667 static void
5668f_gettabinfo(typval_T *argvars, typval_T *rettv)
5669{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005670 tabpage_T *tp, *tparg = NULL;
5671 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005672 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005673
5674 if (rettv_list_alloc(rettv) != OK)
5675 return;
5676
5677 if (argvars[0].v_type != VAR_UNKNOWN)
5678 {
5679 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005680 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005681 if (tparg == NULL)
5682 return;
5683 }
5684
5685 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005686 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005687 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005688 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005689 if (tparg != NULL && tp != tparg)
5690 continue;
5691 d = get_tabpage_info(tp, tpnr);
5692 if (d != NULL)
5693 list_append_dict(rettv->vval.v_list, d);
5694 if (tparg != NULL)
5695 return;
5696 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005697}
5698
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005699/*
5700 * "gettabvar()" function
5701 */
5702 static void
5703f_gettabvar(typval_T *argvars, typval_T *rettv)
5704{
5705 win_T *oldcurwin;
5706 tabpage_T *tp, *oldtabpage;
5707 dictitem_T *v;
5708 char_u *varname;
5709 int done = FALSE;
5710
5711 rettv->v_type = VAR_STRING;
5712 rettv->vval.v_string = NULL;
5713
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005714 varname = tv_get_string_chk(&argvars[1]);
5715 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005716 if (tp != NULL && varname != NULL)
5717 {
5718 /* Set tp to be our tabpage, temporarily. Also set the window to the
5719 * first window in the tabpage, otherwise the window is not valid. */
5720 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005721 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5722 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005723 {
5724 /* look up the variable */
5725 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5726 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5727 if (v != NULL)
5728 {
5729 copy_tv(&v->di_tv, rettv);
5730 done = TRUE;
5731 }
5732 }
5733
5734 /* restore previous notion of curwin */
5735 restore_win(oldcurwin, oldtabpage, TRUE);
5736 }
5737
5738 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5739 copy_tv(&argvars[2], rettv);
5740}
5741
5742/*
5743 * "gettabwinvar()" function
5744 */
5745 static void
5746f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5747{
5748 getwinvar(argvars, rettv, 1);
5749}
5750
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005751/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005752 * "gettagstack()" function
5753 */
5754 static void
5755f_gettagstack(typval_T *argvars, typval_T *rettv)
5756{
5757 win_T *wp = curwin; // default is current window
5758
5759 if (rettv_dict_alloc(rettv) != OK)
5760 return;
5761
5762 if (argvars[0].v_type != VAR_UNKNOWN)
5763 {
5764 wp = find_win_by_nr_or_id(&argvars[0]);
5765 if (wp == NULL)
5766 return;
5767 }
5768
5769 get_tagstack(wp, rettv->vval.v_dict);
5770}
5771
5772/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005773 * Returns information about a window as a dictionary.
5774 */
5775 static dict_T *
5776get_win_info(win_T *wp, short tpnr, short winnr)
5777{
5778 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005779
5780 dict = dict_alloc();
5781 if (dict == NULL)
5782 return NULL;
5783
Bram Moolenaare0be1672018-07-08 16:50:37 +02005784 dict_add_number(dict, "tabnr", tpnr);
5785 dict_add_number(dict, "winnr", winnr);
5786 dict_add_number(dict, "winid", wp->w_id);
5787 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005788 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005789 dict_add_number(dict, "topline", wp->w_topline);
5790 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005791#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005792 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005793#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005794 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005795 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005796 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005797
Bram Moolenaar69905d12017-08-13 18:14:47 +02005798#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005799 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005800#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005801#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005802 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5803 dict_add_number(dict, "loclist",
5804 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005805#endif
5806
Bram Moolenaar30567352016-08-27 21:25:44 +02005807 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005808 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005809
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005810 return dict;
5811}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005812
5813/*
5814 * "getwininfo()" function
5815 */
5816 static void
5817f_getwininfo(typval_T *argvars, typval_T *rettv)
5818{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005819 tabpage_T *tp;
5820 win_T *wp = NULL, *wparg = NULL;
5821 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005822 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005823
5824 if (rettv_list_alloc(rettv) != OK)
5825 return;
5826
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005827 if (argvars[0].v_type != VAR_UNKNOWN)
5828 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005829 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005830 if (wparg == NULL)
5831 return;
5832 }
5833
5834 /* Collect information about either all the windows across all the tab
5835 * pages or one particular window.
5836 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005837 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005838 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005839 tabnr++;
5840 winnr = 0;
5841 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005842 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005843 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005844 if (wparg != NULL && wp != wparg)
5845 continue;
5846 d = get_win_info(wp, tabnr, winnr);
5847 if (d != NULL)
5848 list_append_dict(rettv->vval.v_list, d);
5849 if (wparg != NULL)
5850 /* found information about a specific window */
5851 return;
5852 }
5853 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005854}
5855
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005856/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005857 * "win_findbuf()" function
5858 */
5859 static void
5860f_win_findbuf(typval_T *argvars, typval_T *rettv)
5861{
5862 if (rettv_list_alloc(rettv) != FAIL)
5863 win_findbuf(argvars, rettv->vval.v_list);
5864}
5865
5866/*
5867 * "win_getid()" function
5868 */
5869 static void
5870f_win_getid(typval_T *argvars, typval_T *rettv)
5871{
5872 rettv->vval.v_number = win_getid(argvars);
5873}
5874
5875/*
5876 * "win_gotoid()" function
5877 */
5878 static void
5879f_win_gotoid(typval_T *argvars, typval_T *rettv)
5880{
5881 rettv->vval.v_number = win_gotoid(argvars);
5882}
5883
5884/*
5885 * "win_id2tabwin()" function
5886 */
5887 static void
5888f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5889{
5890 if (rettv_list_alloc(rettv) != FAIL)
5891 win_id2tabwin(argvars, rettv->vval.v_list);
5892}
5893
5894/*
5895 * "win_id2win()" function
5896 */
5897 static void
5898f_win_id2win(typval_T *argvars, typval_T *rettv)
5899{
5900 rettv->vval.v_number = win_id2win(argvars);
5901}
5902
5903/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005904 * "win_screenpos()" function
5905 */
5906 static void
5907f_win_screenpos(typval_T *argvars, typval_T *rettv)
5908{
5909 win_T *wp;
5910
5911 if (rettv_list_alloc(rettv) == FAIL)
5912 return;
5913
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005914 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005915 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5916 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5917}
5918
5919/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005920 * "getwinpos({timeout})" function
5921 */
5922 static void
5923f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5924{
5925 int x = -1;
5926 int y = -1;
5927
5928 if (rettv_list_alloc(rettv) == FAIL)
5929 return;
5930#ifdef FEAT_GUI
5931 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005932 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005933# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5934 else
5935# endif
5936#endif
5937#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5938 {
5939 varnumber_T timeout = 100;
5940
5941 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005942 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005943 term_get_winpos(&x, &y, timeout);
5944 }
5945#endif
5946 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5947 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5948}
5949
5950
5951/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005952 * "getwinposx()" function
5953 */
5954 static void
5955f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5956{
5957 rettv->vval.v_number = -1;
5958#ifdef FEAT_GUI
5959 if (gui.in_use)
5960 {
5961 int x, y;
5962
5963 if (gui_mch_get_winpos(&x, &y) == OK)
5964 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005965 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005966 }
5967#endif
5968#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5969 {
5970 int x, y;
5971
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005972 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005973 rettv->vval.v_number = x;
5974 }
5975#endif
5976}
5977
5978/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005979 * "getwinposy()" function
5980 */
5981 static void
5982f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5983{
5984 rettv->vval.v_number = -1;
5985#ifdef FEAT_GUI
5986 if (gui.in_use)
5987 {
5988 int x, y;
5989
5990 if (gui_mch_get_winpos(&x, &y) == OK)
5991 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005992 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005993 }
5994#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005995#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5996 {
5997 int x, y;
5998
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005999 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006000 rettv->vval.v_number = y;
6001 }
6002#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006003}
6004
6005/*
6006 * "getwinvar()" function
6007 */
6008 static void
6009f_getwinvar(typval_T *argvars, typval_T *rettv)
6010{
6011 getwinvar(argvars, rettv, 0);
6012}
6013
6014/*
6015 * "glob()" function
6016 */
6017 static void
6018f_glob(typval_T *argvars, typval_T *rettv)
6019{
6020 int options = WILD_SILENT|WILD_USE_NL;
6021 expand_T xpc;
6022 int error = FALSE;
6023
6024 /* When the optional second argument is non-zero, don't remove matches
6025 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6026 rettv->v_type = VAR_STRING;
6027 if (argvars[1].v_type != VAR_UNKNOWN)
6028 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006029 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030 options |= WILD_KEEP_ALL;
6031 if (argvars[2].v_type != VAR_UNKNOWN)
6032 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006033 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006034 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006035 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006036 }
6037 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006038 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006039 options |= WILD_ALLLINKS;
6040 }
6041 }
6042 if (!error)
6043 {
6044 ExpandInit(&xpc);
6045 xpc.xp_context = EXPAND_FILES;
6046 if (p_wic)
6047 options += WILD_ICASE;
6048 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006049 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050 NULL, options, WILD_ALL);
6051 else if (rettv_list_alloc(rettv) != FAIL)
6052 {
6053 int i;
6054
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006055 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006056 NULL, options, WILD_ALL_KEEP);
6057 for (i = 0; i < xpc.xp_numfiles; i++)
6058 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6059
6060 ExpandCleanup(&xpc);
6061 }
6062 }
6063 else
6064 rettv->vval.v_string = NULL;
6065}
6066
6067/*
6068 * "globpath()" function
6069 */
6070 static void
6071f_globpath(typval_T *argvars, typval_T *rettv)
6072{
6073 int flags = 0;
6074 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006075 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006076 int error = FALSE;
6077 garray_T ga;
6078 int i;
6079
6080 /* When the optional second argument is non-zero, don't remove matches
6081 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6082 rettv->v_type = VAR_STRING;
6083 if (argvars[2].v_type != VAR_UNKNOWN)
6084 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006085 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006086 flags |= WILD_KEEP_ALL;
6087 if (argvars[3].v_type != VAR_UNKNOWN)
6088 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006089 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006091 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006092 }
6093 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006094 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006095 flags |= WILD_ALLLINKS;
6096 }
6097 }
6098 if (file != NULL && !error)
6099 {
6100 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006101 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006102 if (rettv->v_type == VAR_STRING)
6103 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6104 else if (rettv_list_alloc(rettv) != FAIL)
6105 for (i = 0; i < ga.ga_len; ++i)
6106 list_append_string(rettv->vval.v_list,
6107 ((char_u **)(ga.ga_data))[i], -1);
6108 ga_clear_strings(&ga);
6109 }
6110 else
6111 rettv->vval.v_string = NULL;
6112}
6113
6114/*
6115 * "glob2regpat()" function
6116 */
6117 static void
6118f_glob2regpat(typval_T *argvars, typval_T *rettv)
6119{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006120 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006121
6122 rettv->v_type = VAR_STRING;
6123 rettv->vval.v_string = (pat == NULL)
6124 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6125}
6126
6127/* for VIM_VERSION_ defines */
6128#include "version.h"
6129
6130/*
6131 * "has()" function
6132 */
6133 static void
6134f_has(typval_T *argvars, typval_T *rettv)
6135{
6136 int i;
6137 char_u *name;
6138 int n = FALSE;
6139 static char *(has_list[]) =
6140 {
6141#ifdef AMIGA
6142 "amiga",
6143# ifdef FEAT_ARP
6144 "arp",
6145# endif
6146#endif
6147#ifdef __BEOS__
6148 "beos",
6149#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006150#if defined(BSD) && !defined(MACOS_X)
6151 "bsd",
6152#endif
6153#ifdef hpux
6154 "hpux",
6155#endif
6156#ifdef __linux__
6157 "linux",
6158#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006159#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006160 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6161 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006162# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006163 "macunix", /* Mac OS X, with the darwin feature */
6164 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006165# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166#endif
6167#ifdef __QNX__
6168 "qnx",
6169#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006170#ifdef SUN_SYSTEM
6171 "sun",
6172#else
6173 "moon",
6174#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175#ifdef UNIX
6176 "unix",
6177#endif
6178#ifdef VMS
6179 "vms",
6180#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006181#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182 "win32",
6183#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006184#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 "win32unix",
6186#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006187#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 "win64",
6189#endif
6190#ifdef EBCDIC
6191 "ebcdic",
6192#endif
6193#ifndef CASE_INSENSITIVE_FILENAME
6194 "fname_case",
6195#endif
6196#ifdef HAVE_ACL
6197 "acl",
6198#endif
6199#ifdef FEAT_ARABIC
6200 "arabic",
6201#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006202 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006203#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006204 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006205#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006206#ifdef FEAT_AUTOSERVERNAME
6207 "autoservername",
6208#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006209#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006210 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006211# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212 "balloon_multiline",
6213# endif
6214#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006215#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006216 "balloon_eval_term",
6217#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6219 "builtin_terms",
6220# ifdef ALL_BUILTIN_TCAPS
6221 "all_builtin_terms",
6222# endif
6223#endif
6224#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006225 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006226 || defined(FEAT_GUI_MOTIF))
6227 "browsefilter",
6228#endif
6229#ifdef FEAT_BYTEOFF
6230 "byte_offset",
6231#endif
6232#ifdef FEAT_JOB_CHANNEL
6233 "channel",
6234#endif
6235#ifdef FEAT_CINDENT
6236 "cindent",
6237#endif
6238#ifdef FEAT_CLIENTSERVER
6239 "clientserver",
6240#endif
6241#ifdef FEAT_CLIPBOARD
6242 "clipboard",
6243#endif
6244#ifdef FEAT_CMDL_COMPL
6245 "cmdline_compl",
6246#endif
6247#ifdef FEAT_CMDHIST
6248 "cmdline_hist",
6249#endif
6250#ifdef FEAT_COMMENTS
6251 "comments",
6252#endif
6253#ifdef FEAT_CONCEAL
6254 "conceal",
6255#endif
6256#ifdef FEAT_CRYPT
6257 "cryptv",
6258 "crypt-blowfish",
6259 "crypt-blowfish2",
6260#endif
6261#ifdef FEAT_CSCOPE
6262 "cscope",
6263#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006265#ifdef CURSOR_SHAPE
6266 "cursorshape",
6267#endif
6268#ifdef DEBUG
6269 "debug",
6270#endif
6271#ifdef FEAT_CON_DIALOG
6272 "dialog_con",
6273#endif
6274#ifdef FEAT_GUI_DIALOG
6275 "dialog_gui",
6276#endif
6277#ifdef FEAT_DIFF
6278 "diff",
6279#endif
6280#ifdef FEAT_DIGRAPHS
6281 "digraphs",
6282#endif
6283#ifdef FEAT_DIRECTX
6284 "directx",
6285#endif
6286#ifdef FEAT_DND
6287 "dnd",
6288#endif
6289#ifdef FEAT_EMACS_TAGS
6290 "emacs_tags",
6291#endif
6292 "eval", /* always present, of course! */
6293 "ex_extra", /* graduated feature */
6294#ifdef FEAT_SEARCH_EXTRA
6295 "extra_search",
6296#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297#ifdef FEAT_SEARCHPATH
6298 "file_in_path",
6299#endif
6300#ifdef FEAT_FILTERPIPE
6301 "filterpipe",
6302#endif
6303#ifdef FEAT_FIND_ID
6304 "find_in_path",
6305#endif
6306#ifdef FEAT_FLOAT
6307 "float",
6308#endif
6309#ifdef FEAT_FOLDING
6310 "folding",
6311#endif
6312#ifdef FEAT_FOOTER
6313 "footer",
6314#endif
6315#if !defined(USE_SYSTEM) && defined(UNIX)
6316 "fork",
6317#endif
6318#ifdef FEAT_GETTEXT
6319 "gettext",
6320#endif
6321#ifdef FEAT_GUI
6322 "gui",
6323#endif
6324#ifdef FEAT_GUI_ATHENA
6325# ifdef FEAT_GUI_NEXTAW
6326 "gui_neXtaw",
6327# else
6328 "gui_athena",
6329# endif
6330#endif
6331#ifdef FEAT_GUI_GTK
6332 "gui_gtk",
6333# ifdef USE_GTK3
6334 "gui_gtk3",
6335# else
6336 "gui_gtk2",
6337# endif
6338#endif
6339#ifdef FEAT_GUI_GNOME
6340 "gui_gnome",
6341#endif
6342#ifdef FEAT_GUI_MAC
6343 "gui_mac",
6344#endif
6345#ifdef FEAT_GUI_MOTIF
6346 "gui_motif",
6347#endif
6348#ifdef FEAT_GUI_PHOTON
6349 "gui_photon",
6350#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006351#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006352 "gui_win32",
6353#endif
6354#ifdef FEAT_HANGULIN
6355 "hangul_input",
6356#endif
6357#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6358 "iconv",
6359#endif
6360#ifdef FEAT_INS_EXPAND
6361 "insert_expand",
6362#endif
6363#ifdef FEAT_JOB_CHANNEL
6364 "job",
6365#endif
6366#ifdef FEAT_JUMPLIST
6367 "jumplist",
6368#endif
6369#ifdef FEAT_KEYMAP
6370 "keymap",
6371#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006372 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373#ifdef FEAT_LANGMAP
6374 "langmap",
6375#endif
6376#ifdef FEAT_LIBCALL
6377 "libcall",
6378#endif
6379#ifdef FEAT_LINEBREAK
6380 "linebreak",
6381#endif
6382#ifdef FEAT_LISP
6383 "lispindent",
6384#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006386#ifdef FEAT_LOCALMAP
6387 "localmap",
6388#endif
6389#ifdef FEAT_LUA
6390# ifndef DYNAMIC_LUA
6391 "lua",
6392# endif
6393#endif
6394#ifdef FEAT_MENU
6395 "menu",
6396#endif
6397#ifdef FEAT_SESSION
6398 "mksession",
6399#endif
6400#ifdef FEAT_MODIFY_FNAME
6401 "modify_fname",
6402#endif
6403#ifdef FEAT_MOUSE
6404 "mouse",
6405#endif
6406#ifdef FEAT_MOUSESHAPE
6407 "mouseshape",
6408#endif
6409#if defined(UNIX) || defined(VMS)
6410# ifdef FEAT_MOUSE_DEC
6411 "mouse_dec",
6412# endif
6413# ifdef FEAT_MOUSE_GPM
6414 "mouse_gpm",
6415# endif
6416# ifdef FEAT_MOUSE_JSB
6417 "mouse_jsbterm",
6418# endif
6419# ifdef FEAT_MOUSE_NET
6420 "mouse_netterm",
6421# endif
6422# ifdef FEAT_MOUSE_PTERM
6423 "mouse_pterm",
6424# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006425# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 "mouse_sgr",
6427# endif
6428# ifdef FEAT_SYSMOUSE
6429 "mouse_sysmouse",
6430# endif
6431# ifdef FEAT_MOUSE_URXVT
6432 "mouse_urxvt",
6433# endif
6434# ifdef FEAT_MOUSE_XTERM
6435 "mouse_xterm",
6436# endif
6437#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006438 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006439#ifdef FEAT_MBYTE_IME
6440 "multi_byte_ime",
6441#endif
6442#ifdef FEAT_MULTI_LANG
6443 "multi_lang",
6444#endif
6445#ifdef FEAT_MZSCHEME
6446#ifndef DYNAMIC_MZSCHEME
6447 "mzscheme",
6448#endif
6449#endif
6450#ifdef FEAT_NUM64
6451 "num64",
6452#endif
6453#ifdef FEAT_OLE
6454 "ole",
6455#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006456#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006457 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006458#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006459#ifdef FEAT_PATH_EXTRA
6460 "path_extra",
6461#endif
6462#ifdef FEAT_PERL
6463#ifndef DYNAMIC_PERL
6464 "perl",
6465#endif
6466#endif
6467#ifdef FEAT_PERSISTENT_UNDO
6468 "persistent_undo",
6469#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006470#if defined(FEAT_PYTHON)
6471 "python_compiled",
6472# if defined(DYNAMIC_PYTHON)
6473 "python_dynamic",
6474# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006476 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006477# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006479#if defined(FEAT_PYTHON3)
6480 "python3_compiled",
6481# if defined(DYNAMIC_PYTHON3)
6482 "python3_dynamic",
6483# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006485 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006486# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487#endif
6488#ifdef FEAT_POSTSCRIPT
6489 "postscript",
6490#endif
6491#ifdef FEAT_PRINTER
6492 "printer",
6493#endif
6494#ifdef FEAT_PROFILE
6495 "profile",
6496#endif
6497#ifdef FEAT_RELTIME
6498 "reltime",
6499#endif
6500#ifdef FEAT_QUICKFIX
6501 "quickfix",
6502#endif
6503#ifdef FEAT_RIGHTLEFT
6504 "rightleft",
6505#endif
6506#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6507 "ruby",
6508#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006509 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006510#ifdef FEAT_CMDL_INFO
6511 "showcmd",
6512 "cmdline_info",
6513#endif
6514#ifdef FEAT_SIGNS
6515 "signs",
6516#endif
6517#ifdef FEAT_SMARTINDENT
6518 "smartindent",
6519#endif
6520#ifdef STARTUPTIME
6521 "startuptime",
6522#endif
6523#ifdef FEAT_STL_OPT
6524 "statusline",
6525#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526#ifdef FEAT_NETBEANS_INTG
6527 "netbeans_intg",
6528#endif
6529#ifdef FEAT_SPELL
6530 "spell",
6531#endif
6532#ifdef FEAT_SYN_HL
6533 "syntax",
6534#endif
6535#if defined(USE_SYSTEM) || !defined(UNIX)
6536 "system",
6537#endif
6538#ifdef FEAT_TAG_BINS
6539 "tag_binary",
6540#endif
6541#ifdef FEAT_TAG_OLDSTATIC
6542 "tag_old_static",
6543#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006544#ifdef FEAT_TCL
6545# ifndef DYNAMIC_TCL
6546 "tcl",
6547# endif
6548#endif
6549#ifdef FEAT_TERMGUICOLORS
6550 "termguicolors",
6551#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006552#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006553 "terminal",
6554#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555#ifdef TERMINFO
6556 "terminfo",
6557#endif
6558#ifdef FEAT_TERMRESPONSE
6559 "termresponse",
6560#endif
6561#ifdef FEAT_TEXTOBJ
6562 "textobjects",
6563#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006564#ifdef FEAT_TEXT_PROP
6565 "textprop",
6566#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006567#ifdef HAVE_TGETENT
6568 "tgetent",
6569#endif
6570#ifdef FEAT_TIMERS
6571 "timers",
6572#endif
6573#ifdef FEAT_TITLE
6574 "title",
6575#endif
6576#ifdef FEAT_TOOLBAR
6577 "toolbar",
6578#endif
6579#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6580 "unnamedplus",
6581#endif
6582#ifdef FEAT_USR_CMDS
6583 "user-commands", /* was accidentally included in 5.4 */
6584 "user_commands",
6585#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006586#ifdef FEAT_VARTABS
6587 "vartabs",
6588#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589#ifdef FEAT_VIMINFO
6590 "viminfo",
6591#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006592 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006593 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006595 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006596 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006597#ifdef FEAT_VTP
6598 "vtp",
6599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600#ifdef FEAT_WILDIGN
6601 "wildignore",
6602#endif
6603#ifdef FEAT_WILDMENU
6604 "wildmenu",
6605#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006606 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006607#ifdef FEAT_WAK
6608 "winaltkeys",
6609#endif
6610#ifdef FEAT_WRITEBACKUP
6611 "writebackup",
6612#endif
6613#ifdef FEAT_XIM
6614 "xim",
6615#endif
6616#ifdef FEAT_XFONTSET
6617 "xfontset",
6618#endif
6619#ifdef FEAT_XPM_W32
6620 "xpm",
6621 "xpm_w32", /* for backward compatibility */
6622#else
6623# if defined(HAVE_XPM)
6624 "xpm",
6625# endif
6626#endif
6627#ifdef USE_XSMP
6628 "xsmp",
6629#endif
6630#ifdef USE_XSMP_INTERACT
6631 "xsmp_interact",
6632#endif
6633#ifdef FEAT_XCLIPBOARD
6634 "xterm_clipboard",
6635#endif
6636#ifdef FEAT_XTERM_SAVE
6637 "xterm_save",
6638#endif
6639#if defined(UNIX) && defined(FEAT_X11)
6640 "X11",
6641#endif
6642 NULL
6643 };
6644
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006645 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006646 for (i = 0; has_list[i] != NULL; ++i)
6647 if (STRICMP(name, has_list[i]) == 0)
6648 {
6649 n = TRUE;
6650 break;
6651 }
6652
6653 if (n == FALSE)
6654 {
6655 if (STRNICMP(name, "patch", 5) == 0)
6656 {
6657 if (name[5] == '-'
6658 && STRLEN(name) >= 11
6659 && vim_isdigit(name[6])
6660 && vim_isdigit(name[8])
6661 && vim_isdigit(name[10]))
6662 {
6663 int major = atoi((char *)name + 6);
6664 int minor = atoi((char *)name + 8);
6665
6666 /* Expect "patch-9.9.01234". */
6667 n = (major < VIM_VERSION_MAJOR
6668 || (major == VIM_VERSION_MAJOR
6669 && (minor < VIM_VERSION_MINOR
6670 || (minor == VIM_VERSION_MINOR
6671 && has_patch(atoi((char *)name + 10))))));
6672 }
6673 else
6674 n = has_patch(atoi((char *)name + 5));
6675 }
6676 else if (STRICMP(name, "vim_starting") == 0)
6677 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006678 else if (STRICMP(name, "ttyin") == 0)
6679 n = mch_input_isatty();
6680 else if (STRICMP(name, "ttyout") == 0)
6681 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006682 else if (STRICMP(name, "multi_byte_encoding") == 0)
6683 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006684#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685 else if (STRICMP(name, "balloon_multiline") == 0)
6686 n = multiline_balloon_available();
6687#endif
6688#ifdef DYNAMIC_TCL
6689 else if (STRICMP(name, "tcl") == 0)
6690 n = tcl_enabled(FALSE);
6691#endif
6692#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6693 else if (STRICMP(name, "iconv") == 0)
6694 n = iconv_enabled(FALSE);
6695#endif
6696#ifdef DYNAMIC_LUA
6697 else if (STRICMP(name, "lua") == 0)
6698 n = lua_enabled(FALSE);
6699#endif
6700#ifdef DYNAMIC_MZSCHEME
6701 else if (STRICMP(name, "mzscheme") == 0)
6702 n = mzscheme_enabled(FALSE);
6703#endif
6704#ifdef DYNAMIC_RUBY
6705 else if (STRICMP(name, "ruby") == 0)
6706 n = ruby_enabled(FALSE);
6707#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006708#ifdef DYNAMIC_PYTHON
6709 else if (STRICMP(name, "python") == 0)
6710 n = python_enabled(FALSE);
6711#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006712#ifdef DYNAMIC_PYTHON3
6713 else if (STRICMP(name, "python3") == 0)
6714 n = python3_enabled(FALSE);
6715#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006716#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6717 else if (STRICMP(name, "pythonx") == 0)
6718 {
6719# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6720 if (p_pyx == 0)
6721 n = python3_enabled(FALSE) || python_enabled(FALSE);
6722 else if (p_pyx == 3)
6723 n = python3_enabled(FALSE);
6724 else if (p_pyx == 2)
6725 n = python_enabled(FALSE);
6726# elif defined(DYNAMIC_PYTHON)
6727 n = python_enabled(FALSE);
6728# elif defined(DYNAMIC_PYTHON3)
6729 n = python3_enabled(FALSE);
6730# endif
6731 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006732#endif
6733#ifdef DYNAMIC_PERL
6734 else if (STRICMP(name, "perl") == 0)
6735 n = perl_enabled(FALSE);
6736#endif
6737#ifdef FEAT_GUI
6738 else if (STRICMP(name, "gui_running") == 0)
6739 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006740# ifdef FEAT_BROWSE
6741 else if (STRICMP(name, "browse") == 0)
6742 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6743# endif
6744#endif
6745#ifdef FEAT_SYN_HL
6746 else if (STRICMP(name, "syntax_items") == 0)
6747 n = syntax_present(curwin);
6748#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006749#ifdef FEAT_VTP
6750 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006751 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006752#endif
6753#ifdef FEAT_NETBEANS_INTG
6754 else if (STRICMP(name, "netbeans_enabled") == 0)
6755 n = netbeans_active();
6756#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006757#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006758 else if (STRICMP(name, "terminal") == 0)
6759 n = terminal_enabled();
6760#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006761#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006762 else if (STRICMP(name, "conpty") == 0)
6763 n = use_conpty();
6764#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006765 }
6766
6767 rettv->vval.v_number = n;
6768}
6769
6770/*
6771 * "has_key()" function
6772 */
6773 static void
6774f_has_key(typval_T *argvars, typval_T *rettv)
6775{
6776 if (argvars[0].v_type != VAR_DICT)
6777 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006778 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 return;
6780 }
6781 if (argvars[0].vval.v_dict == NULL)
6782 return;
6783
6784 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006785 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006786}
6787
6788/*
6789 * "haslocaldir()" function
6790 */
6791 static void
6792f_haslocaldir(typval_T *argvars, typval_T *rettv)
6793{
6794 win_T *wp = NULL;
6795
6796 wp = find_tabwin(&argvars[0], &argvars[1]);
6797 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6798}
6799
6800/*
6801 * "hasmapto()" function
6802 */
6803 static void
6804f_hasmapto(typval_T *argvars, typval_T *rettv)
6805{
6806 char_u *name;
6807 char_u *mode;
6808 char_u buf[NUMBUFLEN];
6809 int abbr = FALSE;
6810
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006811 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812 if (argvars[1].v_type == VAR_UNKNOWN)
6813 mode = (char_u *)"nvo";
6814 else
6815 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006816 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006817 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006818 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006819 }
6820
6821 if (map_to_exists(name, mode, abbr))
6822 rettv->vval.v_number = TRUE;
6823 else
6824 rettv->vval.v_number = FALSE;
6825}
6826
6827/*
6828 * "histadd()" function
6829 */
6830 static void
6831f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6832{
6833#ifdef FEAT_CMDHIST
6834 int histype;
6835 char_u *str;
6836 char_u buf[NUMBUFLEN];
6837#endif
6838
6839 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006840 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006841 return;
6842#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006843 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006844 histype = str != NULL ? get_histtype(str) : -1;
6845 if (histype >= 0)
6846 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006847 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006848 if (*str != NUL)
6849 {
6850 init_history();
6851 add_to_history(histype, str, FALSE, NUL);
6852 rettv->vval.v_number = TRUE;
6853 return;
6854 }
6855 }
6856#endif
6857}
6858
6859/*
6860 * "histdel()" function
6861 */
6862 static void
6863f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6864{
6865#ifdef FEAT_CMDHIST
6866 int n;
6867 char_u buf[NUMBUFLEN];
6868 char_u *str;
6869
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006870 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006871 if (str == NULL)
6872 n = 0;
6873 else if (argvars[1].v_type == VAR_UNKNOWN)
6874 /* only one argument: clear entire history */
6875 n = clr_history(get_histtype(str));
6876 else if (argvars[1].v_type == VAR_NUMBER)
6877 /* index given: remove that entry */
6878 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006879 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 else
6881 /* string given: remove all matching entries */
6882 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006883 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006884 rettv->vval.v_number = n;
6885#endif
6886}
6887
6888/*
6889 * "histget()" function
6890 */
6891 static void
6892f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6893{
6894#ifdef FEAT_CMDHIST
6895 int type;
6896 int idx;
6897 char_u *str;
6898
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006899 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006900 if (str == NULL)
6901 rettv->vval.v_string = NULL;
6902 else
6903 {
6904 type = get_histtype(str);
6905 if (argvars[1].v_type == VAR_UNKNOWN)
6906 idx = get_history_idx(type);
6907 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006908 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006909 /* -1 on type error */
6910 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6911 }
6912#else
6913 rettv->vval.v_string = NULL;
6914#endif
6915 rettv->v_type = VAR_STRING;
6916}
6917
6918/*
6919 * "histnr()" function
6920 */
6921 static void
6922f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6923{
6924 int i;
6925
6926#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006927 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006928
6929 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6930 if (i >= HIST_CMD && i < HIST_COUNT)
6931 i = get_history_idx(i);
6932 else
6933#endif
6934 i = -1;
6935 rettv->vval.v_number = i;
6936}
6937
6938/*
6939 * "highlightID(name)" function
6940 */
6941 static void
6942f_hlID(typval_T *argvars, typval_T *rettv)
6943{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006944 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006945}
6946
6947/*
6948 * "highlight_exists()" function
6949 */
6950 static void
6951f_hlexists(typval_T *argvars, typval_T *rettv)
6952{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006953 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954}
6955
6956/*
6957 * "hostname()" function
6958 */
6959 static void
6960f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6961{
6962 char_u hostname[256];
6963
6964 mch_get_host_name(hostname, 256);
6965 rettv->v_type = VAR_STRING;
6966 rettv->vval.v_string = vim_strsave(hostname);
6967}
6968
6969/*
6970 * iconv() function
6971 */
6972 static void
6973f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6974{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 char_u buf1[NUMBUFLEN];
6976 char_u buf2[NUMBUFLEN];
6977 char_u *from, *to, *str;
6978 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006979
6980 rettv->v_type = VAR_STRING;
6981 rettv->vval.v_string = NULL;
6982
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006983 str = tv_get_string(&argvars[0]);
6984 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6985 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986 vimconv.vc_type = CONV_NONE;
6987 convert_setup(&vimconv, from, to);
6988
6989 /* If the encodings are equal, no conversion needed. */
6990 if (vimconv.vc_type == CONV_NONE)
6991 rettv->vval.v_string = vim_strsave(str);
6992 else
6993 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6994
6995 convert_setup(&vimconv, NULL, NULL);
6996 vim_free(from);
6997 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006998}
6999
7000/*
7001 * "indent()" function
7002 */
7003 static void
7004f_indent(typval_T *argvars, typval_T *rettv)
7005{
7006 linenr_T lnum;
7007
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007008 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007009 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7010 rettv->vval.v_number = get_indent_lnum(lnum);
7011 else
7012 rettv->vval.v_number = -1;
7013}
7014
7015/*
7016 * "index()" function
7017 */
7018 static void
7019f_index(typval_T *argvars, typval_T *rettv)
7020{
7021 list_T *l;
7022 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007023 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024 long idx = 0;
7025 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007026 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007027
7028 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007029 if (argvars[0].v_type == VAR_BLOB)
7030 {
7031 typval_T tv;
7032 int start = 0;
7033
7034 if (argvars[2].v_type != VAR_UNKNOWN)
7035 {
7036 start = tv_get_number_chk(&argvars[2], &error);
7037 if (error)
7038 return;
7039 }
7040 b = argvars[0].vval.v_blob;
7041 if (b == NULL)
7042 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007043 if (start < 0)
7044 {
7045 start = blob_len(b) + start;
7046 if (start < 0)
7047 start = 0;
7048 }
7049
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007050 for (idx = start; idx < blob_len(b); ++idx)
7051 {
7052 tv.v_type = VAR_NUMBER;
7053 tv.vval.v_number = blob_get(b, idx);
7054 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7055 {
7056 rettv->vval.v_number = idx;
7057 return;
7058 }
7059 }
7060 return;
7061 }
7062 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007064 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007065 return;
7066 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007067
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068 l = argvars[0].vval.v_list;
7069 if (l != NULL)
7070 {
7071 item = l->lv_first;
7072 if (argvars[2].v_type != VAR_UNKNOWN)
7073 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074 /* Start at specified item. Use the cached index that list_find()
7075 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007076 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007077 idx = l->lv_idx;
7078 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007079 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 if (error)
7081 item = NULL;
7082 }
7083
7084 for ( ; item != NULL; item = item->li_next, ++idx)
7085 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7086 {
7087 rettv->vval.v_number = idx;
7088 break;
7089 }
7090 }
7091}
7092
7093static int inputsecret_flag = 0;
7094
7095/*
7096 * "input()" function
7097 * Also handles inputsecret() when inputsecret is set.
7098 */
7099 static void
7100f_input(typval_T *argvars, typval_T *rettv)
7101{
7102 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7103}
7104
7105/*
7106 * "inputdialog()" function
7107 */
7108 static void
7109f_inputdialog(typval_T *argvars, typval_T *rettv)
7110{
7111#if defined(FEAT_GUI_TEXTDIALOG)
7112 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7113 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7114 {
7115 char_u *message;
7116 char_u buf[NUMBUFLEN];
7117 char_u *defstr = (char_u *)"";
7118
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007119 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007120 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007121 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007122 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7123 else
7124 IObuff[0] = NUL;
7125 if (message != NULL && defstr != NULL
7126 && do_dialog(VIM_QUESTION, NULL, message,
7127 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7128 rettv->vval.v_string = vim_strsave(IObuff);
7129 else
7130 {
7131 if (message != NULL && defstr != NULL
7132 && argvars[1].v_type != VAR_UNKNOWN
7133 && argvars[2].v_type != VAR_UNKNOWN)
7134 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007135 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 else
7137 rettv->vval.v_string = NULL;
7138 }
7139 rettv->v_type = VAR_STRING;
7140 }
7141 else
7142#endif
7143 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7144}
7145
7146/*
7147 * "inputlist()" function
7148 */
7149 static void
7150f_inputlist(typval_T *argvars, typval_T *rettv)
7151{
7152 listitem_T *li;
7153 int selected;
7154 int mouse_used;
7155
7156#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007157 /* While starting up, there is no place to enter text. When running tests
7158 * with --not-a-term we assume feedkeys() will be used. */
7159 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160 return;
7161#endif
7162 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7163 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007164 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007165 return;
7166 }
7167
7168 msg_start();
7169 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7170 lines_left = Rows; /* avoid more prompt */
7171 msg_scroll = TRUE;
7172 msg_clr_eos();
7173
7174 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7175 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007176 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007177 msg_putchar('\n');
7178 }
7179
7180 /* Ask for choice. */
7181 selected = prompt_for_number(&mouse_used);
7182 if (mouse_used)
7183 selected -= lines_left;
7184
7185 rettv->vval.v_number = selected;
7186}
7187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7189
7190/*
7191 * "inputrestore()" function
7192 */
7193 static void
7194f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7195{
7196 if (ga_userinput.ga_len > 0)
7197 {
7198 --ga_userinput.ga_len;
7199 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7200 + ga_userinput.ga_len);
7201 /* default return is zero == OK */
7202 }
7203 else if (p_verbose > 1)
7204 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007205 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 rettv->vval.v_number = 1; /* Failed */
7207 }
7208}
7209
7210/*
7211 * "inputsave()" function
7212 */
7213 static void
7214f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7215{
7216 /* Add an entry to the stack of typeahead storage. */
7217 if (ga_grow(&ga_userinput, 1) == OK)
7218 {
7219 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7220 + ga_userinput.ga_len);
7221 ++ga_userinput.ga_len;
7222 /* default return is zero == OK */
7223 }
7224 else
7225 rettv->vval.v_number = 1; /* Failed */
7226}
7227
7228/*
7229 * "inputsecret()" function
7230 */
7231 static void
7232f_inputsecret(typval_T *argvars, typval_T *rettv)
7233{
7234 ++cmdline_star;
7235 ++inputsecret_flag;
7236 f_input(argvars, rettv);
7237 --cmdline_star;
7238 --inputsecret_flag;
7239}
7240
7241/*
7242 * "insert()" function
7243 */
7244 static void
7245f_insert(typval_T *argvars, typval_T *rettv)
7246{
7247 long before = 0;
7248 listitem_T *item;
7249 list_T *l;
7250 int error = FALSE;
7251
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007252 if (argvars[0].v_type == VAR_BLOB)
7253 {
7254 int val, len;
7255 char_u *p;
7256
7257 len = blob_len(argvars[0].vval.v_blob);
7258 if (argvars[2].v_type != VAR_UNKNOWN)
7259 {
7260 before = (long)tv_get_number_chk(&argvars[2], &error);
7261 if (error)
7262 return; // type error; errmsg already given
7263 if (before < 0 || before > len)
7264 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007265 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007266 return;
7267 }
7268 }
7269 val = tv_get_number_chk(&argvars[1], &error);
7270 if (error)
7271 return;
7272 if (val < 0 || val > 255)
7273 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007274 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007275 return;
7276 }
7277
7278 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7279 return;
7280 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7281 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7282 *(p + before) = val;
7283 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7284
7285 copy_tv(&argvars[0], rettv);
7286 }
7287 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007288 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007289 else if ((l = argvars[0].vval.v_list) != NULL
7290 && !var_check_lock(l->lv_lock,
7291 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007292 {
7293 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007294 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007295 if (error)
7296 return; /* type error; errmsg already given */
7297
7298 if (before == l->lv_len)
7299 item = NULL;
7300 else
7301 {
7302 item = list_find(l, before);
7303 if (item == NULL)
7304 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007305 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306 l = NULL;
7307 }
7308 }
7309 if (l != NULL)
7310 {
7311 list_insert_tv(l, &argvars[1], item);
7312 copy_tv(&argvars[0], rettv);
7313 }
7314 }
7315}
7316
7317/*
7318 * "invert(expr)" function
7319 */
7320 static void
7321f_invert(typval_T *argvars, typval_T *rettv)
7322{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007323 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324}
7325
7326/*
7327 * "isdirectory()" function
7328 */
7329 static void
7330f_isdirectory(typval_T *argvars, typval_T *rettv)
7331{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007332 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007333}
7334
7335/*
7336 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7337 * or it refers to a List or Dictionary that is locked.
7338 */
7339 static int
7340tv_islocked(typval_T *tv)
7341{
7342 return (tv->v_lock & VAR_LOCKED)
7343 || (tv->v_type == VAR_LIST
7344 && tv->vval.v_list != NULL
7345 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7346 || (tv->v_type == VAR_DICT
7347 && tv->vval.v_dict != NULL
7348 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7349}
7350
7351/*
7352 * "islocked()" function
7353 */
7354 static void
7355f_islocked(typval_T *argvars, typval_T *rettv)
7356{
7357 lval_T lv;
7358 char_u *end;
7359 dictitem_T *di;
7360
7361 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007362 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007363 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364 if (end != NULL && lv.ll_name != NULL)
7365 {
7366 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007367 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368 else
7369 {
7370 if (lv.ll_tv == NULL)
7371 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007372 di = find_var(lv.ll_name, NULL, TRUE);
7373 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007375 /* Consider a variable locked when:
7376 * 1. the variable itself is locked
7377 * 2. the value of the variable is locked.
7378 * 3. the List or Dict value is locked.
7379 */
7380 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7381 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 }
7383 }
7384 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007385 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007387 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388 else if (lv.ll_list != NULL)
7389 /* List item. */
7390 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7391 else
7392 /* Dictionary item. */
7393 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7394 }
7395 }
7396
7397 clear_lval(&lv);
7398}
7399
7400#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7401/*
7402 * "isnan()" function
7403 */
7404 static void
7405f_isnan(typval_T *argvars, typval_T *rettv)
7406{
7407 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7408 && isnan(argvars[0].vval.v_float);
7409}
7410#endif
7411
7412/*
7413 * "items(dict)" function
7414 */
7415 static void
7416f_items(typval_T *argvars, typval_T *rettv)
7417{
7418 dict_list(argvars, rettv, 2);
7419}
7420
7421#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7422/*
7423 * Get the job from the argument.
7424 * Returns NULL if the job is invalid.
7425 */
7426 static job_T *
7427get_job_arg(typval_T *tv)
7428{
7429 job_T *job;
7430
7431 if (tv->v_type != VAR_JOB)
7432 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007433 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 return NULL;
7435 }
7436 job = tv->vval.v_job;
7437
7438 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007439 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 return job;
7441}
7442
7443/*
7444 * "job_getchannel()" function
7445 */
7446 static void
7447f_job_getchannel(typval_T *argvars, typval_T *rettv)
7448{
7449 job_T *job = get_job_arg(&argvars[0]);
7450
7451 if (job != NULL)
7452 {
7453 rettv->v_type = VAR_CHANNEL;
7454 rettv->vval.v_channel = job->jv_channel;
7455 if (job->jv_channel != NULL)
7456 ++job->jv_channel->ch_refcount;
7457 }
7458}
7459
7460/*
7461 * "job_info()" function
7462 */
7463 static void
7464f_job_info(typval_T *argvars, typval_T *rettv)
7465{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007466 if (argvars[0].v_type != VAR_UNKNOWN)
7467 {
7468 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007469
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007470 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7471 job_info(job, rettv->vval.v_dict);
7472 }
7473 else if (rettv_list_alloc(rettv) == OK)
7474 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007475}
7476
7477/*
7478 * "job_setoptions()" function
7479 */
7480 static void
7481f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7482{
7483 job_T *job = get_job_arg(&argvars[0]);
7484 jobopt_T opt;
7485
7486 if (job == NULL)
7487 return;
7488 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007489 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007490 job_set_options(job, &opt);
7491 free_job_options(&opt);
7492}
7493
7494/*
7495 * "job_start()" function
7496 */
7497 static void
7498f_job_start(typval_T *argvars, typval_T *rettv)
7499{
7500 rettv->v_type = VAR_JOB;
7501 if (check_restricted() || check_secure())
7502 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007503 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504}
7505
7506/*
7507 * "job_status()" function
7508 */
7509 static void
7510f_job_status(typval_T *argvars, typval_T *rettv)
7511{
7512 job_T *job = get_job_arg(&argvars[0]);
7513
7514 if (job != NULL)
7515 {
7516 rettv->v_type = VAR_STRING;
7517 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7518 }
7519}
7520
7521/*
7522 * "job_stop()" function
7523 */
7524 static void
7525f_job_stop(typval_T *argvars, typval_T *rettv)
7526{
7527 job_T *job = get_job_arg(&argvars[0]);
7528
7529 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007530 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531}
7532#endif
7533
7534/*
7535 * "join()" function
7536 */
7537 static void
7538f_join(typval_T *argvars, typval_T *rettv)
7539{
7540 garray_T ga;
7541 char_u *sep;
7542
7543 if (argvars[0].v_type != VAR_LIST)
7544 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007545 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 return;
7547 }
7548 if (argvars[0].vval.v_list == NULL)
7549 return;
7550 if (argvars[1].v_type == VAR_UNKNOWN)
7551 sep = (char_u *)" ";
7552 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007553 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554
7555 rettv->v_type = VAR_STRING;
7556
7557 if (sep != NULL)
7558 {
7559 ga_init2(&ga, (int)sizeof(char), 80);
7560 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7561 ga_append(&ga, NUL);
7562 rettv->vval.v_string = (char_u *)ga.ga_data;
7563 }
7564 else
7565 rettv->vval.v_string = NULL;
7566}
7567
7568/*
7569 * "js_decode()" function
7570 */
7571 static void
7572f_js_decode(typval_T *argvars, typval_T *rettv)
7573{
7574 js_read_T reader;
7575
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 reader.js_fill = NULL;
7578 reader.js_used = 0;
7579 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007580 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581}
7582
7583/*
7584 * "js_encode()" function
7585 */
7586 static void
7587f_js_encode(typval_T *argvars, typval_T *rettv)
7588{
7589 rettv->v_type = VAR_STRING;
7590 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7591}
7592
7593/*
7594 * "json_decode()" function
7595 */
7596 static void
7597f_json_decode(typval_T *argvars, typval_T *rettv)
7598{
7599 js_read_T reader;
7600
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007601 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007602 reader.js_fill = NULL;
7603 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007604 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007605}
7606
7607/*
7608 * "json_encode()" function
7609 */
7610 static void
7611f_json_encode(typval_T *argvars, typval_T *rettv)
7612{
7613 rettv->v_type = VAR_STRING;
7614 rettv->vval.v_string = json_encode(&argvars[0], 0);
7615}
7616
7617/*
7618 * "keys()" function
7619 */
7620 static void
7621f_keys(typval_T *argvars, typval_T *rettv)
7622{
7623 dict_list(argvars, rettv, 0);
7624}
7625
7626/*
7627 * "last_buffer_nr()" function.
7628 */
7629 static void
7630f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7631{
7632 int n = 0;
7633 buf_T *buf;
7634
Bram Moolenaar29323592016-07-24 22:04:11 +02007635 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007636 if (n < buf->b_fnum)
7637 n = buf->b_fnum;
7638
7639 rettv->vval.v_number = n;
7640}
7641
7642/*
7643 * "len()" function
7644 */
7645 static void
7646f_len(typval_T *argvars, typval_T *rettv)
7647{
7648 switch (argvars[0].v_type)
7649 {
7650 case VAR_STRING:
7651 case VAR_NUMBER:
7652 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007653 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007654 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007655 case VAR_BLOB:
7656 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7657 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007658 case VAR_LIST:
7659 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7660 break;
7661 case VAR_DICT:
7662 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7663 break;
7664 case VAR_UNKNOWN:
7665 case VAR_SPECIAL:
7666 case VAR_FLOAT:
7667 case VAR_FUNC:
7668 case VAR_PARTIAL:
7669 case VAR_JOB:
7670 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007671 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 break;
7673 }
7674}
7675
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007676 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007677libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678{
7679#ifdef FEAT_LIBCALL
7680 char_u *string_in;
7681 char_u **string_result;
7682 int nr_result;
7683#endif
7684
7685 rettv->v_type = type;
7686 if (type != VAR_NUMBER)
7687 rettv->vval.v_string = NULL;
7688
7689 if (check_restricted() || check_secure())
7690 return;
7691
7692#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007693 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007694 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7695 {
7696 string_in = NULL;
7697 if (argvars[2].v_type == VAR_STRING)
7698 string_in = argvars[2].vval.v_string;
7699 if (type == VAR_NUMBER)
7700 string_result = NULL;
7701 else
7702 string_result = &rettv->vval.v_string;
7703 if (mch_libcall(argvars[0].vval.v_string,
7704 argvars[1].vval.v_string,
7705 string_in,
7706 argvars[2].vval.v_number,
7707 string_result,
7708 &nr_result) == OK
7709 && type == VAR_NUMBER)
7710 rettv->vval.v_number = nr_result;
7711 }
7712#endif
7713}
7714
7715/*
7716 * "libcall()" function
7717 */
7718 static void
7719f_libcall(typval_T *argvars, typval_T *rettv)
7720{
7721 libcall_common(argvars, rettv, VAR_STRING);
7722}
7723
7724/*
7725 * "libcallnr()" function
7726 */
7727 static void
7728f_libcallnr(typval_T *argvars, typval_T *rettv)
7729{
7730 libcall_common(argvars, rettv, VAR_NUMBER);
7731}
7732
7733/*
7734 * "line(string)" function
7735 */
7736 static void
7737f_line(typval_T *argvars, typval_T *rettv)
7738{
7739 linenr_T lnum = 0;
7740 pos_T *fp;
7741 int fnum;
7742
7743 fp = var2fpos(&argvars[0], TRUE, &fnum);
7744 if (fp != NULL)
7745 lnum = fp->lnum;
7746 rettv->vval.v_number = lnum;
7747}
7748
7749/*
7750 * "line2byte(lnum)" function
7751 */
7752 static void
7753f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7754{
7755#ifndef FEAT_BYTEOFF
7756 rettv->vval.v_number = -1;
7757#else
7758 linenr_T lnum;
7759
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007760 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007761 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7762 rettv->vval.v_number = -1;
7763 else
7764 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7765 if (rettv->vval.v_number >= 0)
7766 ++rettv->vval.v_number;
7767#endif
7768}
7769
7770/*
7771 * "lispindent(lnum)" function
7772 */
7773 static void
7774f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7775{
7776#ifdef FEAT_LISP
7777 pos_T pos;
7778 linenr_T lnum;
7779
7780 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007781 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007782 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7783 {
7784 curwin->w_cursor.lnum = lnum;
7785 rettv->vval.v_number = get_lisp_indent();
7786 curwin->w_cursor = pos;
7787 }
7788 else
7789#endif
7790 rettv->vval.v_number = -1;
7791}
7792
7793/*
7794 * "localtime()" function
7795 */
7796 static void
7797f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7798{
7799 rettv->vval.v_number = (varnumber_T)time(NULL);
7800}
7801
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007802 static void
7803get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7804{
7805 char_u *keys;
7806 char_u *which;
7807 char_u buf[NUMBUFLEN];
7808 char_u *keys_buf = NULL;
7809 char_u *rhs;
7810 int mode;
7811 int abbr = FALSE;
7812 int get_dict = FALSE;
7813 mapblock_T *mp;
7814 int buffer_local;
7815
7816 /* return empty string for failure */
7817 rettv->v_type = VAR_STRING;
7818 rettv->vval.v_string = NULL;
7819
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007820 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007821 if (*keys == NUL)
7822 return;
7823
7824 if (argvars[1].v_type != VAR_UNKNOWN)
7825 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007826 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007827 if (argvars[2].v_type != VAR_UNKNOWN)
7828 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007829 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007830 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007831 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 }
7833 }
7834 else
7835 which = (char_u *)"";
7836 if (which == NULL)
7837 return;
7838
7839 mode = get_map_mode(&which, 0);
7840
7841 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7842 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7843 vim_free(keys_buf);
7844
7845 if (!get_dict)
7846 {
7847 /* Return a string. */
7848 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007849 {
7850 if (*rhs == NUL)
7851 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7852 else
7853 rettv->vval.v_string = str2special_save(rhs, FALSE);
7854 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007855
7856 }
7857 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7858 {
7859 /* Return a dictionary. */
7860 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7861 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7862 dict_T *dict = rettv->vval.v_dict;
7863
Bram Moolenaare0be1672018-07-08 16:50:37 +02007864 dict_add_string(dict, "lhs", lhs);
7865 dict_add_string(dict, "rhs", mp->m_orig_str);
7866 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7867 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7868 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007869 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7870 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007871 dict_add_number(dict, "buffer", (long)buffer_local);
7872 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7873 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874
7875 vim_free(lhs);
7876 vim_free(mapmode);
7877 }
7878}
7879
7880#ifdef FEAT_FLOAT
7881/*
7882 * "log()" function
7883 */
7884 static void
7885f_log(typval_T *argvars, typval_T *rettv)
7886{
7887 float_T f = 0.0;
7888
7889 rettv->v_type = VAR_FLOAT;
7890 if (get_float_arg(argvars, &f) == OK)
7891 rettv->vval.v_float = log(f);
7892 else
7893 rettv->vval.v_float = 0.0;
7894}
7895
7896/*
7897 * "log10()" function
7898 */
7899 static void
7900f_log10(typval_T *argvars, typval_T *rettv)
7901{
7902 float_T f = 0.0;
7903
7904 rettv->v_type = VAR_FLOAT;
7905 if (get_float_arg(argvars, &f) == OK)
7906 rettv->vval.v_float = log10(f);
7907 else
7908 rettv->vval.v_float = 0.0;
7909}
7910#endif
7911
7912#ifdef FEAT_LUA
7913/*
7914 * "luaeval()" function
7915 */
7916 static void
7917f_luaeval(typval_T *argvars, typval_T *rettv)
7918{
7919 char_u *str;
7920 char_u buf[NUMBUFLEN];
7921
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007922 if (check_restricted() || check_secure())
7923 return;
7924
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007925 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007926 do_luaeval(str, argvars + 1, rettv);
7927}
7928#endif
7929
7930/*
7931 * "map()" function
7932 */
7933 static void
7934f_map(typval_T *argvars, typval_T *rettv)
7935{
7936 filter_map(argvars, rettv, TRUE);
7937}
7938
7939/*
7940 * "maparg()" function
7941 */
7942 static void
7943f_maparg(typval_T *argvars, typval_T *rettv)
7944{
7945 get_maparg(argvars, rettv, TRUE);
7946}
7947
7948/*
7949 * "mapcheck()" function
7950 */
7951 static void
7952f_mapcheck(typval_T *argvars, typval_T *rettv)
7953{
7954 get_maparg(argvars, rettv, FALSE);
7955}
7956
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007957typedef enum
7958{
7959 MATCH_END, /* matchend() */
7960 MATCH_MATCH, /* match() */
7961 MATCH_STR, /* matchstr() */
7962 MATCH_LIST, /* matchlist() */
7963 MATCH_POS /* matchstrpos() */
7964} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007965
7966 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007967find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007968{
7969 char_u *str = NULL;
7970 long len = 0;
7971 char_u *expr = NULL;
7972 char_u *pat;
7973 regmatch_T regmatch;
7974 char_u patbuf[NUMBUFLEN];
7975 char_u strbuf[NUMBUFLEN];
7976 char_u *save_cpo;
7977 long start = 0;
7978 long nth = 1;
7979 colnr_T startcol = 0;
7980 int match = 0;
7981 list_T *l = NULL;
7982 listitem_T *li = NULL;
7983 long idx = 0;
7984 char_u *tofree = NULL;
7985
7986 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7987 save_cpo = p_cpo;
7988 p_cpo = (char_u *)"";
7989
7990 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007991 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007993 /* type MATCH_LIST: return empty list when there are no matches.
7994 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995 if (rettv_list_alloc(rettv) == FAIL)
7996 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007997 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007998 && (list_append_string(rettv->vval.v_list,
7999 (char_u *)"", 0) == FAIL
8000 || list_append_number(rettv->vval.v_list,
8001 (varnumber_T)-1) == FAIL
8002 || list_append_number(rettv->vval.v_list,
8003 (varnumber_T)-1) == FAIL
8004 || list_append_number(rettv->vval.v_list,
8005 (varnumber_T)-1) == FAIL))
8006 {
8007 list_free(rettv->vval.v_list);
8008 rettv->vval.v_list = NULL;
8009 goto theend;
8010 }
8011 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008012 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008013 {
8014 rettv->v_type = VAR_STRING;
8015 rettv->vval.v_string = NULL;
8016 }
8017
8018 if (argvars[0].v_type == VAR_LIST)
8019 {
8020 if ((l = argvars[0].vval.v_list) == NULL)
8021 goto theend;
8022 li = l->lv_first;
8023 }
8024 else
8025 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008026 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008027 len = (long)STRLEN(str);
8028 }
8029
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008030 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008031 if (pat == NULL)
8032 goto theend;
8033
8034 if (argvars[2].v_type != VAR_UNKNOWN)
8035 {
8036 int error = FALSE;
8037
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008038 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039 if (error)
8040 goto theend;
8041 if (l != NULL)
8042 {
8043 li = list_find(l, start);
8044 if (li == NULL)
8045 goto theend;
8046 idx = l->lv_idx; /* use the cached index */
8047 }
8048 else
8049 {
8050 if (start < 0)
8051 start = 0;
8052 if (start > len)
8053 goto theend;
8054 /* When "count" argument is there ignore matches before "start",
8055 * otherwise skip part of the string. Differs when pattern is "^"
8056 * or "\<". */
8057 if (argvars[3].v_type != VAR_UNKNOWN)
8058 startcol = start;
8059 else
8060 {
8061 str += start;
8062 len -= start;
8063 }
8064 }
8065
8066 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008067 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008068 if (error)
8069 goto theend;
8070 }
8071
8072 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8073 if (regmatch.regprog != NULL)
8074 {
8075 regmatch.rm_ic = p_ic;
8076
8077 for (;;)
8078 {
8079 if (l != NULL)
8080 {
8081 if (li == NULL)
8082 {
8083 match = FALSE;
8084 break;
8085 }
8086 vim_free(tofree);
8087 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8088 if (str == NULL)
8089 break;
8090 }
8091
8092 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8093
8094 if (match && --nth <= 0)
8095 break;
8096 if (l == NULL && !match)
8097 break;
8098
8099 /* Advance to just after the match. */
8100 if (l != NULL)
8101 {
8102 li = li->li_next;
8103 ++idx;
8104 }
8105 else
8106 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008107 startcol = (colnr_T)(regmatch.startp[0]
8108 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008109 if (startcol > (colnr_T)len
8110 || str + startcol <= regmatch.startp[0])
8111 {
8112 match = FALSE;
8113 break;
8114 }
8115 }
8116 }
8117
8118 if (match)
8119 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008120 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008121 {
8122 listitem_T *li1 = rettv->vval.v_list->lv_first;
8123 listitem_T *li2 = li1->li_next;
8124 listitem_T *li3 = li2->li_next;
8125 listitem_T *li4 = li3->li_next;
8126
8127 vim_free(li1->li_tv.vval.v_string);
8128 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8129 (int)(regmatch.endp[0] - regmatch.startp[0]));
8130 li3->li_tv.vval.v_number =
8131 (varnumber_T)(regmatch.startp[0] - expr);
8132 li4->li_tv.vval.v_number =
8133 (varnumber_T)(regmatch.endp[0] - expr);
8134 if (l != NULL)
8135 li2->li_tv.vval.v_number = (varnumber_T)idx;
8136 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008137 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008138 {
8139 int i;
8140
8141 /* return list with matched string and submatches */
8142 for (i = 0; i < NSUBEXP; ++i)
8143 {
8144 if (regmatch.endp[i] == NULL)
8145 {
8146 if (list_append_string(rettv->vval.v_list,
8147 (char_u *)"", 0) == FAIL)
8148 break;
8149 }
8150 else if (list_append_string(rettv->vval.v_list,
8151 regmatch.startp[i],
8152 (int)(regmatch.endp[i] - regmatch.startp[i]))
8153 == FAIL)
8154 break;
8155 }
8156 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008157 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158 {
8159 /* return matched string */
8160 if (l != NULL)
8161 copy_tv(&li->li_tv, rettv);
8162 else
8163 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8164 (int)(regmatch.endp[0] - regmatch.startp[0]));
8165 }
8166 else if (l != NULL)
8167 rettv->vval.v_number = idx;
8168 else
8169 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008170 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008171 rettv->vval.v_number =
8172 (varnumber_T)(regmatch.startp[0] - str);
8173 else
8174 rettv->vval.v_number =
8175 (varnumber_T)(regmatch.endp[0] - str);
8176 rettv->vval.v_number += (varnumber_T)(str - expr);
8177 }
8178 }
8179 vim_regfree(regmatch.regprog);
8180 }
8181
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008182theend:
8183 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 /* matchstrpos() without a list: drop the second item. */
8185 listitem_remove(rettv->vval.v_list,
8186 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008187 vim_free(tofree);
8188 p_cpo = save_cpo;
8189}
8190
8191/*
8192 * "match()" function
8193 */
8194 static void
8195f_match(typval_T *argvars, typval_T *rettv)
8196{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008197 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008198}
8199
Bram Moolenaar95e51472018-07-28 16:55:56 +02008200#ifdef FEAT_SEARCH_EXTRA
8201 static int
8202matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8203{
8204 dictitem_T *di;
8205
8206 if (tv->v_type != VAR_DICT)
8207 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008208 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008209 return FAIL;
8210 }
8211
8212 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008213 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008214 (char_u *)"conceal", FALSE);
8215
8216 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8217 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008218 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008219 if (*win == NULL)
8220 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008221 emsg(_("E957: Invalid window number"));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008222 return FAIL;
8223 }
8224 }
8225
8226 return OK;
8227}
8228#endif
8229
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008230/*
8231 * "matchadd()" function
8232 */
8233 static void
8234f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8235{
8236#ifdef FEAT_SEARCH_EXTRA
8237 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008238 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8239 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008240 int prio = 10; /* default priority */
8241 int id = -1;
8242 int error = FALSE;
8243 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008244 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008245
8246 rettv->vval.v_number = -1;
8247
8248 if (grp == NULL || pat == NULL)
8249 return;
8250 if (argvars[2].v_type != VAR_UNKNOWN)
8251 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008252 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008253 if (argvars[3].v_type != VAR_UNKNOWN)
8254 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008255 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008256 if (argvars[4].v_type != VAR_UNKNOWN
8257 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8258 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 }
8260 }
8261 if (error == TRUE)
8262 return;
8263 if (id >= 1 && id <= 3)
8264 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008265 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008266 return;
8267 }
8268
Bram Moolenaar95e51472018-07-28 16:55:56 +02008269 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008270 conceal_char);
8271#endif
8272}
8273
8274/*
8275 * "matchaddpos()" function
8276 */
8277 static void
8278f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8279{
8280#ifdef FEAT_SEARCH_EXTRA
8281 char_u buf[NUMBUFLEN];
8282 char_u *group;
8283 int prio = 10;
8284 int id = -1;
8285 int error = FALSE;
8286 list_T *l;
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
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008292 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008293 if (group == NULL)
8294 return;
8295
8296 if (argvars[1].v_type != VAR_LIST)
8297 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008298 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008299 return;
8300 }
8301 l = argvars[1].vval.v_list;
8302 if (l == NULL)
8303 return;
8304
8305 if (argvars[2].v_type != VAR_UNKNOWN)
8306 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008307 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308 if (argvars[3].v_type != VAR_UNKNOWN)
8309 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008310 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008311
8312 if (argvars[4].v_type != VAR_UNKNOWN
8313 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8314 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008315 }
8316 }
8317 if (error == TRUE)
8318 return;
8319
8320 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8321 if (id == 1 || id == 2)
8322 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008323 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008324 return;
8325 }
8326
Bram Moolenaar95e51472018-07-28 16:55:56 +02008327 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008328 conceal_char);
8329#endif
8330}
8331
8332/*
8333 * "matcharg()" function
8334 */
8335 static void
8336f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8337{
8338 if (rettv_list_alloc(rettv) == OK)
8339 {
8340#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008341 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 matchitem_T *m;
8343
8344 if (id >= 1 && id <= 3)
8345 {
8346 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8347 {
8348 list_append_string(rettv->vval.v_list,
8349 syn_id2name(m->hlg_id), -1);
8350 list_append_string(rettv->vval.v_list, m->pattern, -1);
8351 }
8352 else
8353 {
8354 list_append_string(rettv->vval.v_list, NULL, -1);
8355 list_append_string(rettv->vval.v_list, NULL, -1);
8356 }
8357 }
8358#endif
8359 }
8360}
8361
8362/*
8363 * "matchdelete()" function
8364 */
8365 static void
8366f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8367{
8368#ifdef FEAT_SEARCH_EXTRA
8369 rettv->vval.v_number = match_delete(curwin,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008370 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371#endif
8372}
8373
8374/*
8375 * "matchend()" function
8376 */
8377 static void
8378f_matchend(typval_T *argvars, typval_T *rettv)
8379{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008380 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008381}
8382
8383/*
8384 * "matchlist()" function
8385 */
8386 static void
8387f_matchlist(typval_T *argvars, typval_T *rettv)
8388{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008389 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390}
8391
8392/*
8393 * "matchstr()" function
8394 */
8395 static void
8396f_matchstr(typval_T *argvars, typval_T *rettv)
8397{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008398 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008399}
8400
8401/*
8402 * "matchstrpos()" function
8403 */
8404 static void
8405f_matchstrpos(typval_T *argvars, typval_T *rettv)
8406{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008407 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008408}
8409
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008410 static void
8411max_min(typval_T *argvars, typval_T *rettv, int domax)
8412{
8413 varnumber_T n = 0;
8414 varnumber_T i;
8415 int error = FALSE;
8416
8417 if (argvars[0].v_type == VAR_LIST)
8418 {
8419 list_T *l;
8420 listitem_T *li;
8421
8422 l = argvars[0].vval.v_list;
8423 if (l != NULL)
8424 {
8425 li = l->lv_first;
8426 if (li != NULL)
8427 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008428 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008429 for (;;)
8430 {
8431 li = li->li_next;
8432 if (li == NULL)
8433 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008434 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008435 if (domax ? i > n : i < n)
8436 n = i;
8437 }
8438 }
8439 }
8440 }
8441 else if (argvars[0].v_type == VAR_DICT)
8442 {
8443 dict_T *d;
8444 int first = TRUE;
8445 hashitem_T *hi;
8446 int todo;
8447
8448 d = argvars[0].vval.v_dict;
8449 if (d != NULL)
8450 {
8451 todo = (int)d->dv_hashtab.ht_used;
8452 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8453 {
8454 if (!HASHITEM_EMPTY(hi))
8455 {
8456 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008457 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458 if (first)
8459 {
8460 n = i;
8461 first = FALSE;
8462 }
8463 else if (domax ? i > n : i < n)
8464 n = i;
8465 }
8466 }
8467 }
8468 }
8469 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008470 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008471 rettv->vval.v_number = error ? 0 : n;
8472}
8473
8474/*
8475 * "max()" function
8476 */
8477 static void
8478f_max(typval_T *argvars, typval_T *rettv)
8479{
8480 max_min(argvars, rettv, TRUE);
8481}
8482
8483/*
8484 * "min()" function
8485 */
8486 static void
8487f_min(typval_T *argvars, typval_T *rettv)
8488{
8489 max_min(argvars, rettv, FALSE);
8490}
8491
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008492/*
8493 * Create the directory in which "dir" is located, and higher levels when
8494 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008495 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008496 */
8497 static int
8498mkdir_recurse(char_u *dir, int prot)
8499{
8500 char_u *p;
8501 char_u *updir;
8502 int r = FAIL;
8503
8504 /* Get end of directory name in "dir".
8505 * We're done when it's "/" or "c:/". */
8506 p = gettail_sep(dir);
8507 if (p <= get_past_head(dir))
8508 return OK;
8509
8510 /* If the directory exists we're done. Otherwise: create it.*/
8511 updir = vim_strnsave(dir, (int)(p - dir));
8512 if (updir == NULL)
8513 return FAIL;
8514 if (mch_isdir(updir))
8515 r = OK;
8516 else if (mkdir_recurse(updir, prot) == OK)
8517 r = vim_mkdir_emsg(updir, prot);
8518 vim_free(updir);
8519 return r;
8520}
8521
8522#ifdef vim_mkdir
8523/*
8524 * "mkdir()" function
8525 */
8526 static void
8527f_mkdir(typval_T *argvars, typval_T *rettv)
8528{
8529 char_u *dir;
8530 char_u buf[NUMBUFLEN];
8531 int prot = 0755;
8532
8533 rettv->vval.v_number = FAIL;
8534 if (check_restricted() || check_secure())
8535 return;
8536
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008537 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008538 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008539 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008540
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008541 if (*gettail(dir) == NUL)
8542 /* remove trailing slashes */
8543 *gettail_sep(dir) = NUL;
8544
8545 if (argvars[1].v_type != VAR_UNKNOWN)
8546 {
8547 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008548 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008549 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008550 if (prot == -1)
8551 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008552 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008553 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008554 {
8555 if (mch_isdir(dir))
8556 {
8557 /* With the "p" flag it's OK if the dir already exists. */
8558 rettv->vval.v_number = OK;
8559 return;
8560 }
8561 mkdir_recurse(dir, prot);
8562 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008563 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008564 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008565}
8566#endif
8567
8568/*
8569 * "mode()" function
8570 */
8571 static void
8572f_mode(typval_T *argvars, typval_T *rettv)
8573{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008574 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008575
Bram Moolenaar612cc382018-07-29 15:34:26 +02008576 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008577
8578 if (time_for_testing == 93784)
8579 {
8580 /* Testing the two-character code. */
8581 buf[0] = 'x';
8582 buf[1] = '!';
8583 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008584#ifdef FEAT_TERMINAL
8585 else if (term_use_loop())
8586 buf[0] = 't';
8587#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008588 else if (VIsual_active)
8589 {
8590 if (VIsual_select)
8591 buf[0] = VIsual_mode + 's' - 'v';
8592 else
8593 buf[0] = VIsual_mode;
8594 }
8595 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8596 || State == CONFIRM)
8597 {
8598 buf[0] = 'r';
8599 if (State == ASKMORE)
8600 buf[1] = 'm';
8601 else if (State == CONFIRM)
8602 buf[1] = '?';
8603 }
8604 else if (State == EXTERNCMD)
8605 buf[0] = '!';
8606 else if (State & INSERT)
8607 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608 if (State & VREPLACE_FLAG)
8609 {
8610 buf[0] = 'R';
8611 buf[1] = 'v';
8612 }
8613 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008614 {
8615 if (State & REPLACE_FLAG)
8616 buf[0] = 'R';
8617 else
8618 buf[0] = 'i';
8619#ifdef FEAT_INS_EXPAND
8620 if (ins_compl_active())
8621 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008622 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008623 buf[1] = 'x';
8624#endif
8625 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008626 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008627 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008628 {
8629 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008630 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008631 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008632 else if (exmode_active == EXMODE_NORMAL)
8633 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008634 }
8635 else
8636 {
8637 buf[0] = 'n';
8638 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008639 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008640 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008641 // to be able to detect force-linewise/blockwise/characterwise operations
8642 buf[2] = motion_force;
8643 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008644 else if (restart_edit == 'I' || restart_edit == 'R'
8645 || restart_edit == 'V')
8646 {
8647 buf[1] = 'i';
8648 buf[2] = restart_edit;
8649 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008650 }
8651
8652 /* Clear out the minor mode when the argument is not a non-zero number or
8653 * non-empty string. */
8654 if (!non_zero_arg(&argvars[0]))
8655 buf[1] = NUL;
8656
8657 rettv->vval.v_string = vim_strsave(buf);
8658 rettv->v_type = VAR_STRING;
8659}
8660
8661#if defined(FEAT_MZSCHEME) || defined(PROTO)
8662/*
8663 * "mzeval()" function
8664 */
8665 static void
8666f_mzeval(typval_T *argvars, typval_T *rettv)
8667{
8668 char_u *str;
8669 char_u buf[NUMBUFLEN];
8670
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008671 if (check_restricted() || check_secure())
8672 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008673 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008674 do_mzeval(str, rettv);
8675}
8676
8677 void
8678mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8679{
8680 typval_T argvars[3];
8681
8682 argvars[0].v_type = VAR_STRING;
8683 argvars[0].vval.v_string = name;
8684 copy_tv(args, &argvars[1]);
8685 argvars[2].v_type = VAR_UNKNOWN;
8686 f_call(argvars, rettv);
8687 clear_tv(&argvars[1]);
8688}
8689#endif
8690
8691/*
8692 * "nextnonblank()" function
8693 */
8694 static void
8695f_nextnonblank(typval_T *argvars, typval_T *rettv)
8696{
8697 linenr_T lnum;
8698
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008699 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008700 {
8701 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8702 {
8703 lnum = 0;
8704 break;
8705 }
8706 if (*skipwhite(ml_get(lnum)) != NUL)
8707 break;
8708 }
8709 rettv->vval.v_number = lnum;
8710}
8711
8712/*
8713 * "nr2char()" function
8714 */
8715 static void
8716f_nr2char(typval_T *argvars, typval_T *rettv)
8717{
8718 char_u buf[NUMBUFLEN];
8719
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 if (has_mbyte)
8721 {
8722 int utf8 = 0;
8723
8724 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008725 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008727 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008728 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008729 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008730 }
8731 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008732 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008733 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008734 buf[1] = NUL;
8735 }
8736 rettv->v_type = VAR_STRING;
8737 rettv->vval.v_string = vim_strsave(buf);
8738}
8739
8740/*
8741 * "or(expr, expr)" function
8742 */
8743 static void
8744f_or(typval_T *argvars, typval_T *rettv)
8745{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008746 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8747 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008748}
8749
8750/*
8751 * "pathshorten()" function
8752 */
8753 static void
8754f_pathshorten(typval_T *argvars, typval_T *rettv)
8755{
8756 char_u *p;
8757
8758 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008759 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008760 if (p == NULL)
8761 rettv->vval.v_string = NULL;
8762 else
8763 {
8764 p = vim_strsave(p);
8765 rettv->vval.v_string = p;
8766 if (p != NULL)
8767 shorten_dir(p);
8768 }
8769}
8770
8771#ifdef FEAT_PERL
8772/*
8773 * "perleval()" function
8774 */
8775 static void
8776f_perleval(typval_T *argvars, typval_T *rettv)
8777{
8778 char_u *str;
8779 char_u buf[NUMBUFLEN];
8780
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008781 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008782 do_perleval(str, rettv);
8783}
8784#endif
8785
8786#ifdef FEAT_FLOAT
8787/*
8788 * "pow()" function
8789 */
8790 static void
8791f_pow(typval_T *argvars, typval_T *rettv)
8792{
8793 float_T fx = 0.0, fy = 0.0;
8794
8795 rettv->v_type = VAR_FLOAT;
8796 if (get_float_arg(argvars, &fx) == OK
8797 && get_float_arg(&argvars[1], &fy) == OK)
8798 rettv->vval.v_float = pow(fx, fy);
8799 else
8800 rettv->vval.v_float = 0.0;
8801}
8802#endif
8803
8804/*
8805 * "prevnonblank()" function
8806 */
8807 static void
8808f_prevnonblank(typval_T *argvars, typval_T *rettv)
8809{
8810 linenr_T lnum;
8811
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008812 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008813 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8814 lnum = 0;
8815 else
8816 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8817 --lnum;
8818 rettv->vval.v_number = lnum;
8819}
8820
8821/* This dummy va_list is here because:
8822 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8823 * - locally in the function results in a "used before set" warning
8824 * - using va_start() to initialize it gives "function with fixed args" error */
8825static va_list ap;
8826
8827/*
8828 * "printf()" function
8829 */
8830 static void
8831f_printf(typval_T *argvars, typval_T *rettv)
8832{
8833 char_u buf[NUMBUFLEN];
8834 int len;
8835 char_u *s;
8836 int saved_did_emsg = did_emsg;
8837 char *fmt;
8838
8839 rettv->v_type = VAR_STRING;
8840 rettv->vval.v_string = NULL;
8841
8842 /* Get the required length, allocate the buffer and do it for real. */
8843 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008844 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008845 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008846 if (!did_emsg)
8847 {
8848 s = alloc(len + 1);
8849 if (s != NULL)
8850 {
8851 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008852 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8853 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854 }
8855 }
8856 did_emsg |= saved_did_emsg;
8857}
8858
Bram Moolenaarf2732452018-06-03 14:47:35 +02008859#ifdef FEAT_JOB_CHANNEL
8860/*
8861 * "prompt_setcallback({buffer}, {callback})" function
8862 */
8863 static void
8864f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8865{
8866 buf_T *buf;
8867 char_u *callback;
8868 partial_T *partial;
8869
8870 if (check_secure())
8871 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008872 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008873 if (buf == NULL)
8874 return;
8875
8876 callback = get_callback(&argvars[1], &partial);
8877 if (callback == NULL)
8878 return;
8879
8880 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8881 if (partial == NULL)
8882 buf->b_prompt_callback = vim_strsave(callback);
8883 else
8884 /* pointer into the partial */
8885 buf->b_prompt_callback = callback;
8886 buf->b_prompt_partial = partial;
8887}
8888
8889/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008890 * "prompt_setinterrupt({buffer}, {callback})" function
8891 */
8892 static void
8893f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8894{
8895 buf_T *buf;
8896 char_u *callback;
8897 partial_T *partial;
8898
8899 if (check_secure())
8900 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008901 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008902 if (buf == NULL)
8903 return;
8904
8905 callback = get_callback(&argvars[1], &partial);
8906 if (callback == NULL)
8907 return;
8908
8909 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8910 if (partial == NULL)
8911 buf->b_prompt_interrupt = vim_strsave(callback);
8912 else
8913 /* pointer into the partial */
8914 buf->b_prompt_interrupt = callback;
8915 buf->b_prompt_int_partial = partial;
8916}
8917
8918/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008919 * "prompt_setprompt({buffer}, {text})" function
8920 */
8921 static void
8922f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8923{
8924 buf_T *buf;
8925 char_u *text;
8926
8927 if (check_secure())
8928 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008929 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008930 if (buf == NULL)
8931 return;
8932
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008933 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008934 vim_free(buf->b_prompt_text);
8935 buf->b_prompt_text = vim_strsave(text);
8936}
8937#endif
8938
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008939/*
8940 * "pumvisible()" function
8941 */
8942 static void
8943f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8944{
8945#ifdef FEAT_INS_EXPAND
8946 if (pum_visible())
8947 rettv->vval.v_number = 1;
8948#endif
8949}
8950
8951#ifdef FEAT_PYTHON3
8952/*
8953 * "py3eval()" function
8954 */
8955 static void
8956f_py3eval(typval_T *argvars, typval_T *rettv)
8957{
8958 char_u *str;
8959 char_u buf[NUMBUFLEN];
8960
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008961 if (check_restricted() || check_secure())
8962 return;
8963
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008964 if (p_pyx == 0)
8965 p_pyx = 3;
8966
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008967 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008968 do_py3eval(str, rettv);
8969}
8970#endif
8971
8972#ifdef FEAT_PYTHON
8973/*
8974 * "pyeval()" function
8975 */
8976 static void
8977f_pyeval(typval_T *argvars, typval_T *rettv)
8978{
8979 char_u *str;
8980 char_u buf[NUMBUFLEN];
8981
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008982 if (check_restricted() || check_secure())
8983 return;
8984
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008985 if (p_pyx == 0)
8986 p_pyx = 2;
8987
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008988 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008989 do_pyeval(str, rettv);
8990}
8991#endif
8992
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008993#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8994/*
8995 * "pyxeval()" function
8996 */
8997 static void
8998f_pyxeval(typval_T *argvars, typval_T *rettv)
8999{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009000 if (check_restricted() || check_secure())
9001 return;
9002
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009003# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9004 init_pyxversion();
9005 if (p_pyx == 2)
9006 f_pyeval(argvars, rettv);
9007 else
9008 f_py3eval(argvars, rettv);
9009# elif defined(FEAT_PYTHON)
9010 f_pyeval(argvars, rettv);
9011# elif defined(FEAT_PYTHON3)
9012 f_py3eval(argvars, rettv);
9013# endif
9014}
9015#endif
9016
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009017/*
9018 * "range()" function
9019 */
9020 static void
9021f_range(typval_T *argvars, typval_T *rettv)
9022{
9023 varnumber_T start;
9024 varnumber_T end;
9025 varnumber_T stride = 1;
9026 varnumber_T i;
9027 int error = FALSE;
9028
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009029 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009030 if (argvars[1].v_type == VAR_UNKNOWN)
9031 {
9032 end = start - 1;
9033 start = 0;
9034 }
9035 else
9036 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009037 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009038 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009039 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009040 }
9041
9042 if (error)
9043 return; /* type error; errmsg already given */
9044 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009045 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009046 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009047 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009048 else
9049 {
9050 if (rettv_list_alloc(rettv) == OK)
9051 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9052 if (list_append_number(rettv->vval.v_list,
9053 (varnumber_T)i) == FAIL)
9054 break;
9055 }
9056}
9057
9058/*
9059 * "readfile()" function
9060 */
9061 static void
9062f_readfile(typval_T *argvars, typval_T *rettv)
9063{
9064 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009065 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009066 int failed = FALSE;
9067 char_u *fname;
9068 FILE *fd;
9069 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9070 int io_size = sizeof(buf);
9071 int readlen; /* size of last fread() */
9072 char_u *prev = NULL; /* previously read bytes, if any */
9073 long prevlen = 0; /* length of data in prev */
9074 long prevsize = 0; /* size of prev buffer */
9075 long maxline = MAXLNUM;
9076 long cnt = 0;
9077 char_u *p; /* position in buf */
9078 char_u *start; /* start of current line */
9079
9080 if (argvars[1].v_type != VAR_UNKNOWN)
9081 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009082 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009083 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009084 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9085 blob = TRUE;
9086
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009087 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009088 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009089 }
9090
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009091 if (blob)
9092 {
9093 if (rettv_blob_alloc(rettv) == FAIL)
9094 return;
9095 }
9096 else
9097 {
9098 if (rettv_list_alloc(rettv) == FAIL)
9099 return;
9100 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009101
9102 /* Always open the file in binary mode, library functions have a mind of
9103 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009104 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009105 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9106 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009107 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009108 return;
9109 }
9110
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009111 if (blob)
9112 {
9113 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9114 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009115 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009116 blob_free(rettv->vval.v_blob);
9117 }
9118 fclose(fd);
9119 return;
9120 }
9121
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009122 while (cnt < maxline || maxline < 0)
9123 {
9124 readlen = (int)fread(buf, 1, io_size, fd);
9125
9126 /* This for loop processes what was read, but is also entered at end
9127 * of file so that either:
9128 * - an incomplete line gets written
9129 * - a "binary" file gets an empty line at the end if it ends in a
9130 * newline. */
9131 for (p = buf, start = buf;
9132 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9133 ++p)
9134 {
9135 if (*p == '\n' || readlen <= 0)
9136 {
9137 listitem_T *li;
9138 char_u *s = NULL;
9139 long_u len = p - start;
9140
9141 /* Finished a line. Remove CRs before NL. */
9142 if (readlen > 0 && !binary)
9143 {
9144 while (len > 0 && start[len - 1] == '\r')
9145 --len;
9146 /* removal may cross back to the "prev" string */
9147 if (len == 0)
9148 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9149 --prevlen;
9150 }
9151 if (prevlen == 0)
9152 s = vim_strnsave(start, (int)len);
9153 else
9154 {
9155 /* Change "prev" buffer to be the right size. This way
9156 * the bytes are only copied once, and very long lines are
9157 * allocated only once. */
9158 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9159 {
9160 mch_memmove(s + prevlen, start, len);
9161 s[prevlen + len] = NUL;
9162 prev = NULL; /* the list will own the string */
9163 prevlen = prevsize = 0;
9164 }
9165 }
9166 if (s == NULL)
9167 {
9168 do_outofmem_msg((long_u) prevlen + len + 1);
9169 failed = TRUE;
9170 break;
9171 }
9172
9173 if ((li = listitem_alloc()) == NULL)
9174 {
9175 vim_free(s);
9176 failed = TRUE;
9177 break;
9178 }
9179 li->li_tv.v_type = VAR_STRING;
9180 li->li_tv.v_lock = 0;
9181 li->li_tv.vval.v_string = s;
9182 list_append(rettv->vval.v_list, li);
9183
9184 start = p + 1; /* step over newline */
9185 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9186 break;
9187 }
9188 else if (*p == NUL)
9189 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009190 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9191 * when finding the BF and check the previous two bytes. */
9192 else if (*p == 0xbf && enc_utf8 && !binary)
9193 {
9194 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9195 * + 1, these may be in the "prev" string. */
9196 char_u back1 = p >= buf + 1 ? p[-1]
9197 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9198 char_u back2 = p >= buf + 2 ? p[-2]
9199 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9200 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9201
9202 if (back2 == 0xef && back1 == 0xbb)
9203 {
9204 char_u *dest = p - 2;
9205
9206 /* Usually a BOM is at the beginning of a file, and so at
9207 * the beginning of a line; then we can just step over it.
9208 */
9209 if (start == dest)
9210 start = p + 1;
9211 else
9212 {
9213 /* have to shuffle buf to close gap */
9214 int adjust_prevlen = 0;
9215
9216 if (dest < buf)
9217 {
9218 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9219 dest = buf;
9220 }
9221 if (readlen > p - buf + 1)
9222 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9223 readlen -= 3 - adjust_prevlen;
9224 prevlen -= adjust_prevlen;
9225 p = dest - 1;
9226 }
9227 }
9228 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009229 } /* for */
9230
9231 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9232 break;
9233 if (start < p)
9234 {
9235 /* There's part of a line in buf, store it in "prev". */
9236 if (p - start + prevlen >= prevsize)
9237 {
9238 /* need bigger "prev" buffer */
9239 char_u *newprev;
9240
9241 /* A common use case is ordinary text files and "prev" gets a
9242 * fragment of a line, so the first allocation is made
9243 * small, to avoid repeatedly 'allocing' large and
9244 * 'reallocing' small. */
9245 if (prevsize == 0)
9246 prevsize = (long)(p - start);
9247 else
9248 {
9249 long grow50pc = (prevsize * 3) / 2;
9250 long growmin = (long)((p - start) * 2 + prevlen);
9251 prevsize = grow50pc > growmin ? grow50pc : growmin;
9252 }
9253 newprev = prev == NULL ? alloc(prevsize)
9254 : vim_realloc(prev, prevsize);
9255 if (newprev == NULL)
9256 {
9257 do_outofmem_msg((long_u)prevsize);
9258 failed = TRUE;
9259 break;
9260 }
9261 prev = newprev;
9262 }
9263 /* Add the line part to end of "prev". */
9264 mch_memmove(prev + prevlen, start, p - start);
9265 prevlen += (long)(p - start);
9266 }
9267 } /* while */
9268
9269 /*
9270 * For a negative line count use only the lines at the end of the file,
9271 * free the rest.
9272 */
9273 if (!failed && maxline < 0)
9274 while (cnt > -maxline)
9275 {
9276 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9277 --cnt;
9278 }
9279
9280 if (failed)
9281 {
9282 list_free(rettv->vval.v_list);
9283 /* readfile doc says an empty list is returned on error */
9284 rettv->vval.v_list = list_alloc();
9285 }
9286
9287 vim_free(prev);
9288 fclose(fd);
9289}
9290
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009291 static void
9292return_register(int regname, typval_T *rettv)
9293{
9294 char_u buf[2] = {0, 0};
9295
9296 buf[0] = (char_u)regname;
9297 rettv->v_type = VAR_STRING;
9298 rettv->vval.v_string = vim_strsave(buf);
9299}
9300
9301/*
9302 * "reg_executing()" function
9303 */
9304 static void
9305f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9306{
9307 return_register(reg_executing, rettv);
9308}
9309
9310/*
9311 * "reg_recording()" function
9312 */
9313 static void
9314f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9315{
9316 return_register(reg_recording, rettv);
9317}
9318
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009319#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009320/*
9321 * Convert a List to proftime_T.
9322 * Return FAIL when there is something wrong.
9323 */
9324 static int
9325list2proftime(typval_T *arg, proftime_T *tm)
9326{
9327 long n1, n2;
9328 int error = FALSE;
9329
9330 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9331 || arg->vval.v_list->lv_len != 2)
9332 return FAIL;
9333 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9334 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009335# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009336 tm->HighPart = n1;
9337 tm->LowPart = n2;
9338# else
9339 tm->tv_sec = n1;
9340 tm->tv_usec = n2;
9341# endif
9342 return error ? FAIL : OK;
9343}
9344#endif /* FEAT_RELTIME */
9345
9346/*
9347 * "reltime()" function
9348 */
9349 static void
9350f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9351{
9352#ifdef FEAT_RELTIME
9353 proftime_T res;
9354 proftime_T start;
9355
9356 if (argvars[0].v_type == VAR_UNKNOWN)
9357 {
9358 /* No arguments: get current time. */
9359 profile_start(&res);
9360 }
9361 else if (argvars[1].v_type == VAR_UNKNOWN)
9362 {
9363 if (list2proftime(&argvars[0], &res) == FAIL)
9364 return;
9365 profile_end(&res);
9366 }
9367 else
9368 {
9369 /* Two arguments: compute the difference. */
9370 if (list2proftime(&argvars[0], &start) == FAIL
9371 || list2proftime(&argvars[1], &res) == FAIL)
9372 return;
9373 profile_sub(&res, &start);
9374 }
9375
9376 if (rettv_list_alloc(rettv) == OK)
9377 {
9378 long n1, n2;
9379
Bram Moolenaar4f974752019-02-17 17:44:42 +01009380# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009381 n1 = res.HighPart;
9382 n2 = res.LowPart;
9383# else
9384 n1 = res.tv_sec;
9385 n2 = res.tv_usec;
9386# endif
9387 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9388 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9389 }
9390#endif
9391}
9392
9393#ifdef FEAT_FLOAT
9394/*
9395 * "reltimefloat()" function
9396 */
9397 static void
9398f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9399{
9400# ifdef FEAT_RELTIME
9401 proftime_T tm;
9402# endif
9403
9404 rettv->v_type = VAR_FLOAT;
9405 rettv->vval.v_float = 0;
9406# ifdef FEAT_RELTIME
9407 if (list2proftime(&argvars[0], &tm) == OK)
9408 rettv->vval.v_float = profile_float(&tm);
9409# endif
9410}
9411#endif
9412
9413/*
9414 * "reltimestr()" function
9415 */
9416 static void
9417f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9418{
9419#ifdef FEAT_RELTIME
9420 proftime_T tm;
9421#endif
9422
9423 rettv->v_type = VAR_STRING;
9424 rettv->vval.v_string = NULL;
9425#ifdef FEAT_RELTIME
9426 if (list2proftime(&argvars[0], &tm) == OK)
9427 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9428#endif
9429}
9430
9431#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009432 static void
9433make_connection(void)
9434{
9435 if (X_DISPLAY == NULL
9436# ifdef FEAT_GUI
9437 && !gui.in_use
9438# endif
9439 )
9440 {
9441 x_force_connect = TRUE;
9442 setup_term_clip();
9443 x_force_connect = FALSE;
9444 }
9445}
9446
9447 static int
9448check_connection(void)
9449{
9450 make_connection();
9451 if (X_DISPLAY == NULL)
9452 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009453 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009454 return FAIL;
9455 }
9456 return OK;
9457}
9458#endif
9459
9460#ifdef FEAT_CLIENTSERVER
9461 static void
9462remote_common(typval_T *argvars, typval_T *rettv, int expr)
9463{
9464 char_u *server_name;
9465 char_u *keys;
9466 char_u *r = NULL;
9467 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009468 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009469# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009470 HWND w;
9471# else
9472 Window w;
9473# endif
9474
9475 if (check_restricted() || check_secure())
9476 return;
9477
9478# ifdef FEAT_X11
9479 if (check_connection() == FAIL)
9480 return;
9481# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009482 if (argvars[2].v_type != VAR_UNKNOWN
9483 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009484 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009485
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009486 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 if (server_name == NULL)
9488 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009489 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009490# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009491 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009493 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9494 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009495# endif
9496 {
9497 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009498 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009499 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009500 vim_free(r);
9501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009502 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009503 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009504 return;
9505 }
9506
9507 rettv->vval.v_string = r;
9508
9509 if (argvars[2].v_type != VAR_UNKNOWN)
9510 {
9511 dictitem_T v;
9512 char_u str[30];
9513 char_u *idvar;
9514
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009515 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009516 if (idvar != NULL && *idvar != NUL)
9517 {
9518 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9519 v.di_tv.v_type = VAR_STRING;
9520 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009521 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009522 vim_free(v.di_tv.vval.v_string);
9523 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009524 }
9525}
9526#endif
9527
9528/*
9529 * "remote_expr()" function
9530 */
9531 static void
9532f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9533{
9534 rettv->v_type = VAR_STRING;
9535 rettv->vval.v_string = NULL;
9536#ifdef FEAT_CLIENTSERVER
9537 remote_common(argvars, rettv, TRUE);
9538#endif
9539}
9540
9541/*
9542 * "remote_foreground()" function
9543 */
9544 static void
9545f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9546{
9547#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009548# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009549 /* On Win32 it's done in this application. */
9550 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009551 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009552
9553 if (server_name != NULL)
9554 serverForeground(server_name);
9555 }
9556# else
9557 /* Send a foreground() expression to the server. */
9558 argvars[1].v_type = VAR_STRING;
9559 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9560 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009561 rettv->v_type = VAR_STRING;
9562 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009563 remote_common(argvars, rettv, TRUE);
9564 vim_free(argvars[1].vval.v_string);
9565# endif
9566#endif
9567}
9568
9569 static void
9570f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9571{
9572#ifdef FEAT_CLIENTSERVER
9573 dictitem_T v;
9574 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009575# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009576 long_u n = 0;
9577# endif
9578 char_u *serverid;
9579
9580 if (check_restricted() || check_secure())
9581 {
9582 rettv->vval.v_number = -1;
9583 return;
9584 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009585 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009586 if (serverid == NULL)
9587 {
9588 rettv->vval.v_number = -1;
9589 return; /* type error; errmsg already given */
9590 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009591# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009592 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9593 if (n == 0)
9594 rettv->vval.v_number = -1;
9595 else
9596 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009597 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009598 rettv->vval.v_number = (s != NULL);
9599 }
9600# else
9601 if (check_connection() == FAIL)
9602 return;
9603
9604 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9605 serverStrToWin(serverid), &s);
9606# endif
9607
9608 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9609 {
9610 char_u *retvar;
9611
9612 v.di_tv.v_type = VAR_STRING;
9613 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009614 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009615 if (retvar != NULL)
9616 set_var(retvar, &v.di_tv, FALSE);
9617 vim_free(v.di_tv.vval.v_string);
9618 }
9619#else
9620 rettv->vval.v_number = -1;
9621#endif
9622}
9623
9624 static void
9625f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9626{
9627 char_u *r = NULL;
9628
9629#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009630 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009631
9632 if (serverid != NULL && !check_restricted() && !check_secure())
9633 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009634 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009635# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009636 /* The server's HWND is encoded in the 'id' parameter */
9637 long_u n = 0;
9638# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009639
9640 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009641 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009642
Bram Moolenaar4f974752019-02-17 17:44:42 +01009643# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009644 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9645 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009646 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009647 if (r == NULL)
9648# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009649 if (check_connection() == FAIL
9650 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9651 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009652# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009653 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009654 }
9655#endif
9656 rettv->v_type = VAR_STRING;
9657 rettv->vval.v_string = r;
9658}
9659
9660/*
9661 * "remote_send()" function
9662 */
9663 static void
9664f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9665{
9666 rettv->v_type = VAR_STRING;
9667 rettv->vval.v_string = NULL;
9668#ifdef FEAT_CLIENTSERVER
9669 remote_common(argvars, rettv, FALSE);
9670#endif
9671}
9672
9673/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009674 * "remote_startserver()" function
9675 */
9676 static void
9677f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9678{
9679#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009680 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009681
9682 if (server == NULL)
9683 return; /* type error; errmsg already given */
9684 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009685 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009686 else
9687 {
9688# ifdef FEAT_X11
9689 if (check_connection() == OK)
9690 serverRegisterName(X_DISPLAY, server);
9691# else
9692 serverSetName(server);
9693# endif
9694 }
9695#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009696 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009697#endif
9698}
9699
9700/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009701 * "remove()" function
9702 */
9703 static void
9704f_remove(typval_T *argvars, typval_T *rettv)
9705{
9706 list_T *l;
9707 listitem_T *item, *item2;
9708 listitem_T *li;
9709 long idx;
9710 long end;
9711 char_u *key;
9712 dict_T *d;
9713 dictitem_T *di;
9714 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009715 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009716
9717 if (argvars[0].v_type == VAR_DICT)
9718 {
9719 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009720 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009721 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009722 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009723 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009724 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009725 if (key != NULL)
9726 {
9727 di = dict_find(d, key, -1);
9728 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009729 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009730 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9731 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9732 {
9733 *rettv = di->di_tv;
9734 init_tv(&di->di_tv);
9735 dictitem_remove(d, di);
9736 }
9737 }
9738 }
9739 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009740 else if (argvars[0].v_type == VAR_BLOB)
9741 {
9742 idx = (long)tv_get_number_chk(&argvars[1], &error);
9743 if (!error)
9744 {
9745 blob_T *b = argvars[0].vval.v_blob;
9746 int len = blob_len(b);
9747 char_u *p;
9748
9749 if (idx < 0)
9750 // count from the end
9751 idx = len + idx;
9752 if (idx < 0 || idx >= len)
9753 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009754 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009755 return;
9756 }
9757 if (argvars[2].v_type == VAR_UNKNOWN)
9758 {
9759 // Remove one item, return its value.
9760 p = (char_u *)b->bv_ga.ga_data;
9761 rettv->vval.v_number = (varnumber_T) *(p + idx);
9762 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9763 --b->bv_ga.ga_len;
9764 }
9765 else
9766 {
9767 blob_T *blob;
9768
9769 // Remove range of items, return list with values.
9770 end = (long)tv_get_number_chk(&argvars[2], &error);
9771 if (error)
9772 return;
9773 if (end < 0)
9774 // count from the end
9775 end = len + end;
9776 if (end >= len || idx > end)
9777 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009778 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009779 return;
9780 }
9781 blob = blob_alloc();
9782 if (blob == NULL)
9783 return;
9784 blob->bv_ga.ga_len = end - idx + 1;
9785 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9786 {
9787 vim_free(blob);
9788 return;
9789 }
9790 p = (char_u *)b->bv_ga.ga_data;
9791 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9792 (size_t)(end - idx + 1));
9793 ++blob->bv_refcount;
9794 rettv->v_type = VAR_BLOB;
9795 rettv->vval.v_blob = blob;
9796
9797 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9798 b->bv_ga.ga_len -= end - idx + 1;
9799 }
9800 }
9801 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009802 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009803 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009804 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009805 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009806 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009807 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009808 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009809 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009810 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009811 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009812 else
9813 {
9814 if (argvars[2].v_type == VAR_UNKNOWN)
9815 {
9816 /* Remove one item, return its value. */
9817 vimlist_remove(l, item, item);
9818 *rettv = item->li_tv;
9819 vim_free(item);
9820 }
9821 else
9822 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009823 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009824 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009825 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009826 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009827 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009828 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009829 else
9830 {
9831 int cnt = 0;
9832
9833 for (li = item; li != NULL; li = li->li_next)
9834 {
9835 ++cnt;
9836 if (li == item2)
9837 break;
9838 }
9839 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009840 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009841 else
9842 {
9843 vimlist_remove(l, item, item2);
9844 if (rettv_list_alloc(rettv) == OK)
9845 {
9846 l = rettv->vval.v_list;
9847 l->lv_first = item;
9848 l->lv_last = item2;
9849 item->li_prev = NULL;
9850 item2->li_next = NULL;
9851 l->lv_len = cnt;
9852 }
9853 }
9854 }
9855 }
9856 }
9857 }
9858}
9859
9860/*
9861 * "rename({from}, {to})" function
9862 */
9863 static void
9864f_rename(typval_T *argvars, typval_T *rettv)
9865{
9866 char_u buf[NUMBUFLEN];
9867
9868 if (check_restricted() || check_secure())
9869 rettv->vval.v_number = -1;
9870 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009871 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9872 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009873}
9874
9875/*
9876 * "repeat()" function
9877 */
9878 static void
9879f_repeat(typval_T *argvars, typval_T *rettv)
9880{
9881 char_u *p;
9882 int n;
9883 int slen;
9884 int len;
9885 char_u *r;
9886 int i;
9887
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009888 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009889 if (argvars[0].v_type == VAR_LIST)
9890 {
9891 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9892 while (n-- > 0)
9893 if (list_extend(rettv->vval.v_list,
9894 argvars[0].vval.v_list, NULL) == FAIL)
9895 break;
9896 }
9897 else
9898 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009899 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009900 rettv->v_type = VAR_STRING;
9901 rettv->vval.v_string = NULL;
9902
9903 slen = (int)STRLEN(p);
9904 len = slen * n;
9905 if (len <= 0)
9906 return;
9907
9908 r = alloc(len + 1);
9909 if (r != NULL)
9910 {
9911 for (i = 0; i < n; i++)
9912 mch_memmove(r + i * slen, p, (size_t)slen);
9913 r[len] = NUL;
9914 }
9915
9916 rettv->vval.v_string = r;
9917 }
9918}
9919
9920/*
9921 * "resolve()" function
9922 */
9923 static void
9924f_resolve(typval_T *argvars, typval_T *rettv)
9925{
9926 char_u *p;
9927#ifdef HAVE_READLINK
9928 char_u *buf = NULL;
9929#endif
9930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009931 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009932#ifdef FEAT_SHORTCUT
9933 {
9934 char_u *v = NULL;
9935
Bram Moolenaardce1e892019-02-10 23:18:53 +01009936 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009937 if (v != NULL)
9938 rettv->vval.v_string = v;
9939 else
9940 rettv->vval.v_string = vim_strsave(p);
9941 }
9942#else
9943# ifdef HAVE_READLINK
9944 {
9945 char_u *cpy;
9946 int len;
9947 char_u *remain = NULL;
9948 char_u *q;
9949 int is_relative_to_current = FALSE;
9950 int has_trailing_pathsep = FALSE;
9951 int limit = 100;
9952
9953 p = vim_strsave(p);
9954
9955 if (p[0] == '.' && (vim_ispathsep(p[1])
9956 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9957 is_relative_to_current = TRUE;
9958
9959 len = STRLEN(p);
9960 if (len > 0 && after_pathsep(p, p + len))
9961 {
9962 has_trailing_pathsep = TRUE;
9963 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9964 }
9965
9966 q = getnextcomp(p);
9967 if (*q != NUL)
9968 {
9969 /* Separate the first path component in "p", and keep the
9970 * remainder (beginning with the path separator). */
9971 remain = vim_strsave(q - 1);
9972 q[-1] = NUL;
9973 }
9974
9975 buf = alloc(MAXPATHL + 1);
9976 if (buf == NULL)
9977 goto fail;
9978
9979 for (;;)
9980 {
9981 for (;;)
9982 {
9983 len = readlink((char *)p, (char *)buf, MAXPATHL);
9984 if (len <= 0)
9985 break;
9986 buf[len] = NUL;
9987
9988 if (limit-- == 0)
9989 {
9990 vim_free(p);
9991 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009992 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009993 rettv->vval.v_string = NULL;
9994 goto fail;
9995 }
9996
9997 /* Ensure that the result will have a trailing path separator
9998 * if the argument has one. */
9999 if (remain == NULL && has_trailing_pathsep)
10000 add_pathsep(buf);
10001
10002 /* Separate the first path component in the link value and
10003 * concatenate the remainders. */
10004 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10005 if (*q != NUL)
10006 {
10007 if (remain == NULL)
10008 remain = vim_strsave(q - 1);
10009 else
10010 {
10011 cpy = concat_str(q - 1, remain);
10012 if (cpy != NULL)
10013 {
10014 vim_free(remain);
10015 remain = cpy;
10016 }
10017 }
10018 q[-1] = NUL;
10019 }
10020
10021 q = gettail(p);
10022 if (q > p && *q == NUL)
10023 {
10024 /* Ignore trailing path separator. */
10025 q[-1] = NUL;
10026 q = gettail(p);
10027 }
10028 if (q > p && !mch_isFullName(buf))
10029 {
10030 /* symlink is relative to directory of argument */
10031 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10032 if (cpy != NULL)
10033 {
10034 STRCPY(cpy, p);
10035 STRCPY(gettail(cpy), buf);
10036 vim_free(p);
10037 p = cpy;
10038 }
10039 }
10040 else
10041 {
10042 vim_free(p);
10043 p = vim_strsave(buf);
10044 }
10045 }
10046
10047 if (remain == NULL)
10048 break;
10049
10050 /* Append the first path component of "remain" to "p". */
10051 q = getnextcomp(remain + 1);
10052 len = q - remain - (*q != NUL);
10053 cpy = vim_strnsave(p, STRLEN(p) + len);
10054 if (cpy != NULL)
10055 {
10056 STRNCAT(cpy, remain, len);
10057 vim_free(p);
10058 p = cpy;
10059 }
10060 /* Shorten "remain". */
10061 if (*q != NUL)
10062 STRMOVE(remain, q - 1);
10063 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010064 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010065 }
10066
10067 /* If the result is a relative path name, make it explicitly relative to
10068 * the current directory if and only if the argument had this form. */
10069 if (!vim_ispathsep(*p))
10070 {
10071 if (is_relative_to_current
10072 && *p != NUL
10073 && !(p[0] == '.'
10074 && (p[1] == NUL
10075 || vim_ispathsep(p[1])
10076 || (p[1] == '.'
10077 && (p[2] == NUL
10078 || vim_ispathsep(p[2]))))))
10079 {
10080 /* Prepend "./". */
10081 cpy = concat_str((char_u *)"./", p);
10082 if (cpy != NULL)
10083 {
10084 vim_free(p);
10085 p = cpy;
10086 }
10087 }
10088 else if (!is_relative_to_current)
10089 {
10090 /* Strip leading "./". */
10091 q = p;
10092 while (q[0] == '.' && vim_ispathsep(q[1]))
10093 q += 2;
10094 if (q > p)
10095 STRMOVE(p, p + 2);
10096 }
10097 }
10098
10099 /* Ensure that the result will have no trailing path separator
10100 * if the argument had none. But keep "/" or "//". */
10101 if (!has_trailing_pathsep)
10102 {
10103 q = p + STRLEN(p);
10104 if (after_pathsep(p, q))
10105 *gettail_sep(p) = NUL;
10106 }
10107
10108 rettv->vval.v_string = p;
10109 }
10110# else
10111 rettv->vval.v_string = vim_strsave(p);
10112# endif
10113#endif
10114
10115 simplify_filename(rettv->vval.v_string);
10116
10117#ifdef HAVE_READLINK
10118fail:
10119 vim_free(buf);
10120#endif
10121 rettv->v_type = VAR_STRING;
10122}
10123
10124/*
10125 * "reverse({list})" function
10126 */
10127 static void
10128f_reverse(typval_T *argvars, typval_T *rettv)
10129{
10130 list_T *l;
10131 listitem_T *li, *ni;
10132
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010133 if (argvars[0].v_type == VAR_BLOB)
10134 {
10135 blob_T *b = argvars[0].vval.v_blob;
10136 int i, len = blob_len(b);
10137
10138 for (i = 0; i < len / 2; i++)
10139 {
10140 int tmp = blob_get(b, i);
10141
10142 blob_set(b, i, blob_get(b, len - i - 1));
10143 blob_set(b, len - i - 1, tmp);
10144 }
10145 rettv_blob_set(rettv, b);
10146 return;
10147 }
10148
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010149 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010150 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010151 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010152 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010153 (char_u *)N_("reverse() argument"), TRUE))
10154 {
10155 li = l->lv_last;
10156 l->lv_first = l->lv_last = NULL;
10157 l->lv_len = 0;
10158 while (li != NULL)
10159 {
10160 ni = li->li_prev;
10161 list_append(l, li);
10162 li = ni;
10163 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010164 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010165 l->lv_idx = l->lv_len - l->lv_idx - 1;
10166 }
10167}
10168
10169#define SP_NOMOVE 0x01 /* don't move cursor */
10170#define SP_REPEAT 0x02 /* repeat to find outer pair */
10171#define SP_RETCOUNT 0x04 /* return matchcount */
10172#define SP_SETPCMARK 0x08 /* set previous context mark */
10173#define SP_START 0x10 /* accept match at start position */
10174#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10175#define SP_END 0x40 /* leave cursor at end of match */
10176#define SP_COLUMN 0x80 /* start at cursor column */
10177
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010178/*
10179 * Get flags for a search function.
10180 * Possibly sets "p_ws".
10181 * Returns BACKWARD, FORWARD or zero (for an error).
10182 */
10183 static int
10184get_search_arg(typval_T *varp, int *flagsp)
10185{
10186 int dir = FORWARD;
10187 char_u *flags;
10188 char_u nbuf[NUMBUFLEN];
10189 int mask;
10190
10191 if (varp->v_type != VAR_UNKNOWN)
10192 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010193 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010194 if (flags == NULL)
10195 return 0; /* type error; errmsg already given */
10196 while (*flags != NUL)
10197 {
10198 switch (*flags)
10199 {
10200 case 'b': dir = BACKWARD; break;
10201 case 'w': p_ws = TRUE; break;
10202 case 'W': p_ws = FALSE; break;
10203 default: mask = 0;
10204 if (flagsp != NULL)
10205 switch (*flags)
10206 {
10207 case 'c': mask = SP_START; break;
10208 case 'e': mask = SP_END; break;
10209 case 'm': mask = SP_RETCOUNT; break;
10210 case 'n': mask = SP_NOMOVE; break;
10211 case 'p': mask = SP_SUBPAT; break;
10212 case 'r': mask = SP_REPEAT; break;
10213 case 's': mask = SP_SETPCMARK; break;
10214 case 'z': mask = SP_COLUMN; break;
10215 }
10216 if (mask == 0)
10217 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010218 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010219 dir = 0;
10220 }
10221 else
10222 *flagsp |= mask;
10223 }
10224 if (dir == 0)
10225 break;
10226 ++flags;
10227 }
10228 }
10229 return dir;
10230}
10231
10232/*
10233 * Shared by search() and searchpos() functions.
10234 */
10235 static int
10236search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10237{
10238 int flags;
10239 char_u *pat;
10240 pos_T pos;
10241 pos_T save_cursor;
10242 int save_p_ws = p_ws;
10243 int dir;
10244 int retval = 0; /* default: FAIL */
10245 long lnum_stop = 0;
10246 proftime_T tm;
10247#ifdef FEAT_RELTIME
10248 long time_limit = 0;
10249#endif
10250 int options = SEARCH_KEEP;
10251 int subpatnum;
10252
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010253 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010254 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10255 if (dir == 0)
10256 goto theend;
10257 flags = *flagsp;
10258 if (flags & SP_START)
10259 options |= SEARCH_START;
10260 if (flags & SP_END)
10261 options |= SEARCH_END;
10262 if (flags & SP_COLUMN)
10263 options |= SEARCH_COL;
10264
10265 /* Optional arguments: line number to stop searching and timeout. */
10266 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10267 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010268 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010269 if (lnum_stop < 0)
10270 goto theend;
10271#ifdef FEAT_RELTIME
10272 if (argvars[3].v_type != VAR_UNKNOWN)
10273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010274 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010275 if (time_limit < 0)
10276 goto theend;
10277 }
10278#endif
10279 }
10280
10281#ifdef FEAT_RELTIME
10282 /* Set the time limit, if there is one. */
10283 profile_setlimit(time_limit, &tm);
10284#endif
10285
10286 /*
10287 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10288 * Check to make sure only those flags are set.
10289 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10290 * flags cannot be set. Check for that condition also.
10291 */
10292 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10293 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10294 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010295 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 goto theend;
10297 }
10298
10299 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010300 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010301 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010302 if (subpatnum != FAIL)
10303 {
10304 if (flags & SP_SUBPAT)
10305 retval = subpatnum;
10306 else
10307 retval = pos.lnum;
10308 if (flags & SP_SETPCMARK)
10309 setpcmark();
10310 curwin->w_cursor = pos;
10311 if (match_pos != NULL)
10312 {
10313 /* Store the match cursor position */
10314 match_pos->lnum = pos.lnum;
10315 match_pos->col = pos.col + 1;
10316 }
10317 /* "/$" will put the cursor after the end of the line, may need to
10318 * correct that here */
10319 check_cursor();
10320 }
10321
10322 /* If 'n' flag is used: restore cursor position. */
10323 if (flags & SP_NOMOVE)
10324 curwin->w_cursor = save_cursor;
10325 else
10326 curwin->w_set_curswant = TRUE;
10327theend:
10328 p_ws = save_p_ws;
10329
10330 return retval;
10331}
10332
10333#ifdef FEAT_FLOAT
10334
10335/*
10336 * round() is not in C90, use ceil() or floor() instead.
10337 */
10338 float_T
10339vim_round(float_T f)
10340{
10341 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10342}
10343
10344/*
10345 * "round({float})" function
10346 */
10347 static void
10348f_round(typval_T *argvars, typval_T *rettv)
10349{
10350 float_T f = 0.0;
10351
10352 rettv->v_type = VAR_FLOAT;
10353 if (get_float_arg(argvars, &f) == OK)
10354 rettv->vval.v_float = vim_round(f);
10355 else
10356 rettv->vval.v_float = 0.0;
10357}
10358#endif
10359
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010360#ifdef FEAT_RUBY
10361/*
10362 * "rubyeval()" function
10363 */
10364 static void
10365f_rubyeval(typval_T *argvars, typval_T *rettv)
10366{
10367 char_u *str;
10368 char_u buf[NUMBUFLEN];
10369
10370 str = tv_get_string_buf(&argvars[0], buf);
10371 do_rubyeval(str, rettv);
10372}
10373#endif
10374
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010375/*
10376 * "screenattr()" function
10377 */
10378 static void
10379f_screenattr(typval_T *argvars, typval_T *rettv)
10380{
10381 int row;
10382 int col;
10383 int c;
10384
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010385 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10386 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010387 if (row < 0 || row >= screen_Rows
10388 || col < 0 || col >= screen_Columns)
10389 c = -1;
10390 else
10391 c = ScreenAttrs[LineOffset[row] + col];
10392 rettv->vval.v_number = c;
10393}
10394
10395/*
10396 * "screenchar()" function
10397 */
10398 static void
10399f_screenchar(typval_T *argvars, typval_T *rettv)
10400{
10401 int row;
10402 int col;
10403 int off;
10404 int c;
10405
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010406 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10407 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010408 if (row < 0 || row >= screen_Rows
10409 || col < 0 || col >= screen_Columns)
10410 c = -1;
10411 else
10412 {
10413 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010414 if (enc_utf8 && ScreenLinesUC[off] != 0)
10415 c = ScreenLinesUC[off];
10416 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010417 c = ScreenLines[off];
10418 }
10419 rettv->vval.v_number = c;
10420}
10421
10422/*
10423 * "screencol()" function
10424 *
10425 * First column is 1 to be consistent with virtcol().
10426 */
10427 static void
10428f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10429{
10430 rettv->vval.v_number = screen_screencol() + 1;
10431}
10432
10433/*
10434 * "screenrow()" function
10435 */
10436 static void
10437f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10438{
10439 rettv->vval.v_number = screen_screenrow() + 1;
10440}
10441
10442/*
10443 * "search()" function
10444 */
10445 static void
10446f_search(typval_T *argvars, typval_T *rettv)
10447{
10448 int flags = 0;
10449
10450 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10451}
10452
10453/*
10454 * "searchdecl()" function
10455 */
10456 static void
10457f_searchdecl(typval_T *argvars, typval_T *rettv)
10458{
10459 int locally = 1;
10460 int thisblock = 0;
10461 int error = FALSE;
10462 char_u *name;
10463
10464 rettv->vval.v_number = 1; /* default: FAIL */
10465
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010466 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010467 if (argvars[1].v_type != VAR_UNKNOWN)
10468 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010469 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010470 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010471 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010472 }
10473 if (!error && name != NULL)
10474 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10475 locally, thisblock, SEARCH_KEEP) == FAIL;
10476}
10477
10478/*
10479 * Used by searchpair() and searchpairpos()
10480 */
10481 static int
10482searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10483{
10484 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010485 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010486 int save_p_ws = p_ws;
10487 int dir;
10488 int flags = 0;
10489 char_u nbuf1[NUMBUFLEN];
10490 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010491 int retval = 0; /* default: FAIL */
10492 long lnum_stop = 0;
10493 long time_limit = 0;
10494
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010495 /* Get the three pattern arguments: start, middle, end. Will result in an
10496 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010497 spat = tv_get_string_chk(&argvars[0]);
10498 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10499 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010500 if (spat == NULL || mpat == NULL || epat == NULL)
10501 goto theend; /* type error */
10502
10503 /* Handle the optional fourth argument: flags */
10504 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10505 if (dir == 0)
10506 goto theend;
10507
10508 /* Don't accept SP_END or SP_SUBPAT.
10509 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10510 */
10511 if ((flags & (SP_END | SP_SUBPAT)) != 0
10512 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10513 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010514 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010515 goto theend;
10516 }
10517
10518 /* Using 'r' implies 'W', otherwise it doesn't work. */
10519 if (flags & SP_REPEAT)
10520 p_ws = FALSE;
10521
10522 /* Optional fifth argument: skip expression */
10523 if (argvars[3].v_type == VAR_UNKNOWN
10524 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010525 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010526 else
10527 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010528 skip = &argvars[4];
10529 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10530 && skip->v_type != VAR_STRING)
10531 {
10532 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010533 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010534 goto theend;
10535 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010536 if (argvars[5].v_type != VAR_UNKNOWN)
10537 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010538 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010539 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010540 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010541 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010542 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010543 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010544#ifdef FEAT_RELTIME
10545 if (argvars[6].v_type != VAR_UNKNOWN)
10546 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010547 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010548 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010549 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010550 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010551 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010552 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010553 }
10554#endif
10555 }
10556 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010557
10558 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10559 match_pos, lnum_stop, time_limit);
10560
10561theend:
10562 p_ws = save_p_ws;
10563
10564 return retval;
10565}
10566
10567/*
10568 * "searchpair()" function
10569 */
10570 static void
10571f_searchpair(typval_T *argvars, typval_T *rettv)
10572{
10573 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10574}
10575
10576/*
10577 * "searchpairpos()" function
10578 */
10579 static void
10580f_searchpairpos(typval_T *argvars, typval_T *rettv)
10581{
10582 pos_T match_pos;
10583 int lnum = 0;
10584 int col = 0;
10585
10586 if (rettv_list_alloc(rettv) == FAIL)
10587 return;
10588
10589 if (searchpair_cmn(argvars, &match_pos) > 0)
10590 {
10591 lnum = match_pos.lnum;
10592 col = match_pos.col;
10593 }
10594
10595 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10596 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10597}
10598
10599/*
10600 * Search for a start/middle/end thing.
10601 * Used by searchpair(), see its documentation for the details.
10602 * Returns 0 or -1 for no match,
10603 */
10604 long
10605do_searchpair(
10606 char_u *spat, /* start pattern */
10607 char_u *mpat, /* middle pattern */
10608 char_u *epat, /* end pattern */
10609 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010610 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010611 int flags, /* SP_SETPCMARK and other SP_ values */
10612 pos_T *match_pos,
10613 linenr_T lnum_stop, /* stop at this line if not zero */
10614 long time_limit UNUSED) /* stop after this many msec */
10615{
10616 char_u *save_cpo;
10617 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10618 long retval = 0;
10619 pos_T pos;
10620 pos_T firstpos;
10621 pos_T foundpos;
10622 pos_T save_cursor;
10623 pos_T save_pos;
10624 int n;
10625 int r;
10626 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010627 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010628 int err;
10629 int options = SEARCH_KEEP;
10630 proftime_T tm;
10631
10632 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10633 save_cpo = p_cpo;
10634 p_cpo = empty_option;
10635
10636#ifdef FEAT_RELTIME
10637 /* Set the time limit, if there is one. */
10638 profile_setlimit(time_limit, &tm);
10639#endif
10640
10641 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10642 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010643 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10644 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010645 if (pat2 == NULL || pat3 == NULL)
10646 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010647 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010648 if (*mpat == NUL)
10649 STRCPY(pat3, pat2);
10650 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010651 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010652 spat, epat, mpat);
10653 if (flags & SP_START)
10654 options |= SEARCH_START;
10655
Bram Moolenaar48570482017-10-30 21:48:41 +010010656 if (skip != NULL)
10657 {
10658 /* Empty string means to not use the skip expression. */
10659 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10660 use_skip = skip->vval.v_string != NULL
10661 && *skip->vval.v_string != NUL;
10662 }
10663
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010664 save_cursor = curwin->w_cursor;
10665 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010666 CLEAR_POS(&firstpos);
10667 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668 pat = pat3;
10669 for (;;)
10670 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010671 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010672 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010673 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010674 /* didn't find it or found the first match again: FAIL */
10675 break;
10676
10677 if (firstpos.lnum == 0)
10678 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010679 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010680 {
10681 /* Found the same position again. Can happen with a pattern that
10682 * has "\zs" at the end and searching backwards. Advance one
10683 * character and try again. */
10684 if (dir == BACKWARD)
10685 decl(&pos);
10686 else
10687 incl(&pos);
10688 }
10689 foundpos = pos;
10690
10691 /* clear the start flag to avoid getting stuck here */
10692 options &= ~SEARCH_START;
10693
10694 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010695 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010696 {
10697 save_pos = curwin->w_cursor;
10698 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010699 err = FALSE;
10700 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010701 curwin->w_cursor = save_pos;
10702 if (err)
10703 {
10704 /* Evaluating {skip} caused an error, break here. */
10705 curwin->w_cursor = save_cursor;
10706 retval = -1;
10707 break;
10708 }
10709 if (r)
10710 continue;
10711 }
10712
10713 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10714 {
10715 /* Found end when searching backwards or start when searching
10716 * forward: nested pair. */
10717 ++nest;
10718 pat = pat2; /* nested, don't search for middle */
10719 }
10720 else
10721 {
10722 /* Found end when searching forward or start when searching
10723 * backward: end of (nested) pair; or found middle in outer pair. */
10724 if (--nest == 1)
10725 pat = pat3; /* outer level, search for middle */
10726 }
10727
10728 if (nest == 0)
10729 {
10730 /* Found the match: return matchcount or line number. */
10731 if (flags & SP_RETCOUNT)
10732 ++retval;
10733 else
10734 retval = pos.lnum;
10735 if (flags & SP_SETPCMARK)
10736 setpcmark();
10737 curwin->w_cursor = pos;
10738 if (!(flags & SP_REPEAT))
10739 break;
10740 nest = 1; /* search for next unmatched */
10741 }
10742 }
10743
10744 if (match_pos != NULL)
10745 {
10746 /* Store the match cursor position */
10747 match_pos->lnum = curwin->w_cursor.lnum;
10748 match_pos->col = curwin->w_cursor.col + 1;
10749 }
10750
10751 /* If 'n' flag is used or search failed: restore cursor position. */
10752 if ((flags & SP_NOMOVE) || retval == 0)
10753 curwin->w_cursor = save_cursor;
10754
10755theend:
10756 vim_free(pat2);
10757 vim_free(pat3);
10758 if (p_cpo == empty_option)
10759 p_cpo = save_cpo;
10760 else
10761 /* Darn, evaluating the {skip} expression changed the value. */
10762 free_string_option(save_cpo);
10763
10764 return retval;
10765}
10766
10767/*
10768 * "searchpos()" function
10769 */
10770 static void
10771f_searchpos(typval_T *argvars, typval_T *rettv)
10772{
10773 pos_T match_pos;
10774 int lnum = 0;
10775 int col = 0;
10776 int n;
10777 int flags = 0;
10778
10779 if (rettv_list_alloc(rettv) == FAIL)
10780 return;
10781
10782 n = search_cmn(argvars, &match_pos, &flags);
10783 if (n > 0)
10784 {
10785 lnum = match_pos.lnum;
10786 col = match_pos.col;
10787 }
10788
10789 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10790 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10791 if (flags & SP_SUBPAT)
10792 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10793}
10794
10795 static void
10796f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10797{
10798#ifdef FEAT_CLIENTSERVER
10799 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010800 char_u *server = tv_get_string_chk(&argvars[0]);
10801 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010802
10803 rettv->vval.v_number = -1;
10804 if (server == NULL || reply == NULL)
10805 return;
10806 if (check_restricted() || check_secure())
10807 return;
10808# ifdef FEAT_X11
10809 if (check_connection() == FAIL)
10810 return;
10811# endif
10812
10813 if (serverSendReply(server, reply) < 0)
10814 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010815 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010816 return;
10817 }
10818 rettv->vval.v_number = 0;
10819#else
10820 rettv->vval.v_number = -1;
10821#endif
10822}
10823
10824 static void
10825f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10826{
10827 char_u *r = NULL;
10828
10829#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010830# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010831 r = serverGetVimNames();
10832# else
10833 make_connection();
10834 if (X_DISPLAY != NULL)
10835 r = serverGetVimNames(X_DISPLAY);
10836# endif
10837#endif
10838 rettv->v_type = VAR_STRING;
10839 rettv->vval.v_string = r;
10840}
10841
10842/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010843 * "setbufline()" function
10844 */
10845 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010846f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010847{
10848 linenr_T lnum;
10849 buf_T *buf;
10850
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010851 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010852 if (buf == NULL)
10853 rettv->vval.v_number = 1; /* FAIL */
10854 else
10855 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010856 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010857 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010858 }
10859}
10860
10861/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010862 * "setbufvar()" function
10863 */
10864 static void
10865f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10866{
10867 buf_T *buf;
10868 char_u *varname, *bufvarname;
10869 typval_T *varp;
10870 char_u nbuf[NUMBUFLEN];
10871
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010872 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010873 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010874 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10875 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010876 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010877 varp = &argvars[2];
10878
10879 if (buf != NULL && varname != NULL && varp != NULL)
10880 {
10881 if (*varname == '&')
10882 {
10883 long numval;
10884 char_u *strval;
10885 int error = FALSE;
10886 aco_save_T aco;
10887
10888 /* set curbuf to be our buf, temporarily */
10889 aucmd_prepbuf(&aco, buf);
10890
10891 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010892 numval = (long)tv_get_number_chk(varp, &error);
10893 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010894 if (!error && strval != NULL)
10895 set_option_value(varname, numval, strval, OPT_LOCAL);
10896
10897 /* reset notion of buffer */
10898 aucmd_restbuf(&aco);
10899 }
10900 else
10901 {
10902 buf_T *save_curbuf = curbuf;
10903
10904 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10905 if (bufvarname != NULL)
10906 {
10907 curbuf = buf;
10908 STRCPY(bufvarname, "b:");
10909 STRCPY(bufvarname + 2, varname);
10910 set_var(bufvarname, varp, TRUE);
10911 vim_free(bufvarname);
10912 curbuf = save_curbuf;
10913 }
10914 }
10915 }
10916}
10917
10918 static void
10919f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10920{
10921 dict_T *d;
10922 dictitem_T *di;
10923 char_u *csearch;
10924
10925 if (argvars[0].v_type != VAR_DICT)
10926 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010927 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010928 return;
10929 }
10930
10931 if ((d = argvars[0].vval.v_dict) != NULL)
10932 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010933 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010934 if (csearch != NULL)
10935 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010936 if (enc_utf8)
10937 {
10938 int pcc[MAX_MCO];
10939 int c = utfc_ptr2char(csearch, pcc);
10940
10941 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10942 }
10943 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010944 set_last_csearch(PTR2CHAR(csearch),
10945 csearch, MB_PTR2LEN(csearch));
10946 }
10947
10948 di = dict_find(d, (char_u *)"forward", -1);
10949 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010950 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010951 ? FORWARD : BACKWARD);
10952
10953 di = dict_find(d, (char_u *)"until", -1);
10954 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010955 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010956 }
10957}
10958
10959/*
10960 * "setcmdpos()" function
10961 */
10962 static void
10963f_setcmdpos(typval_T *argvars, typval_T *rettv)
10964{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010965 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010966
10967 if (pos >= 0)
10968 rettv->vval.v_number = set_cmdline_pos(pos);
10969}
10970
10971/*
10972 * "setfperm({fname}, {mode})" function
10973 */
10974 static void
10975f_setfperm(typval_T *argvars, typval_T *rettv)
10976{
10977 char_u *fname;
10978 char_u modebuf[NUMBUFLEN];
10979 char_u *mode_str;
10980 int i;
10981 int mask;
10982 int mode = 0;
10983
10984 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010985 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010986 if (fname == NULL)
10987 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010988 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010989 if (mode_str == NULL)
10990 return;
10991 if (STRLEN(mode_str) != 9)
10992 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010993 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010994 return;
10995 }
10996
10997 mask = 1;
10998 for (i = 8; i >= 0; --i)
10999 {
11000 if (mode_str[i] != '-')
11001 mode |= mask;
11002 mask = mask << 1;
11003 }
11004 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11005}
11006
11007/*
11008 * "setline()" function
11009 */
11010 static void
11011f_setline(typval_T *argvars, typval_T *rettv)
11012{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011013 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011014
Bram Moolenaarca851592018-06-06 21:04:07 +020011015 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011016}
11017
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011018/*
11019 * Used by "setqflist()" and "setloclist()" functions
11020 */
11021 static void
11022set_qf_ll_list(
11023 win_T *wp UNUSED,
11024 typval_T *list_arg UNUSED,
11025 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011026 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011027 typval_T *rettv)
11028{
11029#ifdef FEAT_QUICKFIX
11030 static char *e_invact = N_("E927: Invalid action: '%s'");
11031 char_u *act;
11032 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011033 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011034#endif
11035
11036 rettv->vval.v_number = -1;
11037
11038#ifdef FEAT_QUICKFIX
11039 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011040 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011041 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011042 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011043 else
11044 {
11045 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011046 dict_T *d = NULL;
11047 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011048
11049 if (action_arg->v_type == VAR_STRING)
11050 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011051 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011052 if (act == NULL)
11053 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011054 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11055 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011056 action = *act;
11057 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011058 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059 }
11060 else if (action_arg->v_type == VAR_UNKNOWN)
11061 action = ' ';
11062 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011063 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011064
Bram Moolenaard823fa92016-08-12 16:29:27 +020011065 if (action_arg->v_type != VAR_UNKNOWN
11066 && what_arg->v_type != VAR_UNKNOWN)
11067 {
11068 if (what_arg->v_type == VAR_DICT)
11069 d = what_arg->vval.v_dict;
11070 else
11071 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011072 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011073 valid_dict = FALSE;
11074 }
11075 }
11076
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011077 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011078 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011079 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11080 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011081 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011082 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011083 }
11084#endif
11085}
11086
11087/*
11088 * "setloclist()" function
11089 */
11090 static void
11091f_setloclist(typval_T *argvars, typval_T *rettv)
11092{
11093 win_T *win;
11094
11095 rettv->vval.v_number = -1;
11096
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011097 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011098 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011099 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011100}
11101
11102/*
11103 * "setmatches()" function
11104 */
11105 static void
11106f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11107{
11108#ifdef FEAT_SEARCH_EXTRA
11109 list_T *l;
11110 listitem_T *li;
11111 dict_T *d;
11112 list_T *s = NULL;
11113
11114 rettv->vval.v_number = -1;
11115 if (argvars[0].v_type != VAR_LIST)
11116 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011117 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011118 return;
11119 }
11120 if ((l = argvars[0].vval.v_list) != NULL)
11121 {
11122
11123 /* To some extent make sure that we are dealing with a list from
11124 * "getmatches()". */
11125 li = l->lv_first;
11126 while (li != NULL)
11127 {
11128 if (li->li_tv.v_type != VAR_DICT
11129 || (d = li->li_tv.vval.v_dict) == NULL)
11130 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011131 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011132 return;
11133 }
11134 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11135 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11136 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11137 && dict_find(d, (char_u *)"priority", -1) != NULL
11138 && dict_find(d, (char_u *)"id", -1) != NULL))
11139 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011140 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011141 return;
11142 }
11143 li = li->li_next;
11144 }
11145
11146 clear_matches(curwin);
11147 li = l->lv_first;
11148 while (li != NULL)
11149 {
11150 int i = 0;
11151 char_u buf[5];
11152 dictitem_T *di;
11153 char_u *group;
11154 int priority;
11155 int id;
11156 char_u *conceal;
11157
11158 d = li->li_tv.vval.v_dict;
11159 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11160 {
11161 if (s == NULL)
11162 {
11163 s = list_alloc();
11164 if (s == NULL)
11165 return;
11166 }
11167
11168 /* match from matchaddpos() */
11169 for (i = 1; i < 9; i++)
11170 {
11171 sprintf((char *)buf, (char *)"pos%d", i);
11172 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11173 {
11174 if (di->di_tv.v_type != VAR_LIST)
11175 return;
11176
11177 list_append_tv(s, &di->di_tv);
11178 s->lv_refcount++;
11179 }
11180 else
11181 break;
11182 }
11183 }
11184
Bram Moolenaar8f667172018-12-14 15:38:31 +010011185 group = dict_get_string(d, (char_u *)"group", TRUE);
11186 priority = (int)dict_get_number(d, (char_u *)"priority");
11187 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011188 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011189 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011190 : NULL;
11191 if (i == 0)
11192 {
11193 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011194 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011195 priority, id, NULL, conceal);
11196 }
11197 else
11198 {
11199 match_add(curwin, group, NULL, priority, id, s, conceal);
11200 list_unref(s);
11201 s = NULL;
11202 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011203 vim_free(group);
11204 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011205
11206 li = li->li_next;
11207 }
11208 rettv->vval.v_number = 0;
11209 }
11210#endif
11211}
11212
11213/*
11214 * "setpos()" function
11215 */
11216 static void
11217f_setpos(typval_T *argvars, typval_T *rettv)
11218{
11219 pos_T pos;
11220 int fnum;
11221 char_u *name;
11222 colnr_T curswant = -1;
11223
11224 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011225 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011226 if (name != NULL)
11227 {
11228 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11229 {
11230 if (--pos.col < 0)
11231 pos.col = 0;
11232 if (name[0] == '.' && name[1] == NUL)
11233 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011234 /* set cursor; "fnum" is ignored */
11235 curwin->w_cursor = pos;
11236 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011237 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011238 curwin->w_curswant = curswant - 1;
11239 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011240 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011241 check_cursor();
11242 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011243 }
11244 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11245 {
11246 /* set mark */
11247 if (setmark_pos(name[1], &pos, fnum) == OK)
11248 rettv->vval.v_number = 0;
11249 }
11250 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011251 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011252 }
11253 }
11254}
11255
11256/*
11257 * "setqflist()" function
11258 */
11259 static void
11260f_setqflist(typval_T *argvars, typval_T *rettv)
11261{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011262 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011263}
11264
11265/*
11266 * "setreg()" function
11267 */
11268 static void
11269f_setreg(typval_T *argvars, typval_T *rettv)
11270{
11271 int regname;
11272 char_u *strregname;
11273 char_u *stropt;
11274 char_u *strval;
11275 int append;
11276 char_u yank_type;
11277 long block_len;
11278
11279 block_len = -1;
11280 yank_type = MAUTO;
11281 append = FALSE;
11282
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011283 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011284 rettv->vval.v_number = 1; /* FAIL is default */
11285
11286 if (strregname == NULL)
11287 return; /* type error; errmsg already given */
11288 regname = *strregname;
11289 if (regname == 0 || regname == '@')
11290 regname = '"';
11291
11292 if (argvars[2].v_type != VAR_UNKNOWN)
11293 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011294 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011295 if (stropt == NULL)
11296 return; /* type error */
11297 for (; *stropt != NUL; ++stropt)
11298 switch (*stropt)
11299 {
11300 case 'a': case 'A': /* append */
11301 append = TRUE;
11302 break;
11303 case 'v': case 'c': /* character-wise selection */
11304 yank_type = MCHAR;
11305 break;
11306 case 'V': case 'l': /* line-wise selection */
11307 yank_type = MLINE;
11308 break;
11309 case 'b': case Ctrl_V: /* block-wise selection */
11310 yank_type = MBLOCK;
11311 if (VIM_ISDIGIT(stropt[1]))
11312 {
11313 ++stropt;
11314 block_len = getdigits(&stropt) - 1;
11315 --stropt;
11316 }
11317 break;
11318 }
11319 }
11320
11321 if (argvars[1].v_type == VAR_LIST)
11322 {
11323 char_u **lstval;
11324 char_u **allocval;
11325 char_u buf[NUMBUFLEN];
11326 char_u **curval;
11327 char_u **curallocval;
11328 list_T *ll = argvars[1].vval.v_list;
11329 listitem_T *li;
11330 int len;
11331
11332 /* If the list is NULL handle like an empty list. */
11333 len = ll == NULL ? 0 : ll->lv_len;
11334
11335 /* First half: use for pointers to result lines; second half: use for
11336 * pointers to allocated copies. */
11337 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11338 if (lstval == NULL)
11339 return;
11340 curval = lstval;
11341 allocval = lstval + len + 2;
11342 curallocval = allocval;
11343
11344 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11345 li = li->li_next)
11346 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011347 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011348 if (strval == NULL)
11349 goto free_lstval;
11350 if (strval == buf)
11351 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011352 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011353 * overwrite the string. */
11354 strval = vim_strsave(buf);
11355 if (strval == NULL)
11356 goto free_lstval;
11357 *curallocval++ = strval;
11358 }
11359 *curval++ = strval;
11360 }
11361 *curval++ = NULL;
11362
11363 write_reg_contents_lst(regname, lstval, -1,
11364 append, yank_type, block_len);
11365free_lstval:
11366 while (curallocval > allocval)
11367 vim_free(*--curallocval);
11368 vim_free(lstval);
11369 }
11370 else
11371 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011372 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011373 if (strval == NULL)
11374 return;
11375 write_reg_contents_ex(regname, strval, -1,
11376 append, yank_type, block_len);
11377 }
11378 rettv->vval.v_number = 0;
11379}
11380
11381/*
11382 * "settabvar()" function
11383 */
11384 static void
11385f_settabvar(typval_T *argvars, typval_T *rettv)
11386{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011387 tabpage_T *save_curtab;
11388 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011389 char_u *varname, *tabvarname;
11390 typval_T *varp;
11391
11392 rettv->vval.v_number = 0;
11393
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011394 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011395 return;
11396
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011397 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11398 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011399 varp = &argvars[2];
11400
Bram Moolenaar4033c552017-09-16 20:54:51 +020011401 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011402 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011403 save_curtab = curtab;
11404 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011405
11406 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11407 if (tabvarname != NULL)
11408 {
11409 STRCPY(tabvarname, "t:");
11410 STRCPY(tabvarname + 2, varname);
11411 set_var(tabvarname, varp, TRUE);
11412 vim_free(tabvarname);
11413 }
11414
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011415 /* Restore current tabpage */
11416 if (valid_tabpage(save_curtab))
11417 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011418 }
11419}
11420
11421/*
11422 * "settabwinvar()" function
11423 */
11424 static void
11425f_settabwinvar(typval_T *argvars, typval_T *rettv)
11426{
11427 setwinvar(argvars, rettv, 1);
11428}
11429
11430/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011431 * "settagstack()" function
11432 */
11433 static void
11434f_settagstack(typval_T *argvars, typval_T *rettv)
11435{
11436 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11437 win_T *wp;
11438 dict_T *d;
11439 int action = 'r';
11440
11441 rettv->vval.v_number = -1;
11442
11443 // first argument: window number or id
11444 wp = find_win_by_nr_or_id(&argvars[0]);
11445 if (wp == NULL)
11446 return;
11447
11448 // second argument: dict with items to set in the tag stack
11449 if (argvars[1].v_type != VAR_DICT)
11450 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011451 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011452 return;
11453 }
11454 d = argvars[1].vval.v_dict;
11455 if (d == NULL)
11456 return;
11457
11458 // third argument: action - 'a' for append and 'r' for replace.
11459 // default is to replace the stack.
11460 if (argvars[2].v_type == VAR_UNKNOWN)
11461 action = 'r';
11462 else if (argvars[2].v_type == VAR_STRING)
11463 {
11464 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011465 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011466 if (actstr == NULL)
11467 return;
11468 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11469 action = *actstr;
11470 else
11471 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011472 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011473 return;
11474 }
11475 }
11476 else
11477 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011478 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011479 return;
11480 }
11481
11482 if (set_tagstack(wp, d, action) == OK)
11483 rettv->vval.v_number = 0;
11484}
11485
11486/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011487 * "setwinvar()" function
11488 */
11489 static void
11490f_setwinvar(typval_T *argvars, typval_T *rettv)
11491{
11492 setwinvar(argvars, rettv, 0);
11493}
11494
11495#ifdef FEAT_CRYPT
11496/*
11497 * "sha256({string})" function
11498 */
11499 static void
11500f_sha256(typval_T *argvars, typval_T *rettv)
11501{
11502 char_u *p;
11503
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011504 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011505 rettv->vval.v_string = vim_strsave(
11506 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11507 rettv->v_type = VAR_STRING;
11508}
11509#endif /* FEAT_CRYPT */
11510
11511/*
11512 * "shellescape({string})" function
11513 */
11514 static void
11515f_shellescape(typval_T *argvars, typval_T *rettv)
11516{
Bram Moolenaar20615522017-06-05 18:46:26 +020011517 int do_special = non_zero_arg(&argvars[1]);
11518
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011519 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011520 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011521 rettv->v_type = VAR_STRING;
11522}
11523
11524/*
11525 * shiftwidth() function
11526 */
11527 static void
11528f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11529{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011530 rettv->vval.v_number = 0;
11531
11532 if (argvars[0].v_type != VAR_UNKNOWN)
11533 {
11534 long col;
11535
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011536 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011537 if (col < 0)
11538 return; // type error; errmsg already given
11539#ifdef FEAT_VARTABS
11540 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11541 return;
11542#endif
11543 }
11544
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011545 rettv->vval.v_number = get_sw_value(curbuf);
11546}
11547
Bram Moolenaar162b7142018-12-21 15:17:36 +010011548#ifdef FEAT_SIGNS
11549/*
11550 * "sign_define()" function
11551 */
11552 static void
11553f_sign_define(typval_T *argvars, typval_T *rettv)
11554{
11555 char_u *name;
11556 dict_T *dict;
11557 char_u *icon = NULL;
11558 char_u *linehl = NULL;
11559 char_u *text = NULL;
11560 char_u *texthl = NULL;
11561
11562 rettv->vval.v_number = -1;
11563
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011564 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011565 if (name == NULL)
11566 return;
11567
11568 if (argvars[1].v_type != VAR_UNKNOWN)
11569 {
11570 if (argvars[1].v_type != VAR_DICT)
11571 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011572 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011573 return;
11574 }
11575
11576 // sign attributes
11577 dict = argvars[1].vval.v_dict;
11578 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11579 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11580 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11581 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11582 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11583 text = dict_get_string(dict, (char_u *)"text", TRUE);
11584 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11585 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11586 }
11587
11588 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11589 rettv->vval.v_number = 0;
11590
11591 vim_free(icon);
11592 vim_free(linehl);
11593 vim_free(text);
11594 vim_free(texthl);
11595}
11596
11597/*
11598 * "sign_getdefined()" function
11599 */
11600 static void
11601f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11602{
11603 char_u *name = NULL;
11604
11605 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11606 return;
11607
11608 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011609 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011610
11611 sign_getlist(name, rettv->vval.v_list);
11612}
11613
11614/*
11615 * "sign_getplaced()" function
11616 */
11617 static void
11618f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11619{
11620 buf_T *buf = NULL;
11621 dict_T *dict;
11622 dictitem_T *di;
11623 linenr_T lnum = 0;
11624 int sign_id = 0;
11625 char_u *group = NULL;
11626 int notanum = FALSE;
11627
11628 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11629 return;
11630
11631 if (argvars[0].v_type != VAR_UNKNOWN)
11632 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011633 // get signs placed in the specified buffer
11634 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011635 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011636 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011637
11638 if (argvars[1].v_type != VAR_UNKNOWN)
11639 {
11640 if (argvars[1].v_type != VAR_DICT ||
11641 ((dict = argvars[1].vval.v_dict) == NULL))
11642 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011643 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011644 return;
11645 }
11646 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11647 {
11648 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011649 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011650 if (notanum)
11651 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011652 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011653 }
11654 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11655 {
11656 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011657 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011658 if (notanum)
11659 return;
11660 }
11661 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11662 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011663 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011664 if (group == NULL)
11665 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011666 if (*group == '\0') // empty string means global group
11667 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011668 }
11669 }
11670 }
11671
11672 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11673}
11674
11675/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011676 * "sign_jump()" function
11677 */
11678 static void
11679f_sign_jump(typval_T *argvars, typval_T *rettv)
11680{
11681 int sign_id;
11682 char_u *sign_group = NULL;
11683 buf_T *buf;
11684 int notanum = FALSE;
11685
11686 rettv->vval.v_number = -1;
11687
Bram Moolenaarbdace832019-03-02 10:13:42 +010011688 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011689 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11690 if (notanum)
11691 return;
11692 if (sign_id <= 0)
11693 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011694 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011695 return;
11696 }
11697
11698 // Sign group
11699 sign_group = tv_get_string_chk(&argvars[1]);
11700 if (sign_group == NULL)
11701 return;
11702 if (sign_group[0] == '\0')
11703 sign_group = NULL; // global sign group
11704 else
11705 {
11706 sign_group = vim_strsave(sign_group);
11707 if (sign_group == NULL)
11708 return;
11709 }
11710
11711 // Buffer to place the sign
11712 buf = get_buf_arg(&argvars[2]);
11713 if (buf == NULL)
11714 goto cleanup;
11715
11716 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11717
11718cleanup:
11719 vim_free(sign_group);
11720}
11721
11722/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011723 * "sign_place()" function
11724 */
11725 static void
11726f_sign_place(typval_T *argvars, typval_T *rettv)
11727{
11728 int sign_id;
11729 char_u *group = NULL;
11730 char_u *sign_name;
11731 buf_T *buf;
11732 dict_T *dict;
11733 dictitem_T *di;
11734 linenr_T lnum = 0;
11735 int prio = SIGN_DEF_PRIO;
11736 int notanum = FALSE;
11737
11738 rettv->vval.v_number = -1;
11739
Bram Moolenaarbdace832019-03-02 10:13:42 +010011740 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011741 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011742 if (notanum)
11743 return;
11744 if (sign_id < 0)
11745 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011746 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011747 return;
11748 }
11749
11750 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011751 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011752 if (group == NULL)
11753 return;
11754 if (group[0] == '\0')
11755 group = NULL; // global sign group
11756 else
11757 {
11758 group = vim_strsave(group);
11759 if (group == NULL)
11760 return;
11761 }
11762
11763 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011764 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011765 if (sign_name == NULL)
11766 goto cleanup;
11767
11768 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011769 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011770 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011771 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011772
11773 if (argvars[4].v_type != VAR_UNKNOWN)
11774 {
11775 if (argvars[4].v_type != VAR_DICT ||
11776 ((dict = argvars[4].vval.v_dict) == NULL))
11777 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011778 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011779 goto cleanup;
11780 }
11781
11782 // Line number where the sign is to be placed
11783 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11784 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011785 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011786 if (notanum)
11787 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011788 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011789 }
11790 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11791 {
11792 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011793 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011794 if (notanum)
11795 goto cleanup;
11796 }
11797 }
11798
11799 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11800 rettv->vval.v_number = sign_id;
11801
11802cleanup:
11803 vim_free(group);
11804}
11805
11806/*
11807 * "sign_undefine()" function
11808 */
11809 static void
11810f_sign_undefine(typval_T *argvars, typval_T *rettv)
11811{
11812 char_u *name;
11813
11814 rettv->vval.v_number = -1;
11815
11816 if (argvars[0].v_type == VAR_UNKNOWN)
11817 {
11818 // Free all the signs
11819 free_signs();
11820 rettv->vval.v_number = 0;
11821 }
11822 else
11823 {
11824 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011825 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011826 if (name == NULL)
11827 return;
11828
11829 if (sign_undefine_by_name(name) == OK)
11830 rettv->vval.v_number = 0;
11831 }
11832}
11833
11834/*
11835 * "sign_unplace()" function
11836 */
11837 static void
11838f_sign_unplace(typval_T *argvars, typval_T *rettv)
11839{
11840 dict_T *dict;
11841 dictitem_T *di;
11842 int sign_id = 0;
11843 buf_T *buf = NULL;
11844 char_u *group = NULL;
11845
11846 rettv->vval.v_number = -1;
11847
11848 if (argvars[0].v_type != VAR_STRING)
11849 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011850 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011851 return;
11852 }
11853
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011854 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011855 if (group[0] == '\0')
11856 group = NULL; // global sign group
11857 else
11858 {
11859 group = vim_strsave(group);
11860 if (group == NULL)
11861 return;
11862 }
11863
11864 if (argvars[1].v_type != VAR_UNKNOWN)
11865 {
11866 if (argvars[1].v_type != VAR_DICT)
11867 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011868 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011869 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011870 }
11871 dict = argvars[1].vval.v_dict;
11872
11873 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11874 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011875 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011876 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011877 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011878 }
11879 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11880 sign_id = dict_get_number(dict, (char_u *)"id");
11881 }
11882
11883 if (buf == NULL)
11884 {
11885 // Delete the sign in all the buffers
11886 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011887 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011888 rettv->vval.v_number = 0;
11889 }
11890 else
11891 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011892 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011893 rettv->vval.v_number = 0;
11894 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011895
11896cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010011897 vim_free(group);
11898}
11899#endif
11900
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011901/*
11902 * "simplify()" function
11903 */
11904 static void
11905f_simplify(typval_T *argvars, typval_T *rettv)
11906{
11907 char_u *p;
11908
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011909 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011910 rettv->vval.v_string = vim_strsave(p);
11911 simplify_filename(rettv->vval.v_string); /* simplify in place */
11912 rettv->v_type = VAR_STRING;
11913}
11914
11915#ifdef FEAT_FLOAT
11916/*
11917 * "sin()" function
11918 */
11919 static void
11920f_sin(typval_T *argvars, typval_T *rettv)
11921{
11922 float_T f = 0.0;
11923
11924 rettv->v_type = VAR_FLOAT;
11925 if (get_float_arg(argvars, &f) == OK)
11926 rettv->vval.v_float = sin(f);
11927 else
11928 rettv->vval.v_float = 0.0;
11929}
11930
11931/*
11932 * "sinh()" function
11933 */
11934 static void
11935f_sinh(typval_T *argvars, typval_T *rettv)
11936{
11937 float_T f = 0.0;
11938
11939 rettv->v_type = VAR_FLOAT;
11940 if (get_float_arg(argvars, &f) == OK)
11941 rettv->vval.v_float = sinh(f);
11942 else
11943 rettv->vval.v_float = 0.0;
11944}
11945#endif
11946
11947static int
11948#ifdef __BORLANDC__
11949 _RTLENTRYF
11950#endif
11951 item_compare(const void *s1, const void *s2);
11952static int
11953#ifdef __BORLANDC__
11954 _RTLENTRYF
11955#endif
11956 item_compare2(const void *s1, const void *s2);
11957
11958/* struct used in the array that's given to qsort() */
11959typedef struct
11960{
11961 listitem_T *item;
11962 int idx;
11963} sortItem_T;
11964
11965/* struct storing information about current sort */
11966typedef struct
11967{
11968 int item_compare_ic;
11969 int item_compare_numeric;
11970 int item_compare_numbers;
11971#ifdef FEAT_FLOAT
11972 int item_compare_float;
11973#endif
11974 char_u *item_compare_func;
11975 partial_T *item_compare_partial;
11976 dict_T *item_compare_selfdict;
11977 int item_compare_func_err;
11978 int item_compare_keep_zero;
11979} sortinfo_T;
11980static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011981#define ITEM_COMPARE_FAIL 999
11982
11983/*
11984 * Compare functions for f_sort() and f_uniq() below.
11985 */
11986 static int
11987#ifdef __BORLANDC__
11988_RTLENTRYF
11989#endif
11990item_compare(const void *s1, const void *s2)
11991{
11992 sortItem_T *si1, *si2;
11993 typval_T *tv1, *tv2;
11994 char_u *p1, *p2;
11995 char_u *tofree1 = NULL, *tofree2 = NULL;
11996 int res;
11997 char_u numbuf1[NUMBUFLEN];
11998 char_u numbuf2[NUMBUFLEN];
11999
12000 si1 = (sortItem_T *)s1;
12001 si2 = (sortItem_T *)s2;
12002 tv1 = &si1->item->li_tv;
12003 tv2 = &si2->item->li_tv;
12004
12005 if (sortinfo->item_compare_numbers)
12006 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012007 varnumber_T v1 = tv_get_number(tv1);
12008 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012009
12010 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12011 }
12012
12013#ifdef FEAT_FLOAT
12014 if (sortinfo->item_compare_float)
12015 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012016 float_T v1 = tv_get_float(tv1);
12017 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012018
12019 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12020 }
12021#endif
12022
12023 /* tv2string() puts quotes around a string and allocates memory. Don't do
12024 * that for string variables. Use a single quote when comparing with a
12025 * non-string to do what the docs promise. */
12026 if (tv1->v_type == VAR_STRING)
12027 {
12028 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12029 p1 = (char_u *)"'";
12030 else
12031 p1 = tv1->vval.v_string;
12032 }
12033 else
12034 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12035 if (tv2->v_type == VAR_STRING)
12036 {
12037 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12038 p2 = (char_u *)"'";
12039 else
12040 p2 = tv2->vval.v_string;
12041 }
12042 else
12043 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12044 if (p1 == NULL)
12045 p1 = (char_u *)"";
12046 if (p2 == NULL)
12047 p2 = (char_u *)"";
12048 if (!sortinfo->item_compare_numeric)
12049 {
12050 if (sortinfo->item_compare_ic)
12051 res = STRICMP(p1, p2);
12052 else
12053 res = STRCMP(p1, p2);
12054 }
12055 else
12056 {
12057 double n1, n2;
12058 n1 = strtod((char *)p1, (char **)&p1);
12059 n2 = strtod((char *)p2, (char **)&p2);
12060 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12061 }
12062
12063 /* When the result would be zero, compare the item indexes. Makes the
12064 * sort stable. */
12065 if (res == 0 && !sortinfo->item_compare_keep_zero)
12066 res = si1->idx > si2->idx ? 1 : -1;
12067
12068 vim_free(tofree1);
12069 vim_free(tofree2);
12070 return res;
12071}
12072
12073 static int
12074#ifdef __BORLANDC__
12075_RTLENTRYF
12076#endif
12077item_compare2(const void *s1, const void *s2)
12078{
12079 sortItem_T *si1, *si2;
12080 int res;
12081 typval_T rettv;
12082 typval_T argv[3];
12083 int dummy;
12084 char_u *func_name;
12085 partial_T *partial = sortinfo->item_compare_partial;
12086
12087 /* shortcut after failure in previous call; compare all items equal */
12088 if (sortinfo->item_compare_func_err)
12089 return 0;
12090
12091 si1 = (sortItem_T *)s1;
12092 si2 = (sortItem_T *)s2;
12093
12094 if (partial == NULL)
12095 func_name = sortinfo->item_compare_func;
12096 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012097 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012098
12099 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12100 * in the copy without changing the original list items. */
12101 copy_tv(&si1->item->li_tv, &argv[0]);
12102 copy_tv(&si2->item->li_tv, &argv[1]);
12103
12104 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12105 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012106 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012107 partial, sortinfo->item_compare_selfdict);
12108 clear_tv(&argv[0]);
12109 clear_tv(&argv[1]);
12110
12111 if (res == FAIL)
12112 res = ITEM_COMPARE_FAIL;
12113 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012114 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012115 if (sortinfo->item_compare_func_err)
12116 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12117 clear_tv(&rettv);
12118
12119 /* When the result would be zero, compare the pointers themselves. Makes
12120 * the sort stable. */
12121 if (res == 0 && !sortinfo->item_compare_keep_zero)
12122 res = si1->idx > si2->idx ? 1 : -1;
12123
12124 return res;
12125}
12126
12127/*
12128 * "sort({list})" function
12129 */
12130 static void
12131do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12132{
12133 list_T *l;
12134 listitem_T *li;
12135 sortItem_T *ptrs;
12136 sortinfo_T *old_sortinfo;
12137 sortinfo_T info;
12138 long len;
12139 long i;
12140
12141 /* Pointer to current info struct used in compare function. Save and
12142 * restore the current one for nested calls. */
12143 old_sortinfo = sortinfo;
12144 sortinfo = &info;
12145
12146 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012147 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012148 else
12149 {
12150 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012151 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012152 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12153 TRUE))
12154 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012155 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012156
12157 len = list_len(l);
12158 if (len <= 1)
12159 goto theend; /* short list sorts pretty quickly */
12160
12161 info.item_compare_ic = FALSE;
12162 info.item_compare_numeric = FALSE;
12163 info.item_compare_numbers = FALSE;
12164#ifdef FEAT_FLOAT
12165 info.item_compare_float = FALSE;
12166#endif
12167 info.item_compare_func = NULL;
12168 info.item_compare_partial = NULL;
12169 info.item_compare_selfdict = NULL;
12170 if (argvars[1].v_type != VAR_UNKNOWN)
12171 {
12172 /* optional second argument: {func} */
12173 if (argvars[1].v_type == VAR_FUNC)
12174 info.item_compare_func = argvars[1].vval.v_string;
12175 else if (argvars[1].v_type == VAR_PARTIAL)
12176 info.item_compare_partial = argvars[1].vval.v_partial;
12177 else
12178 {
12179 int error = FALSE;
12180
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012181 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012182 if (error)
12183 goto theend; /* type error; errmsg already given */
12184 if (i == 1)
12185 info.item_compare_ic = TRUE;
12186 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012187 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012188 else if (i != 0)
12189 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012190 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012191 goto theend;
12192 }
12193 if (info.item_compare_func != NULL)
12194 {
12195 if (*info.item_compare_func == NUL)
12196 {
12197 /* empty string means default sort */
12198 info.item_compare_func = NULL;
12199 }
12200 else if (STRCMP(info.item_compare_func, "n") == 0)
12201 {
12202 info.item_compare_func = NULL;
12203 info.item_compare_numeric = TRUE;
12204 }
12205 else if (STRCMP(info.item_compare_func, "N") == 0)
12206 {
12207 info.item_compare_func = NULL;
12208 info.item_compare_numbers = TRUE;
12209 }
12210#ifdef FEAT_FLOAT
12211 else if (STRCMP(info.item_compare_func, "f") == 0)
12212 {
12213 info.item_compare_func = NULL;
12214 info.item_compare_float = TRUE;
12215 }
12216#endif
12217 else if (STRCMP(info.item_compare_func, "i") == 0)
12218 {
12219 info.item_compare_func = NULL;
12220 info.item_compare_ic = TRUE;
12221 }
12222 }
12223 }
12224
12225 if (argvars[2].v_type != VAR_UNKNOWN)
12226 {
12227 /* optional third argument: {dict} */
12228 if (argvars[2].v_type != VAR_DICT)
12229 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012230 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012231 goto theend;
12232 }
12233 info.item_compare_selfdict = argvars[2].vval.v_dict;
12234 }
12235 }
12236
12237 /* Make an array with each entry pointing to an item in the List. */
12238 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12239 if (ptrs == NULL)
12240 goto theend;
12241
12242 i = 0;
12243 if (sort)
12244 {
12245 /* sort(): ptrs will be the list to sort */
12246 for (li = l->lv_first; li != NULL; li = li->li_next)
12247 {
12248 ptrs[i].item = li;
12249 ptrs[i].idx = i;
12250 ++i;
12251 }
12252
12253 info.item_compare_func_err = FALSE;
12254 info.item_compare_keep_zero = FALSE;
12255 /* test the compare function */
12256 if ((info.item_compare_func != NULL
12257 || info.item_compare_partial != NULL)
12258 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12259 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012260 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012261 else
12262 {
12263 /* Sort the array with item pointers. */
12264 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12265 info.item_compare_func == NULL
12266 && info.item_compare_partial == NULL
12267 ? item_compare : item_compare2);
12268
12269 if (!info.item_compare_func_err)
12270 {
12271 /* Clear the List and append the items in sorted order. */
12272 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12273 l->lv_len = 0;
12274 for (i = 0; i < len; ++i)
12275 list_append(l, ptrs[i].item);
12276 }
12277 }
12278 }
12279 else
12280 {
12281 int (*item_compare_func_ptr)(const void *, const void *);
12282
12283 /* f_uniq(): ptrs will be a stack of items to remove */
12284 info.item_compare_func_err = FALSE;
12285 info.item_compare_keep_zero = TRUE;
12286 item_compare_func_ptr = info.item_compare_func != NULL
12287 || info.item_compare_partial != NULL
12288 ? item_compare2 : item_compare;
12289
12290 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12291 li = li->li_next)
12292 {
12293 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12294 == 0)
12295 ptrs[i++].item = li;
12296 if (info.item_compare_func_err)
12297 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012298 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012299 break;
12300 }
12301 }
12302
12303 if (!info.item_compare_func_err)
12304 {
12305 while (--i >= 0)
12306 {
12307 li = ptrs[i].item->li_next;
12308 ptrs[i].item->li_next = li->li_next;
12309 if (li->li_next != NULL)
12310 li->li_next->li_prev = ptrs[i].item;
12311 else
12312 l->lv_last = ptrs[i].item;
12313 list_fix_watch(l, li);
12314 listitem_free(li);
12315 l->lv_len--;
12316 }
12317 }
12318 }
12319
12320 vim_free(ptrs);
12321 }
12322theend:
12323 sortinfo = old_sortinfo;
12324}
12325
12326/*
12327 * "sort({list})" function
12328 */
12329 static void
12330f_sort(typval_T *argvars, typval_T *rettv)
12331{
12332 do_sort_uniq(argvars, rettv, TRUE);
12333}
12334
12335/*
12336 * "uniq({list})" function
12337 */
12338 static void
12339f_uniq(typval_T *argvars, typval_T *rettv)
12340{
12341 do_sort_uniq(argvars, rettv, FALSE);
12342}
12343
12344/*
12345 * "soundfold({word})" function
12346 */
12347 static void
12348f_soundfold(typval_T *argvars, typval_T *rettv)
12349{
12350 char_u *s;
12351
12352 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012353 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012354#ifdef FEAT_SPELL
12355 rettv->vval.v_string = eval_soundfold(s);
12356#else
12357 rettv->vval.v_string = vim_strsave(s);
12358#endif
12359}
12360
12361/*
12362 * "spellbadword()" function
12363 */
12364 static void
12365f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12366{
12367 char_u *word = (char_u *)"";
12368 hlf_T attr = HLF_COUNT;
12369 int len = 0;
12370
12371 if (rettv_list_alloc(rettv) == FAIL)
12372 return;
12373
12374#ifdef FEAT_SPELL
12375 if (argvars[0].v_type == VAR_UNKNOWN)
12376 {
12377 /* Find the start and length of the badly spelled word. */
12378 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12379 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012380 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012381 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012382 curwin->w_set_curswant = TRUE;
12383 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012384 }
12385 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12386 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012387 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012388 int capcol = -1;
12389
12390 if (str != NULL)
12391 {
12392 /* Check the argument for spelling. */
12393 while (*str != NUL)
12394 {
12395 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12396 if (attr != HLF_COUNT)
12397 {
12398 word = str;
12399 break;
12400 }
12401 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012402 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012403 }
12404 }
12405 }
12406#endif
12407
12408 list_append_string(rettv->vval.v_list, word, len);
12409 list_append_string(rettv->vval.v_list, (char_u *)(
12410 attr == HLF_SPB ? "bad" :
12411 attr == HLF_SPR ? "rare" :
12412 attr == HLF_SPL ? "local" :
12413 attr == HLF_SPC ? "caps" :
12414 ""), -1);
12415}
12416
12417/*
12418 * "spellsuggest()" function
12419 */
12420 static void
12421f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12422{
12423#ifdef FEAT_SPELL
12424 char_u *str;
12425 int typeerr = FALSE;
12426 int maxcount;
12427 garray_T ga;
12428 int i;
12429 listitem_T *li;
12430 int need_capital = FALSE;
12431#endif
12432
12433 if (rettv_list_alloc(rettv) == FAIL)
12434 return;
12435
12436#ifdef FEAT_SPELL
12437 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12438 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012439 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012440 if (argvars[1].v_type != VAR_UNKNOWN)
12441 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012442 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012443 if (maxcount <= 0)
12444 return;
12445 if (argvars[2].v_type != VAR_UNKNOWN)
12446 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012447 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012448 if (typeerr)
12449 return;
12450 }
12451 }
12452 else
12453 maxcount = 25;
12454
12455 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12456
12457 for (i = 0; i < ga.ga_len; ++i)
12458 {
12459 str = ((char_u **)ga.ga_data)[i];
12460
12461 li = listitem_alloc();
12462 if (li == NULL)
12463 vim_free(str);
12464 else
12465 {
12466 li->li_tv.v_type = VAR_STRING;
12467 li->li_tv.v_lock = 0;
12468 li->li_tv.vval.v_string = str;
12469 list_append(rettv->vval.v_list, li);
12470 }
12471 }
12472 ga_clear(&ga);
12473 }
12474#endif
12475}
12476
12477 static void
12478f_split(typval_T *argvars, typval_T *rettv)
12479{
12480 char_u *str;
12481 char_u *end;
12482 char_u *pat = NULL;
12483 regmatch_T regmatch;
12484 char_u patbuf[NUMBUFLEN];
12485 char_u *save_cpo;
12486 int match;
12487 colnr_T col = 0;
12488 int keepempty = FALSE;
12489 int typeerr = FALSE;
12490
12491 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12492 save_cpo = p_cpo;
12493 p_cpo = (char_u *)"";
12494
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012495 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012496 if (argvars[1].v_type != VAR_UNKNOWN)
12497 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012498 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012499 if (pat == NULL)
12500 typeerr = TRUE;
12501 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012502 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012503 }
12504 if (pat == NULL || *pat == NUL)
12505 pat = (char_u *)"[\\x01- ]\\+";
12506
12507 if (rettv_list_alloc(rettv) == FAIL)
12508 return;
12509 if (typeerr)
12510 return;
12511
12512 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12513 if (regmatch.regprog != NULL)
12514 {
12515 regmatch.rm_ic = FALSE;
12516 while (*str != NUL || keepempty)
12517 {
12518 if (*str == NUL)
12519 match = FALSE; /* empty item at the end */
12520 else
12521 match = vim_regexec_nl(&regmatch, str, col);
12522 if (match)
12523 end = regmatch.startp[0];
12524 else
12525 end = str + STRLEN(str);
12526 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12527 && *str != NUL && match && end < regmatch.endp[0]))
12528 {
12529 if (list_append_string(rettv->vval.v_list, str,
12530 (int)(end - str)) == FAIL)
12531 break;
12532 }
12533 if (!match)
12534 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012535 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012536 if (regmatch.endp[0] > str)
12537 col = 0;
12538 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012539 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012540 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012541 str = regmatch.endp[0];
12542 }
12543
12544 vim_regfree(regmatch.regprog);
12545 }
12546
12547 p_cpo = save_cpo;
12548}
12549
12550#ifdef FEAT_FLOAT
12551/*
12552 * "sqrt()" function
12553 */
12554 static void
12555f_sqrt(typval_T *argvars, typval_T *rettv)
12556{
12557 float_T f = 0.0;
12558
12559 rettv->v_type = VAR_FLOAT;
12560 if (get_float_arg(argvars, &f) == OK)
12561 rettv->vval.v_float = sqrt(f);
12562 else
12563 rettv->vval.v_float = 0.0;
12564}
12565
12566/*
12567 * "str2float()" function
12568 */
12569 static void
12570f_str2float(typval_T *argvars, typval_T *rettv)
12571{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012572 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012573 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012574
Bram Moolenaar08243d22017-01-10 16:12:29 +010012575 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012576 p = skipwhite(p + 1);
12577 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012578 if (isneg)
12579 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012580 rettv->v_type = VAR_FLOAT;
12581}
12582#endif
12583
12584/*
12585 * "str2nr()" function
12586 */
12587 static void
12588f_str2nr(typval_T *argvars, typval_T *rettv)
12589{
12590 int base = 10;
12591 char_u *p;
12592 varnumber_T n;
12593 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012594 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012595
12596 if (argvars[1].v_type != VAR_UNKNOWN)
12597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012598 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012599 if (base != 2 && base != 8 && base != 10 && base != 16)
12600 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012601 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012602 return;
12603 }
12604 }
12605
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012606 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012607 isneg = (*p == '-');
12608 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012609 p = skipwhite(p + 1);
12610 switch (base)
12611 {
12612 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12613 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12614 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12615 default: what = 0;
12616 }
12617 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012618 if (isneg)
12619 rettv->vval.v_number = -n;
12620 else
12621 rettv->vval.v_number = n;
12622
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012623}
12624
12625#ifdef HAVE_STRFTIME
12626/*
12627 * "strftime({format}[, {time}])" function
12628 */
12629 static void
12630f_strftime(typval_T *argvars, typval_T *rettv)
12631{
12632 char_u result_buf[256];
12633 struct tm *curtime;
12634 time_t seconds;
12635 char_u *p;
12636
12637 rettv->v_type = VAR_STRING;
12638
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012639 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012640 if (argvars[1].v_type == VAR_UNKNOWN)
12641 seconds = time(NULL);
12642 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012643 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012644 curtime = localtime(&seconds);
12645 /* MSVC returns NULL for an invalid value of seconds. */
12646 if (curtime == NULL)
12647 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12648 else
12649 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012650 vimconv_T conv;
12651 char_u *enc;
12652
12653 conv.vc_type = CONV_NONE;
12654 enc = enc_locale();
12655 convert_setup(&conv, p_enc, enc);
12656 if (conv.vc_type != CONV_NONE)
12657 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012658 if (p != NULL)
12659 (void)strftime((char *)result_buf, sizeof(result_buf),
12660 (char *)p, curtime);
12661 else
12662 result_buf[0] = NUL;
12663
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012664 if (conv.vc_type != CONV_NONE)
12665 vim_free(p);
12666 convert_setup(&conv, enc, p_enc);
12667 if (conv.vc_type != CONV_NONE)
12668 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12669 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012670 rettv->vval.v_string = vim_strsave(result_buf);
12671
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012672 /* Release conversion descriptors */
12673 convert_setup(&conv, NULL, NULL);
12674 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012675 }
12676}
12677#endif
12678
12679/*
12680 * "strgetchar()" function
12681 */
12682 static void
12683f_strgetchar(typval_T *argvars, typval_T *rettv)
12684{
12685 char_u *str;
12686 int len;
12687 int error = FALSE;
12688 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012689 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012690
12691 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012692 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012693 if (str == NULL)
12694 return;
12695 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012696 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012697 if (error)
12698 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012699
Bram Moolenaar13505972019-01-24 15:04:48 +010012700 while (charidx >= 0 && byteidx < len)
12701 {
12702 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012703 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012704 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12705 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012706 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012707 --charidx;
12708 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012709 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012710}
12711
12712/*
12713 * "stridx()" function
12714 */
12715 static void
12716f_stridx(typval_T *argvars, typval_T *rettv)
12717{
12718 char_u buf[NUMBUFLEN];
12719 char_u *needle;
12720 char_u *haystack;
12721 char_u *save_haystack;
12722 char_u *pos;
12723 int start_idx;
12724
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012725 needle = tv_get_string_chk(&argvars[1]);
12726 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012727 rettv->vval.v_number = -1;
12728 if (needle == NULL || haystack == NULL)
12729 return; /* type error; errmsg already given */
12730
12731 if (argvars[2].v_type != VAR_UNKNOWN)
12732 {
12733 int error = FALSE;
12734
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012735 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012736 if (error || start_idx >= (int)STRLEN(haystack))
12737 return;
12738 if (start_idx >= 0)
12739 haystack += start_idx;
12740 }
12741
12742 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12743 if (pos != NULL)
12744 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12745}
12746
12747/*
12748 * "string()" function
12749 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012750 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012751f_string(typval_T *argvars, typval_T *rettv)
12752{
12753 char_u *tofree;
12754 char_u numbuf[NUMBUFLEN];
12755
12756 rettv->v_type = VAR_STRING;
12757 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12758 get_copyID());
12759 /* Make a copy if we have a value but it's not in allocated memory. */
12760 if (rettv->vval.v_string != NULL && tofree == NULL)
12761 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12762}
12763
12764/*
12765 * "strlen()" function
12766 */
12767 static void
12768f_strlen(typval_T *argvars, typval_T *rettv)
12769{
12770 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012771 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012772}
12773
12774/*
12775 * "strchars()" function
12776 */
12777 static void
12778f_strchars(typval_T *argvars, typval_T *rettv)
12779{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012780 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012781 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012782 varnumber_T len = 0;
12783 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012784
12785 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012786 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012787 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012788 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012789 else
12790 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12792 while (*s != NUL)
12793 {
12794 func_mb_ptr2char_adv(&s);
12795 ++len;
12796 }
12797 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012798 }
12799}
12800
12801/*
12802 * "strdisplaywidth()" function
12803 */
12804 static void
12805f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12806{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012807 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012808 int col = 0;
12809
12810 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012811 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012812
12813 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12814}
12815
12816/*
12817 * "strwidth()" function
12818 */
12819 static void
12820f_strwidth(typval_T *argvars, typval_T *rettv)
12821{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012822 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012823
Bram Moolenaar13505972019-01-24 15:04:48 +010012824 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012825}
12826
12827/*
12828 * "strcharpart()" function
12829 */
12830 static void
12831f_strcharpart(typval_T *argvars, typval_T *rettv)
12832{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012833 char_u *p;
12834 int nchar;
12835 int nbyte = 0;
12836 int charlen;
12837 int len = 0;
12838 int slen;
12839 int error = FALSE;
12840
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012841 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012842 slen = (int)STRLEN(p);
12843
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012844 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012845 if (!error)
12846 {
12847 if (nchar > 0)
12848 while (nchar > 0 && nbyte < slen)
12849 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012850 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012851 --nchar;
12852 }
12853 else
12854 nbyte = nchar;
12855 if (argvars[2].v_type != VAR_UNKNOWN)
12856 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012857 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012858 while (charlen > 0 && nbyte + len < slen)
12859 {
12860 int off = nbyte + len;
12861
12862 if (off < 0)
12863 len += 1;
12864 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012865 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012866 --charlen;
12867 }
12868 }
12869 else
12870 len = slen - nbyte; /* default: all bytes that are available. */
12871 }
12872
12873 /*
12874 * Only return the overlap between the specified part and the actual
12875 * string.
12876 */
12877 if (nbyte < 0)
12878 {
12879 len += nbyte;
12880 nbyte = 0;
12881 }
12882 else if (nbyte > slen)
12883 nbyte = slen;
12884 if (len < 0)
12885 len = 0;
12886 else if (nbyte + len > slen)
12887 len = slen - nbyte;
12888
12889 rettv->v_type = VAR_STRING;
12890 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012891}
12892
12893/*
12894 * "strpart()" function
12895 */
12896 static void
12897f_strpart(typval_T *argvars, typval_T *rettv)
12898{
12899 char_u *p;
12900 int n;
12901 int len;
12902 int slen;
12903 int error = FALSE;
12904
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012905 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012906 slen = (int)STRLEN(p);
12907
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012908 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012909 if (error)
12910 len = 0;
12911 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012912 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012913 else
12914 len = slen - n; /* default len: all bytes that are available. */
12915
12916 /*
12917 * Only return the overlap between the specified part and the actual
12918 * string.
12919 */
12920 if (n < 0)
12921 {
12922 len += n;
12923 n = 0;
12924 }
12925 else if (n > slen)
12926 n = slen;
12927 if (len < 0)
12928 len = 0;
12929 else if (n + len > slen)
12930 len = slen - n;
12931
12932 rettv->v_type = VAR_STRING;
12933 rettv->vval.v_string = vim_strnsave(p + n, len);
12934}
12935
12936/*
12937 * "strridx()" function
12938 */
12939 static void
12940f_strridx(typval_T *argvars, typval_T *rettv)
12941{
12942 char_u buf[NUMBUFLEN];
12943 char_u *needle;
12944 char_u *haystack;
12945 char_u *rest;
12946 char_u *lastmatch = NULL;
12947 int haystack_len, end_idx;
12948
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012949 needle = tv_get_string_chk(&argvars[1]);
12950 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012951
12952 rettv->vval.v_number = -1;
12953 if (needle == NULL || haystack == NULL)
12954 return; /* type error; errmsg already given */
12955
12956 haystack_len = (int)STRLEN(haystack);
12957 if (argvars[2].v_type != VAR_UNKNOWN)
12958 {
12959 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012960 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012961 if (end_idx < 0)
12962 return; /* can never find a match */
12963 }
12964 else
12965 end_idx = haystack_len;
12966
12967 if (*needle == NUL)
12968 {
12969 /* Empty string matches past the end. */
12970 lastmatch = haystack + end_idx;
12971 }
12972 else
12973 {
12974 for (rest = haystack; *rest != '\0'; ++rest)
12975 {
12976 rest = (char_u *)strstr((char *)rest, (char *)needle);
12977 if (rest == NULL || rest > haystack + end_idx)
12978 break;
12979 lastmatch = rest;
12980 }
12981 }
12982
12983 if (lastmatch == NULL)
12984 rettv->vval.v_number = -1;
12985 else
12986 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12987}
12988
12989/*
12990 * "strtrans()" function
12991 */
12992 static void
12993f_strtrans(typval_T *argvars, typval_T *rettv)
12994{
12995 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012996 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012997}
12998
12999/*
13000 * "submatch()" function
13001 */
13002 static void
13003f_submatch(typval_T *argvars, typval_T *rettv)
13004{
13005 int error = FALSE;
13006 int no;
13007 int retList = 0;
13008
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013009 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013010 if (error)
13011 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013012 if (no < 0 || no >= NSUBEXP)
13013 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013014 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010013015 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013016 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013017 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013018 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013019 if (error)
13020 return;
13021
13022 if (retList == 0)
13023 {
13024 rettv->v_type = VAR_STRING;
13025 rettv->vval.v_string = reg_submatch(no);
13026 }
13027 else
13028 {
13029 rettv->v_type = VAR_LIST;
13030 rettv->vval.v_list = reg_submatch_list(no);
13031 }
13032}
13033
13034/*
13035 * "substitute()" function
13036 */
13037 static void
13038f_substitute(typval_T *argvars, typval_T *rettv)
13039{
13040 char_u patbuf[NUMBUFLEN];
13041 char_u subbuf[NUMBUFLEN];
13042 char_u flagsbuf[NUMBUFLEN];
13043
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013044 char_u *str = tv_get_string_chk(&argvars[0]);
13045 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013046 char_u *sub = NULL;
13047 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013048 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013049
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013050 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13051 expr = &argvars[2];
13052 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013053 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013055 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013056 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13057 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013058 rettv->vval.v_string = NULL;
13059 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013060 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013061}
13062
13063/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013064 * "swapinfo(swap_filename)" function
13065 */
13066 static void
13067f_swapinfo(typval_T *argvars, typval_T *rettv)
13068{
13069 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013070 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013071}
13072
13073/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013074 * "swapname(expr)" function
13075 */
13076 static void
13077f_swapname(typval_T *argvars, typval_T *rettv)
13078{
13079 buf_T *buf;
13080
13081 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013082 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013083 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13084 || buf->b_ml.ml_mfp->mf_fname == NULL)
13085 rettv->vval.v_string = NULL;
13086 else
13087 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13088}
13089
13090/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013091 * "synID(lnum, col, trans)" function
13092 */
13093 static void
13094f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13095{
13096 int id = 0;
13097#ifdef FEAT_SYN_HL
13098 linenr_T lnum;
13099 colnr_T col;
13100 int trans;
13101 int transerr = FALSE;
13102
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013103 lnum = tv_get_lnum(argvars); /* -1 on type error */
13104 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13105 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013106
13107 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13108 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13109 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13110#endif
13111
13112 rettv->vval.v_number = id;
13113}
13114
13115/*
13116 * "synIDattr(id, what [, mode])" function
13117 */
13118 static void
13119f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13120{
13121 char_u *p = NULL;
13122#ifdef FEAT_SYN_HL
13123 int id;
13124 char_u *what;
13125 char_u *mode;
13126 char_u modebuf[NUMBUFLEN];
13127 int modec;
13128
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013129 id = (int)tv_get_number(&argvars[0]);
13130 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013131 if (argvars[2].v_type != VAR_UNKNOWN)
13132 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013133 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013134 modec = TOLOWER_ASC(mode[0]);
13135 if (modec != 't' && modec != 'c' && modec != 'g')
13136 modec = 0; /* replace invalid with current */
13137 }
13138 else
13139 {
13140#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13141 if (USE_24BIT)
13142 modec = 'g';
13143 else
13144#endif
13145 if (t_colors > 1)
13146 modec = 'c';
13147 else
13148 modec = 't';
13149 }
13150
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013151 switch (TOLOWER_ASC(what[0]))
13152 {
13153 case 'b':
13154 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13155 p = highlight_color(id, what, modec);
13156 else /* bold */
13157 p = highlight_has_attr(id, HL_BOLD, modec);
13158 break;
13159
13160 case 'f': /* fg[#] or font */
13161 p = highlight_color(id, what, modec);
13162 break;
13163
13164 case 'i':
13165 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13166 p = highlight_has_attr(id, HL_INVERSE, modec);
13167 else /* italic */
13168 p = highlight_has_attr(id, HL_ITALIC, modec);
13169 break;
13170
13171 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013172 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013173 break;
13174
13175 case 'r': /* reverse */
13176 p = highlight_has_attr(id, HL_INVERSE, modec);
13177 break;
13178
13179 case 's':
13180 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13181 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013182 /* strikeout */
13183 else if (TOLOWER_ASC(what[1]) == 't' &&
13184 TOLOWER_ASC(what[2]) == 'r')
13185 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013186 else /* standout */
13187 p = highlight_has_attr(id, HL_STANDOUT, modec);
13188 break;
13189
13190 case 'u':
13191 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13192 /* underline */
13193 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13194 else
13195 /* undercurl */
13196 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13197 break;
13198 }
13199
13200 if (p != NULL)
13201 p = vim_strsave(p);
13202#endif
13203 rettv->v_type = VAR_STRING;
13204 rettv->vval.v_string = p;
13205}
13206
13207/*
13208 * "synIDtrans(id)" function
13209 */
13210 static void
13211f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13212{
13213 int id;
13214
13215#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013216 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013217
13218 if (id > 0)
13219 id = syn_get_final_id(id);
13220 else
13221#endif
13222 id = 0;
13223
13224 rettv->vval.v_number = id;
13225}
13226
13227/*
13228 * "synconcealed(lnum, col)" function
13229 */
13230 static void
13231f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13232{
13233#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13234 linenr_T lnum;
13235 colnr_T col;
13236 int syntax_flags = 0;
13237 int cchar;
13238 int matchid = 0;
13239 char_u str[NUMBUFLEN];
13240#endif
13241
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013242 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013243
13244#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013245 lnum = tv_get_lnum(argvars); /* -1 on type error */
13246 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013247
13248 vim_memset(str, NUL, sizeof(str));
13249
13250 if (rettv_list_alloc(rettv) != FAIL)
13251 {
13252 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13253 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13254 && curwin->w_p_cole > 0)
13255 {
13256 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13257 syntax_flags = get_syntax_info(&matchid);
13258
13259 /* get the conceal character */
13260 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13261 {
13262 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013263 if (cchar == NUL && curwin->w_p_cole == 1)
13264 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013265 if (cchar != NUL)
13266 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013267 if (has_mbyte)
13268 (*mb_char2bytes)(cchar, str);
13269 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013270 str[0] = cchar;
13271 }
13272 }
13273 }
13274
13275 list_append_number(rettv->vval.v_list,
13276 (syntax_flags & HL_CONCEAL) != 0);
13277 /* -1 to auto-determine strlen */
13278 list_append_string(rettv->vval.v_list, str, -1);
13279 list_append_number(rettv->vval.v_list, matchid);
13280 }
13281#endif
13282}
13283
13284/*
13285 * "synstack(lnum, col)" function
13286 */
13287 static void
13288f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13289{
13290#ifdef FEAT_SYN_HL
13291 linenr_T lnum;
13292 colnr_T col;
13293 int i;
13294 int id;
13295#endif
13296
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013297 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013298
13299#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013300 lnum = tv_get_lnum(argvars); /* -1 on type error */
13301 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013302
13303 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13304 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13305 && rettv_list_alloc(rettv) != FAIL)
13306 {
13307 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13308 for (i = 0; ; ++i)
13309 {
13310 id = syn_get_stack_item(i);
13311 if (id < 0)
13312 break;
13313 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13314 break;
13315 }
13316 }
13317#endif
13318}
13319
13320 static void
13321get_cmd_output_as_rettv(
13322 typval_T *argvars,
13323 typval_T *rettv,
13324 int retlist)
13325{
13326 char_u *res = NULL;
13327 char_u *p;
13328 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013329 int err = FALSE;
13330 FILE *fd;
13331 list_T *list = NULL;
13332 int flags = SHELL_SILENT;
13333
13334 rettv->v_type = VAR_STRING;
13335 rettv->vval.v_string = NULL;
13336 if (check_restricted() || check_secure())
13337 goto errret;
13338
13339 if (argvars[1].v_type != VAR_UNKNOWN)
13340 {
13341 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013342 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013343 * command.
13344 */
13345 if ((infile = vim_tempname('i', TRUE)) == NULL)
13346 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013347 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013348 goto errret;
13349 }
13350
13351 fd = mch_fopen((char *)infile, WRITEBIN);
13352 if (fd == NULL)
13353 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013354 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013355 goto errret;
13356 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013357 if (argvars[1].v_type == VAR_NUMBER)
13358 {
13359 linenr_T lnum;
13360 buf_T *buf;
13361
13362 buf = buflist_findnr(argvars[1].vval.v_number);
13363 if (buf == NULL)
13364 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013365 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013366 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013367 goto errret;
13368 }
13369
13370 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13371 {
13372 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13373 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13374 {
13375 err = TRUE;
13376 break;
13377 }
13378 if (putc(NL, fd) == EOF)
13379 {
13380 err = TRUE;
13381 break;
13382 }
13383 }
13384 }
13385 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013386 {
13387 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13388 err = TRUE;
13389 }
13390 else
13391 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013392 size_t len;
13393 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013394
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013395 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013396 if (p == NULL)
13397 {
13398 fclose(fd);
13399 goto errret; /* type error; errmsg already given */
13400 }
13401 len = STRLEN(p);
13402 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13403 err = TRUE;
13404 }
13405 if (fclose(fd) != 0)
13406 err = TRUE;
13407 if (err)
13408 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013409 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013410 goto errret;
13411 }
13412 }
13413
13414 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13415 * echoes typeahead, that messes up the display. */
13416 if (!msg_silent)
13417 flags += SHELL_COOKED;
13418
13419 if (retlist)
13420 {
13421 int len;
13422 listitem_T *li;
13423 char_u *s = NULL;
13424 char_u *start;
13425 char_u *end;
13426 int i;
13427
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013428 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013429 if (res == NULL)
13430 goto errret;
13431
13432 list = list_alloc();
13433 if (list == NULL)
13434 goto errret;
13435
13436 for (i = 0; i < len; ++i)
13437 {
13438 start = res + i;
13439 while (i < len && res[i] != NL)
13440 ++i;
13441 end = res + i;
13442
13443 s = alloc((unsigned)(end - start + 1));
13444 if (s == NULL)
13445 goto errret;
13446
13447 for (p = s; start < end; ++p, ++start)
13448 *p = *start == NUL ? NL : *start;
13449 *p = NUL;
13450
13451 li = listitem_alloc();
13452 if (li == NULL)
13453 {
13454 vim_free(s);
13455 goto errret;
13456 }
13457 li->li_tv.v_type = VAR_STRING;
13458 li->li_tv.v_lock = 0;
13459 li->li_tv.vval.v_string = s;
13460 list_append(list, li);
13461 }
13462
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013463 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013464 list = NULL;
13465 }
13466 else
13467 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013468 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013469#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013470 /* translate <CR><NL> into <NL> */
13471 if (res != NULL)
13472 {
13473 char_u *s, *d;
13474
13475 d = res;
13476 for (s = res; *s; ++s)
13477 {
13478 if (s[0] == CAR && s[1] == NL)
13479 ++s;
13480 *d++ = *s;
13481 }
13482 *d = NUL;
13483 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013484#endif
13485 rettv->vval.v_string = res;
13486 res = NULL;
13487 }
13488
13489errret:
13490 if (infile != NULL)
13491 {
13492 mch_remove(infile);
13493 vim_free(infile);
13494 }
13495 if (res != NULL)
13496 vim_free(res);
13497 if (list != NULL)
13498 list_free(list);
13499}
13500
13501/*
13502 * "system()" function
13503 */
13504 static void
13505f_system(typval_T *argvars, typval_T *rettv)
13506{
13507 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13508}
13509
13510/*
13511 * "systemlist()" function
13512 */
13513 static void
13514f_systemlist(typval_T *argvars, typval_T *rettv)
13515{
13516 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13517}
13518
13519/*
13520 * "tabpagebuflist()" function
13521 */
13522 static void
13523f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13524{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013525 tabpage_T *tp;
13526 win_T *wp = NULL;
13527
13528 if (argvars[0].v_type == VAR_UNKNOWN)
13529 wp = firstwin;
13530 else
13531 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013532 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013533 if (tp != NULL)
13534 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13535 }
13536 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13537 {
13538 for (; wp != NULL; wp = wp->w_next)
13539 if (list_append_number(rettv->vval.v_list,
13540 wp->w_buffer->b_fnum) == FAIL)
13541 break;
13542 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013543}
13544
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013545/*
13546 * "tabpagenr()" function
13547 */
13548 static void
13549f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13550{
13551 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013552 char_u *arg;
13553
13554 if (argvars[0].v_type != VAR_UNKNOWN)
13555 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013556 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013557 nr = 0;
13558 if (arg != NULL)
13559 {
13560 if (STRCMP(arg, "$") == 0)
13561 nr = tabpage_index(NULL) - 1;
13562 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013563 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013564 }
13565 }
13566 else
13567 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013568 rettv->vval.v_number = nr;
13569}
13570
13571
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013572/*
13573 * Common code for tabpagewinnr() and winnr().
13574 */
13575 static int
13576get_winnr(tabpage_T *tp, typval_T *argvar)
13577{
13578 win_T *twin;
13579 int nr = 1;
13580 win_T *wp;
13581 char_u *arg;
13582
13583 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13584 if (argvar->v_type != VAR_UNKNOWN)
13585 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013586 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013587 if (arg == NULL)
13588 nr = 0; /* type error; errmsg already given */
13589 else if (STRCMP(arg, "$") == 0)
13590 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13591 else if (STRCMP(arg, "#") == 0)
13592 {
13593 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13594 if (twin == NULL)
13595 nr = 0;
13596 }
13597 else
13598 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013599 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013600 nr = 0;
13601 }
13602 }
13603
13604 if (nr > 0)
13605 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13606 wp != twin; wp = wp->w_next)
13607 {
13608 if (wp == NULL)
13609 {
13610 /* didn't find it in this tabpage */
13611 nr = 0;
13612 break;
13613 }
13614 ++nr;
13615 }
13616 return nr;
13617}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013618
13619/*
13620 * "tabpagewinnr()" function
13621 */
13622 static void
13623f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13624{
13625 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013626 tabpage_T *tp;
13627
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013628 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013629 if (tp == NULL)
13630 nr = 0;
13631 else
13632 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013633 rettv->vval.v_number = nr;
13634}
13635
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013636/*
13637 * "tagfiles()" function
13638 */
13639 static void
13640f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13641{
13642 char_u *fname;
13643 tagname_T tn;
13644 int first;
13645
13646 if (rettv_list_alloc(rettv) == FAIL)
13647 return;
13648 fname = alloc(MAXPATHL);
13649 if (fname == NULL)
13650 return;
13651
13652 for (first = TRUE; ; first = FALSE)
13653 if (get_tagfname(&tn, first, fname) == FAIL
13654 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13655 break;
13656 tagname_free(&tn);
13657 vim_free(fname);
13658}
13659
13660/*
13661 * "taglist()" function
13662 */
13663 static void
13664f_taglist(typval_T *argvars, typval_T *rettv)
13665{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013666 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013667 char_u *tag_pattern;
13668
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013669 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013670
13671 rettv->vval.v_number = FALSE;
13672 if (*tag_pattern == NUL)
13673 return;
13674
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013675 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013676 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013677 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013678 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013679}
13680
13681/*
13682 * "tempname()" function
13683 */
13684 static void
13685f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13686{
13687 static int x = 'A';
13688
13689 rettv->v_type = VAR_STRING;
13690 rettv->vval.v_string = vim_tempname(x, FALSE);
13691
13692 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13693 * names. Skip 'I' and 'O', they are used for shell redirection. */
13694 do
13695 {
13696 if (x == 'Z')
13697 x = '0';
13698 else if (x == '9')
13699 x = 'A';
13700 else
13701 {
13702#ifdef EBCDIC
13703 if (x == 'I')
13704 x = 'J';
13705 else if (x == 'R')
13706 x = 'S';
13707 else
13708#endif
13709 ++x;
13710 }
13711 } while (x == 'I' || x == 'O');
13712}
13713
13714#ifdef FEAT_FLOAT
13715/*
13716 * "tan()" function
13717 */
13718 static void
13719f_tan(typval_T *argvars, typval_T *rettv)
13720{
13721 float_T f = 0.0;
13722
13723 rettv->v_type = VAR_FLOAT;
13724 if (get_float_arg(argvars, &f) == OK)
13725 rettv->vval.v_float = tan(f);
13726 else
13727 rettv->vval.v_float = 0.0;
13728}
13729
13730/*
13731 * "tanh()" function
13732 */
13733 static void
13734f_tanh(typval_T *argvars, typval_T *rettv)
13735{
13736 float_T f = 0.0;
13737
13738 rettv->v_type = VAR_FLOAT;
13739 if (get_float_arg(argvars, &f) == OK)
13740 rettv->vval.v_float = tanh(f);
13741 else
13742 rettv->vval.v_float = 0.0;
13743}
13744#endif
13745
13746/*
13747 * "test_alloc_fail(id, countdown, repeat)" function
13748 */
13749 static void
13750f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13751{
13752 if (argvars[0].v_type != VAR_NUMBER
13753 || argvars[0].vval.v_number <= 0
13754 || argvars[1].v_type != VAR_NUMBER
13755 || argvars[1].vval.v_number < 0
13756 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013757 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013758 else
13759 {
13760 alloc_fail_id = argvars[0].vval.v_number;
13761 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013762 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013763 alloc_fail_countdown = argvars[1].vval.v_number;
13764 alloc_fail_repeat = argvars[2].vval.v_number;
13765 did_outofmem_msg = FALSE;
13766 }
13767}
13768
13769/*
13770 * "test_autochdir()"
13771 */
13772 static void
13773f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13774{
13775#if defined(FEAT_AUTOCHDIR)
13776 test_autochdir = TRUE;
13777#endif
13778}
13779
13780/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013781 * "test_feedinput()"
13782 */
13783 static void
13784f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13785{
13786#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013787 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013788
13789 if (val != NULL)
13790 {
13791 trash_input_buf();
13792 add_to_input_buf_csi(val, (int)STRLEN(val));
13793 }
13794#endif
13795}
13796
13797/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013798 * "test_option_not_set({name})" function
13799 */
13800 static void
13801f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13802{
13803 char_u *name = (char_u *)"";
13804
13805 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013806 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013807 else
13808 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013809 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013810 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013811 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013812 }
13813}
13814
13815/*
13816 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013817 */
13818 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013819f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013820{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013821 char_u *name = (char_u *)"";
13822 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013823 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013824
13825 if (argvars[0].v_type != VAR_STRING
13826 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013827 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013828 else
13829 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013830 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013831 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013832
13833 if (STRCMP(name, (char_u *)"redraw") == 0)
13834 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013835 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13836 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013837 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13838 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013839 else if (STRCMP(name, (char_u *)"starting") == 0)
13840 {
13841 if (val)
13842 {
13843 if (save_starting < 0)
13844 save_starting = starting;
13845 starting = 0;
13846 }
13847 else
13848 {
13849 starting = save_starting;
13850 save_starting = -1;
13851 }
13852 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013853 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13854 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013855 else if (STRCMP(name, (char_u *)"ALL") == 0)
13856 {
13857 disable_char_avail_for_testing = FALSE;
13858 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013859 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013860 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013861 if (save_starting >= 0)
13862 {
13863 starting = save_starting;
13864 save_starting = -1;
13865 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013866 }
13867 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013868 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013869 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013870}
13871
13872/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010013873 * "test_refcount({expr})" function
13874 */
13875 static void
13876f_test_refcount(typval_T *argvars, typval_T *rettv)
13877{
13878 int retval = -1;
13879
13880 switch (argvars[0].v_type)
13881 {
13882 case VAR_UNKNOWN:
13883 case VAR_NUMBER:
13884 case VAR_FLOAT:
13885 case VAR_SPECIAL:
13886 case VAR_STRING:
13887 break;
13888 case VAR_JOB:
13889#ifdef FEAT_JOB_CHANNEL
13890 if (argvars[0].vval.v_job != NULL)
13891 retval = argvars[0].vval.v_job->jv_refcount - 1;
13892#endif
13893 break;
13894 case VAR_CHANNEL:
13895#ifdef FEAT_JOB_CHANNEL
13896 if (argvars[0].vval.v_channel != NULL)
13897 retval = argvars[0].vval.v_channel->ch_refcount - 1;
13898#endif
13899 break;
13900 case VAR_FUNC:
13901 if (argvars[0].vval.v_string != NULL)
13902 {
13903 ufunc_T *fp;
13904
13905 fp = find_func(argvars[0].vval.v_string);
13906 if (fp != NULL)
13907 retval = fp->uf_refcount;
13908 }
13909 break;
13910 case VAR_PARTIAL:
13911 if (argvars[0].vval.v_partial != NULL)
13912 retval = argvars[0].vval.v_partial->pt_refcount - 1;
13913 break;
13914 case VAR_BLOB:
13915 if (argvars[0].vval.v_blob != NULL)
13916 retval = argvars[0].vval.v_blob->bv_refcount - 1;
13917 break;
13918 case VAR_LIST:
13919 if (argvars[0].vval.v_list != NULL)
13920 retval = argvars[0].vval.v_list->lv_refcount - 1;
13921 break;
13922 case VAR_DICT:
13923 if (argvars[0].vval.v_dict != NULL)
13924 retval = argvars[0].vval.v_dict->dv_refcount - 1;
13925 break;
13926 }
13927
13928 rettv->v_type = VAR_NUMBER;
13929 rettv->vval.v_number = retval;
13930
13931}
13932
13933/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013934 * "test_garbagecollect_now()" function
13935 */
13936 static void
13937f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13938{
13939 /* This is dangerous, any Lists and Dicts used internally may be freed
13940 * while still in use. */
13941 garbage_collect(TRUE);
13942}
13943
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013944/*
13945 * "test_ignore_error()" function
13946 */
13947 static void
13948f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13949{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013950 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013951}
13952
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010013953 static void
13954f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
13955{
13956 rettv->v_type = VAR_BLOB;
13957 rettv->vval.v_blob = NULL;
13958}
13959
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013960#ifdef FEAT_JOB_CHANNEL
13961 static void
13962f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13963{
13964 rettv->v_type = VAR_CHANNEL;
13965 rettv->vval.v_channel = NULL;
13966}
13967#endif
13968
13969 static void
13970f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13971{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013972 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013973}
13974
13975#ifdef FEAT_JOB_CHANNEL
13976 static void
13977f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13978{
13979 rettv->v_type = VAR_JOB;
13980 rettv->vval.v_job = NULL;
13981}
13982#endif
13983
13984 static void
13985f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13986{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013987 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013988}
13989
13990 static void
13991f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13992{
13993 rettv->v_type = VAR_PARTIAL;
13994 rettv->vval.v_partial = NULL;
13995}
13996
13997 static void
13998f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13999{
14000 rettv->v_type = VAR_STRING;
14001 rettv->vval.v_string = NULL;
14002}
14003
Bram Moolenaarab186732018-09-14 21:27:06 +020014004#ifdef FEAT_GUI
14005 static void
14006f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14007{
14008 char_u *which;
14009 long value;
14010 int dragging;
14011 scrollbar_T *sb = NULL;
14012
14013 if (argvars[0].v_type != VAR_STRING
14014 || (argvars[1].v_type) != VAR_NUMBER
14015 || (argvars[2].v_type) != VAR_NUMBER)
14016 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014017 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020014018 return;
14019 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014020 which = tv_get_string(&argvars[0]);
14021 value = tv_get_number(&argvars[1]);
14022 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014023
14024 if (STRCMP(which, "left") == 0)
14025 sb = &curwin->w_scrollbars[SBAR_LEFT];
14026 else if (STRCMP(which, "right") == 0)
14027 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14028 else if (STRCMP(which, "hor") == 0)
14029 sb = &gui.bottom_sbar;
14030 if (sb == NULL)
14031 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014032 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014033 return;
14034 }
14035 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014036# ifndef USE_ON_FLY_SCROLL
14037 // need to loop through normal_cmd() to handle the scroll events
14038 exec_normal(FALSE, TRUE, FALSE);
14039# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014040}
14041#endif
14042
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014043 static void
14044f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14045{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014046 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014047}
14048
14049#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14050/*
14051 * Get a callback from "arg". It can be a Funcref or a function name.
14052 * When "arg" is zero return an empty string.
14053 * Return NULL for an invalid argument.
14054 */
14055 char_u *
14056get_callback(typval_T *arg, partial_T **pp)
14057{
14058 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14059 {
14060 *pp = arg->vval.v_partial;
14061 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014062 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014063 }
14064 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014065 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014066 {
14067 func_ref(arg->vval.v_string);
14068 return arg->vval.v_string;
14069 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014070 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14071 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014072 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014073 return NULL;
14074}
14075
14076/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014077 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014078 */
14079 void
14080free_callback(char_u *callback, partial_T *partial)
14081{
14082 if (partial != NULL)
14083 partial_unref(partial);
14084 else if (callback != NULL)
14085 {
14086 func_unref(callback);
14087 vim_free(callback);
14088 }
14089}
14090#endif
14091
14092#ifdef FEAT_TIMERS
14093/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014094 * "timer_info([timer])" function
14095 */
14096 static void
14097f_timer_info(typval_T *argvars, typval_T *rettv)
14098{
14099 timer_T *timer = NULL;
14100
14101 if (rettv_list_alloc(rettv) != OK)
14102 return;
14103 if (argvars[0].v_type != VAR_UNKNOWN)
14104 {
14105 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014106 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014107 else
14108 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014109 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014110 if (timer != NULL)
14111 add_timer_info(rettv, timer);
14112 }
14113 }
14114 else
14115 add_timer_info_all(rettv);
14116}
14117
14118/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014119 * "timer_pause(timer, paused)" function
14120 */
14121 static void
14122f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14123{
14124 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014125 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014126
14127 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014128 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014129 else
14130 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014131 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014132 if (timer != NULL)
14133 timer->tr_paused = paused;
14134 }
14135}
14136
14137/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014138 * "timer_start(time, callback [, options])" function
14139 */
14140 static void
14141f_timer_start(typval_T *argvars, typval_T *rettv)
14142{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014143 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014144 timer_T *timer;
14145 int repeat = 0;
14146 char_u *callback;
14147 dict_T *dict;
14148 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014149
Bram Moolenaar75537a92016-09-05 22:45:28 +020014150 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014151 if (check_secure())
14152 return;
14153 if (argvars[2].v_type != VAR_UNKNOWN)
14154 {
14155 if (argvars[2].v_type != VAR_DICT
14156 || (dict = argvars[2].vval.v_dict) == NULL)
14157 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014158 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014159 return;
14160 }
14161 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014162 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014163 }
14164
Bram Moolenaar75537a92016-09-05 22:45:28 +020014165 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014166 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014167 return;
14168
14169 timer = create_timer(msec, repeat);
14170 if (timer == NULL)
14171 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014172 else
14173 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014174 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014175 timer->tr_callback = vim_strsave(callback);
14176 else
14177 /* pointer into the partial */
14178 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014179 timer->tr_partial = partial;
14180 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014181 }
14182}
14183
14184/*
14185 * "timer_stop(timer)" function
14186 */
14187 static void
14188f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14189{
14190 timer_T *timer;
14191
14192 if (argvars[0].v_type != VAR_NUMBER)
14193 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014194 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014195 return;
14196 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014197 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014198 if (timer != NULL)
14199 stop_timer(timer);
14200}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014201
14202/*
14203 * "timer_stopall()" function
14204 */
14205 static void
14206f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14207{
14208 stop_all_timers();
14209}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014210#endif
14211
14212/*
14213 * "tolower(string)" function
14214 */
14215 static void
14216f_tolower(typval_T *argvars, typval_T *rettv)
14217{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014218 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014219 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014220}
14221
14222/*
14223 * "toupper(string)" function
14224 */
14225 static void
14226f_toupper(typval_T *argvars, typval_T *rettv)
14227{
14228 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014229 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014230}
14231
14232/*
14233 * "tr(string, fromstr, tostr)" function
14234 */
14235 static void
14236f_tr(typval_T *argvars, typval_T *rettv)
14237{
14238 char_u *in_str;
14239 char_u *fromstr;
14240 char_u *tostr;
14241 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014242 int inlen;
14243 int fromlen;
14244 int tolen;
14245 int idx;
14246 char_u *cpstr;
14247 int cplen;
14248 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014249 char_u buf[NUMBUFLEN];
14250 char_u buf2[NUMBUFLEN];
14251 garray_T ga;
14252
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014253 in_str = tv_get_string(&argvars[0]);
14254 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14255 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014256
14257 /* Default return value: empty string. */
14258 rettv->v_type = VAR_STRING;
14259 rettv->vval.v_string = NULL;
14260 if (fromstr == NULL || tostr == NULL)
14261 return; /* type error; errmsg already given */
14262 ga_init2(&ga, (int)sizeof(char), 80);
14263
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014264 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014265 /* not multi-byte: fromstr and tostr must be the same length */
14266 if (STRLEN(fromstr) != STRLEN(tostr))
14267 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014268error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014269 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014270 ga_clear(&ga);
14271 return;
14272 }
14273
14274 /* fromstr and tostr have to contain the same number of chars */
14275 while (*in_str != NUL)
14276 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014277 if (has_mbyte)
14278 {
14279 inlen = (*mb_ptr2len)(in_str);
14280 cpstr = in_str;
14281 cplen = inlen;
14282 idx = 0;
14283 for (p = fromstr; *p != NUL; p += fromlen)
14284 {
14285 fromlen = (*mb_ptr2len)(p);
14286 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14287 {
14288 for (p = tostr; *p != NUL; p += tolen)
14289 {
14290 tolen = (*mb_ptr2len)(p);
14291 if (idx-- == 0)
14292 {
14293 cplen = tolen;
14294 cpstr = p;
14295 break;
14296 }
14297 }
14298 if (*p == NUL) /* tostr is shorter than fromstr */
14299 goto error;
14300 break;
14301 }
14302 ++idx;
14303 }
14304
14305 if (first && cpstr == in_str)
14306 {
14307 /* Check that fromstr and tostr have the same number of
14308 * (multi-byte) characters. Done only once when a character
14309 * of in_str doesn't appear in fromstr. */
14310 first = FALSE;
14311 for (p = tostr; *p != NUL; p += tolen)
14312 {
14313 tolen = (*mb_ptr2len)(p);
14314 --idx;
14315 }
14316 if (idx != 0)
14317 goto error;
14318 }
14319
14320 (void)ga_grow(&ga, cplen);
14321 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14322 ga.ga_len += cplen;
14323
14324 in_str += inlen;
14325 }
14326 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014327 {
14328 /* When not using multi-byte chars we can do it faster. */
14329 p = vim_strchr(fromstr, *in_str);
14330 if (p != NULL)
14331 ga_append(&ga, tostr[p - fromstr]);
14332 else
14333 ga_append(&ga, *in_str);
14334 ++in_str;
14335 }
14336 }
14337
14338 /* add a terminating NUL */
14339 (void)ga_grow(&ga, 1);
14340 ga_append(&ga, NUL);
14341
14342 rettv->vval.v_string = ga.ga_data;
14343}
14344
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014345/*
14346 * "trim({expr})" function
14347 */
14348 static void
14349f_trim(typval_T *argvars, typval_T *rettv)
14350{
14351 char_u buf1[NUMBUFLEN];
14352 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014353 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014354 char_u *mask = NULL;
14355 char_u *tail;
14356 char_u *prev;
14357 char_u *p;
14358 int c1;
14359
14360 rettv->v_type = VAR_STRING;
14361 if (head == NULL)
14362 {
14363 rettv->vval.v_string = NULL;
14364 return;
14365 }
14366
14367 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014368 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014369
14370 while (*head != NUL)
14371 {
14372 c1 = PTR2CHAR(head);
14373 if (mask == NULL)
14374 {
14375 if (c1 > ' ' && c1 != 0xa0)
14376 break;
14377 }
14378 else
14379 {
14380 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14381 if (c1 == PTR2CHAR(p))
14382 break;
14383 if (*p == NUL)
14384 break;
14385 }
14386 MB_PTR_ADV(head);
14387 }
14388
14389 for (tail = head + STRLEN(head); tail > head; tail = prev)
14390 {
14391 prev = tail;
14392 MB_PTR_BACK(head, prev);
14393 c1 = PTR2CHAR(prev);
14394 if (mask == NULL)
14395 {
14396 if (c1 > ' ' && c1 != 0xa0)
14397 break;
14398 }
14399 else
14400 {
14401 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14402 if (c1 == PTR2CHAR(p))
14403 break;
14404 if (*p == NUL)
14405 break;
14406 }
14407 }
14408 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14409}
14410
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014411#ifdef FEAT_FLOAT
14412/*
14413 * "trunc({float})" function
14414 */
14415 static void
14416f_trunc(typval_T *argvars, typval_T *rettv)
14417{
14418 float_T f = 0.0;
14419
14420 rettv->v_type = VAR_FLOAT;
14421 if (get_float_arg(argvars, &f) == OK)
14422 /* trunc() is not in C90, use floor() or ceil() instead. */
14423 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14424 else
14425 rettv->vval.v_float = 0.0;
14426}
14427#endif
14428
14429/*
14430 * "type(expr)" function
14431 */
14432 static void
14433f_type(typval_T *argvars, typval_T *rettv)
14434{
14435 int n = -1;
14436
14437 switch (argvars[0].v_type)
14438 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014439 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14440 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014441 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014442 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14443 case VAR_LIST: n = VAR_TYPE_LIST; break;
14444 case VAR_DICT: n = VAR_TYPE_DICT; break;
14445 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014446 case VAR_SPECIAL:
14447 if (argvars[0].vval.v_number == VVAL_FALSE
14448 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014449 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014450 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014451 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014452 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014453 case VAR_JOB: n = VAR_TYPE_JOB; break;
14454 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014455 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014456 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014457 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014458 n = -1;
14459 break;
14460 }
14461 rettv->vval.v_number = n;
14462}
14463
14464/*
14465 * "undofile(name)" function
14466 */
14467 static void
14468f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14469{
14470 rettv->v_type = VAR_STRING;
14471#ifdef FEAT_PERSISTENT_UNDO
14472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014473 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014474
14475 if (*fname == NUL)
14476 {
14477 /* If there is no file name there will be no undo file. */
14478 rettv->vval.v_string = NULL;
14479 }
14480 else
14481 {
14482 char_u *ffname = FullName_save(fname, FALSE);
14483
14484 if (ffname != NULL)
14485 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14486 vim_free(ffname);
14487 }
14488 }
14489#else
14490 rettv->vval.v_string = NULL;
14491#endif
14492}
14493
14494/*
14495 * "undotree()" function
14496 */
14497 static void
14498f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14499{
14500 if (rettv_dict_alloc(rettv) == OK)
14501 {
14502 dict_T *dict = rettv->vval.v_dict;
14503 list_T *list;
14504
Bram Moolenaare0be1672018-07-08 16:50:37 +020014505 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14506 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14507 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14508 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14509 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14510 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014511
14512 list = list_alloc();
14513 if (list != NULL)
14514 {
14515 u_eval_tree(curbuf->b_u_oldhead, list);
14516 dict_add_list(dict, "entries", list);
14517 }
14518 }
14519}
14520
14521/*
14522 * "values(dict)" function
14523 */
14524 static void
14525f_values(typval_T *argvars, typval_T *rettv)
14526{
14527 dict_list(argvars, rettv, 1);
14528}
14529
14530/*
14531 * "virtcol(string)" function
14532 */
14533 static void
14534f_virtcol(typval_T *argvars, typval_T *rettv)
14535{
14536 colnr_T vcol = 0;
14537 pos_T *fp;
14538 int fnum = curbuf->b_fnum;
14539
14540 fp = var2fpos(&argvars[0], FALSE, &fnum);
14541 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14542 && fnum == curbuf->b_fnum)
14543 {
14544 getvvcol(curwin, fp, NULL, NULL, &vcol);
14545 ++vcol;
14546 }
14547
14548 rettv->vval.v_number = vcol;
14549}
14550
14551/*
14552 * "visualmode()" function
14553 */
14554 static void
14555f_visualmode(typval_T *argvars, typval_T *rettv)
14556{
14557 char_u str[2];
14558
14559 rettv->v_type = VAR_STRING;
14560 str[0] = curbuf->b_visual_mode_eval;
14561 str[1] = NUL;
14562 rettv->vval.v_string = vim_strsave(str);
14563
14564 /* A non-zero number or non-empty string argument: reset mode. */
14565 if (non_zero_arg(&argvars[0]))
14566 curbuf->b_visual_mode_eval = NUL;
14567}
14568
14569/*
14570 * "wildmenumode()" function
14571 */
14572 static void
14573f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14574{
14575#ifdef FEAT_WILDMENU
14576 if (wild_menu_showing)
14577 rettv->vval.v_number = 1;
14578#endif
14579}
14580
14581/*
14582 * "winbufnr(nr)" function
14583 */
14584 static void
14585f_winbufnr(typval_T *argvars, typval_T *rettv)
14586{
14587 win_T *wp;
14588
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014589 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014590 if (wp == NULL)
14591 rettv->vval.v_number = -1;
14592 else
14593 rettv->vval.v_number = wp->w_buffer->b_fnum;
14594}
14595
14596/*
14597 * "wincol()" function
14598 */
14599 static void
14600f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14601{
14602 validate_cursor();
14603 rettv->vval.v_number = curwin->w_wcol + 1;
14604}
14605
14606/*
14607 * "winheight(nr)" function
14608 */
14609 static void
14610f_winheight(typval_T *argvars, typval_T *rettv)
14611{
14612 win_T *wp;
14613
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014614 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014615 if (wp == NULL)
14616 rettv->vval.v_number = -1;
14617 else
14618 rettv->vval.v_number = wp->w_height;
14619}
14620
14621/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014622 * "winlayout()" function
14623 */
14624 static void
14625f_winlayout(typval_T *argvars, typval_T *rettv)
14626{
14627 tabpage_T *tp;
14628
14629 if (rettv_list_alloc(rettv) != OK)
14630 return;
14631
14632 if (argvars[0].v_type == VAR_UNKNOWN)
14633 tp = curtab;
14634 else
14635 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014636 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014637 if (tp == NULL)
14638 return;
14639 }
14640
14641 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14642}
14643
14644/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014645 * "winline()" function
14646 */
14647 static void
14648f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14649{
14650 validate_cursor();
14651 rettv->vval.v_number = curwin->w_wrow + 1;
14652}
14653
14654/*
14655 * "winnr()" function
14656 */
14657 static void
14658f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14659{
14660 int nr = 1;
14661
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014662 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014663 rettv->vval.v_number = nr;
14664}
14665
14666/*
14667 * "winrestcmd()" function
14668 */
14669 static void
14670f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14671{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014672 win_T *wp;
14673 int winnr = 1;
14674 garray_T ga;
14675 char_u buf[50];
14676
14677 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014678 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014679 {
14680 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14681 ga_concat(&ga, buf);
14682 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14683 ga_concat(&ga, buf);
14684 ++winnr;
14685 }
14686 ga_append(&ga, NUL);
14687
14688 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014689 rettv->v_type = VAR_STRING;
14690}
14691
14692/*
14693 * "winrestview()" function
14694 */
14695 static void
14696f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14697{
14698 dict_T *dict;
14699
14700 if (argvars[0].v_type != VAR_DICT
14701 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014702 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014703 else
14704 {
14705 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014706 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014707 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014708 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014709 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014710 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014711 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14712 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014713 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014714 curwin->w_set_curswant = FALSE;
14715 }
14716
14717 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014718 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014719#ifdef FEAT_DIFF
14720 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014721 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014722#endif
14723 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014724 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014725 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014726 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014727
14728 check_cursor();
14729 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014730 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014731 changed_window_setting();
14732
14733 if (curwin->w_topline <= 0)
14734 curwin->w_topline = 1;
14735 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14736 curwin->w_topline = curbuf->b_ml.ml_line_count;
14737#ifdef FEAT_DIFF
14738 check_topfill(curwin, TRUE);
14739#endif
14740 }
14741}
14742
14743/*
14744 * "winsaveview()" function
14745 */
14746 static void
14747f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14748{
14749 dict_T *dict;
14750
14751 if (rettv_dict_alloc(rettv) == FAIL)
14752 return;
14753 dict = rettv->vval.v_dict;
14754
Bram Moolenaare0be1672018-07-08 16:50:37 +020014755 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14756 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014757 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014758 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014759 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014760
Bram Moolenaare0be1672018-07-08 16:50:37 +020014761 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014762#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014763 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014764#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014765 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14766 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014767}
14768
14769/*
14770 * "winwidth(nr)" function
14771 */
14772 static void
14773f_winwidth(typval_T *argvars, typval_T *rettv)
14774{
14775 win_T *wp;
14776
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014777 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014778 if (wp == NULL)
14779 rettv->vval.v_number = -1;
14780 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014781 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014782}
14783
14784/*
14785 * "wordcount()" function
14786 */
14787 static void
14788f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14789{
14790 if (rettv_dict_alloc(rettv) == FAIL)
14791 return;
14792 cursor_pos_info(rettv->vval.v_dict);
14793}
14794
14795/*
14796 * "writefile()" function
14797 */
14798 static void
14799f_writefile(typval_T *argvars, typval_T *rettv)
14800{
14801 int binary = FALSE;
14802 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014803#ifdef HAVE_FSYNC
14804 int do_fsync = p_fs;
14805#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014806 char_u *fname;
14807 FILE *fd;
14808 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014809 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014810 list_T *list = NULL;
14811 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014812
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014813 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014814 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014815 return;
14816
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014817 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014818 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014819 list = argvars[0].vval.v_list;
14820 if (list == NULL)
14821 return;
14822 for (li = list->lv_first; li != NULL; li = li->li_next)
14823 if (tv_get_string_chk(&li->li_tv) == NULL)
14824 return;
14825 }
14826 else if (argvars[0].v_type == VAR_BLOB)
14827 {
14828 blob = argvars[0].vval.v_blob;
14829 if (blob == NULL)
14830 return;
14831 }
14832 else
14833 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014834 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014835 return;
14836 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014837
14838 if (argvars[2].v_type != VAR_UNKNOWN)
14839 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014840 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014841
14842 if (arg2 == NULL)
14843 return;
14844 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014845 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014846 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014847 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014848#ifdef HAVE_FSYNC
14849 if (vim_strchr(arg2, 's') != NULL)
14850 do_fsync = TRUE;
14851 else if (vim_strchr(arg2, 'S') != NULL)
14852 do_fsync = FALSE;
14853#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014854 }
14855
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014856 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014857 if (fname == NULL)
14858 return;
14859
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014860 /* Always open the file in binary mode, library functions have a mind of
14861 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014862 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14863 append ? APPENDBIN : WRITEBIN)) == NULL)
14864 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014865 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014866 ret = -1;
14867 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014868 else if (blob)
14869 {
14870 if (write_blob(fd, blob) == FAIL)
14871 ret = -1;
14872#ifdef HAVE_FSYNC
14873 else if (do_fsync)
14874 // Ignore the error, the user wouldn't know what to do about it.
14875 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010014876 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014877#endif
14878 fclose(fd);
14879 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014880 else
14881 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014882 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014883 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014884#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014885 else if (do_fsync)
14886 /* Ignore the error, the user wouldn't know what to do about it.
14887 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010014888 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014889#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014890 fclose(fd);
14891 }
14892
14893 rettv->vval.v_number = ret;
14894}
14895
14896/*
14897 * "xor(expr, expr)" function
14898 */
14899 static void
14900f_xor(typval_T *argvars, typval_T *rettv)
14901{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014902 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14903 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014904}
14905
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014906#endif /* FEAT_EVAL */