blob: a46b339cd5896d584e75bd527a6275cfe9fa78e7 [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 Moolenaar73dad1e2016-07-17 22:13:49 +020032static char *e_stringreq = N_("E928: String required");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020033
34#ifdef FEAT_FLOAT
35static void f_abs(typval_T *argvars, typval_T *rettv);
36static void f_acos(typval_T *argvars, typval_T *rettv);
37#endif
38static void f_add(typval_T *argvars, typval_T *rettv);
39static void f_and(typval_T *argvars, typval_T *rettv);
40static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020041static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020042static void f_argc(typval_T *argvars, typval_T *rettv);
43static void f_argidx(typval_T *argvars, typval_T *rettv);
44static void f_arglistid(typval_T *argvars, typval_T *rettv);
45static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010046static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020047static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010048static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_assert_exception(typval_T *argvars, typval_T *rettv);
50static void f_assert_fails(typval_T *argvars, typval_T *rettv);
51static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020052static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020053static void f_assert_match(typval_T *argvars, typval_T *rettv);
54static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
55static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010056static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_assert_true(typval_T *argvars, typval_T *rettv);
58#ifdef FEAT_FLOAT
59static void f_asin(typval_T *argvars, typval_T *rettv);
60static void f_atan(typval_T *argvars, typval_T *rettv);
61static void f_atan2(typval_T *argvars, typval_T *rettv);
62#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010063#ifdef FEAT_BEVAL
64static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010065# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010066static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010067# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010068#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_browse(typval_T *argvars, typval_T *rettv);
70static void f_browsedir(typval_T *argvars, typval_T *rettv);
71static void f_bufexists(typval_T *argvars, typval_T *rettv);
72static void f_buflisted(typval_T *argvars, typval_T *rettv);
73static void f_bufloaded(typval_T *argvars, typval_T *rettv);
74static void f_bufname(typval_T *argvars, typval_T *rettv);
75static void f_bufnr(typval_T *argvars, typval_T *rettv);
76static void f_bufwinid(typval_T *argvars, typval_T *rettv);
77static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
78static void f_byte2line(typval_T *argvars, typval_T *rettv);
79static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
80static void f_byteidx(typval_T *argvars, typval_T *rettv);
81static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
82static void f_call(typval_T *argvars, typval_T *rettv);
83#ifdef FEAT_FLOAT
84static void f_ceil(typval_T *argvars, typval_T *rettv);
85#endif
86#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010087static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020089static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020090static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
91static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
92static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
93static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
94static void f_ch_info(typval_T *argvars, typval_T *rettv);
95static void f_ch_log(typval_T *argvars, typval_T *rettv);
96static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
97static void f_ch_open(typval_T *argvars, typval_T *rettv);
98static void f_ch_read(typval_T *argvars, typval_T *rettv);
99static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
100static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
101static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
102static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
103static void f_ch_status(typval_T *argvars, typval_T *rettv);
104#endif
105static void f_changenr(typval_T *argvars, typval_T *rettv);
106static void f_char2nr(typval_T *argvars, typval_T *rettv);
107static void f_cindent(typval_T *argvars, typval_T *rettv);
108static void f_clearmatches(typval_T *argvars, typval_T *rettv);
109static void f_col(typval_T *argvars, typval_T *rettv);
110#if defined(FEAT_INS_EXPAND)
111static void f_complete(typval_T *argvars, typval_T *rettv);
112static void f_complete_add(typval_T *argvars, typval_T *rettv);
113static void f_complete_check(typval_T *argvars, typval_T *rettv);
114#endif
115static void f_confirm(typval_T *argvars, typval_T *rettv);
116static void f_copy(typval_T *argvars, typval_T *rettv);
117#ifdef FEAT_FLOAT
118static void f_cos(typval_T *argvars, typval_T *rettv);
119static void f_cosh(typval_T *argvars, typval_T *rettv);
120#endif
121static void f_count(typval_T *argvars, typval_T *rettv);
122static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
123static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200124#ifdef WIN3264
125static void f_debugbreak(typval_T *argvars, typval_T *rettv);
126#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127static void f_deepcopy(typval_T *argvars, typval_T *rettv);
128static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200129static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200130static void f_did_filetype(typval_T *argvars, typval_T *rettv);
131static void f_diff_filler(typval_T *argvars, typval_T *rettv);
132static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
133static void f_empty(typval_T *argvars, typval_T *rettv);
134static void f_escape(typval_T *argvars, typval_T *rettv);
135static void f_eval(typval_T *argvars, typval_T *rettv);
136static void f_eventhandler(typval_T *argvars, typval_T *rettv);
137static void f_executable(typval_T *argvars, typval_T *rettv);
138static void f_execute(typval_T *argvars, typval_T *rettv);
139static void f_exepath(typval_T *argvars, typval_T *rettv);
140static void f_exists(typval_T *argvars, typval_T *rettv);
141#ifdef FEAT_FLOAT
142static void f_exp(typval_T *argvars, typval_T *rettv);
143#endif
144static void f_expand(typval_T *argvars, typval_T *rettv);
145static void f_extend(typval_T *argvars, typval_T *rettv);
146static void f_feedkeys(typval_T *argvars, typval_T *rettv);
147static void f_filereadable(typval_T *argvars, typval_T *rettv);
148static void f_filewritable(typval_T *argvars, typval_T *rettv);
149static void f_filter(typval_T *argvars, typval_T *rettv);
150static void f_finddir(typval_T *argvars, typval_T *rettv);
151static void f_findfile(typval_T *argvars, typval_T *rettv);
152#ifdef FEAT_FLOAT
153static void f_float2nr(typval_T *argvars, typval_T *rettv);
154static void f_floor(typval_T *argvars, typval_T *rettv);
155static void f_fmod(typval_T *argvars, typval_T *rettv);
156#endif
157static void f_fnameescape(typval_T *argvars, typval_T *rettv);
158static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
159static void f_foldclosed(typval_T *argvars, typval_T *rettv);
160static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
161static void f_foldlevel(typval_T *argvars, typval_T *rettv);
162static void f_foldtext(typval_T *argvars, typval_T *rettv);
163static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
164static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200165static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200166static void f_function(typval_T *argvars, typval_T *rettv);
167static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
168static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200169static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_getbufline(typval_T *argvars, typval_T *rettv);
171static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100172static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_getchar(typval_T *argvars, typval_T *rettv);
174static void f_getcharmod(typval_T *argvars, typval_T *rettv);
175static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
176static void f_getcmdline(typval_T *argvars, typval_T *rettv);
177#if defined(FEAT_CMDL_COMPL)
178static void f_getcompletion(typval_T *argvars, typval_T *rettv);
179#endif
180static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
181static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
182static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
183static void f_getcwd(typval_T *argvars, typval_T *rettv);
184static void f_getfontname(typval_T *argvars, typval_T *rettv);
185static void f_getfperm(typval_T *argvars, typval_T *rettv);
186static void f_getfsize(typval_T *argvars, typval_T *rettv);
187static void f_getftime(typval_T *argvars, typval_T *rettv);
188static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100189static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200190static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200191static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_getmatches(typval_T *argvars, typval_T *rettv);
193static void f_getpid(typval_T *argvars, typval_T *rettv);
194static void f_getcurpos(typval_T *argvars, typval_T *rettv);
195static void f_getpos(typval_T *argvars, typval_T *rettv);
196static void f_getqflist(typval_T *argvars, typval_T *rettv);
197static void f_getreg(typval_T *argvars, typval_T *rettv);
198static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200199static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_gettabvar(typval_T *argvars, typval_T *rettv);
201static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100202static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200203static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100204static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200205static void f_getwinposx(typval_T *argvars, typval_T *rettv);
206static void f_getwinposy(typval_T *argvars, typval_T *rettv);
207static void f_getwinvar(typval_T *argvars, typval_T *rettv);
208static void f_glob(typval_T *argvars, typval_T *rettv);
209static void f_globpath(typval_T *argvars, typval_T *rettv);
210static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
211static void f_has(typval_T *argvars, typval_T *rettv);
212static void f_has_key(typval_T *argvars, typval_T *rettv);
213static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
214static void f_hasmapto(typval_T *argvars, typval_T *rettv);
215static void f_histadd(typval_T *argvars, typval_T *rettv);
216static void f_histdel(typval_T *argvars, typval_T *rettv);
217static void f_histget(typval_T *argvars, typval_T *rettv);
218static void f_histnr(typval_T *argvars, typval_T *rettv);
219static void f_hlID(typval_T *argvars, typval_T *rettv);
220static void f_hlexists(typval_T *argvars, typval_T *rettv);
221static void f_hostname(typval_T *argvars, typval_T *rettv);
222static void f_iconv(typval_T *argvars, typval_T *rettv);
223static void f_indent(typval_T *argvars, typval_T *rettv);
224static void f_index(typval_T *argvars, typval_T *rettv);
225static void f_input(typval_T *argvars, typval_T *rettv);
226static void f_inputdialog(typval_T *argvars, typval_T *rettv);
227static void f_inputlist(typval_T *argvars, typval_T *rettv);
228static void f_inputrestore(typval_T *argvars, typval_T *rettv);
229static void f_inputsave(typval_T *argvars, typval_T *rettv);
230static void f_inputsecret(typval_T *argvars, typval_T *rettv);
231static void f_insert(typval_T *argvars, typval_T *rettv);
232static void f_invert(typval_T *argvars, typval_T *rettv);
233static void f_isdirectory(typval_T *argvars, typval_T *rettv);
234static void f_islocked(typval_T *argvars, typval_T *rettv);
235#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
236static void f_isnan(typval_T *argvars, typval_T *rettv);
237#endif
238static void f_items(typval_T *argvars, typval_T *rettv);
239#ifdef FEAT_JOB_CHANNEL
240static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
241static void f_job_info(typval_T *argvars, typval_T *rettv);
242static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
243static void f_job_start(typval_T *argvars, typval_T *rettv);
244static void f_job_stop(typval_T *argvars, typval_T *rettv);
245static void f_job_status(typval_T *argvars, typval_T *rettv);
246#endif
247static void f_join(typval_T *argvars, typval_T *rettv);
248static void f_js_decode(typval_T *argvars, typval_T *rettv);
249static void f_js_encode(typval_T *argvars, typval_T *rettv);
250static void f_json_decode(typval_T *argvars, typval_T *rettv);
251static void f_json_encode(typval_T *argvars, typval_T *rettv);
252static void f_keys(typval_T *argvars, typval_T *rettv);
253static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
254static void f_len(typval_T *argvars, typval_T *rettv);
255static void f_libcall(typval_T *argvars, typval_T *rettv);
256static void f_libcallnr(typval_T *argvars, typval_T *rettv);
257static void f_line(typval_T *argvars, typval_T *rettv);
258static void f_line2byte(typval_T *argvars, typval_T *rettv);
259static void f_lispindent(typval_T *argvars, typval_T *rettv);
260static void f_localtime(typval_T *argvars, typval_T *rettv);
261#ifdef FEAT_FLOAT
262static void f_log(typval_T *argvars, typval_T *rettv);
263static void f_log10(typval_T *argvars, typval_T *rettv);
264#endif
265#ifdef FEAT_LUA
266static void f_luaeval(typval_T *argvars, typval_T *rettv);
267#endif
268static void f_map(typval_T *argvars, typval_T *rettv);
269static void f_maparg(typval_T *argvars, typval_T *rettv);
270static void f_mapcheck(typval_T *argvars, typval_T *rettv);
271static void f_match(typval_T *argvars, typval_T *rettv);
272static void f_matchadd(typval_T *argvars, typval_T *rettv);
273static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
274static void f_matcharg(typval_T *argvars, typval_T *rettv);
275static void f_matchdelete(typval_T *argvars, typval_T *rettv);
276static void f_matchend(typval_T *argvars, typval_T *rettv);
277static void f_matchlist(typval_T *argvars, typval_T *rettv);
278static void f_matchstr(typval_T *argvars, typval_T *rettv);
279static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
280static void f_max(typval_T *argvars, typval_T *rettv);
281static void f_min(typval_T *argvars, typval_T *rettv);
282#ifdef vim_mkdir
283static void f_mkdir(typval_T *argvars, typval_T *rettv);
284#endif
285static void f_mode(typval_T *argvars, typval_T *rettv);
286#ifdef FEAT_MZSCHEME
287static void f_mzeval(typval_T *argvars, typval_T *rettv);
288#endif
289static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
290static void f_nr2char(typval_T *argvars, typval_T *rettv);
291static void f_or(typval_T *argvars, typval_T *rettv);
292static void f_pathshorten(typval_T *argvars, typval_T *rettv);
293#ifdef FEAT_PERL
294static void f_perleval(typval_T *argvars, typval_T *rettv);
295#endif
296#ifdef FEAT_FLOAT
297static void f_pow(typval_T *argvars, typval_T *rettv);
298#endif
299static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
300static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200301#ifdef FEAT_JOB_CHANNEL
302static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200303static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200304static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
305#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306static void f_pumvisible(typval_T *argvars, typval_T *rettv);
307#ifdef FEAT_PYTHON3
308static void f_py3eval(typval_T *argvars, typval_T *rettv);
309#endif
310#ifdef FEAT_PYTHON
311static void f_pyeval(typval_T *argvars, typval_T *rettv);
312#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100313#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
314static void f_pyxeval(typval_T *argvars, typval_T *rettv);
315#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200316static void f_range(typval_T *argvars, typval_T *rettv);
317static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200318static void f_reg_executing(typval_T *argvars, typval_T *rettv);
319static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200320static void f_reltime(typval_T *argvars, typval_T *rettv);
321#ifdef FEAT_FLOAT
322static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
323#endif
324static void f_reltimestr(typval_T *argvars, typval_T *rettv);
325static void f_remote_expr(typval_T *argvars, typval_T *rettv);
326static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
327static void f_remote_peek(typval_T *argvars, typval_T *rettv);
328static void f_remote_read(typval_T *argvars, typval_T *rettv);
329static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100330static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200331static void f_remove(typval_T *argvars, typval_T *rettv);
332static void f_rename(typval_T *argvars, typval_T *rettv);
333static void f_repeat(typval_T *argvars, typval_T *rettv);
334static void f_resolve(typval_T *argvars, typval_T *rettv);
335static void f_reverse(typval_T *argvars, typval_T *rettv);
336#ifdef FEAT_FLOAT
337static void f_round(typval_T *argvars, typval_T *rettv);
338#endif
339static void f_screenattr(typval_T *argvars, typval_T *rettv);
340static void f_screenchar(typval_T *argvars, typval_T *rettv);
341static void f_screencol(typval_T *argvars, typval_T *rettv);
342static void f_screenrow(typval_T *argvars, typval_T *rettv);
343static void f_search(typval_T *argvars, typval_T *rettv);
344static void f_searchdecl(typval_T *argvars, typval_T *rettv);
345static void f_searchpair(typval_T *argvars, typval_T *rettv);
346static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
347static void f_searchpos(typval_T *argvars, typval_T *rettv);
348static void f_server2client(typval_T *argvars, typval_T *rettv);
349static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200350static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200351static void f_setbufvar(typval_T *argvars, typval_T *rettv);
352static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
353static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
354static void f_setfperm(typval_T *argvars, typval_T *rettv);
355static void f_setline(typval_T *argvars, typval_T *rettv);
356static void f_setloclist(typval_T *argvars, typval_T *rettv);
357static void f_setmatches(typval_T *argvars, typval_T *rettv);
358static void f_setpos(typval_T *argvars, typval_T *rettv);
359static void f_setqflist(typval_T *argvars, typval_T *rettv);
360static void f_setreg(typval_T *argvars, typval_T *rettv);
361static void f_settabvar(typval_T *argvars, typval_T *rettv);
362static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100363static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200364static void f_setwinvar(typval_T *argvars, typval_T *rettv);
365#ifdef FEAT_CRYPT
366static void f_sha256(typval_T *argvars, typval_T *rettv);
367#endif /* FEAT_CRYPT */
368static void f_shellescape(typval_T *argvars, typval_T *rettv);
369static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100370#ifdef FEAT_SIGNS
371static void f_sign_define(typval_T *argvars, typval_T *rettv);
372static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
373static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
374static void f_sign_place(typval_T *argvars, typval_T *rettv);
375static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
376static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
377#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378static void f_simplify(typval_T *argvars, typval_T *rettv);
379#ifdef FEAT_FLOAT
380static void f_sin(typval_T *argvars, typval_T *rettv);
381static void f_sinh(typval_T *argvars, typval_T *rettv);
382#endif
383static void f_sort(typval_T *argvars, typval_T *rettv);
384static void f_soundfold(typval_T *argvars, typval_T *rettv);
385static void f_spellbadword(typval_T *argvars, typval_T *rettv);
386static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
387static void f_split(typval_T *argvars, typval_T *rettv);
388#ifdef FEAT_FLOAT
389static void f_sqrt(typval_T *argvars, typval_T *rettv);
390static void f_str2float(typval_T *argvars, typval_T *rettv);
391#endif
392static void f_str2nr(typval_T *argvars, typval_T *rettv);
393static void f_strchars(typval_T *argvars, typval_T *rettv);
394#ifdef HAVE_STRFTIME
395static void f_strftime(typval_T *argvars, typval_T *rettv);
396#endif
397static void f_strgetchar(typval_T *argvars, typval_T *rettv);
398static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200399static void f_strlen(typval_T *argvars, typval_T *rettv);
400static void f_strcharpart(typval_T *argvars, typval_T *rettv);
401static void f_strpart(typval_T *argvars, typval_T *rettv);
402static void f_strridx(typval_T *argvars, typval_T *rettv);
403static void f_strtrans(typval_T *argvars, typval_T *rettv);
404static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
405static void f_strwidth(typval_T *argvars, typval_T *rettv);
406static void f_submatch(typval_T *argvars, typval_T *rettv);
407static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200408static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200409static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200410static void f_synID(typval_T *argvars, typval_T *rettv);
411static void f_synIDattr(typval_T *argvars, typval_T *rettv);
412static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
413static void f_synstack(typval_T *argvars, typval_T *rettv);
414static void f_synconcealed(typval_T *argvars, typval_T *rettv);
415static void f_system(typval_T *argvars, typval_T *rettv);
416static void f_systemlist(typval_T *argvars, typval_T *rettv);
417static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
418static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
419static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
420static void f_taglist(typval_T *argvars, typval_T *rettv);
421static void f_tagfiles(typval_T *argvars, typval_T *rettv);
422static void f_tempname(typval_T *argvars, typval_T *rettv);
423static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
424static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200425static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200426static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100427static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200428static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100429static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430#ifdef FEAT_JOB_CHANNEL
431static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
432#endif
433static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
434#ifdef FEAT_JOB_CHANNEL
435static void f_test_null_job(typval_T *argvars, typval_T *rettv);
436#endif
437static void f_test_null_list(typval_T *argvars, typval_T *rettv);
438static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
439static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200440#ifdef FEAT_GUI
441static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
442#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200443static void f_test_settime(typval_T *argvars, typval_T *rettv);
444#ifdef FEAT_FLOAT
445static void f_tan(typval_T *argvars, typval_T *rettv);
446static void f_tanh(typval_T *argvars, typval_T *rettv);
447#endif
448#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200449static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200450static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200451static void f_timer_start(typval_T *argvars, typval_T *rettv);
452static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200453static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200454#endif
455static void f_tolower(typval_T *argvars, typval_T *rettv);
456static void f_toupper(typval_T *argvars, typval_T *rettv);
457static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100458static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200459#ifdef FEAT_FLOAT
460static void f_trunc(typval_T *argvars, typval_T *rettv);
461#endif
462static void f_type(typval_T *argvars, typval_T *rettv);
463static void f_undofile(typval_T *argvars, typval_T *rettv);
464static void f_undotree(typval_T *argvars, typval_T *rettv);
465static void f_uniq(typval_T *argvars, typval_T *rettv);
466static void f_values(typval_T *argvars, typval_T *rettv);
467static void f_virtcol(typval_T *argvars, typval_T *rettv);
468static void f_visualmode(typval_T *argvars, typval_T *rettv);
469static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
470static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
471static void f_win_getid(typval_T *argvars, typval_T *rettv);
472static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
473static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
474static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100475static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200476static void f_winbufnr(typval_T *argvars, typval_T *rettv);
477static void f_wincol(typval_T *argvars, typval_T *rettv);
478static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200479static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200480static void f_winline(typval_T *argvars, typval_T *rettv);
481static void f_winnr(typval_T *argvars, typval_T *rettv);
482static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
483static void f_winrestview(typval_T *argvars, typval_T *rettv);
484static void f_winsaveview(typval_T *argvars, typval_T *rettv);
485static void f_winwidth(typval_T *argvars, typval_T *rettv);
486static void f_writefile(typval_T *argvars, typval_T *rettv);
487static void f_wordcount(typval_T *argvars, typval_T *rettv);
488static void f_xor(typval_T *argvars, typval_T *rettv);
489
490/*
491 * Array with names and number of arguments of all internal functions
492 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
493 */
494static struct fst
495{
496 char *f_name; /* function name */
497 char f_min_argc; /* minimal number of arguments */
498 char f_max_argc; /* maximal number of arguments */
499 void (*f_func)(typval_T *args, typval_T *rvar);
500 /* implementation of function */
501} functions[] =
502{
503#ifdef FEAT_FLOAT
504 {"abs", 1, 1, f_abs},
505 {"acos", 1, 1, f_acos}, /* WJMc */
506#endif
507 {"add", 2, 2, f_add},
508 {"and", 2, 2, f_and},
509 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200510 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200511 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200512 {"argidx", 0, 0, f_argidx},
513 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200514 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200515#ifdef FEAT_FLOAT
516 {"asin", 1, 1, f_asin}, /* WJMc */
517#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100518 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200519 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100520 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200521 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200522 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200523 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100524 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525 {"assert_match", 2, 3, f_assert_match},
526 {"assert_notequal", 2, 3, f_assert_notequal},
527 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100528 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529 {"assert_true", 1, 2, f_assert_true},
530#ifdef FEAT_FLOAT
531 {"atan", 1, 1, f_atan},
532 {"atan2", 2, 2, f_atan2},
533#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100534#ifdef FEAT_BEVAL
535 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100536# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100537 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100538# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100539#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200540 {"browse", 4, 4, f_browse},
541 {"browsedir", 2, 2, f_browsedir},
542 {"bufexists", 1, 1, f_bufexists},
543 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
544 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
545 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
546 {"buflisted", 1, 1, f_buflisted},
547 {"bufloaded", 1, 1, f_bufloaded},
548 {"bufname", 1, 1, f_bufname},
549 {"bufnr", 1, 2, f_bufnr},
550 {"bufwinid", 1, 1, f_bufwinid},
551 {"bufwinnr", 1, 1, f_bufwinnr},
552 {"byte2line", 1, 1, f_byte2line},
553 {"byteidx", 2, 2, f_byteidx},
554 {"byteidxcomp", 2, 2, f_byteidxcomp},
555 {"call", 2, 3, f_call},
556#ifdef FEAT_FLOAT
557 {"ceil", 1, 1, f_ceil},
558#endif
559#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100560 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200561 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200562 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200563 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
564 {"ch_evalraw", 2, 3, f_ch_evalraw},
565 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
566 {"ch_getjob", 1, 1, f_ch_getjob},
567 {"ch_info", 1, 1, f_ch_info},
568 {"ch_log", 1, 2, f_ch_log},
569 {"ch_logfile", 1, 2, f_ch_logfile},
570 {"ch_open", 1, 2, f_ch_open},
571 {"ch_read", 1, 2, f_ch_read},
572 {"ch_readraw", 1, 2, f_ch_readraw},
573 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
574 {"ch_sendraw", 2, 3, f_ch_sendraw},
575 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200576 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200577#endif
578 {"changenr", 0, 0, f_changenr},
579 {"char2nr", 1, 2, f_char2nr},
580 {"cindent", 1, 1, f_cindent},
581 {"clearmatches", 0, 0, f_clearmatches},
582 {"col", 1, 1, f_col},
583#if defined(FEAT_INS_EXPAND)
584 {"complete", 2, 2, f_complete},
585 {"complete_add", 1, 1, f_complete_add},
586 {"complete_check", 0, 0, f_complete_check},
587#endif
588 {"confirm", 1, 4, f_confirm},
589 {"copy", 1, 1, f_copy},
590#ifdef FEAT_FLOAT
591 {"cos", 1, 1, f_cos},
592 {"cosh", 1, 1, f_cosh},
593#endif
594 {"count", 2, 4, f_count},
595 {"cscope_connection",0,3, f_cscope_connection},
596 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200597#ifdef WIN3264
598 {"debugbreak", 1, 1, f_debugbreak},
599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600 {"deepcopy", 1, 2, f_deepcopy},
601 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200602 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603 {"did_filetype", 0, 0, f_did_filetype},
604 {"diff_filler", 1, 1, f_diff_filler},
605 {"diff_hlID", 2, 2, f_diff_hlID},
606 {"empty", 1, 1, f_empty},
607 {"escape", 2, 2, f_escape},
608 {"eval", 1, 1, f_eval},
609 {"eventhandler", 0, 0, f_eventhandler},
610 {"executable", 1, 1, f_executable},
611 {"execute", 1, 2, f_execute},
612 {"exepath", 1, 1, f_exepath},
613 {"exists", 1, 1, f_exists},
614#ifdef FEAT_FLOAT
615 {"exp", 1, 1, f_exp},
616#endif
617 {"expand", 1, 3, f_expand},
618 {"extend", 2, 3, f_extend},
619 {"feedkeys", 1, 2, f_feedkeys},
620 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
621 {"filereadable", 1, 1, f_filereadable},
622 {"filewritable", 1, 1, f_filewritable},
623 {"filter", 2, 2, f_filter},
624 {"finddir", 1, 3, f_finddir},
625 {"findfile", 1, 3, f_findfile},
626#ifdef FEAT_FLOAT
627 {"float2nr", 1, 1, f_float2nr},
628 {"floor", 1, 1, f_floor},
629 {"fmod", 2, 2, f_fmod},
630#endif
631 {"fnameescape", 1, 1, f_fnameescape},
632 {"fnamemodify", 2, 2, f_fnamemodify},
633 {"foldclosed", 1, 1, f_foldclosed},
634 {"foldclosedend", 1, 1, f_foldclosedend},
635 {"foldlevel", 1, 1, f_foldlevel},
636 {"foldtext", 0, 0, f_foldtext},
637 {"foldtextresult", 1, 1, f_foldtextresult},
638 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200639 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640 {"function", 1, 3, f_function},
641 {"garbagecollect", 0, 1, f_garbagecollect},
642 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200643 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644 {"getbufline", 2, 3, f_getbufline},
645 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100646 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200647 {"getchar", 0, 1, f_getchar},
648 {"getcharmod", 0, 0, f_getcharmod},
649 {"getcharsearch", 0, 0, f_getcharsearch},
650 {"getcmdline", 0, 0, f_getcmdline},
651 {"getcmdpos", 0, 0, f_getcmdpos},
652 {"getcmdtype", 0, 0, f_getcmdtype},
653 {"getcmdwintype", 0, 0, f_getcmdwintype},
654#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200655 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200656#endif
657 {"getcurpos", 0, 0, f_getcurpos},
658 {"getcwd", 0, 2, f_getcwd},
659 {"getfontname", 0, 1, f_getfontname},
660 {"getfperm", 1, 1, f_getfperm},
661 {"getfsize", 1, 1, f_getfsize},
662 {"getftime", 1, 1, f_getftime},
663 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100664 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200665 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200666 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200667 {"getmatches", 0, 0, f_getmatches},
668 {"getpid", 0, 0, f_getpid},
669 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200670 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200671 {"getreg", 0, 3, f_getreg},
672 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200673 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200674 {"gettabvar", 2, 3, f_gettabvar},
675 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100676 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200677 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100678 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200679 {"getwinposx", 0, 0, f_getwinposx},
680 {"getwinposy", 0, 0, f_getwinposy},
681 {"getwinvar", 2, 3, f_getwinvar},
682 {"glob", 1, 4, f_glob},
683 {"glob2regpat", 1, 1, f_glob2regpat},
684 {"globpath", 2, 5, f_globpath},
685 {"has", 1, 1, f_has},
686 {"has_key", 2, 2, f_has_key},
687 {"haslocaldir", 0, 2, f_haslocaldir},
688 {"hasmapto", 1, 3, f_hasmapto},
689 {"highlightID", 1, 1, f_hlID}, /* obsolete */
690 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
691 {"histadd", 2, 2, f_histadd},
692 {"histdel", 1, 2, f_histdel},
693 {"histget", 1, 2, f_histget},
694 {"histnr", 1, 1, f_histnr},
695 {"hlID", 1, 1, f_hlID},
696 {"hlexists", 1, 1, f_hlexists},
697 {"hostname", 0, 0, f_hostname},
698 {"iconv", 3, 3, f_iconv},
699 {"indent", 1, 1, f_indent},
700 {"index", 2, 4, f_index},
701 {"input", 1, 3, f_input},
702 {"inputdialog", 1, 3, f_inputdialog},
703 {"inputlist", 1, 1, f_inputlist},
704 {"inputrestore", 0, 0, f_inputrestore},
705 {"inputsave", 0, 0, f_inputsave},
706 {"inputsecret", 1, 2, f_inputsecret},
707 {"insert", 2, 3, f_insert},
708 {"invert", 1, 1, f_invert},
709 {"isdirectory", 1, 1, f_isdirectory},
710 {"islocked", 1, 1, f_islocked},
711#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
712 {"isnan", 1, 1, f_isnan},
713#endif
714 {"items", 1, 1, f_items},
715#ifdef FEAT_JOB_CHANNEL
716 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200717 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200718 {"job_setoptions", 2, 2, f_job_setoptions},
719 {"job_start", 1, 2, f_job_start},
720 {"job_status", 1, 1, f_job_status},
721 {"job_stop", 1, 2, f_job_stop},
722#endif
723 {"join", 1, 2, f_join},
724 {"js_decode", 1, 1, f_js_decode},
725 {"js_encode", 1, 1, f_js_encode},
726 {"json_decode", 1, 1, f_json_decode},
727 {"json_encode", 1, 1, f_json_encode},
728 {"keys", 1, 1, f_keys},
729 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
730 {"len", 1, 1, f_len},
731 {"libcall", 3, 3, f_libcall},
732 {"libcallnr", 3, 3, f_libcallnr},
733 {"line", 1, 1, f_line},
734 {"line2byte", 1, 1, f_line2byte},
735 {"lispindent", 1, 1, f_lispindent},
736 {"localtime", 0, 0, f_localtime},
737#ifdef FEAT_FLOAT
738 {"log", 1, 1, f_log},
739 {"log10", 1, 1, f_log10},
740#endif
741#ifdef FEAT_LUA
742 {"luaeval", 1, 2, f_luaeval},
743#endif
744 {"map", 2, 2, f_map},
745 {"maparg", 1, 4, f_maparg},
746 {"mapcheck", 1, 3, f_mapcheck},
747 {"match", 2, 4, f_match},
748 {"matchadd", 2, 5, f_matchadd},
749 {"matchaddpos", 2, 5, f_matchaddpos},
750 {"matcharg", 1, 1, f_matcharg},
751 {"matchdelete", 1, 1, f_matchdelete},
752 {"matchend", 2, 4, f_matchend},
753 {"matchlist", 2, 4, f_matchlist},
754 {"matchstr", 2, 4, f_matchstr},
755 {"matchstrpos", 2, 4, f_matchstrpos},
756 {"max", 1, 1, f_max},
757 {"min", 1, 1, f_min},
758#ifdef vim_mkdir
759 {"mkdir", 1, 3, f_mkdir},
760#endif
761 {"mode", 0, 1, f_mode},
762#ifdef FEAT_MZSCHEME
763 {"mzeval", 1, 1, f_mzeval},
764#endif
765 {"nextnonblank", 1, 1, f_nextnonblank},
766 {"nr2char", 1, 2, f_nr2char},
767 {"or", 2, 2, f_or},
768 {"pathshorten", 1, 1, f_pathshorten},
769#ifdef FEAT_PERL
770 {"perleval", 1, 1, f_perleval},
771#endif
772#ifdef FEAT_FLOAT
773 {"pow", 2, 2, f_pow},
774#endif
775 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100776 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200777#ifdef FEAT_JOB_CHANNEL
778 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200779 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200780 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
781#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100782#ifdef FEAT_TEXT_PROP
783 {"prop_add", 3, 3, f_prop_add},
784 {"prop_clear", 1, 3, f_prop_clear},
785 {"prop_list", 1, 2, f_prop_list},
786 {"prop_remove", 2, 3, f_prop_remove},
787 {"prop_type_add", 2, 2, f_prop_type_add},
788 {"prop_type_change", 2, 2, f_prop_type_change},
789 {"prop_type_delete", 1, 2, f_prop_type_delete},
790 {"prop_type_get", 1, 2, f_prop_type_get},
791 {"prop_type_list", 0, 1, f_prop_type_list},
792#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793 {"pumvisible", 0, 0, f_pumvisible},
794#ifdef FEAT_PYTHON3
795 {"py3eval", 1, 1, f_py3eval},
796#endif
797#ifdef FEAT_PYTHON
798 {"pyeval", 1, 1, f_pyeval},
799#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100800#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
801 {"pyxeval", 1, 1, f_pyxeval},
802#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200803 {"range", 1, 3, f_range},
804 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200805 {"reg_executing", 0, 0, f_reg_executing},
806 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807 {"reltime", 0, 2, f_reltime},
808#ifdef FEAT_FLOAT
809 {"reltimefloat", 1, 1, f_reltimefloat},
810#endif
811 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100812 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200813 {"remote_foreground", 1, 1, f_remote_foreground},
814 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100815 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200816 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100817 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200818 {"remove", 2, 3, f_remove},
819 {"rename", 2, 2, f_rename},
820 {"repeat", 2, 2, f_repeat},
821 {"resolve", 1, 1, f_resolve},
822 {"reverse", 1, 1, f_reverse},
823#ifdef FEAT_FLOAT
824 {"round", 1, 1, f_round},
825#endif
826 {"screenattr", 2, 2, f_screenattr},
827 {"screenchar", 2, 2, f_screenchar},
828 {"screencol", 0, 0, f_screencol},
829 {"screenrow", 0, 0, f_screenrow},
830 {"search", 1, 4, f_search},
831 {"searchdecl", 1, 3, f_searchdecl},
832 {"searchpair", 3, 7, f_searchpair},
833 {"searchpairpos", 3, 7, f_searchpairpos},
834 {"searchpos", 1, 4, f_searchpos},
835 {"server2client", 2, 2, f_server2client},
836 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200837 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200838 {"setbufvar", 3, 3, f_setbufvar},
839 {"setcharsearch", 1, 1, f_setcharsearch},
840 {"setcmdpos", 1, 1, f_setcmdpos},
841 {"setfperm", 2, 2, f_setfperm},
842 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200843 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200844 {"setmatches", 1, 1, f_setmatches},
845 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200846 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847 {"setreg", 2, 3, f_setreg},
848 {"settabvar", 3, 3, f_settabvar},
849 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100850 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851 {"setwinvar", 3, 3, f_setwinvar},
852#ifdef FEAT_CRYPT
853 {"sha256", 1, 1, f_sha256},
854#endif
855 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100856 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100857#ifdef FEAT_SIGNS
858 {"sign_define", 1, 2, f_sign_define},
859 {"sign_getdefined", 0, 1, f_sign_getdefined},
860 {"sign_getplaced", 0, 2, f_sign_getplaced},
861 {"sign_place", 4, 5, f_sign_place},
862 {"sign_undefine", 0, 1, f_sign_undefine},
863 {"sign_unplace", 1, 2, f_sign_unplace},
864#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200865 {"simplify", 1, 1, f_simplify},
866#ifdef FEAT_FLOAT
867 {"sin", 1, 1, f_sin},
868 {"sinh", 1, 1, f_sinh},
869#endif
870 {"sort", 1, 3, f_sort},
871 {"soundfold", 1, 1, f_soundfold},
872 {"spellbadword", 0, 1, f_spellbadword},
873 {"spellsuggest", 1, 3, f_spellsuggest},
874 {"split", 1, 3, f_split},
875#ifdef FEAT_FLOAT
876 {"sqrt", 1, 1, f_sqrt},
877 {"str2float", 1, 1, f_str2float},
878#endif
879 {"str2nr", 1, 2, f_str2nr},
880 {"strcharpart", 2, 3, f_strcharpart},
881 {"strchars", 1, 2, f_strchars},
882 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
883#ifdef HAVE_STRFTIME
884 {"strftime", 1, 2, f_strftime},
885#endif
886 {"strgetchar", 2, 2, f_strgetchar},
887 {"stridx", 2, 3, f_stridx},
888 {"string", 1, 1, f_string},
889 {"strlen", 1, 1, f_strlen},
890 {"strpart", 2, 3, f_strpart},
891 {"strridx", 2, 3, f_strridx},
892 {"strtrans", 1, 1, f_strtrans},
893 {"strwidth", 1, 1, f_strwidth},
894 {"submatch", 1, 2, f_submatch},
895 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200896 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200897 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200898 {"synID", 3, 3, f_synID},
899 {"synIDattr", 2, 3, f_synIDattr},
900 {"synIDtrans", 1, 1, f_synIDtrans},
901 {"synconcealed", 2, 2, f_synconcealed},
902 {"synstack", 2, 2, f_synstack},
903 {"system", 1, 2, f_system},
904 {"systemlist", 1, 2, f_systemlist},
905 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
906 {"tabpagenr", 0, 1, f_tabpagenr},
907 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
908 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100909 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200910#ifdef FEAT_FLOAT
911 {"tan", 1, 1, f_tan},
912 {"tanh", 1, 1, f_tanh},
913#endif
914 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200915#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100916 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
917 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100918 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200919 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200920# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
921 {"term_getansicolors", 1, 1, f_term_getansicolors},
922# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200923 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200924 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200925 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200926 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200927 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200928 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200929 {"term_getstatus", 1, 1, f_term_getstatus},
930 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200931 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200932 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200933 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200934 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200935# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
936 {"term_setansicolors", 2, 2, f_term_setansicolors},
937# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100938 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100939 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200940 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200941 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200942 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200943#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200944 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
945 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200946 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200947 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100948 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949#ifdef FEAT_JOB_CHANNEL
950 {"test_null_channel", 0, 0, f_test_null_channel},
951#endif
952 {"test_null_dict", 0, 0, f_test_null_dict},
953#ifdef FEAT_JOB_CHANNEL
954 {"test_null_job", 0, 0, f_test_null_job},
955#endif
956 {"test_null_list", 0, 0, f_test_null_list},
957 {"test_null_partial", 0, 0, f_test_null_partial},
958 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200959 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100960 {"test_override", 2, 2, f_test_override},
Bram Moolenaarab186732018-09-14 21:27:06 +0200961#ifdef FEAT_GUI
962 {"test_scrollbar", 3, 3, f_test_scrollbar},
963#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964 {"test_settime", 1, 1, f_test_settime},
965#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200966 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200967 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200968 {"timer_start", 2, 3, f_timer_start},
969 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200970 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200971#endif
972 {"tolower", 1, 1, f_tolower},
973 {"toupper", 1, 1, f_toupper},
974 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100975 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200976#ifdef FEAT_FLOAT
977 {"trunc", 1, 1, f_trunc},
978#endif
979 {"type", 1, 1, f_type},
980 {"undofile", 1, 1, f_undofile},
981 {"undotree", 0, 0, f_undotree},
982 {"uniq", 1, 3, f_uniq},
983 {"values", 1, 1, f_values},
984 {"virtcol", 1, 1, f_virtcol},
985 {"visualmode", 0, 1, f_visualmode},
986 {"wildmenumode", 0, 0, f_wildmenumode},
987 {"win_findbuf", 1, 1, f_win_findbuf},
988 {"win_getid", 0, 2, f_win_getid},
989 {"win_gotoid", 1, 1, f_win_gotoid},
990 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
991 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100992 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200993 {"winbufnr", 1, 1, f_winbufnr},
994 {"wincol", 0, 0, f_wincol},
995 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200996 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200997 {"winline", 0, 0, f_winline},
998 {"winnr", 0, 1, f_winnr},
999 {"winrestcmd", 0, 0, f_winrestcmd},
1000 {"winrestview", 1, 1, f_winrestview},
1001 {"winsaveview", 0, 0, f_winsaveview},
1002 {"winwidth", 1, 1, f_winwidth},
1003 {"wordcount", 0, 0, f_wordcount},
1004 {"writefile", 2, 3, f_writefile},
1005 {"xor", 2, 2, f_xor},
1006};
1007
1008#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1009
1010/*
1011 * Function given to ExpandGeneric() to obtain the list of internal
1012 * or user defined function names.
1013 */
1014 char_u *
1015get_function_name(expand_T *xp, int idx)
1016{
1017 static int intidx = -1;
1018 char_u *name;
1019
1020 if (idx == 0)
1021 intidx = -1;
1022 if (intidx < 0)
1023 {
1024 name = get_user_func_name(xp, idx);
1025 if (name != NULL)
1026 return name;
1027 }
1028 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1029 {
1030 STRCPY(IObuff, functions[intidx].f_name);
1031 STRCAT(IObuff, "(");
1032 if (functions[intidx].f_max_argc == 0)
1033 STRCAT(IObuff, ")");
1034 return IObuff;
1035 }
1036
1037 return NULL;
1038}
1039
1040/*
1041 * Function given to ExpandGeneric() to obtain the list of internal or
1042 * user defined variable or function names.
1043 */
1044 char_u *
1045get_expr_name(expand_T *xp, int idx)
1046{
1047 static int intidx = -1;
1048 char_u *name;
1049
1050 if (idx == 0)
1051 intidx = -1;
1052 if (intidx < 0)
1053 {
1054 name = get_function_name(xp, idx);
1055 if (name != NULL)
1056 return name;
1057 }
1058 return get_user_var_name(xp, ++intidx);
1059}
1060
1061#endif /* FEAT_CMDL_COMPL */
1062
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001063/*
1064 * Find internal function in table above.
1065 * Return index, or -1 if not found
1066 */
1067 int
1068find_internal_func(
1069 char_u *name) /* name of the function */
1070{
1071 int first = 0;
1072 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1073 int cmp;
1074 int x;
1075
1076 /*
1077 * Find the function name in the table. Binary search.
1078 */
1079 while (first <= last)
1080 {
1081 x = first + ((unsigned)(last - first) >> 1);
1082 cmp = STRCMP(name, functions[x].f_name);
1083 if (cmp < 0)
1084 last = x - 1;
1085 else if (cmp > 0)
1086 first = x + 1;
1087 else
1088 return x;
1089 }
1090 return -1;
1091}
1092
1093 int
1094call_internal_func(
1095 char_u *name,
1096 int argcount,
1097 typval_T *argvars,
1098 typval_T *rettv)
1099{
1100 int i;
1101
1102 i = find_internal_func(name);
1103 if (i < 0)
1104 return ERROR_UNKNOWN;
1105 if (argcount < functions[i].f_min_argc)
1106 return ERROR_TOOFEW;
1107 if (argcount > functions[i].f_max_argc)
1108 return ERROR_TOOMANY;
1109 argvars[argcount].v_type = VAR_UNKNOWN;
1110 functions[i].f_func(argvars, rettv);
1111 return ERROR_NONE;
1112}
1113
1114/*
1115 * Return TRUE for a non-zero Number and a non-empty String.
1116 */
1117 static int
1118non_zero_arg(typval_T *argvars)
1119{
1120 return ((argvars[0].v_type == VAR_NUMBER
1121 && argvars[0].vval.v_number != 0)
1122 || (argvars[0].v_type == VAR_SPECIAL
1123 && argvars[0].vval.v_number == VVAL_TRUE)
1124 || (argvars[0].v_type == VAR_STRING
1125 && argvars[0].vval.v_string != NULL
1126 && *argvars[0].vval.v_string != NUL));
1127}
1128
1129/*
1130 * Get the lnum from the first argument.
1131 * Also accepts ".", "$", etc., but that only works for the current buffer.
1132 * Returns -1 on error.
1133 */
1134 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001135tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001136{
1137 typval_T rettv;
1138 linenr_T lnum;
1139
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001140 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001141 if (lnum == 0) /* no valid number, try using line() */
1142 {
1143 rettv.v_type = VAR_NUMBER;
1144 f_line(argvars, &rettv);
1145 lnum = (linenr_T)rettv.vval.v_number;
1146 clear_tv(&rettv);
1147 }
1148 return lnum;
1149}
1150
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001151/*
1152 * Get the lnum from the first argument.
1153 * Also accepts "$", then "buf" is used.
1154 * Returns 0 on error.
1155 */
1156 static linenr_T
1157tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1158{
1159 if (argvars[0].v_type == VAR_STRING
1160 && argvars[0].vval.v_string != NULL
1161 && argvars[0].vval.v_string[0] == '$'
1162 && buf != NULL)
1163 return buf->b_ml.ml_line_count;
1164 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1165}
1166
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001167#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001168/*
1169 * Get the float value of "argvars[0]" into "f".
1170 * Returns FAIL when the argument is not a Number or Float.
1171 */
1172 static int
1173get_float_arg(typval_T *argvars, float_T *f)
1174{
1175 if (argvars[0].v_type == VAR_FLOAT)
1176 {
1177 *f = argvars[0].vval.v_float;
1178 return OK;
1179 }
1180 if (argvars[0].v_type == VAR_NUMBER)
1181 {
1182 *f = (float_T)argvars[0].vval.v_number;
1183 return OK;
1184 }
1185 EMSG(_("E808: Number or Float required"));
1186 return FAIL;
1187}
1188
1189/*
1190 * "abs(expr)" function
1191 */
1192 static void
1193f_abs(typval_T *argvars, typval_T *rettv)
1194{
1195 if (argvars[0].v_type == VAR_FLOAT)
1196 {
1197 rettv->v_type = VAR_FLOAT;
1198 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1199 }
1200 else
1201 {
1202 varnumber_T n;
1203 int error = FALSE;
1204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001205 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001206 if (error)
1207 rettv->vval.v_number = -1;
1208 else if (n > 0)
1209 rettv->vval.v_number = n;
1210 else
1211 rettv->vval.v_number = -n;
1212 }
1213}
1214
1215/*
1216 * "acos()" function
1217 */
1218 static void
1219f_acos(typval_T *argvars, typval_T *rettv)
1220{
1221 float_T f = 0.0;
1222
1223 rettv->v_type = VAR_FLOAT;
1224 if (get_float_arg(argvars, &f) == OK)
1225 rettv->vval.v_float = acos(f);
1226 else
1227 rettv->vval.v_float = 0.0;
1228}
1229#endif
1230
1231/*
1232 * "add(list, item)" function
1233 */
1234 static void
1235f_add(typval_T *argvars, typval_T *rettv)
1236{
1237 list_T *l;
1238
1239 rettv->vval.v_number = 1; /* Default: Failed */
1240 if (argvars[0].v_type == VAR_LIST)
1241 {
1242 if ((l = argvars[0].vval.v_list) != NULL
1243 && !tv_check_lock(l->lv_lock,
1244 (char_u *)N_("add() argument"), TRUE)
1245 && list_append_tv(l, &argvars[1]) == OK)
1246 copy_tv(&argvars[0], rettv);
1247 }
1248 else
1249 EMSG(_(e_listreq));
1250}
1251
1252/*
1253 * "and(expr, expr)" function
1254 */
1255 static void
1256f_and(typval_T *argvars, typval_T *rettv)
1257{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001258 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1259 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001260}
1261
1262/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001263 * If there is a window for "curbuf", make it the current window.
1264 */
1265 static void
1266find_win_for_curbuf(void)
1267{
1268 wininfo_T *wip;
1269
1270 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1271 {
1272 if (wip->wi_win != NULL)
1273 {
1274 curwin = wip->wi_win;
1275 break;
1276 }
1277 }
1278}
1279
1280/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001281 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001282 */
1283 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001284set_buffer_lines(
1285 buf_T *buf,
1286 linenr_T lnum_arg,
1287 int append,
1288 typval_T *lines,
1289 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001290{
Bram Moolenaarca851592018-06-06 21:04:07 +02001291 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1292 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 list_T *l = NULL;
1294 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001296 linenr_T append_lnum;
1297 buf_T *curbuf_save = NULL;
1298 win_T *curwin_save = NULL;
1299 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001300
Bram Moolenaarca851592018-06-06 21:04:07 +02001301 /* When using the current buffer ml_mfp will be set if needed. Useful when
1302 * setline() is used on startup. For other buffers the buffer must be
1303 * loaded. */
1304 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001305 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001306 rettv->vval.v_number = 1; /* FAIL */
1307 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001308 }
1309
Bram Moolenaarca851592018-06-06 21:04:07 +02001310 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001311 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001312 curbuf_save = curbuf;
1313 curwin_save = curwin;
1314 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001315 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001316 }
1317
1318 if (append)
1319 // appendbufline() uses the line number below which we insert
1320 append_lnum = lnum - 1;
1321 else
1322 // setbufline() uses the line number above which we insert, we only
1323 // append if it's below the last line
1324 append_lnum = curbuf->b_ml.ml_line_count;
1325
1326 if (lines->v_type == VAR_LIST)
1327 {
1328 l = lines->vval.v_list;
1329 li = l->lv_first;
1330 }
1331 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001332 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001333
1334 /* default result is zero == OK */
1335 for (;;)
1336 {
1337 if (l != NULL)
1338 {
1339 /* list argument, get next string */
1340 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001341 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001342 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343 li = li->li_next;
1344 }
1345
Bram Moolenaarca851592018-06-06 21:04:07 +02001346 rettv->vval.v_number = 1; /* FAIL */
1347 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1348 break;
1349
1350 /* When coming here from Insert mode, sync undo, so that this can be
1351 * undone separately from what was previously inserted. */
1352 if (u_sync_once == 2)
1353 {
1354 u_sync_once = 1; /* notify that u_sync() was called */
1355 u_sync(TRUE);
1356 }
1357
1358 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1359 {
1360 /* existing line, replace it */
1361 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1362 {
1363 changed_bytes(lnum, 0);
1364 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1365 check_cursor_col();
1366 rettv->vval.v_number = 0; /* OK */
1367 }
1368 }
1369 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1370 {
1371 /* append the line */
1372 ++added;
1373 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1374 rettv->vval.v_number = 0; /* OK */
1375 }
1376
1377 if (l == NULL) /* only one string argument */
1378 break;
1379 ++lnum;
1380 }
1381
1382 if (added > 0)
1383 {
1384 win_T *wp;
1385 tabpage_T *tp;
1386
1387 appended_lines_mark(append_lnum, added);
1388 FOR_ALL_TAB_WINDOWS(tp, wp)
1389 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1390 wp->w_cursor.lnum += added;
1391 check_cursor_col();
1392
Bram Moolenaarf2732452018-06-03 14:47:35 +02001393#ifdef FEAT_JOB_CHANNEL
1394 if (bt_prompt(curbuf) && (State & INSERT))
1395 // show the line with the prompt
1396 update_topline();
1397#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001398 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001399
1400 if (!is_curbuf)
1401 {
1402 curbuf = curbuf_save;
1403 curwin = curwin_save;
1404 }
1405}
1406
1407/*
1408 * "append(lnum, string/list)" function
1409 */
1410 static void
1411f_append(typval_T *argvars, typval_T *rettv)
1412{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001413 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001414
1415 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1416}
1417
1418/*
1419 * "appendbufline(buf, lnum, string/list)" function
1420 */
1421 static void
1422f_appendbufline(typval_T *argvars, typval_T *rettv)
1423{
1424 linenr_T lnum;
1425 buf_T *buf;
1426
1427 buf = get_buf_tv(&argvars[0], FALSE);
1428 if (buf == NULL)
1429 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001430 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001431 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001432 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001433 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1434 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001435}
1436
1437/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001438 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001439 */
1440 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001441f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001442{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001443 win_T *wp;
1444
1445 if (argvars[0].v_type == VAR_UNKNOWN)
1446 // use the current window
1447 rettv->vval.v_number = ARGCOUNT;
1448 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001449 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001450 // use the global argument list
1451 rettv->vval.v_number = GARGCOUNT;
1452 else
1453 {
1454 // use the argument list of the specified window
1455 wp = find_win_by_nr_or_id(&argvars[0]);
1456 if (wp != NULL)
1457 rettv->vval.v_number = WARGCOUNT(wp);
1458 else
1459 rettv->vval.v_number = -1;
1460 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001461}
1462
1463/*
1464 * "argidx()" function
1465 */
1466 static void
1467f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1468{
1469 rettv->vval.v_number = curwin->w_arg_idx;
1470}
1471
1472/*
1473 * "arglistid()" function
1474 */
1475 static void
1476f_arglistid(typval_T *argvars, typval_T *rettv)
1477{
1478 win_T *wp;
1479
1480 rettv->vval.v_number = -1;
1481 wp = find_tabwin(&argvars[0], &argvars[1]);
1482 if (wp != NULL)
1483 rettv->vval.v_number = wp->w_alist->id;
1484}
1485
1486/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001487 * Get the argument list for a given window
1488 */
1489 static void
1490get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1491{
1492 int idx;
1493
1494 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1495 for (idx = 0; idx < argcount; ++idx)
1496 list_append_string(rettv->vval.v_list,
1497 alist_name(&arglist[idx]), -1);
1498}
1499
1500/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 * "argv(nr)" function
1502 */
1503 static void
1504f_argv(typval_T *argvars, typval_T *rettv)
1505{
1506 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001507 aentry_T *arglist = NULL;
1508 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001509
1510 if (argvars[0].v_type != VAR_UNKNOWN)
1511 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001512 if (argvars[1].v_type == VAR_UNKNOWN)
1513 {
1514 arglist = ARGLIST;
1515 argcount = ARGCOUNT;
1516 }
1517 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001518 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001519 {
1520 arglist = GARGLIST;
1521 argcount = GARGCOUNT;
1522 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001523 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001524 {
1525 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1526
1527 if (wp != NULL)
1528 {
1529 /* Use the argument list of the specified window */
1530 arglist = WARGLIST(wp);
1531 argcount = WARGCOUNT(wp);
1532 }
1533 }
1534
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001536 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001537 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001538 if (arglist != NULL && idx >= 0 && idx < argcount)
1539 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1540 else if (idx == -1)
1541 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001543 else
1544 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001545}
1546
1547/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001548 * "assert_beeps(cmd [, error])" function
1549 */
1550 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001551f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001552{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001553 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001554}
1555
1556/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001557 * "assert_equal(expected, actual[, msg])" function
1558 */
1559 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001560f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001561{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001562 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001563}
1564
1565/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001566 * "assert_equalfile(fname-one, fname-two)" function
1567 */
1568 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001569f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001570{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001571 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001572}
1573
1574/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575 * "assert_notequal(expected, actual[, msg])" function
1576 */
1577 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001578f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001579{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001580 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001581}
1582
1583/*
1584 * "assert_exception(string[, msg])" function
1585 */
1586 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001587f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001588{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001589 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001590}
1591
1592/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001593 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001594 */
1595 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001596f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001598 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001599}
1600
1601/*
1602 * "assert_false(actual[, msg])" function
1603 */
1604 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001605f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001606{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001607 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001608}
1609
1610/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001611 * "assert_inrange(lower, upper[, msg])" function
1612 */
1613 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001614f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001615{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001616 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001617}
1618
1619/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001620 * "assert_match(pattern, actual[, msg])" function
1621 */
1622 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001623f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001625 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001626}
1627
1628/*
1629 * "assert_notmatch(pattern, actual[, msg])" function
1630 */
1631 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001632f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001633{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001634 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635}
1636
1637/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001638 * "assert_report(msg)" function
1639 */
1640 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001641f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001642{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001643 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001644}
1645
1646/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001647 * "assert_true(actual[, msg])" function
1648 */
1649 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001650f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001652 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001653}
1654
1655#ifdef FEAT_FLOAT
1656/*
1657 * "asin()" function
1658 */
1659 static void
1660f_asin(typval_T *argvars, typval_T *rettv)
1661{
1662 float_T f = 0.0;
1663
1664 rettv->v_type = VAR_FLOAT;
1665 if (get_float_arg(argvars, &f) == OK)
1666 rettv->vval.v_float = asin(f);
1667 else
1668 rettv->vval.v_float = 0.0;
1669}
1670
1671/*
1672 * "atan()" function
1673 */
1674 static void
1675f_atan(typval_T *argvars, typval_T *rettv)
1676{
1677 float_T f = 0.0;
1678
1679 rettv->v_type = VAR_FLOAT;
1680 if (get_float_arg(argvars, &f) == OK)
1681 rettv->vval.v_float = atan(f);
1682 else
1683 rettv->vval.v_float = 0.0;
1684}
1685
1686/*
1687 * "atan2()" function
1688 */
1689 static void
1690f_atan2(typval_T *argvars, typval_T *rettv)
1691{
1692 float_T fx = 0.0, fy = 0.0;
1693
1694 rettv->v_type = VAR_FLOAT;
1695 if (get_float_arg(argvars, &fx) == OK
1696 && get_float_arg(&argvars[1], &fy) == OK)
1697 rettv->vval.v_float = atan2(fx, fy);
1698 else
1699 rettv->vval.v_float = 0.0;
1700}
1701#endif
1702
1703/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001704 * "balloon_show()" function
1705 */
1706#ifdef FEAT_BEVAL
1707 static void
1708f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1709{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001710 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001711 {
1712 if (argvars[0].v_type == VAR_LIST
1713# ifdef FEAT_GUI
1714 && !gui.in_use
1715# endif
1716 )
1717 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1718 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001719 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001720 }
1721}
1722
Bram Moolenaar669a8282017-11-19 20:13:05 +01001723# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001724 static void
1725f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1726{
1727 if (rettv_list_alloc(rettv) == OK)
1728 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001729 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001730
1731 if (msg != NULL)
1732 {
1733 pumitem_T *array;
1734 int size = split_message(msg, &array);
1735 int i;
1736
1737 /* Skip the first and last item, they are always empty. */
1738 for (i = 1; i < size - 1; ++i)
1739 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001740 while (size > 0)
1741 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001742 vim_free(array);
1743 }
1744 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001745}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001746# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001747#endif
1748
1749/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001750 * "browse(save, title, initdir, default)" function
1751 */
1752 static void
1753f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1754{
1755#ifdef FEAT_BROWSE
1756 int save;
1757 char_u *title;
1758 char_u *initdir;
1759 char_u *defname;
1760 char_u buf[NUMBUFLEN];
1761 char_u buf2[NUMBUFLEN];
1762 int error = FALSE;
1763
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001764 save = (int)tv_get_number_chk(&argvars[0], &error);
1765 title = tv_get_string_chk(&argvars[1]);
1766 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1767 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001768
1769 if (error || title == NULL || initdir == NULL || defname == NULL)
1770 rettv->vval.v_string = NULL;
1771 else
1772 rettv->vval.v_string =
1773 do_browse(save ? BROWSE_SAVE : 0,
1774 title, defname, NULL, initdir, NULL, curbuf);
1775#else
1776 rettv->vval.v_string = NULL;
1777#endif
1778 rettv->v_type = VAR_STRING;
1779}
1780
1781/*
1782 * "browsedir(title, initdir)" function
1783 */
1784 static void
1785f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1786{
1787#ifdef FEAT_BROWSE
1788 char_u *title;
1789 char_u *initdir;
1790 char_u buf[NUMBUFLEN];
1791
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001792 title = tv_get_string_chk(&argvars[0]);
1793 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001794
1795 if (title == NULL || initdir == NULL)
1796 rettv->vval.v_string = NULL;
1797 else
1798 rettv->vval.v_string = do_browse(BROWSE_DIR,
1799 title, NULL, NULL, initdir, NULL, curbuf);
1800#else
1801 rettv->vval.v_string = NULL;
1802#endif
1803 rettv->v_type = VAR_STRING;
1804}
1805
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001806/*
1807 * Find a buffer by number or exact name.
1808 */
1809 static buf_T *
1810find_buffer(typval_T *avar)
1811{
1812 buf_T *buf = NULL;
1813
1814 if (avar->v_type == VAR_NUMBER)
1815 buf = buflist_findnr((int)avar->vval.v_number);
1816 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1817 {
1818 buf = buflist_findname_exp(avar->vval.v_string);
1819 if (buf == NULL)
1820 {
1821 /* No full path name match, try a match with a URL or a "nofile"
1822 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001823 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001824 if (buf->b_fname != NULL
1825 && (path_with_url(buf->b_fname)
1826#ifdef FEAT_QUICKFIX
1827 || bt_nofile(buf)
1828#endif
1829 )
1830 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1831 break;
1832 }
1833 }
1834 return buf;
1835}
1836
1837/*
1838 * "bufexists(expr)" function
1839 */
1840 static void
1841f_bufexists(typval_T *argvars, typval_T *rettv)
1842{
1843 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1844}
1845
1846/*
1847 * "buflisted(expr)" function
1848 */
1849 static void
1850f_buflisted(typval_T *argvars, typval_T *rettv)
1851{
1852 buf_T *buf;
1853
1854 buf = find_buffer(&argvars[0]);
1855 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1856}
1857
1858/*
1859 * "bufloaded(expr)" function
1860 */
1861 static void
1862f_bufloaded(typval_T *argvars, typval_T *rettv)
1863{
1864 buf_T *buf;
1865
1866 buf = find_buffer(&argvars[0]);
1867 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1868}
1869
1870 buf_T *
1871buflist_find_by_name(char_u *name, int curtab_only)
1872{
1873 int save_magic;
1874 char_u *save_cpo;
1875 buf_T *buf;
1876
1877 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1878 save_magic = p_magic;
1879 p_magic = TRUE;
1880 save_cpo = p_cpo;
1881 p_cpo = (char_u *)"";
1882
1883 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1884 TRUE, FALSE, curtab_only));
1885
1886 p_magic = save_magic;
1887 p_cpo = save_cpo;
1888 return buf;
1889}
1890
1891/*
1892 * Get buffer by number or pattern.
1893 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001894 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001895get_buf_tv(typval_T *tv, int curtab_only)
1896{
1897 char_u *name = tv->vval.v_string;
1898 buf_T *buf;
1899
1900 if (tv->v_type == VAR_NUMBER)
1901 return buflist_findnr((int)tv->vval.v_number);
1902 if (tv->v_type != VAR_STRING)
1903 return NULL;
1904 if (name == NULL || *name == NUL)
1905 return curbuf;
1906 if (name[0] == '$' && name[1] == NUL)
1907 return lastbuf;
1908
1909 buf = buflist_find_by_name(name, curtab_only);
1910
1911 /* If not found, try expanding the name, like done for bufexists(). */
1912 if (buf == NULL)
1913 buf = find_buffer(tv);
1914
1915 return buf;
1916}
1917
1918/*
1919 * "bufname(expr)" function
1920 */
1921 static void
1922f_bufname(typval_T *argvars, typval_T *rettv)
1923{
1924 buf_T *buf;
1925
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001926 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927 ++emsg_off;
1928 buf = get_buf_tv(&argvars[0], FALSE);
1929 rettv->v_type = VAR_STRING;
1930 if (buf != NULL && buf->b_fname != NULL)
1931 rettv->vval.v_string = vim_strsave(buf->b_fname);
1932 else
1933 rettv->vval.v_string = NULL;
1934 --emsg_off;
1935}
1936
1937/*
1938 * "bufnr(expr)" function
1939 */
1940 static void
1941f_bufnr(typval_T *argvars, typval_T *rettv)
1942{
1943 buf_T *buf;
1944 int error = FALSE;
1945 char_u *name;
1946
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001947 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001948 ++emsg_off;
1949 buf = get_buf_tv(&argvars[0], FALSE);
1950 --emsg_off;
1951
1952 /* If the buffer isn't found and the second argument is not zero create a
1953 * new buffer. */
1954 if (buf == NULL
1955 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001956 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001958 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001959 && !error)
1960 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1961
1962 if (buf != NULL)
1963 rettv->vval.v_number = buf->b_fnum;
1964 else
1965 rettv->vval.v_number = -1;
1966}
1967
1968 static void
1969buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1970{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001971 win_T *wp;
1972 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001973 buf_T *buf;
1974
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001975 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 ++emsg_off;
1977 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001978 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979 {
1980 ++winnr;
1981 if (wp->w_buffer == buf)
1982 break;
1983 }
1984 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985 --emsg_off;
1986}
1987
1988/*
1989 * "bufwinid(nr)" function
1990 */
1991 static void
1992f_bufwinid(typval_T *argvars, typval_T *rettv)
1993{
1994 buf_win_common(argvars, rettv, FALSE);
1995}
1996
1997/*
1998 * "bufwinnr(nr)" function
1999 */
2000 static void
2001f_bufwinnr(typval_T *argvars, typval_T *rettv)
2002{
2003 buf_win_common(argvars, rettv, TRUE);
2004}
2005
2006/*
2007 * "byte2line(byte)" function
2008 */
2009 static void
2010f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2011{
2012#ifndef FEAT_BYTEOFF
2013 rettv->vval.v_number = -1;
2014#else
2015 long boff = 0;
2016
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002017 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002018 if (boff < 0)
2019 rettv->vval.v_number = -1;
2020 else
2021 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2022 (linenr_T)0, &boff);
2023#endif
2024}
2025
2026 static void
2027byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2028{
2029#ifdef FEAT_MBYTE
2030 char_u *t;
2031#endif
2032 char_u *str;
2033 varnumber_T idx;
2034
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002035 str = tv_get_string_chk(&argvars[0]);
2036 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002037 rettv->vval.v_number = -1;
2038 if (str == NULL || idx < 0)
2039 return;
2040
2041#ifdef FEAT_MBYTE
2042 t = str;
2043 for ( ; idx > 0; idx--)
2044 {
2045 if (*t == NUL) /* EOL reached */
2046 return;
2047 if (enc_utf8 && comp)
2048 t += utf_ptr2len(t);
2049 else
2050 t += (*mb_ptr2len)(t);
2051 }
2052 rettv->vval.v_number = (varnumber_T)(t - str);
2053#else
2054 if ((size_t)idx <= STRLEN(str))
2055 rettv->vval.v_number = idx;
2056#endif
2057}
2058
2059/*
2060 * "byteidx()" function
2061 */
2062 static void
2063f_byteidx(typval_T *argvars, typval_T *rettv)
2064{
2065 byteidx(argvars, rettv, FALSE);
2066}
2067
2068/*
2069 * "byteidxcomp()" function
2070 */
2071 static void
2072f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2073{
2074 byteidx(argvars, rettv, TRUE);
2075}
2076
2077/*
2078 * "call(func, arglist [, dict])" function
2079 */
2080 static void
2081f_call(typval_T *argvars, typval_T *rettv)
2082{
2083 char_u *func;
2084 partial_T *partial = NULL;
2085 dict_T *selfdict = NULL;
2086
2087 if (argvars[1].v_type != VAR_LIST)
2088 {
2089 EMSG(_(e_listreq));
2090 return;
2091 }
2092 if (argvars[1].vval.v_list == NULL)
2093 return;
2094
2095 if (argvars[0].v_type == VAR_FUNC)
2096 func = argvars[0].vval.v_string;
2097 else if (argvars[0].v_type == VAR_PARTIAL)
2098 {
2099 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002100 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002101 }
2102 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002103 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002104 if (*func == NUL)
2105 return; /* type error or empty name */
2106
2107 if (argvars[2].v_type != VAR_UNKNOWN)
2108 {
2109 if (argvars[2].v_type != VAR_DICT)
2110 {
2111 EMSG(_(e_dictreq));
2112 return;
2113 }
2114 selfdict = argvars[2].vval.v_dict;
2115 }
2116
2117 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2118}
2119
2120#ifdef FEAT_FLOAT
2121/*
2122 * "ceil({float})" function
2123 */
2124 static void
2125f_ceil(typval_T *argvars, typval_T *rettv)
2126{
2127 float_T f = 0.0;
2128
2129 rettv->v_type = VAR_FLOAT;
2130 if (get_float_arg(argvars, &f) == OK)
2131 rettv->vval.v_float = ceil(f);
2132 else
2133 rettv->vval.v_float = 0.0;
2134}
2135#endif
2136
2137#ifdef FEAT_JOB_CHANNEL
2138/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002139 * "ch_canread()" function
2140 */
2141 static void
2142f_ch_canread(typval_T *argvars, typval_T *rettv)
2143{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002144 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002145
2146 rettv->vval.v_number = 0;
2147 if (channel != NULL)
2148 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2149 || channel_has_readahead(channel, PART_OUT)
2150 || channel_has_readahead(channel, PART_ERR);
2151}
2152
2153/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 * "ch_close()" function
2155 */
2156 static void
2157f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2158{
2159 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2160
2161 if (channel != NULL)
2162 {
2163 channel_close(channel, FALSE);
2164 channel_clear(channel);
2165 }
2166}
2167
2168/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002169 * "ch_close()" function
2170 */
2171 static void
2172f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2173{
2174 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2175
2176 if (channel != NULL)
2177 channel_close_in(channel);
2178}
2179
2180/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002181 * "ch_getbufnr()" function
2182 */
2183 static void
2184f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2185{
2186 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2187
2188 rettv->vval.v_number = -1;
2189 if (channel != NULL)
2190 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002191 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 int part;
2193
2194 if (STRCMP(what, "err") == 0)
2195 part = PART_ERR;
2196 else if (STRCMP(what, "out") == 0)
2197 part = PART_OUT;
2198 else if (STRCMP(what, "in") == 0)
2199 part = PART_IN;
2200 else
2201 part = PART_SOCK;
2202 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2203 rettv->vval.v_number =
2204 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2205 }
2206}
2207
2208/*
2209 * "ch_getjob()" function
2210 */
2211 static void
2212f_ch_getjob(typval_T *argvars, typval_T *rettv)
2213{
2214 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2215
2216 if (channel != NULL)
2217 {
2218 rettv->v_type = VAR_JOB;
2219 rettv->vval.v_job = channel->ch_job;
2220 if (channel->ch_job != NULL)
2221 ++channel->ch_job->jv_refcount;
2222 }
2223}
2224
2225/*
2226 * "ch_info()" function
2227 */
2228 static void
2229f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2230{
2231 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2232
2233 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2234 channel_info(channel, rettv->vval.v_dict);
2235}
2236
2237/*
2238 * "ch_log()" function
2239 */
2240 static void
2241f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2242{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002243 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002244 channel_T *channel = NULL;
2245
2246 if (argvars[1].v_type != VAR_UNKNOWN)
2247 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2248
Bram Moolenaard5359b22018-04-05 22:44:39 +02002249 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002250}
2251
2252/*
2253 * "ch_logfile()" function
2254 */
2255 static void
2256f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2257{
2258 char_u *fname;
2259 char_u *opt = (char_u *)"";
2260 char_u buf[NUMBUFLEN];
2261
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002262 /* Don't open a file in restricted mode. */
2263 if (check_restricted() || check_secure())
2264 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002265 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002267 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 ch_logfile(fname, opt);
2269}
2270
2271/*
2272 * "ch_open()" function
2273 */
2274 static void
2275f_ch_open(typval_T *argvars, typval_T *rettv)
2276{
2277 rettv->v_type = VAR_CHANNEL;
2278 if (check_restricted() || check_secure())
2279 return;
2280 rettv->vval.v_channel = channel_open_func(argvars);
2281}
2282
2283/*
2284 * "ch_read()" function
2285 */
2286 static void
2287f_ch_read(typval_T *argvars, typval_T *rettv)
2288{
2289 common_channel_read(argvars, rettv, FALSE);
2290}
2291
2292/*
2293 * "ch_readraw()" function
2294 */
2295 static void
2296f_ch_readraw(typval_T *argvars, typval_T *rettv)
2297{
2298 common_channel_read(argvars, rettv, TRUE);
2299}
2300
2301/*
2302 * "ch_evalexpr()" function
2303 */
2304 static void
2305f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2306{
2307 ch_expr_common(argvars, rettv, TRUE);
2308}
2309
2310/*
2311 * "ch_sendexpr()" function
2312 */
2313 static void
2314f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2315{
2316 ch_expr_common(argvars, rettv, FALSE);
2317}
2318
2319/*
2320 * "ch_evalraw()" function
2321 */
2322 static void
2323f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2324{
2325 ch_raw_common(argvars, rettv, TRUE);
2326}
2327
2328/*
2329 * "ch_sendraw()" function
2330 */
2331 static void
2332f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2333{
2334 ch_raw_common(argvars, rettv, FALSE);
2335}
2336
2337/*
2338 * "ch_setoptions()" function
2339 */
2340 static void
2341f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2342{
2343 channel_T *channel;
2344 jobopt_T opt;
2345
2346 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2347 if (channel == NULL)
2348 return;
2349 clear_job_options(&opt);
2350 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002351 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002352 channel_set_options(channel, &opt);
2353 free_job_options(&opt);
2354}
2355
2356/*
2357 * "ch_status()" function
2358 */
2359 static void
2360f_ch_status(typval_T *argvars, typval_T *rettv)
2361{
2362 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002363 jobopt_T opt;
2364 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365
2366 /* return an empty string by default */
2367 rettv->v_type = VAR_STRING;
2368 rettv->vval.v_string = NULL;
2369
2370 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002371
2372 if (argvars[1].v_type != VAR_UNKNOWN)
2373 {
2374 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002375 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002376 && (opt.jo_set & JO_PART))
2377 part = opt.jo_part;
2378 }
2379
2380 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002381}
2382#endif
2383
2384/*
2385 * "changenr()" function
2386 */
2387 static void
2388f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2389{
2390 rettv->vval.v_number = curbuf->b_u_seq_cur;
2391}
2392
2393/*
2394 * "char2nr(string)" function
2395 */
2396 static void
2397f_char2nr(typval_T *argvars, typval_T *rettv)
2398{
2399#ifdef FEAT_MBYTE
2400 if (has_mbyte)
2401 {
2402 int utf8 = 0;
2403
2404 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002405 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002406
2407 if (utf8)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002408 rettv->vval.v_number = (*utf_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002409 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002410 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002411 }
2412 else
2413#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002414 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002415}
2416
2417/*
2418 * "cindent(lnum)" function
2419 */
2420 static void
2421f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2422{
2423#ifdef FEAT_CINDENT
2424 pos_T pos;
2425 linenr_T lnum;
2426
2427 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002428 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002429 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2430 {
2431 curwin->w_cursor.lnum = lnum;
2432 rettv->vval.v_number = get_c_indent();
2433 curwin->w_cursor = pos;
2434 }
2435 else
2436#endif
2437 rettv->vval.v_number = -1;
2438}
2439
2440/*
2441 * "clearmatches()" function
2442 */
2443 static void
2444f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2445{
2446#ifdef FEAT_SEARCH_EXTRA
2447 clear_matches(curwin);
2448#endif
2449}
2450
2451/*
2452 * "col(string)" function
2453 */
2454 static void
2455f_col(typval_T *argvars, typval_T *rettv)
2456{
2457 colnr_T col = 0;
2458 pos_T *fp;
2459 int fnum = curbuf->b_fnum;
2460
2461 fp = var2fpos(&argvars[0], FALSE, &fnum);
2462 if (fp != NULL && fnum == curbuf->b_fnum)
2463 {
2464 if (fp->col == MAXCOL)
2465 {
2466 /* '> can be MAXCOL, get the length of the line then */
2467 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2468 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2469 else
2470 col = MAXCOL;
2471 }
2472 else
2473 {
2474 col = fp->col + 1;
2475#ifdef FEAT_VIRTUALEDIT
2476 /* col(".") when the cursor is on the NUL at the end of the line
2477 * because of "coladd" can be seen as an extra column. */
2478 if (virtual_active() && fp == &curwin->w_cursor)
2479 {
2480 char_u *p = ml_get_cursor();
2481
2482 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2483 curwin->w_virtcol - curwin->w_cursor.coladd))
2484 {
2485# ifdef FEAT_MBYTE
2486 int l;
2487
2488 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2489 col += l;
2490# else
2491 if (*p != NUL && p[1] == NUL)
2492 ++col;
2493# endif
2494 }
2495 }
2496#endif
2497 }
2498 }
2499 rettv->vval.v_number = col;
2500}
2501
2502#if defined(FEAT_INS_EXPAND)
2503/*
2504 * "complete()" function
2505 */
2506 static void
2507f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2508{
2509 int startcol;
2510
2511 if ((State & INSERT) == 0)
2512 {
2513 EMSG(_("E785: complete() can only be used in Insert mode"));
2514 return;
2515 }
2516
2517 /* Check for undo allowed here, because if something was already inserted
2518 * the line was already saved for undo and this check isn't done. */
2519 if (!undo_allowed())
2520 return;
2521
2522 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2523 {
2524 EMSG(_(e_invarg));
2525 return;
2526 }
2527
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002528 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002529 if (startcol <= 0)
2530 return;
2531
2532 set_completion(startcol - 1, argvars[1].vval.v_list);
2533}
2534
2535/*
2536 * "complete_add()" function
2537 */
2538 static void
2539f_complete_add(typval_T *argvars, typval_T *rettv)
2540{
2541 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2542}
2543
2544/*
2545 * "complete_check()" function
2546 */
2547 static void
2548f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2549{
2550 int saved = RedrawingDisabled;
2551
2552 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002553 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 rettv->vval.v_number = compl_interrupted;
2555 RedrawingDisabled = saved;
2556}
2557#endif
2558
2559/*
2560 * "confirm(message, buttons[, default [, type]])" function
2561 */
2562 static void
2563f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2564{
2565#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2566 char_u *message;
2567 char_u *buttons = NULL;
2568 char_u buf[NUMBUFLEN];
2569 char_u buf2[NUMBUFLEN];
2570 int def = 1;
2571 int type = VIM_GENERIC;
2572 char_u *typestr;
2573 int error = FALSE;
2574
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002575 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002576 if (message == NULL)
2577 error = TRUE;
2578 if (argvars[1].v_type != VAR_UNKNOWN)
2579 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002580 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002581 if (buttons == NULL)
2582 error = TRUE;
2583 if (argvars[2].v_type != VAR_UNKNOWN)
2584 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002585 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002586 if (argvars[3].v_type != VAR_UNKNOWN)
2587 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002588 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002589 if (typestr == NULL)
2590 error = TRUE;
2591 else
2592 {
2593 switch (TOUPPER_ASC(*typestr))
2594 {
2595 case 'E': type = VIM_ERROR; break;
2596 case 'Q': type = VIM_QUESTION; break;
2597 case 'I': type = VIM_INFO; break;
2598 case 'W': type = VIM_WARNING; break;
2599 case 'G': type = VIM_GENERIC; break;
2600 }
2601 }
2602 }
2603 }
2604 }
2605
2606 if (buttons == NULL || *buttons == NUL)
2607 buttons = (char_u *)_("&Ok");
2608
2609 if (!error)
2610 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2611 def, NULL, FALSE);
2612#endif
2613}
2614
2615/*
2616 * "copy()" function
2617 */
2618 static void
2619f_copy(typval_T *argvars, typval_T *rettv)
2620{
2621 item_copy(&argvars[0], rettv, FALSE, 0);
2622}
2623
2624#ifdef FEAT_FLOAT
2625/*
2626 * "cos()" function
2627 */
2628 static void
2629f_cos(typval_T *argvars, typval_T *rettv)
2630{
2631 float_T f = 0.0;
2632
2633 rettv->v_type = VAR_FLOAT;
2634 if (get_float_arg(argvars, &f) == OK)
2635 rettv->vval.v_float = cos(f);
2636 else
2637 rettv->vval.v_float = 0.0;
2638}
2639
2640/*
2641 * "cosh()" function
2642 */
2643 static void
2644f_cosh(typval_T *argvars, typval_T *rettv)
2645{
2646 float_T f = 0.0;
2647
2648 rettv->v_type = VAR_FLOAT;
2649 if (get_float_arg(argvars, &f) == OK)
2650 rettv->vval.v_float = cosh(f);
2651 else
2652 rettv->vval.v_float = 0.0;
2653}
2654#endif
2655
2656/*
2657 * "count()" function
2658 */
2659 static void
2660f_count(typval_T *argvars, typval_T *rettv)
2661{
2662 long n = 0;
2663 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002664 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002665
Bram Moolenaar9966b212017-07-28 16:46:57 +02002666 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002667 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002668
2669 if (argvars[0].v_type == VAR_STRING)
2670 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002671 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002672 char_u *p = argvars[0].vval.v_string;
2673 char_u *next;
2674
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002675 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002676 {
2677 if (ic)
2678 {
2679 size_t len = STRLEN(expr);
2680
2681 while (*p != NUL)
2682 {
2683 if (MB_STRNICMP(p, expr, len) == 0)
2684 {
2685 ++n;
2686 p += len;
2687 }
2688 else
2689 MB_PTR_ADV(p);
2690 }
2691 }
2692 else
2693 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2694 != NULL)
2695 {
2696 ++n;
2697 p = next + STRLEN(expr);
2698 }
2699 }
2700
2701 }
2702 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703 {
2704 listitem_T *li;
2705 list_T *l;
2706 long idx;
2707
2708 if ((l = argvars[0].vval.v_list) != NULL)
2709 {
2710 li = l->lv_first;
2711 if (argvars[2].v_type != VAR_UNKNOWN)
2712 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 if (argvars[3].v_type != VAR_UNKNOWN)
2714 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002715 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002716 if (!error)
2717 {
2718 li = list_find(l, idx);
2719 if (li == NULL)
2720 EMSGN(_(e_listidx), idx);
2721 }
2722 }
2723 if (error)
2724 li = NULL;
2725 }
2726
2727 for ( ; li != NULL; li = li->li_next)
2728 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2729 ++n;
2730 }
2731 }
2732 else if (argvars[0].v_type == VAR_DICT)
2733 {
2734 int todo;
2735 dict_T *d;
2736 hashitem_T *hi;
2737
2738 if ((d = argvars[0].vval.v_dict) != NULL)
2739 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002740 if (argvars[2].v_type != VAR_UNKNOWN)
2741 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002742 if (argvars[3].v_type != VAR_UNKNOWN)
2743 EMSG(_(e_invarg));
2744 }
2745
2746 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2747 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2748 {
2749 if (!HASHITEM_EMPTY(hi))
2750 {
2751 --todo;
2752 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2753 ++n;
2754 }
2755 }
2756 }
2757 }
2758 else
2759 EMSG2(_(e_listdictarg), "count()");
2760 rettv->vval.v_number = n;
2761}
2762
2763/*
2764 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2765 *
2766 * Checks the existence of a cscope connection.
2767 */
2768 static void
2769f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2770{
2771#ifdef FEAT_CSCOPE
2772 int num = 0;
2773 char_u *dbpath = NULL;
2774 char_u *prepend = NULL;
2775 char_u buf[NUMBUFLEN];
2776
2777 if (argvars[0].v_type != VAR_UNKNOWN
2778 && argvars[1].v_type != VAR_UNKNOWN)
2779 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002780 num = (int)tv_get_number(&argvars[0]);
2781 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002782 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002783 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002784 }
2785
2786 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2787#endif
2788}
2789
2790/*
2791 * "cursor(lnum, col)" function, or
2792 * "cursor(list)"
2793 *
2794 * Moves the cursor to the specified line and column.
2795 * Returns 0 when the position could be set, -1 otherwise.
2796 */
2797 static void
2798f_cursor(typval_T *argvars, typval_T *rettv)
2799{
2800 long line, col;
2801#ifdef FEAT_VIRTUALEDIT
2802 long coladd = 0;
2803#endif
2804 int set_curswant = TRUE;
2805
2806 rettv->vval.v_number = -1;
2807 if (argvars[1].v_type == VAR_UNKNOWN)
2808 {
2809 pos_T pos;
2810 colnr_T curswant = -1;
2811
2812 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2813 {
2814 EMSG(_(e_invarg));
2815 return;
2816 }
2817 line = pos.lnum;
2818 col = pos.col;
2819#ifdef FEAT_VIRTUALEDIT
2820 coladd = pos.coladd;
2821#endif
2822 if (curswant >= 0)
2823 {
2824 curwin->w_curswant = curswant - 1;
2825 set_curswant = FALSE;
2826 }
2827 }
2828 else
2829 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002830 line = tv_get_lnum(argvars);
2831 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002832#ifdef FEAT_VIRTUALEDIT
2833 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002834 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002835#endif
2836 }
2837 if (line < 0 || col < 0
2838#ifdef FEAT_VIRTUALEDIT
2839 || coladd < 0
2840#endif
2841 )
2842 return; /* type error; errmsg already given */
2843 if (line > 0)
2844 curwin->w_cursor.lnum = line;
2845 if (col > 0)
2846 curwin->w_cursor.col = col - 1;
2847#ifdef FEAT_VIRTUALEDIT
2848 curwin->w_cursor.coladd = coladd;
2849#endif
2850
2851 /* Make sure the cursor is in a valid position. */
2852 check_cursor();
2853#ifdef FEAT_MBYTE
2854 /* Correct cursor for multi-byte character. */
2855 if (has_mbyte)
2856 mb_adjust_cursor();
2857#endif
2858
2859 curwin->w_set_curswant = set_curswant;
2860 rettv->vval.v_number = 0;
2861}
2862
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002863#ifdef WIN3264
2864/*
2865 * "debugbreak()" function
2866 */
2867 static void
2868f_debugbreak(typval_T *argvars, typval_T *rettv)
2869{
2870 int pid;
2871
2872 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002873 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002874 if (pid == 0)
2875 EMSG(_(e_invarg));
2876 else
2877 {
2878 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2879
2880 if (hProcess != NULL)
2881 {
2882 DebugBreakProcess(hProcess);
2883 CloseHandle(hProcess);
2884 rettv->vval.v_number = OK;
2885 }
2886 }
2887}
2888#endif
2889
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002890/*
2891 * "deepcopy()" function
2892 */
2893 static void
2894f_deepcopy(typval_T *argvars, typval_T *rettv)
2895{
2896 int noref = 0;
2897 int copyID;
2898
2899 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002900 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002901 if (noref < 0 || noref > 1)
2902 EMSG(_(e_invarg));
2903 else
2904 {
2905 copyID = get_copyID();
2906 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2907 }
2908}
2909
2910/*
2911 * "delete()" function
2912 */
2913 static void
2914f_delete(typval_T *argvars, typval_T *rettv)
2915{
2916 char_u nbuf[NUMBUFLEN];
2917 char_u *name;
2918 char_u *flags;
2919
2920 rettv->vval.v_number = -1;
2921 if (check_restricted() || check_secure())
2922 return;
2923
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002924 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002925 if (name == NULL || *name == NUL)
2926 {
2927 EMSG(_(e_invarg));
2928 return;
2929 }
2930
2931 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002932 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933 else
2934 flags = (char_u *)"";
2935
2936 if (*flags == NUL)
2937 /* delete a file */
2938 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2939 else if (STRCMP(flags, "d") == 0)
2940 /* delete an empty directory */
2941 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2942 else if (STRCMP(flags, "rf") == 0)
2943 /* delete a directory recursively */
2944 rettv->vval.v_number = delete_recursive(name);
2945 else
2946 EMSG2(_(e_invexpr2), flags);
2947}
2948
2949/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002950 * "deletebufline()" function
2951 */
2952 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002953f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002954{
2955 buf_T *buf;
2956 linenr_T first, last;
2957 linenr_T lnum;
2958 long count;
2959 int is_curbuf;
2960 buf_T *curbuf_save = NULL;
2961 win_T *curwin_save = NULL;
2962 tabpage_T *tp;
2963 win_T *wp;
2964
2965 buf = get_buf_tv(&argvars[0], FALSE);
2966 if (buf == NULL)
2967 {
2968 rettv->vval.v_number = 1; /* FAIL */
2969 return;
2970 }
2971 is_curbuf = buf == curbuf;
2972
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002973 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002974 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002975 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002976 else
2977 last = first;
2978
2979 if (buf->b_ml.ml_mfp == NULL || first < 1
2980 || first > buf->b_ml.ml_line_count || last < first)
2981 {
2982 rettv->vval.v_number = 1; /* FAIL */
2983 return;
2984 }
2985
2986 if (!is_curbuf)
2987 {
2988 curbuf_save = curbuf;
2989 curwin_save = curwin;
2990 curbuf = buf;
2991 find_win_for_curbuf();
2992 }
2993 if (last > curbuf->b_ml.ml_line_count)
2994 last = curbuf->b_ml.ml_line_count;
2995 count = last - first + 1;
2996
2997 // When coming here from Insert mode, sync undo, so that this can be
2998 // undone separately from what was previously inserted.
2999 if (u_sync_once == 2)
3000 {
3001 u_sync_once = 1; // notify that u_sync() was called
3002 u_sync(TRUE);
3003 }
3004
3005 if (u_save(first - 1, last + 1) == FAIL)
3006 {
3007 rettv->vval.v_number = 1; /* FAIL */
3008 return;
3009 }
3010
3011 for (lnum = first; lnum <= last; ++lnum)
3012 ml_delete(first, TRUE);
3013
3014 FOR_ALL_TAB_WINDOWS(tp, wp)
3015 if (wp->w_buffer == buf)
3016 {
3017 if (wp->w_cursor.lnum > last)
3018 wp->w_cursor.lnum -= count;
3019 else if (wp->w_cursor.lnum> first)
3020 wp->w_cursor.lnum = first;
3021 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3022 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3023 }
3024 check_cursor_col();
3025 deleted_lines_mark(first, count);
3026
3027 if (!is_curbuf)
3028 {
3029 curbuf = curbuf_save;
3030 curwin = curwin_save;
3031 }
3032}
3033
3034/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003035 * "did_filetype()" function
3036 */
3037 static void
3038f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3039{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003040 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003041}
3042
3043/*
3044 * "diff_filler()" function
3045 */
3046 static void
3047f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3048{
3049#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003050 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003051#endif
3052}
3053
3054/*
3055 * "diff_hlID()" function
3056 */
3057 static void
3058f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3059{
3060#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003061 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003063 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003064 static int fnum = 0;
3065 static int change_start = 0;
3066 static int change_end = 0;
3067 static hlf_T hlID = (hlf_T)0;
3068 int filler_lines;
3069 int col;
3070
3071 if (lnum < 0) /* ignore type error in {lnum} arg */
3072 lnum = 0;
3073 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003074 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 || fnum != curbuf->b_fnum)
3076 {
3077 /* New line, buffer, change: need to get the values. */
3078 filler_lines = diff_check(curwin, lnum);
3079 if (filler_lines < 0)
3080 {
3081 if (filler_lines == -1)
3082 {
3083 change_start = MAXCOL;
3084 change_end = -1;
3085 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3086 hlID = HLF_ADD; /* added line */
3087 else
3088 hlID = HLF_CHD; /* changed line */
3089 }
3090 else
3091 hlID = HLF_ADD; /* added line */
3092 }
3093 else
3094 hlID = (hlf_T)0;
3095 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003096 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003097 fnum = curbuf->b_fnum;
3098 }
3099
3100 if (hlID == HLF_CHD || hlID == HLF_TXD)
3101 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003102 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003103 if (col >= change_start && col <= change_end)
3104 hlID = HLF_TXD; /* changed text */
3105 else
3106 hlID = HLF_CHD; /* changed line */
3107 }
3108 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3109#endif
3110}
3111
3112/*
3113 * "empty({expr})" function
3114 */
3115 static void
3116f_empty(typval_T *argvars, typval_T *rettv)
3117{
3118 int n = FALSE;
3119
3120 switch (argvars[0].v_type)
3121 {
3122 case VAR_STRING:
3123 case VAR_FUNC:
3124 n = argvars[0].vval.v_string == NULL
3125 || *argvars[0].vval.v_string == NUL;
3126 break;
3127 case VAR_PARTIAL:
3128 n = FALSE;
3129 break;
3130 case VAR_NUMBER:
3131 n = argvars[0].vval.v_number == 0;
3132 break;
3133 case VAR_FLOAT:
3134#ifdef FEAT_FLOAT
3135 n = argvars[0].vval.v_float == 0.0;
3136 break;
3137#endif
3138 case VAR_LIST:
3139 n = argvars[0].vval.v_list == NULL
3140 || argvars[0].vval.v_list->lv_first == NULL;
3141 break;
3142 case VAR_DICT:
3143 n = argvars[0].vval.v_dict == NULL
3144 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3145 break;
3146 case VAR_SPECIAL:
3147 n = argvars[0].vval.v_number != VVAL_TRUE;
3148 break;
3149
3150 case VAR_JOB:
3151#ifdef FEAT_JOB_CHANNEL
3152 n = argvars[0].vval.v_job == NULL
3153 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3154 break;
3155#endif
3156 case VAR_CHANNEL:
3157#ifdef FEAT_JOB_CHANNEL
3158 n = argvars[0].vval.v_channel == NULL
3159 || !channel_is_open(argvars[0].vval.v_channel);
3160 break;
3161#endif
3162 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003163 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003164 n = TRUE;
3165 break;
3166 }
3167
3168 rettv->vval.v_number = n;
3169}
3170
3171/*
3172 * "escape({string}, {chars})" function
3173 */
3174 static void
3175f_escape(typval_T *argvars, typval_T *rettv)
3176{
3177 char_u buf[NUMBUFLEN];
3178
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003179 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3180 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003181 rettv->v_type = VAR_STRING;
3182}
3183
3184/*
3185 * "eval()" function
3186 */
3187 static void
3188f_eval(typval_T *argvars, typval_T *rettv)
3189{
3190 char_u *s, *p;
3191
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003192 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003193 if (s != NULL)
3194 s = skipwhite(s);
3195
3196 p = s;
3197 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3198 {
3199 if (p != NULL && !aborting())
3200 EMSG2(_(e_invexpr2), p);
3201 need_clr_eos = FALSE;
3202 rettv->v_type = VAR_NUMBER;
3203 rettv->vval.v_number = 0;
3204 }
3205 else if (*s != NUL)
3206 EMSG(_(e_trailing));
3207}
3208
3209/*
3210 * "eventhandler()" function
3211 */
3212 static void
3213f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3214{
3215 rettv->vval.v_number = vgetc_busy;
3216}
3217
3218/*
3219 * "executable()" function
3220 */
3221 static void
3222f_executable(typval_T *argvars, typval_T *rettv)
3223{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003224 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003225
3226 /* Check in $PATH and also check directly if there is a directory name. */
3227 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3228 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3229}
3230
3231static garray_T redir_execute_ga;
3232
3233/*
3234 * Append "value[value_len]" to the execute() output.
3235 */
3236 void
3237execute_redir_str(char_u *value, int value_len)
3238{
3239 int len;
3240
3241 if (value_len == -1)
3242 len = (int)STRLEN(value); /* Append the entire string */
3243 else
3244 len = value_len; /* Append only "value_len" characters */
3245 if (ga_grow(&redir_execute_ga, len) == OK)
3246 {
3247 mch_memmove((char *)redir_execute_ga.ga_data
3248 + redir_execute_ga.ga_len, value, len);
3249 redir_execute_ga.ga_len += len;
3250 }
3251}
3252
3253/*
3254 * Get next line from a list.
3255 * Called by do_cmdline() to get the next line.
3256 * Returns allocated string, or NULL for end of function.
3257 */
3258
3259 static char_u *
3260get_list_line(
3261 int c UNUSED,
3262 void *cookie,
3263 int indent UNUSED)
3264{
3265 listitem_T **p = (listitem_T **)cookie;
3266 listitem_T *item = *p;
3267 char_u buf[NUMBUFLEN];
3268 char_u *s;
3269
3270 if (item == NULL)
3271 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003272 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003273 *p = item->li_next;
3274 return s == NULL ? NULL : vim_strsave(s);
3275}
3276
3277/*
3278 * "execute()" function
3279 */
3280 static void
3281f_execute(typval_T *argvars, typval_T *rettv)
3282{
3283 char_u *cmd = NULL;
3284 list_T *list = NULL;
3285 int save_msg_silent = msg_silent;
3286 int save_emsg_silent = emsg_silent;
3287 int save_emsg_noredir = emsg_noredir;
3288 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003289 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003290 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003291 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003292 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003293
3294 rettv->vval.v_string = NULL;
3295 rettv->v_type = VAR_STRING;
3296
3297 if (argvars[0].v_type == VAR_LIST)
3298 {
3299 list = argvars[0].vval.v_list;
3300 if (list == NULL || list->lv_first == NULL)
3301 /* empty list, no commands, empty output */
3302 return;
3303 ++list->lv_refcount;
3304 }
3305 else
3306 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003307 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 if (cmd == NULL)
3309 return;
3310 }
3311
3312 if (argvars[1].v_type != VAR_UNKNOWN)
3313 {
3314 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003315 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316
3317 if (s == NULL)
3318 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003319 if (*s == NUL)
3320 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321 if (STRNCMP(s, "silent", 6) == 0)
3322 ++msg_silent;
3323 if (STRCMP(s, "silent!") == 0)
3324 {
3325 emsg_silent = TRUE;
3326 emsg_noredir = TRUE;
3327 }
3328 }
3329 else
3330 ++msg_silent;
3331
3332 if (redir_execute)
3333 save_ga = redir_execute_ga;
3334 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3335 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003336 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003337 if (!echo_output)
3338 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003339
3340 if (cmd != NULL)
3341 do_cmdline_cmd(cmd);
3342 else
3343 {
3344 listitem_T *item = list->lv_first;
3345
3346 do_cmdline(NULL, get_list_line, (void *)&item,
3347 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3348 --list->lv_refcount;
3349 }
3350
Bram Moolenaard297f352017-01-29 20:31:21 +01003351 /* Need to append a NUL to the result. */
3352 if (ga_grow(&redir_execute_ga, 1) == OK)
3353 {
3354 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3355 rettv->vval.v_string = redir_execute_ga.ga_data;
3356 }
3357 else
3358 {
3359 ga_clear(&redir_execute_ga);
3360 rettv->vval.v_string = NULL;
3361 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003362 msg_silent = save_msg_silent;
3363 emsg_silent = save_emsg_silent;
3364 emsg_noredir = save_emsg_noredir;
3365
3366 redir_execute = save_redir_execute;
3367 if (redir_execute)
3368 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003369 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003370
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003371 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003372 if (echo_output)
3373 // When not working silently: put it in column zero. A following
3374 // "echon" will overwrite the message, unavoidably.
3375 msg_col = 0;
3376 else
3377 // When working silently: Put it back where it was, since nothing
3378 // should have been written.
3379 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380}
3381
3382/*
3383 * "exepath()" function
3384 */
3385 static void
3386f_exepath(typval_T *argvars, typval_T *rettv)
3387{
3388 char_u *p = NULL;
3389
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003390 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 rettv->v_type = VAR_STRING;
3392 rettv->vval.v_string = p;
3393}
3394
3395/*
3396 * "exists()" function
3397 */
3398 static void
3399f_exists(typval_T *argvars, typval_T *rettv)
3400{
3401 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003402 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003404 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003405 if (*p == '$') /* environment variable */
3406 {
3407 /* first try "normal" environment variables (fast) */
3408 if (mch_getenv(p + 1) != NULL)
3409 n = TRUE;
3410 else
3411 {
3412 /* try expanding things like $VIM and ${HOME} */
3413 p = expand_env_save(p);
3414 if (p != NULL && *p != '$')
3415 n = TRUE;
3416 vim_free(p);
3417 }
3418 }
3419 else if (*p == '&' || *p == '+') /* option */
3420 {
3421 n = (get_option_tv(&p, NULL, TRUE) == OK);
3422 if (*skipwhite(p) != NUL)
3423 n = FALSE; /* trailing garbage */
3424 }
3425 else if (*p == '*') /* internal or user defined function */
3426 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003427 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428 }
3429 else if (*p == ':')
3430 {
3431 n = cmd_exists(p + 1);
3432 }
3433 else if (*p == '#')
3434 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435 if (p[1] == '#')
3436 n = autocmd_supported(p + 2);
3437 else
3438 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003439 }
3440 else /* internal variable */
3441 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003442 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003443 }
3444
3445 rettv->vval.v_number = n;
3446}
3447
3448#ifdef FEAT_FLOAT
3449/*
3450 * "exp()" function
3451 */
3452 static void
3453f_exp(typval_T *argvars, typval_T *rettv)
3454{
3455 float_T f = 0.0;
3456
3457 rettv->v_type = VAR_FLOAT;
3458 if (get_float_arg(argvars, &f) == OK)
3459 rettv->vval.v_float = exp(f);
3460 else
3461 rettv->vval.v_float = 0.0;
3462}
3463#endif
3464
3465/*
3466 * "expand()" function
3467 */
3468 static void
3469f_expand(typval_T *argvars, typval_T *rettv)
3470{
3471 char_u *s;
3472 int len;
3473 char_u *errormsg;
3474 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3475 expand_T xpc;
3476 int error = FALSE;
3477 char_u *result;
3478
3479 rettv->v_type = VAR_STRING;
3480 if (argvars[1].v_type != VAR_UNKNOWN
3481 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003482 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 && !error)
3484 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003485 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003486 }
3487
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003488 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003489 if (*s == '%' || *s == '#' || *s == '<')
3490 {
3491 ++emsg_off;
3492 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3493 --emsg_off;
3494 if (rettv->v_type == VAR_LIST)
3495 {
3496 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3497 list_append_string(rettv->vval.v_list, result, -1);
3498 else
3499 vim_free(result);
3500 }
3501 else
3502 rettv->vval.v_string = result;
3503 }
3504 else
3505 {
3506 /* When the optional second argument is non-zero, don't remove matches
3507 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3508 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003509 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003510 options |= WILD_KEEP_ALL;
3511 if (!error)
3512 {
3513 ExpandInit(&xpc);
3514 xpc.xp_context = EXPAND_FILES;
3515 if (p_wic)
3516 options += WILD_ICASE;
3517 if (rettv->v_type == VAR_STRING)
3518 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3519 options, WILD_ALL);
3520 else if (rettv_list_alloc(rettv) != FAIL)
3521 {
3522 int i;
3523
3524 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3525 for (i = 0; i < xpc.xp_numfiles; i++)
3526 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3527 ExpandCleanup(&xpc);
3528 }
3529 }
3530 else
3531 rettv->vval.v_string = NULL;
3532 }
3533}
3534
3535/*
3536 * "extend(list, list [, idx])" function
3537 * "extend(dict, dict [, action])" function
3538 */
3539 static void
3540f_extend(typval_T *argvars, typval_T *rettv)
3541{
3542 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3543
3544 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3545 {
3546 list_T *l1, *l2;
3547 listitem_T *item;
3548 long before;
3549 int error = FALSE;
3550
3551 l1 = argvars[0].vval.v_list;
3552 l2 = argvars[1].vval.v_list;
3553 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3554 && l2 != NULL)
3555 {
3556 if (argvars[2].v_type != VAR_UNKNOWN)
3557 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003558 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003559 if (error)
3560 return; /* type error; errmsg already given */
3561
3562 if (before == l1->lv_len)
3563 item = NULL;
3564 else
3565 {
3566 item = list_find(l1, before);
3567 if (item == NULL)
3568 {
3569 EMSGN(_(e_listidx), before);
3570 return;
3571 }
3572 }
3573 }
3574 else
3575 item = NULL;
3576 list_extend(l1, l2, item);
3577
3578 copy_tv(&argvars[0], rettv);
3579 }
3580 }
3581 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3582 {
3583 dict_T *d1, *d2;
3584 char_u *action;
3585 int i;
3586
3587 d1 = argvars[0].vval.v_dict;
3588 d2 = argvars[1].vval.v_dict;
3589 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3590 && d2 != NULL)
3591 {
3592 /* Check the third argument. */
3593 if (argvars[2].v_type != VAR_UNKNOWN)
3594 {
3595 static char *(av[]) = {"keep", "force", "error"};
3596
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003597 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003598 if (action == NULL)
3599 return; /* type error; errmsg already given */
3600 for (i = 0; i < 3; ++i)
3601 if (STRCMP(action, av[i]) == 0)
3602 break;
3603 if (i == 3)
3604 {
3605 EMSG2(_(e_invarg2), action);
3606 return;
3607 }
3608 }
3609 else
3610 action = (char_u *)"force";
3611
3612 dict_extend(d1, d2, action);
3613
3614 copy_tv(&argvars[0], rettv);
3615 }
3616 }
3617 else
3618 EMSG2(_(e_listdictarg), "extend()");
3619}
3620
3621/*
3622 * "feedkeys()" function
3623 */
3624 static void
3625f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3626{
3627 int remap = TRUE;
3628 int insert = FALSE;
3629 char_u *keys, *flags;
3630 char_u nbuf[NUMBUFLEN];
3631 int typed = FALSE;
3632 int execute = FALSE;
3633 int dangerous = FALSE;
3634 char_u *keys_esc;
3635
3636 /* This is not allowed in the sandbox. If the commands would still be
3637 * executed in the sandbox it would be OK, but it probably happens later,
3638 * when "sandbox" is no longer set. */
3639 if (check_secure())
3640 return;
3641
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003642 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643
3644 if (argvars[1].v_type != VAR_UNKNOWN)
3645 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003646 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647 for ( ; *flags != NUL; ++flags)
3648 {
3649 switch (*flags)
3650 {
3651 case 'n': remap = FALSE; break;
3652 case 'm': remap = TRUE; break;
3653 case 't': typed = TRUE; break;
3654 case 'i': insert = TRUE; break;
3655 case 'x': execute = TRUE; break;
3656 case '!': dangerous = TRUE; break;
3657 }
3658 }
3659 }
3660
3661 if (*keys != NUL || execute)
3662 {
3663 /* Need to escape K_SPECIAL and CSI before putting the string in the
3664 * typeahead buffer. */
3665 keys_esc = vim_strsave_escape_csi(keys);
3666 if (keys_esc != NULL)
3667 {
3668 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3669 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3670 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003671 if (vgetc_busy
3672#ifdef FEAT_TIMERS
3673 || timer_busy
3674#endif
3675 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003676 typebuf_was_filled = TRUE;
3677 if (execute)
3678 {
3679 int save_msg_scroll = msg_scroll;
3680
3681 /* Avoid a 1 second delay when the keys start Insert mode. */
3682 msg_scroll = FALSE;
3683
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003684 if (!dangerous)
3685 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003686 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003687 if (!dangerous)
3688 --ex_normal_busy;
3689
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003690 msg_scroll |= save_msg_scroll;
3691 }
3692 }
3693 }
3694}
3695
3696/*
3697 * "filereadable()" function
3698 */
3699 static void
3700f_filereadable(typval_T *argvars, typval_T *rettv)
3701{
3702 int fd;
3703 char_u *p;
3704 int n;
3705
3706#ifndef O_NONBLOCK
3707# define O_NONBLOCK 0
3708#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003709 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003710 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3711 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3712 {
3713 n = TRUE;
3714 close(fd);
3715 }
3716 else
3717 n = FALSE;
3718
3719 rettv->vval.v_number = n;
3720}
3721
3722/*
3723 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3724 * rights to write into.
3725 */
3726 static void
3727f_filewritable(typval_T *argvars, typval_T *rettv)
3728{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003729 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003730}
3731
3732 static void
3733findfilendir(
3734 typval_T *argvars UNUSED,
3735 typval_T *rettv,
3736 int find_what UNUSED)
3737{
3738#ifdef FEAT_SEARCHPATH
3739 char_u *fname;
3740 char_u *fresult = NULL;
3741 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3742 char_u *p;
3743 char_u pathbuf[NUMBUFLEN];
3744 int count = 1;
3745 int first = TRUE;
3746 int error = FALSE;
3747#endif
3748
3749 rettv->vval.v_string = NULL;
3750 rettv->v_type = VAR_STRING;
3751
3752#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003753 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003754
3755 if (argvars[1].v_type != VAR_UNKNOWN)
3756 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003757 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003758 if (p == NULL)
3759 error = TRUE;
3760 else
3761 {
3762 if (*p != NUL)
3763 path = p;
3764
3765 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003766 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767 }
3768 }
3769
3770 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3771 error = TRUE;
3772
3773 if (*fname != NUL && !error)
3774 {
3775 do
3776 {
3777 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3778 vim_free(fresult);
3779 fresult = find_file_in_path_option(first ? fname : NULL,
3780 first ? (int)STRLEN(fname) : 0,
3781 0, first, path,
3782 find_what,
3783 curbuf->b_ffname,
3784 find_what == FINDFILE_DIR
3785 ? (char_u *)"" : curbuf->b_p_sua);
3786 first = FALSE;
3787
3788 if (fresult != NULL && rettv->v_type == VAR_LIST)
3789 list_append_string(rettv->vval.v_list, fresult, -1);
3790
3791 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3792 }
3793
3794 if (rettv->v_type == VAR_STRING)
3795 rettv->vval.v_string = fresult;
3796#endif
3797}
3798
3799/*
3800 * "filter()" function
3801 */
3802 static void
3803f_filter(typval_T *argvars, typval_T *rettv)
3804{
3805 filter_map(argvars, rettv, FALSE);
3806}
3807
3808/*
3809 * "finddir({fname}[, {path}[, {count}]])" function
3810 */
3811 static void
3812f_finddir(typval_T *argvars, typval_T *rettv)
3813{
3814 findfilendir(argvars, rettv, FINDFILE_DIR);
3815}
3816
3817/*
3818 * "findfile({fname}[, {path}[, {count}]])" function
3819 */
3820 static void
3821f_findfile(typval_T *argvars, typval_T *rettv)
3822{
3823 findfilendir(argvars, rettv, FINDFILE_FILE);
3824}
3825
3826#ifdef FEAT_FLOAT
3827/*
3828 * "float2nr({float})" function
3829 */
3830 static void
3831f_float2nr(typval_T *argvars, typval_T *rettv)
3832{
3833 float_T f = 0.0;
3834
3835 if (get_float_arg(argvars, &f) == OK)
3836 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003837 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003838 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003839 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003840 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003841 else
3842 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003843 }
3844}
3845
3846/*
3847 * "floor({float})" function
3848 */
3849 static void
3850f_floor(typval_T *argvars, typval_T *rettv)
3851{
3852 float_T f = 0.0;
3853
3854 rettv->v_type = VAR_FLOAT;
3855 if (get_float_arg(argvars, &f) == OK)
3856 rettv->vval.v_float = floor(f);
3857 else
3858 rettv->vval.v_float = 0.0;
3859}
3860
3861/*
3862 * "fmod()" function
3863 */
3864 static void
3865f_fmod(typval_T *argvars, typval_T *rettv)
3866{
3867 float_T fx = 0.0, fy = 0.0;
3868
3869 rettv->v_type = VAR_FLOAT;
3870 if (get_float_arg(argvars, &fx) == OK
3871 && get_float_arg(&argvars[1], &fy) == OK)
3872 rettv->vval.v_float = fmod(fx, fy);
3873 else
3874 rettv->vval.v_float = 0.0;
3875}
3876#endif
3877
3878/*
3879 * "fnameescape({string})" function
3880 */
3881 static void
3882f_fnameescape(typval_T *argvars, typval_T *rettv)
3883{
3884 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003885 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003886 rettv->v_type = VAR_STRING;
3887}
3888
3889/*
3890 * "fnamemodify({fname}, {mods})" function
3891 */
3892 static void
3893f_fnamemodify(typval_T *argvars, typval_T *rettv)
3894{
3895 char_u *fname;
3896 char_u *mods;
3897 int usedlen = 0;
3898 int len;
3899 char_u *fbuf = NULL;
3900 char_u buf[NUMBUFLEN];
3901
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003902 fname = tv_get_string_chk(&argvars[0]);
3903 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003904 if (fname == NULL || mods == NULL)
3905 fname = NULL;
3906 else
3907 {
3908 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003909 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003910 }
3911
3912 rettv->v_type = VAR_STRING;
3913 if (fname == NULL)
3914 rettv->vval.v_string = NULL;
3915 else
3916 rettv->vval.v_string = vim_strnsave(fname, len);
3917 vim_free(fbuf);
3918}
3919
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920/*
3921 * "foldclosed()" function
3922 */
3923 static void
3924foldclosed_both(
3925 typval_T *argvars UNUSED,
3926 typval_T *rettv,
3927 int end UNUSED)
3928{
3929#ifdef FEAT_FOLDING
3930 linenr_T lnum;
3931 linenr_T first, last;
3932
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003933 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3935 {
3936 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3937 {
3938 if (end)
3939 rettv->vval.v_number = (varnumber_T)last;
3940 else
3941 rettv->vval.v_number = (varnumber_T)first;
3942 return;
3943 }
3944 }
3945#endif
3946 rettv->vval.v_number = -1;
3947}
3948
3949/*
3950 * "foldclosed()" function
3951 */
3952 static void
3953f_foldclosed(typval_T *argvars, typval_T *rettv)
3954{
3955 foldclosed_both(argvars, rettv, FALSE);
3956}
3957
3958/*
3959 * "foldclosedend()" function
3960 */
3961 static void
3962f_foldclosedend(typval_T *argvars, typval_T *rettv)
3963{
3964 foldclosed_both(argvars, rettv, TRUE);
3965}
3966
3967/*
3968 * "foldlevel()" function
3969 */
3970 static void
3971f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3972{
3973#ifdef FEAT_FOLDING
3974 linenr_T lnum;
3975
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003976 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003977 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3978 rettv->vval.v_number = foldLevel(lnum);
3979#endif
3980}
3981
3982/*
3983 * "foldtext()" function
3984 */
3985 static void
3986f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3987{
3988#ifdef FEAT_FOLDING
3989 linenr_T foldstart;
3990 linenr_T foldend;
3991 char_u *dashes;
3992 linenr_T lnum;
3993 char_u *s;
3994 char_u *r;
3995 int len;
3996 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003997 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003998#endif
3999
4000 rettv->v_type = VAR_STRING;
4001 rettv->vval.v_string = NULL;
4002#ifdef FEAT_FOLDING
4003 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4004 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4005 dashes = get_vim_var_str(VV_FOLDDASHES);
4006 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4007 && dashes != NULL)
4008 {
4009 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004010 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004011 if (!linewhite(lnum))
4012 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013
4014 /* Find interesting text in this line. */
4015 s = skipwhite(ml_get(lnum));
4016 /* skip C comment-start */
4017 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4018 {
4019 s = skipwhite(s + 2);
4020 if (*skipwhite(s) == NUL
4021 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4022 {
4023 s = skipwhite(ml_get(lnum + 1));
4024 if (*s == '*')
4025 s = skipwhite(s + 1);
4026 }
4027 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004028 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004029 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004030 r = alloc((unsigned)(STRLEN(txt)
4031 + STRLEN(dashes) /* for %s */
4032 + 20 /* for %3ld */
4033 + STRLEN(s))); /* concatenated */
4034 if (r != NULL)
4035 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004036 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004037 len = (int)STRLEN(r);
4038 STRCAT(r, s);
4039 /* remove 'foldmarker' and 'commentstring' */
4040 foldtext_cleanup(r + len);
4041 rettv->vval.v_string = r;
4042 }
4043 }
4044#endif
4045}
4046
4047/*
4048 * "foldtextresult(lnum)" function
4049 */
4050 static void
4051f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4052{
4053#ifdef FEAT_FOLDING
4054 linenr_T lnum;
4055 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004056 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057 foldinfo_T foldinfo;
4058 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004059 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004060#endif
4061
4062 rettv->v_type = VAR_STRING;
4063 rettv->vval.v_string = NULL;
4064#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004065 if (entered)
4066 return; /* reject recursive use */
4067 entered = TRUE;
4068
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004069 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 /* treat illegal types and illegal string values for {lnum} the same */
4071 if (lnum < 0)
4072 lnum = 0;
4073 fold_count = foldedCount(curwin, lnum, &foldinfo);
4074 if (fold_count > 0)
4075 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004076 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4077 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078 if (text == buf)
4079 text = vim_strsave(text);
4080 rettv->vval.v_string = text;
4081 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004082
4083 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084#endif
4085}
4086
4087/*
4088 * "foreground()" function
4089 */
4090 static void
4091f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4092{
4093#ifdef FEAT_GUI
4094 if (gui.in_use)
4095 gui_mch_set_foreground();
4096#else
4097# ifdef WIN32
4098 win32_set_foreground();
4099# endif
4100#endif
4101}
4102
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004103 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004104common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004105{
4106 char_u *s;
4107 char_u *name;
4108 int use_string = FALSE;
4109 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004110 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004111
4112 if (argvars[0].v_type == VAR_FUNC)
4113 {
4114 /* function(MyFunc, [arg], dict) */
4115 s = argvars[0].vval.v_string;
4116 }
4117 else if (argvars[0].v_type == VAR_PARTIAL
4118 && argvars[0].vval.v_partial != NULL)
4119 {
4120 /* function(dict.MyFunc, [arg]) */
4121 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004122 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004123 }
4124 else
4125 {
4126 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004127 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004128 use_string = TRUE;
4129 }
4130
Bram Moolenaar843b8842016-08-21 14:36:15 +02004131 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004132 {
4133 name = s;
4134 trans_name = trans_function_name(&name, FALSE,
4135 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4136 if (*name != NUL)
4137 s = NULL;
4138 }
4139
Bram Moolenaar843b8842016-08-21 14:36:15 +02004140 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4141 || (is_funcref && trans_name == NULL))
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004142 EMSG2(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004143 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004144 else if (trans_name != NULL && (is_funcref
4145 ? find_func(trans_name) == NULL
4146 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004147 EMSG2(_("E700: Unknown function: %s"), s);
4148 else
4149 {
4150 int dict_idx = 0;
4151 int arg_idx = 0;
4152 list_T *list = NULL;
4153
4154 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4155 {
4156 char sid_buf[25];
4157 int off = *s == 's' ? 2 : 5;
4158
4159 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4160 * also be called from another script. Using trans_function_name()
4161 * would also work, but some plugins depend on the name being
4162 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004163 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004164 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4165 if (name != NULL)
4166 {
4167 STRCPY(name, sid_buf);
4168 STRCAT(name, s + off);
4169 }
4170 }
4171 else
4172 name = vim_strsave(s);
4173
4174 if (argvars[1].v_type != VAR_UNKNOWN)
4175 {
4176 if (argvars[2].v_type != VAR_UNKNOWN)
4177 {
4178 /* function(name, [args], dict) */
4179 arg_idx = 1;
4180 dict_idx = 2;
4181 }
4182 else if (argvars[1].v_type == VAR_DICT)
4183 /* function(name, dict) */
4184 dict_idx = 1;
4185 else
4186 /* function(name, [args]) */
4187 arg_idx = 1;
4188 if (dict_idx > 0)
4189 {
4190 if (argvars[dict_idx].v_type != VAR_DICT)
4191 {
4192 EMSG(_("E922: expected a dict"));
4193 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004194 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004195 }
4196 if (argvars[dict_idx].vval.v_dict == NULL)
4197 dict_idx = 0;
4198 }
4199 if (arg_idx > 0)
4200 {
4201 if (argvars[arg_idx].v_type != VAR_LIST)
4202 {
4203 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4204 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004205 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004206 }
4207 list = argvars[arg_idx].vval.v_list;
4208 if (list == NULL || list->lv_len == 0)
4209 arg_idx = 0;
4210 }
4211 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004212 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004213 {
4214 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4215
4216 /* result is a VAR_PARTIAL */
4217 if (pt == NULL)
4218 vim_free(name);
4219 else
4220 {
4221 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4222 {
4223 listitem_T *li;
4224 int i = 0;
4225 int arg_len = 0;
4226 int lv_len = 0;
4227
4228 if (arg_pt != NULL)
4229 arg_len = arg_pt->pt_argc;
4230 if (list != NULL)
4231 lv_len = list->lv_len;
4232 pt->pt_argc = arg_len + lv_len;
4233 pt->pt_argv = (typval_T *)alloc(
4234 sizeof(typval_T) * pt->pt_argc);
4235 if (pt->pt_argv == NULL)
4236 {
4237 vim_free(pt);
4238 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004239 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004240 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004241 for (i = 0; i < arg_len; i++)
4242 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4243 if (lv_len > 0)
4244 for (li = list->lv_first; li != NULL;
4245 li = li->li_next)
4246 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247 }
4248
4249 /* For "function(dict.func, [], dict)" and "func" is a partial
4250 * use "dict". That is backwards compatible. */
4251 if (dict_idx > 0)
4252 {
4253 /* The dict is bound explicitly, pt_auto is FALSE. */
4254 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4255 ++pt->pt_dict->dv_refcount;
4256 }
4257 else if (arg_pt != NULL)
4258 {
4259 /* If the dict was bound automatically the result is also
4260 * bound automatically. */
4261 pt->pt_dict = arg_pt->pt_dict;
4262 pt->pt_auto = arg_pt->pt_auto;
4263 if (pt->pt_dict != NULL)
4264 ++pt->pt_dict->dv_refcount;
4265 }
4266
4267 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004268 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4269 {
4270 pt->pt_func = arg_pt->pt_func;
4271 func_ptr_ref(pt->pt_func);
4272 vim_free(name);
4273 }
4274 else if (is_funcref)
4275 {
4276 pt->pt_func = find_func(trans_name);
4277 func_ptr_ref(pt->pt_func);
4278 vim_free(name);
4279 }
4280 else
4281 {
4282 pt->pt_name = name;
4283 func_ref(name);
4284 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004285 }
4286 rettv->v_type = VAR_PARTIAL;
4287 rettv->vval.v_partial = pt;
4288 }
4289 else
4290 {
4291 /* result is a VAR_FUNC */
4292 rettv->v_type = VAR_FUNC;
4293 rettv->vval.v_string = name;
4294 func_ref(name);
4295 }
4296 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004297theend:
4298 vim_free(trans_name);
4299}
4300
4301/*
4302 * "funcref()" function
4303 */
4304 static void
4305f_funcref(typval_T *argvars, typval_T *rettv)
4306{
4307 common_function(argvars, rettv, TRUE);
4308}
4309
4310/*
4311 * "function()" function
4312 */
4313 static void
4314f_function(typval_T *argvars, typval_T *rettv)
4315{
4316 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004317}
4318
4319/*
4320 * "garbagecollect()" function
4321 */
4322 static void
4323f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4324{
4325 /* This is postponed until we are back at the toplevel, because we may be
4326 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4327 want_garbage_collect = TRUE;
4328
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004329 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004330 garbage_collect_at_exit = TRUE;
4331}
4332
4333/*
4334 * "get()" function
4335 */
4336 static void
4337f_get(typval_T *argvars, typval_T *rettv)
4338{
4339 listitem_T *li;
4340 list_T *l;
4341 dictitem_T *di;
4342 dict_T *d;
4343 typval_T *tv = NULL;
4344
4345 if (argvars[0].v_type == VAR_LIST)
4346 {
4347 if ((l = argvars[0].vval.v_list) != NULL)
4348 {
4349 int error = FALSE;
4350
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004351 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004352 if (!error && li != NULL)
4353 tv = &li->li_tv;
4354 }
4355 }
4356 else if (argvars[0].v_type == VAR_DICT)
4357 {
4358 if ((d = argvars[0].vval.v_dict) != NULL)
4359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004360 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004361 if (di != NULL)
4362 tv = &di->di_tv;
4363 }
4364 }
4365 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4366 {
4367 partial_T *pt;
4368 partial_T fref_pt;
4369
4370 if (argvars[0].v_type == VAR_PARTIAL)
4371 pt = argvars[0].vval.v_partial;
4372 else
4373 {
4374 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4375 fref_pt.pt_name = argvars[0].vval.v_string;
4376 pt = &fref_pt;
4377 }
4378
4379 if (pt != NULL)
4380 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004381 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004382 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004383
4384 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4385 {
4386 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004387 n = partial_name(pt);
4388 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004389 rettv->vval.v_string = NULL;
4390 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004391 {
4392 rettv->vval.v_string = vim_strsave(n);
4393 if (rettv->v_type == VAR_FUNC)
4394 func_ref(rettv->vval.v_string);
4395 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004396 }
4397 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004398 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004399 else if (STRCMP(what, "args") == 0)
4400 {
4401 rettv->v_type = VAR_LIST;
4402 if (rettv_list_alloc(rettv) == OK)
4403 {
4404 int i;
4405
4406 for (i = 0; i < pt->pt_argc; ++i)
4407 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4408 }
4409 }
4410 else
4411 EMSG2(_(e_invarg2), what);
4412 return;
4413 }
4414 }
4415 else
4416 EMSG2(_(e_listdictarg), "get()");
4417
4418 if (tv == NULL)
4419 {
4420 if (argvars[2].v_type != VAR_UNKNOWN)
4421 copy_tv(&argvars[2], rettv);
4422 }
4423 else
4424 copy_tv(tv, rettv);
4425}
4426
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004427/*
4428 * Returns buffer options, variables and other attributes in a dictionary.
4429 */
4430 static dict_T *
4431get_buffer_info(buf_T *buf)
4432{
4433 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004434 tabpage_T *tp;
4435 win_T *wp;
4436 list_T *windows;
4437
4438 dict = dict_alloc();
4439 if (dict == NULL)
4440 return NULL;
4441
Bram Moolenaare0be1672018-07-08 16:50:37 +02004442 dict_add_number(dict, "bufnr", buf->b_fnum);
4443 dict_add_string(dict, "name", buf->b_ffname);
4444 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4445 : buflist_findlnum(buf));
4446 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4447 dict_add_number(dict, "listed", buf->b_p_bl);
4448 dict_add_number(dict, "changed", bufIsChanged(buf));
4449 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4450 dict_add_number(dict, "hidden",
4451 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004452
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004453 /* Get a reference to buffer variables */
4454 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004455
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004456 /* List of windows displaying this buffer */
4457 windows = list_alloc();
4458 if (windows != NULL)
4459 {
4460 FOR_ALL_TAB_WINDOWS(tp, wp)
4461 if (wp->w_buffer == buf)
4462 list_append_number(windows, (varnumber_T)wp->w_id);
4463 dict_add_list(dict, "windows", windows);
4464 }
4465
4466#ifdef FEAT_SIGNS
4467 if (buf->b_signlist != NULL)
4468 {
4469 /* List of signs placed in this buffer */
4470 list_T *signs = list_alloc();
4471 if (signs != NULL)
4472 {
4473 get_buffer_signs(buf, signs);
4474 dict_add_list(dict, "signs", signs);
4475 }
4476 }
4477#endif
4478
4479 return dict;
4480}
4481
4482/*
4483 * "getbufinfo()" function
4484 */
4485 static void
4486f_getbufinfo(typval_T *argvars, typval_T *rettv)
4487{
4488 buf_T *buf = NULL;
4489 buf_T *argbuf = NULL;
4490 dict_T *d;
4491 int filtered = FALSE;
4492 int sel_buflisted = FALSE;
4493 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004494 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004495
4496 if (rettv_list_alloc(rettv) != OK)
4497 return;
4498
4499 /* List of all the buffers or selected buffers */
4500 if (argvars[0].v_type == VAR_DICT)
4501 {
4502 dict_T *sel_d = argvars[0].vval.v_dict;
4503
4504 if (sel_d != NULL)
4505 {
4506 dictitem_T *di;
4507
4508 filtered = TRUE;
4509
4510 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004511 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004512 sel_buflisted = TRUE;
4513
4514 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004515 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004516 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004517
4518 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004519 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004520 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004521 }
4522 }
4523 else if (argvars[0].v_type != VAR_UNKNOWN)
4524 {
4525 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004526 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004527 ++emsg_off;
4528 argbuf = get_buf_tv(&argvars[0], FALSE);
4529 --emsg_off;
4530 if (argbuf == NULL)
4531 return;
4532 }
4533
4534 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004535 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004536 {
4537 if (argbuf != NULL && argbuf != buf)
4538 continue;
4539 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004540 || (sel_buflisted && !buf->b_p_bl)
4541 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004542 continue;
4543
4544 d = get_buffer_info(buf);
4545 if (d != NULL)
4546 list_append_dict(rettv->vval.v_list, d);
4547 if (argbuf != NULL)
4548 return;
4549 }
4550}
4551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004552/*
4553 * Get line or list of lines from buffer "buf" into "rettv".
4554 * Return a range (from start to end) of lines in rettv from the specified
4555 * buffer.
4556 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4557 */
4558 static void
4559get_buffer_lines(
4560 buf_T *buf,
4561 linenr_T start,
4562 linenr_T end,
4563 int retlist,
4564 typval_T *rettv)
4565{
4566 char_u *p;
4567
4568 rettv->v_type = VAR_STRING;
4569 rettv->vval.v_string = NULL;
4570 if (retlist && rettv_list_alloc(rettv) == FAIL)
4571 return;
4572
4573 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4574 return;
4575
4576 if (!retlist)
4577 {
4578 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4579 p = ml_get_buf(buf, start, FALSE);
4580 else
4581 p = (char_u *)"";
4582 rettv->vval.v_string = vim_strsave(p);
4583 }
4584 else
4585 {
4586 if (end < start)
4587 return;
4588
4589 if (start < 1)
4590 start = 1;
4591 if (end > buf->b_ml.ml_line_count)
4592 end = buf->b_ml.ml_line_count;
4593 while (start <= end)
4594 if (list_append_string(rettv->vval.v_list,
4595 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4596 break;
4597 }
4598}
4599
4600/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004601 * "getbufline()" function
4602 */
4603 static void
4604f_getbufline(typval_T *argvars, typval_T *rettv)
4605{
4606 linenr_T lnum;
4607 linenr_T end;
4608 buf_T *buf;
4609
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004610 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611 ++emsg_off;
4612 buf = get_buf_tv(&argvars[0], FALSE);
4613 --emsg_off;
4614
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004615 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004616 if (argvars[2].v_type == VAR_UNKNOWN)
4617 end = lnum;
4618 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004619 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004620
4621 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4622}
4623
4624/*
4625 * "getbufvar()" function
4626 */
4627 static void
4628f_getbufvar(typval_T *argvars, typval_T *rettv)
4629{
4630 buf_T *buf;
4631 buf_T *save_curbuf;
4632 char_u *varname;
4633 dictitem_T *v;
4634 int done = FALSE;
4635
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004636 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4637 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004638 ++emsg_off;
4639 buf = get_buf_tv(&argvars[0], FALSE);
4640
4641 rettv->v_type = VAR_STRING;
4642 rettv->vval.v_string = NULL;
4643
4644 if (buf != NULL && varname != NULL)
4645 {
4646 /* set curbuf to be our buf, temporarily */
4647 save_curbuf = curbuf;
4648 curbuf = buf;
4649
Bram Moolenaar30567352016-08-27 21:25:44 +02004650 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004651 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004652 if (varname[1] == NUL)
4653 {
4654 /* get all buffer-local options in a dict */
4655 dict_T *opts = get_winbuf_options(TRUE);
4656
4657 if (opts != NULL)
4658 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004659 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004660 done = TRUE;
4661 }
4662 }
4663 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4664 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004665 done = TRUE;
4666 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004667 else
4668 {
4669 /* Look up the variable. */
4670 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4671 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4672 'b', varname, FALSE);
4673 if (v != NULL)
4674 {
4675 copy_tv(&v->di_tv, rettv);
4676 done = TRUE;
4677 }
4678 }
4679
4680 /* restore previous notion of curbuf */
4681 curbuf = save_curbuf;
4682 }
4683
4684 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4685 /* use the default value */
4686 copy_tv(&argvars[2], rettv);
4687
4688 --emsg_off;
4689}
4690
4691/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004692 * "getchangelist()" function
4693 */
4694 static void
4695f_getchangelist(typval_T *argvars, typval_T *rettv)
4696{
4697#ifdef FEAT_JUMPLIST
4698 buf_T *buf;
4699 int i;
4700 list_T *l;
4701 dict_T *d;
4702#endif
4703
4704 if (rettv_list_alloc(rettv) != OK)
4705 return;
4706
4707#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004708 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004709 ++emsg_off;
4710 buf = get_buf_tv(&argvars[0], FALSE);
4711 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004712 if (buf == NULL)
4713 return;
4714
4715 l = list_alloc();
4716 if (l == NULL)
4717 return;
4718
4719 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4720 return;
4721 /*
4722 * The current window change list index tracks only the position in the
4723 * current buffer change list. For other buffers, use the change list
4724 * length as the current index.
4725 */
4726 list_append_number(rettv->vval.v_list,
4727 (varnumber_T)((buf == curwin->w_buffer)
4728 ? curwin->w_changelistidx : buf->b_changelistlen));
4729
4730 for (i = 0; i < buf->b_changelistlen; ++i)
4731 {
4732 if (buf->b_changelist[i].lnum == 0)
4733 continue;
4734 if ((d = dict_alloc()) == NULL)
4735 return;
4736 if (list_append_dict(l, d) == FAIL)
4737 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004738 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4739 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004740# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004741 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004742# endif
4743 }
4744#endif
4745}
4746/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004747 * "getchar()" function
4748 */
4749 static void
4750f_getchar(typval_T *argvars, typval_T *rettv)
4751{
4752 varnumber_T n;
4753 int error = FALSE;
4754
Bram Moolenaar84d93902018-09-11 20:10:20 +02004755#ifdef MESSAGE_QUEUE
4756 // vpeekc() used to check for messages, but that caused problems, invoking
4757 // a callback where it was not expected. Some plugins use getchar(1) in a
4758 // loop to await a message, therefore make sure we check for messages here.
4759 parse_queued_messages();
4760#endif
4761
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004762 /* Position the cursor. Needed after a message that ends in a space. */
4763 windgoto(msg_row, msg_col);
4764
4765 ++no_mapping;
4766 ++allow_keys;
4767 for (;;)
4768 {
4769 if (argvars[0].v_type == VAR_UNKNOWN)
4770 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004771 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004772 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004773 /* getchar(1): only check if char avail */
4774 n = vpeekc_any();
4775 else if (error || vpeekc_any() == NUL)
4776 /* illegal argument or getchar(0) and no char avail: return zero */
4777 n = 0;
4778 else
4779 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004780 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004781
4782 if (n == K_IGNORE)
4783 continue;
4784 break;
4785 }
4786 --no_mapping;
4787 --allow_keys;
4788
4789 set_vim_var_nr(VV_MOUSE_WIN, 0);
4790 set_vim_var_nr(VV_MOUSE_WINID, 0);
4791 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4792 set_vim_var_nr(VV_MOUSE_COL, 0);
4793
4794 rettv->vval.v_number = n;
4795 if (IS_SPECIAL(n) || mod_mask != 0)
4796 {
4797 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4798 int i = 0;
4799
4800 /* Turn a special key into three bytes, plus modifier. */
4801 if (mod_mask != 0)
4802 {
4803 temp[i++] = K_SPECIAL;
4804 temp[i++] = KS_MODIFIER;
4805 temp[i++] = mod_mask;
4806 }
4807 if (IS_SPECIAL(n))
4808 {
4809 temp[i++] = K_SPECIAL;
4810 temp[i++] = K_SECOND(n);
4811 temp[i++] = K_THIRD(n);
4812 }
4813#ifdef FEAT_MBYTE
4814 else if (has_mbyte)
4815 i += (*mb_char2bytes)(n, temp + i);
4816#endif
4817 else
4818 temp[i++] = n;
4819 temp[i++] = NUL;
4820 rettv->v_type = VAR_STRING;
4821 rettv->vval.v_string = vim_strsave(temp);
4822
4823#ifdef FEAT_MOUSE
4824 if (is_mouse_key(n))
4825 {
4826 int row = mouse_row;
4827 int col = mouse_col;
4828 win_T *win;
4829 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004830 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004831 int winnr = 1;
4832
4833 if (row >= 0 && col >= 0)
4834 {
4835 /* Find the window at the mouse coordinates and compute the
4836 * text position. */
4837 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004838 if (win == NULL)
4839 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004840 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841 for (wp = firstwin; wp != win; wp = wp->w_next)
4842 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004843 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4844 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4845 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4846 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4847 }
4848 }
4849#endif
4850 }
4851}
4852
4853/*
4854 * "getcharmod()" function
4855 */
4856 static void
4857f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4858{
4859 rettv->vval.v_number = mod_mask;
4860}
4861
4862/*
4863 * "getcharsearch()" function
4864 */
4865 static void
4866f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4867{
4868 if (rettv_dict_alloc(rettv) != FAIL)
4869 {
4870 dict_T *dict = rettv->vval.v_dict;
4871
Bram Moolenaare0be1672018-07-08 16:50:37 +02004872 dict_add_string(dict, "char", last_csearch());
4873 dict_add_number(dict, "forward", last_csearch_forward());
4874 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004875 }
4876}
4877
4878/*
4879 * "getcmdline()" function
4880 */
4881 static void
4882f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4883{
4884 rettv->v_type = VAR_STRING;
4885 rettv->vval.v_string = get_cmdline_str();
4886}
4887
4888/*
4889 * "getcmdpos()" function
4890 */
4891 static void
4892f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4893{
4894 rettv->vval.v_number = get_cmdline_pos() + 1;
4895}
4896
4897/*
4898 * "getcmdtype()" function
4899 */
4900 static void
4901f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4902{
4903 rettv->v_type = VAR_STRING;
4904 rettv->vval.v_string = alloc(2);
4905 if (rettv->vval.v_string != NULL)
4906 {
4907 rettv->vval.v_string[0] = get_cmdline_type();
4908 rettv->vval.v_string[1] = NUL;
4909 }
4910}
4911
4912/*
4913 * "getcmdwintype()" function
4914 */
4915 static void
4916f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4917{
4918 rettv->v_type = VAR_STRING;
4919 rettv->vval.v_string = NULL;
4920#ifdef FEAT_CMDWIN
4921 rettv->vval.v_string = alloc(2);
4922 if (rettv->vval.v_string != NULL)
4923 {
4924 rettv->vval.v_string[0] = cmdwin_type;
4925 rettv->vval.v_string[1] = NUL;
4926 }
4927#endif
4928}
4929
4930#if defined(FEAT_CMDL_COMPL)
4931/*
4932 * "getcompletion()" function
4933 */
4934 static void
4935f_getcompletion(typval_T *argvars, typval_T *rettv)
4936{
4937 char_u *pat;
4938 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004939 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004940 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4941 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004943 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004944 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004945
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946 if (p_wic)
4947 options |= WILD_ICASE;
4948
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004949 /* For filtered results, 'wildignore' is used */
4950 if (!filtered)
4951 options |= WILD_KEEP_ALL;
4952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004953 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004954 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004956 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004957 if (xpc.xp_context == EXPAND_NOTHING)
4958 {
4959 if (argvars[1].v_type == VAR_STRING)
4960 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4961 else
4962 EMSG(_(e_invarg));
4963 return;
4964 }
4965
4966# if defined(FEAT_MENU)
4967 if (xpc.xp_context == EXPAND_MENUS)
4968 {
4969 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4970 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4971 }
4972# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004973#ifdef FEAT_CSCOPE
4974 if (xpc.xp_context == EXPAND_CSCOPE)
4975 {
4976 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4977 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4978 }
4979#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004980#ifdef FEAT_SIGNS
4981 if (xpc.xp_context == EXPAND_SIGN)
4982 {
4983 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4984 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4985 }
4986#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004987
4988 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4989 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4990 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004991 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004992
4993 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4994
4995 for (i = 0; i < xpc.xp_numfiles; i++)
4996 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4997 }
4998 vim_free(pat);
4999 ExpandCleanup(&xpc);
5000}
5001#endif
5002
5003/*
5004 * "getcwd()" function
5005 */
5006 static void
5007f_getcwd(typval_T *argvars, typval_T *rettv)
5008{
5009 win_T *wp = NULL;
5010 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005011 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005012
5013 rettv->v_type = VAR_STRING;
5014 rettv->vval.v_string = NULL;
5015
Bram Moolenaar54591292018-02-09 20:53:59 +01005016 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5017 global = TRUE;
5018 else
5019 wp = find_tabwin(&argvars[0], &argvars[1]);
5020
5021 if (wp != NULL && wp->w_localdir != NULL)
5022 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5023 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005024 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005025 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005026 rettv->vval.v_string = vim_strsave(globaldir);
5027 else
5028 {
5029 cwd = alloc(MAXPATHL);
5030 if (cwd != NULL)
5031 {
5032 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5033 rettv->vval.v_string = vim_strsave(cwd);
5034 vim_free(cwd);
5035 }
5036 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005038#ifdef BACKSLASH_IN_FILENAME
5039 if (rettv->vval.v_string != NULL)
5040 slash_adjust(rettv->vval.v_string);
5041#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042}
5043
5044/*
5045 * "getfontname()" function
5046 */
5047 static void
5048f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5049{
5050 rettv->v_type = VAR_STRING;
5051 rettv->vval.v_string = NULL;
5052#ifdef FEAT_GUI
5053 if (gui.in_use)
5054 {
5055 GuiFont font;
5056 char_u *name = NULL;
5057
5058 if (argvars[0].v_type == VAR_UNKNOWN)
5059 {
5060 /* Get the "Normal" font. Either the name saved by
5061 * hl_set_font_name() or from the font ID. */
5062 font = gui.norm_font;
5063 name = hl_get_font_name();
5064 }
5065 else
5066 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005067 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005068 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5069 return;
5070 font = gui_mch_get_font(name, FALSE);
5071 if (font == NOFONT)
5072 return; /* Invalid font name, return empty string. */
5073 }
5074 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5075 if (argvars[0].v_type != VAR_UNKNOWN)
5076 gui_mch_free_font(font);
5077 }
5078#endif
5079}
5080
5081/*
5082 * "getfperm({fname})" function
5083 */
5084 static void
5085f_getfperm(typval_T *argvars, typval_T *rettv)
5086{
5087 char_u *fname;
5088 stat_T st;
5089 char_u *perm = NULL;
5090 char_u flags[] = "rwx";
5091 int i;
5092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005093 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094
5095 rettv->v_type = VAR_STRING;
5096 if (mch_stat((char *)fname, &st) >= 0)
5097 {
5098 perm = vim_strsave((char_u *)"---------");
5099 if (perm != NULL)
5100 {
5101 for (i = 0; i < 9; i++)
5102 {
5103 if (st.st_mode & (1 << (8 - i)))
5104 perm[i] = flags[i % 3];
5105 }
5106 }
5107 }
5108 rettv->vval.v_string = perm;
5109}
5110
5111/*
5112 * "getfsize({fname})" function
5113 */
5114 static void
5115f_getfsize(typval_T *argvars, typval_T *rettv)
5116{
5117 char_u *fname;
5118 stat_T st;
5119
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005120 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005121
5122 rettv->v_type = VAR_NUMBER;
5123
5124 if (mch_stat((char *)fname, &st) >= 0)
5125 {
5126 if (mch_isdir(fname))
5127 rettv->vval.v_number = 0;
5128 else
5129 {
5130 rettv->vval.v_number = (varnumber_T)st.st_size;
5131
5132 /* non-perfect check for overflow */
5133 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5134 rettv->vval.v_number = -2;
5135 }
5136 }
5137 else
5138 rettv->vval.v_number = -1;
5139}
5140
5141/*
5142 * "getftime({fname})" function
5143 */
5144 static void
5145f_getftime(typval_T *argvars, typval_T *rettv)
5146{
5147 char_u *fname;
5148 stat_T st;
5149
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005150 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005151
5152 if (mch_stat((char *)fname, &st) >= 0)
5153 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5154 else
5155 rettv->vval.v_number = -1;
5156}
5157
5158/*
5159 * "getftype({fname})" function
5160 */
5161 static void
5162f_getftype(typval_T *argvars, typval_T *rettv)
5163{
5164 char_u *fname;
5165 stat_T st;
5166 char_u *type = NULL;
5167 char *t;
5168
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005169 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005170
5171 rettv->v_type = VAR_STRING;
5172 if (mch_lstat((char *)fname, &st) >= 0)
5173 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005174 if (S_ISREG(st.st_mode))
5175 t = "file";
5176 else if (S_ISDIR(st.st_mode))
5177 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005178 else if (S_ISLNK(st.st_mode))
5179 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005180 else if (S_ISBLK(st.st_mode))
5181 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005182 else if (S_ISCHR(st.st_mode))
5183 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005184 else if (S_ISFIFO(st.st_mode))
5185 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005186 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005187 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005188 else
5189 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005190 type = vim_strsave((char_u *)t);
5191 }
5192 rettv->vval.v_string = type;
5193}
5194
5195/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005196 * "getjumplist()" function
5197 */
5198 static void
5199f_getjumplist(typval_T *argvars, typval_T *rettv)
5200{
5201#ifdef FEAT_JUMPLIST
5202 win_T *wp;
5203 int i;
5204 list_T *l;
5205 dict_T *d;
5206#endif
5207
5208 if (rettv_list_alloc(rettv) != OK)
5209 return;
5210
5211#ifdef FEAT_JUMPLIST
5212 wp = find_tabwin(&argvars[0], &argvars[1]);
5213 if (wp == NULL)
5214 return;
5215
5216 l = list_alloc();
5217 if (l == NULL)
5218 return;
5219
5220 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5221 return;
5222 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5223
Bram Moolenaar48679742018-02-13 13:33:29 +01005224 cleanup_jumplist(wp, TRUE);
5225
Bram Moolenaar4f505882018-02-10 21:06:32 +01005226 for (i = 0; i < wp->w_jumplistlen; ++i)
5227 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005228 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5229 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005230 if ((d = dict_alloc()) == NULL)
5231 return;
5232 if (list_append_dict(l, d) == FAIL)
5233 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005234 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5235 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005236# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005237 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005238# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005239 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005240 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005241 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005242 }
5243#endif
5244}
5245
5246/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005247 * "getline(lnum, [end])" function
5248 */
5249 static void
5250f_getline(typval_T *argvars, typval_T *rettv)
5251{
5252 linenr_T lnum;
5253 linenr_T end;
5254 int retlist;
5255
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005256 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005257 if (argvars[1].v_type == VAR_UNKNOWN)
5258 {
5259 end = 0;
5260 retlist = FALSE;
5261 }
5262 else
5263 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005264 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005265 retlist = TRUE;
5266 }
5267
5268 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5269}
5270
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005271#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005272 static void
5273get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5274{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005275 if (what_arg->v_type == VAR_UNKNOWN)
5276 {
5277 if (rettv_list_alloc(rettv) == OK)
5278 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005279 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005280 }
5281 else
5282 {
5283 if (rettv_dict_alloc(rettv) == OK)
5284 if (is_qf || (wp != NULL))
5285 {
5286 if (what_arg->v_type == VAR_DICT)
5287 {
5288 dict_T *d = what_arg->vval.v_dict;
5289
5290 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005291 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005292 }
5293 else
5294 EMSG(_(e_dictreq));
5295 }
5296 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005297}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005298#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005299
5300/*
5301 * "getloclist()" function
5302 */
5303 static void
5304f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5305{
5306#ifdef FEAT_QUICKFIX
5307 win_T *wp;
5308
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005309 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005310 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5311#endif
5312}
5313
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005314/*
5315 * "getmatches()" function
5316 */
5317 static void
5318f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5319{
5320#ifdef FEAT_SEARCH_EXTRA
5321 dict_T *dict;
5322 matchitem_T *cur = curwin->w_match_head;
5323 int i;
5324
5325 if (rettv_list_alloc(rettv) == OK)
5326 {
5327 while (cur != NULL)
5328 {
5329 dict = dict_alloc();
5330 if (dict == NULL)
5331 return;
5332 if (cur->match.regprog == NULL)
5333 {
5334 /* match added with matchaddpos() */
5335 for (i = 0; i < MAXPOSMATCH; ++i)
5336 {
5337 llpos_T *llpos;
5338 char buf[6];
5339 list_T *l;
5340
5341 llpos = &cur->pos.pos[i];
5342 if (llpos->lnum == 0)
5343 break;
5344 l = list_alloc();
5345 if (l == NULL)
5346 break;
5347 list_append_number(l, (varnumber_T)llpos->lnum);
5348 if (llpos->col > 0)
5349 {
5350 list_append_number(l, (varnumber_T)llpos->col);
5351 list_append_number(l, (varnumber_T)llpos->len);
5352 }
5353 sprintf(buf, "pos%d", i + 1);
5354 dict_add_list(dict, buf, l);
5355 }
5356 }
5357 else
5358 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005359 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005360 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005361 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5362 dict_add_number(dict, "priority", (long)cur->priority);
5363 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005364# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5365 if (cur->conceal_char)
5366 {
5367 char_u buf[MB_MAXBYTES + 1];
5368
5369 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005370 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005371 }
5372# endif
5373 list_append_dict(rettv->vval.v_list, dict);
5374 cur = cur->next;
5375 }
5376 }
5377#endif
5378}
5379
5380/*
5381 * "getpid()" function
5382 */
5383 static void
5384f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5385{
5386 rettv->vval.v_number = mch_get_pid();
5387}
5388
5389 static void
5390getpos_both(
5391 typval_T *argvars,
5392 typval_T *rettv,
5393 int getcurpos)
5394{
5395 pos_T *fp;
5396 list_T *l;
5397 int fnum = -1;
5398
5399 if (rettv_list_alloc(rettv) == OK)
5400 {
5401 l = rettv->vval.v_list;
5402 if (getcurpos)
5403 fp = &curwin->w_cursor;
5404 else
5405 fp = var2fpos(&argvars[0], TRUE, &fnum);
5406 if (fnum != -1)
5407 list_append_number(l, (varnumber_T)fnum);
5408 else
5409 list_append_number(l, (varnumber_T)0);
5410 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5411 : (varnumber_T)0);
5412 list_append_number(l, (fp != NULL)
5413 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5414 : (varnumber_T)0);
5415 list_append_number(l,
5416#ifdef FEAT_VIRTUALEDIT
5417 (fp != NULL) ? (varnumber_T)fp->coladd :
5418#endif
5419 (varnumber_T)0);
5420 if (getcurpos)
5421 {
5422 update_curswant();
5423 list_append_number(l, curwin->w_curswant == MAXCOL ?
5424 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5425 }
5426 }
5427 else
5428 rettv->vval.v_number = FALSE;
5429}
5430
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005431/*
5432 * "getcurpos()" function
5433 */
5434 static void
5435f_getcurpos(typval_T *argvars, typval_T *rettv)
5436{
5437 getpos_both(argvars, rettv, TRUE);
5438}
5439
5440/*
5441 * "getpos(string)" function
5442 */
5443 static void
5444f_getpos(typval_T *argvars, typval_T *rettv)
5445{
5446 getpos_both(argvars, rettv, FALSE);
5447}
5448
5449/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005450 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005451 */
5452 static void
5453f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5454{
5455#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005456 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457#endif
5458}
5459
5460/*
5461 * "getreg()" function
5462 */
5463 static void
5464f_getreg(typval_T *argvars, typval_T *rettv)
5465{
5466 char_u *strregname;
5467 int regname;
5468 int arg2 = FALSE;
5469 int return_list = FALSE;
5470 int error = FALSE;
5471
5472 if (argvars[0].v_type != VAR_UNKNOWN)
5473 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005474 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005475 error = strregname == NULL;
5476 if (argvars[1].v_type != VAR_UNKNOWN)
5477 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005478 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005480 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005481 }
5482 }
5483 else
5484 strregname = get_vim_var_str(VV_REG);
5485
5486 if (error)
5487 return;
5488
5489 regname = (strregname == NULL ? '"' : *strregname);
5490 if (regname == 0)
5491 regname = '"';
5492
5493 if (return_list)
5494 {
5495 rettv->v_type = VAR_LIST;
5496 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5497 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5498 if (rettv->vval.v_list == NULL)
5499 (void)rettv_list_alloc(rettv);
5500 else
5501 ++rettv->vval.v_list->lv_refcount;
5502 }
5503 else
5504 {
5505 rettv->v_type = VAR_STRING;
5506 rettv->vval.v_string = get_reg_contents(regname,
5507 arg2 ? GREG_EXPR_SRC : 0);
5508 }
5509}
5510
5511/*
5512 * "getregtype()" function
5513 */
5514 static void
5515f_getregtype(typval_T *argvars, typval_T *rettv)
5516{
5517 char_u *strregname;
5518 int regname;
5519 char_u buf[NUMBUFLEN + 2];
5520 long reglen = 0;
5521
5522 if (argvars[0].v_type != VAR_UNKNOWN)
5523 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005524 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005525 if (strregname == NULL) /* type error; errmsg already given */
5526 {
5527 rettv->v_type = VAR_STRING;
5528 rettv->vval.v_string = NULL;
5529 return;
5530 }
5531 }
5532 else
5533 /* Default to v:register */
5534 strregname = get_vim_var_str(VV_REG);
5535
5536 regname = (strregname == NULL ? '"' : *strregname);
5537 if (regname == 0)
5538 regname = '"';
5539
5540 buf[0] = NUL;
5541 buf[1] = NUL;
5542 switch (get_reg_type(regname, &reglen))
5543 {
5544 case MLINE: buf[0] = 'V'; break;
5545 case MCHAR: buf[0] = 'v'; break;
5546 case MBLOCK:
5547 buf[0] = Ctrl_V;
5548 sprintf((char *)buf + 1, "%ld", reglen + 1);
5549 break;
5550 }
5551 rettv->v_type = VAR_STRING;
5552 rettv->vval.v_string = vim_strsave(buf);
5553}
5554
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005555/*
5556 * Returns information (variables, options, etc.) about a tab page
5557 * as a dictionary.
5558 */
5559 static dict_T *
5560get_tabpage_info(tabpage_T *tp, int tp_idx)
5561{
5562 win_T *wp;
5563 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005564 list_T *l;
5565
5566 dict = dict_alloc();
5567 if (dict == NULL)
5568 return NULL;
5569
Bram Moolenaare0be1672018-07-08 16:50:37 +02005570 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005571
5572 l = list_alloc();
5573 if (l != NULL)
5574 {
5575 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5576 wp; wp = wp->w_next)
5577 list_append_number(l, (varnumber_T)wp->w_id);
5578 dict_add_list(dict, "windows", l);
5579 }
5580
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005581 /* Make a reference to tabpage variables */
5582 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005583
5584 return dict;
5585}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005586
5587/*
5588 * "gettabinfo()" function
5589 */
5590 static void
5591f_gettabinfo(typval_T *argvars, typval_T *rettv)
5592{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005593 tabpage_T *tp, *tparg = NULL;
5594 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005595 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005596
5597 if (rettv_list_alloc(rettv) != OK)
5598 return;
5599
5600 if (argvars[0].v_type != VAR_UNKNOWN)
5601 {
5602 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005603 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005604 if (tparg == NULL)
5605 return;
5606 }
5607
5608 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005609 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005610 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005611 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005612 if (tparg != NULL && tp != tparg)
5613 continue;
5614 d = get_tabpage_info(tp, tpnr);
5615 if (d != NULL)
5616 list_append_dict(rettv->vval.v_list, d);
5617 if (tparg != NULL)
5618 return;
5619 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005620}
5621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005622/*
5623 * "gettabvar()" function
5624 */
5625 static void
5626f_gettabvar(typval_T *argvars, typval_T *rettv)
5627{
5628 win_T *oldcurwin;
5629 tabpage_T *tp, *oldtabpage;
5630 dictitem_T *v;
5631 char_u *varname;
5632 int done = FALSE;
5633
5634 rettv->v_type = VAR_STRING;
5635 rettv->vval.v_string = NULL;
5636
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005637 varname = tv_get_string_chk(&argvars[1]);
5638 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639 if (tp != NULL && varname != NULL)
5640 {
5641 /* Set tp to be our tabpage, temporarily. Also set the window to the
5642 * first window in the tabpage, otherwise the window is not valid. */
5643 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005644 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5645 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005646 {
5647 /* look up the variable */
5648 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5649 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5650 if (v != NULL)
5651 {
5652 copy_tv(&v->di_tv, rettv);
5653 done = TRUE;
5654 }
5655 }
5656
5657 /* restore previous notion of curwin */
5658 restore_win(oldcurwin, oldtabpage, TRUE);
5659 }
5660
5661 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5662 copy_tv(&argvars[2], rettv);
5663}
5664
5665/*
5666 * "gettabwinvar()" function
5667 */
5668 static void
5669f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5670{
5671 getwinvar(argvars, rettv, 1);
5672}
5673
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005674/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005675 * "gettagstack()" function
5676 */
5677 static void
5678f_gettagstack(typval_T *argvars, typval_T *rettv)
5679{
5680 win_T *wp = curwin; // default is current window
5681
5682 if (rettv_dict_alloc(rettv) != OK)
5683 return;
5684
5685 if (argvars[0].v_type != VAR_UNKNOWN)
5686 {
5687 wp = find_win_by_nr_or_id(&argvars[0]);
5688 if (wp == NULL)
5689 return;
5690 }
5691
5692 get_tagstack(wp, rettv->vval.v_dict);
5693}
5694
5695/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005696 * Returns information about a window as a dictionary.
5697 */
5698 static dict_T *
5699get_win_info(win_T *wp, short tpnr, short winnr)
5700{
5701 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005702
5703 dict = dict_alloc();
5704 if (dict == NULL)
5705 return NULL;
5706
Bram Moolenaare0be1672018-07-08 16:50:37 +02005707 dict_add_number(dict, "tabnr", tpnr);
5708 dict_add_number(dict, "winnr", winnr);
5709 dict_add_number(dict, "winid", wp->w_id);
5710 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005711 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005712#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005713 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005714#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005715 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005716 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005717 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005718
Bram Moolenaar69905d12017-08-13 18:14:47 +02005719#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005720 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005721#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005722#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005723 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5724 dict_add_number(dict, "loclist",
5725 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005726#endif
5727
Bram Moolenaar30567352016-08-27 21:25:44 +02005728 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005729 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005730
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005731 return dict;
5732}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005733
5734/*
5735 * "getwininfo()" function
5736 */
5737 static void
5738f_getwininfo(typval_T *argvars, typval_T *rettv)
5739{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005740 tabpage_T *tp;
5741 win_T *wp = NULL, *wparg = NULL;
5742 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005743 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005744
5745 if (rettv_list_alloc(rettv) != OK)
5746 return;
5747
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005748 if (argvars[0].v_type != VAR_UNKNOWN)
5749 {
5750 wparg = win_id2wp(argvars);
5751 if (wparg == NULL)
5752 return;
5753 }
5754
5755 /* Collect information about either all the windows across all the tab
5756 * pages or one particular window.
5757 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005758 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005759 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005760 tabnr++;
5761 winnr = 0;
5762 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005763 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005764 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005765 if (wparg != NULL && wp != wparg)
5766 continue;
5767 d = get_win_info(wp, tabnr, winnr);
5768 if (d != NULL)
5769 list_append_dict(rettv->vval.v_list, d);
5770 if (wparg != NULL)
5771 /* found information about a specific window */
5772 return;
5773 }
5774 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005775}
5776
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005777/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005778 * "win_findbuf()" function
5779 */
5780 static void
5781f_win_findbuf(typval_T *argvars, typval_T *rettv)
5782{
5783 if (rettv_list_alloc(rettv) != FAIL)
5784 win_findbuf(argvars, rettv->vval.v_list);
5785}
5786
5787/*
5788 * "win_getid()" function
5789 */
5790 static void
5791f_win_getid(typval_T *argvars, typval_T *rettv)
5792{
5793 rettv->vval.v_number = win_getid(argvars);
5794}
5795
5796/*
5797 * "win_gotoid()" function
5798 */
5799 static void
5800f_win_gotoid(typval_T *argvars, typval_T *rettv)
5801{
5802 rettv->vval.v_number = win_gotoid(argvars);
5803}
5804
5805/*
5806 * "win_id2tabwin()" function
5807 */
5808 static void
5809f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5810{
5811 if (rettv_list_alloc(rettv) != FAIL)
5812 win_id2tabwin(argvars, rettv->vval.v_list);
5813}
5814
5815/*
5816 * "win_id2win()" function
5817 */
5818 static void
5819f_win_id2win(typval_T *argvars, typval_T *rettv)
5820{
5821 rettv->vval.v_number = win_id2win(argvars);
5822}
5823
5824/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005825 * "win_screenpos()" function
5826 */
5827 static void
5828f_win_screenpos(typval_T *argvars, typval_T *rettv)
5829{
5830 win_T *wp;
5831
5832 if (rettv_list_alloc(rettv) == FAIL)
5833 return;
5834
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005835 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005836 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5837 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5838}
5839
5840/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005841 * "getwinpos({timeout})" function
5842 */
5843 static void
5844f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5845{
5846 int x = -1;
5847 int y = -1;
5848
5849 if (rettv_list_alloc(rettv) == FAIL)
5850 return;
5851#ifdef FEAT_GUI
5852 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005853 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005854# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5855 else
5856# endif
5857#endif
5858#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5859 {
5860 varnumber_T timeout = 100;
5861
5862 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005863 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005864 term_get_winpos(&x, &y, timeout);
5865 }
5866#endif
5867 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5868 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5869}
5870
5871
5872/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005873 * "getwinposx()" function
5874 */
5875 static void
5876f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5877{
5878 rettv->vval.v_number = -1;
5879#ifdef FEAT_GUI
5880 if (gui.in_use)
5881 {
5882 int x, y;
5883
5884 if (gui_mch_get_winpos(&x, &y) == OK)
5885 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005886 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005887 }
5888#endif
5889#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5890 {
5891 int x, y;
5892
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005893 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005894 rettv->vval.v_number = x;
5895 }
5896#endif
5897}
5898
5899/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900 * "getwinposy()" function
5901 */
5902 static void
5903f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5904{
5905 rettv->vval.v_number = -1;
5906#ifdef FEAT_GUI
5907 if (gui.in_use)
5908 {
5909 int x, y;
5910
5911 if (gui_mch_get_winpos(&x, &y) == OK)
5912 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005913 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914 }
5915#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005916#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5917 {
5918 int x, y;
5919
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005920 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005921 rettv->vval.v_number = y;
5922 }
5923#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005924}
5925
5926/*
5927 * "getwinvar()" function
5928 */
5929 static void
5930f_getwinvar(typval_T *argvars, typval_T *rettv)
5931{
5932 getwinvar(argvars, rettv, 0);
5933}
5934
5935/*
5936 * "glob()" function
5937 */
5938 static void
5939f_glob(typval_T *argvars, typval_T *rettv)
5940{
5941 int options = WILD_SILENT|WILD_USE_NL;
5942 expand_T xpc;
5943 int error = FALSE;
5944
5945 /* When the optional second argument is non-zero, don't remove matches
5946 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5947 rettv->v_type = VAR_STRING;
5948 if (argvars[1].v_type != VAR_UNKNOWN)
5949 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005950 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005951 options |= WILD_KEEP_ALL;
5952 if (argvars[2].v_type != VAR_UNKNOWN)
5953 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005954 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005955 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005956 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005957 }
5958 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005959 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005960 options |= WILD_ALLLINKS;
5961 }
5962 }
5963 if (!error)
5964 {
5965 ExpandInit(&xpc);
5966 xpc.xp_context = EXPAND_FILES;
5967 if (p_wic)
5968 options += WILD_ICASE;
5969 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005970 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005971 NULL, options, WILD_ALL);
5972 else if (rettv_list_alloc(rettv) != FAIL)
5973 {
5974 int i;
5975
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005976 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005977 NULL, options, WILD_ALL_KEEP);
5978 for (i = 0; i < xpc.xp_numfiles; i++)
5979 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5980
5981 ExpandCleanup(&xpc);
5982 }
5983 }
5984 else
5985 rettv->vval.v_string = NULL;
5986}
5987
5988/*
5989 * "globpath()" function
5990 */
5991 static void
5992f_globpath(typval_T *argvars, typval_T *rettv)
5993{
5994 int flags = 0;
5995 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005996 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997 int error = FALSE;
5998 garray_T ga;
5999 int i;
6000
6001 /* When the optional second argument is non-zero, don't remove matches
6002 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6003 rettv->v_type = VAR_STRING;
6004 if (argvars[2].v_type != VAR_UNKNOWN)
6005 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006006 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006007 flags |= WILD_KEEP_ALL;
6008 if (argvars[3].v_type != VAR_UNKNOWN)
6009 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006010 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006011 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006012 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006013 }
6014 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006015 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006016 flags |= WILD_ALLLINKS;
6017 }
6018 }
6019 if (file != NULL && !error)
6020 {
6021 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006022 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 if (rettv->v_type == VAR_STRING)
6024 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6025 else if (rettv_list_alloc(rettv) != FAIL)
6026 for (i = 0; i < ga.ga_len; ++i)
6027 list_append_string(rettv->vval.v_list,
6028 ((char_u **)(ga.ga_data))[i], -1);
6029 ga_clear_strings(&ga);
6030 }
6031 else
6032 rettv->vval.v_string = NULL;
6033}
6034
6035/*
6036 * "glob2regpat()" function
6037 */
6038 static void
6039f_glob2regpat(typval_T *argvars, typval_T *rettv)
6040{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006041 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006042
6043 rettv->v_type = VAR_STRING;
6044 rettv->vval.v_string = (pat == NULL)
6045 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6046}
6047
6048/* for VIM_VERSION_ defines */
6049#include "version.h"
6050
6051/*
6052 * "has()" function
6053 */
6054 static void
6055f_has(typval_T *argvars, typval_T *rettv)
6056{
6057 int i;
6058 char_u *name;
6059 int n = FALSE;
6060 static char *(has_list[]) =
6061 {
6062#ifdef AMIGA
6063 "amiga",
6064# ifdef FEAT_ARP
6065 "arp",
6066# endif
6067#endif
6068#ifdef __BEOS__
6069 "beos",
6070#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006071#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006072 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6073 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006074# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006075 "macunix", /* Mac OS X, with the darwin feature */
6076 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006077# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006078#endif
6079#ifdef __QNX__
6080 "qnx",
6081#endif
6082#ifdef UNIX
6083 "unix",
6084#endif
6085#ifdef VMS
6086 "vms",
6087#endif
6088#ifdef WIN32
6089 "win32",
6090#endif
6091#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6092 "win32unix",
6093#endif
6094#if defined(WIN64) || defined(_WIN64)
6095 "win64",
6096#endif
6097#ifdef EBCDIC
6098 "ebcdic",
6099#endif
6100#ifndef CASE_INSENSITIVE_FILENAME
6101 "fname_case",
6102#endif
6103#ifdef HAVE_ACL
6104 "acl",
6105#endif
6106#ifdef FEAT_ARABIC
6107 "arabic",
6108#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006109 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006110#ifdef FEAT_AUTOCHDIR
6111 "autochdir",
6112#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006113#ifdef FEAT_AUTOSERVERNAME
6114 "autoservername",
6115#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006116#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006117 "balloon_eval",
6118# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6119 "balloon_multiline",
6120# endif
6121#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006122#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006123 "balloon_eval_term",
6124#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006125#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6126 "builtin_terms",
6127# ifdef ALL_BUILTIN_TCAPS
6128 "all_builtin_terms",
6129# endif
6130#endif
6131#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6132 || defined(FEAT_GUI_W32) \
6133 || defined(FEAT_GUI_MOTIF))
6134 "browsefilter",
6135#endif
6136#ifdef FEAT_BYTEOFF
6137 "byte_offset",
6138#endif
6139#ifdef FEAT_JOB_CHANNEL
6140 "channel",
6141#endif
6142#ifdef FEAT_CINDENT
6143 "cindent",
6144#endif
6145#ifdef FEAT_CLIENTSERVER
6146 "clientserver",
6147#endif
6148#ifdef FEAT_CLIPBOARD
6149 "clipboard",
6150#endif
6151#ifdef FEAT_CMDL_COMPL
6152 "cmdline_compl",
6153#endif
6154#ifdef FEAT_CMDHIST
6155 "cmdline_hist",
6156#endif
6157#ifdef FEAT_COMMENTS
6158 "comments",
6159#endif
6160#ifdef FEAT_CONCEAL
6161 "conceal",
6162#endif
6163#ifdef FEAT_CRYPT
6164 "cryptv",
6165 "crypt-blowfish",
6166 "crypt-blowfish2",
6167#endif
6168#ifdef FEAT_CSCOPE
6169 "cscope",
6170#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006171 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006172#ifdef CURSOR_SHAPE
6173 "cursorshape",
6174#endif
6175#ifdef DEBUG
6176 "debug",
6177#endif
6178#ifdef FEAT_CON_DIALOG
6179 "dialog_con",
6180#endif
6181#ifdef FEAT_GUI_DIALOG
6182 "dialog_gui",
6183#endif
6184#ifdef FEAT_DIFF
6185 "diff",
6186#endif
6187#ifdef FEAT_DIGRAPHS
6188 "digraphs",
6189#endif
6190#ifdef FEAT_DIRECTX
6191 "directx",
6192#endif
6193#ifdef FEAT_DND
6194 "dnd",
6195#endif
6196#ifdef FEAT_EMACS_TAGS
6197 "emacs_tags",
6198#endif
6199 "eval", /* always present, of course! */
6200 "ex_extra", /* graduated feature */
6201#ifdef FEAT_SEARCH_EXTRA
6202 "extra_search",
6203#endif
6204#ifdef FEAT_FKMAP
6205 "farsi",
6206#endif
6207#ifdef FEAT_SEARCHPATH
6208 "file_in_path",
6209#endif
6210#ifdef FEAT_FILTERPIPE
6211 "filterpipe",
6212#endif
6213#ifdef FEAT_FIND_ID
6214 "find_in_path",
6215#endif
6216#ifdef FEAT_FLOAT
6217 "float",
6218#endif
6219#ifdef FEAT_FOLDING
6220 "folding",
6221#endif
6222#ifdef FEAT_FOOTER
6223 "footer",
6224#endif
6225#if !defined(USE_SYSTEM) && defined(UNIX)
6226 "fork",
6227#endif
6228#ifdef FEAT_GETTEXT
6229 "gettext",
6230#endif
6231#ifdef FEAT_GUI
6232 "gui",
6233#endif
6234#ifdef FEAT_GUI_ATHENA
6235# ifdef FEAT_GUI_NEXTAW
6236 "gui_neXtaw",
6237# else
6238 "gui_athena",
6239# endif
6240#endif
6241#ifdef FEAT_GUI_GTK
6242 "gui_gtk",
6243# ifdef USE_GTK3
6244 "gui_gtk3",
6245# else
6246 "gui_gtk2",
6247# endif
6248#endif
6249#ifdef FEAT_GUI_GNOME
6250 "gui_gnome",
6251#endif
6252#ifdef FEAT_GUI_MAC
6253 "gui_mac",
6254#endif
6255#ifdef FEAT_GUI_MOTIF
6256 "gui_motif",
6257#endif
6258#ifdef FEAT_GUI_PHOTON
6259 "gui_photon",
6260#endif
6261#ifdef FEAT_GUI_W32
6262 "gui_win32",
6263#endif
6264#ifdef FEAT_HANGULIN
6265 "hangul_input",
6266#endif
6267#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6268 "iconv",
6269#endif
6270#ifdef FEAT_INS_EXPAND
6271 "insert_expand",
6272#endif
6273#ifdef FEAT_JOB_CHANNEL
6274 "job",
6275#endif
6276#ifdef FEAT_JUMPLIST
6277 "jumplist",
6278#endif
6279#ifdef FEAT_KEYMAP
6280 "keymap",
6281#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006282 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283#ifdef FEAT_LANGMAP
6284 "langmap",
6285#endif
6286#ifdef FEAT_LIBCALL
6287 "libcall",
6288#endif
6289#ifdef FEAT_LINEBREAK
6290 "linebreak",
6291#endif
6292#ifdef FEAT_LISP
6293 "lispindent",
6294#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006295 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006296#ifdef FEAT_LOCALMAP
6297 "localmap",
6298#endif
6299#ifdef FEAT_LUA
6300# ifndef DYNAMIC_LUA
6301 "lua",
6302# endif
6303#endif
6304#ifdef FEAT_MENU
6305 "menu",
6306#endif
6307#ifdef FEAT_SESSION
6308 "mksession",
6309#endif
6310#ifdef FEAT_MODIFY_FNAME
6311 "modify_fname",
6312#endif
6313#ifdef FEAT_MOUSE
6314 "mouse",
6315#endif
6316#ifdef FEAT_MOUSESHAPE
6317 "mouseshape",
6318#endif
6319#if defined(UNIX) || defined(VMS)
6320# ifdef FEAT_MOUSE_DEC
6321 "mouse_dec",
6322# endif
6323# ifdef FEAT_MOUSE_GPM
6324 "mouse_gpm",
6325# endif
6326# ifdef FEAT_MOUSE_JSB
6327 "mouse_jsbterm",
6328# endif
6329# ifdef FEAT_MOUSE_NET
6330 "mouse_netterm",
6331# endif
6332# ifdef FEAT_MOUSE_PTERM
6333 "mouse_pterm",
6334# endif
6335# ifdef FEAT_MOUSE_SGR
6336 "mouse_sgr",
6337# endif
6338# ifdef FEAT_SYSMOUSE
6339 "mouse_sysmouse",
6340# endif
6341# ifdef FEAT_MOUSE_URXVT
6342 "mouse_urxvt",
6343# endif
6344# ifdef FEAT_MOUSE_XTERM
6345 "mouse_xterm",
6346# endif
6347#endif
6348#ifdef FEAT_MBYTE
6349 "multi_byte",
6350#endif
6351#ifdef FEAT_MBYTE_IME
6352 "multi_byte_ime",
6353#endif
6354#ifdef FEAT_MULTI_LANG
6355 "multi_lang",
6356#endif
6357#ifdef FEAT_MZSCHEME
6358#ifndef DYNAMIC_MZSCHEME
6359 "mzscheme",
6360#endif
6361#endif
6362#ifdef FEAT_NUM64
6363 "num64",
6364#endif
6365#ifdef FEAT_OLE
6366 "ole",
6367#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006368#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006369 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006370#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006371#ifdef FEAT_PATH_EXTRA
6372 "path_extra",
6373#endif
6374#ifdef FEAT_PERL
6375#ifndef DYNAMIC_PERL
6376 "perl",
6377#endif
6378#endif
6379#ifdef FEAT_PERSISTENT_UNDO
6380 "persistent_undo",
6381#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006382#if defined(FEAT_PYTHON)
6383 "python_compiled",
6384# if defined(DYNAMIC_PYTHON)
6385 "python_dynamic",
6386# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006387 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006388 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006389# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006390#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006391#if defined(FEAT_PYTHON3)
6392 "python3_compiled",
6393# if defined(DYNAMIC_PYTHON3)
6394 "python3_dynamic",
6395# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006397 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006398# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006399#endif
6400#ifdef FEAT_POSTSCRIPT
6401 "postscript",
6402#endif
6403#ifdef FEAT_PRINTER
6404 "printer",
6405#endif
6406#ifdef FEAT_PROFILE
6407 "profile",
6408#endif
6409#ifdef FEAT_RELTIME
6410 "reltime",
6411#endif
6412#ifdef FEAT_QUICKFIX
6413 "quickfix",
6414#endif
6415#ifdef FEAT_RIGHTLEFT
6416 "rightleft",
6417#endif
6418#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6419 "ruby",
6420#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422#ifdef FEAT_CMDL_INFO
6423 "showcmd",
6424 "cmdline_info",
6425#endif
6426#ifdef FEAT_SIGNS
6427 "signs",
6428#endif
6429#ifdef FEAT_SMARTINDENT
6430 "smartindent",
6431#endif
6432#ifdef STARTUPTIME
6433 "startuptime",
6434#endif
6435#ifdef FEAT_STL_OPT
6436 "statusline",
6437#endif
6438#ifdef FEAT_SUN_WORKSHOP
6439 "sun_workshop",
6440#endif
6441#ifdef FEAT_NETBEANS_INTG
6442 "netbeans_intg",
6443#endif
6444#ifdef FEAT_SPELL
6445 "spell",
6446#endif
6447#ifdef FEAT_SYN_HL
6448 "syntax",
6449#endif
6450#if defined(USE_SYSTEM) || !defined(UNIX)
6451 "system",
6452#endif
6453#ifdef FEAT_TAG_BINS
6454 "tag_binary",
6455#endif
6456#ifdef FEAT_TAG_OLDSTATIC
6457 "tag_old_static",
6458#endif
6459#ifdef FEAT_TAG_ANYWHITE
6460 "tag_any_white",
6461#endif
6462#ifdef FEAT_TCL
6463# ifndef DYNAMIC_TCL
6464 "tcl",
6465# endif
6466#endif
6467#ifdef FEAT_TERMGUICOLORS
6468 "termguicolors",
6469#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006470#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006471 "terminal",
6472#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473#ifdef TERMINFO
6474 "terminfo",
6475#endif
6476#ifdef FEAT_TERMRESPONSE
6477 "termresponse",
6478#endif
6479#ifdef FEAT_TEXTOBJ
6480 "textobjects",
6481#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006482#ifdef FEAT_TEXT_PROP
6483 "textprop",
6484#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485#ifdef HAVE_TGETENT
6486 "tgetent",
6487#endif
6488#ifdef FEAT_TIMERS
6489 "timers",
6490#endif
6491#ifdef FEAT_TITLE
6492 "title",
6493#endif
6494#ifdef FEAT_TOOLBAR
6495 "toolbar",
6496#endif
6497#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6498 "unnamedplus",
6499#endif
6500#ifdef FEAT_USR_CMDS
6501 "user-commands", /* was accidentally included in 5.4 */
6502 "user_commands",
6503#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006504#ifdef FEAT_VARTABS
6505 "vartabs",
6506#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507#ifdef FEAT_VIMINFO
6508 "viminfo",
6509#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006510 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006511#ifdef FEAT_VIRTUALEDIT
6512 "virtualedit",
6513#endif
6514 "visual",
6515#ifdef FEAT_VISUALEXTRA
6516 "visualextra",
6517#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006518 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006519#ifdef FEAT_VTP
6520 "vtp",
6521#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006522#ifdef FEAT_WILDIGN
6523 "wildignore",
6524#endif
6525#ifdef FEAT_WILDMENU
6526 "wildmenu",
6527#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006528 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006529#ifdef FEAT_WAK
6530 "winaltkeys",
6531#endif
6532#ifdef FEAT_WRITEBACKUP
6533 "writebackup",
6534#endif
6535#ifdef FEAT_XIM
6536 "xim",
6537#endif
6538#ifdef FEAT_XFONTSET
6539 "xfontset",
6540#endif
6541#ifdef FEAT_XPM_W32
6542 "xpm",
6543 "xpm_w32", /* for backward compatibility */
6544#else
6545# if defined(HAVE_XPM)
6546 "xpm",
6547# endif
6548#endif
6549#ifdef USE_XSMP
6550 "xsmp",
6551#endif
6552#ifdef USE_XSMP_INTERACT
6553 "xsmp_interact",
6554#endif
6555#ifdef FEAT_XCLIPBOARD
6556 "xterm_clipboard",
6557#endif
6558#ifdef FEAT_XTERM_SAVE
6559 "xterm_save",
6560#endif
6561#if defined(UNIX) && defined(FEAT_X11)
6562 "X11",
6563#endif
6564 NULL
6565 };
6566
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006567 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568 for (i = 0; has_list[i] != NULL; ++i)
6569 if (STRICMP(name, has_list[i]) == 0)
6570 {
6571 n = TRUE;
6572 break;
6573 }
6574
6575 if (n == FALSE)
6576 {
6577 if (STRNICMP(name, "patch", 5) == 0)
6578 {
6579 if (name[5] == '-'
6580 && STRLEN(name) >= 11
6581 && vim_isdigit(name[6])
6582 && vim_isdigit(name[8])
6583 && vim_isdigit(name[10]))
6584 {
6585 int major = atoi((char *)name + 6);
6586 int minor = atoi((char *)name + 8);
6587
6588 /* Expect "patch-9.9.01234". */
6589 n = (major < VIM_VERSION_MAJOR
6590 || (major == VIM_VERSION_MAJOR
6591 && (minor < VIM_VERSION_MINOR
6592 || (minor == VIM_VERSION_MINOR
6593 && has_patch(atoi((char *)name + 10))))));
6594 }
6595 else
6596 n = has_patch(atoi((char *)name + 5));
6597 }
6598 else if (STRICMP(name, "vim_starting") == 0)
6599 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006600 else if (STRICMP(name, "ttyin") == 0)
6601 n = mch_input_isatty();
6602 else if (STRICMP(name, "ttyout") == 0)
6603 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006604#ifdef FEAT_MBYTE
6605 else if (STRICMP(name, "multi_byte_encoding") == 0)
6606 n = has_mbyte;
6607#endif
6608#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6609 else if (STRICMP(name, "balloon_multiline") == 0)
6610 n = multiline_balloon_available();
6611#endif
6612#ifdef DYNAMIC_TCL
6613 else if (STRICMP(name, "tcl") == 0)
6614 n = tcl_enabled(FALSE);
6615#endif
6616#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6617 else if (STRICMP(name, "iconv") == 0)
6618 n = iconv_enabled(FALSE);
6619#endif
6620#ifdef DYNAMIC_LUA
6621 else if (STRICMP(name, "lua") == 0)
6622 n = lua_enabled(FALSE);
6623#endif
6624#ifdef DYNAMIC_MZSCHEME
6625 else if (STRICMP(name, "mzscheme") == 0)
6626 n = mzscheme_enabled(FALSE);
6627#endif
6628#ifdef DYNAMIC_RUBY
6629 else if (STRICMP(name, "ruby") == 0)
6630 n = ruby_enabled(FALSE);
6631#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006632#ifdef DYNAMIC_PYTHON
6633 else if (STRICMP(name, "python") == 0)
6634 n = python_enabled(FALSE);
6635#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006636#ifdef DYNAMIC_PYTHON3
6637 else if (STRICMP(name, "python3") == 0)
6638 n = python3_enabled(FALSE);
6639#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006640#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6641 else if (STRICMP(name, "pythonx") == 0)
6642 {
6643# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6644 if (p_pyx == 0)
6645 n = python3_enabled(FALSE) || python_enabled(FALSE);
6646 else if (p_pyx == 3)
6647 n = python3_enabled(FALSE);
6648 else if (p_pyx == 2)
6649 n = python_enabled(FALSE);
6650# elif defined(DYNAMIC_PYTHON)
6651 n = python_enabled(FALSE);
6652# elif defined(DYNAMIC_PYTHON3)
6653 n = python3_enabled(FALSE);
6654# endif
6655 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006656#endif
6657#ifdef DYNAMIC_PERL
6658 else if (STRICMP(name, "perl") == 0)
6659 n = perl_enabled(FALSE);
6660#endif
6661#ifdef FEAT_GUI
6662 else if (STRICMP(name, "gui_running") == 0)
6663 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006664# ifdef FEAT_BROWSE
6665 else if (STRICMP(name, "browse") == 0)
6666 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6667# endif
6668#endif
6669#ifdef FEAT_SYN_HL
6670 else if (STRICMP(name, "syntax_items") == 0)
6671 n = syntax_present(curwin);
6672#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006673#ifdef FEAT_VTP
6674 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006675 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006676#endif
6677#ifdef FEAT_NETBEANS_INTG
6678 else if (STRICMP(name, "netbeans_enabled") == 0)
6679 n = netbeans_active();
6680#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006681#if defined(FEAT_TERMINAL) && defined(WIN3264)
6682 else if (STRICMP(name, "terminal") == 0)
6683 n = terminal_enabled();
6684#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685 }
6686
6687 rettv->vval.v_number = n;
6688}
6689
6690/*
6691 * "has_key()" function
6692 */
6693 static void
6694f_has_key(typval_T *argvars, typval_T *rettv)
6695{
6696 if (argvars[0].v_type != VAR_DICT)
6697 {
6698 EMSG(_(e_dictreq));
6699 return;
6700 }
6701 if (argvars[0].vval.v_dict == NULL)
6702 return;
6703
6704 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006705 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006706}
6707
6708/*
6709 * "haslocaldir()" function
6710 */
6711 static void
6712f_haslocaldir(typval_T *argvars, typval_T *rettv)
6713{
6714 win_T *wp = NULL;
6715
6716 wp = find_tabwin(&argvars[0], &argvars[1]);
6717 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6718}
6719
6720/*
6721 * "hasmapto()" function
6722 */
6723 static void
6724f_hasmapto(typval_T *argvars, typval_T *rettv)
6725{
6726 char_u *name;
6727 char_u *mode;
6728 char_u buf[NUMBUFLEN];
6729 int abbr = FALSE;
6730
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006731 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006732 if (argvars[1].v_type == VAR_UNKNOWN)
6733 mode = (char_u *)"nvo";
6734 else
6735 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006736 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006738 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 }
6740
6741 if (map_to_exists(name, mode, abbr))
6742 rettv->vval.v_number = TRUE;
6743 else
6744 rettv->vval.v_number = FALSE;
6745}
6746
6747/*
6748 * "histadd()" function
6749 */
6750 static void
6751f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6752{
6753#ifdef FEAT_CMDHIST
6754 int histype;
6755 char_u *str;
6756 char_u buf[NUMBUFLEN];
6757#endif
6758
6759 rettv->vval.v_number = FALSE;
6760 if (check_restricted() || check_secure())
6761 return;
6762#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006763 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006764 histype = str != NULL ? get_histtype(str) : -1;
6765 if (histype >= 0)
6766 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006767 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 if (*str != NUL)
6769 {
6770 init_history();
6771 add_to_history(histype, str, FALSE, NUL);
6772 rettv->vval.v_number = TRUE;
6773 return;
6774 }
6775 }
6776#endif
6777}
6778
6779/*
6780 * "histdel()" function
6781 */
6782 static void
6783f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6784{
6785#ifdef FEAT_CMDHIST
6786 int n;
6787 char_u buf[NUMBUFLEN];
6788 char_u *str;
6789
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006790 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006791 if (str == NULL)
6792 n = 0;
6793 else if (argvars[1].v_type == VAR_UNKNOWN)
6794 /* only one argument: clear entire history */
6795 n = clr_history(get_histtype(str));
6796 else if (argvars[1].v_type == VAR_NUMBER)
6797 /* index given: remove that entry */
6798 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006799 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006800 else
6801 /* string given: remove all matching entries */
6802 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006803 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804 rettv->vval.v_number = n;
6805#endif
6806}
6807
6808/*
6809 * "histget()" function
6810 */
6811 static void
6812f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6813{
6814#ifdef FEAT_CMDHIST
6815 int type;
6816 int idx;
6817 char_u *str;
6818
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006819 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006820 if (str == NULL)
6821 rettv->vval.v_string = NULL;
6822 else
6823 {
6824 type = get_histtype(str);
6825 if (argvars[1].v_type == VAR_UNKNOWN)
6826 idx = get_history_idx(type);
6827 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006828 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006829 /* -1 on type error */
6830 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6831 }
6832#else
6833 rettv->vval.v_string = NULL;
6834#endif
6835 rettv->v_type = VAR_STRING;
6836}
6837
6838/*
6839 * "histnr()" function
6840 */
6841 static void
6842f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6843{
6844 int i;
6845
6846#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006847 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006848
6849 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6850 if (i >= HIST_CMD && i < HIST_COUNT)
6851 i = get_history_idx(i);
6852 else
6853#endif
6854 i = -1;
6855 rettv->vval.v_number = i;
6856}
6857
6858/*
6859 * "highlightID(name)" function
6860 */
6861 static void
6862f_hlID(typval_T *argvars, typval_T *rettv)
6863{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006864 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865}
6866
6867/*
6868 * "highlight_exists()" function
6869 */
6870 static void
6871f_hlexists(typval_T *argvars, typval_T *rettv)
6872{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006873 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874}
6875
6876/*
6877 * "hostname()" function
6878 */
6879 static void
6880f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6881{
6882 char_u hostname[256];
6883
6884 mch_get_host_name(hostname, 256);
6885 rettv->v_type = VAR_STRING;
6886 rettv->vval.v_string = vim_strsave(hostname);
6887}
6888
6889/*
6890 * iconv() function
6891 */
6892 static void
6893f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6894{
6895#ifdef FEAT_MBYTE
6896 char_u buf1[NUMBUFLEN];
6897 char_u buf2[NUMBUFLEN];
6898 char_u *from, *to, *str;
6899 vimconv_T vimconv;
6900#endif
6901
6902 rettv->v_type = VAR_STRING;
6903 rettv->vval.v_string = NULL;
6904
6905#ifdef FEAT_MBYTE
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006906 str = tv_get_string(&argvars[0]);
6907 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6908 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006909 vimconv.vc_type = CONV_NONE;
6910 convert_setup(&vimconv, from, to);
6911
6912 /* If the encodings are equal, no conversion needed. */
6913 if (vimconv.vc_type == CONV_NONE)
6914 rettv->vval.v_string = vim_strsave(str);
6915 else
6916 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6917
6918 convert_setup(&vimconv, NULL, NULL);
6919 vim_free(from);
6920 vim_free(to);
6921#endif
6922}
6923
6924/*
6925 * "indent()" function
6926 */
6927 static void
6928f_indent(typval_T *argvars, typval_T *rettv)
6929{
6930 linenr_T lnum;
6931
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006932 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006933 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6934 rettv->vval.v_number = get_indent_lnum(lnum);
6935 else
6936 rettv->vval.v_number = -1;
6937}
6938
6939/*
6940 * "index()" function
6941 */
6942 static void
6943f_index(typval_T *argvars, typval_T *rettv)
6944{
6945 list_T *l;
6946 listitem_T *item;
6947 long idx = 0;
6948 int ic = FALSE;
6949
6950 rettv->vval.v_number = -1;
6951 if (argvars[0].v_type != VAR_LIST)
6952 {
6953 EMSG(_(e_listreq));
6954 return;
6955 }
6956 l = argvars[0].vval.v_list;
6957 if (l != NULL)
6958 {
6959 item = l->lv_first;
6960 if (argvars[2].v_type != VAR_UNKNOWN)
6961 {
6962 int error = FALSE;
6963
6964 /* Start at specified item. Use the cached index that list_find()
6965 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006966 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006967 idx = l->lv_idx;
6968 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006969 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 if (error)
6971 item = NULL;
6972 }
6973
6974 for ( ; item != NULL; item = item->li_next, ++idx)
6975 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6976 {
6977 rettv->vval.v_number = idx;
6978 break;
6979 }
6980 }
6981}
6982
6983static int inputsecret_flag = 0;
6984
6985/*
6986 * "input()" function
6987 * Also handles inputsecret() when inputsecret is set.
6988 */
6989 static void
6990f_input(typval_T *argvars, typval_T *rettv)
6991{
6992 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6993}
6994
6995/*
6996 * "inputdialog()" function
6997 */
6998 static void
6999f_inputdialog(typval_T *argvars, typval_T *rettv)
7000{
7001#if defined(FEAT_GUI_TEXTDIALOG)
7002 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7003 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7004 {
7005 char_u *message;
7006 char_u buf[NUMBUFLEN];
7007 char_u *defstr = (char_u *)"";
7008
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007009 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007011 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007012 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7013 else
7014 IObuff[0] = NUL;
7015 if (message != NULL && defstr != NULL
7016 && do_dialog(VIM_QUESTION, NULL, message,
7017 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7018 rettv->vval.v_string = vim_strsave(IObuff);
7019 else
7020 {
7021 if (message != NULL && defstr != NULL
7022 && argvars[1].v_type != VAR_UNKNOWN
7023 && argvars[2].v_type != VAR_UNKNOWN)
7024 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007025 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007026 else
7027 rettv->vval.v_string = NULL;
7028 }
7029 rettv->v_type = VAR_STRING;
7030 }
7031 else
7032#endif
7033 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7034}
7035
7036/*
7037 * "inputlist()" function
7038 */
7039 static void
7040f_inputlist(typval_T *argvars, typval_T *rettv)
7041{
7042 listitem_T *li;
7043 int selected;
7044 int mouse_used;
7045
7046#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007047 /* While starting up, there is no place to enter text. When running tests
7048 * with --not-a-term we assume feedkeys() will be used. */
7049 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007050 return;
7051#endif
7052 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7053 {
7054 EMSG2(_(e_listarg), "inputlist()");
7055 return;
7056 }
7057
7058 msg_start();
7059 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7060 lines_left = Rows; /* avoid more prompt */
7061 msg_scroll = TRUE;
7062 msg_clr_eos();
7063
7064 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7065 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007066 msg_puts(tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007067 msg_putchar('\n');
7068 }
7069
7070 /* Ask for choice. */
7071 selected = prompt_for_number(&mouse_used);
7072 if (mouse_used)
7073 selected -= lines_left;
7074
7075 rettv->vval.v_number = selected;
7076}
7077
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7079
7080/*
7081 * "inputrestore()" function
7082 */
7083 static void
7084f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7085{
7086 if (ga_userinput.ga_len > 0)
7087 {
7088 --ga_userinput.ga_len;
7089 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7090 + ga_userinput.ga_len);
7091 /* default return is zero == OK */
7092 }
7093 else if (p_verbose > 1)
7094 {
7095 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
7096 rettv->vval.v_number = 1; /* Failed */
7097 }
7098}
7099
7100/*
7101 * "inputsave()" function
7102 */
7103 static void
7104f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7105{
7106 /* Add an entry to the stack of typeahead storage. */
7107 if (ga_grow(&ga_userinput, 1) == OK)
7108 {
7109 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7110 + ga_userinput.ga_len);
7111 ++ga_userinput.ga_len;
7112 /* default return is zero == OK */
7113 }
7114 else
7115 rettv->vval.v_number = 1; /* Failed */
7116}
7117
7118/*
7119 * "inputsecret()" function
7120 */
7121 static void
7122f_inputsecret(typval_T *argvars, typval_T *rettv)
7123{
7124 ++cmdline_star;
7125 ++inputsecret_flag;
7126 f_input(argvars, rettv);
7127 --cmdline_star;
7128 --inputsecret_flag;
7129}
7130
7131/*
7132 * "insert()" function
7133 */
7134 static void
7135f_insert(typval_T *argvars, typval_T *rettv)
7136{
7137 long before = 0;
7138 listitem_T *item;
7139 list_T *l;
7140 int error = FALSE;
7141
7142 if (argvars[0].v_type != VAR_LIST)
7143 EMSG2(_(e_listarg), "insert()");
7144 else if ((l = argvars[0].vval.v_list) != NULL
7145 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7146 {
7147 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007148 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007149 if (error)
7150 return; /* type error; errmsg already given */
7151
7152 if (before == l->lv_len)
7153 item = NULL;
7154 else
7155 {
7156 item = list_find(l, before);
7157 if (item == NULL)
7158 {
7159 EMSGN(_(e_listidx), before);
7160 l = NULL;
7161 }
7162 }
7163 if (l != NULL)
7164 {
7165 list_insert_tv(l, &argvars[1], item);
7166 copy_tv(&argvars[0], rettv);
7167 }
7168 }
7169}
7170
7171/*
7172 * "invert(expr)" function
7173 */
7174 static void
7175f_invert(typval_T *argvars, typval_T *rettv)
7176{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007177 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007178}
7179
7180/*
7181 * "isdirectory()" function
7182 */
7183 static void
7184f_isdirectory(typval_T *argvars, typval_T *rettv)
7185{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007186 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187}
7188
7189/*
7190 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7191 * or it refers to a List or Dictionary that is locked.
7192 */
7193 static int
7194tv_islocked(typval_T *tv)
7195{
7196 return (tv->v_lock & VAR_LOCKED)
7197 || (tv->v_type == VAR_LIST
7198 && tv->vval.v_list != NULL
7199 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7200 || (tv->v_type == VAR_DICT
7201 && tv->vval.v_dict != NULL
7202 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7203}
7204
7205/*
7206 * "islocked()" function
7207 */
7208 static void
7209f_islocked(typval_T *argvars, typval_T *rettv)
7210{
7211 lval_T lv;
7212 char_u *end;
7213 dictitem_T *di;
7214
7215 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007216 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007217 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218 if (end != NULL && lv.ll_name != NULL)
7219 {
7220 if (*end != NUL)
7221 EMSG(_(e_trailing));
7222 else
7223 {
7224 if (lv.ll_tv == NULL)
7225 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007226 di = find_var(lv.ll_name, NULL, TRUE);
7227 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007229 /* Consider a variable locked when:
7230 * 1. the variable itself is locked
7231 * 2. the value of the variable is locked.
7232 * 3. the List or Dict value is locked.
7233 */
7234 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7235 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 }
7237 }
7238 else if (lv.ll_range)
7239 EMSG(_("E786: Range not allowed"));
7240 else if (lv.ll_newkey != NULL)
7241 EMSG2(_(e_dictkey), lv.ll_newkey);
7242 else if (lv.ll_list != NULL)
7243 /* List item. */
7244 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7245 else
7246 /* Dictionary item. */
7247 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7248 }
7249 }
7250
7251 clear_lval(&lv);
7252}
7253
7254#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7255/*
7256 * "isnan()" function
7257 */
7258 static void
7259f_isnan(typval_T *argvars, typval_T *rettv)
7260{
7261 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7262 && isnan(argvars[0].vval.v_float);
7263}
7264#endif
7265
7266/*
7267 * "items(dict)" function
7268 */
7269 static void
7270f_items(typval_T *argvars, typval_T *rettv)
7271{
7272 dict_list(argvars, rettv, 2);
7273}
7274
7275#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7276/*
7277 * Get the job from the argument.
7278 * Returns NULL if the job is invalid.
7279 */
7280 static job_T *
7281get_job_arg(typval_T *tv)
7282{
7283 job_T *job;
7284
7285 if (tv->v_type != VAR_JOB)
7286 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007287 EMSG2(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 return NULL;
7289 }
7290 job = tv->vval.v_job;
7291
7292 if (job == NULL)
7293 EMSG(_("E916: not a valid job"));
7294 return job;
7295}
7296
7297/*
7298 * "job_getchannel()" function
7299 */
7300 static void
7301f_job_getchannel(typval_T *argvars, typval_T *rettv)
7302{
7303 job_T *job = get_job_arg(&argvars[0]);
7304
7305 if (job != NULL)
7306 {
7307 rettv->v_type = VAR_CHANNEL;
7308 rettv->vval.v_channel = job->jv_channel;
7309 if (job->jv_channel != NULL)
7310 ++job->jv_channel->ch_refcount;
7311 }
7312}
7313
7314/*
7315 * "job_info()" function
7316 */
7317 static void
7318f_job_info(typval_T *argvars, typval_T *rettv)
7319{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007320 if (argvars[0].v_type != VAR_UNKNOWN)
7321 {
7322 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007323
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007324 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7325 job_info(job, rettv->vval.v_dict);
7326 }
7327 else if (rettv_list_alloc(rettv) == OK)
7328 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007329}
7330
7331/*
7332 * "job_setoptions()" function
7333 */
7334 static void
7335f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7336{
7337 job_T *job = get_job_arg(&argvars[0]);
7338 jobopt_T opt;
7339
7340 if (job == NULL)
7341 return;
7342 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007343 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 job_set_options(job, &opt);
7345 free_job_options(&opt);
7346}
7347
7348/*
7349 * "job_start()" function
7350 */
7351 static void
7352f_job_start(typval_T *argvars, typval_T *rettv)
7353{
7354 rettv->v_type = VAR_JOB;
7355 if (check_restricted() || check_secure())
7356 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007357 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358}
7359
7360/*
7361 * "job_status()" function
7362 */
7363 static void
7364f_job_status(typval_T *argvars, typval_T *rettv)
7365{
7366 job_T *job = get_job_arg(&argvars[0]);
7367
7368 if (job != NULL)
7369 {
7370 rettv->v_type = VAR_STRING;
7371 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7372 }
7373}
7374
7375/*
7376 * "job_stop()" function
7377 */
7378 static void
7379f_job_stop(typval_T *argvars, typval_T *rettv)
7380{
7381 job_T *job = get_job_arg(&argvars[0]);
7382
7383 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007384 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007385}
7386#endif
7387
7388/*
7389 * "join()" function
7390 */
7391 static void
7392f_join(typval_T *argvars, typval_T *rettv)
7393{
7394 garray_T ga;
7395 char_u *sep;
7396
7397 if (argvars[0].v_type != VAR_LIST)
7398 {
7399 EMSG(_(e_listreq));
7400 return;
7401 }
7402 if (argvars[0].vval.v_list == NULL)
7403 return;
7404 if (argvars[1].v_type == VAR_UNKNOWN)
7405 sep = (char_u *)" ";
7406 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007407 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007408
7409 rettv->v_type = VAR_STRING;
7410
7411 if (sep != NULL)
7412 {
7413 ga_init2(&ga, (int)sizeof(char), 80);
7414 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7415 ga_append(&ga, NUL);
7416 rettv->vval.v_string = (char_u *)ga.ga_data;
7417 }
7418 else
7419 rettv->vval.v_string = NULL;
7420}
7421
7422/*
7423 * "js_decode()" function
7424 */
7425 static void
7426f_js_decode(typval_T *argvars, typval_T *rettv)
7427{
7428 js_read_T reader;
7429
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007430 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431 reader.js_fill = NULL;
7432 reader.js_used = 0;
7433 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7434 EMSG(_(e_invarg));
7435}
7436
7437/*
7438 * "js_encode()" function
7439 */
7440 static void
7441f_js_encode(typval_T *argvars, typval_T *rettv)
7442{
7443 rettv->v_type = VAR_STRING;
7444 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7445}
7446
7447/*
7448 * "json_decode()" function
7449 */
7450 static void
7451f_json_decode(typval_T *argvars, typval_T *rettv)
7452{
7453 js_read_T reader;
7454
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007455 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007456 reader.js_fill = NULL;
7457 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007458 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007459}
7460
7461/*
7462 * "json_encode()" function
7463 */
7464 static void
7465f_json_encode(typval_T *argvars, typval_T *rettv)
7466{
7467 rettv->v_type = VAR_STRING;
7468 rettv->vval.v_string = json_encode(&argvars[0], 0);
7469}
7470
7471/*
7472 * "keys()" function
7473 */
7474 static void
7475f_keys(typval_T *argvars, typval_T *rettv)
7476{
7477 dict_list(argvars, rettv, 0);
7478}
7479
7480/*
7481 * "last_buffer_nr()" function.
7482 */
7483 static void
7484f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7485{
7486 int n = 0;
7487 buf_T *buf;
7488
Bram Moolenaar29323592016-07-24 22:04:11 +02007489 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007490 if (n < buf->b_fnum)
7491 n = buf->b_fnum;
7492
7493 rettv->vval.v_number = n;
7494}
7495
7496/*
7497 * "len()" function
7498 */
7499 static void
7500f_len(typval_T *argvars, typval_T *rettv)
7501{
7502 switch (argvars[0].v_type)
7503 {
7504 case VAR_STRING:
7505 case VAR_NUMBER:
7506 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007507 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007508 break;
7509 case VAR_LIST:
7510 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7511 break;
7512 case VAR_DICT:
7513 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7514 break;
7515 case VAR_UNKNOWN:
7516 case VAR_SPECIAL:
7517 case VAR_FLOAT:
7518 case VAR_FUNC:
7519 case VAR_PARTIAL:
7520 case VAR_JOB:
7521 case VAR_CHANNEL:
7522 EMSG(_("E701: Invalid type for len()"));
7523 break;
7524 }
7525}
7526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007528libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529{
7530#ifdef FEAT_LIBCALL
7531 char_u *string_in;
7532 char_u **string_result;
7533 int nr_result;
7534#endif
7535
7536 rettv->v_type = type;
7537 if (type != VAR_NUMBER)
7538 rettv->vval.v_string = NULL;
7539
7540 if (check_restricted() || check_secure())
7541 return;
7542
7543#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007544 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007545 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7546 {
7547 string_in = NULL;
7548 if (argvars[2].v_type == VAR_STRING)
7549 string_in = argvars[2].vval.v_string;
7550 if (type == VAR_NUMBER)
7551 string_result = NULL;
7552 else
7553 string_result = &rettv->vval.v_string;
7554 if (mch_libcall(argvars[0].vval.v_string,
7555 argvars[1].vval.v_string,
7556 string_in,
7557 argvars[2].vval.v_number,
7558 string_result,
7559 &nr_result) == OK
7560 && type == VAR_NUMBER)
7561 rettv->vval.v_number = nr_result;
7562 }
7563#endif
7564}
7565
7566/*
7567 * "libcall()" function
7568 */
7569 static void
7570f_libcall(typval_T *argvars, typval_T *rettv)
7571{
7572 libcall_common(argvars, rettv, VAR_STRING);
7573}
7574
7575/*
7576 * "libcallnr()" function
7577 */
7578 static void
7579f_libcallnr(typval_T *argvars, typval_T *rettv)
7580{
7581 libcall_common(argvars, rettv, VAR_NUMBER);
7582}
7583
7584/*
7585 * "line(string)" function
7586 */
7587 static void
7588f_line(typval_T *argvars, typval_T *rettv)
7589{
7590 linenr_T lnum = 0;
7591 pos_T *fp;
7592 int fnum;
7593
7594 fp = var2fpos(&argvars[0], TRUE, &fnum);
7595 if (fp != NULL)
7596 lnum = fp->lnum;
7597 rettv->vval.v_number = lnum;
7598}
7599
7600/*
7601 * "line2byte(lnum)" function
7602 */
7603 static void
7604f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7605{
7606#ifndef FEAT_BYTEOFF
7607 rettv->vval.v_number = -1;
7608#else
7609 linenr_T lnum;
7610
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007611 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007612 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7613 rettv->vval.v_number = -1;
7614 else
7615 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7616 if (rettv->vval.v_number >= 0)
7617 ++rettv->vval.v_number;
7618#endif
7619}
7620
7621/*
7622 * "lispindent(lnum)" function
7623 */
7624 static void
7625f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7626{
7627#ifdef FEAT_LISP
7628 pos_T pos;
7629 linenr_T lnum;
7630
7631 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007632 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7634 {
7635 curwin->w_cursor.lnum = lnum;
7636 rettv->vval.v_number = get_lisp_indent();
7637 curwin->w_cursor = pos;
7638 }
7639 else
7640#endif
7641 rettv->vval.v_number = -1;
7642}
7643
7644/*
7645 * "localtime()" function
7646 */
7647 static void
7648f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7649{
7650 rettv->vval.v_number = (varnumber_T)time(NULL);
7651}
7652
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653 static void
7654get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7655{
7656 char_u *keys;
7657 char_u *which;
7658 char_u buf[NUMBUFLEN];
7659 char_u *keys_buf = NULL;
7660 char_u *rhs;
7661 int mode;
7662 int abbr = FALSE;
7663 int get_dict = FALSE;
7664 mapblock_T *mp;
7665 int buffer_local;
7666
7667 /* return empty string for failure */
7668 rettv->v_type = VAR_STRING;
7669 rettv->vval.v_string = NULL;
7670
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007671 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 if (*keys == NUL)
7673 return;
7674
7675 if (argvars[1].v_type != VAR_UNKNOWN)
7676 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007677 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678 if (argvars[2].v_type != VAR_UNKNOWN)
7679 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007680 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007681 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007682 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007683 }
7684 }
7685 else
7686 which = (char_u *)"";
7687 if (which == NULL)
7688 return;
7689
7690 mode = get_map_mode(&which, 0);
7691
7692 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7693 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7694 vim_free(keys_buf);
7695
7696 if (!get_dict)
7697 {
7698 /* Return a string. */
7699 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007700 {
7701 if (*rhs == NUL)
7702 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7703 else
7704 rettv->vval.v_string = str2special_save(rhs, FALSE);
7705 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007706
7707 }
7708 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7709 {
7710 /* Return a dictionary. */
7711 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7712 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7713 dict_T *dict = rettv->vval.v_dict;
7714
Bram Moolenaare0be1672018-07-08 16:50:37 +02007715 dict_add_string(dict, "lhs", lhs);
7716 dict_add_string(dict, "rhs", mp->m_orig_str);
7717 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7718 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7719 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007720 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7721 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007722 dict_add_number(dict, "buffer", (long)buffer_local);
7723 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7724 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725
7726 vim_free(lhs);
7727 vim_free(mapmode);
7728 }
7729}
7730
7731#ifdef FEAT_FLOAT
7732/*
7733 * "log()" function
7734 */
7735 static void
7736f_log(typval_T *argvars, typval_T *rettv)
7737{
7738 float_T f = 0.0;
7739
7740 rettv->v_type = VAR_FLOAT;
7741 if (get_float_arg(argvars, &f) == OK)
7742 rettv->vval.v_float = log(f);
7743 else
7744 rettv->vval.v_float = 0.0;
7745}
7746
7747/*
7748 * "log10()" function
7749 */
7750 static void
7751f_log10(typval_T *argvars, typval_T *rettv)
7752{
7753 float_T f = 0.0;
7754
7755 rettv->v_type = VAR_FLOAT;
7756 if (get_float_arg(argvars, &f) == OK)
7757 rettv->vval.v_float = log10(f);
7758 else
7759 rettv->vval.v_float = 0.0;
7760}
7761#endif
7762
7763#ifdef FEAT_LUA
7764/*
7765 * "luaeval()" function
7766 */
7767 static void
7768f_luaeval(typval_T *argvars, typval_T *rettv)
7769{
7770 char_u *str;
7771 char_u buf[NUMBUFLEN];
7772
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007773 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007774 do_luaeval(str, argvars + 1, rettv);
7775}
7776#endif
7777
7778/*
7779 * "map()" function
7780 */
7781 static void
7782f_map(typval_T *argvars, typval_T *rettv)
7783{
7784 filter_map(argvars, rettv, TRUE);
7785}
7786
7787/*
7788 * "maparg()" function
7789 */
7790 static void
7791f_maparg(typval_T *argvars, typval_T *rettv)
7792{
7793 get_maparg(argvars, rettv, TRUE);
7794}
7795
7796/*
7797 * "mapcheck()" function
7798 */
7799 static void
7800f_mapcheck(typval_T *argvars, typval_T *rettv)
7801{
7802 get_maparg(argvars, rettv, FALSE);
7803}
7804
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007805typedef enum
7806{
7807 MATCH_END, /* matchend() */
7808 MATCH_MATCH, /* match() */
7809 MATCH_STR, /* matchstr() */
7810 MATCH_LIST, /* matchlist() */
7811 MATCH_POS /* matchstrpos() */
7812} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007813
7814 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007815find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007816{
7817 char_u *str = NULL;
7818 long len = 0;
7819 char_u *expr = NULL;
7820 char_u *pat;
7821 regmatch_T regmatch;
7822 char_u patbuf[NUMBUFLEN];
7823 char_u strbuf[NUMBUFLEN];
7824 char_u *save_cpo;
7825 long start = 0;
7826 long nth = 1;
7827 colnr_T startcol = 0;
7828 int match = 0;
7829 list_T *l = NULL;
7830 listitem_T *li = NULL;
7831 long idx = 0;
7832 char_u *tofree = NULL;
7833
7834 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7835 save_cpo = p_cpo;
7836 p_cpo = (char_u *)"";
7837
7838 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007839 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007841 /* type MATCH_LIST: return empty list when there are no matches.
7842 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843 if (rettv_list_alloc(rettv) == FAIL)
7844 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007845 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 && (list_append_string(rettv->vval.v_list,
7847 (char_u *)"", 0) == FAIL
7848 || list_append_number(rettv->vval.v_list,
7849 (varnumber_T)-1) == FAIL
7850 || list_append_number(rettv->vval.v_list,
7851 (varnumber_T)-1) == FAIL
7852 || list_append_number(rettv->vval.v_list,
7853 (varnumber_T)-1) == FAIL))
7854 {
7855 list_free(rettv->vval.v_list);
7856 rettv->vval.v_list = NULL;
7857 goto theend;
7858 }
7859 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007860 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 {
7862 rettv->v_type = VAR_STRING;
7863 rettv->vval.v_string = NULL;
7864 }
7865
7866 if (argvars[0].v_type == VAR_LIST)
7867 {
7868 if ((l = argvars[0].vval.v_list) == NULL)
7869 goto theend;
7870 li = l->lv_first;
7871 }
7872 else
7873 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007874 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875 len = (long)STRLEN(str);
7876 }
7877
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007878 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007879 if (pat == NULL)
7880 goto theend;
7881
7882 if (argvars[2].v_type != VAR_UNKNOWN)
7883 {
7884 int error = FALSE;
7885
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007886 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 if (error)
7888 goto theend;
7889 if (l != NULL)
7890 {
7891 li = list_find(l, start);
7892 if (li == NULL)
7893 goto theend;
7894 idx = l->lv_idx; /* use the cached index */
7895 }
7896 else
7897 {
7898 if (start < 0)
7899 start = 0;
7900 if (start > len)
7901 goto theend;
7902 /* When "count" argument is there ignore matches before "start",
7903 * otherwise skip part of the string. Differs when pattern is "^"
7904 * or "\<". */
7905 if (argvars[3].v_type != VAR_UNKNOWN)
7906 startcol = start;
7907 else
7908 {
7909 str += start;
7910 len -= start;
7911 }
7912 }
7913
7914 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007915 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007916 if (error)
7917 goto theend;
7918 }
7919
7920 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7921 if (regmatch.regprog != NULL)
7922 {
7923 regmatch.rm_ic = p_ic;
7924
7925 for (;;)
7926 {
7927 if (l != NULL)
7928 {
7929 if (li == NULL)
7930 {
7931 match = FALSE;
7932 break;
7933 }
7934 vim_free(tofree);
7935 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7936 if (str == NULL)
7937 break;
7938 }
7939
7940 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7941
7942 if (match && --nth <= 0)
7943 break;
7944 if (l == NULL && !match)
7945 break;
7946
7947 /* Advance to just after the match. */
7948 if (l != NULL)
7949 {
7950 li = li->li_next;
7951 ++idx;
7952 }
7953 else
7954 {
7955#ifdef FEAT_MBYTE
7956 startcol = (colnr_T)(regmatch.startp[0]
7957 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7958#else
7959 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7960#endif
7961 if (startcol > (colnr_T)len
7962 || str + startcol <= regmatch.startp[0])
7963 {
7964 match = FALSE;
7965 break;
7966 }
7967 }
7968 }
7969
7970 if (match)
7971 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007972 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007973 {
7974 listitem_T *li1 = rettv->vval.v_list->lv_first;
7975 listitem_T *li2 = li1->li_next;
7976 listitem_T *li3 = li2->li_next;
7977 listitem_T *li4 = li3->li_next;
7978
7979 vim_free(li1->li_tv.vval.v_string);
7980 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7981 (int)(regmatch.endp[0] - regmatch.startp[0]));
7982 li3->li_tv.vval.v_number =
7983 (varnumber_T)(regmatch.startp[0] - expr);
7984 li4->li_tv.vval.v_number =
7985 (varnumber_T)(regmatch.endp[0] - expr);
7986 if (l != NULL)
7987 li2->li_tv.vval.v_number = (varnumber_T)idx;
7988 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007989 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007990 {
7991 int i;
7992
7993 /* return list with matched string and submatches */
7994 for (i = 0; i < NSUBEXP; ++i)
7995 {
7996 if (regmatch.endp[i] == NULL)
7997 {
7998 if (list_append_string(rettv->vval.v_list,
7999 (char_u *)"", 0) == FAIL)
8000 break;
8001 }
8002 else if (list_append_string(rettv->vval.v_list,
8003 regmatch.startp[i],
8004 (int)(regmatch.endp[i] - regmatch.startp[i]))
8005 == FAIL)
8006 break;
8007 }
8008 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008009 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008010 {
8011 /* return matched string */
8012 if (l != NULL)
8013 copy_tv(&li->li_tv, rettv);
8014 else
8015 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8016 (int)(regmatch.endp[0] - regmatch.startp[0]));
8017 }
8018 else if (l != NULL)
8019 rettv->vval.v_number = idx;
8020 else
8021 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008022 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023 rettv->vval.v_number =
8024 (varnumber_T)(regmatch.startp[0] - str);
8025 else
8026 rettv->vval.v_number =
8027 (varnumber_T)(regmatch.endp[0] - str);
8028 rettv->vval.v_number += (varnumber_T)(str - expr);
8029 }
8030 }
8031 vim_regfree(regmatch.regprog);
8032 }
8033
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008034theend:
8035 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008036 /* matchstrpos() without a list: drop the second item. */
8037 listitem_remove(rettv->vval.v_list,
8038 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039 vim_free(tofree);
8040 p_cpo = save_cpo;
8041}
8042
8043/*
8044 * "match()" function
8045 */
8046 static void
8047f_match(typval_T *argvars, typval_T *rettv)
8048{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008049 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050}
8051
Bram Moolenaar95e51472018-07-28 16:55:56 +02008052#ifdef FEAT_SEARCH_EXTRA
8053 static int
8054matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8055{
8056 dictitem_T *di;
8057
8058 if (tv->v_type != VAR_DICT)
8059 {
8060 EMSG(_(e_dictreq));
8061 return FAIL;
8062 }
8063
8064 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008065 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008066 (char_u *)"conceal", FALSE);
8067
8068 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8069 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008070 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008071 if (*win == NULL)
8072 {
8073 EMSG(_("E957: Invalid window number"));
8074 return FAIL;
8075 }
8076 }
8077
8078 return OK;
8079}
8080#endif
8081
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082/*
8083 * "matchadd()" function
8084 */
8085 static void
8086f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8087{
8088#ifdef FEAT_SEARCH_EXTRA
8089 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008090 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8091 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008092 int prio = 10; /* default priority */
8093 int id = -1;
8094 int error = FALSE;
8095 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008096 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008097
8098 rettv->vval.v_number = -1;
8099
8100 if (grp == NULL || pat == NULL)
8101 return;
8102 if (argvars[2].v_type != VAR_UNKNOWN)
8103 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008104 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008105 if (argvars[3].v_type != VAR_UNKNOWN)
8106 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008107 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008108 if (argvars[4].v_type != VAR_UNKNOWN
8109 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8110 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111 }
8112 }
8113 if (error == TRUE)
8114 return;
8115 if (id >= 1 && id <= 3)
8116 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008117 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118 return;
8119 }
8120
Bram Moolenaar95e51472018-07-28 16:55:56 +02008121 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122 conceal_char);
8123#endif
8124}
8125
8126/*
8127 * "matchaddpos()" function
8128 */
8129 static void
8130f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8131{
8132#ifdef FEAT_SEARCH_EXTRA
8133 char_u buf[NUMBUFLEN];
8134 char_u *group;
8135 int prio = 10;
8136 int id = -1;
8137 int error = FALSE;
8138 list_T *l;
8139 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008140 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141
8142 rettv->vval.v_number = -1;
8143
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008144 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008145 if (group == NULL)
8146 return;
8147
8148 if (argvars[1].v_type != VAR_LIST)
8149 {
8150 EMSG2(_(e_listarg), "matchaddpos()");
8151 return;
8152 }
8153 l = argvars[1].vval.v_list;
8154 if (l == NULL)
8155 return;
8156
8157 if (argvars[2].v_type != VAR_UNKNOWN)
8158 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008159 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160 if (argvars[3].v_type != VAR_UNKNOWN)
8161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008162 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008163
8164 if (argvars[4].v_type != VAR_UNKNOWN
8165 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8166 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167 }
8168 }
8169 if (error == TRUE)
8170 return;
8171
8172 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8173 if (id == 1 || id == 2)
8174 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008175 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 return;
8177 }
8178
Bram Moolenaar95e51472018-07-28 16:55:56 +02008179 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008180 conceal_char);
8181#endif
8182}
8183
8184/*
8185 * "matcharg()" function
8186 */
8187 static void
8188f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8189{
8190 if (rettv_list_alloc(rettv) == OK)
8191 {
8192#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008193 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008194 matchitem_T *m;
8195
8196 if (id >= 1 && id <= 3)
8197 {
8198 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8199 {
8200 list_append_string(rettv->vval.v_list,
8201 syn_id2name(m->hlg_id), -1);
8202 list_append_string(rettv->vval.v_list, m->pattern, -1);
8203 }
8204 else
8205 {
8206 list_append_string(rettv->vval.v_list, NULL, -1);
8207 list_append_string(rettv->vval.v_list, NULL, -1);
8208 }
8209 }
8210#endif
8211 }
8212}
8213
8214/*
8215 * "matchdelete()" function
8216 */
8217 static void
8218f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8219{
8220#ifdef FEAT_SEARCH_EXTRA
8221 rettv->vval.v_number = match_delete(curwin,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008222 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223#endif
8224}
8225
8226/*
8227 * "matchend()" function
8228 */
8229 static void
8230f_matchend(typval_T *argvars, typval_T *rettv)
8231{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008232 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008233}
8234
8235/*
8236 * "matchlist()" function
8237 */
8238 static void
8239f_matchlist(typval_T *argvars, typval_T *rettv)
8240{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008241 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008242}
8243
8244/*
8245 * "matchstr()" function
8246 */
8247 static void
8248f_matchstr(typval_T *argvars, typval_T *rettv)
8249{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008250 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008251}
8252
8253/*
8254 * "matchstrpos()" function
8255 */
8256 static void
8257f_matchstrpos(typval_T *argvars, typval_T *rettv)
8258{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008259 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008260}
8261
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008262 static void
8263max_min(typval_T *argvars, typval_T *rettv, int domax)
8264{
8265 varnumber_T n = 0;
8266 varnumber_T i;
8267 int error = FALSE;
8268
8269 if (argvars[0].v_type == VAR_LIST)
8270 {
8271 list_T *l;
8272 listitem_T *li;
8273
8274 l = argvars[0].vval.v_list;
8275 if (l != NULL)
8276 {
8277 li = l->lv_first;
8278 if (li != NULL)
8279 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008280 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281 for (;;)
8282 {
8283 li = li->li_next;
8284 if (li == NULL)
8285 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008286 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008287 if (domax ? i > n : i < n)
8288 n = i;
8289 }
8290 }
8291 }
8292 }
8293 else if (argvars[0].v_type == VAR_DICT)
8294 {
8295 dict_T *d;
8296 int first = TRUE;
8297 hashitem_T *hi;
8298 int todo;
8299
8300 d = argvars[0].vval.v_dict;
8301 if (d != NULL)
8302 {
8303 todo = (int)d->dv_hashtab.ht_used;
8304 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8305 {
8306 if (!HASHITEM_EMPTY(hi))
8307 {
8308 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008309 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008310 if (first)
8311 {
8312 n = i;
8313 first = FALSE;
8314 }
8315 else if (domax ? i > n : i < n)
8316 n = i;
8317 }
8318 }
8319 }
8320 }
8321 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008322 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008323 rettv->vval.v_number = error ? 0 : n;
8324}
8325
8326/*
8327 * "max()" function
8328 */
8329 static void
8330f_max(typval_T *argvars, typval_T *rettv)
8331{
8332 max_min(argvars, rettv, TRUE);
8333}
8334
8335/*
8336 * "min()" function
8337 */
8338 static void
8339f_min(typval_T *argvars, typval_T *rettv)
8340{
8341 max_min(argvars, rettv, FALSE);
8342}
8343
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008344/*
8345 * Create the directory in which "dir" is located, and higher levels when
8346 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008347 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008348 */
8349 static int
8350mkdir_recurse(char_u *dir, int prot)
8351{
8352 char_u *p;
8353 char_u *updir;
8354 int r = FAIL;
8355
8356 /* Get end of directory name in "dir".
8357 * We're done when it's "/" or "c:/". */
8358 p = gettail_sep(dir);
8359 if (p <= get_past_head(dir))
8360 return OK;
8361
8362 /* If the directory exists we're done. Otherwise: create it.*/
8363 updir = vim_strnsave(dir, (int)(p - dir));
8364 if (updir == NULL)
8365 return FAIL;
8366 if (mch_isdir(updir))
8367 r = OK;
8368 else if (mkdir_recurse(updir, prot) == OK)
8369 r = vim_mkdir_emsg(updir, prot);
8370 vim_free(updir);
8371 return r;
8372}
8373
8374#ifdef vim_mkdir
8375/*
8376 * "mkdir()" function
8377 */
8378 static void
8379f_mkdir(typval_T *argvars, typval_T *rettv)
8380{
8381 char_u *dir;
8382 char_u buf[NUMBUFLEN];
8383 int prot = 0755;
8384
8385 rettv->vval.v_number = FAIL;
8386 if (check_restricted() || check_secure())
8387 return;
8388
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008389 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008391 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008392
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008393 if (*gettail(dir) == NUL)
8394 /* remove trailing slashes */
8395 *gettail_sep(dir) = NUL;
8396
8397 if (argvars[1].v_type != VAR_UNKNOWN)
8398 {
8399 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008400 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008401 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008402 if (prot == -1)
8403 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008405 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008406 {
8407 if (mch_isdir(dir))
8408 {
8409 /* With the "p" flag it's OK if the dir already exists. */
8410 rettv->vval.v_number = OK;
8411 return;
8412 }
8413 mkdir_recurse(dir, prot);
8414 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008415 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008416 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008417}
8418#endif
8419
8420/*
8421 * "mode()" function
8422 */
8423 static void
8424f_mode(typval_T *argvars, typval_T *rettv)
8425{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008426 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008427
Bram Moolenaar612cc382018-07-29 15:34:26 +02008428 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008429
8430 if (time_for_testing == 93784)
8431 {
8432 /* Testing the two-character code. */
8433 buf[0] = 'x';
8434 buf[1] = '!';
8435 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008436#ifdef FEAT_TERMINAL
8437 else if (term_use_loop())
8438 buf[0] = 't';
8439#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008440 else if (VIsual_active)
8441 {
8442 if (VIsual_select)
8443 buf[0] = VIsual_mode + 's' - 'v';
8444 else
8445 buf[0] = VIsual_mode;
8446 }
8447 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8448 || State == CONFIRM)
8449 {
8450 buf[0] = 'r';
8451 if (State == ASKMORE)
8452 buf[1] = 'm';
8453 else if (State == CONFIRM)
8454 buf[1] = '?';
8455 }
8456 else if (State == EXTERNCMD)
8457 buf[0] = '!';
8458 else if (State & INSERT)
8459 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008460 if (State & VREPLACE_FLAG)
8461 {
8462 buf[0] = 'R';
8463 buf[1] = 'v';
8464 }
8465 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008466 {
8467 if (State & REPLACE_FLAG)
8468 buf[0] = 'R';
8469 else
8470 buf[0] = 'i';
8471#ifdef FEAT_INS_EXPAND
8472 if (ins_compl_active())
8473 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008474 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008475 buf[1] = 'x';
8476#endif
8477 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008478 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008479 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480 {
8481 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008482 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008483 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008484 else if (exmode_active == EXMODE_NORMAL)
8485 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008486 }
8487 else
8488 {
8489 buf[0] = 'n';
8490 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008491 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008492 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008493 // to be able to detect force-linewise/blockwise/characterwise operations
8494 buf[2] = motion_force;
8495 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008496 else if (restart_edit == 'I' || restart_edit == 'R'
8497 || restart_edit == 'V')
8498 {
8499 buf[1] = 'i';
8500 buf[2] = restart_edit;
8501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008502 }
8503
8504 /* Clear out the minor mode when the argument is not a non-zero number or
8505 * non-empty string. */
8506 if (!non_zero_arg(&argvars[0]))
8507 buf[1] = NUL;
8508
8509 rettv->vval.v_string = vim_strsave(buf);
8510 rettv->v_type = VAR_STRING;
8511}
8512
8513#if defined(FEAT_MZSCHEME) || defined(PROTO)
8514/*
8515 * "mzeval()" function
8516 */
8517 static void
8518f_mzeval(typval_T *argvars, typval_T *rettv)
8519{
8520 char_u *str;
8521 char_u buf[NUMBUFLEN];
8522
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008523 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008524 do_mzeval(str, rettv);
8525}
8526
8527 void
8528mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8529{
8530 typval_T argvars[3];
8531
8532 argvars[0].v_type = VAR_STRING;
8533 argvars[0].vval.v_string = name;
8534 copy_tv(args, &argvars[1]);
8535 argvars[2].v_type = VAR_UNKNOWN;
8536 f_call(argvars, rettv);
8537 clear_tv(&argvars[1]);
8538}
8539#endif
8540
8541/*
8542 * "nextnonblank()" function
8543 */
8544 static void
8545f_nextnonblank(typval_T *argvars, typval_T *rettv)
8546{
8547 linenr_T lnum;
8548
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008549 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008550 {
8551 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8552 {
8553 lnum = 0;
8554 break;
8555 }
8556 if (*skipwhite(ml_get(lnum)) != NUL)
8557 break;
8558 }
8559 rettv->vval.v_number = lnum;
8560}
8561
8562/*
8563 * "nr2char()" function
8564 */
8565 static void
8566f_nr2char(typval_T *argvars, typval_T *rettv)
8567{
8568 char_u buf[NUMBUFLEN];
8569
8570#ifdef FEAT_MBYTE
8571 if (has_mbyte)
8572 {
8573 int utf8 = 0;
8574
8575 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008576 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008577 if (utf8)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008578 buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008579 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008580 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008581 }
8582 else
8583#endif
8584 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008585 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008586 buf[1] = NUL;
8587 }
8588 rettv->v_type = VAR_STRING;
8589 rettv->vval.v_string = vim_strsave(buf);
8590}
8591
8592/*
8593 * "or(expr, expr)" function
8594 */
8595 static void
8596f_or(typval_T *argvars, typval_T *rettv)
8597{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008598 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8599 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008600}
8601
8602/*
8603 * "pathshorten()" function
8604 */
8605 static void
8606f_pathshorten(typval_T *argvars, typval_T *rettv)
8607{
8608 char_u *p;
8609
8610 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008611 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008612 if (p == NULL)
8613 rettv->vval.v_string = NULL;
8614 else
8615 {
8616 p = vim_strsave(p);
8617 rettv->vval.v_string = p;
8618 if (p != NULL)
8619 shorten_dir(p);
8620 }
8621}
8622
8623#ifdef FEAT_PERL
8624/*
8625 * "perleval()" function
8626 */
8627 static void
8628f_perleval(typval_T *argvars, typval_T *rettv)
8629{
8630 char_u *str;
8631 char_u buf[NUMBUFLEN];
8632
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008633 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008634 do_perleval(str, rettv);
8635}
8636#endif
8637
8638#ifdef FEAT_FLOAT
8639/*
8640 * "pow()" function
8641 */
8642 static void
8643f_pow(typval_T *argvars, typval_T *rettv)
8644{
8645 float_T fx = 0.0, fy = 0.0;
8646
8647 rettv->v_type = VAR_FLOAT;
8648 if (get_float_arg(argvars, &fx) == OK
8649 && get_float_arg(&argvars[1], &fy) == OK)
8650 rettv->vval.v_float = pow(fx, fy);
8651 else
8652 rettv->vval.v_float = 0.0;
8653}
8654#endif
8655
8656/*
8657 * "prevnonblank()" function
8658 */
8659 static void
8660f_prevnonblank(typval_T *argvars, typval_T *rettv)
8661{
8662 linenr_T lnum;
8663
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008664 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008665 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8666 lnum = 0;
8667 else
8668 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8669 --lnum;
8670 rettv->vval.v_number = lnum;
8671}
8672
8673/* This dummy va_list is here because:
8674 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8675 * - locally in the function results in a "used before set" warning
8676 * - using va_start() to initialize it gives "function with fixed args" error */
8677static va_list ap;
8678
8679/*
8680 * "printf()" function
8681 */
8682 static void
8683f_printf(typval_T *argvars, typval_T *rettv)
8684{
8685 char_u buf[NUMBUFLEN];
8686 int len;
8687 char_u *s;
8688 int saved_did_emsg = did_emsg;
8689 char *fmt;
8690
8691 rettv->v_type = VAR_STRING;
8692 rettv->vval.v_string = NULL;
8693
8694 /* Get the required length, allocate the buffer and do it for real. */
8695 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008696 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008697 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008698 if (!did_emsg)
8699 {
8700 s = alloc(len + 1);
8701 if (s != NULL)
8702 {
8703 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008704 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8705 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008706 }
8707 }
8708 did_emsg |= saved_did_emsg;
8709}
8710
Bram Moolenaarf2732452018-06-03 14:47:35 +02008711#ifdef FEAT_JOB_CHANNEL
8712/*
8713 * "prompt_setcallback({buffer}, {callback})" function
8714 */
8715 static void
8716f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8717{
8718 buf_T *buf;
8719 char_u *callback;
8720 partial_T *partial;
8721
8722 if (check_secure())
8723 return;
8724 buf = get_buf_tv(&argvars[0], FALSE);
8725 if (buf == NULL)
8726 return;
8727
8728 callback = get_callback(&argvars[1], &partial);
8729 if (callback == NULL)
8730 return;
8731
8732 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8733 if (partial == NULL)
8734 buf->b_prompt_callback = vim_strsave(callback);
8735 else
8736 /* pointer into the partial */
8737 buf->b_prompt_callback = callback;
8738 buf->b_prompt_partial = partial;
8739}
8740
8741/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008742 * "prompt_setinterrupt({buffer}, {callback})" function
8743 */
8744 static void
8745f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8746{
8747 buf_T *buf;
8748 char_u *callback;
8749 partial_T *partial;
8750
8751 if (check_secure())
8752 return;
8753 buf = get_buf_tv(&argvars[0], FALSE);
8754 if (buf == NULL)
8755 return;
8756
8757 callback = get_callback(&argvars[1], &partial);
8758 if (callback == NULL)
8759 return;
8760
8761 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8762 if (partial == NULL)
8763 buf->b_prompt_interrupt = vim_strsave(callback);
8764 else
8765 /* pointer into the partial */
8766 buf->b_prompt_interrupt = callback;
8767 buf->b_prompt_int_partial = partial;
8768}
8769
8770/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008771 * "prompt_setprompt({buffer}, {text})" function
8772 */
8773 static void
8774f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8775{
8776 buf_T *buf;
8777 char_u *text;
8778
8779 if (check_secure())
8780 return;
8781 buf = get_buf_tv(&argvars[0], FALSE);
8782 if (buf == NULL)
8783 return;
8784
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008785 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008786 vim_free(buf->b_prompt_text);
8787 buf->b_prompt_text = vim_strsave(text);
8788}
8789#endif
8790
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008791/*
8792 * "pumvisible()" function
8793 */
8794 static void
8795f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8796{
8797#ifdef FEAT_INS_EXPAND
8798 if (pum_visible())
8799 rettv->vval.v_number = 1;
8800#endif
8801}
8802
8803#ifdef FEAT_PYTHON3
8804/*
8805 * "py3eval()" function
8806 */
8807 static void
8808f_py3eval(typval_T *argvars, typval_T *rettv)
8809{
8810 char_u *str;
8811 char_u buf[NUMBUFLEN];
8812
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008813 if (p_pyx == 0)
8814 p_pyx = 3;
8815
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008816 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008817 do_py3eval(str, rettv);
8818}
8819#endif
8820
8821#ifdef FEAT_PYTHON
8822/*
8823 * "pyeval()" function
8824 */
8825 static void
8826f_pyeval(typval_T *argvars, typval_T *rettv)
8827{
8828 char_u *str;
8829 char_u buf[NUMBUFLEN];
8830
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008831 if (p_pyx == 0)
8832 p_pyx = 2;
8833
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008834 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008835 do_pyeval(str, rettv);
8836}
8837#endif
8838
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008839#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8840/*
8841 * "pyxeval()" function
8842 */
8843 static void
8844f_pyxeval(typval_T *argvars, typval_T *rettv)
8845{
8846# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8847 init_pyxversion();
8848 if (p_pyx == 2)
8849 f_pyeval(argvars, rettv);
8850 else
8851 f_py3eval(argvars, rettv);
8852# elif defined(FEAT_PYTHON)
8853 f_pyeval(argvars, rettv);
8854# elif defined(FEAT_PYTHON3)
8855 f_py3eval(argvars, rettv);
8856# endif
8857}
8858#endif
8859
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008860/*
8861 * "range()" function
8862 */
8863 static void
8864f_range(typval_T *argvars, typval_T *rettv)
8865{
8866 varnumber_T start;
8867 varnumber_T end;
8868 varnumber_T stride = 1;
8869 varnumber_T i;
8870 int error = FALSE;
8871
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008872 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008873 if (argvars[1].v_type == VAR_UNKNOWN)
8874 {
8875 end = start - 1;
8876 start = 0;
8877 }
8878 else
8879 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008880 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008881 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008882 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008883 }
8884
8885 if (error)
8886 return; /* type error; errmsg already given */
8887 if (stride == 0)
8888 EMSG(_("E726: Stride is zero"));
8889 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8890 EMSG(_("E727: Start past end"));
8891 else
8892 {
8893 if (rettv_list_alloc(rettv) == OK)
8894 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8895 if (list_append_number(rettv->vval.v_list,
8896 (varnumber_T)i) == FAIL)
8897 break;
8898 }
8899}
8900
8901/*
8902 * "readfile()" function
8903 */
8904 static void
8905f_readfile(typval_T *argvars, typval_T *rettv)
8906{
8907 int binary = FALSE;
8908 int failed = FALSE;
8909 char_u *fname;
8910 FILE *fd;
8911 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8912 int io_size = sizeof(buf);
8913 int readlen; /* size of last fread() */
8914 char_u *prev = NULL; /* previously read bytes, if any */
8915 long prevlen = 0; /* length of data in prev */
8916 long prevsize = 0; /* size of prev buffer */
8917 long maxline = MAXLNUM;
8918 long cnt = 0;
8919 char_u *p; /* position in buf */
8920 char_u *start; /* start of current line */
8921
8922 if (argvars[1].v_type != VAR_UNKNOWN)
8923 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008924 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008925 binary = TRUE;
8926 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008927 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008928 }
8929
8930 if (rettv_list_alloc(rettv) == FAIL)
8931 return;
8932
8933 /* Always open the file in binary mode, library functions have a mind of
8934 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008935 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008936 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8937 {
8938 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8939 return;
8940 }
8941
8942 while (cnt < maxline || maxline < 0)
8943 {
8944 readlen = (int)fread(buf, 1, io_size, fd);
8945
8946 /* This for loop processes what was read, but is also entered at end
8947 * of file so that either:
8948 * - an incomplete line gets written
8949 * - a "binary" file gets an empty line at the end if it ends in a
8950 * newline. */
8951 for (p = buf, start = buf;
8952 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8953 ++p)
8954 {
8955 if (*p == '\n' || readlen <= 0)
8956 {
8957 listitem_T *li;
8958 char_u *s = NULL;
8959 long_u len = p - start;
8960
8961 /* Finished a line. Remove CRs before NL. */
8962 if (readlen > 0 && !binary)
8963 {
8964 while (len > 0 && start[len - 1] == '\r')
8965 --len;
8966 /* removal may cross back to the "prev" string */
8967 if (len == 0)
8968 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8969 --prevlen;
8970 }
8971 if (prevlen == 0)
8972 s = vim_strnsave(start, (int)len);
8973 else
8974 {
8975 /* Change "prev" buffer to be the right size. This way
8976 * the bytes are only copied once, and very long lines are
8977 * allocated only once. */
8978 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8979 {
8980 mch_memmove(s + prevlen, start, len);
8981 s[prevlen + len] = NUL;
8982 prev = NULL; /* the list will own the string */
8983 prevlen = prevsize = 0;
8984 }
8985 }
8986 if (s == NULL)
8987 {
8988 do_outofmem_msg((long_u) prevlen + len + 1);
8989 failed = TRUE;
8990 break;
8991 }
8992
8993 if ((li = listitem_alloc()) == NULL)
8994 {
8995 vim_free(s);
8996 failed = TRUE;
8997 break;
8998 }
8999 li->li_tv.v_type = VAR_STRING;
9000 li->li_tv.v_lock = 0;
9001 li->li_tv.vval.v_string = s;
9002 list_append(rettv->vval.v_list, li);
9003
9004 start = p + 1; /* step over newline */
9005 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9006 break;
9007 }
9008 else if (*p == NUL)
9009 *p = '\n';
9010#ifdef FEAT_MBYTE
9011 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9012 * when finding the BF and check the previous two bytes. */
9013 else if (*p == 0xbf && enc_utf8 && !binary)
9014 {
9015 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9016 * + 1, these may be in the "prev" string. */
9017 char_u back1 = p >= buf + 1 ? p[-1]
9018 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9019 char_u back2 = p >= buf + 2 ? p[-2]
9020 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9021 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9022
9023 if (back2 == 0xef && back1 == 0xbb)
9024 {
9025 char_u *dest = p - 2;
9026
9027 /* Usually a BOM is at the beginning of a file, and so at
9028 * the beginning of a line; then we can just step over it.
9029 */
9030 if (start == dest)
9031 start = p + 1;
9032 else
9033 {
9034 /* have to shuffle buf to close gap */
9035 int adjust_prevlen = 0;
9036
9037 if (dest < buf)
9038 {
9039 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9040 dest = buf;
9041 }
9042 if (readlen > p - buf + 1)
9043 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9044 readlen -= 3 - adjust_prevlen;
9045 prevlen -= adjust_prevlen;
9046 p = dest - 1;
9047 }
9048 }
9049 }
9050#endif
9051 } /* for */
9052
9053 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9054 break;
9055 if (start < p)
9056 {
9057 /* There's part of a line in buf, store it in "prev". */
9058 if (p - start + prevlen >= prevsize)
9059 {
9060 /* need bigger "prev" buffer */
9061 char_u *newprev;
9062
9063 /* A common use case is ordinary text files and "prev" gets a
9064 * fragment of a line, so the first allocation is made
9065 * small, to avoid repeatedly 'allocing' large and
9066 * 'reallocing' small. */
9067 if (prevsize == 0)
9068 prevsize = (long)(p - start);
9069 else
9070 {
9071 long grow50pc = (prevsize * 3) / 2;
9072 long growmin = (long)((p - start) * 2 + prevlen);
9073 prevsize = grow50pc > growmin ? grow50pc : growmin;
9074 }
9075 newprev = prev == NULL ? alloc(prevsize)
9076 : vim_realloc(prev, prevsize);
9077 if (newprev == NULL)
9078 {
9079 do_outofmem_msg((long_u)prevsize);
9080 failed = TRUE;
9081 break;
9082 }
9083 prev = newprev;
9084 }
9085 /* Add the line part to end of "prev". */
9086 mch_memmove(prev + prevlen, start, p - start);
9087 prevlen += (long)(p - start);
9088 }
9089 } /* while */
9090
9091 /*
9092 * For a negative line count use only the lines at the end of the file,
9093 * free the rest.
9094 */
9095 if (!failed && maxline < 0)
9096 while (cnt > -maxline)
9097 {
9098 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9099 --cnt;
9100 }
9101
9102 if (failed)
9103 {
9104 list_free(rettv->vval.v_list);
9105 /* readfile doc says an empty list is returned on error */
9106 rettv->vval.v_list = list_alloc();
9107 }
9108
9109 vim_free(prev);
9110 fclose(fd);
9111}
9112
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009113 static void
9114return_register(int regname, typval_T *rettv)
9115{
9116 char_u buf[2] = {0, 0};
9117
9118 buf[0] = (char_u)regname;
9119 rettv->v_type = VAR_STRING;
9120 rettv->vval.v_string = vim_strsave(buf);
9121}
9122
9123/*
9124 * "reg_executing()" function
9125 */
9126 static void
9127f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9128{
9129 return_register(reg_executing, rettv);
9130}
9131
9132/*
9133 * "reg_recording()" function
9134 */
9135 static void
9136f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9137{
9138 return_register(reg_recording, rettv);
9139}
9140
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009141#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009142/*
9143 * Convert a List to proftime_T.
9144 * Return FAIL when there is something wrong.
9145 */
9146 static int
9147list2proftime(typval_T *arg, proftime_T *tm)
9148{
9149 long n1, n2;
9150 int error = FALSE;
9151
9152 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9153 || arg->vval.v_list->lv_len != 2)
9154 return FAIL;
9155 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9156 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9157# ifdef WIN3264
9158 tm->HighPart = n1;
9159 tm->LowPart = n2;
9160# else
9161 tm->tv_sec = n1;
9162 tm->tv_usec = n2;
9163# endif
9164 return error ? FAIL : OK;
9165}
9166#endif /* FEAT_RELTIME */
9167
9168/*
9169 * "reltime()" function
9170 */
9171 static void
9172f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9173{
9174#ifdef FEAT_RELTIME
9175 proftime_T res;
9176 proftime_T start;
9177
9178 if (argvars[0].v_type == VAR_UNKNOWN)
9179 {
9180 /* No arguments: get current time. */
9181 profile_start(&res);
9182 }
9183 else if (argvars[1].v_type == VAR_UNKNOWN)
9184 {
9185 if (list2proftime(&argvars[0], &res) == FAIL)
9186 return;
9187 profile_end(&res);
9188 }
9189 else
9190 {
9191 /* Two arguments: compute the difference. */
9192 if (list2proftime(&argvars[0], &start) == FAIL
9193 || list2proftime(&argvars[1], &res) == FAIL)
9194 return;
9195 profile_sub(&res, &start);
9196 }
9197
9198 if (rettv_list_alloc(rettv) == OK)
9199 {
9200 long n1, n2;
9201
9202# ifdef WIN3264
9203 n1 = res.HighPart;
9204 n2 = res.LowPart;
9205# else
9206 n1 = res.tv_sec;
9207 n2 = res.tv_usec;
9208# endif
9209 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9210 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9211 }
9212#endif
9213}
9214
9215#ifdef FEAT_FLOAT
9216/*
9217 * "reltimefloat()" function
9218 */
9219 static void
9220f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9221{
9222# ifdef FEAT_RELTIME
9223 proftime_T tm;
9224# endif
9225
9226 rettv->v_type = VAR_FLOAT;
9227 rettv->vval.v_float = 0;
9228# ifdef FEAT_RELTIME
9229 if (list2proftime(&argvars[0], &tm) == OK)
9230 rettv->vval.v_float = profile_float(&tm);
9231# endif
9232}
9233#endif
9234
9235/*
9236 * "reltimestr()" function
9237 */
9238 static void
9239f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9240{
9241#ifdef FEAT_RELTIME
9242 proftime_T tm;
9243#endif
9244
9245 rettv->v_type = VAR_STRING;
9246 rettv->vval.v_string = NULL;
9247#ifdef FEAT_RELTIME
9248 if (list2proftime(&argvars[0], &tm) == OK)
9249 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9250#endif
9251}
9252
9253#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009254 static void
9255make_connection(void)
9256{
9257 if (X_DISPLAY == NULL
9258# ifdef FEAT_GUI
9259 && !gui.in_use
9260# endif
9261 )
9262 {
9263 x_force_connect = TRUE;
9264 setup_term_clip();
9265 x_force_connect = FALSE;
9266 }
9267}
9268
9269 static int
9270check_connection(void)
9271{
9272 make_connection();
9273 if (X_DISPLAY == NULL)
9274 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009275 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009276 return FAIL;
9277 }
9278 return OK;
9279}
9280#endif
9281
9282#ifdef FEAT_CLIENTSERVER
9283 static void
9284remote_common(typval_T *argvars, typval_T *rettv, int expr)
9285{
9286 char_u *server_name;
9287 char_u *keys;
9288 char_u *r = NULL;
9289 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009290 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009291# ifdef WIN32
9292 HWND w;
9293# else
9294 Window w;
9295# endif
9296
9297 if (check_restricted() || check_secure())
9298 return;
9299
9300# ifdef FEAT_X11
9301 if (check_connection() == FAIL)
9302 return;
9303# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009304 if (argvars[2].v_type != VAR_UNKNOWN
9305 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009306 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009307
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009308 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009309 if (server_name == NULL)
9310 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009311 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009312# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009313 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009314# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009315 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9316 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009317# endif
9318 {
9319 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009320 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009321 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009322 vim_free(r);
9323 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009324 else
9325 EMSG2(_("E241: Unable to send to %s"), server_name);
9326 return;
9327 }
9328
9329 rettv->vval.v_string = r;
9330
9331 if (argvars[2].v_type != VAR_UNKNOWN)
9332 {
9333 dictitem_T v;
9334 char_u str[30];
9335 char_u *idvar;
9336
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009337 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009338 if (idvar != NULL && *idvar != NUL)
9339 {
9340 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9341 v.di_tv.v_type = VAR_STRING;
9342 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009343 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009344 vim_free(v.di_tv.vval.v_string);
9345 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009346 }
9347}
9348#endif
9349
9350/*
9351 * "remote_expr()" function
9352 */
9353 static void
9354f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9355{
9356 rettv->v_type = VAR_STRING;
9357 rettv->vval.v_string = NULL;
9358#ifdef FEAT_CLIENTSERVER
9359 remote_common(argvars, rettv, TRUE);
9360#endif
9361}
9362
9363/*
9364 * "remote_foreground()" function
9365 */
9366 static void
9367f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9368{
9369#ifdef FEAT_CLIENTSERVER
9370# ifdef WIN32
9371 /* On Win32 it's done in this application. */
9372 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009373 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009374
9375 if (server_name != NULL)
9376 serverForeground(server_name);
9377 }
9378# else
9379 /* Send a foreground() expression to the server. */
9380 argvars[1].v_type = VAR_STRING;
9381 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9382 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009383 rettv->v_type = VAR_STRING;
9384 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009385 remote_common(argvars, rettv, TRUE);
9386 vim_free(argvars[1].vval.v_string);
9387# endif
9388#endif
9389}
9390
9391 static void
9392f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9393{
9394#ifdef FEAT_CLIENTSERVER
9395 dictitem_T v;
9396 char_u *s = NULL;
9397# ifdef WIN32
9398 long_u n = 0;
9399# endif
9400 char_u *serverid;
9401
9402 if (check_restricted() || check_secure())
9403 {
9404 rettv->vval.v_number = -1;
9405 return;
9406 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009407 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009408 if (serverid == NULL)
9409 {
9410 rettv->vval.v_number = -1;
9411 return; /* type error; errmsg already given */
9412 }
9413# ifdef WIN32
9414 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9415 if (n == 0)
9416 rettv->vval.v_number = -1;
9417 else
9418 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009419 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009420 rettv->vval.v_number = (s != NULL);
9421 }
9422# else
9423 if (check_connection() == FAIL)
9424 return;
9425
9426 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9427 serverStrToWin(serverid), &s);
9428# endif
9429
9430 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9431 {
9432 char_u *retvar;
9433
9434 v.di_tv.v_type = VAR_STRING;
9435 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009436 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009437 if (retvar != NULL)
9438 set_var(retvar, &v.di_tv, FALSE);
9439 vim_free(v.di_tv.vval.v_string);
9440 }
9441#else
9442 rettv->vval.v_number = -1;
9443#endif
9444}
9445
9446 static void
9447f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9448{
9449 char_u *r = NULL;
9450
9451#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009452 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009453
9454 if (serverid != NULL && !check_restricted() && !check_secure())
9455 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009456 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009457# ifdef WIN32
9458 /* The server's HWND is encoded in the 'id' parameter */
9459 long_u n = 0;
9460# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009461
9462 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009463 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009464
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009465# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009466 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9467 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009468 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009469 if (r == NULL)
9470# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009471 if (check_connection() == FAIL
9472 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9473 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009474# endif
9475 EMSG(_("E277: Unable to read a server reply"));
9476 }
9477#endif
9478 rettv->v_type = VAR_STRING;
9479 rettv->vval.v_string = r;
9480}
9481
9482/*
9483 * "remote_send()" function
9484 */
9485 static void
9486f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9487{
9488 rettv->v_type = VAR_STRING;
9489 rettv->vval.v_string = NULL;
9490#ifdef FEAT_CLIENTSERVER
9491 remote_common(argvars, rettv, FALSE);
9492#endif
9493}
9494
9495/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009496 * "remote_startserver()" function
9497 */
9498 static void
9499f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9500{
9501#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009502 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009503
9504 if (server == NULL)
9505 return; /* type error; errmsg already given */
9506 if (serverName != NULL)
9507 EMSG(_("E941: already started a server"));
9508 else
9509 {
9510# ifdef FEAT_X11
9511 if (check_connection() == OK)
9512 serverRegisterName(X_DISPLAY, server);
9513# else
9514 serverSetName(server);
9515# endif
9516 }
9517#else
9518 EMSG(_("E942: +clientserver feature not available"));
9519#endif
9520}
9521
9522/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009523 * "remove()" function
9524 */
9525 static void
9526f_remove(typval_T *argvars, typval_T *rettv)
9527{
9528 list_T *l;
9529 listitem_T *item, *item2;
9530 listitem_T *li;
9531 long idx;
9532 long end;
9533 char_u *key;
9534 dict_T *d;
9535 dictitem_T *di;
9536 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9537
9538 if (argvars[0].v_type == VAR_DICT)
9539 {
9540 if (argvars[2].v_type != VAR_UNKNOWN)
9541 EMSG2(_(e_toomanyarg), "remove()");
9542 else if ((d = argvars[0].vval.v_dict) != NULL
9543 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9544 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009545 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009546 if (key != NULL)
9547 {
9548 di = dict_find(d, key, -1);
9549 if (di == NULL)
9550 EMSG2(_(e_dictkey), key);
9551 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9552 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9553 {
9554 *rettv = di->di_tv;
9555 init_tv(&di->di_tv);
9556 dictitem_remove(d, di);
9557 }
9558 }
9559 }
9560 }
9561 else if (argvars[0].v_type != VAR_LIST)
9562 EMSG2(_(e_listdictarg), "remove()");
9563 else if ((l = argvars[0].vval.v_list) != NULL
9564 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9565 {
9566 int error = FALSE;
9567
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009568 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009569 if (error)
9570 ; /* type error: do nothing, errmsg already given */
9571 else if ((item = list_find(l, idx)) == NULL)
9572 EMSGN(_(e_listidx), idx);
9573 else
9574 {
9575 if (argvars[2].v_type == VAR_UNKNOWN)
9576 {
9577 /* Remove one item, return its value. */
9578 vimlist_remove(l, item, item);
9579 *rettv = item->li_tv;
9580 vim_free(item);
9581 }
9582 else
9583 {
9584 /* Remove range of items, return list with values. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009585 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009586 if (error)
9587 ; /* type error: do nothing */
9588 else if ((item2 = list_find(l, end)) == NULL)
9589 EMSGN(_(e_listidx), end);
9590 else
9591 {
9592 int cnt = 0;
9593
9594 for (li = item; li != NULL; li = li->li_next)
9595 {
9596 ++cnt;
9597 if (li == item2)
9598 break;
9599 }
9600 if (li == NULL) /* didn't find "item2" after "item" */
9601 EMSG(_(e_invrange));
9602 else
9603 {
9604 vimlist_remove(l, item, item2);
9605 if (rettv_list_alloc(rettv) == OK)
9606 {
9607 l = rettv->vval.v_list;
9608 l->lv_first = item;
9609 l->lv_last = item2;
9610 item->li_prev = NULL;
9611 item2->li_next = NULL;
9612 l->lv_len = cnt;
9613 }
9614 }
9615 }
9616 }
9617 }
9618 }
9619}
9620
9621/*
9622 * "rename({from}, {to})" function
9623 */
9624 static void
9625f_rename(typval_T *argvars, typval_T *rettv)
9626{
9627 char_u buf[NUMBUFLEN];
9628
9629 if (check_restricted() || check_secure())
9630 rettv->vval.v_number = -1;
9631 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009632 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9633 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009634}
9635
9636/*
9637 * "repeat()" function
9638 */
9639 static void
9640f_repeat(typval_T *argvars, typval_T *rettv)
9641{
9642 char_u *p;
9643 int n;
9644 int slen;
9645 int len;
9646 char_u *r;
9647 int i;
9648
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009649 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009650 if (argvars[0].v_type == VAR_LIST)
9651 {
9652 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9653 while (n-- > 0)
9654 if (list_extend(rettv->vval.v_list,
9655 argvars[0].vval.v_list, NULL) == FAIL)
9656 break;
9657 }
9658 else
9659 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009660 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009661 rettv->v_type = VAR_STRING;
9662 rettv->vval.v_string = NULL;
9663
9664 slen = (int)STRLEN(p);
9665 len = slen * n;
9666 if (len <= 0)
9667 return;
9668
9669 r = alloc(len + 1);
9670 if (r != NULL)
9671 {
9672 for (i = 0; i < n; i++)
9673 mch_memmove(r + i * slen, p, (size_t)slen);
9674 r[len] = NUL;
9675 }
9676
9677 rettv->vval.v_string = r;
9678 }
9679}
9680
9681/*
9682 * "resolve()" function
9683 */
9684 static void
9685f_resolve(typval_T *argvars, typval_T *rettv)
9686{
9687 char_u *p;
9688#ifdef HAVE_READLINK
9689 char_u *buf = NULL;
9690#endif
9691
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009692 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009693#ifdef FEAT_SHORTCUT
9694 {
9695 char_u *v = NULL;
9696
9697 v = mch_resolve_shortcut(p);
9698 if (v != NULL)
9699 rettv->vval.v_string = v;
9700 else
9701 rettv->vval.v_string = vim_strsave(p);
9702 }
9703#else
9704# ifdef HAVE_READLINK
9705 {
9706 char_u *cpy;
9707 int len;
9708 char_u *remain = NULL;
9709 char_u *q;
9710 int is_relative_to_current = FALSE;
9711 int has_trailing_pathsep = FALSE;
9712 int limit = 100;
9713
9714 p = vim_strsave(p);
9715
9716 if (p[0] == '.' && (vim_ispathsep(p[1])
9717 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9718 is_relative_to_current = TRUE;
9719
9720 len = STRLEN(p);
9721 if (len > 0 && after_pathsep(p, p + len))
9722 {
9723 has_trailing_pathsep = TRUE;
9724 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9725 }
9726
9727 q = getnextcomp(p);
9728 if (*q != NUL)
9729 {
9730 /* Separate the first path component in "p", and keep the
9731 * remainder (beginning with the path separator). */
9732 remain = vim_strsave(q - 1);
9733 q[-1] = NUL;
9734 }
9735
9736 buf = alloc(MAXPATHL + 1);
9737 if (buf == NULL)
9738 goto fail;
9739
9740 for (;;)
9741 {
9742 for (;;)
9743 {
9744 len = readlink((char *)p, (char *)buf, MAXPATHL);
9745 if (len <= 0)
9746 break;
9747 buf[len] = NUL;
9748
9749 if (limit-- == 0)
9750 {
9751 vim_free(p);
9752 vim_free(remain);
9753 EMSG(_("E655: Too many symbolic links (cycle?)"));
9754 rettv->vval.v_string = NULL;
9755 goto fail;
9756 }
9757
9758 /* Ensure that the result will have a trailing path separator
9759 * if the argument has one. */
9760 if (remain == NULL && has_trailing_pathsep)
9761 add_pathsep(buf);
9762
9763 /* Separate the first path component in the link value and
9764 * concatenate the remainders. */
9765 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9766 if (*q != NUL)
9767 {
9768 if (remain == NULL)
9769 remain = vim_strsave(q - 1);
9770 else
9771 {
9772 cpy = concat_str(q - 1, remain);
9773 if (cpy != NULL)
9774 {
9775 vim_free(remain);
9776 remain = cpy;
9777 }
9778 }
9779 q[-1] = NUL;
9780 }
9781
9782 q = gettail(p);
9783 if (q > p && *q == NUL)
9784 {
9785 /* Ignore trailing path separator. */
9786 q[-1] = NUL;
9787 q = gettail(p);
9788 }
9789 if (q > p && !mch_isFullName(buf))
9790 {
9791 /* symlink is relative to directory of argument */
9792 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9793 if (cpy != NULL)
9794 {
9795 STRCPY(cpy, p);
9796 STRCPY(gettail(cpy), buf);
9797 vim_free(p);
9798 p = cpy;
9799 }
9800 }
9801 else
9802 {
9803 vim_free(p);
9804 p = vim_strsave(buf);
9805 }
9806 }
9807
9808 if (remain == NULL)
9809 break;
9810
9811 /* Append the first path component of "remain" to "p". */
9812 q = getnextcomp(remain + 1);
9813 len = q - remain - (*q != NUL);
9814 cpy = vim_strnsave(p, STRLEN(p) + len);
9815 if (cpy != NULL)
9816 {
9817 STRNCAT(cpy, remain, len);
9818 vim_free(p);
9819 p = cpy;
9820 }
9821 /* Shorten "remain". */
9822 if (*q != NUL)
9823 STRMOVE(remain, q - 1);
9824 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009825 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009826 }
9827
9828 /* If the result is a relative path name, make it explicitly relative to
9829 * the current directory if and only if the argument had this form. */
9830 if (!vim_ispathsep(*p))
9831 {
9832 if (is_relative_to_current
9833 && *p != NUL
9834 && !(p[0] == '.'
9835 && (p[1] == NUL
9836 || vim_ispathsep(p[1])
9837 || (p[1] == '.'
9838 && (p[2] == NUL
9839 || vim_ispathsep(p[2]))))))
9840 {
9841 /* Prepend "./". */
9842 cpy = concat_str((char_u *)"./", p);
9843 if (cpy != NULL)
9844 {
9845 vim_free(p);
9846 p = cpy;
9847 }
9848 }
9849 else if (!is_relative_to_current)
9850 {
9851 /* Strip leading "./". */
9852 q = p;
9853 while (q[0] == '.' && vim_ispathsep(q[1]))
9854 q += 2;
9855 if (q > p)
9856 STRMOVE(p, p + 2);
9857 }
9858 }
9859
9860 /* Ensure that the result will have no trailing path separator
9861 * if the argument had none. But keep "/" or "//". */
9862 if (!has_trailing_pathsep)
9863 {
9864 q = p + STRLEN(p);
9865 if (after_pathsep(p, q))
9866 *gettail_sep(p) = NUL;
9867 }
9868
9869 rettv->vval.v_string = p;
9870 }
9871# else
9872 rettv->vval.v_string = vim_strsave(p);
9873# endif
9874#endif
9875
9876 simplify_filename(rettv->vval.v_string);
9877
9878#ifdef HAVE_READLINK
9879fail:
9880 vim_free(buf);
9881#endif
9882 rettv->v_type = VAR_STRING;
9883}
9884
9885/*
9886 * "reverse({list})" function
9887 */
9888 static void
9889f_reverse(typval_T *argvars, typval_T *rettv)
9890{
9891 list_T *l;
9892 listitem_T *li, *ni;
9893
9894 if (argvars[0].v_type != VAR_LIST)
9895 EMSG2(_(e_listarg), "reverse()");
9896 else if ((l = argvars[0].vval.v_list) != NULL
9897 && !tv_check_lock(l->lv_lock,
9898 (char_u *)N_("reverse() argument"), TRUE))
9899 {
9900 li = l->lv_last;
9901 l->lv_first = l->lv_last = NULL;
9902 l->lv_len = 0;
9903 while (li != NULL)
9904 {
9905 ni = li->li_prev;
9906 list_append(l, li);
9907 li = ni;
9908 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009909 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009910 l->lv_idx = l->lv_len - l->lv_idx - 1;
9911 }
9912}
9913
9914#define SP_NOMOVE 0x01 /* don't move cursor */
9915#define SP_REPEAT 0x02 /* repeat to find outer pair */
9916#define SP_RETCOUNT 0x04 /* return matchcount */
9917#define SP_SETPCMARK 0x08 /* set previous context mark */
9918#define SP_START 0x10 /* accept match at start position */
9919#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9920#define SP_END 0x40 /* leave cursor at end of match */
9921#define SP_COLUMN 0x80 /* start at cursor column */
9922
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009923/*
9924 * Get flags for a search function.
9925 * Possibly sets "p_ws".
9926 * Returns BACKWARD, FORWARD or zero (for an error).
9927 */
9928 static int
9929get_search_arg(typval_T *varp, int *flagsp)
9930{
9931 int dir = FORWARD;
9932 char_u *flags;
9933 char_u nbuf[NUMBUFLEN];
9934 int mask;
9935
9936 if (varp->v_type != VAR_UNKNOWN)
9937 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009938 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009939 if (flags == NULL)
9940 return 0; /* type error; errmsg already given */
9941 while (*flags != NUL)
9942 {
9943 switch (*flags)
9944 {
9945 case 'b': dir = BACKWARD; break;
9946 case 'w': p_ws = TRUE; break;
9947 case 'W': p_ws = FALSE; break;
9948 default: mask = 0;
9949 if (flagsp != NULL)
9950 switch (*flags)
9951 {
9952 case 'c': mask = SP_START; break;
9953 case 'e': mask = SP_END; break;
9954 case 'm': mask = SP_RETCOUNT; break;
9955 case 'n': mask = SP_NOMOVE; break;
9956 case 'p': mask = SP_SUBPAT; break;
9957 case 'r': mask = SP_REPEAT; break;
9958 case 's': mask = SP_SETPCMARK; break;
9959 case 'z': mask = SP_COLUMN; break;
9960 }
9961 if (mask == 0)
9962 {
9963 EMSG2(_(e_invarg2), flags);
9964 dir = 0;
9965 }
9966 else
9967 *flagsp |= mask;
9968 }
9969 if (dir == 0)
9970 break;
9971 ++flags;
9972 }
9973 }
9974 return dir;
9975}
9976
9977/*
9978 * Shared by search() and searchpos() functions.
9979 */
9980 static int
9981search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9982{
9983 int flags;
9984 char_u *pat;
9985 pos_T pos;
9986 pos_T save_cursor;
9987 int save_p_ws = p_ws;
9988 int dir;
9989 int retval = 0; /* default: FAIL */
9990 long lnum_stop = 0;
9991 proftime_T tm;
9992#ifdef FEAT_RELTIME
9993 long time_limit = 0;
9994#endif
9995 int options = SEARCH_KEEP;
9996 int subpatnum;
9997
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009998 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009999 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10000 if (dir == 0)
10001 goto theend;
10002 flags = *flagsp;
10003 if (flags & SP_START)
10004 options |= SEARCH_START;
10005 if (flags & SP_END)
10006 options |= SEARCH_END;
10007 if (flags & SP_COLUMN)
10008 options |= SEARCH_COL;
10009
10010 /* Optional arguments: line number to stop searching and timeout. */
10011 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10012 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010013 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010014 if (lnum_stop < 0)
10015 goto theend;
10016#ifdef FEAT_RELTIME
10017 if (argvars[3].v_type != VAR_UNKNOWN)
10018 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010019 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010020 if (time_limit < 0)
10021 goto theend;
10022 }
10023#endif
10024 }
10025
10026#ifdef FEAT_RELTIME
10027 /* Set the time limit, if there is one. */
10028 profile_setlimit(time_limit, &tm);
10029#endif
10030
10031 /*
10032 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10033 * Check to make sure only those flags are set.
10034 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10035 * flags cannot be set. Check for that condition also.
10036 */
10037 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10038 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10039 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010040 EMSG2(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010041 goto theend;
10042 }
10043
10044 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010045 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010046 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010047 if (subpatnum != FAIL)
10048 {
10049 if (flags & SP_SUBPAT)
10050 retval = subpatnum;
10051 else
10052 retval = pos.lnum;
10053 if (flags & SP_SETPCMARK)
10054 setpcmark();
10055 curwin->w_cursor = pos;
10056 if (match_pos != NULL)
10057 {
10058 /* Store the match cursor position */
10059 match_pos->lnum = pos.lnum;
10060 match_pos->col = pos.col + 1;
10061 }
10062 /* "/$" will put the cursor after the end of the line, may need to
10063 * correct that here */
10064 check_cursor();
10065 }
10066
10067 /* If 'n' flag is used: restore cursor position. */
10068 if (flags & SP_NOMOVE)
10069 curwin->w_cursor = save_cursor;
10070 else
10071 curwin->w_set_curswant = TRUE;
10072theend:
10073 p_ws = save_p_ws;
10074
10075 return retval;
10076}
10077
10078#ifdef FEAT_FLOAT
10079
10080/*
10081 * round() is not in C90, use ceil() or floor() instead.
10082 */
10083 float_T
10084vim_round(float_T f)
10085{
10086 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10087}
10088
10089/*
10090 * "round({float})" function
10091 */
10092 static void
10093f_round(typval_T *argvars, typval_T *rettv)
10094{
10095 float_T f = 0.0;
10096
10097 rettv->v_type = VAR_FLOAT;
10098 if (get_float_arg(argvars, &f) == OK)
10099 rettv->vval.v_float = vim_round(f);
10100 else
10101 rettv->vval.v_float = 0.0;
10102}
10103#endif
10104
10105/*
10106 * "screenattr()" function
10107 */
10108 static void
10109f_screenattr(typval_T *argvars, typval_T *rettv)
10110{
10111 int row;
10112 int col;
10113 int c;
10114
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010115 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10116 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010117 if (row < 0 || row >= screen_Rows
10118 || col < 0 || col >= screen_Columns)
10119 c = -1;
10120 else
10121 c = ScreenAttrs[LineOffset[row] + col];
10122 rettv->vval.v_number = c;
10123}
10124
10125/*
10126 * "screenchar()" function
10127 */
10128 static void
10129f_screenchar(typval_T *argvars, typval_T *rettv)
10130{
10131 int row;
10132 int col;
10133 int off;
10134 int c;
10135
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010136 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10137 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010138 if (row < 0 || row >= screen_Rows
10139 || col < 0 || col >= screen_Columns)
10140 c = -1;
10141 else
10142 {
10143 off = LineOffset[row] + col;
10144#ifdef FEAT_MBYTE
10145 if (enc_utf8 && ScreenLinesUC[off] != 0)
10146 c = ScreenLinesUC[off];
10147 else
10148#endif
10149 c = ScreenLines[off];
10150 }
10151 rettv->vval.v_number = c;
10152}
10153
10154/*
10155 * "screencol()" function
10156 *
10157 * First column is 1 to be consistent with virtcol().
10158 */
10159 static void
10160f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10161{
10162 rettv->vval.v_number = screen_screencol() + 1;
10163}
10164
10165/*
10166 * "screenrow()" function
10167 */
10168 static void
10169f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10170{
10171 rettv->vval.v_number = screen_screenrow() + 1;
10172}
10173
10174/*
10175 * "search()" function
10176 */
10177 static void
10178f_search(typval_T *argvars, typval_T *rettv)
10179{
10180 int flags = 0;
10181
10182 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10183}
10184
10185/*
10186 * "searchdecl()" function
10187 */
10188 static void
10189f_searchdecl(typval_T *argvars, typval_T *rettv)
10190{
10191 int locally = 1;
10192 int thisblock = 0;
10193 int error = FALSE;
10194 char_u *name;
10195
10196 rettv->vval.v_number = 1; /* default: FAIL */
10197
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010198 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010199 if (argvars[1].v_type != VAR_UNKNOWN)
10200 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010201 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010202 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010203 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010204 }
10205 if (!error && name != NULL)
10206 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10207 locally, thisblock, SEARCH_KEEP) == FAIL;
10208}
10209
10210/*
10211 * Used by searchpair() and searchpairpos()
10212 */
10213 static int
10214searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10215{
10216 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010217 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010218 int save_p_ws = p_ws;
10219 int dir;
10220 int flags = 0;
10221 char_u nbuf1[NUMBUFLEN];
10222 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010223 int retval = 0; /* default: FAIL */
10224 long lnum_stop = 0;
10225 long time_limit = 0;
10226
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010227 /* Get the three pattern arguments: start, middle, end. Will result in an
10228 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010229 spat = tv_get_string_chk(&argvars[0]);
10230 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10231 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010232 if (spat == NULL || mpat == NULL || epat == NULL)
10233 goto theend; /* type error */
10234
10235 /* Handle the optional fourth argument: flags */
10236 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10237 if (dir == 0)
10238 goto theend;
10239
10240 /* Don't accept SP_END or SP_SUBPAT.
10241 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10242 */
10243 if ((flags & (SP_END | SP_SUBPAT)) != 0
10244 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10245 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010246 EMSG2(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010247 goto theend;
10248 }
10249
10250 /* Using 'r' implies 'W', otherwise it doesn't work. */
10251 if (flags & SP_REPEAT)
10252 p_ws = FALSE;
10253
10254 /* Optional fifth argument: skip expression */
10255 if (argvars[3].v_type == VAR_UNKNOWN
10256 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010257 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010258 else
10259 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010260 skip = &argvars[4];
10261 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10262 && skip->v_type != VAR_STRING)
10263 {
10264 /* Type error */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010265 EMSG2(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010266 goto theend;
10267 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010268 if (argvars[5].v_type != VAR_UNKNOWN)
10269 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010270 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010271 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010273 EMSG2(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010274 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010275 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010276#ifdef FEAT_RELTIME
10277 if (argvars[6].v_type != VAR_UNKNOWN)
10278 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010279 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010280 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010281 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010282 EMSG2(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010283 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010284 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010285 }
10286#endif
10287 }
10288 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010289
10290 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10291 match_pos, lnum_stop, time_limit);
10292
10293theend:
10294 p_ws = save_p_ws;
10295
10296 return retval;
10297}
10298
10299/*
10300 * "searchpair()" function
10301 */
10302 static void
10303f_searchpair(typval_T *argvars, typval_T *rettv)
10304{
10305 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10306}
10307
10308/*
10309 * "searchpairpos()" function
10310 */
10311 static void
10312f_searchpairpos(typval_T *argvars, typval_T *rettv)
10313{
10314 pos_T match_pos;
10315 int lnum = 0;
10316 int col = 0;
10317
10318 if (rettv_list_alloc(rettv) == FAIL)
10319 return;
10320
10321 if (searchpair_cmn(argvars, &match_pos) > 0)
10322 {
10323 lnum = match_pos.lnum;
10324 col = match_pos.col;
10325 }
10326
10327 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10328 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10329}
10330
10331/*
10332 * Search for a start/middle/end thing.
10333 * Used by searchpair(), see its documentation for the details.
10334 * Returns 0 or -1 for no match,
10335 */
10336 long
10337do_searchpair(
10338 char_u *spat, /* start pattern */
10339 char_u *mpat, /* middle pattern */
10340 char_u *epat, /* end pattern */
10341 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010342 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010343 int flags, /* SP_SETPCMARK and other SP_ values */
10344 pos_T *match_pos,
10345 linenr_T lnum_stop, /* stop at this line if not zero */
10346 long time_limit UNUSED) /* stop after this many msec */
10347{
10348 char_u *save_cpo;
10349 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10350 long retval = 0;
10351 pos_T pos;
10352 pos_T firstpos;
10353 pos_T foundpos;
10354 pos_T save_cursor;
10355 pos_T save_pos;
10356 int n;
10357 int r;
10358 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010359 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010360 int err;
10361 int options = SEARCH_KEEP;
10362 proftime_T tm;
10363
10364 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10365 save_cpo = p_cpo;
10366 p_cpo = empty_option;
10367
10368#ifdef FEAT_RELTIME
10369 /* Set the time limit, if there is one. */
10370 profile_setlimit(time_limit, &tm);
10371#endif
10372
10373 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10374 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010375 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10376 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010377 if (pat2 == NULL || pat3 == NULL)
10378 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010379 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010380 if (*mpat == NUL)
10381 STRCPY(pat3, pat2);
10382 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010383 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010384 spat, epat, mpat);
10385 if (flags & SP_START)
10386 options |= SEARCH_START;
10387
Bram Moolenaar48570482017-10-30 21:48:41 +010010388 if (skip != NULL)
10389 {
10390 /* Empty string means to not use the skip expression. */
10391 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10392 use_skip = skip->vval.v_string != NULL
10393 && *skip->vval.v_string != NUL;
10394 }
10395
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010396 save_cursor = curwin->w_cursor;
10397 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010398 CLEAR_POS(&firstpos);
10399 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010400 pat = pat3;
10401 for (;;)
10402 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010403 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010404 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010405 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010406 /* didn't find it or found the first match again: FAIL */
10407 break;
10408
10409 if (firstpos.lnum == 0)
10410 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010411 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010412 {
10413 /* Found the same position again. Can happen with a pattern that
10414 * has "\zs" at the end and searching backwards. Advance one
10415 * character and try again. */
10416 if (dir == BACKWARD)
10417 decl(&pos);
10418 else
10419 incl(&pos);
10420 }
10421 foundpos = pos;
10422
10423 /* clear the start flag to avoid getting stuck here */
10424 options &= ~SEARCH_START;
10425
10426 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010427 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010428 {
10429 save_pos = curwin->w_cursor;
10430 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010431 err = FALSE;
10432 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010433 curwin->w_cursor = save_pos;
10434 if (err)
10435 {
10436 /* Evaluating {skip} caused an error, break here. */
10437 curwin->w_cursor = save_cursor;
10438 retval = -1;
10439 break;
10440 }
10441 if (r)
10442 continue;
10443 }
10444
10445 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10446 {
10447 /* Found end when searching backwards or start when searching
10448 * forward: nested pair. */
10449 ++nest;
10450 pat = pat2; /* nested, don't search for middle */
10451 }
10452 else
10453 {
10454 /* Found end when searching forward or start when searching
10455 * backward: end of (nested) pair; or found middle in outer pair. */
10456 if (--nest == 1)
10457 pat = pat3; /* outer level, search for middle */
10458 }
10459
10460 if (nest == 0)
10461 {
10462 /* Found the match: return matchcount or line number. */
10463 if (flags & SP_RETCOUNT)
10464 ++retval;
10465 else
10466 retval = pos.lnum;
10467 if (flags & SP_SETPCMARK)
10468 setpcmark();
10469 curwin->w_cursor = pos;
10470 if (!(flags & SP_REPEAT))
10471 break;
10472 nest = 1; /* search for next unmatched */
10473 }
10474 }
10475
10476 if (match_pos != NULL)
10477 {
10478 /* Store the match cursor position */
10479 match_pos->lnum = curwin->w_cursor.lnum;
10480 match_pos->col = curwin->w_cursor.col + 1;
10481 }
10482
10483 /* If 'n' flag is used or search failed: restore cursor position. */
10484 if ((flags & SP_NOMOVE) || retval == 0)
10485 curwin->w_cursor = save_cursor;
10486
10487theend:
10488 vim_free(pat2);
10489 vim_free(pat3);
10490 if (p_cpo == empty_option)
10491 p_cpo = save_cpo;
10492 else
10493 /* Darn, evaluating the {skip} expression changed the value. */
10494 free_string_option(save_cpo);
10495
10496 return retval;
10497}
10498
10499/*
10500 * "searchpos()" function
10501 */
10502 static void
10503f_searchpos(typval_T *argvars, typval_T *rettv)
10504{
10505 pos_T match_pos;
10506 int lnum = 0;
10507 int col = 0;
10508 int n;
10509 int flags = 0;
10510
10511 if (rettv_list_alloc(rettv) == FAIL)
10512 return;
10513
10514 n = search_cmn(argvars, &match_pos, &flags);
10515 if (n > 0)
10516 {
10517 lnum = match_pos.lnum;
10518 col = match_pos.col;
10519 }
10520
10521 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10522 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10523 if (flags & SP_SUBPAT)
10524 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10525}
10526
10527 static void
10528f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10529{
10530#ifdef FEAT_CLIENTSERVER
10531 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010532 char_u *server = tv_get_string_chk(&argvars[0]);
10533 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010534
10535 rettv->vval.v_number = -1;
10536 if (server == NULL || reply == NULL)
10537 return;
10538 if (check_restricted() || check_secure())
10539 return;
10540# ifdef FEAT_X11
10541 if (check_connection() == FAIL)
10542 return;
10543# endif
10544
10545 if (serverSendReply(server, reply) < 0)
10546 {
10547 EMSG(_("E258: Unable to send to client"));
10548 return;
10549 }
10550 rettv->vval.v_number = 0;
10551#else
10552 rettv->vval.v_number = -1;
10553#endif
10554}
10555
10556 static void
10557f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10558{
10559 char_u *r = NULL;
10560
10561#ifdef FEAT_CLIENTSERVER
10562# ifdef WIN32
10563 r = serverGetVimNames();
10564# else
10565 make_connection();
10566 if (X_DISPLAY != NULL)
10567 r = serverGetVimNames(X_DISPLAY);
10568# endif
10569#endif
10570 rettv->v_type = VAR_STRING;
10571 rettv->vval.v_string = r;
10572}
10573
10574/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010575 * "setbufline()" function
10576 */
10577 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010578f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010579{
10580 linenr_T lnum;
10581 buf_T *buf;
10582
10583 buf = get_buf_tv(&argvars[0], FALSE);
10584 if (buf == NULL)
10585 rettv->vval.v_number = 1; /* FAIL */
10586 else
10587 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010588 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010589 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010590 }
10591}
10592
10593/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010594 * "setbufvar()" function
10595 */
10596 static void
10597f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10598{
10599 buf_T *buf;
10600 char_u *varname, *bufvarname;
10601 typval_T *varp;
10602 char_u nbuf[NUMBUFLEN];
10603
10604 if (check_restricted() || check_secure())
10605 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010606 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10607 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010608 buf = get_buf_tv(&argvars[0], FALSE);
10609 varp = &argvars[2];
10610
10611 if (buf != NULL && varname != NULL && varp != NULL)
10612 {
10613 if (*varname == '&')
10614 {
10615 long numval;
10616 char_u *strval;
10617 int error = FALSE;
10618 aco_save_T aco;
10619
10620 /* set curbuf to be our buf, temporarily */
10621 aucmd_prepbuf(&aco, buf);
10622
10623 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010624 numval = (long)tv_get_number_chk(varp, &error);
10625 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010626 if (!error && strval != NULL)
10627 set_option_value(varname, numval, strval, OPT_LOCAL);
10628
10629 /* reset notion of buffer */
10630 aucmd_restbuf(&aco);
10631 }
10632 else
10633 {
10634 buf_T *save_curbuf = curbuf;
10635
10636 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10637 if (bufvarname != NULL)
10638 {
10639 curbuf = buf;
10640 STRCPY(bufvarname, "b:");
10641 STRCPY(bufvarname + 2, varname);
10642 set_var(bufvarname, varp, TRUE);
10643 vim_free(bufvarname);
10644 curbuf = save_curbuf;
10645 }
10646 }
10647 }
10648}
10649
10650 static void
10651f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10652{
10653 dict_T *d;
10654 dictitem_T *di;
10655 char_u *csearch;
10656
10657 if (argvars[0].v_type != VAR_DICT)
10658 {
10659 EMSG(_(e_dictreq));
10660 return;
10661 }
10662
10663 if ((d = argvars[0].vval.v_dict) != NULL)
10664 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010665 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010666 if (csearch != NULL)
10667 {
10668#ifdef FEAT_MBYTE
10669 if (enc_utf8)
10670 {
10671 int pcc[MAX_MCO];
10672 int c = utfc_ptr2char(csearch, pcc);
10673
10674 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10675 }
10676 else
10677#endif
10678 set_last_csearch(PTR2CHAR(csearch),
10679 csearch, MB_PTR2LEN(csearch));
10680 }
10681
10682 di = dict_find(d, (char_u *)"forward", -1);
10683 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010684 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010685 ? FORWARD : BACKWARD);
10686
10687 di = dict_find(d, (char_u *)"until", -1);
10688 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010689 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010690 }
10691}
10692
10693/*
10694 * "setcmdpos()" function
10695 */
10696 static void
10697f_setcmdpos(typval_T *argvars, typval_T *rettv)
10698{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010699 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010700
10701 if (pos >= 0)
10702 rettv->vval.v_number = set_cmdline_pos(pos);
10703}
10704
10705/*
10706 * "setfperm({fname}, {mode})" function
10707 */
10708 static void
10709f_setfperm(typval_T *argvars, typval_T *rettv)
10710{
10711 char_u *fname;
10712 char_u modebuf[NUMBUFLEN];
10713 char_u *mode_str;
10714 int i;
10715 int mask;
10716 int mode = 0;
10717
10718 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010719 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010720 if (fname == NULL)
10721 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010722 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010723 if (mode_str == NULL)
10724 return;
10725 if (STRLEN(mode_str) != 9)
10726 {
10727 EMSG2(_(e_invarg2), mode_str);
10728 return;
10729 }
10730
10731 mask = 1;
10732 for (i = 8; i >= 0; --i)
10733 {
10734 if (mode_str[i] != '-')
10735 mode |= mask;
10736 mask = mask << 1;
10737 }
10738 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10739}
10740
10741/*
10742 * "setline()" function
10743 */
10744 static void
10745f_setline(typval_T *argvars, typval_T *rettv)
10746{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010747 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010748
Bram Moolenaarca851592018-06-06 21:04:07 +020010749 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010750}
10751
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010752/*
10753 * Used by "setqflist()" and "setloclist()" functions
10754 */
10755 static void
10756set_qf_ll_list(
10757 win_T *wp UNUSED,
10758 typval_T *list_arg UNUSED,
10759 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010760 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010761 typval_T *rettv)
10762{
10763#ifdef FEAT_QUICKFIX
10764 static char *e_invact = N_("E927: Invalid action: '%s'");
10765 char_u *act;
10766 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010767 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010768#endif
10769
10770 rettv->vval.v_number = -1;
10771
10772#ifdef FEAT_QUICKFIX
10773 if (list_arg->v_type != VAR_LIST)
10774 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010775 else if (recursive != 0)
10776 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010777 else
10778 {
10779 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010780 dict_T *d = NULL;
10781 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782
10783 if (action_arg->v_type == VAR_STRING)
10784 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010785 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010786 if (act == NULL)
10787 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010788 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10789 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010790 action = *act;
10791 else
10792 EMSG2(_(e_invact), act);
10793 }
10794 else if (action_arg->v_type == VAR_UNKNOWN)
10795 action = ' ';
10796 else
10797 EMSG(_(e_stringreq));
10798
Bram Moolenaard823fa92016-08-12 16:29:27 +020010799 if (action_arg->v_type != VAR_UNKNOWN
10800 && what_arg->v_type != VAR_UNKNOWN)
10801 {
10802 if (what_arg->v_type == VAR_DICT)
10803 d = what_arg->vval.v_dict;
10804 else
10805 {
10806 EMSG(_(e_dictreq));
10807 valid_dict = FALSE;
10808 }
10809 }
10810
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010811 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010812 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010813 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10814 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010815 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010816 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010817 }
10818#endif
10819}
10820
10821/*
10822 * "setloclist()" function
10823 */
10824 static void
10825f_setloclist(typval_T *argvars, typval_T *rettv)
10826{
10827 win_T *win;
10828
10829 rettv->vval.v_number = -1;
10830
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010831 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010832 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010833 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010834}
10835
10836/*
10837 * "setmatches()" function
10838 */
10839 static void
10840f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10841{
10842#ifdef FEAT_SEARCH_EXTRA
10843 list_T *l;
10844 listitem_T *li;
10845 dict_T *d;
10846 list_T *s = NULL;
10847
10848 rettv->vval.v_number = -1;
10849 if (argvars[0].v_type != VAR_LIST)
10850 {
10851 EMSG(_(e_listreq));
10852 return;
10853 }
10854 if ((l = argvars[0].vval.v_list) != NULL)
10855 {
10856
10857 /* To some extent make sure that we are dealing with a list from
10858 * "getmatches()". */
10859 li = l->lv_first;
10860 while (li != NULL)
10861 {
10862 if (li->li_tv.v_type != VAR_DICT
10863 || (d = li->li_tv.vval.v_dict) == NULL)
10864 {
10865 EMSG(_(e_invarg));
10866 return;
10867 }
10868 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10869 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10870 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10871 && dict_find(d, (char_u *)"priority", -1) != NULL
10872 && dict_find(d, (char_u *)"id", -1) != NULL))
10873 {
10874 EMSG(_(e_invarg));
10875 return;
10876 }
10877 li = li->li_next;
10878 }
10879
10880 clear_matches(curwin);
10881 li = l->lv_first;
10882 while (li != NULL)
10883 {
10884 int i = 0;
10885 char_u buf[5];
10886 dictitem_T *di;
10887 char_u *group;
10888 int priority;
10889 int id;
10890 char_u *conceal;
10891
10892 d = li->li_tv.vval.v_dict;
10893 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10894 {
10895 if (s == NULL)
10896 {
10897 s = list_alloc();
10898 if (s == NULL)
10899 return;
10900 }
10901
10902 /* match from matchaddpos() */
10903 for (i = 1; i < 9; i++)
10904 {
10905 sprintf((char *)buf, (char *)"pos%d", i);
10906 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10907 {
10908 if (di->di_tv.v_type != VAR_LIST)
10909 return;
10910
10911 list_append_tv(s, &di->di_tv);
10912 s->lv_refcount++;
10913 }
10914 else
10915 break;
10916 }
10917 }
10918
Bram Moolenaar8f667172018-12-14 15:38:31 +010010919 group = dict_get_string(d, (char_u *)"group", TRUE);
10920 priority = (int)dict_get_number(d, (char_u *)"priority");
10921 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010922 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010010923 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010924 : NULL;
10925 if (i == 0)
10926 {
10927 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010010928 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010929 priority, id, NULL, conceal);
10930 }
10931 else
10932 {
10933 match_add(curwin, group, NULL, priority, id, s, conceal);
10934 list_unref(s);
10935 s = NULL;
10936 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010937 vim_free(group);
10938 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010939
10940 li = li->li_next;
10941 }
10942 rettv->vval.v_number = 0;
10943 }
10944#endif
10945}
10946
10947/*
10948 * "setpos()" function
10949 */
10950 static void
10951f_setpos(typval_T *argvars, typval_T *rettv)
10952{
10953 pos_T pos;
10954 int fnum;
10955 char_u *name;
10956 colnr_T curswant = -1;
10957
10958 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010959 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010960 if (name != NULL)
10961 {
10962 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10963 {
10964 if (--pos.col < 0)
10965 pos.col = 0;
10966 if (name[0] == '.' && name[1] == NUL)
10967 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010968 /* set cursor; "fnum" is ignored */
10969 curwin->w_cursor = pos;
10970 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010971 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010972 curwin->w_curswant = curswant - 1;
10973 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010974 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010975 check_cursor();
10976 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010977 }
10978 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10979 {
10980 /* set mark */
10981 if (setmark_pos(name[1], &pos, fnum) == OK)
10982 rettv->vval.v_number = 0;
10983 }
10984 else
10985 EMSG(_(e_invarg));
10986 }
10987 }
10988}
10989
10990/*
10991 * "setqflist()" function
10992 */
10993 static void
10994f_setqflist(typval_T *argvars, typval_T *rettv)
10995{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010996 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997}
10998
10999/*
11000 * "setreg()" function
11001 */
11002 static void
11003f_setreg(typval_T *argvars, typval_T *rettv)
11004{
11005 int regname;
11006 char_u *strregname;
11007 char_u *stropt;
11008 char_u *strval;
11009 int append;
11010 char_u yank_type;
11011 long block_len;
11012
11013 block_len = -1;
11014 yank_type = MAUTO;
11015 append = FALSE;
11016
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011017 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011018 rettv->vval.v_number = 1; /* FAIL is default */
11019
11020 if (strregname == NULL)
11021 return; /* type error; errmsg already given */
11022 regname = *strregname;
11023 if (regname == 0 || regname == '@')
11024 regname = '"';
11025
11026 if (argvars[2].v_type != VAR_UNKNOWN)
11027 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011028 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011029 if (stropt == NULL)
11030 return; /* type error */
11031 for (; *stropt != NUL; ++stropt)
11032 switch (*stropt)
11033 {
11034 case 'a': case 'A': /* append */
11035 append = TRUE;
11036 break;
11037 case 'v': case 'c': /* character-wise selection */
11038 yank_type = MCHAR;
11039 break;
11040 case 'V': case 'l': /* line-wise selection */
11041 yank_type = MLINE;
11042 break;
11043 case 'b': case Ctrl_V: /* block-wise selection */
11044 yank_type = MBLOCK;
11045 if (VIM_ISDIGIT(stropt[1]))
11046 {
11047 ++stropt;
11048 block_len = getdigits(&stropt) - 1;
11049 --stropt;
11050 }
11051 break;
11052 }
11053 }
11054
11055 if (argvars[1].v_type == VAR_LIST)
11056 {
11057 char_u **lstval;
11058 char_u **allocval;
11059 char_u buf[NUMBUFLEN];
11060 char_u **curval;
11061 char_u **curallocval;
11062 list_T *ll = argvars[1].vval.v_list;
11063 listitem_T *li;
11064 int len;
11065
11066 /* If the list is NULL handle like an empty list. */
11067 len = ll == NULL ? 0 : ll->lv_len;
11068
11069 /* First half: use for pointers to result lines; second half: use for
11070 * pointers to allocated copies. */
11071 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11072 if (lstval == NULL)
11073 return;
11074 curval = lstval;
11075 allocval = lstval + len + 2;
11076 curallocval = allocval;
11077
11078 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11079 li = li->li_next)
11080 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011081 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011082 if (strval == NULL)
11083 goto free_lstval;
11084 if (strval == buf)
11085 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011086 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011087 * overwrite the string. */
11088 strval = vim_strsave(buf);
11089 if (strval == NULL)
11090 goto free_lstval;
11091 *curallocval++ = strval;
11092 }
11093 *curval++ = strval;
11094 }
11095 *curval++ = NULL;
11096
11097 write_reg_contents_lst(regname, lstval, -1,
11098 append, yank_type, block_len);
11099free_lstval:
11100 while (curallocval > allocval)
11101 vim_free(*--curallocval);
11102 vim_free(lstval);
11103 }
11104 else
11105 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011106 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011107 if (strval == NULL)
11108 return;
11109 write_reg_contents_ex(regname, strval, -1,
11110 append, yank_type, block_len);
11111 }
11112 rettv->vval.v_number = 0;
11113}
11114
11115/*
11116 * "settabvar()" function
11117 */
11118 static void
11119f_settabvar(typval_T *argvars, typval_T *rettv)
11120{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011121 tabpage_T *save_curtab;
11122 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011123 char_u *varname, *tabvarname;
11124 typval_T *varp;
11125
11126 rettv->vval.v_number = 0;
11127
11128 if (check_restricted() || check_secure())
11129 return;
11130
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011131 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11132 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011133 varp = &argvars[2];
11134
Bram Moolenaar4033c552017-09-16 20:54:51 +020011135 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011136 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011137 save_curtab = curtab;
11138 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011139
11140 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11141 if (tabvarname != NULL)
11142 {
11143 STRCPY(tabvarname, "t:");
11144 STRCPY(tabvarname + 2, varname);
11145 set_var(tabvarname, varp, TRUE);
11146 vim_free(tabvarname);
11147 }
11148
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011149 /* Restore current tabpage */
11150 if (valid_tabpage(save_curtab))
11151 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152 }
11153}
11154
11155/*
11156 * "settabwinvar()" function
11157 */
11158 static void
11159f_settabwinvar(typval_T *argvars, typval_T *rettv)
11160{
11161 setwinvar(argvars, rettv, 1);
11162}
11163
11164/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011165 * "settagstack()" function
11166 */
11167 static void
11168f_settagstack(typval_T *argvars, typval_T *rettv)
11169{
11170 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11171 win_T *wp;
11172 dict_T *d;
11173 int action = 'r';
11174
11175 rettv->vval.v_number = -1;
11176
11177 // first argument: window number or id
11178 wp = find_win_by_nr_or_id(&argvars[0]);
11179 if (wp == NULL)
11180 return;
11181
11182 // second argument: dict with items to set in the tag stack
11183 if (argvars[1].v_type != VAR_DICT)
11184 {
11185 EMSG(_(e_dictreq));
11186 return;
11187 }
11188 d = argvars[1].vval.v_dict;
11189 if (d == NULL)
11190 return;
11191
11192 // third argument: action - 'a' for append and 'r' for replace.
11193 // default is to replace the stack.
11194 if (argvars[2].v_type == VAR_UNKNOWN)
11195 action = 'r';
11196 else if (argvars[2].v_type == VAR_STRING)
11197 {
11198 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011199 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011200 if (actstr == NULL)
11201 return;
11202 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11203 action = *actstr;
11204 else
11205 {
11206 EMSG2(_(e_invact2), actstr);
11207 return;
11208 }
11209 }
11210 else
11211 {
11212 EMSG(_(e_stringreq));
11213 return;
11214 }
11215
11216 if (set_tagstack(wp, d, action) == OK)
11217 rettv->vval.v_number = 0;
11218}
11219
11220/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011221 * "setwinvar()" function
11222 */
11223 static void
11224f_setwinvar(typval_T *argvars, typval_T *rettv)
11225{
11226 setwinvar(argvars, rettv, 0);
11227}
11228
11229#ifdef FEAT_CRYPT
11230/*
11231 * "sha256({string})" function
11232 */
11233 static void
11234f_sha256(typval_T *argvars, typval_T *rettv)
11235{
11236 char_u *p;
11237
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011238 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011239 rettv->vval.v_string = vim_strsave(
11240 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11241 rettv->v_type = VAR_STRING;
11242}
11243#endif /* FEAT_CRYPT */
11244
11245/*
11246 * "shellescape({string})" function
11247 */
11248 static void
11249f_shellescape(typval_T *argvars, typval_T *rettv)
11250{
Bram Moolenaar20615522017-06-05 18:46:26 +020011251 int do_special = non_zero_arg(&argvars[1]);
11252
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011253 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011254 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011255 rettv->v_type = VAR_STRING;
11256}
11257
11258/*
11259 * shiftwidth() function
11260 */
11261 static void
11262f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11263{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011264 rettv->vval.v_number = 0;
11265
11266 if (argvars[0].v_type != VAR_UNKNOWN)
11267 {
11268 long col;
11269
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011270 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011271 if (col < 0)
11272 return; // type error; errmsg already given
11273#ifdef FEAT_VARTABS
11274 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11275 return;
11276#endif
11277 }
11278
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011279 rettv->vval.v_number = get_sw_value(curbuf);
11280}
11281
Bram Moolenaar162b7142018-12-21 15:17:36 +010011282#ifdef FEAT_SIGNS
11283/*
11284 * "sign_define()" function
11285 */
11286 static void
11287f_sign_define(typval_T *argvars, typval_T *rettv)
11288{
11289 char_u *name;
11290 dict_T *dict;
11291 char_u *icon = NULL;
11292 char_u *linehl = NULL;
11293 char_u *text = NULL;
11294 char_u *texthl = NULL;
11295
11296 rettv->vval.v_number = -1;
11297
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011298 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011299 if (name == NULL)
11300 return;
11301
11302 if (argvars[1].v_type != VAR_UNKNOWN)
11303 {
11304 if (argvars[1].v_type != VAR_DICT)
11305 {
11306 EMSG(_(e_dictreq));
11307 return;
11308 }
11309
11310 // sign attributes
11311 dict = argvars[1].vval.v_dict;
11312 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11313 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11314 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11315 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11316 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11317 text = dict_get_string(dict, (char_u *)"text", TRUE);
11318 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11319 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11320 }
11321
11322 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11323 rettv->vval.v_number = 0;
11324
11325 vim_free(icon);
11326 vim_free(linehl);
11327 vim_free(text);
11328 vim_free(texthl);
11329}
11330
11331/*
11332 * "sign_getdefined()" function
11333 */
11334 static void
11335f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11336{
11337 char_u *name = NULL;
11338
11339 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11340 return;
11341
11342 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011343 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011344
11345 sign_getlist(name, rettv->vval.v_list);
11346}
11347
11348/*
11349 * "sign_getplaced()" function
11350 */
11351 static void
11352f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11353{
11354 buf_T *buf = NULL;
11355 dict_T *dict;
11356 dictitem_T *di;
11357 linenr_T lnum = 0;
11358 int sign_id = 0;
11359 char_u *group = NULL;
11360 int notanum = FALSE;
11361
11362 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11363 return;
11364
11365 if (argvars[0].v_type != VAR_UNKNOWN)
11366 {
11367 // get signs placed in this buffer
Bram Moolenaar2cbc1a02019-01-02 13:40:31 +010011368 buf = get_buf_tv(&argvars[0], FALSE);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011369 if (buf == NULL)
11370 {
11371 EMSG2(_("E158: Invalid buffer name: %s"),
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011372 tv_get_string(&argvars[0]));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011373 return;
11374 }
11375
11376 if (argvars[1].v_type != VAR_UNKNOWN)
11377 {
11378 if (argvars[1].v_type != VAR_DICT ||
11379 ((dict = argvars[1].vval.v_dict) == NULL))
11380 {
11381 EMSG(_(e_dictreq));
11382 return;
11383 }
11384 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11385 {
11386 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011387 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011388 if (notanum)
11389 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011390 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011391 }
11392 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11393 {
11394 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011395 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011396 if (notanum)
11397 return;
11398 }
11399 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11400 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011401 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011402 if (group == NULL)
11403 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011404 if (*group == '\0') // empty string means global group
11405 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011406 }
11407 }
11408 }
11409
11410 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11411}
11412
11413/*
11414 * "sign_place()" function
11415 */
11416 static void
11417f_sign_place(typval_T *argvars, typval_T *rettv)
11418{
11419 int sign_id;
11420 char_u *group = NULL;
11421 char_u *sign_name;
11422 buf_T *buf;
11423 dict_T *dict;
11424 dictitem_T *di;
11425 linenr_T lnum = 0;
11426 int prio = SIGN_DEF_PRIO;
11427 int notanum = FALSE;
11428
11429 rettv->vval.v_number = -1;
11430
11431 // Sign identifer
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011432 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011433 if (notanum)
11434 return;
11435 if (sign_id < 0)
11436 {
11437 EMSG(_(e_invarg));
11438 return;
11439 }
11440
11441 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011442 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011443 if (group == NULL)
11444 return;
11445 if (group[0] == '\0')
11446 group = NULL; // global sign group
11447 else
11448 {
11449 group = vim_strsave(group);
11450 if (group == NULL)
11451 return;
11452 }
11453
11454 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011455 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011456 if (sign_name == NULL)
11457 goto cleanup;
11458
11459 // Buffer to place the sign
Bram Moolenaar2cbc1a02019-01-02 13:40:31 +010011460 buf = get_buf_tv(&argvars[3], FALSE);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011461 if (buf == NULL)
11462 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011463 EMSG2(_("E158: Invalid buffer name: %s"), tv_get_string(&argvars[2]));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011464 goto cleanup;
11465 }
11466
11467 if (argvars[4].v_type != VAR_UNKNOWN)
11468 {
11469 if (argvars[4].v_type != VAR_DICT ||
11470 ((dict = argvars[4].vval.v_dict) == NULL))
11471 {
11472 EMSG(_(e_dictreq));
11473 goto cleanup;
11474 }
11475
11476 // Line number where the sign is to be placed
11477 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11478 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011479 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011480 if (notanum)
11481 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011482 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011483 }
11484 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11485 {
11486 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011487 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011488 if (notanum)
11489 goto cleanup;
11490 }
11491 }
11492
11493 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11494 rettv->vval.v_number = sign_id;
11495
11496cleanup:
11497 vim_free(group);
11498}
11499
11500/*
11501 * "sign_undefine()" function
11502 */
11503 static void
11504f_sign_undefine(typval_T *argvars, typval_T *rettv)
11505{
11506 char_u *name;
11507
11508 rettv->vval.v_number = -1;
11509
11510 if (argvars[0].v_type == VAR_UNKNOWN)
11511 {
11512 // Free all the signs
11513 free_signs();
11514 rettv->vval.v_number = 0;
11515 }
11516 else
11517 {
11518 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011519 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011520 if (name == NULL)
11521 return;
11522
11523 if (sign_undefine_by_name(name) == OK)
11524 rettv->vval.v_number = 0;
11525 }
11526}
11527
11528/*
11529 * "sign_unplace()" function
11530 */
11531 static void
11532f_sign_unplace(typval_T *argvars, typval_T *rettv)
11533{
11534 dict_T *dict;
11535 dictitem_T *di;
11536 int sign_id = 0;
11537 buf_T *buf = NULL;
11538 char_u *group = NULL;
11539
11540 rettv->vval.v_number = -1;
11541
11542 if (argvars[0].v_type != VAR_STRING)
11543 {
11544 EMSG(_(e_invarg));
11545 return;
11546 }
11547
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011548 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011549 if (group[0] == '\0')
11550 group = NULL; // global sign group
11551 else
11552 {
11553 group = vim_strsave(group);
11554 if (group == NULL)
11555 return;
11556 }
11557
11558 if (argvars[1].v_type != VAR_UNKNOWN)
11559 {
11560 if (argvars[1].v_type != VAR_DICT)
11561 {
11562 EMSG(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011563 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011564 }
11565 dict = argvars[1].vval.v_dict;
11566
11567 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11568 {
Bram Moolenaar2cbc1a02019-01-02 13:40:31 +010011569 buf = get_buf_tv(&di->di_tv, FALSE);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011570 if (buf == NULL)
11571 {
11572 EMSG2(_("E158: Invalid buffer name: %s"),
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011573 tv_get_string(&di->di_tv));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011574 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011575 }
11576 }
11577 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11578 sign_id = dict_get_number(dict, (char_u *)"id");
11579 }
11580
11581 if (buf == NULL)
11582 {
11583 // Delete the sign in all the buffers
11584 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011585 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011586 rettv->vval.v_number = 0;
11587 }
11588 else
11589 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011590 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011591 rettv->vval.v_number = 0;
11592 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011593
11594cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010011595 vim_free(group);
11596}
11597#endif
11598
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011599/*
11600 * "simplify()" function
11601 */
11602 static void
11603f_simplify(typval_T *argvars, typval_T *rettv)
11604{
11605 char_u *p;
11606
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011607 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011608 rettv->vval.v_string = vim_strsave(p);
11609 simplify_filename(rettv->vval.v_string); /* simplify in place */
11610 rettv->v_type = VAR_STRING;
11611}
11612
11613#ifdef FEAT_FLOAT
11614/*
11615 * "sin()" function
11616 */
11617 static void
11618f_sin(typval_T *argvars, typval_T *rettv)
11619{
11620 float_T f = 0.0;
11621
11622 rettv->v_type = VAR_FLOAT;
11623 if (get_float_arg(argvars, &f) == OK)
11624 rettv->vval.v_float = sin(f);
11625 else
11626 rettv->vval.v_float = 0.0;
11627}
11628
11629/*
11630 * "sinh()" function
11631 */
11632 static void
11633f_sinh(typval_T *argvars, typval_T *rettv)
11634{
11635 float_T f = 0.0;
11636
11637 rettv->v_type = VAR_FLOAT;
11638 if (get_float_arg(argvars, &f) == OK)
11639 rettv->vval.v_float = sinh(f);
11640 else
11641 rettv->vval.v_float = 0.0;
11642}
11643#endif
11644
11645static int
11646#ifdef __BORLANDC__
11647 _RTLENTRYF
11648#endif
11649 item_compare(const void *s1, const void *s2);
11650static int
11651#ifdef __BORLANDC__
11652 _RTLENTRYF
11653#endif
11654 item_compare2(const void *s1, const void *s2);
11655
11656/* struct used in the array that's given to qsort() */
11657typedef struct
11658{
11659 listitem_T *item;
11660 int idx;
11661} sortItem_T;
11662
11663/* struct storing information about current sort */
11664typedef struct
11665{
11666 int item_compare_ic;
11667 int item_compare_numeric;
11668 int item_compare_numbers;
11669#ifdef FEAT_FLOAT
11670 int item_compare_float;
11671#endif
11672 char_u *item_compare_func;
11673 partial_T *item_compare_partial;
11674 dict_T *item_compare_selfdict;
11675 int item_compare_func_err;
11676 int item_compare_keep_zero;
11677} sortinfo_T;
11678static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011679#define ITEM_COMPARE_FAIL 999
11680
11681/*
11682 * Compare functions for f_sort() and f_uniq() below.
11683 */
11684 static int
11685#ifdef __BORLANDC__
11686_RTLENTRYF
11687#endif
11688item_compare(const void *s1, const void *s2)
11689{
11690 sortItem_T *si1, *si2;
11691 typval_T *tv1, *tv2;
11692 char_u *p1, *p2;
11693 char_u *tofree1 = NULL, *tofree2 = NULL;
11694 int res;
11695 char_u numbuf1[NUMBUFLEN];
11696 char_u numbuf2[NUMBUFLEN];
11697
11698 si1 = (sortItem_T *)s1;
11699 si2 = (sortItem_T *)s2;
11700 tv1 = &si1->item->li_tv;
11701 tv2 = &si2->item->li_tv;
11702
11703 if (sortinfo->item_compare_numbers)
11704 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011705 varnumber_T v1 = tv_get_number(tv1);
11706 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011707
11708 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11709 }
11710
11711#ifdef FEAT_FLOAT
11712 if (sortinfo->item_compare_float)
11713 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011714 float_T v1 = tv_get_float(tv1);
11715 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011716
11717 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11718 }
11719#endif
11720
11721 /* tv2string() puts quotes around a string and allocates memory. Don't do
11722 * that for string variables. Use a single quote when comparing with a
11723 * non-string to do what the docs promise. */
11724 if (tv1->v_type == VAR_STRING)
11725 {
11726 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11727 p1 = (char_u *)"'";
11728 else
11729 p1 = tv1->vval.v_string;
11730 }
11731 else
11732 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11733 if (tv2->v_type == VAR_STRING)
11734 {
11735 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11736 p2 = (char_u *)"'";
11737 else
11738 p2 = tv2->vval.v_string;
11739 }
11740 else
11741 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11742 if (p1 == NULL)
11743 p1 = (char_u *)"";
11744 if (p2 == NULL)
11745 p2 = (char_u *)"";
11746 if (!sortinfo->item_compare_numeric)
11747 {
11748 if (sortinfo->item_compare_ic)
11749 res = STRICMP(p1, p2);
11750 else
11751 res = STRCMP(p1, p2);
11752 }
11753 else
11754 {
11755 double n1, n2;
11756 n1 = strtod((char *)p1, (char **)&p1);
11757 n2 = strtod((char *)p2, (char **)&p2);
11758 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11759 }
11760
11761 /* When the result would be zero, compare the item indexes. Makes the
11762 * sort stable. */
11763 if (res == 0 && !sortinfo->item_compare_keep_zero)
11764 res = si1->idx > si2->idx ? 1 : -1;
11765
11766 vim_free(tofree1);
11767 vim_free(tofree2);
11768 return res;
11769}
11770
11771 static int
11772#ifdef __BORLANDC__
11773_RTLENTRYF
11774#endif
11775item_compare2(const void *s1, const void *s2)
11776{
11777 sortItem_T *si1, *si2;
11778 int res;
11779 typval_T rettv;
11780 typval_T argv[3];
11781 int dummy;
11782 char_u *func_name;
11783 partial_T *partial = sortinfo->item_compare_partial;
11784
11785 /* shortcut after failure in previous call; compare all items equal */
11786 if (sortinfo->item_compare_func_err)
11787 return 0;
11788
11789 si1 = (sortItem_T *)s1;
11790 si2 = (sortItem_T *)s2;
11791
11792 if (partial == NULL)
11793 func_name = sortinfo->item_compare_func;
11794 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011795 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011796
11797 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11798 * in the copy without changing the original list items. */
11799 copy_tv(&si1->item->li_tv, &argv[0]);
11800 copy_tv(&si2->item->li_tv, &argv[1]);
11801
11802 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11803 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011804 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011805 partial, sortinfo->item_compare_selfdict);
11806 clear_tv(&argv[0]);
11807 clear_tv(&argv[1]);
11808
11809 if (res == FAIL)
11810 res = ITEM_COMPARE_FAIL;
11811 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011812 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011813 if (sortinfo->item_compare_func_err)
11814 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11815 clear_tv(&rettv);
11816
11817 /* When the result would be zero, compare the pointers themselves. Makes
11818 * the sort stable. */
11819 if (res == 0 && !sortinfo->item_compare_keep_zero)
11820 res = si1->idx > si2->idx ? 1 : -1;
11821
11822 return res;
11823}
11824
11825/*
11826 * "sort({list})" function
11827 */
11828 static void
11829do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11830{
11831 list_T *l;
11832 listitem_T *li;
11833 sortItem_T *ptrs;
11834 sortinfo_T *old_sortinfo;
11835 sortinfo_T info;
11836 long len;
11837 long i;
11838
11839 /* Pointer to current info struct used in compare function. Save and
11840 * restore the current one for nested calls. */
11841 old_sortinfo = sortinfo;
11842 sortinfo = &info;
11843
11844 if (argvars[0].v_type != VAR_LIST)
11845 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11846 else
11847 {
11848 l = argvars[0].vval.v_list;
11849 if (l == NULL || tv_check_lock(l->lv_lock,
11850 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11851 TRUE))
11852 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011853 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011854
11855 len = list_len(l);
11856 if (len <= 1)
11857 goto theend; /* short list sorts pretty quickly */
11858
11859 info.item_compare_ic = FALSE;
11860 info.item_compare_numeric = FALSE;
11861 info.item_compare_numbers = FALSE;
11862#ifdef FEAT_FLOAT
11863 info.item_compare_float = FALSE;
11864#endif
11865 info.item_compare_func = NULL;
11866 info.item_compare_partial = NULL;
11867 info.item_compare_selfdict = NULL;
11868 if (argvars[1].v_type != VAR_UNKNOWN)
11869 {
11870 /* optional second argument: {func} */
11871 if (argvars[1].v_type == VAR_FUNC)
11872 info.item_compare_func = argvars[1].vval.v_string;
11873 else if (argvars[1].v_type == VAR_PARTIAL)
11874 info.item_compare_partial = argvars[1].vval.v_partial;
11875 else
11876 {
11877 int error = FALSE;
11878
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011879 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011880 if (error)
11881 goto theend; /* type error; errmsg already given */
11882 if (i == 1)
11883 info.item_compare_ic = TRUE;
11884 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011885 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011886 else if (i != 0)
11887 {
11888 EMSG(_(e_invarg));
11889 goto theend;
11890 }
11891 if (info.item_compare_func != NULL)
11892 {
11893 if (*info.item_compare_func == NUL)
11894 {
11895 /* empty string means default sort */
11896 info.item_compare_func = NULL;
11897 }
11898 else if (STRCMP(info.item_compare_func, "n") == 0)
11899 {
11900 info.item_compare_func = NULL;
11901 info.item_compare_numeric = TRUE;
11902 }
11903 else if (STRCMP(info.item_compare_func, "N") == 0)
11904 {
11905 info.item_compare_func = NULL;
11906 info.item_compare_numbers = TRUE;
11907 }
11908#ifdef FEAT_FLOAT
11909 else if (STRCMP(info.item_compare_func, "f") == 0)
11910 {
11911 info.item_compare_func = NULL;
11912 info.item_compare_float = TRUE;
11913 }
11914#endif
11915 else if (STRCMP(info.item_compare_func, "i") == 0)
11916 {
11917 info.item_compare_func = NULL;
11918 info.item_compare_ic = TRUE;
11919 }
11920 }
11921 }
11922
11923 if (argvars[2].v_type != VAR_UNKNOWN)
11924 {
11925 /* optional third argument: {dict} */
11926 if (argvars[2].v_type != VAR_DICT)
11927 {
11928 EMSG(_(e_dictreq));
11929 goto theend;
11930 }
11931 info.item_compare_selfdict = argvars[2].vval.v_dict;
11932 }
11933 }
11934
11935 /* Make an array with each entry pointing to an item in the List. */
11936 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11937 if (ptrs == NULL)
11938 goto theend;
11939
11940 i = 0;
11941 if (sort)
11942 {
11943 /* sort(): ptrs will be the list to sort */
11944 for (li = l->lv_first; li != NULL; li = li->li_next)
11945 {
11946 ptrs[i].item = li;
11947 ptrs[i].idx = i;
11948 ++i;
11949 }
11950
11951 info.item_compare_func_err = FALSE;
11952 info.item_compare_keep_zero = FALSE;
11953 /* test the compare function */
11954 if ((info.item_compare_func != NULL
11955 || info.item_compare_partial != NULL)
11956 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11957 == ITEM_COMPARE_FAIL)
11958 EMSG(_("E702: Sort compare function failed"));
11959 else
11960 {
11961 /* Sort the array with item pointers. */
11962 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11963 info.item_compare_func == NULL
11964 && info.item_compare_partial == NULL
11965 ? item_compare : item_compare2);
11966
11967 if (!info.item_compare_func_err)
11968 {
11969 /* Clear the List and append the items in sorted order. */
11970 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11971 l->lv_len = 0;
11972 for (i = 0; i < len; ++i)
11973 list_append(l, ptrs[i].item);
11974 }
11975 }
11976 }
11977 else
11978 {
11979 int (*item_compare_func_ptr)(const void *, const void *);
11980
11981 /* f_uniq(): ptrs will be a stack of items to remove */
11982 info.item_compare_func_err = FALSE;
11983 info.item_compare_keep_zero = TRUE;
11984 item_compare_func_ptr = info.item_compare_func != NULL
11985 || info.item_compare_partial != NULL
11986 ? item_compare2 : item_compare;
11987
11988 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11989 li = li->li_next)
11990 {
11991 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11992 == 0)
11993 ptrs[i++].item = li;
11994 if (info.item_compare_func_err)
11995 {
11996 EMSG(_("E882: Uniq compare function failed"));
11997 break;
11998 }
11999 }
12000
12001 if (!info.item_compare_func_err)
12002 {
12003 while (--i >= 0)
12004 {
12005 li = ptrs[i].item->li_next;
12006 ptrs[i].item->li_next = li->li_next;
12007 if (li->li_next != NULL)
12008 li->li_next->li_prev = ptrs[i].item;
12009 else
12010 l->lv_last = ptrs[i].item;
12011 list_fix_watch(l, li);
12012 listitem_free(li);
12013 l->lv_len--;
12014 }
12015 }
12016 }
12017
12018 vim_free(ptrs);
12019 }
12020theend:
12021 sortinfo = old_sortinfo;
12022}
12023
12024/*
12025 * "sort({list})" function
12026 */
12027 static void
12028f_sort(typval_T *argvars, typval_T *rettv)
12029{
12030 do_sort_uniq(argvars, rettv, TRUE);
12031}
12032
12033/*
12034 * "uniq({list})" function
12035 */
12036 static void
12037f_uniq(typval_T *argvars, typval_T *rettv)
12038{
12039 do_sort_uniq(argvars, rettv, FALSE);
12040}
12041
12042/*
12043 * "soundfold({word})" function
12044 */
12045 static void
12046f_soundfold(typval_T *argvars, typval_T *rettv)
12047{
12048 char_u *s;
12049
12050 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012051 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012052#ifdef FEAT_SPELL
12053 rettv->vval.v_string = eval_soundfold(s);
12054#else
12055 rettv->vval.v_string = vim_strsave(s);
12056#endif
12057}
12058
12059/*
12060 * "spellbadword()" function
12061 */
12062 static void
12063f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12064{
12065 char_u *word = (char_u *)"";
12066 hlf_T attr = HLF_COUNT;
12067 int len = 0;
12068
12069 if (rettv_list_alloc(rettv) == FAIL)
12070 return;
12071
12072#ifdef FEAT_SPELL
12073 if (argvars[0].v_type == VAR_UNKNOWN)
12074 {
12075 /* Find the start and length of the badly spelled word. */
12076 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12077 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012078 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012079 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012080 curwin->w_set_curswant = TRUE;
12081 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012082 }
12083 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12084 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012085 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012086 int capcol = -1;
12087
12088 if (str != NULL)
12089 {
12090 /* Check the argument for spelling. */
12091 while (*str != NUL)
12092 {
12093 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12094 if (attr != HLF_COUNT)
12095 {
12096 word = str;
12097 break;
12098 }
12099 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012100 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012101 }
12102 }
12103 }
12104#endif
12105
12106 list_append_string(rettv->vval.v_list, word, len);
12107 list_append_string(rettv->vval.v_list, (char_u *)(
12108 attr == HLF_SPB ? "bad" :
12109 attr == HLF_SPR ? "rare" :
12110 attr == HLF_SPL ? "local" :
12111 attr == HLF_SPC ? "caps" :
12112 ""), -1);
12113}
12114
12115/*
12116 * "spellsuggest()" function
12117 */
12118 static void
12119f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12120{
12121#ifdef FEAT_SPELL
12122 char_u *str;
12123 int typeerr = FALSE;
12124 int maxcount;
12125 garray_T ga;
12126 int i;
12127 listitem_T *li;
12128 int need_capital = FALSE;
12129#endif
12130
12131 if (rettv_list_alloc(rettv) == FAIL)
12132 return;
12133
12134#ifdef FEAT_SPELL
12135 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012137 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012138 if (argvars[1].v_type != VAR_UNKNOWN)
12139 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012140 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012141 if (maxcount <= 0)
12142 return;
12143 if (argvars[2].v_type != VAR_UNKNOWN)
12144 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012145 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012146 if (typeerr)
12147 return;
12148 }
12149 }
12150 else
12151 maxcount = 25;
12152
12153 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12154
12155 for (i = 0; i < ga.ga_len; ++i)
12156 {
12157 str = ((char_u **)ga.ga_data)[i];
12158
12159 li = listitem_alloc();
12160 if (li == NULL)
12161 vim_free(str);
12162 else
12163 {
12164 li->li_tv.v_type = VAR_STRING;
12165 li->li_tv.v_lock = 0;
12166 li->li_tv.vval.v_string = str;
12167 list_append(rettv->vval.v_list, li);
12168 }
12169 }
12170 ga_clear(&ga);
12171 }
12172#endif
12173}
12174
12175 static void
12176f_split(typval_T *argvars, typval_T *rettv)
12177{
12178 char_u *str;
12179 char_u *end;
12180 char_u *pat = NULL;
12181 regmatch_T regmatch;
12182 char_u patbuf[NUMBUFLEN];
12183 char_u *save_cpo;
12184 int match;
12185 colnr_T col = 0;
12186 int keepempty = FALSE;
12187 int typeerr = FALSE;
12188
12189 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12190 save_cpo = p_cpo;
12191 p_cpo = (char_u *)"";
12192
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012193 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012194 if (argvars[1].v_type != VAR_UNKNOWN)
12195 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012196 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012197 if (pat == NULL)
12198 typeerr = TRUE;
12199 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012200 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012201 }
12202 if (pat == NULL || *pat == NUL)
12203 pat = (char_u *)"[\\x01- ]\\+";
12204
12205 if (rettv_list_alloc(rettv) == FAIL)
12206 return;
12207 if (typeerr)
12208 return;
12209
12210 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12211 if (regmatch.regprog != NULL)
12212 {
12213 regmatch.rm_ic = FALSE;
12214 while (*str != NUL || keepempty)
12215 {
12216 if (*str == NUL)
12217 match = FALSE; /* empty item at the end */
12218 else
12219 match = vim_regexec_nl(&regmatch, str, col);
12220 if (match)
12221 end = regmatch.startp[0];
12222 else
12223 end = str + STRLEN(str);
12224 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12225 && *str != NUL && match && end < regmatch.endp[0]))
12226 {
12227 if (list_append_string(rettv->vval.v_list, str,
12228 (int)(end - str)) == FAIL)
12229 break;
12230 }
12231 if (!match)
12232 break;
12233 /* Advance to just after the match. */
12234 if (regmatch.endp[0] > str)
12235 col = 0;
12236 else
12237 {
12238 /* Don't get stuck at the same match. */
12239#ifdef FEAT_MBYTE
12240 col = (*mb_ptr2len)(regmatch.endp[0]);
12241#else
12242 col = 1;
12243#endif
12244 }
12245 str = regmatch.endp[0];
12246 }
12247
12248 vim_regfree(regmatch.regprog);
12249 }
12250
12251 p_cpo = save_cpo;
12252}
12253
12254#ifdef FEAT_FLOAT
12255/*
12256 * "sqrt()" function
12257 */
12258 static void
12259f_sqrt(typval_T *argvars, typval_T *rettv)
12260{
12261 float_T f = 0.0;
12262
12263 rettv->v_type = VAR_FLOAT;
12264 if (get_float_arg(argvars, &f) == OK)
12265 rettv->vval.v_float = sqrt(f);
12266 else
12267 rettv->vval.v_float = 0.0;
12268}
12269
12270/*
12271 * "str2float()" function
12272 */
12273 static void
12274f_str2float(typval_T *argvars, typval_T *rettv)
12275{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012276 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012277 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012278
Bram Moolenaar08243d22017-01-10 16:12:29 +010012279 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012280 p = skipwhite(p + 1);
12281 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012282 if (isneg)
12283 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012284 rettv->v_type = VAR_FLOAT;
12285}
12286#endif
12287
12288/*
12289 * "str2nr()" function
12290 */
12291 static void
12292f_str2nr(typval_T *argvars, typval_T *rettv)
12293{
12294 int base = 10;
12295 char_u *p;
12296 varnumber_T n;
12297 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012298 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012299
12300 if (argvars[1].v_type != VAR_UNKNOWN)
12301 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012302 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012303 if (base != 2 && base != 8 && base != 10 && base != 16)
12304 {
12305 EMSG(_(e_invarg));
12306 return;
12307 }
12308 }
12309
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012310 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012311 isneg = (*p == '-');
12312 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012313 p = skipwhite(p + 1);
12314 switch (base)
12315 {
12316 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12317 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12318 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12319 default: what = 0;
12320 }
12321 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012322 if (isneg)
12323 rettv->vval.v_number = -n;
12324 else
12325 rettv->vval.v_number = n;
12326
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012327}
12328
12329#ifdef HAVE_STRFTIME
12330/*
12331 * "strftime({format}[, {time}])" function
12332 */
12333 static void
12334f_strftime(typval_T *argvars, typval_T *rettv)
12335{
12336 char_u result_buf[256];
12337 struct tm *curtime;
12338 time_t seconds;
12339 char_u *p;
12340
12341 rettv->v_type = VAR_STRING;
12342
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012343 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012344 if (argvars[1].v_type == VAR_UNKNOWN)
12345 seconds = time(NULL);
12346 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012347 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012348 curtime = localtime(&seconds);
12349 /* MSVC returns NULL for an invalid value of seconds. */
12350 if (curtime == NULL)
12351 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12352 else
12353 {
12354# ifdef FEAT_MBYTE
12355 vimconv_T conv;
12356 char_u *enc;
12357
12358 conv.vc_type = CONV_NONE;
12359 enc = enc_locale();
12360 convert_setup(&conv, p_enc, enc);
12361 if (conv.vc_type != CONV_NONE)
12362 p = string_convert(&conv, p, NULL);
12363# endif
12364 if (p != NULL)
12365 (void)strftime((char *)result_buf, sizeof(result_buf),
12366 (char *)p, curtime);
12367 else
12368 result_buf[0] = NUL;
12369
12370# ifdef FEAT_MBYTE
12371 if (conv.vc_type != CONV_NONE)
12372 vim_free(p);
12373 convert_setup(&conv, enc, p_enc);
12374 if (conv.vc_type != CONV_NONE)
12375 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12376 else
12377# endif
12378 rettv->vval.v_string = vim_strsave(result_buf);
12379
12380# ifdef FEAT_MBYTE
12381 /* Release conversion descriptors */
12382 convert_setup(&conv, NULL, NULL);
12383 vim_free(enc);
12384# endif
12385 }
12386}
12387#endif
12388
12389/*
12390 * "strgetchar()" function
12391 */
12392 static void
12393f_strgetchar(typval_T *argvars, typval_T *rettv)
12394{
12395 char_u *str;
12396 int len;
12397 int error = FALSE;
12398 int charidx;
12399
12400 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012401 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012402 if (str == NULL)
12403 return;
12404 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012405 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012406 if (error)
12407 return;
12408#ifdef FEAT_MBYTE
12409 {
12410 int byteidx = 0;
12411
12412 while (charidx >= 0 && byteidx < len)
12413 {
12414 if (charidx == 0)
12415 {
12416 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12417 break;
12418 }
12419 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012420 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012421 }
12422 }
12423#else
12424 if (charidx < len)
12425 rettv->vval.v_number = str[charidx];
12426#endif
12427}
12428
12429/*
12430 * "stridx()" function
12431 */
12432 static void
12433f_stridx(typval_T *argvars, typval_T *rettv)
12434{
12435 char_u buf[NUMBUFLEN];
12436 char_u *needle;
12437 char_u *haystack;
12438 char_u *save_haystack;
12439 char_u *pos;
12440 int start_idx;
12441
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012442 needle = tv_get_string_chk(&argvars[1]);
12443 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012444 rettv->vval.v_number = -1;
12445 if (needle == NULL || haystack == NULL)
12446 return; /* type error; errmsg already given */
12447
12448 if (argvars[2].v_type != VAR_UNKNOWN)
12449 {
12450 int error = FALSE;
12451
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012452 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012453 if (error || start_idx >= (int)STRLEN(haystack))
12454 return;
12455 if (start_idx >= 0)
12456 haystack += start_idx;
12457 }
12458
12459 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12460 if (pos != NULL)
12461 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12462}
12463
12464/*
12465 * "string()" function
12466 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012467 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012468f_string(typval_T *argvars, typval_T *rettv)
12469{
12470 char_u *tofree;
12471 char_u numbuf[NUMBUFLEN];
12472
12473 rettv->v_type = VAR_STRING;
12474 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12475 get_copyID());
12476 /* Make a copy if we have a value but it's not in allocated memory. */
12477 if (rettv->vval.v_string != NULL && tofree == NULL)
12478 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12479}
12480
12481/*
12482 * "strlen()" function
12483 */
12484 static void
12485f_strlen(typval_T *argvars, typval_T *rettv)
12486{
12487 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012488 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012489}
12490
12491/*
12492 * "strchars()" function
12493 */
12494 static void
12495f_strchars(typval_T *argvars, typval_T *rettv)
12496{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012497 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012498 int skipcc = 0;
12499#ifdef FEAT_MBYTE
12500 varnumber_T len = 0;
12501 int (*func_mb_ptr2char_adv)(char_u **pp);
12502#endif
12503
12504 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012505 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012506 if (skipcc < 0 || skipcc > 1)
12507 EMSG(_(e_invarg));
12508 else
12509 {
12510#ifdef FEAT_MBYTE
12511 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12512 while (*s != NUL)
12513 {
12514 func_mb_ptr2char_adv(&s);
12515 ++len;
12516 }
12517 rettv->vval.v_number = len;
12518#else
12519 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12520#endif
12521 }
12522}
12523
12524/*
12525 * "strdisplaywidth()" function
12526 */
12527 static void
12528f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12529{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012530 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012531 int col = 0;
12532
12533 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012534 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012535
12536 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12537}
12538
12539/*
12540 * "strwidth()" function
12541 */
12542 static void
12543f_strwidth(typval_T *argvars, typval_T *rettv)
12544{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012545 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012546
12547 rettv->vval.v_number = (varnumber_T)(
12548#ifdef FEAT_MBYTE
12549 mb_string2cells(s, -1)
12550#else
12551 STRLEN(s)
12552#endif
12553 );
12554}
12555
12556/*
12557 * "strcharpart()" function
12558 */
12559 static void
12560f_strcharpart(typval_T *argvars, typval_T *rettv)
12561{
12562#ifdef FEAT_MBYTE
12563 char_u *p;
12564 int nchar;
12565 int nbyte = 0;
12566 int charlen;
12567 int len = 0;
12568 int slen;
12569 int error = FALSE;
12570
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012571 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012572 slen = (int)STRLEN(p);
12573
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012574 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575 if (!error)
12576 {
12577 if (nchar > 0)
12578 while (nchar > 0 && nbyte < slen)
12579 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012580 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012581 --nchar;
12582 }
12583 else
12584 nbyte = nchar;
12585 if (argvars[2].v_type != VAR_UNKNOWN)
12586 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012587 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012588 while (charlen > 0 && nbyte + len < slen)
12589 {
12590 int off = nbyte + len;
12591
12592 if (off < 0)
12593 len += 1;
12594 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012595 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012596 --charlen;
12597 }
12598 }
12599 else
12600 len = slen - nbyte; /* default: all bytes that are available. */
12601 }
12602
12603 /*
12604 * Only return the overlap between the specified part and the actual
12605 * string.
12606 */
12607 if (nbyte < 0)
12608 {
12609 len += nbyte;
12610 nbyte = 0;
12611 }
12612 else if (nbyte > slen)
12613 nbyte = slen;
12614 if (len < 0)
12615 len = 0;
12616 else if (nbyte + len > slen)
12617 len = slen - nbyte;
12618
12619 rettv->v_type = VAR_STRING;
12620 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12621#else
12622 f_strpart(argvars, rettv);
12623#endif
12624}
12625
12626/*
12627 * "strpart()" function
12628 */
12629 static void
12630f_strpart(typval_T *argvars, typval_T *rettv)
12631{
12632 char_u *p;
12633 int n;
12634 int len;
12635 int slen;
12636 int error = FALSE;
12637
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012638 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012639 slen = (int)STRLEN(p);
12640
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012641 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012642 if (error)
12643 len = 0;
12644 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012645 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012646 else
12647 len = slen - n; /* default len: all bytes that are available. */
12648
12649 /*
12650 * Only return the overlap between the specified part and the actual
12651 * string.
12652 */
12653 if (n < 0)
12654 {
12655 len += n;
12656 n = 0;
12657 }
12658 else if (n > slen)
12659 n = slen;
12660 if (len < 0)
12661 len = 0;
12662 else if (n + len > slen)
12663 len = slen - n;
12664
12665 rettv->v_type = VAR_STRING;
12666 rettv->vval.v_string = vim_strnsave(p + n, len);
12667}
12668
12669/*
12670 * "strridx()" function
12671 */
12672 static void
12673f_strridx(typval_T *argvars, typval_T *rettv)
12674{
12675 char_u buf[NUMBUFLEN];
12676 char_u *needle;
12677 char_u *haystack;
12678 char_u *rest;
12679 char_u *lastmatch = NULL;
12680 int haystack_len, end_idx;
12681
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012682 needle = tv_get_string_chk(&argvars[1]);
12683 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012684
12685 rettv->vval.v_number = -1;
12686 if (needle == NULL || haystack == NULL)
12687 return; /* type error; errmsg already given */
12688
12689 haystack_len = (int)STRLEN(haystack);
12690 if (argvars[2].v_type != VAR_UNKNOWN)
12691 {
12692 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012693 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012694 if (end_idx < 0)
12695 return; /* can never find a match */
12696 }
12697 else
12698 end_idx = haystack_len;
12699
12700 if (*needle == NUL)
12701 {
12702 /* Empty string matches past the end. */
12703 lastmatch = haystack + end_idx;
12704 }
12705 else
12706 {
12707 for (rest = haystack; *rest != '\0'; ++rest)
12708 {
12709 rest = (char_u *)strstr((char *)rest, (char *)needle);
12710 if (rest == NULL || rest > haystack + end_idx)
12711 break;
12712 lastmatch = rest;
12713 }
12714 }
12715
12716 if (lastmatch == NULL)
12717 rettv->vval.v_number = -1;
12718 else
12719 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12720}
12721
12722/*
12723 * "strtrans()" function
12724 */
12725 static void
12726f_strtrans(typval_T *argvars, typval_T *rettv)
12727{
12728 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012729 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012730}
12731
12732/*
12733 * "submatch()" function
12734 */
12735 static void
12736f_submatch(typval_T *argvars, typval_T *rettv)
12737{
12738 int error = FALSE;
12739 int no;
12740 int retList = 0;
12741
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012742 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012743 if (error)
12744 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012745 if (no < 0 || no >= NSUBEXP)
12746 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012747 EMSGN(_("E935: invalid submatch number: %d"), no);
12748 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012749 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012750 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012751 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012752 if (error)
12753 return;
12754
12755 if (retList == 0)
12756 {
12757 rettv->v_type = VAR_STRING;
12758 rettv->vval.v_string = reg_submatch(no);
12759 }
12760 else
12761 {
12762 rettv->v_type = VAR_LIST;
12763 rettv->vval.v_list = reg_submatch_list(no);
12764 }
12765}
12766
12767/*
12768 * "substitute()" function
12769 */
12770 static void
12771f_substitute(typval_T *argvars, typval_T *rettv)
12772{
12773 char_u patbuf[NUMBUFLEN];
12774 char_u subbuf[NUMBUFLEN];
12775 char_u flagsbuf[NUMBUFLEN];
12776
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012777 char_u *str = tv_get_string_chk(&argvars[0]);
12778 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012779 char_u *sub = NULL;
12780 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012781 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012782
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012783 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12784 expr = &argvars[2];
12785 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012786 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012788 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012789 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12790 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791 rettv->vval.v_string = NULL;
12792 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012793 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012794}
12795
12796/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012797 * "swapinfo(swap_filename)" function
12798 */
12799 static void
12800f_swapinfo(typval_T *argvars, typval_T *rettv)
12801{
12802 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012803 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012804}
12805
12806/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020012807 * "swapname(expr)" function
12808 */
12809 static void
12810f_swapname(typval_T *argvars, typval_T *rettv)
12811{
12812 buf_T *buf;
12813
12814 rettv->v_type = VAR_STRING;
12815 buf = get_buf_tv(&argvars[0], FALSE);
12816 if (buf == NULL || buf->b_ml.ml_mfp == NULL
12817 || buf->b_ml.ml_mfp->mf_fname == NULL)
12818 rettv->vval.v_string = NULL;
12819 else
12820 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
12821}
12822
12823/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012824 * "synID(lnum, col, trans)" function
12825 */
12826 static void
12827f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12828{
12829 int id = 0;
12830#ifdef FEAT_SYN_HL
12831 linenr_T lnum;
12832 colnr_T col;
12833 int trans;
12834 int transerr = FALSE;
12835
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012836 lnum = tv_get_lnum(argvars); /* -1 on type error */
12837 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
12838 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012839
12840 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12841 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12842 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12843#endif
12844
12845 rettv->vval.v_number = id;
12846}
12847
12848/*
12849 * "synIDattr(id, what [, mode])" function
12850 */
12851 static void
12852f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12853{
12854 char_u *p = NULL;
12855#ifdef FEAT_SYN_HL
12856 int id;
12857 char_u *what;
12858 char_u *mode;
12859 char_u modebuf[NUMBUFLEN];
12860 int modec;
12861
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012862 id = (int)tv_get_number(&argvars[0]);
12863 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012864 if (argvars[2].v_type != VAR_UNKNOWN)
12865 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012866 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012867 modec = TOLOWER_ASC(mode[0]);
12868 if (modec != 't' && modec != 'c' && modec != 'g')
12869 modec = 0; /* replace invalid with current */
12870 }
12871 else
12872 {
12873#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12874 if (USE_24BIT)
12875 modec = 'g';
12876 else
12877#endif
12878 if (t_colors > 1)
12879 modec = 'c';
12880 else
12881 modec = 't';
12882 }
12883
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012884 switch (TOLOWER_ASC(what[0]))
12885 {
12886 case 'b':
12887 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12888 p = highlight_color(id, what, modec);
12889 else /* bold */
12890 p = highlight_has_attr(id, HL_BOLD, modec);
12891 break;
12892
12893 case 'f': /* fg[#] or font */
12894 p = highlight_color(id, what, modec);
12895 break;
12896
12897 case 'i':
12898 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12899 p = highlight_has_attr(id, HL_INVERSE, modec);
12900 else /* italic */
12901 p = highlight_has_attr(id, HL_ITALIC, modec);
12902 break;
12903
12904 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012905 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012906 break;
12907
12908 case 'r': /* reverse */
12909 p = highlight_has_attr(id, HL_INVERSE, modec);
12910 break;
12911
12912 case 's':
12913 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12914 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012915 /* strikeout */
12916 else if (TOLOWER_ASC(what[1]) == 't' &&
12917 TOLOWER_ASC(what[2]) == 'r')
12918 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012919 else /* standout */
12920 p = highlight_has_attr(id, HL_STANDOUT, modec);
12921 break;
12922
12923 case 'u':
12924 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12925 /* underline */
12926 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12927 else
12928 /* undercurl */
12929 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12930 break;
12931 }
12932
12933 if (p != NULL)
12934 p = vim_strsave(p);
12935#endif
12936 rettv->v_type = VAR_STRING;
12937 rettv->vval.v_string = p;
12938}
12939
12940/*
12941 * "synIDtrans(id)" function
12942 */
12943 static void
12944f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12945{
12946 int id;
12947
12948#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012949 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012950
12951 if (id > 0)
12952 id = syn_get_final_id(id);
12953 else
12954#endif
12955 id = 0;
12956
12957 rettv->vval.v_number = id;
12958}
12959
12960/*
12961 * "synconcealed(lnum, col)" function
12962 */
12963 static void
12964f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12965{
12966#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12967 linenr_T lnum;
12968 colnr_T col;
12969 int syntax_flags = 0;
12970 int cchar;
12971 int matchid = 0;
12972 char_u str[NUMBUFLEN];
12973#endif
12974
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012975 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012976
12977#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012978 lnum = tv_get_lnum(argvars); /* -1 on type error */
12979 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012980
12981 vim_memset(str, NUL, sizeof(str));
12982
12983 if (rettv_list_alloc(rettv) != FAIL)
12984 {
12985 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12986 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12987 && curwin->w_p_cole > 0)
12988 {
12989 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12990 syntax_flags = get_syntax_info(&matchid);
12991
12992 /* get the conceal character */
12993 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12994 {
12995 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012996 if (cchar == NUL && curwin->w_p_cole == 1)
12997 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012998 if (cchar != NUL)
12999 {
13000# ifdef FEAT_MBYTE
13001 if (has_mbyte)
13002 (*mb_char2bytes)(cchar, str);
13003 else
13004# endif
13005 str[0] = cchar;
13006 }
13007 }
13008 }
13009
13010 list_append_number(rettv->vval.v_list,
13011 (syntax_flags & HL_CONCEAL) != 0);
13012 /* -1 to auto-determine strlen */
13013 list_append_string(rettv->vval.v_list, str, -1);
13014 list_append_number(rettv->vval.v_list, matchid);
13015 }
13016#endif
13017}
13018
13019/*
13020 * "synstack(lnum, col)" function
13021 */
13022 static void
13023f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13024{
13025#ifdef FEAT_SYN_HL
13026 linenr_T lnum;
13027 colnr_T col;
13028 int i;
13029 int id;
13030#endif
13031
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013032 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013033
13034#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013035 lnum = tv_get_lnum(argvars); /* -1 on type error */
13036 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013037
13038 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13039 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13040 && rettv_list_alloc(rettv) != FAIL)
13041 {
13042 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13043 for (i = 0; ; ++i)
13044 {
13045 id = syn_get_stack_item(i);
13046 if (id < 0)
13047 break;
13048 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13049 break;
13050 }
13051 }
13052#endif
13053}
13054
13055 static void
13056get_cmd_output_as_rettv(
13057 typval_T *argvars,
13058 typval_T *rettv,
13059 int retlist)
13060{
13061 char_u *res = NULL;
13062 char_u *p;
13063 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013064 int err = FALSE;
13065 FILE *fd;
13066 list_T *list = NULL;
13067 int flags = SHELL_SILENT;
13068
13069 rettv->v_type = VAR_STRING;
13070 rettv->vval.v_string = NULL;
13071 if (check_restricted() || check_secure())
13072 goto errret;
13073
13074 if (argvars[1].v_type != VAR_UNKNOWN)
13075 {
13076 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013077 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013078 * command.
13079 */
13080 if ((infile = vim_tempname('i', TRUE)) == NULL)
13081 {
13082 EMSG(_(e_notmp));
13083 goto errret;
13084 }
13085
13086 fd = mch_fopen((char *)infile, WRITEBIN);
13087 if (fd == NULL)
13088 {
13089 EMSG2(_(e_notopen), infile);
13090 goto errret;
13091 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013092 if (argvars[1].v_type == VAR_NUMBER)
13093 {
13094 linenr_T lnum;
13095 buf_T *buf;
13096
13097 buf = buflist_findnr(argvars[1].vval.v_number);
13098 if (buf == NULL)
13099 {
13100 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013101 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013102 goto errret;
13103 }
13104
13105 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13106 {
13107 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13108 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13109 {
13110 err = TRUE;
13111 break;
13112 }
13113 if (putc(NL, fd) == EOF)
13114 {
13115 err = TRUE;
13116 break;
13117 }
13118 }
13119 }
13120 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013121 {
13122 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13123 err = TRUE;
13124 }
13125 else
13126 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013127 size_t len;
13128 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013129
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013130 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013131 if (p == NULL)
13132 {
13133 fclose(fd);
13134 goto errret; /* type error; errmsg already given */
13135 }
13136 len = STRLEN(p);
13137 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13138 err = TRUE;
13139 }
13140 if (fclose(fd) != 0)
13141 err = TRUE;
13142 if (err)
13143 {
13144 EMSG(_("E677: Error writing temp file"));
13145 goto errret;
13146 }
13147 }
13148
13149 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13150 * echoes typeahead, that messes up the display. */
13151 if (!msg_silent)
13152 flags += SHELL_COOKED;
13153
13154 if (retlist)
13155 {
13156 int len;
13157 listitem_T *li;
13158 char_u *s = NULL;
13159 char_u *start;
13160 char_u *end;
13161 int i;
13162
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013163 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013164 if (res == NULL)
13165 goto errret;
13166
13167 list = list_alloc();
13168 if (list == NULL)
13169 goto errret;
13170
13171 for (i = 0; i < len; ++i)
13172 {
13173 start = res + i;
13174 while (i < len && res[i] != NL)
13175 ++i;
13176 end = res + i;
13177
13178 s = alloc((unsigned)(end - start + 1));
13179 if (s == NULL)
13180 goto errret;
13181
13182 for (p = s; start < end; ++p, ++start)
13183 *p = *start == NUL ? NL : *start;
13184 *p = NUL;
13185
13186 li = listitem_alloc();
13187 if (li == NULL)
13188 {
13189 vim_free(s);
13190 goto errret;
13191 }
13192 li->li_tv.v_type = VAR_STRING;
13193 li->li_tv.v_lock = 0;
13194 li->li_tv.vval.v_string = s;
13195 list_append(list, li);
13196 }
13197
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013198 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013199 list = NULL;
13200 }
13201 else
13202 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013203 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013204#ifdef USE_CR
13205 /* translate <CR> into <NL> */
13206 if (res != NULL)
13207 {
13208 char_u *s;
13209
13210 for (s = res; *s; ++s)
13211 {
13212 if (*s == CAR)
13213 *s = NL;
13214 }
13215 }
13216#else
13217# ifdef USE_CRNL
13218 /* translate <CR><NL> into <NL> */
13219 if (res != NULL)
13220 {
13221 char_u *s, *d;
13222
13223 d = res;
13224 for (s = res; *s; ++s)
13225 {
13226 if (s[0] == CAR && s[1] == NL)
13227 ++s;
13228 *d++ = *s;
13229 }
13230 *d = NUL;
13231 }
13232# endif
13233#endif
13234 rettv->vval.v_string = res;
13235 res = NULL;
13236 }
13237
13238errret:
13239 if (infile != NULL)
13240 {
13241 mch_remove(infile);
13242 vim_free(infile);
13243 }
13244 if (res != NULL)
13245 vim_free(res);
13246 if (list != NULL)
13247 list_free(list);
13248}
13249
13250/*
13251 * "system()" function
13252 */
13253 static void
13254f_system(typval_T *argvars, typval_T *rettv)
13255{
13256 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13257}
13258
13259/*
13260 * "systemlist()" function
13261 */
13262 static void
13263f_systemlist(typval_T *argvars, typval_T *rettv)
13264{
13265 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13266}
13267
13268/*
13269 * "tabpagebuflist()" function
13270 */
13271 static void
13272f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13273{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013274 tabpage_T *tp;
13275 win_T *wp = NULL;
13276
13277 if (argvars[0].v_type == VAR_UNKNOWN)
13278 wp = firstwin;
13279 else
13280 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013281 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013282 if (tp != NULL)
13283 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13284 }
13285 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13286 {
13287 for (; wp != NULL; wp = wp->w_next)
13288 if (list_append_number(rettv->vval.v_list,
13289 wp->w_buffer->b_fnum) == FAIL)
13290 break;
13291 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013292}
13293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013294/*
13295 * "tabpagenr()" function
13296 */
13297 static void
13298f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13299{
13300 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013301 char_u *arg;
13302
13303 if (argvars[0].v_type != VAR_UNKNOWN)
13304 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013305 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013306 nr = 0;
13307 if (arg != NULL)
13308 {
13309 if (STRCMP(arg, "$") == 0)
13310 nr = tabpage_index(NULL) - 1;
13311 else
13312 EMSG2(_(e_invexpr2), arg);
13313 }
13314 }
13315 else
13316 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013317 rettv->vval.v_number = nr;
13318}
13319
13320
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013321/*
13322 * Common code for tabpagewinnr() and winnr().
13323 */
13324 static int
13325get_winnr(tabpage_T *tp, typval_T *argvar)
13326{
13327 win_T *twin;
13328 int nr = 1;
13329 win_T *wp;
13330 char_u *arg;
13331
13332 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13333 if (argvar->v_type != VAR_UNKNOWN)
13334 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013335 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013336 if (arg == NULL)
13337 nr = 0; /* type error; errmsg already given */
13338 else if (STRCMP(arg, "$") == 0)
13339 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13340 else if (STRCMP(arg, "#") == 0)
13341 {
13342 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13343 if (twin == NULL)
13344 nr = 0;
13345 }
13346 else
13347 {
13348 EMSG2(_(e_invexpr2), arg);
13349 nr = 0;
13350 }
13351 }
13352
13353 if (nr > 0)
13354 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13355 wp != twin; wp = wp->w_next)
13356 {
13357 if (wp == NULL)
13358 {
13359 /* didn't find it in this tabpage */
13360 nr = 0;
13361 break;
13362 }
13363 ++nr;
13364 }
13365 return nr;
13366}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013367
13368/*
13369 * "tabpagewinnr()" function
13370 */
13371 static void
13372f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13373{
13374 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013375 tabpage_T *tp;
13376
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013377 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013378 if (tp == NULL)
13379 nr = 0;
13380 else
13381 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013382 rettv->vval.v_number = nr;
13383}
13384
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013385/*
13386 * "tagfiles()" function
13387 */
13388 static void
13389f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13390{
13391 char_u *fname;
13392 tagname_T tn;
13393 int first;
13394
13395 if (rettv_list_alloc(rettv) == FAIL)
13396 return;
13397 fname = alloc(MAXPATHL);
13398 if (fname == NULL)
13399 return;
13400
13401 for (first = TRUE; ; first = FALSE)
13402 if (get_tagfname(&tn, first, fname) == FAIL
13403 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13404 break;
13405 tagname_free(&tn);
13406 vim_free(fname);
13407}
13408
13409/*
13410 * "taglist()" function
13411 */
13412 static void
13413f_taglist(typval_T *argvars, typval_T *rettv)
13414{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013415 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013416 char_u *tag_pattern;
13417
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013418 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013419
13420 rettv->vval.v_number = FALSE;
13421 if (*tag_pattern == NUL)
13422 return;
13423
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013424 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013425 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013426 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013427 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013428}
13429
13430/*
13431 * "tempname()" function
13432 */
13433 static void
13434f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13435{
13436 static int x = 'A';
13437
13438 rettv->v_type = VAR_STRING;
13439 rettv->vval.v_string = vim_tempname(x, FALSE);
13440
13441 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13442 * names. Skip 'I' and 'O', they are used for shell redirection. */
13443 do
13444 {
13445 if (x == 'Z')
13446 x = '0';
13447 else if (x == '9')
13448 x = 'A';
13449 else
13450 {
13451#ifdef EBCDIC
13452 if (x == 'I')
13453 x = 'J';
13454 else if (x == 'R')
13455 x = 'S';
13456 else
13457#endif
13458 ++x;
13459 }
13460 } while (x == 'I' || x == 'O');
13461}
13462
13463#ifdef FEAT_FLOAT
13464/*
13465 * "tan()" function
13466 */
13467 static void
13468f_tan(typval_T *argvars, typval_T *rettv)
13469{
13470 float_T f = 0.0;
13471
13472 rettv->v_type = VAR_FLOAT;
13473 if (get_float_arg(argvars, &f) == OK)
13474 rettv->vval.v_float = tan(f);
13475 else
13476 rettv->vval.v_float = 0.0;
13477}
13478
13479/*
13480 * "tanh()" function
13481 */
13482 static void
13483f_tanh(typval_T *argvars, typval_T *rettv)
13484{
13485 float_T f = 0.0;
13486
13487 rettv->v_type = VAR_FLOAT;
13488 if (get_float_arg(argvars, &f) == OK)
13489 rettv->vval.v_float = tanh(f);
13490 else
13491 rettv->vval.v_float = 0.0;
13492}
13493#endif
13494
13495/*
13496 * "test_alloc_fail(id, countdown, repeat)" function
13497 */
13498 static void
13499f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13500{
13501 if (argvars[0].v_type != VAR_NUMBER
13502 || argvars[0].vval.v_number <= 0
13503 || argvars[1].v_type != VAR_NUMBER
13504 || argvars[1].vval.v_number < 0
13505 || argvars[2].v_type != VAR_NUMBER)
13506 EMSG(_(e_invarg));
13507 else
13508 {
13509 alloc_fail_id = argvars[0].vval.v_number;
13510 if (alloc_fail_id >= aid_last)
13511 EMSG(_(e_invarg));
13512 alloc_fail_countdown = argvars[1].vval.v_number;
13513 alloc_fail_repeat = argvars[2].vval.v_number;
13514 did_outofmem_msg = FALSE;
13515 }
13516}
13517
13518/*
13519 * "test_autochdir()"
13520 */
13521 static void
13522f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13523{
13524#if defined(FEAT_AUTOCHDIR)
13525 test_autochdir = TRUE;
13526#endif
13527}
13528
13529/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013530 * "test_feedinput()"
13531 */
13532 static void
13533f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13534{
13535#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013536 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013537
13538 if (val != NULL)
13539 {
13540 trash_input_buf();
13541 add_to_input_buf_csi(val, (int)STRLEN(val));
13542 }
13543#endif
13544}
13545
13546/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013547 * "test_option_not_set({name})" function
13548 */
13549 static void
13550f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13551{
13552 char_u *name = (char_u *)"";
13553
13554 if (argvars[0].v_type != VAR_STRING)
13555 EMSG(_(e_invarg));
13556 else
13557 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013558 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013559 if (reset_option_was_set(name) == FAIL)
13560 EMSG2(_(e_invarg2), name);
13561 }
13562}
13563
13564/*
13565 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013566 */
13567 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013568f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013569{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013570 char_u *name = (char_u *)"";
13571 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013572 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013573
13574 if (argvars[0].v_type != VAR_STRING
13575 || (argvars[1].v_type) != VAR_NUMBER)
13576 EMSG(_(e_invarg));
13577 else
13578 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013579 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013580 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013581
13582 if (STRCMP(name, (char_u *)"redraw") == 0)
13583 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013584 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13585 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013586 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13587 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013588 else if (STRCMP(name, (char_u *)"starting") == 0)
13589 {
13590 if (val)
13591 {
13592 if (save_starting < 0)
13593 save_starting = starting;
13594 starting = 0;
13595 }
13596 else
13597 {
13598 starting = save_starting;
13599 save_starting = -1;
13600 }
13601 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013602 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13603 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013604 else if (STRCMP(name, (char_u *)"ALL") == 0)
13605 {
13606 disable_char_avail_for_testing = FALSE;
13607 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013608 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013609 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013610 if (save_starting >= 0)
13611 {
13612 starting = save_starting;
13613 save_starting = -1;
13614 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013615 }
13616 else
13617 EMSG2(_(e_invarg2), name);
13618 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013619}
13620
13621/*
13622 * "test_garbagecollect_now()" function
13623 */
13624 static void
13625f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13626{
13627 /* This is dangerous, any Lists and Dicts used internally may be freed
13628 * while still in use. */
13629 garbage_collect(TRUE);
13630}
13631
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013632/*
13633 * "test_ignore_error()" function
13634 */
13635 static void
13636f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13637{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013638 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013639}
13640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013641#ifdef FEAT_JOB_CHANNEL
13642 static void
13643f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13644{
13645 rettv->v_type = VAR_CHANNEL;
13646 rettv->vval.v_channel = NULL;
13647}
13648#endif
13649
13650 static void
13651f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13652{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013653 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013654}
13655
13656#ifdef FEAT_JOB_CHANNEL
13657 static void
13658f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13659{
13660 rettv->v_type = VAR_JOB;
13661 rettv->vval.v_job = NULL;
13662}
13663#endif
13664
13665 static void
13666f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13667{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013668 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013669}
13670
13671 static void
13672f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13673{
13674 rettv->v_type = VAR_PARTIAL;
13675 rettv->vval.v_partial = NULL;
13676}
13677
13678 static void
13679f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13680{
13681 rettv->v_type = VAR_STRING;
13682 rettv->vval.v_string = NULL;
13683}
13684
Bram Moolenaarab186732018-09-14 21:27:06 +020013685#ifdef FEAT_GUI
13686 static void
13687f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13688{
13689 char_u *which;
13690 long value;
13691 int dragging;
13692 scrollbar_T *sb = NULL;
13693
13694 if (argvars[0].v_type != VAR_STRING
13695 || (argvars[1].v_type) != VAR_NUMBER
13696 || (argvars[2].v_type) != VAR_NUMBER)
13697 {
13698 EMSG(_(e_invarg));
13699 return;
13700 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013701 which = tv_get_string(&argvars[0]);
13702 value = tv_get_number(&argvars[1]);
13703 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020013704
13705 if (STRCMP(which, "left") == 0)
13706 sb = &curwin->w_scrollbars[SBAR_LEFT];
13707 else if (STRCMP(which, "right") == 0)
13708 sb = &curwin->w_scrollbars[SBAR_RIGHT];
13709 else if (STRCMP(which, "hor") == 0)
13710 sb = &gui.bottom_sbar;
13711 if (sb == NULL)
13712 {
13713 EMSG2(_(e_invarg2), which);
13714 return;
13715 }
13716 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020013717# ifndef USE_ON_FLY_SCROLL
13718 // need to loop through normal_cmd() to handle the scroll events
13719 exec_normal(FALSE, TRUE, FALSE);
13720# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020013721}
13722#endif
13723
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013724 static void
13725f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13726{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013727 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013728}
13729
13730#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13731/*
13732 * Get a callback from "arg". It can be a Funcref or a function name.
13733 * When "arg" is zero return an empty string.
13734 * Return NULL for an invalid argument.
13735 */
13736 char_u *
13737get_callback(typval_T *arg, partial_T **pp)
13738{
13739 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13740 {
13741 *pp = arg->vval.v_partial;
13742 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013743 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013744 }
13745 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013746 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013747 {
13748 func_ref(arg->vval.v_string);
13749 return arg->vval.v_string;
13750 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013751 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13752 return (char_u *)"";
13753 EMSG(_("E921: Invalid callback argument"));
13754 return NULL;
13755}
13756
13757/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013758 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013759 */
13760 void
13761free_callback(char_u *callback, partial_T *partial)
13762{
13763 if (partial != NULL)
13764 partial_unref(partial);
13765 else if (callback != NULL)
13766 {
13767 func_unref(callback);
13768 vim_free(callback);
13769 }
13770}
13771#endif
13772
13773#ifdef FEAT_TIMERS
13774/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013775 * "timer_info([timer])" function
13776 */
13777 static void
13778f_timer_info(typval_T *argvars, typval_T *rettv)
13779{
13780 timer_T *timer = NULL;
13781
13782 if (rettv_list_alloc(rettv) != OK)
13783 return;
13784 if (argvars[0].v_type != VAR_UNKNOWN)
13785 {
13786 if (argvars[0].v_type != VAR_NUMBER)
13787 EMSG(_(e_number_exp));
13788 else
13789 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013790 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013791 if (timer != NULL)
13792 add_timer_info(rettv, timer);
13793 }
13794 }
13795 else
13796 add_timer_info_all(rettv);
13797}
13798
13799/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013800 * "timer_pause(timer, paused)" function
13801 */
13802 static void
13803f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13804{
13805 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013806 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013807
13808 if (argvars[0].v_type != VAR_NUMBER)
13809 EMSG(_(e_number_exp));
13810 else
13811 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013812 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013813 if (timer != NULL)
13814 timer->tr_paused = paused;
13815 }
13816}
13817
13818/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013819 * "timer_start(time, callback [, options])" function
13820 */
13821 static void
13822f_timer_start(typval_T *argvars, typval_T *rettv)
13823{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013824 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020013825 timer_T *timer;
13826 int repeat = 0;
13827 char_u *callback;
13828 dict_T *dict;
13829 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013830
Bram Moolenaar75537a92016-09-05 22:45:28 +020013831 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013832 if (check_secure())
13833 return;
13834 if (argvars[2].v_type != VAR_UNKNOWN)
13835 {
13836 if (argvars[2].v_type != VAR_DICT
13837 || (dict = argvars[2].vval.v_dict) == NULL)
13838 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013839 EMSG2(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013840 return;
13841 }
13842 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013843 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013844 }
13845
Bram Moolenaar75537a92016-09-05 22:45:28 +020013846 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013847 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013848 return;
13849
13850 timer = create_timer(msec, repeat);
13851 if (timer == NULL)
13852 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013853 else
13854 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013855 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013856 timer->tr_callback = vim_strsave(callback);
13857 else
13858 /* pointer into the partial */
13859 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013860 timer->tr_partial = partial;
13861 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013862 }
13863}
13864
13865/*
13866 * "timer_stop(timer)" function
13867 */
13868 static void
13869f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13870{
13871 timer_T *timer;
13872
13873 if (argvars[0].v_type != VAR_NUMBER)
13874 {
13875 EMSG(_(e_number_exp));
13876 return;
13877 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013878 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013879 if (timer != NULL)
13880 stop_timer(timer);
13881}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013882
13883/*
13884 * "timer_stopall()" function
13885 */
13886 static void
13887f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13888{
13889 stop_all_timers();
13890}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013891#endif
13892
13893/*
13894 * "tolower(string)" function
13895 */
13896 static void
13897f_tolower(typval_T *argvars, typval_T *rettv)
13898{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013899 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013900 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013901}
13902
13903/*
13904 * "toupper(string)" function
13905 */
13906 static void
13907f_toupper(typval_T *argvars, typval_T *rettv)
13908{
13909 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013910 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013911}
13912
13913/*
13914 * "tr(string, fromstr, tostr)" function
13915 */
13916 static void
13917f_tr(typval_T *argvars, typval_T *rettv)
13918{
13919 char_u *in_str;
13920 char_u *fromstr;
13921 char_u *tostr;
13922 char_u *p;
13923#ifdef FEAT_MBYTE
13924 int inlen;
13925 int fromlen;
13926 int tolen;
13927 int idx;
13928 char_u *cpstr;
13929 int cplen;
13930 int first = TRUE;
13931#endif
13932 char_u buf[NUMBUFLEN];
13933 char_u buf2[NUMBUFLEN];
13934 garray_T ga;
13935
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013936 in_str = tv_get_string(&argvars[0]);
13937 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
13938 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013939
13940 /* Default return value: empty string. */
13941 rettv->v_type = VAR_STRING;
13942 rettv->vval.v_string = NULL;
13943 if (fromstr == NULL || tostr == NULL)
13944 return; /* type error; errmsg already given */
13945 ga_init2(&ga, (int)sizeof(char), 80);
13946
13947#ifdef FEAT_MBYTE
13948 if (!has_mbyte)
13949#endif
13950 /* not multi-byte: fromstr and tostr must be the same length */
13951 if (STRLEN(fromstr) != STRLEN(tostr))
13952 {
13953#ifdef FEAT_MBYTE
13954error:
13955#endif
13956 EMSG2(_(e_invarg2), fromstr);
13957 ga_clear(&ga);
13958 return;
13959 }
13960
13961 /* fromstr and tostr have to contain the same number of chars */
13962 while (*in_str != NUL)
13963 {
13964#ifdef FEAT_MBYTE
13965 if (has_mbyte)
13966 {
13967 inlen = (*mb_ptr2len)(in_str);
13968 cpstr = in_str;
13969 cplen = inlen;
13970 idx = 0;
13971 for (p = fromstr; *p != NUL; p += fromlen)
13972 {
13973 fromlen = (*mb_ptr2len)(p);
13974 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13975 {
13976 for (p = tostr; *p != NUL; p += tolen)
13977 {
13978 tolen = (*mb_ptr2len)(p);
13979 if (idx-- == 0)
13980 {
13981 cplen = tolen;
13982 cpstr = p;
13983 break;
13984 }
13985 }
13986 if (*p == NUL) /* tostr is shorter than fromstr */
13987 goto error;
13988 break;
13989 }
13990 ++idx;
13991 }
13992
13993 if (first && cpstr == in_str)
13994 {
13995 /* Check that fromstr and tostr have the same number of
13996 * (multi-byte) characters. Done only once when a character
13997 * of in_str doesn't appear in fromstr. */
13998 first = FALSE;
13999 for (p = tostr; *p != NUL; p += tolen)
14000 {
14001 tolen = (*mb_ptr2len)(p);
14002 --idx;
14003 }
14004 if (idx != 0)
14005 goto error;
14006 }
14007
14008 (void)ga_grow(&ga, cplen);
14009 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14010 ga.ga_len += cplen;
14011
14012 in_str += inlen;
14013 }
14014 else
14015#endif
14016 {
14017 /* When not using multi-byte chars we can do it faster. */
14018 p = vim_strchr(fromstr, *in_str);
14019 if (p != NULL)
14020 ga_append(&ga, tostr[p - fromstr]);
14021 else
14022 ga_append(&ga, *in_str);
14023 ++in_str;
14024 }
14025 }
14026
14027 /* add a terminating NUL */
14028 (void)ga_grow(&ga, 1);
14029 ga_append(&ga, NUL);
14030
14031 rettv->vval.v_string = ga.ga_data;
14032}
14033
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014034/*
14035 * "trim({expr})" function
14036 */
14037 static void
14038f_trim(typval_T *argvars, typval_T *rettv)
14039{
14040 char_u buf1[NUMBUFLEN];
14041 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014042 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014043 char_u *mask = NULL;
14044 char_u *tail;
14045 char_u *prev;
14046 char_u *p;
14047 int c1;
14048
14049 rettv->v_type = VAR_STRING;
14050 if (head == NULL)
14051 {
14052 rettv->vval.v_string = NULL;
14053 return;
14054 }
14055
14056 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014057 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014058
14059 while (*head != NUL)
14060 {
14061 c1 = PTR2CHAR(head);
14062 if (mask == NULL)
14063 {
14064 if (c1 > ' ' && c1 != 0xa0)
14065 break;
14066 }
14067 else
14068 {
14069 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14070 if (c1 == PTR2CHAR(p))
14071 break;
14072 if (*p == NUL)
14073 break;
14074 }
14075 MB_PTR_ADV(head);
14076 }
14077
14078 for (tail = head + STRLEN(head); tail > head; tail = prev)
14079 {
14080 prev = tail;
14081 MB_PTR_BACK(head, prev);
14082 c1 = PTR2CHAR(prev);
14083 if (mask == NULL)
14084 {
14085 if (c1 > ' ' && c1 != 0xa0)
14086 break;
14087 }
14088 else
14089 {
14090 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14091 if (c1 == PTR2CHAR(p))
14092 break;
14093 if (*p == NUL)
14094 break;
14095 }
14096 }
14097 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14098}
14099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014100#ifdef FEAT_FLOAT
14101/*
14102 * "trunc({float})" function
14103 */
14104 static void
14105f_trunc(typval_T *argvars, typval_T *rettv)
14106{
14107 float_T f = 0.0;
14108
14109 rettv->v_type = VAR_FLOAT;
14110 if (get_float_arg(argvars, &f) == OK)
14111 /* trunc() is not in C90, use floor() or ceil() instead. */
14112 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14113 else
14114 rettv->vval.v_float = 0.0;
14115}
14116#endif
14117
14118/*
14119 * "type(expr)" function
14120 */
14121 static void
14122f_type(typval_T *argvars, typval_T *rettv)
14123{
14124 int n = -1;
14125
14126 switch (argvars[0].v_type)
14127 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014128 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14129 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014130 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014131 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14132 case VAR_LIST: n = VAR_TYPE_LIST; break;
14133 case VAR_DICT: n = VAR_TYPE_DICT; break;
14134 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014135 case VAR_SPECIAL:
14136 if (argvars[0].vval.v_number == VVAL_FALSE
14137 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014138 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014139 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014140 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014141 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014142 case VAR_JOB: n = VAR_TYPE_JOB; break;
14143 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014144 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014145 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014146 n = -1;
14147 break;
14148 }
14149 rettv->vval.v_number = n;
14150}
14151
14152/*
14153 * "undofile(name)" function
14154 */
14155 static void
14156f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14157{
14158 rettv->v_type = VAR_STRING;
14159#ifdef FEAT_PERSISTENT_UNDO
14160 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014161 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014162
14163 if (*fname == NUL)
14164 {
14165 /* If there is no file name there will be no undo file. */
14166 rettv->vval.v_string = NULL;
14167 }
14168 else
14169 {
14170 char_u *ffname = FullName_save(fname, FALSE);
14171
14172 if (ffname != NULL)
14173 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14174 vim_free(ffname);
14175 }
14176 }
14177#else
14178 rettv->vval.v_string = NULL;
14179#endif
14180}
14181
14182/*
14183 * "undotree()" function
14184 */
14185 static void
14186f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14187{
14188 if (rettv_dict_alloc(rettv) == OK)
14189 {
14190 dict_T *dict = rettv->vval.v_dict;
14191 list_T *list;
14192
Bram Moolenaare0be1672018-07-08 16:50:37 +020014193 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14194 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14195 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14196 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14197 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14198 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014199
14200 list = list_alloc();
14201 if (list != NULL)
14202 {
14203 u_eval_tree(curbuf->b_u_oldhead, list);
14204 dict_add_list(dict, "entries", list);
14205 }
14206 }
14207}
14208
14209/*
14210 * "values(dict)" function
14211 */
14212 static void
14213f_values(typval_T *argvars, typval_T *rettv)
14214{
14215 dict_list(argvars, rettv, 1);
14216}
14217
14218/*
14219 * "virtcol(string)" function
14220 */
14221 static void
14222f_virtcol(typval_T *argvars, typval_T *rettv)
14223{
14224 colnr_T vcol = 0;
14225 pos_T *fp;
14226 int fnum = curbuf->b_fnum;
14227
14228 fp = var2fpos(&argvars[0], FALSE, &fnum);
14229 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14230 && fnum == curbuf->b_fnum)
14231 {
14232 getvvcol(curwin, fp, NULL, NULL, &vcol);
14233 ++vcol;
14234 }
14235
14236 rettv->vval.v_number = vcol;
14237}
14238
14239/*
14240 * "visualmode()" function
14241 */
14242 static void
14243f_visualmode(typval_T *argvars, typval_T *rettv)
14244{
14245 char_u str[2];
14246
14247 rettv->v_type = VAR_STRING;
14248 str[0] = curbuf->b_visual_mode_eval;
14249 str[1] = NUL;
14250 rettv->vval.v_string = vim_strsave(str);
14251
14252 /* A non-zero number or non-empty string argument: reset mode. */
14253 if (non_zero_arg(&argvars[0]))
14254 curbuf->b_visual_mode_eval = NUL;
14255}
14256
14257/*
14258 * "wildmenumode()" function
14259 */
14260 static void
14261f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14262{
14263#ifdef FEAT_WILDMENU
14264 if (wild_menu_showing)
14265 rettv->vval.v_number = 1;
14266#endif
14267}
14268
14269/*
14270 * "winbufnr(nr)" function
14271 */
14272 static void
14273f_winbufnr(typval_T *argvars, typval_T *rettv)
14274{
14275 win_T *wp;
14276
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014277 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014278 if (wp == NULL)
14279 rettv->vval.v_number = -1;
14280 else
14281 rettv->vval.v_number = wp->w_buffer->b_fnum;
14282}
14283
14284/*
14285 * "wincol()" function
14286 */
14287 static void
14288f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14289{
14290 validate_cursor();
14291 rettv->vval.v_number = curwin->w_wcol + 1;
14292}
14293
14294/*
14295 * "winheight(nr)" function
14296 */
14297 static void
14298f_winheight(typval_T *argvars, typval_T *rettv)
14299{
14300 win_T *wp;
14301
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014302 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014303 if (wp == NULL)
14304 rettv->vval.v_number = -1;
14305 else
14306 rettv->vval.v_number = wp->w_height;
14307}
14308
14309/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014310 * "winlayout()" function
14311 */
14312 static void
14313f_winlayout(typval_T *argvars, typval_T *rettv)
14314{
14315 tabpage_T *tp;
14316
14317 if (rettv_list_alloc(rettv) != OK)
14318 return;
14319
14320 if (argvars[0].v_type == VAR_UNKNOWN)
14321 tp = curtab;
14322 else
14323 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014324 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014325 if (tp == NULL)
14326 return;
14327 }
14328
14329 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14330}
14331
14332/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014333 * "winline()" function
14334 */
14335 static void
14336f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14337{
14338 validate_cursor();
14339 rettv->vval.v_number = curwin->w_wrow + 1;
14340}
14341
14342/*
14343 * "winnr()" function
14344 */
14345 static void
14346f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14347{
14348 int nr = 1;
14349
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014350 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014351 rettv->vval.v_number = nr;
14352}
14353
14354/*
14355 * "winrestcmd()" function
14356 */
14357 static void
14358f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14359{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014360 win_T *wp;
14361 int winnr = 1;
14362 garray_T ga;
14363 char_u buf[50];
14364
14365 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014366 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014367 {
14368 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14369 ga_concat(&ga, buf);
14370 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14371 ga_concat(&ga, buf);
14372 ++winnr;
14373 }
14374 ga_append(&ga, NUL);
14375
14376 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014377 rettv->v_type = VAR_STRING;
14378}
14379
14380/*
14381 * "winrestview()" function
14382 */
14383 static void
14384f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14385{
14386 dict_T *dict;
14387
14388 if (argvars[0].v_type != VAR_DICT
14389 || (dict = argvars[0].vval.v_dict) == NULL)
14390 EMSG(_(e_invarg));
14391 else
14392 {
14393 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014394 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014395 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014396 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014397#ifdef FEAT_VIRTUALEDIT
14398 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014399 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014400#endif
14401 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14402 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014403 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014404 curwin->w_set_curswant = FALSE;
14405 }
14406
14407 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014408 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014409#ifdef FEAT_DIFF
14410 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014411 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014412#endif
14413 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014414 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014415 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014416 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014417
14418 check_cursor();
14419 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014420 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014421 changed_window_setting();
14422
14423 if (curwin->w_topline <= 0)
14424 curwin->w_topline = 1;
14425 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14426 curwin->w_topline = curbuf->b_ml.ml_line_count;
14427#ifdef FEAT_DIFF
14428 check_topfill(curwin, TRUE);
14429#endif
14430 }
14431}
14432
14433/*
14434 * "winsaveview()" function
14435 */
14436 static void
14437f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14438{
14439 dict_T *dict;
14440
14441 if (rettv_dict_alloc(rettv) == FAIL)
14442 return;
14443 dict = rettv->vval.v_dict;
14444
Bram Moolenaare0be1672018-07-08 16:50:37 +020014445 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14446 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014447#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020014448 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014449#endif
14450 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014451 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014452
Bram Moolenaare0be1672018-07-08 16:50:37 +020014453 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014454#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014455 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014456#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014457 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14458 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014459}
14460
14461/*
14462 * "winwidth(nr)" function
14463 */
14464 static void
14465f_winwidth(typval_T *argvars, typval_T *rettv)
14466{
14467 win_T *wp;
14468
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014469 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014470 if (wp == NULL)
14471 rettv->vval.v_number = -1;
14472 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014473 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014474}
14475
14476/*
14477 * "wordcount()" function
14478 */
14479 static void
14480f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14481{
14482 if (rettv_dict_alloc(rettv) == FAIL)
14483 return;
14484 cursor_pos_info(rettv->vval.v_dict);
14485}
14486
14487/*
14488 * "writefile()" function
14489 */
14490 static void
14491f_writefile(typval_T *argvars, typval_T *rettv)
14492{
14493 int binary = FALSE;
14494 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014495#ifdef HAVE_FSYNC
14496 int do_fsync = p_fs;
14497#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014498 char_u *fname;
14499 FILE *fd;
14500 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014501 listitem_T *li;
14502 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014503
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014504 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014505 if (check_restricted() || check_secure())
14506 return;
14507
14508 if (argvars[0].v_type != VAR_LIST)
14509 {
14510 EMSG2(_(e_listarg), "writefile()");
14511 return;
14512 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014513 list = argvars[0].vval.v_list;
14514 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014515 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014516 for (li = list->lv_first; li != NULL; li = li->li_next)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014517 if (tv_get_string_chk(&li->li_tv) == NULL)
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014518 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014519
14520 if (argvars[2].v_type != VAR_UNKNOWN)
14521 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014522 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014523
14524 if (arg2 == NULL)
14525 return;
14526 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014527 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014528 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014529 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014530#ifdef HAVE_FSYNC
14531 if (vim_strchr(arg2, 's') != NULL)
14532 do_fsync = TRUE;
14533 else if (vim_strchr(arg2, 'S') != NULL)
14534 do_fsync = FALSE;
14535#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014536 }
14537
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014538 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014539 if (fname == NULL)
14540 return;
14541
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014542 /* Always open the file in binary mode, library functions have a mind of
14543 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014544 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14545 append ? APPENDBIN : WRITEBIN)) == NULL)
14546 {
14547 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14548 ret = -1;
14549 }
14550 else
14551 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014552 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014553 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014554#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014555 else if (do_fsync)
14556 /* Ignore the error, the user wouldn't know what to do about it.
14557 * May happen for a device. */
Bram Moolenaar42335f52018-09-13 15:33:43 +020014558 vim_ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014559#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014560 fclose(fd);
14561 }
14562
14563 rettv->vval.v_number = ret;
14564}
14565
14566/*
14567 * "xor(expr, expr)" function
14568 */
14569 static void
14570f_xor(typval_T *argvars, typval_T *rettv)
14571{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014572 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14573 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014574}
14575
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014576#endif /* FEAT_EVAL */