blob: 15c625c8be20af76c851dcef45e7d209ba5d0ab5 [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);
399static void f_string(typval_T *argvars, typval_T *rettv);
400static void f_strlen(typval_T *argvars, typval_T *rettv);
401static void f_strcharpart(typval_T *argvars, typval_T *rettv);
402static void f_strpart(typval_T *argvars, typval_T *rettv);
403static void f_strridx(typval_T *argvars, typval_T *rettv);
404static void f_strtrans(typval_T *argvars, typval_T *rettv);
405static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
406static void f_strwidth(typval_T *argvars, typval_T *rettv);
407static void f_submatch(typval_T *argvars, typval_T *rettv);
408static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200409static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200410static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200411static void f_synID(typval_T *argvars, typval_T *rettv);
412static void f_synIDattr(typval_T *argvars, typval_T *rettv);
413static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
414static void f_synstack(typval_T *argvars, typval_T *rettv);
415static void f_synconcealed(typval_T *argvars, typval_T *rettv);
416static void f_system(typval_T *argvars, typval_T *rettv);
417static void f_systemlist(typval_T *argvars, typval_T *rettv);
418static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
419static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
420static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
421static void f_taglist(typval_T *argvars, typval_T *rettv);
422static void f_tagfiles(typval_T *argvars, typval_T *rettv);
423static void f_tempname(typval_T *argvars, typval_T *rettv);
424static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
425static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200426static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200427static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100428static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100430static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200431#ifdef FEAT_JOB_CHANNEL
432static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
433#endif
434static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
435#ifdef FEAT_JOB_CHANNEL
436static void f_test_null_job(typval_T *argvars, typval_T *rettv);
437#endif
438static void f_test_null_list(typval_T *argvars, typval_T *rettv);
439static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
440static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200441#ifdef FEAT_GUI
442static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
443#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200444static void f_test_settime(typval_T *argvars, typval_T *rettv);
445#ifdef FEAT_FLOAT
446static void f_tan(typval_T *argvars, typval_T *rettv);
447static void f_tanh(typval_T *argvars, typval_T *rettv);
448#endif
449#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200450static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200451static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200452static void f_timer_start(typval_T *argvars, typval_T *rettv);
453static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200454static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200455#endif
456static void f_tolower(typval_T *argvars, typval_T *rettv);
457static void f_toupper(typval_T *argvars, typval_T *rettv);
458static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100459static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200460#ifdef FEAT_FLOAT
461static void f_trunc(typval_T *argvars, typval_T *rettv);
462#endif
463static void f_type(typval_T *argvars, typval_T *rettv);
464static void f_undofile(typval_T *argvars, typval_T *rettv);
465static void f_undotree(typval_T *argvars, typval_T *rettv);
466static void f_uniq(typval_T *argvars, typval_T *rettv);
467static void f_values(typval_T *argvars, typval_T *rettv);
468static void f_virtcol(typval_T *argvars, typval_T *rettv);
469static void f_visualmode(typval_T *argvars, typval_T *rettv);
470static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
471static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
472static void f_win_getid(typval_T *argvars, typval_T *rettv);
473static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
474static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
475static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100476static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200477static void f_winbufnr(typval_T *argvars, typval_T *rettv);
478static void f_wincol(typval_T *argvars, typval_T *rettv);
479static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200480static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200481static void f_winline(typval_T *argvars, typval_T *rettv);
482static void f_winnr(typval_T *argvars, typval_T *rettv);
483static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
484static void f_winrestview(typval_T *argvars, typval_T *rettv);
485static void f_winsaveview(typval_T *argvars, typval_T *rettv);
486static void f_winwidth(typval_T *argvars, typval_T *rettv);
487static void f_writefile(typval_T *argvars, typval_T *rettv);
488static void f_wordcount(typval_T *argvars, typval_T *rettv);
489static void f_xor(typval_T *argvars, typval_T *rettv);
490
491/*
492 * Array with names and number of arguments of all internal functions
493 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
494 */
495static struct fst
496{
497 char *f_name; /* function name */
498 char f_min_argc; /* minimal number of arguments */
499 char f_max_argc; /* maximal number of arguments */
500 void (*f_func)(typval_T *args, typval_T *rvar);
501 /* implementation of function */
502} functions[] =
503{
504#ifdef FEAT_FLOAT
505 {"abs", 1, 1, f_abs},
506 {"acos", 1, 1, f_acos}, /* WJMc */
507#endif
508 {"add", 2, 2, f_add},
509 {"and", 2, 2, f_and},
510 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200511 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200512 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513 {"argidx", 0, 0, f_argidx},
514 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200515 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516#ifdef FEAT_FLOAT
517 {"asin", 1, 1, f_asin}, /* WJMc */
518#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100519 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100521 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200522 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200523 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200524 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100525 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526 {"assert_match", 2, 3, f_assert_match},
527 {"assert_notequal", 2, 3, f_assert_notequal},
528 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100529 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200530 {"assert_true", 1, 2, f_assert_true},
531#ifdef FEAT_FLOAT
532 {"atan", 1, 1, f_atan},
533 {"atan2", 2, 2, f_atan2},
534#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100535#ifdef FEAT_BEVAL
536 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100537# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100538 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100539# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100540#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200541 {"browse", 4, 4, f_browse},
542 {"browsedir", 2, 2, f_browsedir},
543 {"bufexists", 1, 1, f_bufexists},
544 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
545 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
546 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
547 {"buflisted", 1, 1, f_buflisted},
548 {"bufloaded", 1, 1, f_bufloaded},
549 {"bufname", 1, 1, f_bufname},
550 {"bufnr", 1, 2, f_bufnr},
551 {"bufwinid", 1, 1, f_bufwinid},
552 {"bufwinnr", 1, 1, f_bufwinnr},
553 {"byte2line", 1, 1, f_byte2line},
554 {"byteidx", 2, 2, f_byteidx},
555 {"byteidxcomp", 2, 2, f_byteidxcomp},
556 {"call", 2, 3, f_call},
557#ifdef FEAT_FLOAT
558 {"ceil", 1, 1, f_ceil},
559#endif
560#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100561 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200562 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200563 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200564 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
565 {"ch_evalraw", 2, 3, f_ch_evalraw},
566 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
567 {"ch_getjob", 1, 1, f_ch_getjob},
568 {"ch_info", 1, 1, f_ch_info},
569 {"ch_log", 1, 2, f_ch_log},
570 {"ch_logfile", 1, 2, f_ch_logfile},
571 {"ch_open", 1, 2, f_ch_open},
572 {"ch_read", 1, 2, f_ch_read},
573 {"ch_readraw", 1, 2, f_ch_readraw},
574 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
575 {"ch_sendraw", 2, 3, f_ch_sendraw},
576 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200577 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200578#endif
579 {"changenr", 0, 0, f_changenr},
580 {"char2nr", 1, 2, f_char2nr},
581 {"cindent", 1, 1, f_cindent},
582 {"clearmatches", 0, 0, f_clearmatches},
583 {"col", 1, 1, f_col},
584#if defined(FEAT_INS_EXPAND)
585 {"complete", 2, 2, f_complete},
586 {"complete_add", 1, 1, f_complete_add},
587 {"complete_check", 0, 0, f_complete_check},
588#endif
589 {"confirm", 1, 4, f_confirm},
590 {"copy", 1, 1, f_copy},
591#ifdef FEAT_FLOAT
592 {"cos", 1, 1, f_cos},
593 {"cosh", 1, 1, f_cosh},
594#endif
595 {"count", 2, 4, f_count},
596 {"cscope_connection",0,3, f_cscope_connection},
597 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200598#ifdef WIN3264
599 {"debugbreak", 1, 1, f_debugbreak},
600#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601 {"deepcopy", 1, 2, f_deepcopy},
602 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200603 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200604 {"did_filetype", 0, 0, f_did_filetype},
605 {"diff_filler", 1, 1, f_diff_filler},
606 {"diff_hlID", 2, 2, f_diff_hlID},
607 {"empty", 1, 1, f_empty},
608 {"escape", 2, 2, f_escape},
609 {"eval", 1, 1, f_eval},
610 {"eventhandler", 0, 0, f_eventhandler},
611 {"executable", 1, 1, f_executable},
612 {"execute", 1, 2, f_execute},
613 {"exepath", 1, 1, f_exepath},
614 {"exists", 1, 1, f_exists},
615#ifdef FEAT_FLOAT
616 {"exp", 1, 1, f_exp},
617#endif
618 {"expand", 1, 3, f_expand},
619 {"extend", 2, 3, f_extend},
620 {"feedkeys", 1, 2, f_feedkeys},
621 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
622 {"filereadable", 1, 1, f_filereadable},
623 {"filewritable", 1, 1, f_filewritable},
624 {"filter", 2, 2, f_filter},
625 {"finddir", 1, 3, f_finddir},
626 {"findfile", 1, 3, f_findfile},
627#ifdef FEAT_FLOAT
628 {"float2nr", 1, 1, f_float2nr},
629 {"floor", 1, 1, f_floor},
630 {"fmod", 2, 2, f_fmod},
631#endif
632 {"fnameescape", 1, 1, f_fnameescape},
633 {"fnamemodify", 2, 2, f_fnamemodify},
634 {"foldclosed", 1, 1, f_foldclosed},
635 {"foldclosedend", 1, 1, f_foldclosedend},
636 {"foldlevel", 1, 1, f_foldlevel},
637 {"foldtext", 0, 0, f_foldtext},
638 {"foldtextresult", 1, 1, f_foldtextresult},
639 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200640 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200641 {"function", 1, 3, f_function},
642 {"garbagecollect", 0, 1, f_garbagecollect},
643 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200644 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200645 {"getbufline", 2, 3, f_getbufline},
646 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100647 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200648 {"getchar", 0, 1, f_getchar},
649 {"getcharmod", 0, 0, f_getcharmod},
650 {"getcharsearch", 0, 0, f_getcharsearch},
651 {"getcmdline", 0, 0, f_getcmdline},
652 {"getcmdpos", 0, 0, f_getcmdpos},
653 {"getcmdtype", 0, 0, f_getcmdtype},
654 {"getcmdwintype", 0, 0, f_getcmdwintype},
655#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200656 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657#endif
658 {"getcurpos", 0, 0, f_getcurpos},
659 {"getcwd", 0, 2, f_getcwd},
660 {"getfontname", 0, 1, f_getfontname},
661 {"getfperm", 1, 1, f_getfperm},
662 {"getfsize", 1, 1, f_getfsize},
663 {"getftime", 1, 1, f_getftime},
664 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100665 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200667 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200668 {"getmatches", 0, 0, f_getmatches},
669 {"getpid", 0, 0, f_getpid},
670 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200671 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200672 {"getreg", 0, 3, f_getreg},
673 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200674 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200675 {"gettabvar", 2, 3, f_gettabvar},
676 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100677 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200678 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100679 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680 {"getwinposx", 0, 0, f_getwinposx},
681 {"getwinposy", 0, 0, f_getwinposy},
682 {"getwinvar", 2, 3, f_getwinvar},
683 {"glob", 1, 4, f_glob},
684 {"glob2regpat", 1, 1, f_glob2regpat},
685 {"globpath", 2, 5, f_globpath},
686 {"has", 1, 1, f_has},
687 {"has_key", 2, 2, f_has_key},
688 {"haslocaldir", 0, 2, f_haslocaldir},
689 {"hasmapto", 1, 3, f_hasmapto},
690 {"highlightID", 1, 1, f_hlID}, /* obsolete */
691 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
692 {"histadd", 2, 2, f_histadd},
693 {"histdel", 1, 2, f_histdel},
694 {"histget", 1, 2, f_histget},
695 {"histnr", 1, 1, f_histnr},
696 {"hlID", 1, 1, f_hlID},
697 {"hlexists", 1, 1, f_hlexists},
698 {"hostname", 0, 0, f_hostname},
699 {"iconv", 3, 3, f_iconv},
700 {"indent", 1, 1, f_indent},
701 {"index", 2, 4, f_index},
702 {"input", 1, 3, f_input},
703 {"inputdialog", 1, 3, f_inputdialog},
704 {"inputlist", 1, 1, f_inputlist},
705 {"inputrestore", 0, 0, f_inputrestore},
706 {"inputsave", 0, 0, f_inputsave},
707 {"inputsecret", 1, 2, f_inputsecret},
708 {"insert", 2, 3, f_insert},
709 {"invert", 1, 1, f_invert},
710 {"isdirectory", 1, 1, f_isdirectory},
711 {"islocked", 1, 1, f_islocked},
712#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
713 {"isnan", 1, 1, f_isnan},
714#endif
715 {"items", 1, 1, f_items},
716#ifdef FEAT_JOB_CHANNEL
717 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200718 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200719 {"job_setoptions", 2, 2, f_job_setoptions},
720 {"job_start", 1, 2, f_job_start},
721 {"job_status", 1, 1, f_job_status},
722 {"job_stop", 1, 2, f_job_stop},
723#endif
724 {"join", 1, 2, f_join},
725 {"js_decode", 1, 1, f_js_decode},
726 {"js_encode", 1, 1, f_js_encode},
727 {"json_decode", 1, 1, f_json_decode},
728 {"json_encode", 1, 1, f_json_encode},
729 {"keys", 1, 1, f_keys},
730 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
731 {"len", 1, 1, f_len},
732 {"libcall", 3, 3, f_libcall},
733 {"libcallnr", 3, 3, f_libcallnr},
734 {"line", 1, 1, f_line},
735 {"line2byte", 1, 1, f_line2byte},
736 {"lispindent", 1, 1, f_lispindent},
737 {"localtime", 0, 0, f_localtime},
738#ifdef FEAT_FLOAT
739 {"log", 1, 1, f_log},
740 {"log10", 1, 1, f_log10},
741#endif
742#ifdef FEAT_LUA
743 {"luaeval", 1, 2, f_luaeval},
744#endif
745 {"map", 2, 2, f_map},
746 {"maparg", 1, 4, f_maparg},
747 {"mapcheck", 1, 3, f_mapcheck},
748 {"match", 2, 4, f_match},
749 {"matchadd", 2, 5, f_matchadd},
750 {"matchaddpos", 2, 5, f_matchaddpos},
751 {"matcharg", 1, 1, f_matcharg},
752 {"matchdelete", 1, 1, f_matchdelete},
753 {"matchend", 2, 4, f_matchend},
754 {"matchlist", 2, 4, f_matchlist},
755 {"matchstr", 2, 4, f_matchstr},
756 {"matchstrpos", 2, 4, f_matchstrpos},
757 {"max", 1, 1, f_max},
758 {"min", 1, 1, f_min},
759#ifdef vim_mkdir
760 {"mkdir", 1, 3, f_mkdir},
761#endif
762 {"mode", 0, 1, f_mode},
763#ifdef FEAT_MZSCHEME
764 {"mzeval", 1, 1, f_mzeval},
765#endif
766 {"nextnonblank", 1, 1, f_nextnonblank},
767 {"nr2char", 1, 2, f_nr2char},
768 {"or", 2, 2, f_or},
769 {"pathshorten", 1, 1, f_pathshorten},
770#ifdef FEAT_PERL
771 {"perleval", 1, 1, f_perleval},
772#endif
773#ifdef FEAT_FLOAT
774 {"pow", 2, 2, f_pow},
775#endif
776 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100777 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200778#ifdef FEAT_JOB_CHANNEL
779 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200780 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200781 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
782#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100783#ifdef FEAT_TEXT_PROP
784 {"prop_add", 3, 3, f_prop_add},
785 {"prop_clear", 1, 3, f_prop_clear},
786 {"prop_list", 1, 2, f_prop_list},
787 {"prop_remove", 2, 3, f_prop_remove},
788 {"prop_type_add", 2, 2, f_prop_type_add},
789 {"prop_type_change", 2, 2, f_prop_type_change},
790 {"prop_type_delete", 1, 2, f_prop_type_delete},
791 {"prop_type_get", 1, 2, f_prop_type_get},
792 {"prop_type_list", 0, 1, f_prop_type_list},
793#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794 {"pumvisible", 0, 0, f_pumvisible},
795#ifdef FEAT_PYTHON3
796 {"py3eval", 1, 1, f_py3eval},
797#endif
798#ifdef FEAT_PYTHON
799 {"pyeval", 1, 1, f_pyeval},
800#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100801#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
802 {"pyxeval", 1, 1, f_pyxeval},
803#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804 {"range", 1, 3, f_range},
805 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200806 {"reg_executing", 0, 0, f_reg_executing},
807 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808 {"reltime", 0, 2, f_reltime},
809#ifdef FEAT_FLOAT
810 {"reltimefloat", 1, 1, f_reltimefloat},
811#endif
812 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100813 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814 {"remote_foreground", 1, 1, f_remote_foreground},
815 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100816 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100818 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819 {"remove", 2, 3, f_remove},
820 {"rename", 2, 2, f_rename},
821 {"repeat", 2, 2, f_repeat},
822 {"resolve", 1, 1, f_resolve},
823 {"reverse", 1, 1, f_reverse},
824#ifdef FEAT_FLOAT
825 {"round", 1, 1, f_round},
826#endif
827 {"screenattr", 2, 2, f_screenattr},
828 {"screenchar", 2, 2, f_screenchar},
829 {"screencol", 0, 0, f_screencol},
830 {"screenrow", 0, 0, f_screenrow},
831 {"search", 1, 4, f_search},
832 {"searchdecl", 1, 3, f_searchdecl},
833 {"searchpair", 3, 7, f_searchpair},
834 {"searchpairpos", 3, 7, f_searchpairpos},
835 {"searchpos", 1, 4, f_searchpos},
836 {"server2client", 2, 2, f_server2client},
837 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200838 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839 {"setbufvar", 3, 3, f_setbufvar},
840 {"setcharsearch", 1, 1, f_setcharsearch},
841 {"setcmdpos", 1, 1, f_setcmdpos},
842 {"setfperm", 2, 2, f_setfperm},
843 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200844 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200845 {"setmatches", 1, 1, f_setmatches},
846 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200847 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848 {"setreg", 2, 3, f_setreg},
849 {"settabvar", 3, 3, f_settabvar},
850 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100851 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200852 {"setwinvar", 3, 3, f_setwinvar},
853#ifdef FEAT_CRYPT
854 {"sha256", 1, 1, f_sha256},
855#endif
856 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100857 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100858#ifdef FEAT_SIGNS
859 {"sign_define", 1, 2, f_sign_define},
860 {"sign_getdefined", 0, 1, f_sign_getdefined},
861 {"sign_getplaced", 0, 2, f_sign_getplaced},
862 {"sign_place", 4, 5, f_sign_place},
863 {"sign_undefine", 0, 1, f_sign_undefine},
864 {"sign_unplace", 1, 2, f_sign_unplace},
865#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200866 {"simplify", 1, 1, f_simplify},
867#ifdef FEAT_FLOAT
868 {"sin", 1, 1, f_sin},
869 {"sinh", 1, 1, f_sinh},
870#endif
871 {"sort", 1, 3, f_sort},
872 {"soundfold", 1, 1, f_soundfold},
873 {"spellbadword", 0, 1, f_spellbadword},
874 {"spellsuggest", 1, 3, f_spellsuggest},
875 {"split", 1, 3, f_split},
876#ifdef FEAT_FLOAT
877 {"sqrt", 1, 1, f_sqrt},
878 {"str2float", 1, 1, f_str2float},
879#endif
880 {"str2nr", 1, 2, f_str2nr},
881 {"strcharpart", 2, 3, f_strcharpart},
882 {"strchars", 1, 2, f_strchars},
883 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
884#ifdef HAVE_STRFTIME
885 {"strftime", 1, 2, f_strftime},
886#endif
887 {"strgetchar", 2, 2, f_strgetchar},
888 {"stridx", 2, 3, f_stridx},
889 {"string", 1, 1, f_string},
890 {"strlen", 1, 1, f_strlen},
891 {"strpart", 2, 3, f_strpart},
892 {"strridx", 2, 3, f_strridx},
893 {"strtrans", 1, 1, f_strtrans},
894 {"strwidth", 1, 1, f_strwidth},
895 {"submatch", 1, 2, f_submatch},
896 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200897 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200898 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200899 {"synID", 3, 3, f_synID},
900 {"synIDattr", 2, 3, f_synIDattr},
901 {"synIDtrans", 1, 1, f_synIDtrans},
902 {"synconcealed", 2, 2, f_synconcealed},
903 {"synstack", 2, 2, f_synstack},
904 {"system", 1, 2, f_system},
905 {"systemlist", 1, 2, f_systemlist},
906 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
907 {"tabpagenr", 0, 1, f_tabpagenr},
908 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
909 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100910 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200911#ifdef FEAT_FLOAT
912 {"tan", 1, 1, f_tan},
913 {"tanh", 1, 1, f_tanh},
914#endif
915 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200916#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100917 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
918 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100919 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200920 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200921# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
922 {"term_getansicolors", 1, 1, f_term_getansicolors},
923# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200924 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200925 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200926 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200927 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200928 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200929 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200930 {"term_getstatus", 1, 1, f_term_getstatus},
931 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200932 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200933 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200934 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200935 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200936# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
937 {"term_setansicolors", 2, 2, f_term_setansicolors},
938# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100939 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100940 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200941 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200942 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200943 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200944#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200945 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
946 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200947 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100949 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200950#ifdef FEAT_JOB_CHANNEL
951 {"test_null_channel", 0, 0, f_test_null_channel},
952#endif
953 {"test_null_dict", 0, 0, f_test_null_dict},
954#ifdef FEAT_JOB_CHANNEL
955 {"test_null_job", 0, 0, f_test_null_job},
956#endif
957 {"test_null_list", 0, 0, f_test_null_list},
958 {"test_null_partial", 0, 0, f_test_null_partial},
959 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200960 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100961 {"test_override", 2, 2, f_test_override},
Bram Moolenaarab186732018-09-14 21:27:06 +0200962#ifdef FEAT_GUI
963 {"test_scrollbar", 3, 3, f_test_scrollbar},
964#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965 {"test_settime", 1, 1, f_test_settime},
966#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200967 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200968 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200969 {"timer_start", 2, 3, f_timer_start},
970 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200971 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200972#endif
973 {"tolower", 1, 1, f_tolower},
974 {"toupper", 1, 1, f_toupper},
975 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100976 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200977#ifdef FEAT_FLOAT
978 {"trunc", 1, 1, f_trunc},
979#endif
980 {"type", 1, 1, f_type},
981 {"undofile", 1, 1, f_undofile},
982 {"undotree", 0, 0, f_undotree},
983 {"uniq", 1, 3, f_uniq},
984 {"values", 1, 1, f_values},
985 {"virtcol", 1, 1, f_virtcol},
986 {"visualmode", 0, 1, f_visualmode},
987 {"wildmenumode", 0, 0, f_wildmenumode},
988 {"win_findbuf", 1, 1, f_win_findbuf},
989 {"win_getid", 0, 2, f_win_getid},
990 {"win_gotoid", 1, 1, f_win_gotoid},
991 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
992 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100993 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200994 {"winbufnr", 1, 1, f_winbufnr},
995 {"wincol", 0, 0, f_wincol},
996 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200997 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200998 {"winline", 0, 0, f_winline},
999 {"winnr", 0, 1, f_winnr},
1000 {"winrestcmd", 0, 0, f_winrestcmd},
1001 {"winrestview", 1, 1, f_winrestview},
1002 {"winsaveview", 0, 0, f_winsaveview},
1003 {"winwidth", 1, 1, f_winwidth},
1004 {"wordcount", 0, 0, f_wordcount},
1005 {"writefile", 2, 3, f_writefile},
1006 {"xor", 2, 2, f_xor},
1007};
1008
1009#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1010
1011/*
1012 * Function given to ExpandGeneric() to obtain the list of internal
1013 * or user defined function names.
1014 */
1015 char_u *
1016get_function_name(expand_T *xp, int idx)
1017{
1018 static int intidx = -1;
1019 char_u *name;
1020
1021 if (idx == 0)
1022 intidx = -1;
1023 if (intidx < 0)
1024 {
1025 name = get_user_func_name(xp, idx);
1026 if (name != NULL)
1027 return name;
1028 }
1029 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1030 {
1031 STRCPY(IObuff, functions[intidx].f_name);
1032 STRCAT(IObuff, "(");
1033 if (functions[intidx].f_max_argc == 0)
1034 STRCAT(IObuff, ")");
1035 return IObuff;
1036 }
1037
1038 return NULL;
1039}
1040
1041/*
1042 * Function given to ExpandGeneric() to obtain the list of internal or
1043 * user defined variable or function names.
1044 */
1045 char_u *
1046get_expr_name(expand_T *xp, int idx)
1047{
1048 static int intidx = -1;
1049 char_u *name;
1050
1051 if (idx == 0)
1052 intidx = -1;
1053 if (intidx < 0)
1054 {
1055 name = get_function_name(xp, idx);
1056 if (name != NULL)
1057 return name;
1058 }
1059 return get_user_var_name(xp, ++intidx);
1060}
1061
1062#endif /* FEAT_CMDL_COMPL */
1063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001064/*
1065 * Find internal function in table above.
1066 * Return index, or -1 if not found
1067 */
1068 int
1069find_internal_func(
1070 char_u *name) /* name of the function */
1071{
1072 int first = 0;
1073 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1074 int cmp;
1075 int x;
1076
1077 /*
1078 * Find the function name in the table. Binary search.
1079 */
1080 while (first <= last)
1081 {
1082 x = first + ((unsigned)(last - first) >> 1);
1083 cmp = STRCMP(name, functions[x].f_name);
1084 if (cmp < 0)
1085 last = x - 1;
1086 else if (cmp > 0)
1087 first = x + 1;
1088 else
1089 return x;
1090 }
1091 return -1;
1092}
1093
1094 int
1095call_internal_func(
1096 char_u *name,
1097 int argcount,
1098 typval_T *argvars,
1099 typval_T *rettv)
1100{
1101 int i;
1102
1103 i = find_internal_func(name);
1104 if (i < 0)
1105 return ERROR_UNKNOWN;
1106 if (argcount < functions[i].f_min_argc)
1107 return ERROR_TOOFEW;
1108 if (argcount > functions[i].f_max_argc)
1109 return ERROR_TOOMANY;
1110 argvars[argcount].v_type = VAR_UNKNOWN;
1111 functions[i].f_func(argvars, rettv);
1112 return ERROR_NONE;
1113}
1114
1115/*
1116 * Return TRUE for a non-zero Number and a non-empty String.
1117 */
1118 static int
1119non_zero_arg(typval_T *argvars)
1120{
1121 return ((argvars[0].v_type == VAR_NUMBER
1122 && argvars[0].vval.v_number != 0)
1123 || (argvars[0].v_type == VAR_SPECIAL
1124 && argvars[0].vval.v_number == VVAL_TRUE)
1125 || (argvars[0].v_type == VAR_STRING
1126 && argvars[0].vval.v_string != NULL
1127 && *argvars[0].vval.v_string != NUL));
1128}
1129
1130/*
1131 * Get the lnum from the first argument.
1132 * Also accepts ".", "$", etc., but that only works for the current buffer.
1133 * Returns -1 on error.
1134 */
1135 static linenr_T
1136get_tv_lnum(typval_T *argvars)
1137{
1138 typval_T rettv;
1139 linenr_T lnum;
1140
1141 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1142 if (lnum == 0) /* no valid number, try using line() */
1143 {
1144 rettv.v_type = VAR_NUMBER;
1145 f_line(argvars, &rettv);
1146 lnum = (linenr_T)rettv.vval.v_number;
1147 clear_tv(&rettv);
1148 }
1149 return lnum;
1150}
1151
1152#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001153/*
1154 * Get the float value of "argvars[0]" into "f".
1155 * Returns FAIL when the argument is not a Number or Float.
1156 */
1157 static int
1158get_float_arg(typval_T *argvars, float_T *f)
1159{
1160 if (argvars[0].v_type == VAR_FLOAT)
1161 {
1162 *f = argvars[0].vval.v_float;
1163 return OK;
1164 }
1165 if (argvars[0].v_type == VAR_NUMBER)
1166 {
1167 *f = (float_T)argvars[0].vval.v_number;
1168 return OK;
1169 }
1170 EMSG(_("E808: Number or Float required"));
1171 return FAIL;
1172}
1173
1174/*
1175 * "abs(expr)" function
1176 */
1177 static void
1178f_abs(typval_T *argvars, typval_T *rettv)
1179{
1180 if (argvars[0].v_type == VAR_FLOAT)
1181 {
1182 rettv->v_type = VAR_FLOAT;
1183 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1184 }
1185 else
1186 {
1187 varnumber_T n;
1188 int error = FALSE;
1189
1190 n = get_tv_number_chk(&argvars[0], &error);
1191 if (error)
1192 rettv->vval.v_number = -1;
1193 else if (n > 0)
1194 rettv->vval.v_number = n;
1195 else
1196 rettv->vval.v_number = -n;
1197 }
1198}
1199
1200/*
1201 * "acos()" function
1202 */
1203 static void
1204f_acos(typval_T *argvars, typval_T *rettv)
1205{
1206 float_T f = 0.0;
1207
1208 rettv->v_type = VAR_FLOAT;
1209 if (get_float_arg(argvars, &f) == OK)
1210 rettv->vval.v_float = acos(f);
1211 else
1212 rettv->vval.v_float = 0.0;
1213}
1214#endif
1215
1216/*
1217 * "add(list, item)" function
1218 */
1219 static void
1220f_add(typval_T *argvars, typval_T *rettv)
1221{
1222 list_T *l;
1223
1224 rettv->vval.v_number = 1; /* Default: Failed */
1225 if (argvars[0].v_type == VAR_LIST)
1226 {
1227 if ((l = argvars[0].vval.v_list) != NULL
1228 && !tv_check_lock(l->lv_lock,
1229 (char_u *)N_("add() argument"), TRUE)
1230 && list_append_tv(l, &argvars[1]) == OK)
1231 copy_tv(&argvars[0], rettv);
1232 }
1233 else
1234 EMSG(_(e_listreq));
1235}
1236
1237/*
1238 * "and(expr, expr)" function
1239 */
1240 static void
1241f_and(typval_T *argvars, typval_T *rettv)
1242{
1243 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1244 & get_tv_number_chk(&argvars[1], NULL);
1245}
1246
1247/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001248 * Get the lnum from the first argument.
1249 * Also accepts "$", then "buf" is used.
1250 * Returns 0 on error.
1251 */
1252 static linenr_T
1253get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
1254{
1255 if (argvars[0].v_type == VAR_STRING
1256 && argvars[0].vval.v_string != NULL
1257 && argvars[0].vval.v_string[0] == '$'
1258 && buf != NULL)
1259 return buf->b_ml.ml_line_count;
1260 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1261}
1262
1263/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001264 * If there is a window for "curbuf", make it the current window.
1265 */
1266 static void
1267find_win_for_curbuf(void)
1268{
1269 wininfo_T *wip;
1270
1271 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1272 {
1273 if (wip->wi_win != NULL)
1274 {
1275 curwin = wip->wi_win;
1276 break;
1277 }
1278 }
1279}
1280
1281/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001282 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001283 */
1284 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001285set_buffer_lines(
1286 buf_T *buf,
1287 linenr_T lnum_arg,
1288 int append,
1289 typval_T *lines,
1290 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001291{
Bram Moolenaarca851592018-06-06 21:04:07 +02001292 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1293 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001294 list_T *l = NULL;
1295 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001296 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001297 linenr_T append_lnum;
1298 buf_T *curbuf_save = NULL;
1299 win_T *curwin_save = NULL;
1300 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001301
Bram Moolenaarca851592018-06-06 21:04:07 +02001302 /* When using the current buffer ml_mfp will be set if needed. Useful when
1303 * setline() is used on startup. For other buffers the buffer must be
1304 * loaded. */
1305 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001306 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001307 rettv->vval.v_number = 1; /* FAIL */
1308 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001309 }
1310
Bram Moolenaarca851592018-06-06 21:04:07 +02001311 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001312 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001313 curbuf_save = curbuf;
1314 curwin_save = curwin;
1315 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001316 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001317 }
1318
1319 if (append)
1320 // appendbufline() uses the line number below which we insert
1321 append_lnum = lnum - 1;
1322 else
1323 // setbufline() uses the line number above which we insert, we only
1324 // append if it's below the last line
1325 append_lnum = curbuf->b_ml.ml_line_count;
1326
1327 if (lines->v_type == VAR_LIST)
1328 {
1329 l = lines->vval.v_list;
1330 li = l->lv_first;
1331 }
1332 else
1333 line = get_tv_string_chk(lines);
1334
1335 /* default result is zero == OK */
1336 for (;;)
1337 {
1338 if (l != NULL)
1339 {
1340 /* list argument, get next string */
1341 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001342 break;
Bram Moolenaarca851592018-06-06 21:04:07 +02001343 line = get_tv_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344 li = li->li_next;
1345 }
1346
Bram Moolenaarca851592018-06-06 21:04:07 +02001347 rettv->vval.v_number = 1; /* FAIL */
1348 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1349 break;
1350
1351 /* When coming here from Insert mode, sync undo, so that this can be
1352 * undone separately from what was previously inserted. */
1353 if (u_sync_once == 2)
1354 {
1355 u_sync_once = 1; /* notify that u_sync() was called */
1356 u_sync(TRUE);
1357 }
1358
1359 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1360 {
1361 /* existing line, replace it */
1362 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1363 {
1364 changed_bytes(lnum, 0);
1365 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1366 check_cursor_col();
1367 rettv->vval.v_number = 0; /* OK */
1368 }
1369 }
1370 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1371 {
1372 /* append the line */
1373 ++added;
1374 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1375 rettv->vval.v_number = 0; /* OK */
1376 }
1377
1378 if (l == NULL) /* only one string argument */
1379 break;
1380 ++lnum;
1381 }
1382
1383 if (added > 0)
1384 {
1385 win_T *wp;
1386 tabpage_T *tp;
1387
1388 appended_lines_mark(append_lnum, added);
1389 FOR_ALL_TAB_WINDOWS(tp, wp)
1390 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1391 wp->w_cursor.lnum += added;
1392 check_cursor_col();
1393
Bram Moolenaarf2732452018-06-03 14:47:35 +02001394#ifdef FEAT_JOB_CHANNEL
1395 if (bt_prompt(curbuf) && (State & INSERT))
1396 // show the line with the prompt
1397 update_topline();
1398#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001399 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001400
1401 if (!is_curbuf)
1402 {
1403 curbuf = curbuf_save;
1404 curwin = curwin_save;
1405 }
1406}
1407
1408/*
1409 * "append(lnum, string/list)" function
1410 */
1411 static void
1412f_append(typval_T *argvars, typval_T *rettv)
1413{
1414 linenr_T lnum = get_tv_lnum(&argvars[0]);
1415
1416 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1417}
1418
1419/*
1420 * "appendbufline(buf, lnum, string/list)" function
1421 */
1422 static void
1423f_appendbufline(typval_T *argvars, typval_T *rettv)
1424{
1425 linenr_T lnum;
1426 buf_T *buf;
1427
1428 buf = get_buf_tv(&argvars[0], FALSE);
1429 if (buf == NULL)
1430 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001431 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001432 {
1433 lnum = get_tv_lnum_buf(&argvars[1], buf);
1434 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1435 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001436}
1437
1438/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001439 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001440 */
1441 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001442f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001443{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001444 win_T *wp;
1445
1446 if (argvars[0].v_type == VAR_UNKNOWN)
1447 // use the current window
1448 rettv->vval.v_number = ARGCOUNT;
1449 else if (argvars[0].v_type == VAR_NUMBER
1450 && get_tv_number(&argvars[0]) == -1)
1451 // use the global argument list
1452 rettv->vval.v_number = GARGCOUNT;
1453 else
1454 {
1455 // use the argument list of the specified window
1456 wp = find_win_by_nr_or_id(&argvars[0]);
1457 if (wp != NULL)
1458 rettv->vval.v_number = WARGCOUNT(wp);
1459 else
1460 rettv->vval.v_number = -1;
1461 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001462}
1463
1464/*
1465 * "argidx()" function
1466 */
1467 static void
1468f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1469{
1470 rettv->vval.v_number = curwin->w_arg_idx;
1471}
1472
1473/*
1474 * "arglistid()" function
1475 */
1476 static void
1477f_arglistid(typval_T *argvars, typval_T *rettv)
1478{
1479 win_T *wp;
1480
1481 rettv->vval.v_number = -1;
1482 wp = find_tabwin(&argvars[0], &argvars[1]);
1483 if (wp != NULL)
1484 rettv->vval.v_number = wp->w_alist->id;
1485}
1486
1487/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001488 * Get the argument list for a given window
1489 */
1490 static void
1491get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1492{
1493 int idx;
1494
1495 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1496 for (idx = 0; idx < argcount; ++idx)
1497 list_append_string(rettv->vval.v_list,
1498 alist_name(&arglist[idx]), -1);
1499}
1500
1501/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502 * "argv(nr)" function
1503 */
1504 static void
1505f_argv(typval_T *argvars, typval_T *rettv)
1506{
1507 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001508 aentry_T *arglist = NULL;
1509 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001510
1511 if (argvars[0].v_type != VAR_UNKNOWN)
1512 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001513 if (argvars[1].v_type == VAR_UNKNOWN)
1514 {
1515 arglist = ARGLIST;
1516 argcount = ARGCOUNT;
1517 }
1518 else if (argvars[1].v_type == VAR_NUMBER
1519 && get_tv_number(&argvars[1]) == -1)
1520 {
1521 arglist = GARGLIST;
1522 argcount = GARGCOUNT;
1523 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001524 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001525 {
1526 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1527
1528 if (wp != NULL)
1529 {
1530 /* Use the argument list of the specified window */
1531 arglist = WARGLIST(wp);
1532 argcount = WARGCOUNT(wp);
1533 }
1534 }
1535
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001536 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001537 rettv->vval.v_string = NULL;
1538 idx = get_tv_number_chk(&argvars[0], NULL);
1539 if (arglist != NULL && idx >= 0 && idx < argcount)
1540 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1541 else if (idx == -1)
1542 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001543 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001544 else
1545 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001546}
1547
1548/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001549 * "assert_beeps(cmd [, error])" function
1550 */
1551 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001552f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001553{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001554 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001555}
1556
1557/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001558 * "assert_equal(expected, actual[, msg])" function
1559 */
1560 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001561f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001562{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001563 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001564}
1565
1566/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001567 * "assert_equalfile(fname-one, fname-two)" function
1568 */
1569 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001570f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001571{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001572 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001573}
1574
1575/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 * "assert_notequal(expected, actual[, msg])" function
1577 */
1578 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001579f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001581 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001582}
1583
1584/*
1585 * "assert_exception(string[, msg])" function
1586 */
1587 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001588f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001589{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001590 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001591}
1592
1593/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001594 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001595 */
1596 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001597f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001599 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001600}
1601
1602/*
1603 * "assert_false(actual[, msg])" function
1604 */
1605 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001606f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001608 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609}
1610
1611/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001612 * "assert_inrange(lower, upper[, msg])" function
1613 */
1614 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001615f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001616{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001617 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001618}
1619
1620/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001621 * "assert_match(pattern, actual[, msg])" function
1622 */
1623 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001624f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001626 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627}
1628
1629/*
1630 * "assert_notmatch(pattern, actual[, msg])" function
1631 */
1632 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001633f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001634{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001635 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001636}
1637
1638/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001639 * "assert_report(msg)" function
1640 */
1641 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001642f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001643{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001644 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001645}
1646
1647/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648 * "assert_true(actual[, msg])" function
1649 */
1650 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001651f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001652{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001653 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001654}
1655
1656#ifdef FEAT_FLOAT
1657/*
1658 * "asin()" function
1659 */
1660 static void
1661f_asin(typval_T *argvars, typval_T *rettv)
1662{
1663 float_T f = 0.0;
1664
1665 rettv->v_type = VAR_FLOAT;
1666 if (get_float_arg(argvars, &f) == OK)
1667 rettv->vval.v_float = asin(f);
1668 else
1669 rettv->vval.v_float = 0.0;
1670}
1671
1672/*
1673 * "atan()" function
1674 */
1675 static void
1676f_atan(typval_T *argvars, typval_T *rettv)
1677{
1678 float_T f = 0.0;
1679
1680 rettv->v_type = VAR_FLOAT;
1681 if (get_float_arg(argvars, &f) == OK)
1682 rettv->vval.v_float = atan(f);
1683 else
1684 rettv->vval.v_float = 0.0;
1685}
1686
1687/*
1688 * "atan2()" function
1689 */
1690 static void
1691f_atan2(typval_T *argvars, typval_T *rettv)
1692{
1693 float_T fx = 0.0, fy = 0.0;
1694
1695 rettv->v_type = VAR_FLOAT;
1696 if (get_float_arg(argvars, &fx) == OK
1697 && get_float_arg(&argvars[1], &fy) == OK)
1698 rettv->vval.v_float = atan2(fx, fy);
1699 else
1700 rettv->vval.v_float = 0.0;
1701}
1702#endif
1703
1704/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001705 * "balloon_show()" function
1706 */
1707#ifdef FEAT_BEVAL
1708 static void
1709f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1710{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001711 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001712 {
1713 if (argvars[0].v_type == VAR_LIST
1714# ifdef FEAT_GUI
1715 && !gui.in_use
1716# endif
1717 )
1718 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1719 else
1720 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1721 }
1722}
1723
Bram Moolenaar669a8282017-11-19 20:13:05 +01001724# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001725 static void
1726f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1727{
1728 if (rettv_list_alloc(rettv) == OK)
1729 {
1730 char_u *msg = get_tv_string_chk(&argvars[0]);
1731
1732 if (msg != NULL)
1733 {
1734 pumitem_T *array;
1735 int size = split_message(msg, &array);
1736 int i;
1737
1738 /* Skip the first and last item, they are always empty. */
1739 for (i = 1; i < size - 1; ++i)
1740 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001741 while (size > 0)
1742 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001743 vim_free(array);
1744 }
1745 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001746}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001747# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001748#endif
1749
1750/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001751 * "browse(save, title, initdir, default)" function
1752 */
1753 static void
1754f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1755{
1756#ifdef FEAT_BROWSE
1757 int save;
1758 char_u *title;
1759 char_u *initdir;
1760 char_u *defname;
1761 char_u buf[NUMBUFLEN];
1762 char_u buf2[NUMBUFLEN];
1763 int error = FALSE;
1764
1765 save = (int)get_tv_number_chk(&argvars[0], &error);
1766 title = get_tv_string_chk(&argvars[1]);
1767 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1768 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1769
1770 if (error || title == NULL || initdir == NULL || defname == NULL)
1771 rettv->vval.v_string = NULL;
1772 else
1773 rettv->vval.v_string =
1774 do_browse(save ? BROWSE_SAVE : 0,
1775 title, defname, NULL, initdir, NULL, curbuf);
1776#else
1777 rettv->vval.v_string = NULL;
1778#endif
1779 rettv->v_type = VAR_STRING;
1780}
1781
1782/*
1783 * "browsedir(title, initdir)" function
1784 */
1785 static void
1786f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1787{
1788#ifdef FEAT_BROWSE
1789 char_u *title;
1790 char_u *initdir;
1791 char_u buf[NUMBUFLEN];
1792
1793 title = get_tv_string_chk(&argvars[0]);
1794 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1795
1796 if (title == NULL || initdir == NULL)
1797 rettv->vval.v_string = NULL;
1798 else
1799 rettv->vval.v_string = do_browse(BROWSE_DIR,
1800 title, NULL, NULL, initdir, NULL, curbuf);
1801#else
1802 rettv->vval.v_string = NULL;
1803#endif
1804 rettv->v_type = VAR_STRING;
1805}
1806
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001807/*
1808 * Find a buffer by number or exact name.
1809 */
1810 static buf_T *
1811find_buffer(typval_T *avar)
1812{
1813 buf_T *buf = NULL;
1814
1815 if (avar->v_type == VAR_NUMBER)
1816 buf = buflist_findnr((int)avar->vval.v_number);
1817 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1818 {
1819 buf = buflist_findname_exp(avar->vval.v_string);
1820 if (buf == NULL)
1821 {
1822 /* No full path name match, try a match with a URL or a "nofile"
1823 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001824 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 if (buf->b_fname != NULL
1826 && (path_with_url(buf->b_fname)
1827#ifdef FEAT_QUICKFIX
1828 || bt_nofile(buf)
1829#endif
1830 )
1831 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1832 break;
1833 }
1834 }
1835 return buf;
1836}
1837
1838/*
1839 * "bufexists(expr)" function
1840 */
1841 static void
1842f_bufexists(typval_T *argvars, typval_T *rettv)
1843{
1844 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1845}
1846
1847/*
1848 * "buflisted(expr)" function
1849 */
1850 static void
1851f_buflisted(typval_T *argvars, typval_T *rettv)
1852{
1853 buf_T *buf;
1854
1855 buf = find_buffer(&argvars[0]);
1856 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1857}
1858
1859/*
1860 * "bufloaded(expr)" function
1861 */
1862 static void
1863f_bufloaded(typval_T *argvars, typval_T *rettv)
1864{
1865 buf_T *buf;
1866
1867 buf = find_buffer(&argvars[0]);
1868 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1869}
1870
1871 buf_T *
1872buflist_find_by_name(char_u *name, int curtab_only)
1873{
1874 int save_magic;
1875 char_u *save_cpo;
1876 buf_T *buf;
1877
1878 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1879 save_magic = p_magic;
1880 p_magic = TRUE;
1881 save_cpo = p_cpo;
1882 p_cpo = (char_u *)"";
1883
1884 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1885 TRUE, FALSE, curtab_only));
1886
1887 p_magic = save_magic;
1888 p_cpo = save_cpo;
1889 return buf;
1890}
1891
1892/*
1893 * Get buffer by number or pattern.
1894 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001895 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001896get_buf_tv(typval_T *tv, int curtab_only)
1897{
1898 char_u *name = tv->vval.v_string;
1899 buf_T *buf;
1900
1901 if (tv->v_type == VAR_NUMBER)
1902 return buflist_findnr((int)tv->vval.v_number);
1903 if (tv->v_type != VAR_STRING)
1904 return NULL;
1905 if (name == NULL || *name == NUL)
1906 return curbuf;
1907 if (name[0] == '$' && name[1] == NUL)
1908 return lastbuf;
1909
1910 buf = buflist_find_by_name(name, curtab_only);
1911
1912 /* If not found, try expanding the name, like done for bufexists(). */
1913 if (buf == NULL)
1914 buf = find_buffer(tv);
1915
1916 return buf;
1917}
1918
1919/*
1920 * "bufname(expr)" function
1921 */
1922 static void
1923f_bufname(typval_T *argvars, typval_T *rettv)
1924{
1925 buf_T *buf;
1926
1927 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1928 ++emsg_off;
1929 buf = get_buf_tv(&argvars[0], FALSE);
1930 rettv->v_type = VAR_STRING;
1931 if (buf != NULL && buf->b_fname != NULL)
1932 rettv->vval.v_string = vim_strsave(buf->b_fname);
1933 else
1934 rettv->vval.v_string = NULL;
1935 --emsg_off;
1936}
1937
1938/*
1939 * "bufnr(expr)" function
1940 */
1941 static void
1942f_bufnr(typval_T *argvars, typval_T *rettv)
1943{
1944 buf_T *buf;
1945 int error = FALSE;
1946 char_u *name;
1947
1948 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1949 ++emsg_off;
1950 buf = get_buf_tv(&argvars[0], FALSE);
1951 --emsg_off;
1952
1953 /* If the buffer isn't found and the second argument is not zero create a
1954 * new buffer. */
1955 if (buf == NULL
1956 && argvars[1].v_type != VAR_UNKNOWN
1957 && get_tv_number_chk(&argvars[1], &error) != 0
1958 && !error
1959 && (name = get_tv_string_chk(&argvars[0])) != NULL
1960 && !error)
1961 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1962
1963 if (buf != NULL)
1964 rettv->vval.v_number = buf->b_fnum;
1965 else
1966 rettv->vval.v_number = -1;
1967}
1968
1969 static void
1970buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1971{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001972 win_T *wp;
1973 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001974 buf_T *buf;
1975
1976 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1977 ++emsg_off;
1978 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001979 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 {
1981 ++winnr;
1982 if (wp->w_buffer == buf)
1983 break;
1984 }
1985 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986 --emsg_off;
1987}
1988
1989/*
1990 * "bufwinid(nr)" function
1991 */
1992 static void
1993f_bufwinid(typval_T *argvars, typval_T *rettv)
1994{
1995 buf_win_common(argvars, rettv, FALSE);
1996}
1997
1998/*
1999 * "bufwinnr(nr)" function
2000 */
2001 static void
2002f_bufwinnr(typval_T *argvars, typval_T *rettv)
2003{
2004 buf_win_common(argvars, rettv, TRUE);
2005}
2006
2007/*
2008 * "byte2line(byte)" function
2009 */
2010 static void
2011f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2012{
2013#ifndef FEAT_BYTEOFF
2014 rettv->vval.v_number = -1;
2015#else
2016 long boff = 0;
2017
2018 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
2019 if (boff < 0)
2020 rettv->vval.v_number = -1;
2021 else
2022 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2023 (linenr_T)0, &boff);
2024#endif
2025}
2026
2027 static void
2028byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2029{
2030#ifdef FEAT_MBYTE
2031 char_u *t;
2032#endif
2033 char_u *str;
2034 varnumber_T idx;
2035
2036 str = get_tv_string_chk(&argvars[0]);
2037 idx = get_tv_number_chk(&argvars[1], NULL);
2038 rettv->vval.v_number = -1;
2039 if (str == NULL || idx < 0)
2040 return;
2041
2042#ifdef FEAT_MBYTE
2043 t = str;
2044 for ( ; idx > 0; idx--)
2045 {
2046 if (*t == NUL) /* EOL reached */
2047 return;
2048 if (enc_utf8 && comp)
2049 t += utf_ptr2len(t);
2050 else
2051 t += (*mb_ptr2len)(t);
2052 }
2053 rettv->vval.v_number = (varnumber_T)(t - str);
2054#else
2055 if ((size_t)idx <= STRLEN(str))
2056 rettv->vval.v_number = idx;
2057#endif
2058}
2059
2060/*
2061 * "byteidx()" function
2062 */
2063 static void
2064f_byteidx(typval_T *argvars, typval_T *rettv)
2065{
2066 byteidx(argvars, rettv, FALSE);
2067}
2068
2069/*
2070 * "byteidxcomp()" function
2071 */
2072 static void
2073f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2074{
2075 byteidx(argvars, rettv, TRUE);
2076}
2077
2078/*
2079 * "call(func, arglist [, dict])" function
2080 */
2081 static void
2082f_call(typval_T *argvars, typval_T *rettv)
2083{
2084 char_u *func;
2085 partial_T *partial = NULL;
2086 dict_T *selfdict = NULL;
2087
2088 if (argvars[1].v_type != VAR_LIST)
2089 {
2090 EMSG(_(e_listreq));
2091 return;
2092 }
2093 if (argvars[1].vval.v_list == NULL)
2094 return;
2095
2096 if (argvars[0].v_type == VAR_FUNC)
2097 func = argvars[0].vval.v_string;
2098 else if (argvars[0].v_type == VAR_PARTIAL)
2099 {
2100 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002101 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002102 }
2103 else
2104 func = get_tv_string(&argvars[0]);
2105 if (*func == NUL)
2106 return; /* type error or empty name */
2107
2108 if (argvars[2].v_type != VAR_UNKNOWN)
2109 {
2110 if (argvars[2].v_type != VAR_DICT)
2111 {
2112 EMSG(_(e_dictreq));
2113 return;
2114 }
2115 selfdict = argvars[2].vval.v_dict;
2116 }
2117
2118 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2119}
2120
2121#ifdef FEAT_FLOAT
2122/*
2123 * "ceil({float})" function
2124 */
2125 static void
2126f_ceil(typval_T *argvars, typval_T *rettv)
2127{
2128 float_T f = 0.0;
2129
2130 rettv->v_type = VAR_FLOAT;
2131 if (get_float_arg(argvars, &f) == OK)
2132 rettv->vval.v_float = ceil(f);
2133 else
2134 rettv->vval.v_float = 0.0;
2135}
2136#endif
2137
2138#ifdef FEAT_JOB_CHANNEL
2139/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002140 * "ch_canread()" function
2141 */
2142 static void
2143f_ch_canread(typval_T *argvars, typval_T *rettv)
2144{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002145 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002146
2147 rettv->vval.v_number = 0;
2148 if (channel != NULL)
2149 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2150 || channel_has_readahead(channel, PART_OUT)
2151 || channel_has_readahead(channel, PART_ERR);
2152}
2153
2154/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002155 * "ch_close()" function
2156 */
2157 static void
2158f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2159{
2160 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2161
2162 if (channel != NULL)
2163 {
2164 channel_close(channel, FALSE);
2165 channel_clear(channel);
2166 }
2167}
2168
2169/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002170 * "ch_close()" function
2171 */
2172 static void
2173f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2174{
2175 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2176
2177 if (channel != NULL)
2178 channel_close_in(channel);
2179}
2180
2181/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182 * "ch_getbufnr()" function
2183 */
2184 static void
2185f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2186{
2187 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2188
2189 rettv->vval.v_number = -1;
2190 if (channel != NULL)
2191 {
2192 char_u *what = get_tv_string(&argvars[1]);
2193 int part;
2194
2195 if (STRCMP(what, "err") == 0)
2196 part = PART_ERR;
2197 else if (STRCMP(what, "out") == 0)
2198 part = PART_OUT;
2199 else if (STRCMP(what, "in") == 0)
2200 part = PART_IN;
2201 else
2202 part = PART_SOCK;
2203 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2204 rettv->vval.v_number =
2205 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2206 }
2207}
2208
2209/*
2210 * "ch_getjob()" function
2211 */
2212 static void
2213f_ch_getjob(typval_T *argvars, typval_T *rettv)
2214{
2215 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2216
2217 if (channel != NULL)
2218 {
2219 rettv->v_type = VAR_JOB;
2220 rettv->vval.v_job = channel->ch_job;
2221 if (channel->ch_job != NULL)
2222 ++channel->ch_job->jv_refcount;
2223 }
2224}
2225
2226/*
2227 * "ch_info()" function
2228 */
2229 static void
2230f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2231{
2232 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2233
2234 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2235 channel_info(channel, rettv->vval.v_dict);
2236}
2237
2238/*
2239 * "ch_log()" function
2240 */
2241 static void
2242f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2243{
2244 char_u *msg = get_tv_string(&argvars[0]);
2245 channel_T *channel = NULL;
2246
2247 if (argvars[1].v_type != VAR_UNKNOWN)
2248 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2249
Bram Moolenaard5359b22018-04-05 22:44:39 +02002250 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002251}
2252
2253/*
2254 * "ch_logfile()" function
2255 */
2256 static void
2257f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2258{
2259 char_u *fname;
2260 char_u *opt = (char_u *)"";
2261 char_u buf[NUMBUFLEN];
2262
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002263 /* Don't open a file in restricted mode. */
2264 if (check_restricted() || check_secure())
2265 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 fname = get_tv_string(&argvars[0]);
2267 if (argvars[1].v_type == VAR_STRING)
2268 opt = get_tv_string_buf(&argvars[1], buf);
2269 ch_logfile(fname, opt);
2270}
2271
2272/*
2273 * "ch_open()" function
2274 */
2275 static void
2276f_ch_open(typval_T *argvars, typval_T *rettv)
2277{
2278 rettv->v_type = VAR_CHANNEL;
2279 if (check_restricted() || check_secure())
2280 return;
2281 rettv->vval.v_channel = channel_open_func(argvars);
2282}
2283
2284/*
2285 * "ch_read()" function
2286 */
2287 static void
2288f_ch_read(typval_T *argvars, typval_T *rettv)
2289{
2290 common_channel_read(argvars, rettv, FALSE);
2291}
2292
2293/*
2294 * "ch_readraw()" function
2295 */
2296 static void
2297f_ch_readraw(typval_T *argvars, typval_T *rettv)
2298{
2299 common_channel_read(argvars, rettv, TRUE);
2300}
2301
2302/*
2303 * "ch_evalexpr()" function
2304 */
2305 static void
2306f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2307{
2308 ch_expr_common(argvars, rettv, TRUE);
2309}
2310
2311/*
2312 * "ch_sendexpr()" function
2313 */
2314 static void
2315f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2316{
2317 ch_expr_common(argvars, rettv, FALSE);
2318}
2319
2320/*
2321 * "ch_evalraw()" function
2322 */
2323 static void
2324f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2325{
2326 ch_raw_common(argvars, rettv, TRUE);
2327}
2328
2329/*
2330 * "ch_sendraw()" function
2331 */
2332 static void
2333f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2334{
2335 ch_raw_common(argvars, rettv, FALSE);
2336}
2337
2338/*
2339 * "ch_setoptions()" function
2340 */
2341 static void
2342f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2343{
2344 channel_T *channel;
2345 jobopt_T opt;
2346
2347 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2348 if (channel == NULL)
2349 return;
2350 clear_job_options(&opt);
2351 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002352 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353 channel_set_options(channel, &opt);
2354 free_job_options(&opt);
2355}
2356
2357/*
2358 * "ch_status()" function
2359 */
2360 static void
2361f_ch_status(typval_T *argvars, typval_T *rettv)
2362{
2363 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002364 jobopt_T opt;
2365 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002366
2367 /* return an empty string by default */
2368 rettv->v_type = VAR_STRING;
2369 rettv->vval.v_string = NULL;
2370
2371 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002372
2373 if (argvars[1].v_type != VAR_UNKNOWN)
2374 {
2375 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002376 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002377 && (opt.jo_set & JO_PART))
2378 part = opt.jo_part;
2379 }
2380
2381 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002382}
2383#endif
2384
2385/*
2386 * "changenr()" function
2387 */
2388 static void
2389f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2390{
2391 rettv->vval.v_number = curbuf->b_u_seq_cur;
2392}
2393
2394/*
2395 * "char2nr(string)" function
2396 */
2397 static void
2398f_char2nr(typval_T *argvars, typval_T *rettv)
2399{
2400#ifdef FEAT_MBYTE
2401 if (has_mbyte)
2402 {
2403 int utf8 = 0;
2404
2405 if (argvars[1].v_type != VAR_UNKNOWN)
2406 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2407
2408 if (utf8)
2409 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2410 else
2411 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2412 }
2413 else
2414#endif
2415 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2416}
2417
2418/*
2419 * "cindent(lnum)" function
2420 */
2421 static void
2422f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2423{
2424#ifdef FEAT_CINDENT
2425 pos_T pos;
2426 linenr_T lnum;
2427
2428 pos = curwin->w_cursor;
2429 lnum = get_tv_lnum(argvars);
2430 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2431 {
2432 curwin->w_cursor.lnum = lnum;
2433 rettv->vval.v_number = get_c_indent();
2434 curwin->w_cursor = pos;
2435 }
2436 else
2437#endif
2438 rettv->vval.v_number = -1;
2439}
2440
2441/*
2442 * "clearmatches()" function
2443 */
2444 static void
2445f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2446{
2447#ifdef FEAT_SEARCH_EXTRA
2448 clear_matches(curwin);
2449#endif
2450}
2451
2452/*
2453 * "col(string)" function
2454 */
2455 static void
2456f_col(typval_T *argvars, typval_T *rettv)
2457{
2458 colnr_T col = 0;
2459 pos_T *fp;
2460 int fnum = curbuf->b_fnum;
2461
2462 fp = var2fpos(&argvars[0], FALSE, &fnum);
2463 if (fp != NULL && fnum == curbuf->b_fnum)
2464 {
2465 if (fp->col == MAXCOL)
2466 {
2467 /* '> can be MAXCOL, get the length of the line then */
2468 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2469 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2470 else
2471 col = MAXCOL;
2472 }
2473 else
2474 {
2475 col = fp->col + 1;
2476#ifdef FEAT_VIRTUALEDIT
2477 /* col(".") when the cursor is on the NUL at the end of the line
2478 * because of "coladd" can be seen as an extra column. */
2479 if (virtual_active() && fp == &curwin->w_cursor)
2480 {
2481 char_u *p = ml_get_cursor();
2482
2483 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2484 curwin->w_virtcol - curwin->w_cursor.coladd))
2485 {
2486# ifdef FEAT_MBYTE
2487 int l;
2488
2489 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2490 col += l;
2491# else
2492 if (*p != NUL && p[1] == NUL)
2493 ++col;
2494# endif
2495 }
2496 }
2497#endif
2498 }
2499 }
2500 rettv->vval.v_number = col;
2501}
2502
2503#if defined(FEAT_INS_EXPAND)
2504/*
2505 * "complete()" function
2506 */
2507 static void
2508f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2509{
2510 int startcol;
2511
2512 if ((State & INSERT) == 0)
2513 {
2514 EMSG(_("E785: complete() can only be used in Insert mode"));
2515 return;
2516 }
2517
2518 /* Check for undo allowed here, because if something was already inserted
2519 * the line was already saved for undo and this check isn't done. */
2520 if (!undo_allowed())
2521 return;
2522
2523 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2524 {
2525 EMSG(_(e_invarg));
2526 return;
2527 }
2528
2529 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2530 if (startcol <= 0)
2531 return;
2532
2533 set_completion(startcol - 1, argvars[1].vval.v_list);
2534}
2535
2536/*
2537 * "complete_add()" function
2538 */
2539 static void
2540f_complete_add(typval_T *argvars, typval_T *rettv)
2541{
2542 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2543}
2544
2545/*
2546 * "complete_check()" function
2547 */
2548 static void
2549f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2550{
2551 int saved = RedrawingDisabled;
2552
2553 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002554 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002555 rettv->vval.v_number = compl_interrupted;
2556 RedrawingDisabled = saved;
2557}
2558#endif
2559
2560/*
2561 * "confirm(message, buttons[, default [, type]])" function
2562 */
2563 static void
2564f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2565{
2566#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2567 char_u *message;
2568 char_u *buttons = NULL;
2569 char_u buf[NUMBUFLEN];
2570 char_u buf2[NUMBUFLEN];
2571 int def = 1;
2572 int type = VIM_GENERIC;
2573 char_u *typestr;
2574 int error = FALSE;
2575
2576 message = get_tv_string_chk(&argvars[0]);
2577 if (message == NULL)
2578 error = TRUE;
2579 if (argvars[1].v_type != VAR_UNKNOWN)
2580 {
2581 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2582 if (buttons == NULL)
2583 error = TRUE;
2584 if (argvars[2].v_type != VAR_UNKNOWN)
2585 {
2586 def = (int)get_tv_number_chk(&argvars[2], &error);
2587 if (argvars[3].v_type != VAR_UNKNOWN)
2588 {
2589 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2590 if (typestr == NULL)
2591 error = TRUE;
2592 else
2593 {
2594 switch (TOUPPER_ASC(*typestr))
2595 {
2596 case 'E': type = VIM_ERROR; break;
2597 case 'Q': type = VIM_QUESTION; break;
2598 case 'I': type = VIM_INFO; break;
2599 case 'W': type = VIM_WARNING; break;
2600 case 'G': type = VIM_GENERIC; break;
2601 }
2602 }
2603 }
2604 }
2605 }
2606
2607 if (buttons == NULL || *buttons == NUL)
2608 buttons = (char_u *)_("&Ok");
2609
2610 if (!error)
2611 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2612 def, NULL, FALSE);
2613#endif
2614}
2615
2616/*
2617 * "copy()" function
2618 */
2619 static void
2620f_copy(typval_T *argvars, typval_T *rettv)
2621{
2622 item_copy(&argvars[0], rettv, FALSE, 0);
2623}
2624
2625#ifdef FEAT_FLOAT
2626/*
2627 * "cos()" function
2628 */
2629 static void
2630f_cos(typval_T *argvars, typval_T *rettv)
2631{
2632 float_T f = 0.0;
2633
2634 rettv->v_type = VAR_FLOAT;
2635 if (get_float_arg(argvars, &f) == OK)
2636 rettv->vval.v_float = cos(f);
2637 else
2638 rettv->vval.v_float = 0.0;
2639}
2640
2641/*
2642 * "cosh()" function
2643 */
2644 static void
2645f_cosh(typval_T *argvars, typval_T *rettv)
2646{
2647 float_T f = 0.0;
2648
2649 rettv->v_type = VAR_FLOAT;
2650 if (get_float_arg(argvars, &f) == OK)
2651 rettv->vval.v_float = cosh(f);
2652 else
2653 rettv->vval.v_float = 0.0;
2654}
2655#endif
2656
2657/*
2658 * "count()" function
2659 */
2660 static void
2661f_count(typval_T *argvars, typval_T *rettv)
2662{
2663 long n = 0;
2664 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002665 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666
Bram Moolenaar9966b212017-07-28 16:46:57 +02002667 if (argvars[2].v_type != VAR_UNKNOWN)
2668 ic = (int)get_tv_number_chk(&argvars[2], &error);
2669
2670 if (argvars[0].v_type == VAR_STRING)
2671 {
2672 char_u *expr = get_tv_string_chk(&argvars[1]);
2673 char_u *p = argvars[0].vval.v_string;
2674 char_u *next;
2675
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002676 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002677 {
2678 if (ic)
2679 {
2680 size_t len = STRLEN(expr);
2681
2682 while (*p != NUL)
2683 {
2684 if (MB_STRNICMP(p, expr, len) == 0)
2685 {
2686 ++n;
2687 p += len;
2688 }
2689 else
2690 MB_PTR_ADV(p);
2691 }
2692 }
2693 else
2694 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2695 != NULL)
2696 {
2697 ++n;
2698 p = next + STRLEN(expr);
2699 }
2700 }
2701
2702 }
2703 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 {
2705 listitem_T *li;
2706 list_T *l;
2707 long idx;
2708
2709 if ((l = argvars[0].vval.v_list) != NULL)
2710 {
2711 li = l->lv_first;
2712 if (argvars[2].v_type != VAR_UNKNOWN)
2713 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002714 if (argvars[3].v_type != VAR_UNKNOWN)
2715 {
2716 idx = (long)get_tv_number_chk(&argvars[3], &error);
2717 if (!error)
2718 {
2719 li = list_find(l, idx);
2720 if (li == NULL)
2721 EMSGN(_(e_listidx), idx);
2722 }
2723 }
2724 if (error)
2725 li = NULL;
2726 }
2727
2728 for ( ; li != NULL; li = li->li_next)
2729 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2730 ++n;
2731 }
2732 }
2733 else if (argvars[0].v_type == VAR_DICT)
2734 {
2735 int todo;
2736 dict_T *d;
2737 hashitem_T *hi;
2738
2739 if ((d = argvars[0].vval.v_dict) != NULL)
2740 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002741 if (argvars[2].v_type != VAR_UNKNOWN)
2742 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002743 if (argvars[3].v_type != VAR_UNKNOWN)
2744 EMSG(_(e_invarg));
2745 }
2746
2747 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2748 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2749 {
2750 if (!HASHITEM_EMPTY(hi))
2751 {
2752 --todo;
2753 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2754 ++n;
2755 }
2756 }
2757 }
2758 }
2759 else
2760 EMSG2(_(e_listdictarg), "count()");
2761 rettv->vval.v_number = n;
2762}
2763
2764/*
2765 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2766 *
2767 * Checks the existence of a cscope connection.
2768 */
2769 static void
2770f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2771{
2772#ifdef FEAT_CSCOPE
2773 int num = 0;
2774 char_u *dbpath = NULL;
2775 char_u *prepend = NULL;
2776 char_u buf[NUMBUFLEN];
2777
2778 if (argvars[0].v_type != VAR_UNKNOWN
2779 && argvars[1].v_type != VAR_UNKNOWN)
2780 {
2781 num = (int)get_tv_number(&argvars[0]);
2782 dbpath = get_tv_string(&argvars[1]);
2783 if (argvars[2].v_type != VAR_UNKNOWN)
2784 prepend = get_tv_string_buf(&argvars[2], buf);
2785 }
2786
2787 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2788#endif
2789}
2790
2791/*
2792 * "cursor(lnum, col)" function, or
2793 * "cursor(list)"
2794 *
2795 * Moves the cursor to the specified line and column.
2796 * Returns 0 when the position could be set, -1 otherwise.
2797 */
2798 static void
2799f_cursor(typval_T *argvars, typval_T *rettv)
2800{
2801 long line, col;
2802#ifdef FEAT_VIRTUALEDIT
2803 long coladd = 0;
2804#endif
2805 int set_curswant = TRUE;
2806
2807 rettv->vval.v_number = -1;
2808 if (argvars[1].v_type == VAR_UNKNOWN)
2809 {
2810 pos_T pos;
2811 colnr_T curswant = -1;
2812
2813 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2814 {
2815 EMSG(_(e_invarg));
2816 return;
2817 }
2818 line = pos.lnum;
2819 col = pos.col;
2820#ifdef FEAT_VIRTUALEDIT
2821 coladd = pos.coladd;
2822#endif
2823 if (curswant >= 0)
2824 {
2825 curwin->w_curswant = curswant - 1;
2826 set_curswant = FALSE;
2827 }
2828 }
2829 else
2830 {
2831 line = get_tv_lnum(argvars);
2832 col = (long)get_tv_number_chk(&argvars[1], NULL);
2833#ifdef FEAT_VIRTUALEDIT
2834 if (argvars[2].v_type != VAR_UNKNOWN)
2835 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2836#endif
2837 }
2838 if (line < 0 || col < 0
2839#ifdef FEAT_VIRTUALEDIT
2840 || coladd < 0
2841#endif
2842 )
2843 return; /* type error; errmsg already given */
2844 if (line > 0)
2845 curwin->w_cursor.lnum = line;
2846 if (col > 0)
2847 curwin->w_cursor.col = col - 1;
2848#ifdef FEAT_VIRTUALEDIT
2849 curwin->w_cursor.coladd = coladd;
2850#endif
2851
2852 /* Make sure the cursor is in a valid position. */
2853 check_cursor();
2854#ifdef FEAT_MBYTE
2855 /* Correct cursor for multi-byte character. */
2856 if (has_mbyte)
2857 mb_adjust_cursor();
2858#endif
2859
2860 curwin->w_set_curswant = set_curswant;
2861 rettv->vval.v_number = 0;
2862}
2863
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002864#ifdef WIN3264
2865/*
2866 * "debugbreak()" function
2867 */
2868 static void
2869f_debugbreak(typval_T *argvars, typval_T *rettv)
2870{
2871 int pid;
2872
2873 rettv->vval.v_number = FAIL;
2874 pid = (int)get_tv_number(&argvars[0]);
2875 if (pid == 0)
2876 EMSG(_(e_invarg));
2877 else
2878 {
2879 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2880
2881 if (hProcess != NULL)
2882 {
2883 DebugBreakProcess(hProcess);
2884 CloseHandle(hProcess);
2885 rettv->vval.v_number = OK;
2886 }
2887 }
2888}
2889#endif
2890
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002891/*
2892 * "deepcopy()" function
2893 */
2894 static void
2895f_deepcopy(typval_T *argvars, typval_T *rettv)
2896{
2897 int noref = 0;
2898 int copyID;
2899
2900 if (argvars[1].v_type != VAR_UNKNOWN)
2901 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2902 if (noref < 0 || noref > 1)
2903 EMSG(_(e_invarg));
2904 else
2905 {
2906 copyID = get_copyID();
2907 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2908 }
2909}
2910
2911/*
2912 * "delete()" function
2913 */
2914 static void
2915f_delete(typval_T *argvars, typval_T *rettv)
2916{
2917 char_u nbuf[NUMBUFLEN];
2918 char_u *name;
2919 char_u *flags;
2920
2921 rettv->vval.v_number = -1;
2922 if (check_restricted() || check_secure())
2923 return;
2924
2925 name = get_tv_string(&argvars[0]);
2926 if (name == NULL || *name == NUL)
2927 {
2928 EMSG(_(e_invarg));
2929 return;
2930 }
2931
2932 if (argvars[1].v_type != VAR_UNKNOWN)
2933 flags = get_tv_string_buf(&argvars[1], nbuf);
2934 else
2935 flags = (char_u *)"";
2936
2937 if (*flags == NUL)
2938 /* delete a file */
2939 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2940 else if (STRCMP(flags, "d") == 0)
2941 /* delete an empty directory */
2942 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2943 else if (STRCMP(flags, "rf") == 0)
2944 /* delete a directory recursively */
2945 rettv->vval.v_number = delete_recursive(name);
2946 else
2947 EMSG2(_(e_invexpr2), flags);
2948}
2949
2950/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002951 * "deletebufline()" function
2952 */
2953 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002954f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002955{
2956 buf_T *buf;
2957 linenr_T first, last;
2958 linenr_T lnum;
2959 long count;
2960 int is_curbuf;
2961 buf_T *curbuf_save = NULL;
2962 win_T *curwin_save = NULL;
2963 tabpage_T *tp;
2964 win_T *wp;
2965
2966 buf = get_buf_tv(&argvars[0], FALSE);
2967 if (buf == NULL)
2968 {
2969 rettv->vval.v_number = 1; /* FAIL */
2970 return;
2971 }
2972 is_curbuf = buf == curbuf;
2973
2974 first = get_tv_lnum_buf(&argvars[1], buf);
2975 if (argvars[2].v_type != VAR_UNKNOWN)
2976 last = get_tv_lnum_buf(&argvars[2], buf);
2977 else
2978 last = first;
2979
2980 if (buf->b_ml.ml_mfp == NULL || first < 1
2981 || first > buf->b_ml.ml_line_count || last < first)
2982 {
2983 rettv->vval.v_number = 1; /* FAIL */
2984 return;
2985 }
2986
2987 if (!is_curbuf)
2988 {
2989 curbuf_save = curbuf;
2990 curwin_save = curwin;
2991 curbuf = buf;
2992 find_win_for_curbuf();
2993 }
2994 if (last > curbuf->b_ml.ml_line_count)
2995 last = curbuf->b_ml.ml_line_count;
2996 count = last - first + 1;
2997
2998 // When coming here from Insert mode, sync undo, so that this can be
2999 // undone separately from what was previously inserted.
3000 if (u_sync_once == 2)
3001 {
3002 u_sync_once = 1; // notify that u_sync() was called
3003 u_sync(TRUE);
3004 }
3005
3006 if (u_save(first - 1, last + 1) == FAIL)
3007 {
3008 rettv->vval.v_number = 1; /* FAIL */
3009 return;
3010 }
3011
3012 for (lnum = first; lnum <= last; ++lnum)
3013 ml_delete(first, TRUE);
3014
3015 FOR_ALL_TAB_WINDOWS(tp, wp)
3016 if (wp->w_buffer == buf)
3017 {
3018 if (wp->w_cursor.lnum > last)
3019 wp->w_cursor.lnum -= count;
3020 else if (wp->w_cursor.lnum> first)
3021 wp->w_cursor.lnum = first;
3022 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3023 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3024 }
3025 check_cursor_col();
3026 deleted_lines_mark(first, count);
3027
3028 if (!is_curbuf)
3029 {
3030 curbuf = curbuf_save;
3031 curwin = curwin_save;
3032 }
3033}
3034
3035/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 * "did_filetype()" function
3037 */
3038 static void
3039f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3040{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003041 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003042}
3043
3044/*
3045 * "diff_filler()" function
3046 */
3047 static void
3048f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3049{
3050#ifdef FEAT_DIFF
3051 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
3052#endif
3053}
3054
3055/*
3056 * "diff_hlID()" function
3057 */
3058 static void
3059f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3060{
3061#ifdef FEAT_DIFF
3062 linenr_T lnum = get_tv_lnum(argvars);
3063 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003064 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065 static int fnum = 0;
3066 static int change_start = 0;
3067 static int change_end = 0;
3068 static hlf_T hlID = (hlf_T)0;
3069 int filler_lines;
3070 int col;
3071
3072 if (lnum < 0) /* ignore type error in {lnum} arg */
3073 lnum = 0;
3074 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003075 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 || fnum != curbuf->b_fnum)
3077 {
3078 /* New line, buffer, change: need to get the values. */
3079 filler_lines = diff_check(curwin, lnum);
3080 if (filler_lines < 0)
3081 {
3082 if (filler_lines == -1)
3083 {
3084 change_start = MAXCOL;
3085 change_end = -1;
3086 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3087 hlID = HLF_ADD; /* added line */
3088 else
3089 hlID = HLF_CHD; /* changed line */
3090 }
3091 else
3092 hlID = HLF_ADD; /* added line */
3093 }
3094 else
3095 hlID = (hlf_T)0;
3096 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003097 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098 fnum = curbuf->b_fnum;
3099 }
3100
3101 if (hlID == HLF_CHD || hlID == HLF_TXD)
3102 {
3103 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
3104 if (col >= change_start && col <= change_end)
3105 hlID = HLF_TXD; /* changed text */
3106 else
3107 hlID = HLF_CHD; /* changed line */
3108 }
3109 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3110#endif
3111}
3112
3113/*
3114 * "empty({expr})" function
3115 */
3116 static void
3117f_empty(typval_T *argvars, typval_T *rettv)
3118{
3119 int n = FALSE;
3120
3121 switch (argvars[0].v_type)
3122 {
3123 case VAR_STRING:
3124 case VAR_FUNC:
3125 n = argvars[0].vval.v_string == NULL
3126 || *argvars[0].vval.v_string == NUL;
3127 break;
3128 case VAR_PARTIAL:
3129 n = FALSE;
3130 break;
3131 case VAR_NUMBER:
3132 n = argvars[0].vval.v_number == 0;
3133 break;
3134 case VAR_FLOAT:
3135#ifdef FEAT_FLOAT
3136 n = argvars[0].vval.v_float == 0.0;
3137 break;
3138#endif
3139 case VAR_LIST:
3140 n = argvars[0].vval.v_list == NULL
3141 || argvars[0].vval.v_list->lv_first == NULL;
3142 break;
3143 case VAR_DICT:
3144 n = argvars[0].vval.v_dict == NULL
3145 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3146 break;
3147 case VAR_SPECIAL:
3148 n = argvars[0].vval.v_number != VVAL_TRUE;
3149 break;
3150
3151 case VAR_JOB:
3152#ifdef FEAT_JOB_CHANNEL
3153 n = argvars[0].vval.v_job == NULL
3154 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3155 break;
3156#endif
3157 case VAR_CHANNEL:
3158#ifdef FEAT_JOB_CHANNEL
3159 n = argvars[0].vval.v_channel == NULL
3160 || !channel_is_open(argvars[0].vval.v_channel);
3161 break;
3162#endif
3163 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003164 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003165 n = TRUE;
3166 break;
3167 }
3168
3169 rettv->vval.v_number = n;
3170}
3171
3172/*
3173 * "escape({string}, {chars})" function
3174 */
3175 static void
3176f_escape(typval_T *argvars, typval_T *rettv)
3177{
3178 char_u buf[NUMBUFLEN];
3179
3180 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
3181 get_tv_string_buf(&argvars[1], buf));
3182 rettv->v_type = VAR_STRING;
3183}
3184
3185/*
3186 * "eval()" function
3187 */
3188 static void
3189f_eval(typval_T *argvars, typval_T *rettv)
3190{
3191 char_u *s, *p;
3192
3193 s = get_tv_string_chk(&argvars[0]);
3194 if (s != NULL)
3195 s = skipwhite(s);
3196
3197 p = s;
3198 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3199 {
3200 if (p != NULL && !aborting())
3201 EMSG2(_(e_invexpr2), p);
3202 need_clr_eos = FALSE;
3203 rettv->v_type = VAR_NUMBER;
3204 rettv->vval.v_number = 0;
3205 }
3206 else if (*s != NUL)
3207 EMSG(_(e_trailing));
3208}
3209
3210/*
3211 * "eventhandler()" function
3212 */
3213 static void
3214f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3215{
3216 rettv->vval.v_number = vgetc_busy;
3217}
3218
3219/*
3220 * "executable()" function
3221 */
3222 static void
3223f_executable(typval_T *argvars, typval_T *rettv)
3224{
3225 char_u *name = get_tv_string(&argvars[0]);
3226
3227 /* Check in $PATH and also check directly if there is a directory name. */
3228 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3229 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3230}
3231
3232static garray_T redir_execute_ga;
3233
3234/*
3235 * Append "value[value_len]" to the execute() output.
3236 */
3237 void
3238execute_redir_str(char_u *value, int value_len)
3239{
3240 int len;
3241
3242 if (value_len == -1)
3243 len = (int)STRLEN(value); /* Append the entire string */
3244 else
3245 len = value_len; /* Append only "value_len" characters */
3246 if (ga_grow(&redir_execute_ga, len) == OK)
3247 {
3248 mch_memmove((char *)redir_execute_ga.ga_data
3249 + redir_execute_ga.ga_len, value, len);
3250 redir_execute_ga.ga_len += len;
3251 }
3252}
3253
3254/*
3255 * Get next line from a list.
3256 * Called by do_cmdline() to get the next line.
3257 * Returns allocated string, or NULL for end of function.
3258 */
3259
3260 static char_u *
3261get_list_line(
3262 int c UNUSED,
3263 void *cookie,
3264 int indent UNUSED)
3265{
3266 listitem_T **p = (listitem_T **)cookie;
3267 listitem_T *item = *p;
3268 char_u buf[NUMBUFLEN];
3269 char_u *s;
3270
3271 if (item == NULL)
3272 return NULL;
3273 s = get_tv_string_buf_chk(&item->li_tv, buf);
3274 *p = item->li_next;
3275 return s == NULL ? NULL : vim_strsave(s);
3276}
3277
3278/*
3279 * "execute()" function
3280 */
3281 static void
3282f_execute(typval_T *argvars, typval_T *rettv)
3283{
3284 char_u *cmd = NULL;
3285 list_T *list = NULL;
3286 int save_msg_silent = msg_silent;
3287 int save_emsg_silent = emsg_silent;
3288 int save_emsg_noredir = emsg_noredir;
3289 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003290 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003291 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003292 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003293 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003294
3295 rettv->vval.v_string = NULL;
3296 rettv->v_type = VAR_STRING;
3297
3298 if (argvars[0].v_type == VAR_LIST)
3299 {
3300 list = argvars[0].vval.v_list;
3301 if (list == NULL || list->lv_first == NULL)
3302 /* empty list, no commands, empty output */
3303 return;
3304 ++list->lv_refcount;
3305 }
3306 else
3307 {
3308 cmd = get_tv_string_chk(&argvars[0]);
3309 if (cmd == NULL)
3310 return;
3311 }
3312
3313 if (argvars[1].v_type != VAR_UNKNOWN)
3314 {
3315 char_u buf[NUMBUFLEN];
3316 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
3317
3318 if (s == NULL)
3319 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003320 if (*s == NUL)
3321 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003322 if (STRNCMP(s, "silent", 6) == 0)
3323 ++msg_silent;
3324 if (STRCMP(s, "silent!") == 0)
3325 {
3326 emsg_silent = TRUE;
3327 emsg_noredir = TRUE;
3328 }
3329 }
3330 else
3331 ++msg_silent;
3332
3333 if (redir_execute)
3334 save_ga = redir_execute_ga;
3335 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3336 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003337 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003338 if (!echo_output)
3339 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003340
3341 if (cmd != NULL)
3342 do_cmdline_cmd(cmd);
3343 else
3344 {
3345 listitem_T *item = list->lv_first;
3346
3347 do_cmdline(NULL, get_list_line, (void *)&item,
3348 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3349 --list->lv_refcount;
3350 }
3351
Bram Moolenaard297f352017-01-29 20:31:21 +01003352 /* Need to append a NUL to the result. */
3353 if (ga_grow(&redir_execute_ga, 1) == OK)
3354 {
3355 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3356 rettv->vval.v_string = redir_execute_ga.ga_data;
3357 }
3358 else
3359 {
3360 ga_clear(&redir_execute_ga);
3361 rettv->vval.v_string = NULL;
3362 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003363 msg_silent = save_msg_silent;
3364 emsg_silent = save_emsg_silent;
3365 emsg_noredir = save_emsg_noredir;
3366
3367 redir_execute = save_redir_execute;
3368 if (redir_execute)
3369 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003370 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003371
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003372 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003373 if (echo_output)
3374 // When not working silently: put it in column zero. A following
3375 // "echon" will overwrite the message, unavoidably.
3376 msg_col = 0;
3377 else
3378 // When working silently: Put it back where it was, since nothing
3379 // should have been written.
3380 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003381}
3382
3383/*
3384 * "exepath()" function
3385 */
3386 static void
3387f_exepath(typval_T *argvars, typval_T *rettv)
3388{
3389 char_u *p = NULL;
3390
3391 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3392 rettv->v_type = VAR_STRING;
3393 rettv->vval.v_string = p;
3394}
3395
3396/*
3397 * "exists()" function
3398 */
3399 static void
3400f_exists(typval_T *argvars, typval_T *rettv)
3401{
3402 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003404
3405 p = get_tv_string(&argvars[0]);
3406 if (*p == '$') /* environment variable */
3407 {
3408 /* first try "normal" environment variables (fast) */
3409 if (mch_getenv(p + 1) != NULL)
3410 n = TRUE;
3411 else
3412 {
3413 /* try expanding things like $VIM and ${HOME} */
3414 p = expand_env_save(p);
3415 if (p != NULL && *p != '$')
3416 n = TRUE;
3417 vim_free(p);
3418 }
3419 }
3420 else if (*p == '&' || *p == '+') /* option */
3421 {
3422 n = (get_option_tv(&p, NULL, TRUE) == OK);
3423 if (*skipwhite(p) != NUL)
3424 n = FALSE; /* trailing garbage */
3425 }
3426 else if (*p == '*') /* internal or user defined function */
3427 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003428 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003429 }
3430 else if (*p == ':')
3431 {
3432 n = cmd_exists(p + 1);
3433 }
3434 else if (*p == '#')
3435 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436 if (p[1] == '#')
3437 n = autocmd_supported(p + 2);
3438 else
3439 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003440 }
3441 else /* internal variable */
3442 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003443 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003444 }
3445
3446 rettv->vval.v_number = n;
3447}
3448
3449#ifdef FEAT_FLOAT
3450/*
3451 * "exp()" function
3452 */
3453 static void
3454f_exp(typval_T *argvars, typval_T *rettv)
3455{
3456 float_T f = 0.0;
3457
3458 rettv->v_type = VAR_FLOAT;
3459 if (get_float_arg(argvars, &f) == OK)
3460 rettv->vval.v_float = exp(f);
3461 else
3462 rettv->vval.v_float = 0.0;
3463}
3464#endif
3465
3466/*
3467 * "expand()" function
3468 */
3469 static void
3470f_expand(typval_T *argvars, typval_T *rettv)
3471{
3472 char_u *s;
3473 int len;
3474 char_u *errormsg;
3475 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3476 expand_T xpc;
3477 int error = FALSE;
3478 char_u *result;
3479
3480 rettv->v_type = VAR_STRING;
3481 if (argvars[1].v_type != VAR_UNKNOWN
3482 && argvars[2].v_type != VAR_UNKNOWN
3483 && get_tv_number_chk(&argvars[2], &error)
3484 && !error)
3485 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003486 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003487 }
3488
3489 s = get_tv_string(&argvars[0]);
3490 if (*s == '%' || *s == '#' || *s == '<')
3491 {
3492 ++emsg_off;
3493 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3494 --emsg_off;
3495 if (rettv->v_type == VAR_LIST)
3496 {
3497 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3498 list_append_string(rettv->vval.v_list, result, -1);
3499 else
3500 vim_free(result);
3501 }
3502 else
3503 rettv->vval.v_string = result;
3504 }
3505 else
3506 {
3507 /* When the optional second argument is non-zero, don't remove matches
3508 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3509 if (argvars[1].v_type != VAR_UNKNOWN
3510 && get_tv_number_chk(&argvars[1], &error))
3511 options |= WILD_KEEP_ALL;
3512 if (!error)
3513 {
3514 ExpandInit(&xpc);
3515 xpc.xp_context = EXPAND_FILES;
3516 if (p_wic)
3517 options += WILD_ICASE;
3518 if (rettv->v_type == VAR_STRING)
3519 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3520 options, WILD_ALL);
3521 else if (rettv_list_alloc(rettv) != FAIL)
3522 {
3523 int i;
3524
3525 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3526 for (i = 0; i < xpc.xp_numfiles; i++)
3527 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3528 ExpandCleanup(&xpc);
3529 }
3530 }
3531 else
3532 rettv->vval.v_string = NULL;
3533 }
3534}
3535
3536/*
3537 * "extend(list, list [, idx])" function
3538 * "extend(dict, dict [, action])" function
3539 */
3540 static void
3541f_extend(typval_T *argvars, typval_T *rettv)
3542{
3543 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3544
3545 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3546 {
3547 list_T *l1, *l2;
3548 listitem_T *item;
3549 long before;
3550 int error = FALSE;
3551
3552 l1 = argvars[0].vval.v_list;
3553 l2 = argvars[1].vval.v_list;
3554 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3555 && l2 != NULL)
3556 {
3557 if (argvars[2].v_type != VAR_UNKNOWN)
3558 {
3559 before = (long)get_tv_number_chk(&argvars[2], &error);
3560 if (error)
3561 return; /* type error; errmsg already given */
3562
3563 if (before == l1->lv_len)
3564 item = NULL;
3565 else
3566 {
3567 item = list_find(l1, before);
3568 if (item == NULL)
3569 {
3570 EMSGN(_(e_listidx), before);
3571 return;
3572 }
3573 }
3574 }
3575 else
3576 item = NULL;
3577 list_extend(l1, l2, item);
3578
3579 copy_tv(&argvars[0], rettv);
3580 }
3581 }
3582 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3583 {
3584 dict_T *d1, *d2;
3585 char_u *action;
3586 int i;
3587
3588 d1 = argvars[0].vval.v_dict;
3589 d2 = argvars[1].vval.v_dict;
3590 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3591 && d2 != NULL)
3592 {
3593 /* Check the third argument. */
3594 if (argvars[2].v_type != VAR_UNKNOWN)
3595 {
3596 static char *(av[]) = {"keep", "force", "error"};
3597
3598 action = get_tv_string_chk(&argvars[2]);
3599 if (action == NULL)
3600 return; /* type error; errmsg already given */
3601 for (i = 0; i < 3; ++i)
3602 if (STRCMP(action, av[i]) == 0)
3603 break;
3604 if (i == 3)
3605 {
3606 EMSG2(_(e_invarg2), action);
3607 return;
3608 }
3609 }
3610 else
3611 action = (char_u *)"force";
3612
3613 dict_extend(d1, d2, action);
3614
3615 copy_tv(&argvars[0], rettv);
3616 }
3617 }
3618 else
3619 EMSG2(_(e_listdictarg), "extend()");
3620}
3621
3622/*
3623 * "feedkeys()" function
3624 */
3625 static void
3626f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3627{
3628 int remap = TRUE;
3629 int insert = FALSE;
3630 char_u *keys, *flags;
3631 char_u nbuf[NUMBUFLEN];
3632 int typed = FALSE;
3633 int execute = FALSE;
3634 int dangerous = FALSE;
3635 char_u *keys_esc;
3636
3637 /* This is not allowed in the sandbox. If the commands would still be
3638 * executed in the sandbox it would be OK, but it probably happens later,
3639 * when "sandbox" is no longer set. */
3640 if (check_secure())
3641 return;
3642
3643 keys = get_tv_string(&argvars[0]);
3644
3645 if (argvars[1].v_type != VAR_UNKNOWN)
3646 {
3647 flags = get_tv_string_buf(&argvars[1], nbuf);
3648 for ( ; *flags != NUL; ++flags)
3649 {
3650 switch (*flags)
3651 {
3652 case 'n': remap = FALSE; break;
3653 case 'm': remap = TRUE; break;
3654 case 't': typed = TRUE; break;
3655 case 'i': insert = TRUE; break;
3656 case 'x': execute = TRUE; break;
3657 case '!': dangerous = TRUE; break;
3658 }
3659 }
3660 }
3661
3662 if (*keys != NUL || execute)
3663 {
3664 /* Need to escape K_SPECIAL and CSI before putting the string in the
3665 * typeahead buffer. */
3666 keys_esc = vim_strsave_escape_csi(keys);
3667 if (keys_esc != NULL)
3668 {
3669 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3670 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3671 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003672 if (vgetc_busy
3673#ifdef FEAT_TIMERS
3674 || timer_busy
3675#endif
3676 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677 typebuf_was_filled = TRUE;
3678 if (execute)
3679 {
3680 int save_msg_scroll = msg_scroll;
3681
3682 /* Avoid a 1 second delay when the keys start Insert mode. */
3683 msg_scroll = FALSE;
3684
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003685 if (!dangerous)
3686 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003687 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003688 if (!dangerous)
3689 --ex_normal_busy;
3690
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003691 msg_scroll |= save_msg_scroll;
3692 }
3693 }
3694 }
3695}
3696
3697/*
3698 * "filereadable()" function
3699 */
3700 static void
3701f_filereadable(typval_T *argvars, typval_T *rettv)
3702{
3703 int fd;
3704 char_u *p;
3705 int n;
3706
3707#ifndef O_NONBLOCK
3708# define O_NONBLOCK 0
3709#endif
3710 p = get_tv_string(&argvars[0]);
3711 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3712 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3713 {
3714 n = TRUE;
3715 close(fd);
3716 }
3717 else
3718 n = FALSE;
3719
3720 rettv->vval.v_number = n;
3721}
3722
3723/*
3724 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3725 * rights to write into.
3726 */
3727 static void
3728f_filewritable(typval_T *argvars, typval_T *rettv)
3729{
3730 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3731}
3732
3733 static void
3734findfilendir(
3735 typval_T *argvars UNUSED,
3736 typval_T *rettv,
3737 int find_what UNUSED)
3738{
3739#ifdef FEAT_SEARCHPATH
3740 char_u *fname;
3741 char_u *fresult = NULL;
3742 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3743 char_u *p;
3744 char_u pathbuf[NUMBUFLEN];
3745 int count = 1;
3746 int first = TRUE;
3747 int error = FALSE;
3748#endif
3749
3750 rettv->vval.v_string = NULL;
3751 rettv->v_type = VAR_STRING;
3752
3753#ifdef FEAT_SEARCHPATH
3754 fname = get_tv_string(&argvars[0]);
3755
3756 if (argvars[1].v_type != VAR_UNKNOWN)
3757 {
3758 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3759 if (p == NULL)
3760 error = TRUE;
3761 else
3762 {
3763 if (*p != NUL)
3764 path = p;
3765
3766 if (argvars[2].v_type != VAR_UNKNOWN)
3767 count = (int)get_tv_number_chk(&argvars[2], &error);
3768 }
3769 }
3770
3771 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3772 error = TRUE;
3773
3774 if (*fname != NUL && !error)
3775 {
3776 do
3777 {
3778 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3779 vim_free(fresult);
3780 fresult = find_file_in_path_option(first ? fname : NULL,
3781 first ? (int)STRLEN(fname) : 0,
3782 0, first, path,
3783 find_what,
3784 curbuf->b_ffname,
3785 find_what == FINDFILE_DIR
3786 ? (char_u *)"" : curbuf->b_p_sua);
3787 first = FALSE;
3788
3789 if (fresult != NULL && rettv->v_type == VAR_LIST)
3790 list_append_string(rettv->vval.v_list, fresult, -1);
3791
3792 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3793 }
3794
3795 if (rettv->v_type == VAR_STRING)
3796 rettv->vval.v_string = fresult;
3797#endif
3798}
3799
3800/*
3801 * "filter()" function
3802 */
3803 static void
3804f_filter(typval_T *argvars, typval_T *rettv)
3805{
3806 filter_map(argvars, rettv, FALSE);
3807}
3808
3809/*
3810 * "finddir({fname}[, {path}[, {count}]])" function
3811 */
3812 static void
3813f_finddir(typval_T *argvars, typval_T *rettv)
3814{
3815 findfilendir(argvars, rettv, FINDFILE_DIR);
3816}
3817
3818/*
3819 * "findfile({fname}[, {path}[, {count}]])" function
3820 */
3821 static void
3822f_findfile(typval_T *argvars, typval_T *rettv)
3823{
3824 findfilendir(argvars, rettv, FINDFILE_FILE);
3825}
3826
3827#ifdef FEAT_FLOAT
3828/*
3829 * "float2nr({float})" function
3830 */
3831 static void
3832f_float2nr(typval_T *argvars, typval_T *rettv)
3833{
3834 float_T f = 0.0;
3835
3836 if (get_float_arg(argvars, &f) == OK)
3837 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003838 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003839 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003840 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003841 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003842 else
3843 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003844 }
3845}
3846
3847/*
3848 * "floor({float})" function
3849 */
3850 static void
3851f_floor(typval_T *argvars, typval_T *rettv)
3852{
3853 float_T f = 0.0;
3854
3855 rettv->v_type = VAR_FLOAT;
3856 if (get_float_arg(argvars, &f) == OK)
3857 rettv->vval.v_float = floor(f);
3858 else
3859 rettv->vval.v_float = 0.0;
3860}
3861
3862/*
3863 * "fmod()" function
3864 */
3865 static void
3866f_fmod(typval_T *argvars, typval_T *rettv)
3867{
3868 float_T fx = 0.0, fy = 0.0;
3869
3870 rettv->v_type = VAR_FLOAT;
3871 if (get_float_arg(argvars, &fx) == OK
3872 && get_float_arg(&argvars[1], &fy) == OK)
3873 rettv->vval.v_float = fmod(fx, fy);
3874 else
3875 rettv->vval.v_float = 0.0;
3876}
3877#endif
3878
3879/*
3880 * "fnameescape({string})" function
3881 */
3882 static void
3883f_fnameescape(typval_T *argvars, typval_T *rettv)
3884{
3885 rettv->vval.v_string = vim_strsave_fnameescape(
3886 get_tv_string(&argvars[0]), FALSE);
3887 rettv->v_type = VAR_STRING;
3888}
3889
3890/*
3891 * "fnamemodify({fname}, {mods})" function
3892 */
3893 static void
3894f_fnamemodify(typval_T *argvars, typval_T *rettv)
3895{
3896 char_u *fname;
3897 char_u *mods;
3898 int usedlen = 0;
3899 int len;
3900 char_u *fbuf = NULL;
3901 char_u buf[NUMBUFLEN];
3902
3903 fname = get_tv_string_chk(&argvars[0]);
3904 mods = get_tv_string_buf_chk(&argvars[1], buf);
3905 if (fname == NULL || mods == NULL)
3906 fname = NULL;
3907 else
3908 {
3909 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003910 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003911 }
3912
3913 rettv->v_type = VAR_STRING;
3914 if (fname == NULL)
3915 rettv->vval.v_string = NULL;
3916 else
3917 rettv->vval.v_string = vim_strnsave(fname, len);
3918 vim_free(fbuf);
3919}
3920
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921/*
3922 * "foldclosed()" function
3923 */
3924 static void
3925foldclosed_both(
3926 typval_T *argvars UNUSED,
3927 typval_T *rettv,
3928 int end UNUSED)
3929{
3930#ifdef FEAT_FOLDING
3931 linenr_T lnum;
3932 linenr_T first, last;
3933
3934 lnum = get_tv_lnum(argvars);
3935 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3936 {
3937 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3938 {
3939 if (end)
3940 rettv->vval.v_number = (varnumber_T)last;
3941 else
3942 rettv->vval.v_number = (varnumber_T)first;
3943 return;
3944 }
3945 }
3946#endif
3947 rettv->vval.v_number = -1;
3948}
3949
3950/*
3951 * "foldclosed()" function
3952 */
3953 static void
3954f_foldclosed(typval_T *argvars, typval_T *rettv)
3955{
3956 foldclosed_both(argvars, rettv, FALSE);
3957}
3958
3959/*
3960 * "foldclosedend()" function
3961 */
3962 static void
3963f_foldclosedend(typval_T *argvars, typval_T *rettv)
3964{
3965 foldclosed_both(argvars, rettv, TRUE);
3966}
3967
3968/*
3969 * "foldlevel()" function
3970 */
3971 static void
3972f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3973{
3974#ifdef FEAT_FOLDING
3975 linenr_T lnum;
3976
3977 lnum = get_tv_lnum(argvars);
3978 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3979 rettv->vval.v_number = foldLevel(lnum);
3980#endif
3981}
3982
3983/*
3984 * "foldtext()" function
3985 */
3986 static void
3987f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3988{
3989#ifdef FEAT_FOLDING
3990 linenr_T foldstart;
3991 linenr_T foldend;
3992 char_u *dashes;
3993 linenr_T lnum;
3994 char_u *s;
3995 char_u *r;
3996 int len;
3997 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003998 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003999#endif
4000
4001 rettv->v_type = VAR_STRING;
4002 rettv->vval.v_string = NULL;
4003#ifdef FEAT_FOLDING
4004 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4005 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4006 dashes = get_vim_var_str(VV_FOLDDASHES);
4007 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4008 && dashes != NULL)
4009 {
4010 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004011 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012 if (!linewhite(lnum))
4013 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004014
4015 /* Find interesting text in this line. */
4016 s = skipwhite(ml_get(lnum));
4017 /* skip C comment-start */
4018 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4019 {
4020 s = skipwhite(s + 2);
4021 if (*skipwhite(s) == NUL
4022 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4023 {
4024 s = skipwhite(ml_get(lnum + 1));
4025 if (*s == '*')
4026 s = skipwhite(s + 1);
4027 }
4028 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004029 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004030 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004031 r = alloc((unsigned)(STRLEN(txt)
4032 + STRLEN(dashes) /* for %s */
4033 + 20 /* for %3ld */
4034 + STRLEN(s))); /* concatenated */
4035 if (r != NULL)
4036 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004037 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004038 len = (int)STRLEN(r);
4039 STRCAT(r, s);
4040 /* remove 'foldmarker' and 'commentstring' */
4041 foldtext_cleanup(r + len);
4042 rettv->vval.v_string = r;
4043 }
4044 }
4045#endif
4046}
4047
4048/*
4049 * "foldtextresult(lnum)" function
4050 */
4051 static void
4052f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4053{
4054#ifdef FEAT_FOLDING
4055 linenr_T lnum;
4056 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004057 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004058 foldinfo_T foldinfo;
4059 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004060 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004061#endif
4062
4063 rettv->v_type = VAR_STRING;
4064 rettv->vval.v_string = NULL;
4065#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004066 if (entered)
4067 return; /* reject recursive use */
4068 entered = TRUE;
4069
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 lnum = get_tv_lnum(argvars);
4071 /* treat illegal types and illegal string values for {lnum} the same */
4072 if (lnum < 0)
4073 lnum = 0;
4074 fold_count = foldedCount(curwin, lnum, &foldinfo);
4075 if (fold_count > 0)
4076 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004077 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4078 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004079 if (text == buf)
4080 text = vim_strsave(text);
4081 rettv->vval.v_string = text;
4082 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004083
4084 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004085#endif
4086}
4087
4088/*
4089 * "foreground()" function
4090 */
4091 static void
4092f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4093{
4094#ifdef FEAT_GUI
4095 if (gui.in_use)
4096 gui_mch_set_foreground();
4097#else
4098# ifdef WIN32
4099 win32_set_foreground();
4100# endif
4101#endif
4102}
4103
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004104 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004105common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004106{
4107 char_u *s;
4108 char_u *name;
4109 int use_string = FALSE;
4110 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004111 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004112
4113 if (argvars[0].v_type == VAR_FUNC)
4114 {
4115 /* function(MyFunc, [arg], dict) */
4116 s = argvars[0].vval.v_string;
4117 }
4118 else if (argvars[0].v_type == VAR_PARTIAL
4119 && argvars[0].vval.v_partial != NULL)
4120 {
4121 /* function(dict.MyFunc, [arg]) */
4122 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004123 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004124 }
4125 else
4126 {
4127 /* function('MyFunc', [arg], dict) */
4128 s = get_tv_string(&argvars[0]);
4129 use_string = TRUE;
4130 }
4131
Bram Moolenaar843b8842016-08-21 14:36:15 +02004132 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004133 {
4134 name = s;
4135 trans_name = trans_function_name(&name, FALSE,
4136 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4137 if (*name != NUL)
4138 s = NULL;
4139 }
4140
Bram Moolenaar843b8842016-08-21 14:36:15 +02004141 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4142 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02004143 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004144 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004145 else if (trans_name != NULL && (is_funcref
4146 ? find_func(trans_name) == NULL
4147 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 EMSG2(_("E700: Unknown function: %s"), s);
4149 else
4150 {
4151 int dict_idx = 0;
4152 int arg_idx = 0;
4153 list_T *list = NULL;
4154
4155 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4156 {
4157 char sid_buf[25];
4158 int off = *s == 's' ? 2 : 5;
4159
4160 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4161 * also be called from another script. Using trans_function_name()
4162 * would also work, but some plugins depend on the name being
4163 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004164 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004165 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4166 if (name != NULL)
4167 {
4168 STRCPY(name, sid_buf);
4169 STRCAT(name, s + off);
4170 }
4171 }
4172 else
4173 name = vim_strsave(s);
4174
4175 if (argvars[1].v_type != VAR_UNKNOWN)
4176 {
4177 if (argvars[2].v_type != VAR_UNKNOWN)
4178 {
4179 /* function(name, [args], dict) */
4180 arg_idx = 1;
4181 dict_idx = 2;
4182 }
4183 else if (argvars[1].v_type == VAR_DICT)
4184 /* function(name, dict) */
4185 dict_idx = 1;
4186 else
4187 /* function(name, [args]) */
4188 arg_idx = 1;
4189 if (dict_idx > 0)
4190 {
4191 if (argvars[dict_idx].v_type != VAR_DICT)
4192 {
4193 EMSG(_("E922: expected a dict"));
4194 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004195 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004196 }
4197 if (argvars[dict_idx].vval.v_dict == NULL)
4198 dict_idx = 0;
4199 }
4200 if (arg_idx > 0)
4201 {
4202 if (argvars[arg_idx].v_type != VAR_LIST)
4203 {
4204 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4205 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004206 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004207 }
4208 list = argvars[arg_idx].vval.v_list;
4209 if (list == NULL || list->lv_len == 0)
4210 arg_idx = 0;
4211 }
4212 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004213 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004214 {
4215 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4216
4217 /* result is a VAR_PARTIAL */
4218 if (pt == NULL)
4219 vim_free(name);
4220 else
4221 {
4222 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4223 {
4224 listitem_T *li;
4225 int i = 0;
4226 int arg_len = 0;
4227 int lv_len = 0;
4228
4229 if (arg_pt != NULL)
4230 arg_len = arg_pt->pt_argc;
4231 if (list != NULL)
4232 lv_len = list->lv_len;
4233 pt->pt_argc = arg_len + lv_len;
4234 pt->pt_argv = (typval_T *)alloc(
4235 sizeof(typval_T) * pt->pt_argc);
4236 if (pt->pt_argv == NULL)
4237 {
4238 vim_free(pt);
4239 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004240 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004241 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004242 for (i = 0; i < arg_len; i++)
4243 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4244 if (lv_len > 0)
4245 for (li = list->lv_first; li != NULL;
4246 li = li->li_next)
4247 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004248 }
4249
4250 /* For "function(dict.func, [], dict)" and "func" is a partial
4251 * use "dict". That is backwards compatible. */
4252 if (dict_idx > 0)
4253 {
4254 /* The dict is bound explicitly, pt_auto is FALSE. */
4255 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4256 ++pt->pt_dict->dv_refcount;
4257 }
4258 else if (arg_pt != NULL)
4259 {
4260 /* If the dict was bound automatically the result is also
4261 * bound automatically. */
4262 pt->pt_dict = arg_pt->pt_dict;
4263 pt->pt_auto = arg_pt->pt_auto;
4264 if (pt->pt_dict != NULL)
4265 ++pt->pt_dict->dv_refcount;
4266 }
4267
4268 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004269 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4270 {
4271 pt->pt_func = arg_pt->pt_func;
4272 func_ptr_ref(pt->pt_func);
4273 vim_free(name);
4274 }
4275 else if (is_funcref)
4276 {
4277 pt->pt_func = find_func(trans_name);
4278 func_ptr_ref(pt->pt_func);
4279 vim_free(name);
4280 }
4281 else
4282 {
4283 pt->pt_name = name;
4284 func_ref(name);
4285 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 }
4287 rettv->v_type = VAR_PARTIAL;
4288 rettv->vval.v_partial = pt;
4289 }
4290 else
4291 {
4292 /* result is a VAR_FUNC */
4293 rettv->v_type = VAR_FUNC;
4294 rettv->vval.v_string = name;
4295 func_ref(name);
4296 }
4297 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004298theend:
4299 vim_free(trans_name);
4300}
4301
4302/*
4303 * "funcref()" function
4304 */
4305 static void
4306f_funcref(typval_T *argvars, typval_T *rettv)
4307{
4308 common_function(argvars, rettv, TRUE);
4309}
4310
4311/*
4312 * "function()" function
4313 */
4314 static void
4315f_function(typval_T *argvars, typval_T *rettv)
4316{
4317 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004318}
4319
4320/*
4321 * "garbagecollect()" function
4322 */
4323 static void
4324f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4325{
4326 /* This is postponed until we are back at the toplevel, because we may be
4327 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4328 want_garbage_collect = TRUE;
4329
4330 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
4331 garbage_collect_at_exit = TRUE;
4332}
4333
4334/*
4335 * "get()" function
4336 */
4337 static void
4338f_get(typval_T *argvars, typval_T *rettv)
4339{
4340 listitem_T *li;
4341 list_T *l;
4342 dictitem_T *di;
4343 dict_T *d;
4344 typval_T *tv = NULL;
4345
4346 if (argvars[0].v_type == VAR_LIST)
4347 {
4348 if ((l = argvars[0].vval.v_list) != NULL)
4349 {
4350 int error = FALSE;
4351
4352 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
4353 if (!error && li != NULL)
4354 tv = &li->li_tv;
4355 }
4356 }
4357 else if (argvars[0].v_type == VAR_DICT)
4358 {
4359 if ((d = argvars[0].vval.v_dict) != NULL)
4360 {
4361 di = dict_find(d, get_tv_string(&argvars[1]), -1);
4362 if (di != NULL)
4363 tv = &di->di_tv;
4364 }
4365 }
4366 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4367 {
4368 partial_T *pt;
4369 partial_T fref_pt;
4370
4371 if (argvars[0].v_type == VAR_PARTIAL)
4372 pt = argvars[0].vval.v_partial;
4373 else
4374 {
4375 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4376 fref_pt.pt_name = argvars[0].vval.v_string;
4377 pt = &fref_pt;
4378 }
4379
4380 if (pt != NULL)
4381 {
4382 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004383 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384
4385 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4386 {
4387 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004388 n = partial_name(pt);
4389 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004390 rettv->vval.v_string = NULL;
4391 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004392 {
4393 rettv->vval.v_string = vim_strsave(n);
4394 if (rettv->v_type == VAR_FUNC)
4395 func_ref(rettv->vval.v_string);
4396 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397 }
4398 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004399 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004400 else if (STRCMP(what, "args") == 0)
4401 {
4402 rettv->v_type = VAR_LIST;
4403 if (rettv_list_alloc(rettv) == OK)
4404 {
4405 int i;
4406
4407 for (i = 0; i < pt->pt_argc; ++i)
4408 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4409 }
4410 }
4411 else
4412 EMSG2(_(e_invarg2), what);
4413 return;
4414 }
4415 }
4416 else
4417 EMSG2(_(e_listdictarg), "get()");
4418
4419 if (tv == NULL)
4420 {
4421 if (argvars[2].v_type != VAR_UNKNOWN)
4422 copy_tv(&argvars[2], rettv);
4423 }
4424 else
4425 copy_tv(tv, rettv);
4426}
4427
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004428#ifdef FEAT_SIGNS
4429/*
4430 * Returns information about signs placed in a buffer as list of dicts.
4431 */
4432 static void
4433get_buffer_signs(buf_T *buf, list_T *l)
4434{
4435 signlist_T *sign;
Bram Moolenaar162b7142018-12-21 15:17:36 +01004436 dict_T *d;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004437
Bram Moolenaar162b7142018-12-21 15:17:36 +01004438 FOR_ALL_SIGNS_IN_BUF(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004439 {
Bram Moolenaar162b7142018-12-21 15:17:36 +01004440 if ((d = sign_get_info(sign)) != NULL)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004441 list_append_dict(l, d);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004442 }
4443}
4444#endif
4445
4446/*
4447 * Returns buffer options, variables and other attributes in a dictionary.
4448 */
4449 static dict_T *
4450get_buffer_info(buf_T *buf)
4451{
4452 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004453 tabpage_T *tp;
4454 win_T *wp;
4455 list_T *windows;
4456
4457 dict = dict_alloc();
4458 if (dict == NULL)
4459 return NULL;
4460
Bram Moolenaare0be1672018-07-08 16:50:37 +02004461 dict_add_number(dict, "bufnr", buf->b_fnum);
4462 dict_add_string(dict, "name", buf->b_ffname);
4463 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4464 : buflist_findlnum(buf));
4465 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4466 dict_add_number(dict, "listed", buf->b_p_bl);
4467 dict_add_number(dict, "changed", bufIsChanged(buf));
4468 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4469 dict_add_number(dict, "hidden",
4470 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004471
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004472 /* Get a reference to buffer variables */
4473 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004474
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004475 /* List of windows displaying this buffer */
4476 windows = list_alloc();
4477 if (windows != NULL)
4478 {
4479 FOR_ALL_TAB_WINDOWS(tp, wp)
4480 if (wp->w_buffer == buf)
4481 list_append_number(windows, (varnumber_T)wp->w_id);
4482 dict_add_list(dict, "windows", windows);
4483 }
4484
4485#ifdef FEAT_SIGNS
4486 if (buf->b_signlist != NULL)
4487 {
4488 /* List of signs placed in this buffer */
4489 list_T *signs = list_alloc();
4490 if (signs != NULL)
4491 {
4492 get_buffer_signs(buf, signs);
4493 dict_add_list(dict, "signs", signs);
4494 }
4495 }
4496#endif
4497
4498 return dict;
4499}
4500
4501/*
4502 * "getbufinfo()" function
4503 */
4504 static void
4505f_getbufinfo(typval_T *argvars, typval_T *rettv)
4506{
4507 buf_T *buf = NULL;
4508 buf_T *argbuf = NULL;
4509 dict_T *d;
4510 int filtered = FALSE;
4511 int sel_buflisted = FALSE;
4512 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004513 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004514
4515 if (rettv_list_alloc(rettv) != OK)
4516 return;
4517
4518 /* List of all the buffers or selected buffers */
4519 if (argvars[0].v_type == VAR_DICT)
4520 {
4521 dict_T *sel_d = argvars[0].vval.v_dict;
4522
4523 if (sel_d != NULL)
4524 {
4525 dictitem_T *di;
4526
4527 filtered = TRUE;
4528
4529 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4530 if (di != NULL && get_tv_number(&di->di_tv))
4531 sel_buflisted = TRUE;
4532
4533 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4534 if (di != NULL && get_tv_number(&di->di_tv))
4535 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004536
4537 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4538 if (di != NULL && get_tv_number(&di->di_tv))
4539 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004540 }
4541 }
4542 else if (argvars[0].v_type != VAR_UNKNOWN)
4543 {
4544 /* Information about one buffer. Argument specifies the buffer */
4545 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4546 ++emsg_off;
4547 argbuf = get_buf_tv(&argvars[0], FALSE);
4548 --emsg_off;
4549 if (argbuf == NULL)
4550 return;
4551 }
4552
4553 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004554 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004555 {
4556 if (argbuf != NULL && argbuf != buf)
4557 continue;
4558 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004559 || (sel_buflisted && !buf->b_p_bl)
4560 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004561 continue;
4562
4563 d = get_buffer_info(buf);
4564 if (d != NULL)
4565 list_append_dict(rettv->vval.v_list, d);
4566 if (argbuf != NULL)
4567 return;
4568 }
4569}
4570
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004571/*
4572 * Get line or list of lines from buffer "buf" into "rettv".
4573 * Return a range (from start to end) of lines in rettv from the specified
4574 * buffer.
4575 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4576 */
4577 static void
4578get_buffer_lines(
4579 buf_T *buf,
4580 linenr_T start,
4581 linenr_T end,
4582 int retlist,
4583 typval_T *rettv)
4584{
4585 char_u *p;
4586
4587 rettv->v_type = VAR_STRING;
4588 rettv->vval.v_string = NULL;
4589 if (retlist && rettv_list_alloc(rettv) == FAIL)
4590 return;
4591
4592 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4593 return;
4594
4595 if (!retlist)
4596 {
4597 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4598 p = ml_get_buf(buf, start, FALSE);
4599 else
4600 p = (char_u *)"";
4601 rettv->vval.v_string = vim_strsave(p);
4602 }
4603 else
4604 {
4605 if (end < start)
4606 return;
4607
4608 if (start < 1)
4609 start = 1;
4610 if (end > buf->b_ml.ml_line_count)
4611 end = buf->b_ml.ml_line_count;
4612 while (start <= end)
4613 if (list_append_string(rettv->vval.v_list,
4614 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4615 break;
4616 }
4617}
4618
4619/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004620 * "getbufline()" function
4621 */
4622 static void
4623f_getbufline(typval_T *argvars, typval_T *rettv)
4624{
4625 linenr_T lnum;
4626 linenr_T end;
4627 buf_T *buf;
4628
4629 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4630 ++emsg_off;
4631 buf = get_buf_tv(&argvars[0], FALSE);
4632 --emsg_off;
4633
4634 lnum = get_tv_lnum_buf(&argvars[1], buf);
4635 if (argvars[2].v_type == VAR_UNKNOWN)
4636 end = lnum;
4637 else
4638 end = get_tv_lnum_buf(&argvars[2], buf);
4639
4640 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4641}
4642
4643/*
4644 * "getbufvar()" function
4645 */
4646 static void
4647f_getbufvar(typval_T *argvars, typval_T *rettv)
4648{
4649 buf_T *buf;
4650 buf_T *save_curbuf;
4651 char_u *varname;
4652 dictitem_T *v;
4653 int done = FALSE;
4654
4655 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4656 varname = get_tv_string_chk(&argvars[1]);
4657 ++emsg_off;
4658 buf = get_buf_tv(&argvars[0], FALSE);
4659
4660 rettv->v_type = VAR_STRING;
4661 rettv->vval.v_string = NULL;
4662
4663 if (buf != NULL && varname != NULL)
4664 {
4665 /* set curbuf to be our buf, temporarily */
4666 save_curbuf = curbuf;
4667 curbuf = buf;
4668
Bram Moolenaar30567352016-08-27 21:25:44 +02004669 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004670 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004671 if (varname[1] == NUL)
4672 {
4673 /* get all buffer-local options in a dict */
4674 dict_T *opts = get_winbuf_options(TRUE);
4675
4676 if (opts != NULL)
4677 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004678 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004679 done = TRUE;
4680 }
4681 }
4682 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4683 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004684 done = TRUE;
4685 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686 else
4687 {
4688 /* Look up the variable. */
4689 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4690 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4691 'b', varname, FALSE);
4692 if (v != NULL)
4693 {
4694 copy_tv(&v->di_tv, rettv);
4695 done = TRUE;
4696 }
4697 }
4698
4699 /* restore previous notion of curbuf */
4700 curbuf = save_curbuf;
4701 }
4702
4703 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4704 /* use the default value */
4705 copy_tv(&argvars[2], rettv);
4706
4707 --emsg_off;
4708}
4709
4710/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004711 * "getchangelist()" function
4712 */
4713 static void
4714f_getchangelist(typval_T *argvars, typval_T *rettv)
4715{
4716#ifdef FEAT_JUMPLIST
4717 buf_T *buf;
4718 int i;
4719 list_T *l;
4720 dict_T *d;
4721#endif
4722
4723 if (rettv_list_alloc(rettv) != OK)
4724 return;
4725
4726#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004727 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4728 ++emsg_off;
4729 buf = get_buf_tv(&argvars[0], FALSE);
4730 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004731 if (buf == NULL)
4732 return;
4733
4734 l = list_alloc();
4735 if (l == NULL)
4736 return;
4737
4738 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4739 return;
4740 /*
4741 * The current window change list index tracks only the position in the
4742 * current buffer change list. For other buffers, use the change list
4743 * length as the current index.
4744 */
4745 list_append_number(rettv->vval.v_list,
4746 (varnumber_T)((buf == curwin->w_buffer)
4747 ? curwin->w_changelistidx : buf->b_changelistlen));
4748
4749 for (i = 0; i < buf->b_changelistlen; ++i)
4750 {
4751 if (buf->b_changelist[i].lnum == 0)
4752 continue;
4753 if ((d = dict_alloc()) == NULL)
4754 return;
4755 if (list_append_dict(l, d) == FAIL)
4756 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004757 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4758 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004759# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004760 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004761# endif
4762 }
4763#endif
4764}
4765/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766 * "getchar()" function
4767 */
4768 static void
4769f_getchar(typval_T *argvars, typval_T *rettv)
4770{
4771 varnumber_T n;
4772 int error = FALSE;
4773
Bram Moolenaar84d93902018-09-11 20:10:20 +02004774#ifdef MESSAGE_QUEUE
4775 // vpeekc() used to check for messages, but that caused problems, invoking
4776 // a callback where it was not expected. Some plugins use getchar(1) in a
4777 // loop to await a message, therefore make sure we check for messages here.
4778 parse_queued_messages();
4779#endif
4780
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004781 /* Position the cursor. Needed after a message that ends in a space. */
4782 windgoto(msg_row, msg_col);
4783
4784 ++no_mapping;
4785 ++allow_keys;
4786 for (;;)
4787 {
4788 if (argvars[0].v_type == VAR_UNKNOWN)
4789 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004790 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004791 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4792 /* getchar(1): only check if char avail */
4793 n = vpeekc_any();
4794 else if (error || vpeekc_any() == NUL)
4795 /* illegal argument or getchar(0) and no char avail: return zero */
4796 n = 0;
4797 else
4798 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004799 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004800
4801 if (n == K_IGNORE)
4802 continue;
4803 break;
4804 }
4805 --no_mapping;
4806 --allow_keys;
4807
4808 set_vim_var_nr(VV_MOUSE_WIN, 0);
4809 set_vim_var_nr(VV_MOUSE_WINID, 0);
4810 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4811 set_vim_var_nr(VV_MOUSE_COL, 0);
4812
4813 rettv->vval.v_number = n;
4814 if (IS_SPECIAL(n) || mod_mask != 0)
4815 {
4816 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4817 int i = 0;
4818
4819 /* Turn a special key into three bytes, plus modifier. */
4820 if (mod_mask != 0)
4821 {
4822 temp[i++] = K_SPECIAL;
4823 temp[i++] = KS_MODIFIER;
4824 temp[i++] = mod_mask;
4825 }
4826 if (IS_SPECIAL(n))
4827 {
4828 temp[i++] = K_SPECIAL;
4829 temp[i++] = K_SECOND(n);
4830 temp[i++] = K_THIRD(n);
4831 }
4832#ifdef FEAT_MBYTE
4833 else if (has_mbyte)
4834 i += (*mb_char2bytes)(n, temp + i);
4835#endif
4836 else
4837 temp[i++] = n;
4838 temp[i++] = NUL;
4839 rettv->v_type = VAR_STRING;
4840 rettv->vval.v_string = vim_strsave(temp);
4841
4842#ifdef FEAT_MOUSE
4843 if (is_mouse_key(n))
4844 {
4845 int row = mouse_row;
4846 int col = mouse_col;
4847 win_T *win;
4848 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004849 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850 int winnr = 1;
4851
4852 if (row >= 0 && col >= 0)
4853 {
4854 /* Find the window at the mouse coordinates and compute the
4855 * text position. */
4856 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004857 if (win == NULL)
4858 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004860 for (wp = firstwin; wp != win; wp = wp->w_next)
4861 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004862 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4863 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4864 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4865 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4866 }
4867 }
4868#endif
4869 }
4870}
4871
4872/*
4873 * "getcharmod()" function
4874 */
4875 static void
4876f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4877{
4878 rettv->vval.v_number = mod_mask;
4879}
4880
4881/*
4882 * "getcharsearch()" function
4883 */
4884 static void
4885f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4886{
4887 if (rettv_dict_alloc(rettv) != FAIL)
4888 {
4889 dict_T *dict = rettv->vval.v_dict;
4890
Bram Moolenaare0be1672018-07-08 16:50:37 +02004891 dict_add_string(dict, "char", last_csearch());
4892 dict_add_number(dict, "forward", last_csearch_forward());
4893 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894 }
4895}
4896
4897/*
4898 * "getcmdline()" function
4899 */
4900 static void
4901f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4902{
4903 rettv->v_type = VAR_STRING;
4904 rettv->vval.v_string = get_cmdline_str();
4905}
4906
4907/*
4908 * "getcmdpos()" function
4909 */
4910 static void
4911f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4912{
4913 rettv->vval.v_number = get_cmdline_pos() + 1;
4914}
4915
4916/*
4917 * "getcmdtype()" function
4918 */
4919 static void
4920f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4921{
4922 rettv->v_type = VAR_STRING;
4923 rettv->vval.v_string = alloc(2);
4924 if (rettv->vval.v_string != NULL)
4925 {
4926 rettv->vval.v_string[0] = get_cmdline_type();
4927 rettv->vval.v_string[1] = NUL;
4928 }
4929}
4930
4931/*
4932 * "getcmdwintype()" function
4933 */
4934 static void
4935f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4936{
4937 rettv->v_type = VAR_STRING;
4938 rettv->vval.v_string = NULL;
4939#ifdef FEAT_CMDWIN
4940 rettv->vval.v_string = alloc(2);
4941 if (rettv->vval.v_string != NULL)
4942 {
4943 rettv->vval.v_string[0] = cmdwin_type;
4944 rettv->vval.v_string[1] = NUL;
4945 }
4946#endif
4947}
4948
4949#if defined(FEAT_CMDL_COMPL)
4950/*
4951 * "getcompletion()" function
4952 */
4953 static void
4954f_getcompletion(typval_T *argvars, typval_T *rettv)
4955{
4956 char_u *pat;
4957 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004958 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004959 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4960 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004962 if (argvars[2].v_type != VAR_UNKNOWN)
4963 filtered = get_tv_number_chk(&argvars[2], NULL);
4964
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965 if (p_wic)
4966 options |= WILD_ICASE;
4967
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004968 /* For filtered results, 'wildignore' is used */
4969 if (!filtered)
4970 options |= WILD_KEEP_ALL;
4971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972 ExpandInit(&xpc);
4973 xpc.xp_pattern = get_tv_string(&argvars[0]);
4974 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4975 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4976 if (xpc.xp_context == EXPAND_NOTHING)
4977 {
4978 if (argvars[1].v_type == VAR_STRING)
4979 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4980 else
4981 EMSG(_(e_invarg));
4982 return;
4983 }
4984
4985# if defined(FEAT_MENU)
4986 if (xpc.xp_context == EXPAND_MENUS)
4987 {
4988 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4989 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4990 }
4991# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004992#ifdef FEAT_CSCOPE
4993 if (xpc.xp_context == EXPAND_CSCOPE)
4994 {
4995 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4996 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4997 }
4998#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004999#ifdef FEAT_SIGNS
5000 if (xpc.xp_context == EXPAND_SIGN)
5001 {
5002 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5003 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5004 }
5005#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005006
5007 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5008 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5009 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005010 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005011
5012 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5013
5014 for (i = 0; i < xpc.xp_numfiles; i++)
5015 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5016 }
5017 vim_free(pat);
5018 ExpandCleanup(&xpc);
5019}
5020#endif
5021
5022/*
5023 * "getcwd()" function
5024 */
5025 static void
5026f_getcwd(typval_T *argvars, typval_T *rettv)
5027{
5028 win_T *wp = NULL;
5029 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005030 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031
5032 rettv->v_type = VAR_STRING;
5033 rettv->vval.v_string = NULL;
5034
Bram Moolenaar54591292018-02-09 20:53:59 +01005035 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5036 global = TRUE;
5037 else
5038 wp = find_tabwin(&argvars[0], &argvars[1]);
5039
5040 if (wp != NULL && wp->w_localdir != NULL)
5041 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5042 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005043 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005044 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005045 rettv->vval.v_string = vim_strsave(globaldir);
5046 else
5047 {
5048 cwd = alloc(MAXPATHL);
5049 if (cwd != NULL)
5050 {
5051 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5052 rettv->vval.v_string = vim_strsave(cwd);
5053 vim_free(cwd);
5054 }
5055 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005056 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005057#ifdef BACKSLASH_IN_FILENAME
5058 if (rettv->vval.v_string != NULL)
5059 slash_adjust(rettv->vval.v_string);
5060#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005061}
5062
5063/*
5064 * "getfontname()" function
5065 */
5066 static void
5067f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5068{
5069 rettv->v_type = VAR_STRING;
5070 rettv->vval.v_string = NULL;
5071#ifdef FEAT_GUI
5072 if (gui.in_use)
5073 {
5074 GuiFont font;
5075 char_u *name = NULL;
5076
5077 if (argvars[0].v_type == VAR_UNKNOWN)
5078 {
5079 /* Get the "Normal" font. Either the name saved by
5080 * hl_set_font_name() or from the font ID. */
5081 font = gui.norm_font;
5082 name = hl_get_font_name();
5083 }
5084 else
5085 {
5086 name = get_tv_string(&argvars[0]);
5087 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5088 return;
5089 font = gui_mch_get_font(name, FALSE);
5090 if (font == NOFONT)
5091 return; /* Invalid font name, return empty string. */
5092 }
5093 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5094 if (argvars[0].v_type != VAR_UNKNOWN)
5095 gui_mch_free_font(font);
5096 }
5097#endif
5098}
5099
5100/*
5101 * "getfperm({fname})" function
5102 */
5103 static void
5104f_getfperm(typval_T *argvars, typval_T *rettv)
5105{
5106 char_u *fname;
5107 stat_T st;
5108 char_u *perm = NULL;
5109 char_u flags[] = "rwx";
5110 int i;
5111
5112 fname = get_tv_string(&argvars[0]);
5113
5114 rettv->v_type = VAR_STRING;
5115 if (mch_stat((char *)fname, &st) >= 0)
5116 {
5117 perm = vim_strsave((char_u *)"---------");
5118 if (perm != NULL)
5119 {
5120 for (i = 0; i < 9; i++)
5121 {
5122 if (st.st_mode & (1 << (8 - i)))
5123 perm[i] = flags[i % 3];
5124 }
5125 }
5126 }
5127 rettv->vval.v_string = perm;
5128}
5129
5130/*
5131 * "getfsize({fname})" function
5132 */
5133 static void
5134f_getfsize(typval_T *argvars, typval_T *rettv)
5135{
5136 char_u *fname;
5137 stat_T st;
5138
5139 fname = get_tv_string(&argvars[0]);
5140
5141 rettv->v_type = VAR_NUMBER;
5142
5143 if (mch_stat((char *)fname, &st) >= 0)
5144 {
5145 if (mch_isdir(fname))
5146 rettv->vval.v_number = 0;
5147 else
5148 {
5149 rettv->vval.v_number = (varnumber_T)st.st_size;
5150
5151 /* non-perfect check for overflow */
5152 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5153 rettv->vval.v_number = -2;
5154 }
5155 }
5156 else
5157 rettv->vval.v_number = -1;
5158}
5159
5160/*
5161 * "getftime({fname})" function
5162 */
5163 static void
5164f_getftime(typval_T *argvars, typval_T *rettv)
5165{
5166 char_u *fname;
5167 stat_T st;
5168
5169 fname = get_tv_string(&argvars[0]);
5170
5171 if (mch_stat((char *)fname, &st) >= 0)
5172 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5173 else
5174 rettv->vval.v_number = -1;
5175}
5176
5177/*
5178 * "getftype({fname})" function
5179 */
5180 static void
5181f_getftype(typval_T *argvars, typval_T *rettv)
5182{
5183 char_u *fname;
5184 stat_T st;
5185 char_u *type = NULL;
5186 char *t;
5187
5188 fname = get_tv_string(&argvars[0]);
5189
5190 rettv->v_type = VAR_STRING;
5191 if (mch_lstat((char *)fname, &st) >= 0)
5192 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193 if (S_ISREG(st.st_mode))
5194 t = "file";
5195 else if (S_ISDIR(st.st_mode))
5196 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005197 else if (S_ISLNK(st.st_mode))
5198 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 else if (S_ISBLK(st.st_mode))
5200 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 else if (S_ISCHR(st.st_mode))
5202 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 else if (S_ISFIFO(st.st_mode))
5204 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005205 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005206 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005207 else
5208 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 type = vim_strsave((char_u *)t);
5210 }
5211 rettv->vval.v_string = type;
5212}
5213
5214/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005215 * "getjumplist()" function
5216 */
5217 static void
5218f_getjumplist(typval_T *argvars, typval_T *rettv)
5219{
5220#ifdef FEAT_JUMPLIST
5221 win_T *wp;
5222 int i;
5223 list_T *l;
5224 dict_T *d;
5225#endif
5226
5227 if (rettv_list_alloc(rettv) != OK)
5228 return;
5229
5230#ifdef FEAT_JUMPLIST
5231 wp = find_tabwin(&argvars[0], &argvars[1]);
5232 if (wp == NULL)
5233 return;
5234
5235 l = list_alloc();
5236 if (l == NULL)
5237 return;
5238
5239 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5240 return;
5241 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5242
Bram Moolenaar48679742018-02-13 13:33:29 +01005243 cleanup_jumplist(wp, TRUE);
5244
Bram Moolenaar4f505882018-02-10 21:06:32 +01005245 for (i = 0; i < wp->w_jumplistlen; ++i)
5246 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005247 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5248 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005249 if ((d = dict_alloc()) == NULL)
5250 return;
5251 if (list_append_dict(l, d) == FAIL)
5252 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005253 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5254 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005255# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005256 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005257# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005258 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005259 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005260 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005261 }
5262#endif
5263}
5264
5265/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005266 * "getline(lnum, [end])" function
5267 */
5268 static void
5269f_getline(typval_T *argvars, typval_T *rettv)
5270{
5271 linenr_T lnum;
5272 linenr_T end;
5273 int retlist;
5274
5275 lnum = get_tv_lnum(argvars);
5276 if (argvars[1].v_type == VAR_UNKNOWN)
5277 {
5278 end = 0;
5279 retlist = FALSE;
5280 }
5281 else
5282 {
5283 end = get_tv_lnum(&argvars[1]);
5284 retlist = TRUE;
5285 }
5286
5287 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5288}
5289
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005290#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005291 static void
5292get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5293{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005294 if (what_arg->v_type == VAR_UNKNOWN)
5295 {
5296 if (rettv_list_alloc(rettv) == OK)
5297 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005298 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005299 }
5300 else
5301 {
5302 if (rettv_dict_alloc(rettv) == OK)
5303 if (is_qf || (wp != NULL))
5304 {
5305 if (what_arg->v_type == VAR_DICT)
5306 {
5307 dict_T *d = what_arg->vval.v_dict;
5308
5309 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005310 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005311 }
5312 else
5313 EMSG(_(e_dictreq));
5314 }
5315 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005316}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005317#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005318
5319/*
5320 * "getloclist()" function
5321 */
5322 static void
5323f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5324{
5325#ifdef FEAT_QUICKFIX
5326 win_T *wp;
5327
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005328 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005329 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5330#endif
5331}
5332
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005333/*
5334 * "getmatches()" function
5335 */
5336 static void
5337f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5338{
5339#ifdef FEAT_SEARCH_EXTRA
5340 dict_T *dict;
5341 matchitem_T *cur = curwin->w_match_head;
5342 int i;
5343
5344 if (rettv_list_alloc(rettv) == OK)
5345 {
5346 while (cur != NULL)
5347 {
5348 dict = dict_alloc();
5349 if (dict == NULL)
5350 return;
5351 if (cur->match.regprog == NULL)
5352 {
5353 /* match added with matchaddpos() */
5354 for (i = 0; i < MAXPOSMATCH; ++i)
5355 {
5356 llpos_T *llpos;
5357 char buf[6];
5358 list_T *l;
5359
5360 llpos = &cur->pos.pos[i];
5361 if (llpos->lnum == 0)
5362 break;
5363 l = list_alloc();
5364 if (l == NULL)
5365 break;
5366 list_append_number(l, (varnumber_T)llpos->lnum);
5367 if (llpos->col > 0)
5368 {
5369 list_append_number(l, (varnumber_T)llpos->col);
5370 list_append_number(l, (varnumber_T)llpos->len);
5371 }
5372 sprintf(buf, "pos%d", i + 1);
5373 dict_add_list(dict, buf, l);
5374 }
5375 }
5376 else
5377 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005378 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005380 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5381 dict_add_number(dict, "priority", (long)cur->priority);
5382 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005383# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5384 if (cur->conceal_char)
5385 {
5386 char_u buf[MB_MAXBYTES + 1];
5387
5388 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005389 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005390 }
5391# endif
5392 list_append_dict(rettv->vval.v_list, dict);
5393 cur = cur->next;
5394 }
5395 }
5396#endif
5397}
5398
5399/*
5400 * "getpid()" function
5401 */
5402 static void
5403f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5404{
5405 rettv->vval.v_number = mch_get_pid();
5406}
5407
5408 static void
5409getpos_both(
5410 typval_T *argvars,
5411 typval_T *rettv,
5412 int getcurpos)
5413{
5414 pos_T *fp;
5415 list_T *l;
5416 int fnum = -1;
5417
5418 if (rettv_list_alloc(rettv) == OK)
5419 {
5420 l = rettv->vval.v_list;
5421 if (getcurpos)
5422 fp = &curwin->w_cursor;
5423 else
5424 fp = var2fpos(&argvars[0], TRUE, &fnum);
5425 if (fnum != -1)
5426 list_append_number(l, (varnumber_T)fnum);
5427 else
5428 list_append_number(l, (varnumber_T)0);
5429 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5430 : (varnumber_T)0);
5431 list_append_number(l, (fp != NULL)
5432 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5433 : (varnumber_T)0);
5434 list_append_number(l,
5435#ifdef FEAT_VIRTUALEDIT
5436 (fp != NULL) ? (varnumber_T)fp->coladd :
5437#endif
5438 (varnumber_T)0);
5439 if (getcurpos)
5440 {
5441 update_curswant();
5442 list_append_number(l, curwin->w_curswant == MAXCOL ?
5443 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5444 }
5445 }
5446 else
5447 rettv->vval.v_number = FALSE;
5448}
5449
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005450/*
5451 * "getcurpos()" function
5452 */
5453 static void
5454f_getcurpos(typval_T *argvars, typval_T *rettv)
5455{
5456 getpos_both(argvars, rettv, TRUE);
5457}
5458
5459/*
5460 * "getpos(string)" function
5461 */
5462 static void
5463f_getpos(typval_T *argvars, typval_T *rettv)
5464{
5465 getpos_both(argvars, rettv, FALSE);
5466}
5467
5468/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005469 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005470 */
5471 static void
5472f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5473{
5474#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005475 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005476#endif
5477}
5478
5479/*
5480 * "getreg()" function
5481 */
5482 static void
5483f_getreg(typval_T *argvars, typval_T *rettv)
5484{
5485 char_u *strregname;
5486 int regname;
5487 int arg2 = FALSE;
5488 int return_list = FALSE;
5489 int error = FALSE;
5490
5491 if (argvars[0].v_type != VAR_UNKNOWN)
5492 {
5493 strregname = get_tv_string_chk(&argvars[0]);
5494 error = strregname == NULL;
5495 if (argvars[1].v_type != VAR_UNKNOWN)
5496 {
5497 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5498 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5499 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5500 }
5501 }
5502 else
5503 strregname = get_vim_var_str(VV_REG);
5504
5505 if (error)
5506 return;
5507
5508 regname = (strregname == NULL ? '"' : *strregname);
5509 if (regname == 0)
5510 regname = '"';
5511
5512 if (return_list)
5513 {
5514 rettv->v_type = VAR_LIST;
5515 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5516 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5517 if (rettv->vval.v_list == NULL)
5518 (void)rettv_list_alloc(rettv);
5519 else
5520 ++rettv->vval.v_list->lv_refcount;
5521 }
5522 else
5523 {
5524 rettv->v_type = VAR_STRING;
5525 rettv->vval.v_string = get_reg_contents(regname,
5526 arg2 ? GREG_EXPR_SRC : 0);
5527 }
5528}
5529
5530/*
5531 * "getregtype()" function
5532 */
5533 static void
5534f_getregtype(typval_T *argvars, typval_T *rettv)
5535{
5536 char_u *strregname;
5537 int regname;
5538 char_u buf[NUMBUFLEN + 2];
5539 long reglen = 0;
5540
5541 if (argvars[0].v_type != VAR_UNKNOWN)
5542 {
5543 strregname = get_tv_string_chk(&argvars[0]);
5544 if (strregname == NULL) /* type error; errmsg already given */
5545 {
5546 rettv->v_type = VAR_STRING;
5547 rettv->vval.v_string = NULL;
5548 return;
5549 }
5550 }
5551 else
5552 /* Default to v:register */
5553 strregname = get_vim_var_str(VV_REG);
5554
5555 regname = (strregname == NULL ? '"' : *strregname);
5556 if (regname == 0)
5557 regname = '"';
5558
5559 buf[0] = NUL;
5560 buf[1] = NUL;
5561 switch (get_reg_type(regname, &reglen))
5562 {
5563 case MLINE: buf[0] = 'V'; break;
5564 case MCHAR: buf[0] = 'v'; break;
5565 case MBLOCK:
5566 buf[0] = Ctrl_V;
5567 sprintf((char *)buf + 1, "%ld", reglen + 1);
5568 break;
5569 }
5570 rettv->v_type = VAR_STRING;
5571 rettv->vval.v_string = vim_strsave(buf);
5572}
5573
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005574/*
5575 * Returns information (variables, options, etc.) about a tab page
5576 * as a dictionary.
5577 */
5578 static dict_T *
5579get_tabpage_info(tabpage_T *tp, int tp_idx)
5580{
5581 win_T *wp;
5582 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005583 list_T *l;
5584
5585 dict = dict_alloc();
5586 if (dict == NULL)
5587 return NULL;
5588
Bram Moolenaare0be1672018-07-08 16:50:37 +02005589 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005590
5591 l = list_alloc();
5592 if (l != NULL)
5593 {
5594 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5595 wp; wp = wp->w_next)
5596 list_append_number(l, (varnumber_T)wp->w_id);
5597 dict_add_list(dict, "windows", l);
5598 }
5599
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005600 /* Make a reference to tabpage variables */
5601 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005602
5603 return dict;
5604}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005605
5606/*
5607 * "gettabinfo()" function
5608 */
5609 static void
5610f_gettabinfo(typval_T *argvars, typval_T *rettv)
5611{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005612 tabpage_T *tp, *tparg = NULL;
5613 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005614 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005615
5616 if (rettv_list_alloc(rettv) != OK)
5617 return;
5618
5619 if (argvars[0].v_type != VAR_UNKNOWN)
5620 {
5621 /* Information about one tab page */
5622 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5623 if (tparg == NULL)
5624 return;
5625 }
5626
5627 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005628 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005629 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005630 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005631 if (tparg != NULL && tp != tparg)
5632 continue;
5633 d = get_tabpage_info(tp, tpnr);
5634 if (d != NULL)
5635 list_append_dict(rettv->vval.v_list, d);
5636 if (tparg != NULL)
5637 return;
5638 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005639}
5640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005641/*
5642 * "gettabvar()" function
5643 */
5644 static void
5645f_gettabvar(typval_T *argvars, typval_T *rettv)
5646{
5647 win_T *oldcurwin;
5648 tabpage_T *tp, *oldtabpage;
5649 dictitem_T *v;
5650 char_u *varname;
5651 int done = FALSE;
5652
5653 rettv->v_type = VAR_STRING;
5654 rettv->vval.v_string = NULL;
5655
5656 varname = get_tv_string_chk(&argvars[1]);
5657 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5658 if (tp != NULL && varname != NULL)
5659 {
5660 /* Set tp to be our tabpage, temporarily. Also set the window to the
5661 * first window in the tabpage, otherwise the window is not valid. */
5662 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005663 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5664 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005665 {
5666 /* look up the variable */
5667 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5668 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5669 if (v != NULL)
5670 {
5671 copy_tv(&v->di_tv, rettv);
5672 done = TRUE;
5673 }
5674 }
5675
5676 /* restore previous notion of curwin */
5677 restore_win(oldcurwin, oldtabpage, TRUE);
5678 }
5679
5680 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5681 copy_tv(&argvars[2], rettv);
5682}
5683
5684/*
5685 * "gettabwinvar()" function
5686 */
5687 static void
5688f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5689{
5690 getwinvar(argvars, rettv, 1);
5691}
5692
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005693/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005694 * "gettagstack()" function
5695 */
5696 static void
5697f_gettagstack(typval_T *argvars, typval_T *rettv)
5698{
5699 win_T *wp = curwin; // default is current window
5700
5701 if (rettv_dict_alloc(rettv) != OK)
5702 return;
5703
5704 if (argvars[0].v_type != VAR_UNKNOWN)
5705 {
5706 wp = find_win_by_nr_or_id(&argvars[0]);
5707 if (wp == NULL)
5708 return;
5709 }
5710
5711 get_tagstack(wp, rettv->vval.v_dict);
5712}
5713
5714/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005715 * Returns information about a window as a dictionary.
5716 */
5717 static dict_T *
5718get_win_info(win_T *wp, short tpnr, short winnr)
5719{
5720 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005721
5722 dict = dict_alloc();
5723 if (dict == NULL)
5724 return NULL;
5725
Bram Moolenaare0be1672018-07-08 16:50:37 +02005726 dict_add_number(dict, "tabnr", tpnr);
5727 dict_add_number(dict, "winnr", winnr);
5728 dict_add_number(dict, "winid", wp->w_id);
5729 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005730 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005731#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005732 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005733#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005734 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005735 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005736 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005737
Bram Moolenaar69905d12017-08-13 18:14:47 +02005738#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005739 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005740#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005741#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005742 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5743 dict_add_number(dict, "loclist",
5744 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005745#endif
5746
Bram Moolenaar30567352016-08-27 21:25:44 +02005747 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005748 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005749
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005750 return dict;
5751}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005752
5753/*
5754 * "getwininfo()" function
5755 */
5756 static void
5757f_getwininfo(typval_T *argvars, typval_T *rettv)
5758{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005759 tabpage_T *tp;
5760 win_T *wp = NULL, *wparg = NULL;
5761 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005762 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005763
5764 if (rettv_list_alloc(rettv) != OK)
5765 return;
5766
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005767 if (argvars[0].v_type != VAR_UNKNOWN)
5768 {
5769 wparg = win_id2wp(argvars);
5770 if (wparg == NULL)
5771 return;
5772 }
5773
5774 /* Collect information about either all the windows across all the tab
5775 * pages or one particular window.
5776 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005777 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005778 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005779 tabnr++;
5780 winnr = 0;
5781 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005782 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005783 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005784 if (wparg != NULL && wp != wparg)
5785 continue;
5786 d = get_win_info(wp, tabnr, winnr);
5787 if (d != NULL)
5788 list_append_dict(rettv->vval.v_list, d);
5789 if (wparg != NULL)
5790 /* found information about a specific window */
5791 return;
5792 }
5793 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005794}
5795
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005796/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005797 * "win_findbuf()" function
5798 */
5799 static void
5800f_win_findbuf(typval_T *argvars, typval_T *rettv)
5801{
5802 if (rettv_list_alloc(rettv) != FAIL)
5803 win_findbuf(argvars, rettv->vval.v_list);
5804}
5805
5806/*
5807 * "win_getid()" function
5808 */
5809 static void
5810f_win_getid(typval_T *argvars, typval_T *rettv)
5811{
5812 rettv->vval.v_number = win_getid(argvars);
5813}
5814
5815/*
5816 * "win_gotoid()" function
5817 */
5818 static void
5819f_win_gotoid(typval_T *argvars, typval_T *rettv)
5820{
5821 rettv->vval.v_number = win_gotoid(argvars);
5822}
5823
5824/*
5825 * "win_id2tabwin()" function
5826 */
5827 static void
5828f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5829{
5830 if (rettv_list_alloc(rettv) != FAIL)
5831 win_id2tabwin(argvars, rettv->vval.v_list);
5832}
5833
5834/*
5835 * "win_id2win()" function
5836 */
5837 static void
5838f_win_id2win(typval_T *argvars, typval_T *rettv)
5839{
5840 rettv->vval.v_number = win_id2win(argvars);
5841}
5842
5843/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005844 * "win_screenpos()" function
5845 */
5846 static void
5847f_win_screenpos(typval_T *argvars, typval_T *rettv)
5848{
5849 win_T *wp;
5850
5851 if (rettv_list_alloc(rettv) == FAIL)
5852 return;
5853
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005854 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005855 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5856 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5857}
5858
5859/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005860 * "getwinpos({timeout})" function
5861 */
5862 static void
5863f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5864{
5865 int x = -1;
5866 int y = -1;
5867
5868 if (rettv_list_alloc(rettv) == FAIL)
5869 return;
5870#ifdef FEAT_GUI
5871 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005872 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005873# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5874 else
5875# endif
5876#endif
5877#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5878 {
5879 varnumber_T timeout = 100;
5880
5881 if (argvars[0].v_type != VAR_UNKNOWN)
5882 timeout = get_tv_number(&argvars[0]);
5883 term_get_winpos(&x, &y, timeout);
5884 }
5885#endif
5886 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5887 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5888}
5889
5890
5891/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005892 * "getwinposx()" function
5893 */
5894 static void
5895f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5896{
5897 rettv->vval.v_number = -1;
5898#ifdef FEAT_GUI
5899 if (gui.in_use)
5900 {
5901 int x, y;
5902
5903 if (gui_mch_get_winpos(&x, &y) == OK)
5904 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005905 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005906 }
5907#endif
5908#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5909 {
5910 int x, y;
5911
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005912 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005913 rettv->vval.v_number = x;
5914 }
5915#endif
5916}
5917
5918/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005919 * "getwinposy()" function
5920 */
5921 static void
5922f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5923{
5924 rettv->vval.v_number = -1;
5925#ifdef FEAT_GUI
5926 if (gui.in_use)
5927 {
5928 int x, y;
5929
5930 if (gui_mch_get_winpos(&x, &y) == OK)
5931 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005932 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005933 }
5934#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005935#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5936 {
5937 int x, y;
5938
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005939 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005940 rettv->vval.v_number = y;
5941 }
5942#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005943}
5944
5945/*
5946 * "getwinvar()" function
5947 */
5948 static void
5949f_getwinvar(typval_T *argvars, typval_T *rettv)
5950{
5951 getwinvar(argvars, rettv, 0);
5952}
5953
5954/*
5955 * "glob()" function
5956 */
5957 static void
5958f_glob(typval_T *argvars, typval_T *rettv)
5959{
5960 int options = WILD_SILENT|WILD_USE_NL;
5961 expand_T xpc;
5962 int error = FALSE;
5963
5964 /* When the optional second argument is non-zero, don't remove matches
5965 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5966 rettv->v_type = VAR_STRING;
5967 if (argvars[1].v_type != VAR_UNKNOWN)
5968 {
5969 if (get_tv_number_chk(&argvars[1], &error))
5970 options |= WILD_KEEP_ALL;
5971 if (argvars[2].v_type != VAR_UNKNOWN)
5972 {
5973 if (get_tv_number_chk(&argvars[2], &error))
5974 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005975 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 }
5977 if (argvars[3].v_type != VAR_UNKNOWN
5978 && get_tv_number_chk(&argvars[3], &error))
5979 options |= WILD_ALLLINKS;
5980 }
5981 }
5982 if (!error)
5983 {
5984 ExpandInit(&xpc);
5985 xpc.xp_context = EXPAND_FILES;
5986 if (p_wic)
5987 options += WILD_ICASE;
5988 if (rettv->v_type == VAR_STRING)
5989 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5990 NULL, options, WILD_ALL);
5991 else if (rettv_list_alloc(rettv) != FAIL)
5992 {
5993 int i;
5994
5995 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5996 NULL, options, WILD_ALL_KEEP);
5997 for (i = 0; i < xpc.xp_numfiles; i++)
5998 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5999
6000 ExpandCleanup(&xpc);
6001 }
6002 }
6003 else
6004 rettv->vval.v_string = NULL;
6005}
6006
6007/*
6008 * "globpath()" function
6009 */
6010 static void
6011f_globpath(typval_T *argvars, typval_T *rettv)
6012{
6013 int flags = 0;
6014 char_u buf1[NUMBUFLEN];
6015 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
6016 int error = FALSE;
6017 garray_T ga;
6018 int i;
6019
6020 /* When the optional second argument is non-zero, don't remove matches
6021 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6022 rettv->v_type = VAR_STRING;
6023 if (argvars[2].v_type != VAR_UNKNOWN)
6024 {
6025 if (get_tv_number_chk(&argvars[2], &error))
6026 flags |= WILD_KEEP_ALL;
6027 if (argvars[3].v_type != VAR_UNKNOWN)
6028 {
6029 if (get_tv_number_chk(&argvars[3], &error))
6030 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006031 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006032 }
6033 if (argvars[4].v_type != VAR_UNKNOWN
6034 && get_tv_number_chk(&argvars[4], &error))
6035 flags |= WILD_ALLLINKS;
6036 }
6037 }
6038 if (file != NULL && !error)
6039 {
6040 ga_init2(&ga, (int)sizeof(char_u *), 10);
6041 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
6042 if (rettv->v_type == VAR_STRING)
6043 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6044 else if (rettv_list_alloc(rettv) != FAIL)
6045 for (i = 0; i < ga.ga_len; ++i)
6046 list_append_string(rettv->vval.v_list,
6047 ((char_u **)(ga.ga_data))[i], -1);
6048 ga_clear_strings(&ga);
6049 }
6050 else
6051 rettv->vval.v_string = NULL;
6052}
6053
6054/*
6055 * "glob2regpat()" function
6056 */
6057 static void
6058f_glob2regpat(typval_T *argvars, typval_T *rettv)
6059{
6060 char_u *pat = get_tv_string_chk(&argvars[0]);
6061
6062 rettv->v_type = VAR_STRING;
6063 rettv->vval.v_string = (pat == NULL)
6064 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6065}
6066
6067/* for VIM_VERSION_ defines */
6068#include "version.h"
6069
6070/*
6071 * "has()" function
6072 */
6073 static void
6074f_has(typval_T *argvars, typval_T *rettv)
6075{
6076 int i;
6077 char_u *name;
6078 int n = FALSE;
6079 static char *(has_list[]) =
6080 {
6081#ifdef AMIGA
6082 "amiga",
6083# ifdef FEAT_ARP
6084 "arp",
6085# endif
6086#endif
6087#ifdef __BEOS__
6088 "beos",
6089#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006090#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006091 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6092 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006093# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006094 "macunix", /* Mac OS X, with the darwin feature */
6095 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006096# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006097#endif
6098#ifdef __QNX__
6099 "qnx",
6100#endif
6101#ifdef UNIX
6102 "unix",
6103#endif
6104#ifdef VMS
6105 "vms",
6106#endif
6107#ifdef WIN32
6108 "win32",
6109#endif
6110#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6111 "win32unix",
6112#endif
6113#if defined(WIN64) || defined(_WIN64)
6114 "win64",
6115#endif
6116#ifdef EBCDIC
6117 "ebcdic",
6118#endif
6119#ifndef CASE_INSENSITIVE_FILENAME
6120 "fname_case",
6121#endif
6122#ifdef HAVE_ACL
6123 "acl",
6124#endif
6125#ifdef FEAT_ARABIC
6126 "arabic",
6127#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006128 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006129#ifdef FEAT_AUTOCHDIR
6130 "autochdir",
6131#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006132#ifdef FEAT_AUTOSERVERNAME
6133 "autoservername",
6134#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006135#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006136 "balloon_eval",
6137# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6138 "balloon_multiline",
6139# endif
6140#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006141#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006142 "balloon_eval_term",
6143#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006144#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6145 "builtin_terms",
6146# ifdef ALL_BUILTIN_TCAPS
6147 "all_builtin_terms",
6148# endif
6149#endif
6150#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6151 || defined(FEAT_GUI_W32) \
6152 || defined(FEAT_GUI_MOTIF))
6153 "browsefilter",
6154#endif
6155#ifdef FEAT_BYTEOFF
6156 "byte_offset",
6157#endif
6158#ifdef FEAT_JOB_CHANNEL
6159 "channel",
6160#endif
6161#ifdef FEAT_CINDENT
6162 "cindent",
6163#endif
6164#ifdef FEAT_CLIENTSERVER
6165 "clientserver",
6166#endif
6167#ifdef FEAT_CLIPBOARD
6168 "clipboard",
6169#endif
6170#ifdef FEAT_CMDL_COMPL
6171 "cmdline_compl",
6172#endif
6173#ifdef FEAT_CMDHIST
6174 "cmdline_hist",
6175#endif
6176#ifdef FEAT_COMMENTS
6177 "comments",
6178#endif
6179#ifdef FEAT_CONCEAL
6180 "conceal",
6181#endif
6182#ifdef FEAT_CRYPT
6183 "cryptv",
6184 "crypt-blowfish",
6185 "crypt-blowfish2",
6186#endif
6187#ifdef FEAT_CSCOPE
6188 "cscope",
6189#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006191#ifdef CURSOR_SHAPE
6192 "cursorshape",
6193#endif
6194#ifdef DEBUG
6195 "debug",
6196#endif
6197#ifdef FEAT_CON_DIALOG
6198 "dialog_con",
6199#endif
6200#ifdef FEAT_GUI_DIALOG
6201 "dialog_gui",
6202#endif
6203#ifdef FEAT_DIFF
6204 "diff",
6205#endif
6206#ifdef FEAT_DIGRAPHS
6207 "digraphs",
6208#endif
6209#ifdef FEAT_DIRECTX
6210 "directx",
6211#endif
6212#ifdef FEAT_DND
6213 "dnd",
6214#endif
6215#ifdef FEAT_EMACS_TAGS
6216 "emacs_tags",
6217#endif
6218 "eval", /* always present, of course! */
6219 "ex_extra", /* graduated feature */
6220#ifdef FEAT_SEARCH_EXTRA
6221 "extra_search",
6222#endif
6223#ifdef FEAT_FKMAP
6224 "farsi",
6225#endif
6226#ifdef FEAT_SEARCHPATH
6227 "file_in_path",
6228#endif
6229#ifdef FEAT_FILTERPIPE
6230 "filterpipe",
6231#endif
6232#ifdef FEAT_FIND_ID
6233 "find_in_path",
6234#endif
6235#ifdef FEAT_FLOAT
6236 "float",
6237#endif
6238#ifdef FEAT_FOLDING
6239 "folding",
6240#endif
6241#ifdef FEAT_FOOTER
6242 "footer",
6243#endif
6244#if !defined(USE_SYSTEM) && defined(UNIX)
6245 "fork",
6246#endif
6247#ifdef FEAT_GETTEXT
6248 "gettext",
6249#endif
6250#ifdef FEAT_GUI
6251 "gui",
6252#endif
6253#ifdef FEAT_GUI_ATHENA
6254# ifdef FEAT_GUI_NEXTAW
6255 "gui_neXtaw",
6256# else
6257 "gui_athena",
6258# endif
6259#endif
6260#ifdef FEAT_GUI_GTK
6261 "gui_gtk",
6262# ifdef USE_GTK3
6263 "gui_gtk3",
6264# else
6265 "gui_gtk2",
6266# endif
6267#endif
6268#ifdef FEAT_GUI_GNOME
6269 "gui_gnome",
6270#endif
6271#ifdef FEAT_GUI_MAC
6272 "gui_mac",
6273#endif
6274#ifdef FEAT_GUI_MOTIF
6275 "gui_motif",
6276#endif
6277#ifdef FEAT_GUI_PHOTON
6278 "gui_photon",
6279#endif
6280#ifdef FEAT_GUI_W32
6281 "gui_win32",
6282#endif
6283#ifdef FEAT_HANGULIN
6284 "hangul_input",
6285#endif
6286#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6287 "iconv",
6288#endif
6289#ifdef FEAT_INS_EXPAND
6290 "insert_expand",
6291#endif
6292#ifdef FEAT_JOB_CHANNEL
6293 "job",
6294#endif
6295#ifdef FEAT_JUMPLIST
6296 "jumplist",
6297#endif
6298#ifdef FEAT_KEYMAP
6299 "keymap",
6300#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006301 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006302#ifdef FEAT_LANGMAP
6303 "langmap",
6304#endif
6305#ifdef FEAT_LIBCALL
6306 "libcall",
6307#endif
6308#ifdef FEAT_LINEBREAK
6309 "linebreak",
6310#endif
6311#ifdef FEAT_LISP
6312 "lispindent",
6313#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006314 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315#ifdef FEAT_LOCALMAP
6316 "localmap",
6317#endif
6318#ifdef FEAT_LUA
6319# ifndef DYNAMIC_LUA
6320 "lua",
6321# endif
6322#endif
6323#ifdef FEAT_MENU
6324 "menu",
6325#endif
6326#ifdef FEAT_SESSION
6327 "mksession",
6328#endif
6329#ifdef FEAT_MODIFY_FNAME
6330 "modify_fname",
6331#endif
6332#ifdef FEAT_MOUSE
6333 "mouse",
6334#endif
6335#ifdef FEAT_MOUSESHAPE
6336 "mouseshape",
6337#endif
6338#if defined(UNIX) || defined(VMS)
6339# ifdef FEAT_MOUSE_DEC
6340 "mouse_dec",
6341# endif
6342# ifdef FEAT_MOUSE_GPM
6343 "mouse_gpm",
6344# endif
6345# ifdef FEAT_MOUSE_JSB
6346 "mouse_jsbterm",
6347# endif
6348# ifdef FEAT_MOUSE_NET
6349 "mouse_netterm",
6350# endif
6351# ifdef FEAT_MOUSE_PTERM
6352 "mouse_pterm",
6353# endif
6354# ifdef FEAT_MOUSE_SGR
6355 "mouse_sgr",
6356# endif
6357# ifdef FEAT_SYSMOUSE
6358 "mouse_sysmouse",
6359# endif
6360# ifdef FEAT_MOUSE_URXVT
6361 "mouse_urxvt",
6362# endif
6363# ifdef FEAT_MOUSE_XTERM
6364 "mouse_xterm",
6365# endif
6366#endif
6367#ifdef FEAT_MBYTE
6368 "multi_byte",
6369#endif
6370#ifdef FEAT_MBYTE_IME
6371 "multi_byte_ime",
6372#endif
6373#ifdef FEAT_MULTI_LANG
6374 "multi_lang",
6375#endif
6376#ifdef FEAT_MZSCHEME
6377#ifndef DYNAMIC_MZSCHEME
6378 "mzscheme",
6379#endif
6380#endif
6381#ifdef FEAT_NUM64
6382 "num64",
6383#endif
6384#ifdef FEAT_OLE
6385 "ole",
6386#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006387#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006388 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006389#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006390#ifdef FEAT_PATH_EXTRA
6391 "path_extra",
6392#endif
6393#ifdef FEAT_PERL
6394#ifndef DYNAMIC_PERL
6395 "perl",
6396#endif
6397#endif
6398#ifdef FEAT_PERSISTENT_UNDO
6399 "persistent_undo",
6400#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006401#if defined(FEAT_PYTHON)
6402 "python_compiled",
6403# if defined(DYNAMIC_PYTHON)
6404 "python_dynamic",
6405# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006407 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006408# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006409#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006410#if defined(FEAT_PYTHON3)
6411 "python3_compiled",
6412# if defined(DYNAMIC_PYTHON3)
6413 "python3_dynamic",
6414# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006416 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006417# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006418#endif
6419#ifdef FEAT_POSTSCRIPT
6420 "postscript",
6421#endif
6422#ifdef FEAT_PRINTER
6423 "printer",
6424#endif
6425#ifdef FEAT_PROFILE
6426 "profile",
6427#endif
6428#ifdef FEAT_RELTIME
6429 "reltime",
6430#endif
6431#ifdef FEAT_QUICKFIX
6432 "quickfix",
6433#endif
6434#ifdef FEAT_RIGHTLEFT
6435 "rightleft",
6436#endif
6437#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6438 "ruby",
6439#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006440 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006441#ifdef FEAT_CMDL_INFO
6442 "showcmd",
6443 "cmdline_info",
6444#endif
6445#ifdef FEAT_SIGNS
6446 "signs",
6447#endif
6448#ifdef FEAT_SMARTINDENT
6449 "smartindent",
6450#endif
6451#ifdef STARTUPTIME
6452 "startuptime",
6453#endif
6454#ifdef FEAT_STL_OPT
6455 "statusline",
6456#endif
6457#ifdef FEAT_SUN_WORKSHOP
6458 "sun_workshop",
6459#endif
6460#ifdef FEAT_NETBEANS_INTG
6461 "netbeans_intg",
6462#endif
6463#ifdef FEAT_SPELL
6464 "spell",
6465#endif
6466#ifdef FEAT_SYN_HL
6467 "syntax",
6468#endif
6469#if defined(USE_SYSTEM) || !defined(UNIX)
6470 "system",
6471#endif
6472#ifdef FEAT_TAG_BINS
6473 "tag_binary",
6474#endif
6475#ifdef FEAT_TAG_OLDSTATIC
6476 "tag_old_static",
6477#endif
6478#ifdef FEAT_TAG_ANYWHITE
6479 "tag_any_white",
6480#endif
6481#ifdef FEAT_TCL
6482# ifndef DYNAMIC_TCL
6483 "tcl",
6484# endif
6485#endif
6486#ifdef FEAT_TERMGUICOLORS
6487 "termguicolors",
6488#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006489#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006490 "terminal",
6491#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006492#ifdef TERMINFO
6493 "terminfo",
6494#endif
6495#ifdef FEAT_TERMRESPONSE
6496 "termresponse",
6497#endif
6498#ifdef FEAT_TEXTOBJ
6499 "textobjects",
6500#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006501#ifdef FEAT_TEXT_PROP
6502 "textprop",
6503#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504#ifdef HAVE_TGETENT
6505 "tgetent",
6506#endif
6507#ifdef FEAT_TIMERS
6508 "timers",
6509#endif
6510#ifdef FEAT_TITLE
6511 "title",
6512#endif
6513#ifdef FEAT_TOOLBAR
6514 "toolbar",
6515#endif
6516#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6517 "unnamedplus",
6518#endif
6519#ifdef FEAT_USR_CMDS
6520 "user-commands", /* was accidentally included in 5.4 */
6521 "user_commands",
6522#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006523#ifdef FEAT_VARTABS
6524 "vartabs",
6525#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526#ifdef FEAT_VIMINFO
6527 "viminfo",
6528#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006529 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006530#ifdef FEAT_VIRTUALEDIT
6531 "virtualedit",
6532#endif
6533 "visual",
6534#ifdef FEAT_VISUALEXTRA
6535 "visualextra",
6536#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006538#ifdef FEAT_VTP
6539 "vtp",
6540#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541#ifdef FEAT_WILDIGN
6542 "wildignore",
6543#endif
6544#ifdef FEAT_WILDMENU
6545 "wildmenu",
6546#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006547 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006548#ifdef FEAT_WAK
6549 "winaltkeys",
6550#endif
6551#ifdef FEAT_WRITEBACKUP
6552 "writebackup",
6553#endif
6554#ifdef FEAT_XIM
6555 "xim",
6556#endif
6557#ifdef FEAT_XFONTSET
6558 "xfontset",
6559#endif
6560#ifdef FEAT_XPM_W32
6561 "xpm",
6562 "xpm_w32", /* for backward compatibility */
6563#else
6564# if defined(HAVE_XPM)
6565 "xpm",
6566# endif
6567#endif
6568#ifdef USE_XSMP
6569 "xsmp",
6570#endif
6571#ifdef USE_XSMP_INTERACT
6572 "xsmp_interact",
6573#endif
6574#ifdef FEAT_XCLIPBOARD
6575 "xterm_clipboard",
6576#endif
6577#ifdef FEAT_XTERM_SAVE
6578 "xterm_save",
6579#endif
6580#if defined(UNIX) && defined(FEAT_X11)
6581 "X11",
6582#endif
6583 NULL
6584 };
6585
6586 name = get_tv_string(&argvars[0]);
6587 for (i = 0; has_list[i] != NULL; ++i)
6588 if (STRICMP(name, has_list[i]) == 0)
6589 {
6590 n = TRUE;
6591 break;
6592 }
6593
6594 if (n == FALSE)
6595 {
6596 if (STRNICMP(name, "patch", 5) == 0)
6597 {
6598 if (name[5] == '-'
6599 && STRLEN(name) >= 11
6600 && vim_isdigit(name[6])
6601 && vim_isdigit(name[8])
6602 && vim_isdigit(name[10]))
6603 {
6604 int major = atoi((char *)name + 6);
6605 int minor = atoi((char *)name + 8);
6606
6607 /* Expect "patch-9.9.01234". */
6608 n = (major < VIM_VERSION_MAJOR
6609 || (major == VIM_VERSION_MAJOR
6610 && (minor < VIM_VERSION_MINOR
6611 || (minor == VIM_VERSION_MINOR
6612 && has_patch(atoi((char *)name + 10))))));
6613 }
6614 else
6615 n = has_patch(atoi((char *)name + 5));
6616 }
6617 else if (STRICMP(name, "vim_starting") == 0)
6618 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006619 else if (STRICMP(name, "ttyin") == 0)
6620 n = mch_input_isatty();
6621 else if (STRICMP(name, "ttyout") == 0)
6622 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006623#ifdef FEAT_MBYTE
6624 else if (STRICMP(name, "multi_byte_encoding") == 0)
6625 n = has_mbyte;
6626#endif
6627#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6628 else if (STRICMP(name, "balloon_multiline") == 0)
6629 n = multiline_balloon_available();
6630#endif
6631#ifdef DYNAMIC_TCL
6632 else if (STRICMP(name, "tcl") == 0)
6633 n = tcl_enabled(FALSE);
6634#endif
6635#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6636 else if (STRICMP(name, "iconv") == 0)
6637 n = iconv_enabled(FALSE);
6638#endif
6639#ifdef DYNAMIC_LUA
6640 else if (STRICMP(name, "lua") == 0)
6641 n = lua_enabled(FALSE);
6642#endif
6643#ifdef DYNAMIC_MZSCHEME
6644 else if (STRICMP(name, "mzscheme") == 0)
6645 n = mzscheme_enabled(FALSE);
6646#endif
6647#ifdef DYNAMIC_RUBY
6648 else if (STRICMP(name, "ruby") == 0)
6649 n = ruby_enabled(FALSE);
6650#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651#ifdef DYNAMIC_PYTHON
6652 else if (STRICMP(name, "python") == 0)
6653 n = python_enabled(FALSE);
6654#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006655#ifdef DYNAMIC_PYTHON3
6656 else if (STRICMP(name, "python3") == 0)
6657 n = python3_enabled(FALSE);
6658#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006659#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6660 else if (STRICMP(name, "pythonx") == 0)
6661 {
6662# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6663 if (p_pyx == 0)
6664 n = python3_enabled(FALSE) || python_enabled(FALSE);
6665 else if (p_pyx == 3)
6666 n = python3_enabled(FALSE);
6667 else if (p_pyx == 2)
6668 n = python_enabled(FALSE);
6669# elif defined(DYNAMIC_PYTHON)
6670 n = python_enabled(FALSE);
6671# elif defined(DYNAMIC_PYTHON3)
6672 n = python3_enabled(FALSE);
6673# endif
6674 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675#endif
6676#ifdef DYNAMIC_PERL
6677 else if (STRICMP(name, "perl") == 0)
6678 n = perl_enabled(FALSE);
6679#endif
6680#ifdef FEAT_GUI
6681 else if (STRICMP(name, "gui_running") == 0)
6682 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683# ifdef FEAT_BROWSE
6684 else if (STRICMP(name, "browse") == 0)
6685 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6686# endif
6687#endif
6688#ifdef FEAT_SYN_HL
6689 else if (STRICMP(name, "syntax_items") == 0)
6690 n = syntax_present(curwin);
6691#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006692#ifdef FEAT_VTP
6693 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006694 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006695#endif
6696#ifdef FEAT_NETBEANS_INTG
6697 else if (STRICMP(name, "netbeans_enabled") == 0)
6698 n = netbeans_active();
6699#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006700#if defined(FEAT_TERMINAL) && defined(WIN3264)
6701 else if (STRICMP(name, "terminal") == 0)
6702 n = terminal_enabled();
6703#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006704 }
6705
6706 rettv->vval.v_number = n;
6707}
6708
6709/*
6710 * "has_key()" function
6711 */
6712 static void
6713f_has_key(typval_T *argvars, typval_T *rettv)
6714{
6715 if (argvars[0].v_type != VAR_DICT)
6716 {
6717 EMSG(_(e_dictreq));
6718 return;
6719 }
6720 if (argvars[0].vval.v_dict == NULL)
6721 return;
6722
6723 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6724 get_tv_string(&argvars[1]), -1) != NULL;
6725}
6726
6727/*
6728 * "haslocaldir()" function
6729 */
6730 static void
6731f_haslocaldir(typval_T *argvars, typval_T *rettv)
6732{
6733 win_T *wp = NULL;
6734
6735 wp = find_tabwin(&argvars[0], &argvars[1]);
6736 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6737}
6738
6739/*
6740 * "hasmapto()" function
6741 */
6742 static void
6743f_hasmapto(typval_T *argvars, typval_T *rettv)
6744{
6745 char_u *name;
6746 char_u *mode;
6747 char_u buf[NUMBUFLEN];
6748 int abbr = FALSE;
6749
6750 name = get_tv_string(&argvars[0]);
6751 if (argvars[1].v_type == VAR_UNKNOWN)
6752 mode = (char_u *)"nvo";
6753 else
6754 {
6755 mode = get_tv_string_buf(&argvars[1], buf);
6756 if (argvars[2].v_type != VAR_UNKNOWN)
6757 abbr = (int)get_tv_number(&argvars[2]);
6758 }
6759
6760 if (map_to_exists(name, mode, abbr))
6761 rettv->vval.v_number = TRUE;
6762 else
6763 rettv->vval.v_number = FALSE;
6764}
6765
6766/*
6767 * "histadd()" function
6768 */
6769 static void
6770f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6771{
6772#ifdef FEAT_CMDHIST
6773 int histype;
6774 char_u *str;
6775 char_u buf[NUMBUFLEN];
6776#endif
6777
6778 rettv->vval.v_number = FALSE;
6779 if (check_restricted() || check_secure())
6780 return;
6781#ifdef FEAT_CMDHIST
6782 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6783 histype = str != NULL ? get_histtype(str) : -1;
6784 if (histype >= 0)
6785 {
6786 str = get_tv_string_buf(&argvars[1], buf);
6787 if (*str != NUL)
6788 {
6789 init_history();
6790 add_to_history(histype, str, FALSE, NUL);
6791 rettv->vval.v_number = TRUE;
6792 return;
6793 }
6794 }
6795#endif
6796}
6797
6798/*
6799 * "histdel()" function
6800 */
6801 static void
6802f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6803{
6804#ifdef FEAT_CMDHIST
6805 int n;
6806 char_u buf[NUMBUFLEN];
6807 char_u *str;
6808
6809 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6810 if (str == NULL)
6811 n = 0;
6812 else if (argvars[1].v_type == VAR_UNKNOWN)
6813 /* only one argument: clear entire history */
6814 n = clr_history(get_histtype(str));
6815 else if (argvars[1].v_type == VAR_NUMBER)
6816 /* index given: remove that entry */
6817 n = del_history_idx(get_histtype(str),
6818 (int)get_tv_number(&argvars[1]));
6819 else
6820 /* string given: remove all matching entries */
6821 n = del_history_entry(get_histtype(str),
6822 get_tv_string_buf(&argvars[1], buf));
6823 rettv->vval.v_number = n;
6824#endif
6825}
6826
6827/*
6828 * "histget()" function
6829 */
6830 static void
6831f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6832{
6833#ifdef FEAT_CMDHIST
6834 int type;
6835 int idx;
6836 char_u *str;
6837
6838 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6839 if (str == NULL)
6840 rettv->vval.v_string = NULL;
6841 else
6842 {
6843 type = get_histtype(str);
6844 if (argvars[1].v_type == VAR_UNKNOWN)
6845 idx = get_history_idx(type);
6846 else
6847 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6848 /* -1 on type error */
6849 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6850 }
6851#else
6852 rettv->vval.v_string = NULL;
6853#endif
6854 rettv->v_type = VAR_STRING;
6855}
6856
6857/*
6858 * "histnr()" function
6859 */
6860 static void
6861f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6862{
6863 int i;
6864
6865#ifdef FEAT_CMDHIST
6866 char_u *history = get_tv_string_chk(&argvars[0]);
6867
6868 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6869 if (i >= HIST_CMD && i < HIST_COUNT)
6870 i = get_history_idx(i);
6871 else
6872#endif
6873 i = -1;
6874 rettv->vval.v_number = i;
6875}
6876
6877/*
6878 * "highlightID(name)" function
6879 */
6880 static void
6881f_hlID(typval_T *argvars, typval_T *rettv)
6882{
6883 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6884}
6885
6886/*
6887 * "highlight_exists()" function
6888 */
6889 static void
6890f_hlexists(typval_T *argvars, typval_T *rettv)
6891{
6892 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6893}
6894
6895/*
6896 * "hostname()" function
6897 */
6898 static void
6899f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6900{
6901 char_u hostname[256];
6902
6903 mch_get_host_name(hostname, 256);
6904 rettv->v_type = VAR_STRING;
6905 rettv->vval.v_string = vim_strsave(hostname);
6906}
6907
6908/*
6909 * iconv() function
6910 */
6911 static void
6912f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6913{
6914#ifdef FEAT_MBYTE
6915 char_u buf1[NUMBUFLEN];
6916 char_u buf2[NUMBUFLEN];
6917 char_u *from, *to, *str;
6918 vimconv_T vimconv;
6919#endif
6920
6921 rettv->v_type = VAR_STRING;
6922 rettv->vval.v_string = NULL;
6923
6924#ifdef FEAT_MBYTE
6925 str = get_tv_string(&argvars[0]);
6926 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6927 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6928 vimconv.vc_type = CONV_NONE;
6929 convert_setup(&vimconv, from, to);
6930
6931 /* If the encodings are equal, no conversion needed. */
6932 if (vimconv.vc_type == CONV_NONE)
6933 rettv->vval.v_string = vim_strsave(str);
6934 else
6935 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6936
6937 convert_setup(&vimconv, NULL, NULL);
6938 vim_free(from);
6939 vim_free(to);
6940#endif
6941}
6942
6943/*
6944 * "indent()" function
6945 */
6946 static void
6947f_indent(typval_T *argvars, typval_T *rettv)
6948{
6949 linenr_T lnum;
6950
6951 lnum = get_tv_lnum(argvars);
6952 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6953 rettv->vval.v_number = get_indent_lnum(lnum);
6954 else
6955 rettv->vval.v_number = -1;
6956}
6957
6958/*
6959 * "index()" function
6960 */
6961 static void
6962f_index(typval_T *argvars, typval_T *rettv)
6963{
6964 list_T *l;
6965 listitem_T *item;
6966 long idx = 0;
6967 int ic = FALSE;
6968
6969 rettv->vval.v_number = -1;
6970 if (argvars[0].v_type != VAR_LIST)
6971 {
6972 EMSG(_(e_listreq));
6973 return;
6974 }
6975 l = argvars[0].vval.v_list;
6976 if (l != NULL)
6977 {
6978 item = l->lv_first;
6979 if (argvars[2].v_type != VAR_UNKNOWN)
6980 {
6981 int error = FALSE;
6982
6983 /* Start at specified item. Use the cached index that list_find()
6984 * sets, so that a negative number also works. */
6985 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6986 idx = l->lv_idx;
6987 if (argvars[3].v_type != VAR_UNKNOWN)
6988 ic = (int)get_tv_number_chk(&argvars[3], &error);
6989 if (error)
6990 item = NULL;
6991 }
6992
6993 for ( ; item != NULL; item = item->li_next, ++idx)
6994 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6995 {
6996 rettv->vval.v_number = idx;
6997 break;
6998 }
6999 }
7000}
7001
7002static int inputsecret_flag = 0;
7003
7004/*
7005 * "input()" function
7006 * Also handles inputsecret() when inputsecret is set.
7007 */
7008 static void
7009f_input(typval_T *argvars, typval_T *rettv)
7010{
7011 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7012}
7013
7014/*
7015 * "inputdialog()" function
7016 */
7017 static void
7018f_inputdialog(typval_T *argvars, typval_T *rettv)
7019{
7020#if defined(FEAT_GUI_TEXTDIALOG)
7021 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7022 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7023 {
7024 char_u *message;
7025 char_u buf[NUMBUFLEN];
7026 char_u *defstr = (char_u *)"";
7027
7028 message = get_tv_string_chk(&argvars[0]);
7029 if (argvars[1].v_type != VAR_UNKNOWN
7030 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
7031 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7032 else
7033 IObuff[0] = NUL;
7034 if (message != NULL && defstr != NULL
7035 && do_dialog(VIM_QUESTION, NULL, message,
7036 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7037 rettv->vval.v_string = vim_strsave(IObuff);
7038 else
7039 {
7040 if (message != NULL && defstr != NULL
7041 && argvars[1].v_type != VAR_UNKNOWN
7042 && argvars[2].v_type != VAR_UNKNOWN)
7043 rettv->vval.v_string = vim_strsave(
7044 get_tv_string_buf(&argvars[2], buf));
7045 else
7046 rettv->vval.v_string = NULL;
7047 }
7048 rettv->v_type = VAR_STRING;
7049 }
7050 else
7051#endif
7052 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7053}
7054
7055/*
7056 * "inputlist()" function
7057 */
7058 static void
7059f_inputlist(typval_T *argvars, typval_T *rettv)
7060{
7061 listitem_T *li;
7062 int selected;
7063 int mouse_used;
7064
7065#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007066 /* While starting up, there is no place to enter text. When running tests
7067 * with --not-a-term we assume feedkeys() will be used. */
7068 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069 return;
7070#endif
7071 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7072 {
7073 EMSG2(_(e_listarg), "inputlist()");
7074 return;
7075 }
7076
7077 msg_start();
7078 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7079 lines_left = Rows; /* avoid more prompt */
7080 msg_scroll = TRUE;
7081 msg_clr_eos();
7082
7083 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7084 {
7085 msg_puts(get_tv_string(&li->li_tv));
7086 msg_putchar('\n');
7087 }
7088
7089 /* Ask for choice. */
7090 selected = prompt_for_number(&mouse_used);
7091 if (mouse_used)
7092 selected -= lines_left;
7093
7094 rettv->vval.v_number = selected;
7095}
7096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007097static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7098
7099/*
7100 * "inputrestore()" function
7101 */
7102 static void
7103f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7104{
7105 if (ga_userinput.ga_len > 0)
7106 {
7107 --ga_userinput.ga_len;
7108 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7109 + ga_userinput.ga_len);
7110 /* default return is zero == OK */
7111 }
7112 else if (p_verbose > 1)
7113 {
7114 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
7115 rettv->vval.v_number = 1; /* Failed */
7116 }
7117}
7118
7119/*
7120 * "inputsave()" function
7121 */
7122 static void
7123f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7124{
7125 /* Add an entry to the stack of typeahead storage. */
7126 if (ga_grow(&ga_userinput, 1) == OK)
7127 {
7128 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7129 + ga_userinput.ga_len);
7130 ++ga_userinput.ga_len;
7131 /* default return is zero == OK */
7132 }
7133 else
7134 rettv->vval.v_number = 1; /* Failed */
7135}
7136
7137/*
7138 * "inputsecret()" function
7139 */
7140 static void
7141f_inputsecret(typval_T *argvars, typval_T *rettv)
7142{
7143 ++cmdline_star;
7144 ++inputsecret_flag;
7145 f_input(argvars, rettv);
7146 --cmdline_star;
7147 --inputsecret_flag;
7148}
7149
7150/*
7151 * "insert()" function
7152 */
7153 static void
7154f_insert(typval_T *argvars, typval_T *rettv)
7155{
7156 long before = 0;
7157 listitem_T *item;
7158 list_T *l;
7159 int error = FALSE;
7160
7161 if (argvars[0].v_type != VAR_LIST)
7162 EMSG2(_(e_listarg), "insert()");
7163 else if ((l = argvars[0].vval.v_list) != NULL
7164 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7165 {
7166 if (argvars[2].v_type != VAR_UNKNOWN)
7167 before = (long)get_tv_number_chk(&argvars[2], &error);
7168 if (error)
7169 return; /* type error; errmsg already given */
7170
7171 if (before == l->lv_len)
7172 item = NULL;
7173 else
7174 {
7175 item = list_find(l, before);
7176 if (item == NULL)
7177 {
7178 EMSGN(_(e_listidx), before);
7179 l = NULL;
7180 }
7181 }
7182 if (l != NULL)
7183 {
7184 list_insert_tv(l, &argvars[1], item);
7185 copy_tv(&argvars[0], rettv);
7186 }
7187 }
7188}
7189
7190/*
7191 * "invert(expr)" function
7192 */
7193 static void
7194f_invert(typval_T *argvars, typval_T *rettv)
7195{
7196 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
7197}
7198
7199/*
7200 * "isdirectory()" function
7201 */
7202 static void
7203f_isdirectory(typval_T *argvars, typval_T *rettv)
7204{
7205 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
7206}
7207
7208/*
7209 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7210 * or it refers to a List or Dictionary that is locked.
7211 */
7212 static int
7213tv_islocked(typval_T *tv)
7214{
7215 return (tv->v_lock & VAR_LOCKED)
7216 || (tv->v_type == VAR_LIST
7217 && tv->vval.v_list != NULL
7218 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7219 || (tv->v_type == VAR_DICT
7220 && tv->vval.v_dict != NULL
7221 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7222}
7223
7224/*
7225 * "islocked()" function
7226 */
7227 static void
7228f_islocked(typval_T *argvars, typval_T *rettv)
7229{
7230 lval_T lv;
7231 char_u *end;
7232 dictitem_T *di;
7233
7234 rettv->vval.v_number = -1;
7235 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007236 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007237 if (end != NULL && lv.ll_name != NULL)
7238 {
7239 if (*end != NUL)
7240 EMSG(_(e_trailing));
7241 else
7242 {
7243 if (lv.ll_tv == NULL)
7244 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007245 di = find_var(lv.ll_name, NULL, TRUE);
7246 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007248 /* Consider a variable locked when:
7249 * 1. the variable itself is locked
7250 * 2. the value of the variable is locked.
7251 * 3. the List or Dict value is locked.
7252 */
7253 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7254 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 }
7256 }
7257 else if (lv.ll_range)
7258 EMSG(_("E786: Range not allowed"));
7259 else if (lv.ll_newkey != NULL)
7260 EMSG2(_(e_dictkey), lv.ll_newkey);
7261 else if (lv.ll_list != NULL)
7262 /* List item. */
7263 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7264 else
7265 /* Dictionary item. */
7266 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7267 }
7268 }
7269
7270 clear_lval(&lv);
7271}
7272
7273#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7274/*
7275 * "isnan()" function
7276 */
7277 static void
7278f_isnan(typval_T *argvars, typval_T *rettv)
7279{
7280 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7281 && isnan(argvars[0].vval.v_float);
7282}
7283#endif
7284
7285/*
7286 * "items(dict)" function
7287 */
7288 static void
7289f_items(typval_T *argvars, typval_T *rettv)
7290{
7291 dict_list(argvars, rettv, 2);
7292}
7293
7294#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7295/*
7296 * Get the job from the argument.
7297 * Returns NULL if the job is invalid.
7298 */
7299 static job_T *
7300get_job_arg(typval_T *tv)
7301{
7302 job_T *job;
7303
7304 if (tv->v_type != VAR_JOB)
7305 {
7306 EMSG2(_(e_invarg2), get_tv_string(tv));
7307 return NULL;
7308 }
7309 job = tv->vval.v_job;
7310
7311 if (job == NULL)
7312 EMSG(_("E916: not a valid job"));
7313 return job;
7314}
7315
7316/*
7317 * "job_getchannel()" function
7318 */
7319 static void
7320f_job_getchannel(typval_T *argvars, typval_T *rettv)
7321{
7322 job_T *job = get_job_arg(&argvars[0]);
7323
7324 if (job != NULL)
7325 {
7326 rettv->v_type = VAR_CHANNEL;
7327 rettv->vval.v_channel = job->jv_channel;
7328 if (job->jv_channel != NULL)
7329 ++job->jv_channel->ch_refcount;
7330 }
7331}
7332
7333/*
7334 * "job_info()" function
7335 */
7336 static void
7337f_job_info(typval_T *argvars, typval_T *rettv)
7338{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007339 if (argvars[0].v_type != VAR_UNKNOWN)
7340 {
7341 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007343 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7344 job_info(job, rettv->vval.v_dict);
7345 }
7346 else if (rettv_list_alloc(rettv) == OK)
7347 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007348}
7349
7350/*
7351 * "job_setoptions()" function
7352 */
7353 static void
7354f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7355{
7356 job_T *job = get_job_arg(&argvars[0]);
7357 jobopt_T opt;
7358
7359 if (job == NULL)
7360 return;
7361 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007362 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007363 job_set_options(job, &opt);
7364 free_job_options(&opt);
7365}
7366
7367/*
7368 * "job_start()" function
7369 */
7370 static void
7371f_job_start(typval_T *argvars, typval_T *rettv)
7372{
7373 rettv->v_type = VAR_JOB;
7374 if (check_restricted() || check_secure())
7375 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007376 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377}
7378
7379/*
7380 * "job_status()" function
7381 */
7382 static void
7383f_job_status(typval_T *argvars, typval_T *rettv)
7384{
7385 job_T *job = get_job_arg(&argvars[0]);
7386
7387 if (job != NULL)
7388 {
7389 rettv->v_type = VAR_STRING;
7390 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7391 }
7392}
7393
7394/*
7395 * "job_stop()" function
7396 */
7397 static void
7398f_job_stop(typval_T *argvars, typval_T *rettv)
7399{
7400 job_T *job = get_job_arg(&argvars[0]);
7401
7402 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007403 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007404}
7405#endif
7406
7407/*
7408 * "join()" function
7409 */
7410 static void
7411f_join(typval_T *argvars, typval_T *rettv)
7412{
7413 garray_T ga;
7414 char_u *sep;
7415
7416 if (argvars[0].v_type != VAR_LIST)
7417 {
7418 EMSG(_(e_listreq));
7419 return;
7420 }
7421 if (argvars[0].vval.v_list == NULL)
7422 return;
7423 if (argvars[1].v_type == VAR_UNKNOWN)
7424 sep = (char_u *)" ";
7425 else
7426 sep = get_tv_string_chk(&argvars[1]);
7427
7428 rettv->v_type = VAR_STRING;
7429
7430 if (sep != NULL)
7431 {
7432 ga_init2(&ga, (int)sizeof(char), 80);
7433 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7434 ga_append(&ga, NUL);
7435 rettv->vval.v_string = (char_u *)ga.ga_data;
7436 }
7437 else
7438 rettv->vval.v_string = NULL;
7439}
7440
7441/*
7442 * "js_decode()" function
7443 */
7444 static void
7445f_js_decode(typval_T *argvars, typval_T *rettv)
7446{
7447 js_read_T reader;
7448
7449 reader.js_buf = get_tv_string(&argvars[0]);
7450 reader.js_fill = NULL;
7451 reader.js_used = 0;
7452 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7453 EMSG(_(e_invarg));
7454}
7455
7456/*
7457 * "js_encode()" function
7458 */
7459 static void
7460f_js_encode(typval_T *argvars, typval_T *rettv)
7461{
7462 rettv->v_type = VAR_STRING;
7463 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7464}
7465
7466/*
7467 * "json_decode()" function
7468 */
7469 static void
7470f_json_decode(typval_T *argvars, typval_T *rettv)
7471{
7472 js_read_T reader;
7473
7474 reader.js_buf = get_tv_string(&argvars[0]);
7475 reader.js_fill = NULL;
7476 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007477 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478}
7479
7480/*
7481 * "json_encode()" function
7482 */
7483 static void
7484f_json_encode(typval_T *argvars, typval_T *rettv)
7485{
7486 rettv->v_type = VAR_STRING;
7487 rettv->vval.v_string = json_encode(&argvars[0], 0);
7488}
7489
7490/*
7491 * "keys()" function
7492 */
7493 static void
7494f_keys(typval_T *argvars, typval_T *rettv)
7495{
7496 dict_list(argvars, rettv, 0);
7497}
7498
7499/*
7500 * "last_buffer_nr()" function.
7501 */
7502 static void
7503f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7504{
7505 int n = 0;
7506 buf_T *buf;
7507
Bram Moolenaar29323592016-07-24 22:04:11 +02007508 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007509 if (n < buf->b_fnum)
7510 n = buf->b_fnum;
7511
7512 rettv->vval.v_number = n;
7513}
7514
7515/*
7516 * "len()" function
7517 */
7518 static void
7519f_len(typval_T *argvars, typval_T *rettv)
7520{
7521 switch (argvars[0].v_type)
7522 {
7523 case VAR_STRING:
7524 case VAR_NUMBER:
7525 rettv->vval.v_number = (varnumber_T)STRLEN(
7526 get_tv_string(&argvars[0]));
7527 break;
7528 case VAR_LIST:
7529 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7530 break;
7531 case VAR_DICT:
7532 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7533 break;
7534 case VAR_UNKNOWN:
7535 case VAR_SPECIAL:
7536 case VAR_FLOAT:
7537 case VAR_FUNC:
7538 case VAR_PARTIAL:
7539 case VAR_JOB:
7540 case VAR_CHANNEL:
7541 EMSG(_("E701: Invalid type for len()"));
7542 break;
7543 }
7544}
7545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007547libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007548{
7549#ifdef FEAT_LIBCALL
7550 char_u *string_in;
7551 char_u **string_result;
7552 int nr_result;
7553#endif
7554
7555 rettv->v_type = type;
7556 if (type != VAR_NUMBER)
7557 rettv->vval.v_string = NULL;
7558
7559 if (check_restricted() || check_secure())
7560 return;
7561
7562#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007563 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007564 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7565 {
7566 string_in = NULL;
7567 if (argvars[2].v_type == VAR_STRING)
7568 string_in = argvars[2].vval.v_string;
7569 if (type == VAR_NUMBER)
7570 string_result = NULL;
7571 else
7572 string_result = &rettv->vval.v_string;
7573 if (mch_libcall(argvars[0].vval.v_string,
7574 argvars[1].vval.v_string,
7575 string_in,
7576 argvars[2].vval.v_number,
7577 string_result,
7578 &nr_result) == OK
7579 && type == VAR_NUMBER)
7580 rettv->vval.v_number = nr_result;
7581 }
7582#endif
7583}
7584
7585/*
7586 * "libcall()" function
7587 */
7588 static void
7589f_libcall(typval_T *argvars, typval_T *rettv)
7590{
7591 libcall_common(argvars, rettv, VAR_STRING);
7592}
7593
7594/*
7595 * "libcallnr()" function
7596 */
7597 static void
7598f_libcallnr(typval_T *argvars, typval_T *rettv)
7599{
7600 libcall_common(argvars, rettv, VAR_NUMBER);
7601}
7602
7603/*
7604 * "line(string)" function
7605 */
7606 static void
7607f_line(typval_T *argvars, typval_T *rettv)
7608{
7609 linenr_T lnum = 0;
7610 pos_T *fp;
7611 int fnum;
7612
7613 fp = var2fpos(&argvars[0], TRUE, &fnum);
7614 if (fp != NULL)
7615 lnum = fp->lnum;
7616 rettv->vval.v_number = lnum;
7617}
7618
7619/*
7620 * "line2byte(lnum)" function
7621 */
7622 static void
7623f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7624{
7625#ifndef FEAT_BYTEOFF
7626 rettv->vval.v_number = -1;
7627#else
7628 linenr_T lnum;
7629
7630 lnum = get_tv_lnum(argvars);
7631 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7632 rettv->vval.v_number = -1;
7633 else
7634 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7635 if (rettv->vval.v_number >= 0)
7636 ++rettv->vval.v_number;
7637#endif
7638}
7639
7640/*
7641 * "lispindent(lnum)" function
7642 */
7643 static void
7644f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7645{
7646#ifdef FEAT_LISP
7647 pos_T pos;
7648 linenr_T lnum;
7649
7650 pos = curwin->w_cursor;
7651 lnum = get_tv_lnum(argvars);
7652 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7653 {
7654 curwin->w_cursor.lnum = lnum;
7655 rettv->vval.v_number = get_lisp_indent();
7656 curwin->w_cursor = pos;
7657 }
7658 else
7659#endif
7660 rettv->vval.v_number = -1;
7661}
7662
7663/*
7664 * "localtime()" function
7665 */
7666 static void
7667f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7668{
7669 rettv->vval.v_number = (varnumber_T)time(NULL);
7670}
7671
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 static void
7673get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7674{
7675 char_u *keys;
7676 char_u *which;
7677 char_u buf[NUMBUFLEN];
7678 char_u *keys_buf = NULL;
7679 char_u *rhs;
7680 int mode;
7681 int abbr = FALSE;
7682 int get_dict = FALSE;
7683 mapblock_T *mp;
7684 int buffer_local;
7685
7686 /* return empty string for failure */
7687 rettv->v_type = VAR_STRING;
7688 rettv->vval.v_string = NULL;
7689
7690 keys = get_tv_string(&argvars[0]);
7691 if (*keys == NUL)
7692 return;
7693
7694 if (argvars[1].v_type != VAR_UNKNOWN)
7695 {
7696 which = get_tv_string_buf_chk(&argvars[1], buf);
7697 if (argvars[2].v_type != VAR_UNKNOWN)
7698 {
7699 abbr = (int)get_tv_number(&argvars[2]);
7700 if (argvars[3].v_type != VAR_UNKNOWN)
7701 get_dict = (int)get_tv_number(&argvars[3]);
7702 }
7703 }
7704 else
7705 which = (char_u *)"";
7706 if (which == NULL)
7707 return;
7708
7709 mode = get_map_mode(&which, 0);
7710
7711 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7712 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7713 vim_free(keys_buf);
7714
7715 if (!get_dict)
7716 {
7717 /* Return a string. */
7718 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007719 {
7720 if (*rhs == NUL)
7721 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7722 else
7723 rettv->vval.v_string = str2special_save(rhs, FALSE);
7724 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725
7726 }
7727 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7728 {
7729 /* Return a dictionary. */
7730 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7731 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7732 dict_T *dict = rettv->vval.v_dict;
7733
Bram Moolenaare0be1672018-07-08 16:50:37 +02007734 dict_add_string(dict, "lhs", lhs);
7735 dict_add_string(dict, "rhs", mp->m_orig_str);
7736 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7737 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7738 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007739 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7740 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007741 dict_add_number(dict, "buffer", (long)buffer_local);
7742 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7743 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744
7745 vim_free(lhs);
7746 vim_free(mapmode);
7747 }
7748}
7749
7750#ifdef FEAT_FLOAT
7751/*
7752 * "log()" function
7753 */
7754 static void
7755f_log(typval_T *argvars, typval_T *rettv)
7756{
7757 float_T f = 0.0;
7758
7759 rettv->v_type = VAR_FLOAT;
7760 if (get_float_arg(argvars, &f) == OK)
7761 rettv->vval.v_float = log(f);
7762 else
7763 rettv->vval.v_float = 0.0;
7764}
7765
7766/*
7767 * "log10()" function
7768 */
7769 static void
7770f_log10(typval_T *argvars, typval_T *rettv)
7771{
7772 float_T f = 0.0;
7773
7774 rettv->v_type = VAR_FLOAT;
7775 if (get_float_arg(argvars, &f) == OK)
7776 rettv->vval.v_float = log10(f);
7777 else
7778 rettv->vval.v_float = 0.0;
7779}
7780#endif
7781
7782#ifdef FEAT_LUA
7783/*
7784 * "luaeval()" function
7785 */
7786 static void
7787f_luaeval(typval_T *argvars, typval_T *rettv)
7788{
7789 char_u *str;
7790 char_u buf[NUMBUFLEN];
7791
7792 str = get_tv_string_buf(&argvars[0], buf);
7793 do_luaeval(str, argvars + 1, rettv);
7794}
7795#endif
7796
7797/*
7798 * "map()" function
7799 */
7800 static void
7801f_map(typval_T *argvars, typval_T *rettv)
7802{
7803 filter_map(argvars, rettv, TRUE);
7804}
7805
7806/*
7807 * "maparg()" function
7808 */
7809 static void
7810f_maparg(typval_T *argvars, typval_T *rettv)
7811{
7812 get_maparg(argvars, rettv, TRUE);
7813}
7814
7815/*
7816 * "mapcheck()" function
7817 */
7818 static void
7819f_mapcheck(typval_T *argvars, typval_T *rettv)
7820{
7821 get_maparg(argvars, rettv, FALSE);
7822}
7823
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007824typedef enum
7825{
7826 MATCH_END, /* matchend() */
7827 MATCH_MATCH, /* match() */
7828 MATCH_STR, /* matchstr() */
7829 MATCH_LIST, /* matchlist() */
7830 MATCH_POS /* matchstrpos() */
7831} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832
7833 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007834find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007835{
7836 char_u *str = NULL;
7837 long len = 0;
7838 char_u *expr = NULL;
7839 char_u *pat;
7840 regmatch_T regmatch;
7841 char_u patbuf[NUMBUFLEN];
7842 char_u strbuf[NUMBUFLEN];
7843 char_u *save_cpo;
7844 long start = 0;
7845 long nth = 1;
7846 colnr_T startcol = 0;
7847 int match = 0;
7848 list_T *l = NULL;
7849 listitem_T *li = NULL;
7850 long idx = 0;
7851 char_u *tofree = NULL;
7852
7853 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7854 save_cpo = p_cpo;
7855 p_cpo = (char_u *)"";
7856
7857 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007858 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007860 /* type MATCH_LIST: return empty list when there are no matches.
7861 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007862 if (rettv_list_alloc(rettv) == FAIL)
7863 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007864 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007865 && (list_append_string(rettv->vval.v_list,
7866 (char_u *)"", 0) == FAIL
7867 || list_append_number(rettv->vval.v_list,
7868 (varnumber_T)-1) == FAIL
7869 || list_append_number(rettv->vval.v_list,
7870 (varnumber_T)-1) == FAIL
7871 || list_append_number(rettv->vval.v_list,
7872 (varnumber_T)-1) == FAIL))
7873 {
7874 list_free(rettv->vval.v_list);
7875 rettv->vval.v_list = NULL;
7876 goto theend;
7877 }
7878 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007879 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 {
7881 rettv->v_type = VAR_STRING;
7882 rettv->vval.v_string = NULL;
7883 }
7884
7885 if (argvars[0].v_type == VAR_LIST)
7886 {
7887 if ((l = argvars[0].vval.v_list) == NULL)
7888 goto theend;
7889 li = l->lv_first;
7890 }
7891 else
7892 {
7893 expr = str = get_tv_string(&argvars[0]);
7894 len = (long)STRLEN(str);
7895 }
7896
7897 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7898 if (pat == NULL)
7899 goto theend;
7900
7901 if (argvars[2].v_type != VAR_UNKNOWN)
7902 {
7903 int error = FALSE;
7904
7905 start = (long)get_tv_number_chk(&argvars[2], &error);
7906 if (error)
7907 goto theend;
7908 if (l != NULL)
7909 {
7910 li = list_find(l, start);
7911 if (li == NULL)
7912 goto theend;
7913 idx = l->lv_idx; /* use the cached index */
7914 }
7915 else
7916 {
7917 if (start < 0)
7918 start = 0;
7919 if (start > len)
7920 goto theend;
7921 /* When "count" argument is there ignore matches before "start",
7922 * otherwise skip part of the string. Differs when pattern is "^"
7923 * or "\<". */
7924 if (argvars[3].v_type != VAR_UNKNOWN)
7925 startcol = start;
7926 else
7927 {
7928 str += start;
7929 len -= start;
7930 }
7931 }
7932
7933 if (argvars[3].v_type != VAR_UNKNOWN)
7934 nth = (long)get_tv_number_chk(&argvars[3], &error);
7935 if (error)
7936 goto theend;
7937 }
7938
7939 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7940 if (regmatch.regprog != NULL)
7941 {
7942 regmatch.rm_ic = p_ic;
7943
7944 for (;;)
7945 {
7946 if (l != NULL)
7947 {
7948 if (li == NULL)
7949 {
7950 match = FALSE;
7951 break;
7952 }
7953 vim_free(tofree);
7954 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7955 if (str == NULL)
7956 break;
7957 }
7958
7959 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7960
7961 if (match && --nth <= 0)
7962 break;
7963 if (l == NULL && !match)
7964 break;
7965
7966 /* Advance to just after the match. */
7967 if (l != NULL)
7968 {
7969 li = li->li_next;
7970 ++idx;
7971 }
7972 else
7973 {
7974#ifdef FEAT_MBYTE
7975 startcol = (colnr_T)(regmatch.startp[0]
7976 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7977#else
7978 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7979#endif
7980 if (startcol > (colnr_T)len
7981 || str + startcol <= regmatch.startp[0])
7982 {
7983 match = FALSE;
7984 break;
7985 }
7986 }
7987 }
7988
7989 if (match)
7990 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007991 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992 {
7993 listitem_T *li1 = rettv->vval.v_list->lv_first;
7994 listitem_T *li2 = li1->li_next;
7995 listitem_T *li3 = li2->li_next;
7996 listitem_T *li4 = li3->li_next;
7997
7998 vim_free(li1->li_tv.vval.v_string);
7999 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8000 (int)(regmatch.endp[0] - regmatch.startp[0]));
8001 li3->li_tv.vval.v_number =
8002 (varnumber_T)(regmatch.startp[0] - expr);
8003 li4->li_tv.vval.v_number =
8004 (varnumber_T)(regmatch.endp[0] - expr);
8005 if (l != NULL)
8006 li2->li_tv.vval.v_number = (varnumber_T)idx;
8007 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008008 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 {
8010 int i;
8011
8012 /* return list with matched string and submatches */
8013 for (i = 0; i < NSUBEXP; ++i)
8014 {
8015 if (regmatch.endp[i] == NULL)
8016 {
8017 if (list_append_string(rettv->vval.v_list,
8018 (char_u *)"", 0) == FAIL)
8019 break;
8020 }
8021 else if (list_append_string(rettv->vval.v_list,
8022 regmatch.startp[i],
8023 (int)(regmatch.endp[i] - regmatch.startp[i]))
8024 == FAIL)
8025 break;
8026 }
8027 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008028 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029 {
8030 /* return matched string */
8031 if (l != NULL)
8032 copy_tv(&li->li_tv, rettv);
8033 else
8034 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8035 (int)(regmatch.endp[0] - regmatch.startp[0]));
8036 }
8037 else if (l != NULL)
8038 rettv->vval.v_number = idx;
8039 else
8040 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008041 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 rettv->vval.v_number =
8043 (varnumber_T)(regmatch.startp[0] - str);
8044 else
8045 rettv->vval.v_number =
8046 (varnumber_T)(regmatch.endp[0] - str);
8047 rettv->vval.v_number += (varnumber_T)(str - expr);
8048 }
8049 }
8050 vim_regfree(regmatch.regprog);
8051 }
8052
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008053theend:
8054 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008055 /* matchstrpos() without a list: drop the second item. */
8056 listitem_remove(rettv->vval.v_list,
8057 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008058 vim_free(tofree);
8059 p_cpo = save_cpo;
8060}
8061
8062/*
8063 * "match()" function
8064 */
8065 static void
8066f_match(typval_T *argvars, typval_T *rettv)
8067{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008068 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069}
8070
Bram Moolenaar95e51472018-07-28 16:55:56 +02008071#ifdef FEAT_SEARCH_EXTRA
8072 static int
8073matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8074{
8075 dictitem_T *di;
8076
8077 if (tv->v_type != VAR_DICT)
8078 {
8079 EMSG(_(e_dictreq));
8080 return FAIL;
8081 }
8082
8083 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008084 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008085 (char_u *)"conceal", FALSE);
8086
8087 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8088 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008089 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008090 if (*win == NULL)
8091 {
8092 EMSG(_("E957: Invalid window number"));
8093 return FAIL;
8094 }
8095 }
8096
8097 return OK;
8098}
8099#endif
8100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008101/*
8102 * "matchadd()" function
8103 */
8104 static void
8105f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8106{
8107#ifdef FEAT_SEARCH_EXTRA
8108 char_u buf[NUMBUFLEN];
8109 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
8110 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
8111 int prio = 10; /* default priority */
8112 int id = -1;
8113 int error = FALSE;
8114 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008115 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116
8117 rettv->vval.v_number = -1;
8118
8119 if (grp == NULL || pat == NULL)
8120 return;
8121 if (argvars[2].v_type != VAR_UNKNOWN)
8122 {
8123 prio = (int)get_tv_number_chk(&argvars[2], &error);
8124 if (argvars[3].v_type != VAR_UNKNOWN)
8125 {
8126 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008127 if (argvars[4].v_type != VAR_UNKNOWN
8128 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8129 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 }
8131 }
8132 if (error == TRUE)
8133 return;
8134 if (id >= 1 && id <= 3)
8135 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008136 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137 return;
8138 }
8139
Bram Moolenaar95e51472018-07-28 16:55:56 +02008140 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141 conceal_char);
8142#endif
8143}
8144
8145/*
8146 * "matchaddpos()" function
8147 */
8148 static void
8149f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8150{
8151#ifdef FEAT_SEARCH_EXTRA
8152 char_u buf[NUMBUFLEN];
8153 char_u *group;
8154 int prio = 10;
8155 int id = -1;
8156 int error = FALSE;
8157 list_T *l;
8158 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008159 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160
8161 rettv->vval.v_number = -1;
8162
8163 group = get_tv_string_buf_chk(&argvars[0], buf);
8164 if (group == NULL)
8165 return;
8166
8167 if (argvars[1].v_type != VAR_LIST)
8168 {
8169 EMSG2(_(e_listarg), "matchaddpos()");
8170 return;
8171 }
8172 l = argvars[1].vval.v_list;
8173 if (l == NULL)
8174 return;
8175
8176 if (argvars[2].v_type != VAR_UNKNOWN)
8177 {
8178 prio = (int)get_tv_number_chk(&argvars[2], &error);
8179 if (argvars[3].v_type != VAR_UNKNOWN)
8180 {
8181 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008182
8183 if (argvars[4].v_type != VAR_UNKNOWN
8184 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8185 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 }
8187 }
8188 if (error == TRUE)
8189 return;
8190
8191 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8192 if (id == 1 || id == 2)
8193 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008194 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 return;
8196 }
8197
Bram Moolenaar95e51472018-07-28 16:55:56 +02008198 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008199 conceal_char);
8200#endif
8201}
8202
8203/*
8204 * "matcharg()" function
8205 */
8206 static void
8207f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8208{
8209 if (rettv_list_alloc(rettv) == OK)
8210 {
8211#ifdef FEAT_SEARCH_EXTRA
8212 int id = (int)get_tv_number(&argvars[0]);
8213 matchitem_T *m;
8214
8215 if (id >= 1 && id <= 3)
8216 {
8217 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8218 {
8219 list_append_string(rettv->vval.v_list,
8220 syn_id2name(m->hlg_id), -1);
8221 list_append_string(rettv->vval.v_list, m->pattern, -1);
8222 }
8223 else
8224 {
8225 list_append_string(rettv->vval.v_list, NULL, -1);
8226 list_append_string(rettv->vval.v_list, NULL, -1);
8227 }
8228 }
8229#endif
8230 }
8231}
8232
8233/*
8234 * "matchdelete()" function
8235 */
8236 static void
8237f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8238{
8239#ifdef FEAT_SEARCH_EXTRA
8240 rettv->vval.v_number = match_delete(curwin,
8241 (int)get_tv_number(&argvars[0]), TRUE);
8242#endif
8243}
8244
8245/*
8246 * "matchend()" function
8247 */
8248 static void
8249f_matchend(typval_T *argvars, typval_T *rettv)
8250{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008251 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008252}
8253
8254/*
8255 * "matchlist()" function
8256 */
8257 static void
8258f_matchlist(typval_T *argvars, typval_T *rettv)
8259{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008260 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008261}
8262
8263/*
8264 * "matchstr()" function
8265 */
8266 static void
8267f_matchstr(typval_T *argvars, typval_T *rettv)
8268{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008269 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008270}
8271
8272/*
8273 * "matchstrpos()" function
8274 */
8275 static void
8276f_matchstrpos(typval_T *argvars, typval_T *rettv)
8277{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008278 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008279}
8280
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281 static void
8282max_min(typval_T *argvars, typval_T *rettv, int domax)
8283{
8284 varnumber_T n = 0;
8285 varnumber_T i;
8286 int error = FALSE;
8287
8288 if (argvars[0].v_type == VAR_LIST)
8289 {
8290 list_T *l;
8291 listitem_T *li;
8292
8293 l = argvars[0].vval.v_list;
8294 if (l != NULL)
8295 {
8296 li = l->lv_first;
8297 if (li != NULL)
8298 {
8299 n = get_tv_number_chk(&li->li_tv, &error);
8300 for (;;)
8301 {
8302 li = li->li_next;
8303 if (li == NULL)
8304 break;
8305 i = get_tv_number_chk(&li->li_tv, &error);
8306 if (domax ? i > n : i < n)
8307 n = i;
8308 }
8309 }
8310 }
8311 }
8312 else if (argvars[0].v_type == VAR_DICT)
8313 {
8314 dict_T *d;
8315 int first = TRUE;
8316 hashitem_T *hi;
8317 int todo;
8318
8319 d = argvars[0].vval.v_dict;
8320 if (d != NULL)
8321 {
8322 todo = (int)d->dv_hashtab.ht_used;
8323 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8324 {
8325 if (!HASHITEM_EMPTY(hi))
8326 {
8327 --todo;
8328 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8329 if (first)
8330 {
8331 n = i;
8332 first = FALSE;
8333 }
8334 else if (domax ? i > n : i < n)
8335 n = i;
8336 }
8337 }
8338 }
8339 }
8340 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008341 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 rettv->vval.v_number = error ? 0 : n;
8343}
8344
8345/*
8346 * "max()" function
8347 */
8348 static void
8349f_max(typval_T *argvars, typval_T *rettv)
8350{
8351 max_min(argvars, rettv, TRUE);
8352}
8353
8354/*
8355 * "min()" function
8356 */
8357 static void
8358f_min(typval_T *argvars, typval_T *rettv)
8359{
8360 max_min(argvars, rettv, FALSE);
8361}
8362
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008363/*
8364 * Create the directory in which "dir" is located, and higher levels when
8365 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008366 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008367 */
8368 static int
8369mkdir_recurse(char_u *dir, int prot)
8370{
8371 char_u *p;
8372 char_u *updir;
8373 int r = FAIL;
8374
8375 /* Get end of directory name in "dir".
8376 * We're done when it's "/" or "c:/". */
8377 p = gettail_sep(dir);
8378 if (p <= get_past_head(dir))
8379 return OK;
8380
8381 /* If the directory exists we're done. Otherwise: create it.*/
8382 updir = vim_strnsave(dir, (int)(p - dir));
8383 if (updir == NULL)
8384 return FAIL;
8385 if (mch_isdir(updir))
8386 r = OK;
8387 else if (mkdir_recurse(updir, prot) == OK)
8388 r = vim_mkdir_emsg(updir, prot);
8389 vim_free(updir);
8390 return r;
8391}
8392
8393#ifdef vim_mkdir
8394/*
8395 * "mkdir()" function
8396 */
8397 static void
8398f_mkdir(typval_T *argvars, typval_T *rettv)
8399{
8400 char_u *dir;
8401 char_u buf[NUMBUFLEN];
8402 int prot = 0755;
8403
8404 rettv->vval.v_number = FAIL;
8405 if (check_restricted() || check_secure())
8406 return;
8407
8408 dir = get_tv_string_buf(&argvars[0], buf);
8409 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008410 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008411
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008412 if (*gettail(dir) == NUL)
8413 /* remove trailing slashes */
8414 *gettail_sep(dir) = NUL;
8415
8416 if (argvars[1].v_type != VAR_UNKNOWN)
8417 {
8418 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008419 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008420 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8421 if (prot == -1)
8422 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008423 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008424 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8425 {
8426 if (mch_isdir(dir))
8427 {
8428 /* With the "p" flag it's OK if the dir already exists. */
8429 rettv->vval.v_number = OK;
8430 return;
8431 }
8432 mkdir_recurse(dir, prot);
8433 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008434 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008435 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008436}
8437#endif
8438
8439/*
8440 * "mode()" function
8441 */
8442 static void
8443f_mode(typval_T *argvars, typval_T *rettv)
8444{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008445 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008446
Bram Moolenaar612cc382018-07-29 15:34:26 +02008447 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448
8449 if (time_for_testing == 93784)
8450 {
8451 /* Testing the two-character code. */
8452 buf[0] = 'x';
8453 buf[1] = '!';
8454 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008455#ifdef FEAT_TERMINAL
8456 else if (term_use_loop())
8457 buf[0] = 't';
8458#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459 else if (VIsual_active)
8460 {
8461 if (VIsual_select)
8462 buf[0] = VIsual_mode + 's' - 'v';
8463 else
8464 buf[0] = VIsual_mode;
8465 }
8466 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8467 || State == CONFIRM)
8468 {
8469 buf[0] = 'r';
8470 if (State == ASKMORE)
8471 buf[1] = 'm';
8472 else if (State == CONFIRM)
8473 buf[1] = '?';
8474 }
8475 else if (State == EXTERNCMD)
8476 buf[0] = '!';
8477 else if (State & INSERT)
8478 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008479 if (State & VREPLACE_FLAG)
8480 {
8481 buf[0] = 'R';
8482 buf[1] = 'v';
8483 }
8484 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008485 {
8486 if (State & REPLACE_FLAG)
8487 buf[0] = 'R';
8488 else
8489 buf[0] = 'i';
8490#ifdef FEAT_INS_EXPAND
8491 if (ins_compl_active())
8492 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008493 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008494 buf[1] = 'x';
8495#endif
8496 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008497 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008498 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008499 {
8500 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008501 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008502 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008503 else if (exmode_active == EXMODE_NORMAL)
8504 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008505 }
8506 else
8507 {
8508 buf[0] = 'n';
8509 if (finish_op)
8510 buf[1] = 'o';
Bram Moolenaar612cc382018-07-29 15:34:26 +02008511 else if (restart_edit == 'I' || restart_edit == 'R'
8512 || restart_edit == 'V')
8513 {
8514 buf[1] = 'i';
8515 buf[2] = restart_edit;
8516 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008517 }
8518
8519 /* Clear out the minor mode when the argument is not a non-zero number or
8520 * non-empty string. */
8521 if (!non_zero_arg(&argvars[0]))
8522 buf[1] = NUL;
8523
8524 rettv->vval.v_string = vim_strsave(buf);
8525 rettv->v_type = VAR_STRING;
8526}
8527
8528#if defined(FEAT_MZSCHEME) || defined(PROTO)
8529/*
8530 * "mzeval()" function
8531 */
8532 static void
8533f_mzeval(typval_T *argvars, typval_T *rettv)
8534{
8535 char_u *str;
8536 char_u buf[NUMBUFLEN];
8537
8538 str = get_tv_string_buf(&argvars[0], buf);
8539 do_mzeval(str, rettv);
8540}
8541
8542 void
8543mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8544{
8545 typval_T argvars[3];
8546
8547 argvars[0].v_type = VAR_STRING;
8548 argvars[0].vval.v_string = name;
8549 copy_tv(args, &argvars[1]);
8550 argvars[2].v_type = VAR_UNKNOWN;
8551 f_call(argvars, rettv);
8552 clear_tv(&argvars[1]);
8553}
8554#endif
8555
8556/*
8557 * "nextnonblank()" function
8558 */
8559 static void
8560f_nextnonblank(typval_T *argvars, typval_T *rettv)
8561{
8562 linenr_T lnum;
8563
8564 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8565 {
8566 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8567 {
8568 lnum = 0;
8569 break;
8570 }
8571 if (*skipwhite(ml_get(lnum)) != NUL)
8572 break;
8573 }
8574 rettv->vval.v_number = lnum;
8575}
8576
8577/*
8578 * "nr2char()" function
8579 */
8580 static void
8581f_nr2char(typval_T *argvars, typval_T *rettv)
8582{
8583 char_u buf[NUMBUFLEN];
8584
8585#ifdef FEAT_MBYTE
8586 if (has_mbyte)
8587 {
8588 int utf8 = 0;
8589
8590 if (argvars[1].v_type != VAR_UNKNOWN)
8591 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8592 if (utf8)
8593 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8594 else
8595 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8596 }
8597 else
8598#endif
8599 {
8600 buf[0] = (char_u)get_tv_number(&argvars[0]);
8601 buf[1] = NUL;
8602 }
8603 rettv->v_type = VAR_STRING;
8604 rettv->vval.v_string = vim_strsave(buf);
8605}
8606
8607/*
8608 * "or(expr, expr)" function
8609 */
8610 static void
8611f_or(typval_T *argvars, typval_T *rettv)
8612{
8613 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8614 | get_tv_number_chk(&argvars[1], NULL);
8615}
8616
8617/*
8618 * "pathshorten()" function
8619 */
8620 static void
8621f_pathshorten(typval_T *argvars, typval_T *rettv)
8622{
8623 char_u *p;
8624
8625 rettv->v_type = VAR_STRING;
8626 p = get_tv_string_chk(&argvars[0]);
8627 if (p == NULL)
8628 rettv->vval.v_string = NULL;
8629 else
8630 {
8631 p = vim_strsave(p);
8632 rettv->vval.v_string = p;
8633 if (p != NULL)
8634 shorten_dir(p);
8635 }
8636}
8637
8638#ifdef FEAT_PERL
8639/*
8640 * "perleval()" function
8641 */
8642 static void
8643f_perleval(typval_T *argvars, typval_T *rettv)
8644{
8645 char_u *str;
8646 char_u buf[NUMBUFLEN];
8647
8648 str = get_tv_string_buf(&argvars[0], buf);
8649 do_perleval(str, rettv);
8650}
8651#endif
8652
8653#ifdef FEAT_FLOAT
8654/*
8655 * "pow()" function
8656 */
8657 static void
8658f_pow(typval_T *argvars, typval_T *rettv)
8659{
8660 float_T fx = 0.0, fy = 0.0;
8661
8662 rettv->v_type = VAR_FLOAT;
8663 if (get_float_arg(argvars, &fx) == OK
8664 && get_float_arg(&argvars[1], &fy) == OK)
8665 rettv->vval.v_float = pow(fx, fy);
8666 else
8667 rettv->vval.v_float = 0.0;
8668}
8669#endif
8670
8671/*
8672 * "prevnonblank()" function
8673 */
8674 static void
8675f_prevnonblank(typval_T *argvars, typval_T *rettv)
8676{
8677 linenr_T lnum;
8678
8679 lnum = get_tv_lnum(argvars);
8680 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8681 lnum = 0;
8682 else
8683 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8684 --lnum;
8685 rettv->vval.v_number = lnum;
8686}
8687
8688/* This dummy va_list is here because:
8689 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8690 * - locally in the function results in a "used before set" warning
8691 * - using va_start() to initialize it gives "function with fixed args" error */
8692static va_list ap;
8693
8694/*
8695 * "printf()" function
8696 */
8697 static void
8698f_printf(typval_T *argvars, typval_T *rettv)
8699{
8700 char_u buf[NUMBUFLEN];
8701 int len;
8702 char_u *s;
8703 int saved_did_emsg = did_emsg;
8704 char *fmt;
8705
8706 rettv->v_type = VAR_STRING;
8707 rettv->vval.v_string = NULL;
8708
8709 /* Get the required length, allocate the buffer and do it for real. */
8710 did_emsg = FALSE;
8711 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008712 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008713 if (!did_emsg)
8714 {
8715 s = alloc(len + 1);
8716 if (s != NULL)
8717 {
8718 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008719 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8720 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 }
8722 }
8723 did_emsg |= saved_did_emsg;
8724}
8725
Bram Moolenaarf2732452018-06-03 14:47:35 +02008726#ifdef FEAT_JOB_CHANNEL
8727/*
8728 * "prompt_setcallback({buffer}, {callback})" function
8729 */
8730 static void
8731f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8732{
8733 buf_T *buf;
8734 char_u *callback;
8735 partial_T *partial;
8736
8737 if (check_secure())
8738 return;
8739 buf = get_buf_tv(&argvars[0], FALSE);
8740 if (buf == NULL)
8741 return;
8742
8743 callback = get_callback(&argvars[1], &partial);
8744 if (callback == NULL)
8745 return;
8746
8747 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8748 if (partial == NULL)
8749 buf->b_prompt_callback = vim_strsave(callback);
8750 else
8751 /* pointer into the partial */
8752 buf->b_prompt_callback = callback;
8753 buf->b_prompt_partial = partial;
8754}
8755
8756/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008757 * "prompt_setinterrupt({buffer}, {callback})" function
8758 */
8759 static void
8760f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8761{
8762 buf_T *buf;
8763 char_u *callback;
8764 partial_T *partial;
8765
8766 if (check_secure())
8767 return;
8768 buf = get_buf_tv(&argvars[0], FALSE);
8769 if (buf == NULL)
8770 return;
8771
8772 callback = get_callback(&argvars[1], &partial);
8773 if (callback == NULL)
8774 return;
8775
8776 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8777 if (partial == NULL)
8778 buf->b_prompt_interrupt = vim_strsave(callback);
8779 else
8780 /* pointer into the partial */
8781 buf->b_prompt_interrupt = callback;
8782 buf->b_prompt_int_partial = partial;
8783}
8784
8785/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008786 * "prompt_setprompt({buffer}, {text})" function
8787 */
8788 static void
8789f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8790{
8791 buf_T *buf;
8792 char_u *text;
8793
8794 if (check_secure())
8795 return;
8796 buf = get_buf_tv(&argvars[0], FALSE);
8797 if (buf == NULL)
8798 return;
8799
8800 text = get_tv_string(&argvars[1]);
8801 vim_free(buf->b_prompt_text);
8802 buf->b_prompt_text = vim_strsave(text);
8803}
8804#endif
8805
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008806/*
8807 * "pumvisible()" function
8808 */
8809 static void
8810f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8811{
8812#ifdef FEAT_INS_EXPAND
8813 if (pum_visible())
8814 rettv->vval.v_number = 1;
8815#endif
8816}
8817
8818#ifdef FEAT_PYTHON3
8819/*
8820 * "py3eval()" function
8821 */
8822 static void
8823f_py3eval(typval_T *argvars, typval_T *rettv)
8824{
8825 char_u *str;
8826 char_u buf[NUMBUFLEN];
8827
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008828 if (p_pyx == 0)
8829 p_pyx = 3;
8830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008831 str = get_tv_string_buf(&argvars[0], buf);
8832 do_py3eval(str, rettv);
8833}
8834#endif
8835
8836#ifdef FEAT_PYTHON
8837/*
8838 * "pyeval()" function
8839 */
8840 static void
8841f_pyeval(typval_T *argvars, typval_T *rettv)
8842{
8843 char_u *str;
8844 char_u buf[NUMBUFLEN];
8845
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008846 if (p_pyx == 0)
8847 p_pyx = 2;
8848
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008849 str = get_tv_string_buf(&argvars[0], buf);
8850 do_pyeval(str, rettv);
8851}
8852#endif
8853
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008854#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8855/*
8856 * "pyxeval()" function
8857 */
8858 static void
8859f_pyxeval(typval_T *argvars, typval_T *rettv)
8860{
8861# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8862 init_pyxversion();
8863 if (p_pyx == 2)
8864 f_pyeval(argvars, rettv);
8865 else
8866 f_py3eval(argvars, rettv);
8867# elif defined(FEAT_PYTHON)
8868 f_pyeval(argvars, rettv);
8869# elif defined(FEAT_PYTHON3)
8870 f_py3eval(argvars, rettv);
8871# endif
8872}
8873#endif
8874
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008875/*
8876 * "range()" function
8877 */
8878 static void
8879f_range(typval_T *argvars, typval_T *rettv)
8880{
8881 varnumber_T start;
8882 varnumber_T end;
8883 varnumber_T stride = 1;
8884 varnumber_T i;
8885 int error = FALSE;
8886
8887 start = get_tv_number_chk(&argvars[0], &error);
8888 if (argvars[1].v_type == VAR_UNKNOWN)
8889 {
8890 end = start - 1;
8891 start = 0;
8892 }
8893 else
8894 {
8895 end = get_tv_number_chk(&argvars[1], &error);
8896 if (argvars[2].v_type != VAR_UNKNOWN)
8897 stride = get_tv_number_chk(&argvars[2], &error);
8898 }
8899
8900 if (error)
8901 return; /* type error; errmsg already given */
8902 if (stride == 0)
8903 EMSG(_("E726: Stride is zero"));
8904 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8905 EMSG(_("E727: Start past end"));
8906 else
8907 {
8908 if (rettv_list_alloc(rettv) == OK)
8909 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8910 if (list_append_number(rettv->vval.v_list,
8911 (varnumber_T)i) == FAIL)
8912 break;
8913 }
8914}
8915
8916/*
8917 * "readfile()" function
8918 */
8919 static void
8920f_readfile(typval_T *argvars, typval_T *rettv)
8921{
8922 int binary = FALSE;
8923 int failed = FALSE;
8924 char_u *fname;
8925 FILE *fd;
8926 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8927 int io_size = sizeof(buf);
8928 int readlen; /* size of last fread() */
8929 char_u *prev = NULL; /* previously read bytes, if any */
8930 long prevlen = 0; /* length of data in prev */
8931 long prevsize = 0; /* size of prev buffer */
8932 long maxline = MAXLNUM;
8933 long cnt = 0;
8934 char_u *p; /* position in buf */
8935 char_u *start; /* start of current line */
8936
8937 if (argvars[1].v_type != VAR_UNKNOWN)
8938 {
8939 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8940 binary = TRUE;
8941 if (argvars[2].v_type != VAR_UNKNOWN)
8942 maxline = (long)get_tv_number(&argvars[2]);
8943 }
8944
8945 if (rettv_list_alloc(rettv) == FAIL)
8946 return;
8947
8948 /* Always open the file in binary mode, library functions have a mind of
8949 * their own about CR-LF conversion. */
8950 fname = get_tv_string(&argvars[0]);
8951 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8952 {
8953 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8954 return;
8955 }
8956
8957 while (cnt < maxline || maxline < 0)
8958 {
8959 readlen = (int)fread(buf, 1, io_size, fd);
8960
8961 /* This for loop processes what was read, but is also entered at end
8962 * of file so that either:
8963 * - an incomplete line gets written
8964 * - a "binary" file gets an empty line at the end if it ends in a
8965 * newline. */
8966 for (p = buf, start = buf;
8967 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8968 ++p)
8969 {
8970 if (*p == '\n' || readlen <= 0)
8971 {
8972 listitem_T *li;
8973 char_u *s = NULL;
8974 long_u len = p - start;
8975
8976 /* Finished a line. Remove CRs before NL. */
8977 if (readlen > 0 && !binary)
8978 {
8979 while (len > 0 && start[len - 1] == '\r')
8980 --len;
8981 /* removal may cross back to the "prev" string */
8982 if (len == 0)
8983 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8984 --prevlen;
8985 }
8986 if (prevlen == 0)
8987 s = vim_strnsave(start, (int)len);
8988 else
8989 {
8990 /* Change "prev" buffer to be the right size. This way
8991 * the bytes are only copied once, and very long lines are
8992 * allocated only once. */
8993 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8994 {
8995 mch_memmove(s + prevlen, start, len);
8996 s[prevlen + len] = NUL;
8997 prev = NULL; /* the list will own the string */
8998 prevlen = prevsize = 0;
8999 }
9000 }
9001 if (s == NULL)
9002 {
9003 do_outofmem_msg((long_u) prevlen + len + 1);
9004 failed = TRUE;
9005 break;
9006 }
9007
9008 if ((li = listitem_alloc()) == NULL)
9009 {
9010 vim_free(s);
9011 failed = TRUE;
9012 break;
9013 }
9014 li->li_tv.v_type = VAR_STRING;
9015 li->li_tv.v_lock = 0;
9016 li->li_tv.vval.v_string = s;
9017 list_append(rettv->vval.v_list, li);
9018
9019 start = p + 1; /* step over newline */
9020 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9021 break;
9022 }
9023 else if (*p == NUL)
9024 *p = '\n';
9025#ifdef FEAT_MBYTE
9026 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9027 * when finding the BF and check the previous two bytes. */
9028 else if (*p == 0xbf && enc_utf8 && !binary)
9029 {
9030 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9031 * + 1, these may be in the "prev" string. */
9032 char_u back1 = p >= buf + 1 ? p[-1]
9033 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9034 char_u back2 = p >= buf + 2 ? p[-2]
9035 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9036 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9037
9038 if (back2 == 0xef && back1 == 0xbb)
9039 {
9040 char_u *dest = p - 2;
9041
9042 /* Usually a BOM is at the beginning of a file, and so at
9043 * the beginning of a line; then we can just step over it.
9044 */
9045 if (start == dest)
9046 start = p + 1;
9047 else
9048 {
9049 /* have to shuffle buf to close gap */
9050 int adjust_prevlen = 0;
9051
9052 if (dest < buf)
9053 {
9054 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9055 dest = buf;
9056 }
9057 if (readlen > p - buf + 1)
9058 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9059 readlen -= 3 - adjust_prevlen;
9060 prevlen -= adjust_prevlen;
9061 p = dest - 1;
9062 }
9063 }
9064 }
9065#endif
9066 } /* for */
9067
9068 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9069 break;
9070 if (start < p)
9071 {
9072 /* There's part of a line in buf, store it in "prev". */
9073 if (p - start + prevlen >= prevsize)
9074 {
9075 /* need bigger "prev" buffer */
9076 char_u *newprev;
9077
9078 /* A common use case is ordinary text files and "prev" gets a
9079 * fragment of a line, so the first allocation is made
9080 * small, to avoid repeatedly 'allocing' large and
9081 * 'reallocing' small. */
9082 if (prevsize == 0)
9083 prevsize = (long)(p - start);
9084 else
9085 {
9086 long grow50pc = (prevsize * 3) / 2;
9087 long growmin = (long)((p - start) * 2 + prevlen);
9088 prevsize = grow50pc > growmin ? grow50pc : growmin;
9089 }
9090 newprev = prev == NULL ? alloc(prevsize)
9091 : vim_realloc(prev, prevsize);
9092 if (newprev == NULL)
9093 {
9094 do_outofmem_msg((long_u)prevsize);
9095 failed = TRUE;
9096 break;
9097 }
9098 prev = newprev;
9099 }
9100 /* Add the line part to end of "prev". */
9101 mch_memmove(prev + prevlen, start, p - start);
9102 prevlen += (long)(p - start);
9103 }
9104 } /* while */
9105
9106 /*
9107 * For a negative line count use only the lines at the end of the file,
9108 * free the rest.
9109 */
9110 if (!failed && maxline < 0)
9111 while (cnt > -maxline)
9112 {
9113 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9114 --cnt;
9115 }
9116
9117 if (failed)
9118 {
9119 list_free(rettv->vval.v_list);
9120 /* readfile doc says an empty list is returned on error */
9121 rettv->vval.v_list = list_alloc();
9122 }
9123
9124 vim_free(prev);
9125 fclose(fd);
9126}
9127
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009128 static void
9129return_register(int regname, typval_T *rettv)
9130{
9131 char_u buf[2] = {0, 0};
9132
9133 buf[0] = (char_u)regname;
9134 rettv->v_type = VAR_STRING;
9135 rettv->vval.v_string = vim_strsave(buf);
9136}
9137
9138/*
9139 * "reg_executing()" function
9140 */
9141 static void
9142f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9143{
9144 return_register(reg_executing, rettv);
9145}
9146
9147/*
9148 * "reg_recording()" function
9149 */
9150 static void
9151f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9152{
9153 return_register(reg_recording, rettv);
9154}
9155
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009156#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009157/*
9158 * Convert a List to proftime_T.
9159 * Return FAIL when there is something wrong.
9160 */
9161 static int
9162list2proftime(typval_T *arg, proftime_T *tm)
9163{
9164 long n1, n2;
9165 int error = FALSE;
9166
9167 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9168 || arg->vval.v_list->lv_len != 2)
9169 return FAIL;
9170 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9171 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9172# ifdef WIN3264
9173 tm->HighPart = n1;
9174 tm->LowPart = n2;
9175# else
9176 tm->tv_sec = n1;
9177 tm->tv_usec = n2;
9178# endif
9179 return error ? FAIL : OK;
9180}
9181#endif /* FEAT_RELTIME */
9182
9183/*
9184 * "reltime()" function
9185 */
9186 static void
9187f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9188{
9189#ifdef FEAT_RELTIME
9190 proftime_T res;
9191 proftime_T start;
9192
9193 if (argvars[0].v_type == VAR_UNKNOWN)
9194 {
9195 /* No arguments: get current time. */
9196 profile_start(&res);
9197 }
9198 else if (argvars[1].v_type == VAR_UNKNOWN)
9199 {
9200 if (list2proftime(&argvars[0], &res) == FAIL)
9201 return;
9202 profile_end(&res);
9203 }
9204 else
9205 {
9206 /* Two arguments: compute the difference. */
9207 if (list2proftime(&argvars[0], &start) == FAIL
9208 || list2proftime(&argvars[1], &res) == FAIL)
9209 return;
9210 profile_sub(&res, &start);
9211 }
9212
9213 if (rettv_list_alloc(rettv) == OK)
9214 {
9215 long n1, n2;
9216
9217# ifdef WIN3264
9218 n1 = res.HighPart;
9219 n2 = res.LowPart;
9220# else
9221 n1 = res.tv_sec;
9222 n2 = res.tv_usec;
9223# endif
9224 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9225 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9226 }
9227#endif
9228}
9229
9230#ifdef FEAT_FLOAT
9231/*
9232 * "reltimefloat()" function
9233 */
9234 static void
9235f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9236{
9237# ifdef FEAT_RELTIME
9238 proftime_T tm;
9239# endif
9240
9241 rettv->v_type = VAR_FLOAT;
9242 rettv->vval.v_float = 0;
9243# ifdef FEAT_RELTIME
9244 if (list2proftime(&argvars[0], &tm) == OK)
9245 rettv->vval.v_float = profile_float(&tm);
9246# endif
9247}
9248#endif
9249
9250/*
9251 * "reltimestr()" function
9252 */
9253 static void
9254f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9255{
9256#ifdef FEAT_RELTIME
9257 proftime_T tm;
9258#endif
9259
9260 rettv->v_type = VAR_STRING;
9261 rettv->vval.v_string = NULL;
9262#ifdef FEAT_RELTIME
9263 if (list2proftime(&argvars[0], &tm) == OK)
9264 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9265#endif
9266}
9267
9268#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009269 static void
9270make_connection(void)
9271{
9272 if (X_DISPLAY == NULL
9273# ifdef FEAT_GUI
9274 && !gui.in_use
9275# endif
9276 )
9277 {
9278 x_force_connect = TRUE;
9279 setup_term_clip();
9280 x_force_connect = FALSE;
9281 }
9282}
9283
9284 static int
9285check_connection(void)
9286{
9287 make_connection();
9288 if (X_DISPLAY == NULL)
9289 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009290 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009291 return FAIL;
9292 }
9293 return OK;
9294}
9295#endif
9296
9297#ifdef FEAT_CLIENTSERVER
9298 static void
9299remote_common(typval_T *argvars, typval_T *rettv, int expr)
9300{
9301 char_u *server_name;
9302 char_u *keys;
9303 char_u *r = NULL;
9304 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009305 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009306# ifdef WIN32
9307 HWND w;
9308# else
9309 Window w;
9310# endif
9311
9312 if (check_restricted() || check_secure())
9313 return;
9314
9315# ifdef FEAT_X11
9316 if (check_connection() == FAIL)
9317 return;
9318# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009319 if (argvars[2].v_type != VAR_UNKNOWN
9320 && argvars[3].v_type != VAR_UNKNOWN)
9321 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009322
9323 server_name = get_tv_string_chk(&argvars[0]);
9324 if (server_name == NULL)
9325 return; /* type error; errmsg already given */
9326 keys = get_tv_string_buf(&argvars[1], buf);
9327# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009328 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009329# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009330 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9331 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009332# endif
9333 {
9334 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009335 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009336 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009337 vim_free(r);
9338 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009339 else
9340 EMSG2(_("E241: Unable to send to %s"), server_name);
9341 return;
9342 }
9343
9344 rettv->vval.v_string = r;
9345
9346 if (argvars[2].v_type != VAR_UNKNOWN)
9347 {
9348 dictitem_T v;
9349 char_u str[30];
9350 char_u *idvar;
9351
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009352 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009353 if (idvar != NULL && *idvar != NUL)
9354 {
9355 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9356 v.di_tv.v_type = VAR_STRING;
9357 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009358 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009359 vim_free(v.di_tv.vval.v_string);
9360 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009361 }
9362}
9363#endif
9364
9365/*
9366 * "remote_expr()" function
9367 */
9368 static void
9369f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9370{
9371 rettv->v_type = VAR_STRING;
9372 rettv->vval.v_string = NULL;
9373#ifdef FEAT_CLIENTSERVER
9374 remote_common(argvars, rettv, TRUE);
9375#endif
9376}
9377
9378/*
9379 * "remote_foreground()" function
9380 */
9381 static void
9382f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9383{
9384#ifdef FEAT_CLIENTSERVER
9385# ifdef WIN32
9386 /* On Win32 it's done in this application. */
9387 {
9388 char_u *server_name = get_tv_string_chk(&argvars[0]);
9389
9390 if (server_name != NULL)
9391 serverForeground(server_name);
9392 }
9393# else
9394 /* Send a foreground() expression to the server. */
9395 argvars[1].v_type = VAR_STRING;
9396 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9397 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009398 rettv->v_type = VAR_STRING;
9399 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009400 remote_common(argvars, rettv, TRUE);
9401 vim_free(argvars[1].vval.v_string);
9402# endif
9403#endif
9404}
9405
9406 static void
9407f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9408{
9409#ifdef FEAT_CLIENTSERVER
9410 dictitem_T v;
9411 char_u *s = NULL;
9412# ifdef WIN32
9413 long_u n = 0;
9414# endif
9415 char_u *serverid;
9416
9417 if (check_restricted() || check_secure())
9418 {
9419 rettv->vval.v_number = -1;
9420 return;
9421 }
9422 serverid = get_tv_string_chk(&argvars[0]);
9423 if (serverid == NULL)
9424 {
9425 rettv->vval.v_number = -1;
9426 return; /* type error; errmsg already given */
9427 }
9428# ifdef WIN32
9429 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9430 if (n == 0)
9431 rettv->vval.v_number = -1;
9432 else
9433 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009434 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009435 rettv->vval.v_number = (s != NULL);
9436 }
9437# else
9438 if (check_connection() == FAIL)
9439 return;
9440
9441 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9442 serverStrToWin(serverid), &s);
9443# endif
9444
9445 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9446 {
9447 char_u *retvar;
9448
9449 v.di_tv.v_type = VAR_STRING;
9450 v.di_tv.vval.v_string = vim_strsave(s);
9451 retvar = get_tv_string_chk(&argvars[1]);
9452 if (retvar != NULL)
9453 set_var(retvar, &v.di_tv, FALSE);
9454 vim_free(v.di_tv.vval.v_string);
9455 }
9456#else
9457 rettv->vval.v_number = -1;
9458#endif
9459}
9460
9461 static void
9462f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9463{
9464 char_u *r = NULL;
9465
9466#ifdef FEAT_CLIENTSERVER
9467 char_u *serverid = get_tv_string_chk(&argvars[0]);
9468
9469 if (serverid != NULL && !check_restricted() && !check_secure())
9470 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009471 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009472# ifdef WIN32
9473 /* The server's HWND is encoded in the 'id' parameter */
9474 long_u n = 0;
9475# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009476
9477 if (argvars[1].v_type != VAR_UNKNOWN)
9478 timeout = get_tv_number(&argvars[1]);
9479
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009480# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009481 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9482 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009483 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009484 if (r == NULL)
9485# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009486 if (check_connection() == FAIL
9487 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9488 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009489# endif
9490 EMSG(_("E277: Unable to read a server reply"));
9491 }
9492#endif
9493 rettv->v_type = VAR_STRING;
9494 rettv->vval.v_string = r;
9495}
9496
9497/*
9498 * "remote_send()" function
9499 */
9500 static void
9501f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9502{
9503 rettv->v_type = VAR_STRING;
9504 rettv->vval.v_string = NULL;
9505#ifdef FEAT_CLIENTSERVER
9506 remote_common(argvars, rettv, FALSE);
9507#endif
9508}
9509
9510/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009511 * "remote_startserver()" function
9512 */
9513 static void
9514f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9515{
9516#ifdef FEAT_CLIENTSERVER
9517 char_u *server = get_tv_string_chk(&argvars[0]);
9518
9519 if (server == NULL)
9520 return; /* type error; errmsg already given */
9521 if (serverName != NULL)
9522 EMSG(_("E941: already started a server"));
9523 else
9524 {
9525# ifdef FEAT_X11
9526 if (check_connection() == OK)
9527 serverRegisterName(X_DISPLAY, server);
9528# else
9529 serverSetName(server);
9530# endif
9531 }
9532#else
9533 EMSG(_("E942: +clientserver feature not available"));
9534#endif
9535}
9536
9537/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009538 * "remove()" function
9539 */
9540 static void
9541f_remove(typval_T *argvars, typval_T *rettv)
9542{
9543 list_T *l;
9544 listitem_T *item, *item2;
9545 listitem_T *li;
9546 long idx;
9547 long end;
9548 char_u *key;
9549 dict_T *d;
9550 dictitem_T *di;
9551 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9552
9553 if (argvars[0].v_type == VAR_DICT)
9554 {
9555 if (argvars[2].v_type != VAR_UNKNOWN)
9556 EMSG2(_(e_toomanyarg), "remove()");
9557 else if ((d = argvars[0].vval.v_dict) != NULL
9558 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9559 {
9560 key = get_tv_string_chk(&argvars[1]);
9561 if (key != NULL)
9562 {
9563 di = dict_find(d, key, -1);
9564 if (di == NULL)
9565 EMSG2(_(e_dictkey), key);
9566 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9567 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9568 {
9569 *rettv = di->di_tv;
9570 init_tv(&di->di_tv);
9571 dictitem_remove(d, di);
9572 }
9573 }
9574 }
9575 }
9576 else if (argvars[0].v_type != VAR_LIST)
9577 EMSG2(_(e_listdictarg), "remove()");
9578 else if ((l = argvars[0].vval.v_list) != NULL
9579 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9580 {
9581 int error = FALSE;
9582
9583 idx = (long)get_tv_number_chk(&argvars[1], &error);
9584 if (error)
9585 ; /* type error: do nothing, errmsg already given */
9586 else if ((item = list_find(l, idx)) == NULL)
9587 EMSGN(_(e_listidx), idx);
9588 else
9589 {
9590 if (argvars[2].v_type == VAR_UNKNOWN)
9591 {
9592 /* Remove one item, return its value. */
9593 vimlist_remove(l, item, item);
9594 *rettv = item->li_tv;
9595 vim_free(item);
9596 }
9597 else
9598 {
9599 /* Remove range of items, return list with values. */
9600 end = (long)get_tv_number_chk(&argvars[2], &error);
9601 if (error)
9602 ; /* type error: do nothing */
9603 else if ((item2 = list_find(l, end)) == NULL)
9604 EMSGN(_(e_listidx), end);
9605 else
9606 {
9607 int cnt = 0;
9608
9609 for (li = item; li != NULL; li = li->li_next)
9610 {
9611 ++cnt;
9612 if (li == item2)
9613 break;
9614 }
9615 if (li == NULL) /* didn't find "item2" after "item" */
9616 EMSG(_(e_invrange));
9617 else
9618 {
9619 vimlist_remove(l, item, item2);
9620 if (rettv_list_alloc(rettv) == OK)
9621 {
9622 l = rettv->vval.v_list;
9623 l->lv_first = item;
9624 l->lv_last = item2;
9625 item->li_prev = NULL;
9626 item2->li_next = NULL;
9627 l->lv_len = cnt;
9628 }
9629 }
9630 }
9631 }
9632 }
9633 }
9634}
9635
9636/*
9637 * "rename({from}, {to})" function
9638 */
9639 static void
9640f_rename(typval_T *argvars, typval_T *rettv)
9641{
9642 char_u buf[NUMBUFLEN];
9643
9644 if (check_restricted() || check_secure())
9645 rettv->vval.v_number = -1;
9646 else
9647 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9648 get_tv_string_buf(&argvars[1], buf));
9649}
9650
9651/*
9652 * "repeat()" function
9653 */
9654 static void
9655f_repeat(typval_T *argvars, typval_T *rettv)
9656{
9657 char_u *p;
9658 int n;
9659 int slen;
9660 int len;
9661 char_u *r;
9662 int i;
9663
9664 n = (int)get_tv_number(&argvars[1]);
9665 if (argvars[0].v_type == VAR_LIST)
9666 {
9667 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9668 while (n-- > 0)
9669 if (list_extend(rettv->vval.v_list,
9670 argvars[0].vval.v_list, NULL) == FAIL)
9671 break;
9672 }
9673 else
9674 {
9675 p = get_tv_string(&argvars[0]);
9676 rettv->v_type = VAR_STRING;
9677 rettv->vval.v_string = NULL;
9678
9679 slen = (int)STRLEN(p);
9680 len = slen * n;
9681 if (len <= 0)
9682 return;
9683
9684 r = alloc(len + 1);
9685 if (r != NULL)
9686 {
9687 for (i = 0; i < n; i++)
9688 mch_memmove(r + i * slen, p, (size_t)slen);
9689 r[len] = NUL;
9690 }
9691
9692 rettv->vval.v_string = r;
9693 }
9694}
9695
9696/*
9697 * "resolve()" function
9698 */
9699 static void
9700f_resolve(typval_T *argvars, typval_T *rettv)
9701{
9702 char_u *p;
9703#ifdef HAVE_READLINK
9704 char_u *buf = NULL;
9705#endif
9706
9707 p = get_tv_string(&argvars[0]);
9708#ifdef FEAT_SHORTCUT
9709 {
9710 char_u *v = NULL;
9711
9712 v = mch_resolve_shortcut(p);
9713 if (v != NULL)
9714 rettv->vval.v_string = v;
9715 else
9716 rettv->vval.v_string = vim_strsave(p);
9717 }
9718#else
9719# ifdef HAVE_READLINK
9720 {
9721 char_u *cpy;
9722 int len;
9723 char_u *remain = NULL;
9724 char_u *q;
9725 int is_relative_to_current = FALSE;
9726 int has_trailing_pathsep = FALSE;
9727 int limit = 100;
9728
9729 p = vim_strsave(p);
9730
9731 if (p[0] == '.' && (vim_ispathsep(p[1])
9732 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9733 is_relative_to_current = TRUE;
9734
9735 len = STRLEN(p);
9736 if (len > 0 && after_pathsep(p, p + len))
9737 {
9738 has_trailing_pathsep = TRUE;
9739 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9740 }
9741
9742 q = getnextcomp(p);
9743 if (*q != NUL)
9744 {
9745 /* Separate the first path component in "p", and keep the
9746 * remainder (beginning with the path separator). */
9747 remain = vim_strsave(q - 1);
9748 q[-1] = NUL;
9749 }
9750
9751 buf = alloc(MAXPATHL + 1);
9752 if (buf == NULL)
9753 goto fail;
9754
9755 for (;;)
9756 {
9757 for (;;)
9758 {
9759 len = readlink((char *)p, (char *)buf, MAXPATHL);
9760 if (len <= 0)
9761 break;
9762 buf[len] = NUL;
9763
9764 if (limit-- == 0)
9765 {
9766 vim_free(p);
9767 vim_free(remain);
9768 EMSG(_("E655: Too many symbolic links (cycle?)"));
9769 rettv->vval.v_string = NULL;
9770 goto fail;
9771 }
9772
9773 /* Ensure that the result will have a trailing path separator
9774 * if the argument has one. */
9775 if (remain == NULL && has_trailing_pathsep)
9776 add_pathsep(buf);
9777
9778 /* Separate the first path component in the link value and
9779 * concatenate the remainders. */
9780 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9781 if (*q != NUL)
9782 {
9783 if (remain == NULL)
9784 remain = vim_strsave(q - 1);
9785 else
9786 {
9787 cpy = concat_str(q - 1, remain);
9788 if (cpy != NULL)
9789 {
9790 vim_free(remain);
9791 remain = cpy;
9792 }
9793 }
9794 q[-1] = NUL;
9795 }
9796
9797 q = gettail(p);
9798 if (q > p && *q == NUL)
9799 {
9800 /* Ignore trailing path separator. */
9801 q[-1] = NUL;
9802 q = gettail(p);
9803 }
9804 if (q > p && !mch_isFullName(buf))
9805 {
9806 /* symlink is relative to directory of argument */
9807 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9808 if (cpy != NULL)
9809 {
9810 STRCPY(cpy, p);
9811 STRCPY(gettail(cpy), buf);
9812 vim_free(p);
9813 p = cpy;
9814 }
9815 }
9816 else
9817 {
9818 vim_free(p);
9819 p = vim_strsave(buf);
9820 }
9821 }
9822
9823 if (remain == NULL)
9824 break;
9825
9826 /* Append the first path component of "remain" to "p". */
9827 q = getnextcomp(remain + 1);
9828 len = q - remain - (*q != NUL);
9829 cpy = vim_strnsave(p, STRLEN(p) + len);
9830 if (cpy != NULL)
9831 {
9832 STRNCAT(cpy, remain, len);
9833 vim_free(p);
9834 p = cpy;
9835 }
9836 /* Shorten "remain". */
9837 if (*q != NUL)
9838 STRMOVE(remain, q - 1);
9839 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009840 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009841 }
9842
9843 /* If the result is a relative path name, make it explicitly relative to
9844 * the current directory if and only if the argument had this form. */
9845 if (!vim_ispathsep(*p))
9846 {
9847 if (is_relative_to_current
9848 && *p != NUL
9849 && !(p[0] == '.'
9850 && (p[1] == NUL
9851 || vim_ispathsep(p[1])
9852 || (p[1] == '.'
9853 && (p[2] == NUL
9854 || vim_ispathsep(p[2]))))))
9855 {
9856 /* Prepend "./". */
9857 cpy = concat_str((char_u *)"./", p);
9858 if (cpy != NULL)
9859 {
9860 vim_free(p);
9861 p = cpy;
9862 }
9863 }
9864 else if (!is_relative_to_current)
9865 {
9866 /* Strip leading "./". */
9867 q = p;
9868 while (q[0] == '.' && vim_ispathsep(q[1]))
9869 q += 2;
9870 if (q > p)
9871 STRMOVE(p, p + 2);
9872 }
9873 }
9874
9875 /* Ensure that the result will have no trailing path separator
9876 * if the argument had none. But keep "/" or "//". */
9877 if (!has_trailing_pathsep)
9878 {
9879 q = p + STRLEN(p);
9880 if (after_pathsep(p, q))
9881 *gettail_sep(p) = NUL;
9882 }
9883
9884 rettv->vval.v_string = p;
9885 }
9886# else
9887 rettv->vval.v_string = vim_strsave(p);
9888# endif
9889#endif
9890
9891 simplify_filename(rettv->vval.v_string);
9892
9893#ifdef HAVE_READLINK
9894fail:
9895 vim_free(buf);
9896#endif
9897 rettv->v_type = VAR_STRING;
9898}
9899
9900/*
9901 * "reverse({list})" function
9902 */
9903 static void
9904f_reverse(typval_T *argvars, typval_T *rettv)
9905{
9906 list_T *l;
9907 listitem_T *li, *ni;
9908
9909 if (argvars[0].v_type != VAR_LIST)
9910 EMSG2(_(e_listarg), "reverse()");
9911 else if ((l = argvars[0].vval.v_list) != NULL
9912 && !tv_check_lock(l->lv_lock,
9913 (char_u *)N_("reverse() argument"), TRUE))
9914 {
9915 li = l->lv_last;
9916 l->lv_first = l->lv_last = NULL;
9917 l->lv_len = 0;
9918 while (li != NULL)
9919 {
9920 ni = li->li_prev;
9921 list_append(l, li);
9922 li = ni;
9923 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009924 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009925 l->lv_idx = l->lv_len - l->lv_idx - 1;
9926 }
9927}
9928
9929#define SP_NOMOVE 0x01 /* don't move cursor */
9930#define SP_REPEAT 0x02 /* repeat to find outer pair */
9931#define SP_RETCOUNT 0x04 /* return matchcount */
9932#define SP_SETPCMARK 0x08 /* set previous context mark */
9933#define SP_START 0x10 /* accept match at start position */
9934#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9935#define SP_END 0x40 /* leave cursor at end of match */
9936#define SP_COLUMN 0x80 /* start at cursor column */
9937
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009938/*
9939 * Get flags for a search function.
9940 * Possibly sets "p_ws".
9941 * Returns BACKWARD, FORWARD or zero (for an error).
9942 */
9943 static int
9944get_search_arg(typval_T *varp, int *flagsp)
9945{
9946 int dir = FORWARD;
9947 char_u *flags;
9948 char_u nbuf[NUMBUFLEN];
9949 int mask;
9950
9951 if (varp->v_type != VAR_UNKNOWN)
9952 {
9953 flags = get_tv_string_buf_chk(varp, nbuf);
9954 if (flags == NULL)
9955 return 0; /* type error; errmsg already given */
9956 while (*flags != NUL)
9957 {
9958 switch (*flags)
9959 {
9960 case 'b': dir = BACKWARD; break;
9961 case 'w': p_ws = TRUE; break;
9962 case 'W': p_ws = FALSE; break;
9963 default: mask = 0;
9964 if (flagsp != NULL)
9965 switch (*flags)
9966 {
9967 case 'c': mask = SP_START; break;
9968 case 'e': mask = SP_END; break;
9969 case 'm': mask = SP_RETCOUNT; break;
9970 case 'n': mask = SP_NOMOVE; break;
9971 case 'p': mask = SP_SUBPAT; break;
9972 case 'r': mask = SP_REPEAT; break;
9973 case 's': mask = SP_SETPCMARK; break;
9974 case 'z': mask = SP_COLUMN; break;
9975 }
9976 if (mask == 0)
9977 {
9978 EMSG2(_(e_invarg2), flags);
9979 dir = 0;
9980 }
9981 else
9982 *flagsp |= mask;
9983 }
9984 if (dir == 0)
9985 break;
9986 ++flags;
9987 }
9988 }
9989 return dir;
9990}
9991
9992/*
9993 * Shared by search() and searchpos() functions.
9994 */
9995 static int
9996search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9997{
9998 int flags;
9999 char_u *pat;
10000 pos_T pos;
10001 pos_T save_cursor;
10002 int save_p_ws = p_ws;
10003 int dir;
10004 int retval = 0; /* default: FAIL */
10005 long lnum_stop = 0;
10006 proftime_T tm;
10007#ifdef FEAT_RELTIME
10008 long time_limit = 0;
10009#endif
10010 int options = SEARCH_KEEP;
10011 int subpatnum;
10012
10013 pat = get_tv_string(&argvars[0]);
10014 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10015 if (dir == 0)
10016 goto theend;
10017 flags = *flagsp;
10018 if (flags & SP_START)
10019 options |= SEARCH_START;
10020 if (flags & SP_END)
10021 options |= SEARCH_END;
10022 if (flags & SP_COLUMN)
10023 options |= SEARCH_COL;
10024
10025 /* Optional arguments: line number to stop searching and timeout. */
10026 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10027 {
10028 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
10029 if (lnum_stop < 0)
10030 goto theend;
10031#ifdef FEAT_RELTIME
10032 if (argvars[3].v_type != VAR_UNKNOWN)
10033 {
10034 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
10035 if (time_limit < 0)
10036 goto theend;
10037 }
10038#endif
10039 }
10040
10041#ifdef FEAT_RELTIME
10042 /* Set the time limit, if there is one. */
10043 profile_setlimit(time_limit, &tm);
10044#endif
10045
10046 /*
10047 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10048 * Check to make sure only those flags are set.
10049 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10050 * flags cannot be set. Check for that condition also.
10051 */
10052 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10053 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10054 {
10055 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
10056 goto theend;
10057 }
10058
10059 pos = save_cursor = curwin->w_cursor;
10060 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010061 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010062 if (subpatnum != FAIL)
10063 {
10064 if (flags & SP_SUBPAT)
10065 retval = subpatnum;
10066 else
10067 retval = pos.lnum;
10068 if (flags & SP_SETPCMARK)
10069 setpcmark();
10070 curwin->w_cursor = pos;
10071 if (match_pos != NULL)
10072 {
10073 /* Store the match cursor position */
10074 match_pos->lnum = pos.lnum;
10075 match_pos->col = pos.col + 1;
10076 }
10077 /* "/$" will put the cursor after the end of the line, may need to
10078 * correct that here */
10079 check_cursor();
10080 }
10081
10082 /* If 'n' flag is used: restore cursor position. */
10083 if (flags & SP_NOMOVE)
10084 curwin->w_cursor = save_cursor;
10085 else
10086 curwin->w_set_curswant = TRUE;
10087theend:
10088 p_ws = save_p_ws;
10089
10090 return retval;
10091}
10092
10093#ifdef FEAT_FLOAT
10094
10095/*
10096 * round() is not in C90, use ceil() or floor() instead.
10097 */
10098 float_T
10099vim_round(float_T f)
10100{
10101 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10102}
10103
10104/*
10105 * "round({float})" function
10106 */
10107 static void
10108f_round(typval_T *argvars, typval_T *rettv)
10109{
10110 float_T f = 0.0;
10111
10112 rettv->v_type = VAR_FLOAT;
10113 if (get_float_arg(argvars, &f) == OK)
10114 rettv->vval.v_float = vim_round(f);
10115 else
10116 rettv->vval.v_float = 0.0;
10117}
10118#endif
10119
10120/*
10121 * "screenattr()" function
10122 */
10123 static void
10124f_screenattr(typval_T *argvars, typval_T *rettv)
10125{
10126 int row;
10127 int col;
10128 int c;
10129
10130 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10131 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10132 if (row < 0 || row >= screen_Rows
10133 || col < 0 || col >= screen_Columns)
10134 c = -1;
10135 else
10136 c = ScreenAttrs[LineOffset[row] + col];
10137 rettv->vval.v_number = c;
10138}
10139
10140/*
10141 * "screenchar()" function
10142 */
10143 static void
10144f_screenchar(typval_T *argvars, typval_T *rettv)
10145{
10146 int row;
10147 int col;
10148 int off;
10149 int c;
10150
10151 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10152 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10153 if (row < 0 || row >= screen_Rows
10154 || col < 0 || col >= screen_Columns)
10155 c = -1;
10156 else
10157 {
10158 off = LineOffset[row] + col;
10159#ifdef FEAT_MBYTE
10160 if (enc_utf8 && ScreenLinesUC[off] != 0)
10161 c = ScreenLinesUC[off];
10162 else
10163#endif
10164 c = ScreenLines[off];
10165 }
10166 rettv->vval.v_number = c;
10167}
10168
10169/*
10170 * "screencol()" function
10171 *
10172 * First column is 1 to be consistent with virtcol().
10173 */
10174 static void
10175f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10176{
10177 rettv->vval.v_number = screen_screencol() + 1;
10178}
10179
10180/*
10181 * "screenrow()" function
10182 */
10183 static void
10184f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10185{
10186 rettv->vval.v_number = screen_screenrow() + 1;
10187}
10188
10189/*
10190 * "search()" function
10191 */
10192 static void
10193f_search(typval_T *argvars, typval_T *rettv)
10194{
10195 int flags = 0;
10196
10197 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10198}
10199
10200/*
10201 * "searchdecl()" function
10202 */
10203 static void
10204f_searchdecl(typval_T *argvars, typval_T *rettv)
10205{
10206 int locally = 1;
10207 int thisblock = 0;
10208 int error = FALSE;
10209 char_u *name;
10210
10211 rettv->vval.v_number = 1; /* default: FAIL */
10212
10213 name = get_tv_string_chk(&argvars[0]);
10214 if (argvars[1].v_type != VAR_UNKNOWN)
10215 {
10216 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
10217 if (!error && argvars[2].v_type != VAR_UNKNOWN)
10218 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
10219 }
10220 if (!error && name != NULL)
10221 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10222 locally, thisblock, SEARCH_KEEP) == FAIL;
10223}
10224
10225/*
10226 * Used by searchpair() and searchpairpos()
10227 */
10228 static int
10229searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10230{
10231 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010232 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010233 int save_p_ws = p_ws;
10234 int dir;
10235 int flags = 0;
10236 char_u nbuf1[NUMBUFLEN];
10237 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010238 int retval = 0; /* default: FAIL */
10239 long lnum_stop = 0;
10240 long time_limit = 0;
10241
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010242 /* Get the three pattern arguments: start, middle, end. Will result in an
10243 * error if not a valid argument. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 spat = get_tv_string_chk(&argvars[0]);
10245 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
10246 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
10247 if (spat == NULL || mpat == NULL || epat == NULL)
10248 goto theend; /* type error */
10249
10250 /* Handle the optional fourth argument: flags */
10251 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10252 if (dir == 0)
10253 goto theend;
10254
10255 /* Don't accept SP_END or SP_SUBPAT.
10256 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10257 */
10258 if ((flags & (SP_END | SP_SUBPAT)) != 0
10259 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10260 {
10261 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10262 goto theend;
10263 }
10264
10265 /* Using 'r' implies 'W', otherwise it doesn't work. */
10266 if (flags & SP_REPEAT)
10267 p_ws = FALSE;
10268
10269 /* Optional fifth argument: skip expression */
10270 if (argvars[3].v_type == VAR_UNKNOWN
10271 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010272 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010273 else
10274 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010275 skip = &argvars[4];
10276 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10277 && skip->v_type != VAR_STRING)
10278 {
10279 /* Type error */
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010280 EMSG2(_(e_invarg2), get_tv_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010281 goto theend;
10282 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010283 if (argvars[5].v_type != VAR_UNKNOWN)
10284 {
10285 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10286 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010287 {
10288 EMSG2(_(e_invarg2), get_tv_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010289 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010290 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010291#ifdef FEAT_RELTIME
10292 if (argvars[6].v_type != VAR_UNKNOWN)
10293 {
10294 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10295 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010296 {
10297 EMSG2(_(e_invarg2), get_tv_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010298 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010299 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010300 }
10301#endif
10302 }
10303 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010304
10305 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10306 match_pos, lnum_stop, time_limit);
10307
10308theend:
10309 p_ws = save_p_ws;
10310
10311 return retval;
10312}
10313
10314/*
10315 * "searchpair()" function
10316 */
10317 static void
10318f_searchpair(typval_T *argvars, typval_T *rettv)
10319{
10320 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10321}
10322
10323/*
10324 * "searchpairpos()" function
10325 */
10326 static void
10327f_searchpairpos(typval_T *argvars, typval_T *rettv)
10328{
10329 pos_T match_pos;
10330 int lnum = 0;
10331 int col = 0;
10332
10333 if (rettv_list_alloc(rettv) == FAIL)
10334 return;
10335
10336 if (searchpair_cmn(argvars, &match_pos) > 0)
10337 {
10338 lnum = match_pos.lnum;
10339 col = match_pos.col;
10340 }
10341
10342 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10343 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10344}
10345
10346/*
10347 * Search for a start/middle/end thing.
10348 * Used by searchpair(), see its documentation for the details.
10349 * Returns 0 or -1 for no match,
10350 */
10351 long
10352do_searchpair(
10353 char_u *spat, /* start pattern */
10354 char_u *mpat, /* middle pattern */
10355 char_u *epat, /* end pattern */
10356 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010357 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010358 int flags, /* SP_SETPCMARK and other SP_ values */
10359 pos_T *match_pos,
10360 linenr_T lnum_stop, /* stop at this line if not zero */
10361 long time_limit UNUSED) /* stop after this many msec */
10362{
10363 char_u *save_cpo;
10364 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10365 long retval = 0;
10366 pos_T pos;
10367 pos_T firstpos;
10368 pos_T foundpos;
10369 pos_T save_cursor;
10370 pos_T save_pos;
10371 int n;
10372 int r;
10373 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010374 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010375 int err;
10376 int options = SEARCH_KEEP;
10377 proftime_T tm;
10378
10379 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10380 save_cpo = p_cpo;
10381 p_cpo = empty_option;
10382
10383#ifdef FEAT_RELTIME
10384 /* Set the time limit, if there is one. */
10385 profile_setlimit(time_limit, &tm);
10386#endif
10387
10388 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10389 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010390 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10391 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010392 if (pat2 == NULL || pat3 == NULL)
10393 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010394 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010395 if (*mpat == NUL)
10396 STRCPY(pat3, pat2);
10397 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010398 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010399 spat, epat, mpat);
10400 if (flags & SP_START)
10401 options |= SEARCH_START;
10402
Bram Moolenaar48570482017-10-30 21:48:41 +010010403 if (skip != NULL)
10404 {
10405 /* Empty string means to not use the skip expression. */
10406 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10407 use_skip = skip->vval.v_string != NULL
10408 && *skip->vval.v_string != NUL;
10409 }
10410
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010411 save_cursor = curwin->w_cursor;
10412 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010413 CLEAR_POS(&firstpos);
10414 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010415 pat = pat3;
10416 for (;;)
10417 {
10418 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010419 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010420 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010421 /* didn't find it or found the first match again: FAIL */
10422 break;
10423
10424 if (firstpos.lnum == 0)
10425 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010426 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010427 {
10428 /* Found the same position again. Can happen with a pattern that
10429 * has "\zs" at the end and searching backwards. Advance one
10430 * character and try again. */
10431 if (dir == BACKWARD)
10432 decl(&pos);
10433 else
10434 incl(&pos);
10435 }
10436 foundpos = pos;
10437
10438 /* clear the start flag to avoid getting stuck here */
10439 options &= ~SEARCH_START;
10440
10441 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010442 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010443 {
10444 save_pos = curwin->w_cursor;
10445 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010446 err = FALSE;
10447 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010448 curwin->w_cursor = save_pos;
10449 if (err)
10450 {
10451 /* Evaluating {skip} caused an error, break here. */
10452 curwin->w_cursor = save_cursor;
10453 retval = -1;
10454 break;
10455 }
10456 if (r)
10457 continue;
10458 }
10459
10460 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10461 {
10462 /* Found end when searching backwards or start when searching
10463 * forward: nested pair. */
10464 ++nest;
10465 pat = pat2; /* nested, don't search for middle */
10466 }
10467 else
10468 {
10469 /* Found end when searching forward or start when searching
10470 * backward: end of (nested) pair; or found middle in outer pair. */
10471 if (--nest == 1)
10472 pat = pat3; /* outer level, search for middle */
10473 }
10474
10475 if (nest == 0)
10476 {
10477 /* Found the match: return matchcount or line number. */
10478 if (flags & SP_RETCOUNT)
10479 ++retval;
10480 else
10481 retval = pos.lnum;
10482 if (flags & SP_SETPCMARK)
10483 setpcmark();
10484 curwin->w_cursor = pos;
10485 if (!(flags & SP_REPEAT))
10486 break;
10487 nest = 1; /* search for next unmatched */
10488 }
10489 }
10490
10491 if (match_pos != NULL)
10492 {
10493 /* Store the match cursor position */
10494 match_pos->lnum = curwin->w_cursor.lnum;
10495 match_pos->col = curwin->w_cursor.col + 1;
10496 }
10497
10498 /* If 'n' flag is used or search failed: restore cursor position. */
10499 if ((flags & SP_NOMOVE) || retval == 0)
10500 curwin->w_cursor = save_cursor;
10501
10502theend:
10503 vim_free(pat2);
10504 vim_free(pat3);
10505 if (p_cpo == empty_option)
10506 p_cpo = save_cpo;
10507 else
10508 /* Darn, evaluating the {skip} expression changed the value. */
10509 free_string_option(save_cpo);
10510
10511 return retval;
10512}
10513
10514/*
10515 * "searchpos()" function
10516 */
10517 static void
10518f_searchpos(typval_T *argvars, typval_T *rettv)
10519{
10520 pos_T match_pos;
10521 int lnum = 0;
10522 int col = 0;
10523 int n;
10524 int flags = 0;
10525
10526 if (rettv_list_alloc(rettv) == FAIL)
10527 return;
10528
10529 n = search_cmn(argvars, &match_pos, &flags);
10530 if (n > 0)
10531 {
10532 lnum = match_pos.lnum;
10533 col = match_pos.col;
10534 }
10535
10536 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10537 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10538 if (flags & SP_SUBPAT)
10539 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10540}
10541
10542 static void
10543f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10544{
10545#ifdef FEAT_CLIENTSERVER
10546 char_u buf[NUMBUFLEN];
10547 char_u *server = get_tv_string_chk(&argvars[0]);
10548 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10549
10550 rettv->vval.v_number = -1;
10551 if (server == NULL || reply == NULL)
10552 return;
10553 if (check_restricted() || check_secure())
10554 return;
10555# ifdef FEAT_X11
10556 if (check_connection() == FAIL)
10557 return;
10558# endif
10559
10560 if (serverSendReply(server, reply) < 0)
10561 {
10562 EMSG(_("E258: Unable to send to client"));
10563 return;
10564 }
10565 rettv->vval.v_number = 0;
10566#else
10567 rettv->vval.v_number = -1;
10568#endif
10569}
10570
10571 static void
10572f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10573{
10574 char_u *r = NULL;
10575
10576#ifdef FEAT_CLIENTSERVER
10577# ifdef WIN32
10578 r = serverGetVimNames();
10579# else
10580 make_connection();
10581 if (X_DISPLAY != NULL)
10582 r = serverGetVimNames(X_DISPLAY);
10583# endif
10584#endif
10585 rettv->v_type = VAR_STRING;
10586 rettv->vval.v_string = r;
10587}
10588
10589/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010590 * "setbufline()" function
10591 */
10592 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010593f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010594{
10595 linenr_T lnum;
10596 buf_T *buf;
10597
10598 buf = get_buf_tv(&argvars[0], FALSE);
10599 if (buf == NULL)
10600 rettv->vval.v_number = 1; /* FAIL */
10601 else
10602 {
10603 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010604 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010605 }
10606}
10607
10608/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010609 * "setbufvar()" function
10610 */
10611 static void
10612f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10613{
10614 buf_T *buf;
10615 char_u *varname, *bufvarname;
10616 typval_T *varp;
10617 char_u nbuf[NUMBUFLEN];
10618
10619 if (check_restricted() || check_secure())
10620 return;
10621 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10622 varname = get_tv_string_chk(&argvars[1]);
10623 buf = get_buf_tv(&argvars[0], FALSE);
10624 varp = &argvars[2];
10625
10626 if (buf != NULL && varname != NULL && varp != NULL)
10627 {
10628 if (*varname == '&')
10629 {
10630 long numval;
10631 char_u *strval;
10632 int error = FALSE;
10633 aco_save_T aco;
10634
10635 /* set curbuf to be our buf, temporarily */
10636 aucmd_prepbuf(&aco, buf);
10637
10638 ++varname;
10639 numval = (long)get_tv_number_chk(varp, &error);
10640 strval = get_tv_string_buf_chk(varp, nbuf);
10641 if (!error && strval != NULL)
10642 set_option_value(varname, numval, strval, OPT_LOCAL);
10643
10644 /* reset notion of buffer */
10645 aucmd_restbuf(&aco);
10646 }
10647 else
10648 {
10649 buf_T *save_curbuf = curbuf;
10650
10651 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10652 if (bufvarname != NULL)
10653 {
10654 curbuf = buf;
10655 STRCPY(bufvarname, "b:");
10656 STRCPY(bufvarname + 2, varname);
10657 set_var(bufvarname, varp, TRUE);
10658 vim_free(bufvarname);
10659 curbuf = save_curbuf;
10660 }
10661 }
10662 }
10663}
10664
10665 static void
10666f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10667{
10668 dict_T *d;
10669 dictitem_T *di;
10670 char_u *csearch;
10671
10672 if (argvars[0].v_type != VAR_DICT)
10673 {
10674 EMSG(_(e_dictreq));
10675 return;
10676 }
10677
10678 if ((d = argvars[0].vval.v_dict) != NULL)
10679 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010680 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010681 if (csearch != NULL)
10682 {
10683#ifdef FEAT_MBYTE
10684 if (enc_utf8)
10685 {
10686 int pcc[MAX_MCO];
10687 int c = utfc_ptr2char(csearch, pcc);
10688
10689 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10690 }
10691 else
10692#endif
10693 set_last_csearch(PTR2CHAR(csearch),
10694 csearch, MB_PTR2LEN(csearch));
10695 }
10696
10697 di = dict_find(d, (char_u *)"forward", -1);
10698 if (di != NULL)
10699 set_csearch_direction((int)get_tv_number(&di->di_tv)
10700 ? FORWARD : BACKWARD);
10701
10702 di = dict_find(d, (char_u *)"until", -1);
10703 if (di != NULL)
10704 set_csearch_until(!!get_tv_number(&di->di_tv));
10705 }
10706}
10707
10708/*
10709 * "setcmdpos()" function
10710 */
10711 static void
10712f_setcmdpos(typval_T *argvars, typval_T *rettv)
10713{
10714 int pos = (int)get_tv_number(&argvars[0]) - 1;
10715
10716 if (pos >= 0)
10717 rettv->vval.v_number = set_cmdline_pos(pos);
10718}
10719
10720/*
10721 * "setfperm({fname}, {mode})" function
10722 */
10723 static void
10724f_setfperm(typval_T *argvars, typval_T *rettv)
10725{
10726 char_u *fname;
10727 char_u modebuf[NUMBUFLEN];
10728 char_u *mode_str;
10729 int i;
10730 int mask;
10731 int mode = 0;
10732
10733 rettv->vval.v_number = 0;
10734 fname = get_tv_string_chk(&argvars[0]);
10735 if (fname == NULL)
10736 return;
10737 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10738 if (mode_str == NULL)
10739 return;
10740 if (STRLEN(mode_str) != 9)
10741 {
10742 EMSG2(_(e_invarg2), mode_str);
10743 return;
10744 }
10745
10746 mask = 1;
10747 for (i = 8; i >= 0; --i)
10748 {
10749 if (mode_str[i] != '-')
10750 mode |= mask;
10751 mask = mask << 1;
10752 }
10753 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10754}
10755
10756/*
10757 * "setline()" function
10758 */
10759 static void
10760f_setline(typval_T *argvars, typval_T *rettv)
10761{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010762 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010763
Bram Moolenaarca851592018-06-06 21:04:07 +020010764 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010765}
10766
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010767/*
10768 * Used by "setqflist()" and "setloclist()" functions
10769 */
10770 static void
10771set_qf_ll_list(
10772 win_T *wp UNUSED,
10773 typval_T *list_arg UNUSED,
10774 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010775 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010776 typval_T *rettv)
10777{
10778#ifdef FEAT_QUICKFIX
10779 static char *e_invact = N_("E927: Invalid action: '%s'");
10780 char_u *act;
10781 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010782 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010783#endif
10784
10785 rettv->vval.v_number = -1;
10786
10787#ifdef FEAT_QUICKFIX
10788 if (list_arg->v_type != VAR_LIST)
10789 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010790 else if (recursive != 0)
10791 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010792 else
10793 {
10794 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010795 dict_T *d = NULL;
10796 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010797
10798 if (action_arg->v_type == VAR_STRING)
10799 {
10800 act = get_tv_string_chk(action_arg);
10801 if (act == NULL)
10802 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010803 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10804 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010805 action = *act;
10806 else
10807 EMSG2(_(e_invact), act);
10808 }
10809 else if (action_arg->v_type == VAR_UNKNOWN)
10810 action = ' ';
10811 else
10812 EMSG(_(e_stringreq));
10813
Bram Moolenaard823fa92016-08-12 16:29:27 +020010814 if (action_arg->v_type != VAR_UNKNOWN
10815 && what_arg->v_type != VAR_UNKNOWN)
10816 {
10817 if (what_arg->v_type == VAR_DICT)
10818 d = what_arg->vval.v_dict;
10819 else
10820 {
10821 EMSG(_(e_dictreq));
10822 valid_dict = FALSE;
10823 }
10824 }
10825
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010826 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010827 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010828 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10829 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010831 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010832 }
10833#endif
10834}
10835
10836/*
10837 * "setloclist()" function
10838 */
10839 static void
10840f_setloclist(typval_T *argvars, typval_T *rettv)
10841{
10842 win_T *win;
10843
10844 rettv->vval.v_number = -1;
10845
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010846 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010847 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010848 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010849}
10850
10851/*
10852 * "setmatches()" function
10853 */
10854 static void
10855f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10856{
10857#ifdef FEAT_SEARCH_EXTRA
10858 list_T *l;
10859 listitem_T *li;
10860 dict_T *d;
10861 list_T *s = NULL;
10862
10863 rettv->vval.v_number = -1;
10864 if (argvars[0].v_type != VAR_LIST)
10865 {
10866 EMSG(_(e_listreq));
10867 return;
10868 }
10869 if ((l = argvars[0].vval.v_list) != NULL)
10870 {
10871
10872 /* To some extent make sure that we are dealing with a list from
10873 * "getmatches()". */
10874 li = l->lv_first;
10875 while (li != NULL)
10876 {
10877 if (li->li_tv.v_type != VAR_DICT
10878 || (d = li->li_tv.vval.v_dict) == NULL)
10879 {
10880 EMSG(_(e_invarg));
10881 return;
10882 }
10883 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10884 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10885 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10886 && dict_find(d, (char_u *)"priority", -1) != NULL
10887 && dict_find(d, (char_u *)"id", -1) != NULL))
10888 {
10889 EMSG(_(e_invarg));
10890 return;
10891 }
10892 li = li->li_next;
10893 }
10894
10895 clear_matches(curwin);
10896 li = l->lv_first;
10897 while (li != NULL)
10898 {
10899 int i = 0;
10900 char_u buf[5];
10901 dictitem_T *di;
10902 char_u *group;
10903 int priority;
10904 int id;
10905 char_u *conceal;
10906
10907 d = li->li_tv.vval.v_dict;
10908 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10909 {
10910 if (s == NULL)
10911 {
10912 s = list_alloc();
10913 if (s == NULL)
10914 return;
10915 }
10916
10917 /* match from matchaddpos() */
10918 for (i = 1; i < 9; i++)
10919 {
10920 sprintf((char *)buf, (char *)"pos%d", i);
10921 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10922 {
10923 if (di->di_tv.v_type != VAR_LIST)
10924 return;
10925
10926 list_append_tv(s, &di->di_tv);
10927 s->lv_refcount++;
10928 }
10929 else
10930 break;
10931 }
10932 }
10933
Bram Moolenaar8f667172018-12-14 15:38:31 +010010934 group = dict_get_string(d, (char_u *)"group", TRUE);
10935 priority = (int)dict_get_number(d, (char_u *)"priority");
10936 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010937 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010010938 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010939 : NULL;
10940 if (i == 0)
10941 {
10942 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010010943 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010944 priority, id, NULL, conceal);
10945 }
10946 else
10947 {
10948 match_add(curwin, group, NULL, priority, id, s, conceal);
10949 list_unref(s);
10950 s = NULL;
10951 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010952 vim_free(group);
10953 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010954
10955 li = li->li_next;
10956 }
10957 rettv->vval.v_number = 0;
10958 }
10959#endif
10960}
10961
10962/*
10963 * "setpos()" function
10964 */
10965 static void
10966f_setpos(typval_T *argvars, typval_T *rettv)
10967{
10968 pos_T pos;
10969 int fnum;
10970 char_u *name;
10971 colnr_T curswant = -1;
10972
10973 rettv->vval.v_number = -1;
10974 name = get_tv_string_chk(argvars);
10975 if (name != NULL)
10976 {
10977 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10978 {
10979 if (--pos.col < 0)
10980 pos.col = 0;
10981 if (name[0] == '.' && name[1] == NUL)
10982 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010983 /* set cursor; "fnum" is ignored */
10984 curwin->w_cursor = pos;
10985 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010986 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010987 curwin->w_curswant = curswant - 1;
10988 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010989 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010990 check_cursor();
10991 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010992 }
10993 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10994 {
10995 /* set mark */
10996 if (setmark_pos(name[1], &pos, fnum) == OK)
10997 rettv->vval.v_number = 0;
10998 }
10999 else
11000 EMSG(_(e_invarg));
11001 }
11002 }
11003}
11004
11005/*
11006 * "setqflist()" function
11007 */
11008 static void
11009f_setqflist(typval_T *argvars, typval_T *rettv)
11010{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011011 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011012}
11013
11014/*
11015 * "setreg()" function
11016 */
11017 static void
11018f_setreg(typval_T *argvars, typval_T *rettv)
11019{
11020 int regname;
11021 char_u *strregname;
11022 char_u *stropt;
11023 char_u *strval;
11024 int append;
11025 char_u yank_type;
11026 long block_len;
11027
11028 block_len = -1;
11029 yank_type = MAUTO;
11030 append = FALSE;
11031
11032 strregname = get_tv_string_chk(argvars);
11033 rettv->vval.v_number = 1; /* FAIL is default */
11034
11035 if (strregname == NULL)
11036 return; /* type error; errmsg already given */
11037 regname = *strregname;
11038 if (regname == 0 || regname == '@')
11039 regname = '"';
11040
11041 if (argvars[2].v_type != VAR_UNKNOWN)
11042 {
11043 stropt = get_tv_string_chk(&argvars[2]);
11044 if (stropt == NULL)
11045 return; /* type error */
11046 for (; *stropt != NUL; ++stropt)
11047 switch (*stropt)
11048 {
11049 case 'a': case 'A': /* append */
11050 append = TRUE;
11051 break;
11052 case 'v': case 'c': /* character-wise selection */
11053 yank_type = MCHAR;
11054 break;
11055 case 'V': case 'l': /* line-wise selection */
11056 yank_type = MLINE;
11057 break;
11058 case 'b': case Ctrl_V: /* block-wise selection */
11059 yank_type = MBLOCK;
11060 if (VIM_ISDIGIT(stropt[1]))
11061 {
11062 ++stropt;
11063 block_len = getdigits(&stropt) - 1;
11064 --stropt;
11065 }
11066 break;
11067 }
11068 }
11069
11070 if (argvars[1].v_type == VAR_LIST)
11071 {
11072 char_u **lstval;
11073 char_u **allocval;
11074 char_u buf[NUMBUFLEN];
11075 char_u **curval;
11076 char_u **curallocval;
11077 list_T *ll = argvars[1].vval.v_list;
11078 listitem_T *li;
11079 int len;
11080
11081 /* If the list is NULL handle like an empty list. */
11082 len = ll == NULL ? 0 : ll->lv_len;
11083
11084 /* First half: use for pointers to result lines; second half: use for
11085 * pointers to allocated copies. */
11086 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11087 if (lstval == NULL)
11088 return;
11089 curval = lstval;
11090 allocval = lstval + len + 2;
11091 curallocval = allocval;
11092
11093 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11094 li = li->li_next)
11095 {
11096 strval = get_tv_string_buf_chk(&li->li_tv, buf);
11097 if (strval == NULL)
11098 goto free_lstval;
11099 if (strval == buf)
11100 {
11101 /* Need to make a copy, next get_tv_string_buf_chk() will
11102 * overwrite the string. */
11103 strval = vim_strsave(buf);
11104 if (strval == NULL)
11105 goto free_lstval;
11106 *curallocval++ = strval;
11107 }
11108 *curval++ = strval;
11109 }
11110 *curval++ = NULL;
11111
11112 write_reg_contents_lst(regname, lstval, -1,
11113 append, yank_type, block_len);
11114free_lstval:
11115 while (curallocval > allocval)
11116 vim_free(*--curallocval);
11117 vim_free(lstval);
11118 }
11119 else
11120 {
11121 strval = get_tv_string_chk(&argvars[1]);
11122 if (strval == NULL)
11123 return;
11124 write_reg_contents_ex(regname, strval, -1,
11125 append, yank_type, block_len);
11126 }
11127 rettv->vval.v_number = 0;
11128}
11129
11130/*
11131 * "settabvar()" function
11132 */
11133 static void
11134f_settabvar(typval_T *argvars, typval_T *rettv)
11135{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011136 tabpage_T *save_curtab;
11137 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011138 char_u *varname, *tabvarname;
11139 typval_T *varp;
11140
11141 rettv->vval.v_number = 0;
11142
11143 if (check_restricted() || check_secure())
11144 return;
11145
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011146 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011147 varname = get_tv_string_chk(&argvars[1]);
11148 varp = &argvars[2];
11149
Bram Moolenaar4033c552017-09-16 20:54:51 +020011150 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011151 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152 save_curtab = curtab;
11153 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011154
11155 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11156 if (tabvarname != NULL)
11157 {
11158 STRCPY(tabvarname, "t:");
11159 STRCPY(tabvarname + 2, varname);
11160 set_var(tabvarname, varp, TRUE);
11161 vim_free(tabvarname);
11162 }
11163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011164 /* Restore current tabpage */
11165 if (valid_tabpage(save_curtab))
11166 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011167 }
11168}
11169
11170/*
11171 * "settabwinvar()" function
11172 */
11173 static void
11174f_settabwinvar(typval_T *argvars, typval_T *rettv)
11175{
11176 setwinvar(argvars, rettv, 1);
11177}
11178
11179/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011180 * "settagstack()" function
11181 */
11182 static void
11183f_settagstack(typval_T *argvars, typval_T *rettv)
11184{
11185 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11186 win_T *wp;
11187 dict_T *d;
11188 int action = 'r';
11189
11190 rettv->vval.v_number = -1;
11191
11192 // first argument: window number or id
11193 wp = find_win_by_nr_or_id(&argvars[0]);
11194 if (wp == NULL)
11195 return;
11196
11197 // second argument: dict with items to set in the tag stack
11198 if (argvars[1].v_type != VAR_DICT)
11199 {
11200 EMSG(_(e_dictreq));
11201 return;
11202 }
11203 d = argvars[1].vval.v_dict;
11204 if (d == NULL)
11205 return;
11206
11207 // third argument: action - 'a' for append and 'r' for replace.
11208 // default is to replace the stack.
11209 if (argvars[2].v_type == VAR_UNKNOWN)
11210 action = 'r';
11211 else if (argvars[2].v_type == VAR_STRING)
11212 {
11213 char_u *actstr;
11214 actstr = get_tv_string_chk(&argvars[2]);
11215 if (actstr == NULL)
11216 return;
11217 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11218 action = *actstr;
11219 else
11220 {
11221 EMSG2(_(e_invact2), actstr);
11222 return;
11223 }
11224 }
11225 else
11226 {
11227 EMSG(_(e_stringreq));
11228 return;
11229 }
11230
11231 if (set_tagstack(wp, d, action) == OK)
11232 rettv->vval.v_number = 0;
11233}
11234
11235/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011236 * "setwinvar()" function
11237 */
11238 static void
11239f_setwinvar(typval_T *argvars, typval_T *rettv)
11240{
11241 setwinvar(argvars, rettv, 0);
11242}
11243
11244#ifdef FEAT_CRYPT
11245/*
11246 * "sha256({string})" function
11247 */
11248 static void
11249f_sha256(typval_T *argvars, typval_T *rettv)
11250{
11251 char_u *p;
11252
11253 p = get_tv_string(&argvars[0]);
11254 rettv->vval.v_string = vim_strsave(
11255 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11256 rettv->v_type = VAR_STRING;
11257}
11258#endif /* FEAT_CRYPT */
11259
11260/*
11261 * "shellescape({string})" function
11262 */
11263 static void
11264f_shellescape(typval_T *argvars, typval_T *rettv)
11265{
Bram Moolenaar20615522017-06-05 18:46:26 +020011266 int do_special = non_zero_arg(&argvars[1]);
11267
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011268 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020011269 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011270 rettv->v_type = VAR_STRING;
11271}
11272
11273/*
11274 * shiftwidth() function
11275 */
11276 static void
11277f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11278{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011279 rettv->vval.v_number = 0;
11280
11281 if (argvars[0].v_type != VAR_UNKNOWN)
11282 {
11283 long col;
11284
11285 col = (long)get_tv_number_chk(argvars, NULL);
11286 if (col < 0)
11287 return; // type error; errmsg already given
11288#ifdef FEAT_VARTABS
11289 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11290 return;
11291#endif
11292 }
11293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011294 rettv->vval.v_number = get_sw_value(curbuf);
11295}
11296
Bram Moolenaar162b7142018-12-21 15:17:36 +010011297#ifdef FEAT_SIGNS
11298/*
11299 * "sign_define()" function
11300 */
11301 static void
11302f_sign_define(typval_T *argvars, typval_T *rettv)
11303{
11304 char_u *name;
11305 dict_T *dict;
11306 char_u *icon = NULL;
11307 char_u *linehl = NULL;
11308 char_u *text = NULL;
11309 char_u *texthl = NULL;
11310
11311 rettv->vval.v_number = -1;
11312
11313 name = get_tv_string_chk(&argvars[0]);
11314 if (name == NULL)
11315 return;
11316
11317 if (argvars[1].v_type != VAR_UNKNOWN)
11318 {
11319 if (argvars[1].v_type != VAR_DICT)
11320 {
11321 EMSG(_(e_dictreq));
11322 return;
11323 }
11324
11325 // sign attributes
11326 dict = argvars[1].vval.v_dict;
11327 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11328 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11329 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11330 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11331 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11332 text = dict_get_string(dict, (char_u *)"text", TRUE);
11333 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11334 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11335 }
11336
11337 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11338 rettv->vval.v_number = 0;
11339
11340 vim_free(icon);
11341 vim_free(linehl);
11342 vim_free(text);
11343 vim_free(texthl);
11344}
11345
11346/*
11347 * "sign_getdefined()" function
11348 */
11349 static void
11350f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11351{
11352 char_u *name = NULL;
11353
11354 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11355 return;
11356
11357 if (argvars[0].v_type != VAR_UNKNOWN)
11358 name = get_tv_string(&argvars[0]);
11359
11360 sign_getlist(name, rettv->vval.v_list);
11361}
11362
11363/*
11364 * "sign_getplaced()" function
11365 */
11366 static void
11367f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11368{
11369 buf_T *buf = NULL;
11370 dict_T *dict;
11371 dictitem_T *di;
11372 linenr_T lnum = 0;
11373 int sign_id = 0;
11374 char_u *group = NULL;
11375 int notanum = FALSE;
11376
11377 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11378 return;
11379
11380 if (argvars[0].v_type != VAR_UNKNOWN)
11381 {
11382 // get signs placed in this buffer
11383 buf = find_buffer(&argvars[0]);
11384 if (buf == NULL)
11385 {
11386 EMSG2(_("E158: Invalid buffer name: %s"),
11387 get_tv_string(&argvars[0]));
11388 return;
11389 }
11390
11391 if (argvars[1].v_type != VAR_UNKNOWN)
11392 {
11393 if (argvars[1].v_type != VAR_DICT ||
11394 ((dict = argvars[1].vval.v_dict) == NULL))
11395 {
11396 EMSG(_(e_dictreq));
11397 return;
11398 }
11399 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11400 {
11401 // get signs placed at this line
11402 (void)get_tv_number_chk(&di->di_tv, &notanum);
11403 if (notanum)
11404 return;
11405 lnum = get_tv_lnum(&di->di_tv);
11406 }
11407 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11408 {
11409 // get sign placed with this identifier
11410 sign_id = (int)get_tv_number_chk(&di->di_tv, &notanum);
11411 if (notanum)
11412 return;
11413 }
11414 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11415 {
11416 group = get_tv_string_chk(&di->di_tv);
11417 if (group == NULL)
11418 return;
11419 }
11420 }
11421 }
11422
11423 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11424}
11425
11426/*
11427 * "sign_place()" function
11428 */
11429 static void
11430f_sign_place(typval_T *argvars, typval_T *rettv)
11431{
11432 int sign_id;
11433 char_u *group = NULL;
11434 char_u *sign_name;
11435 buf_T *buf;
11436 dict_T *dict;
11437 dictitem_T *di;
11438 linenr_T lnum = 0;
11439 int prio = SIGN_DEF_PRIO;
11440 int notanum = FALSE;
11441
11442 rettv->vval.v_number = -1;
11443
11444 // Sign identifer
11445 sign_id = (int)get_tv_number_chk(&argvars[0], &notanum);
11446 if (notanum)
11447 return;
11448 if (sign_id < 0)
11449 {
11450 EMSG(_(e_invarg));
11451 return;
11452 }
11453
11454 // Sign group
11455 group = get_tv_string_chk(&argvars[1]);
11456 if (group == NULL)
11457 return;
11458 if (group[0] == '\0')
11459 group = NULL; // global sign group
11460 else
11461 {
11462 group = vim_strsave(group);
11463 if (group == NULL)
11464 return;
11465 }
11466
11467 // Sign name
11468 sign_name = get_tv_string_chk(&argvars[2]);
11469 if (sign_name == NULL)
11470 goto cleanup;
11471
11472 // Buffer to place the sign
11473 buf = find_buffer(&argvars[3]);
11474 if (buf == NULL)
11475 {
11476 EMSG2(_("E158: Invalid buffer name: %s"), get_tv_string(&argvars[2]));
11477 goto cleanup;
11478 }
11479
11480 if (argvars[4].v_type != VAR_UNKNOWN)
11481 {
11482 if (argvars[4].v_type != VAR_DICT ||
11483 ((dict = argvars[4].vval.v_dict) == NULL))
11484 {
11485 EMSG(_(e_dictreq));
11486 goto cleanup;
11487 }
11488
11489 // Line number where the sign is to be placed
11490 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11491 {
11492 (void)get_tv_number_chk(&di->di_tv, &notanum);
11493 if (notanum)
11494 goto cleanup;
11495 lnum = get_tv_lnum(&di->di_tv);
11496 }
11497 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11498 {
11499 // Sign priority
11500 prio = (int)get_tv_number_chk(&di->di_tv, &notanum);
11501 if (notanum)
11502 goto cleanup;
11503 }
11504 }
11505
11506 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11507 rettv->vval.v_number = sign_id;
11508
11509cleanup:
11510 vim_free(group);
11511}
11512
11513/*
11514 * "sign_undefine()" function
11515 */
11516 static void
11517f_sign_undefine(typval_T *argvars, typval_T *rettv)
11518{
11519 char_u *name;
11520
11521 rettv->vval.v_number = -1;
11522
11523 if (argvars[0].v_type == VAR_UNKNOWN)
11524 {
11525 // Free all the signs
11526 free_signs();
11527 rettv->vval.v_number = 0;
11528 }
11529 else
11530 {
11531 // Free only the specified sign
11532 name = get_tv_string_chk(&argvars[0]);
11533 if (name == NULL)
11534 return;
11535
11536 if (sign_undefine_by_name(name) == OK)
11537 rettv->vval.v_number = 0;
11538 }
11539}
11540
11541/*
11542 * "sign_unplace()" function
11543 */
11544 static void
11545f_sign_unplace(typval_T *argvars, typval_T *rettv)
11546{
11547 dict_T *dict;
11548 dictitem_T *di;
11549 int sign_id = 0;
11550 buf_T *buf = NULL;
11551 char_u *group = NULL;
11552
11553 rettv->vval.v_number = -1;
11554
11555 if (argvars[0].v_type != VAR_STRING)
11556 {
11557 EMSG(_(e_invarg));
11558 return;
11559 }
11560
11561 group = get_tv_string(&argvars[0]);
11562 if (group[0] == '\0')
11563 group = NULL; // global sign group
11564 else
11565 {
11566 group = vim_strsave(group);
11567 if (group == NULL)
11568 return;
11569 }
11570
11571 if (argvars[1].v_type != VAR_UNKNOWN)
11572 {
11573 if (argvars[1].v_type != VAR_DICT)
11574 {
11575 EMSG(_(e_dictreq));
11576 return;
11577 }
11578 dict = argvars[1].vval.v_dict;
11579
11580 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11581 {
11582 buf = find_buffer(&di->di_tv);
11583 if (buf == NULL)
11584 {
11585 EMSG2(_("E158: Invalid buffer name: %s"),
11586 get_tv_string(&di->di_tv));
11587 return;
11588 }
11589 }
11590 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11591 sign_id = dict_get_number(dict, (char_u *)"id");
11592 }
11593
11594 if (buf == NULL)
11595 {
11596 // Delete the sign in all the buffers
11597 FOR_ALL_BUFFERS(buf)
11598 if (sign_unplace(sign_id, group, buf) == OK)
11599 rettv->vval.v_number = 0;
11600 }
11601 else
11602 {
11603 if (sign_unplace(sign_id, group, buf) == OK)
11604 rettv->vval.v_number = 0;
11605 }
11606 vim_free(group);
11607}
11608#endif
11609
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011610/*
11611 * "simplify()" function
11612 */
11613 static void
11614f_simplify(typval_T *argvars, typval_T *rettv)
11615{
11616 char_u *p;
11617
11618 p = get_tv_string(&argvars[0]);
11619 rettv->vval.v_string = vim_strsave(p);
11620 simplify_filename(rettv->vval.v_string); /* simplify in place */
11621 rettv->v_type = VAR_STRING;
11622}
11623
11624#ifdef FEAT_FLOAT
11625/*
11626 * "sin()" function
11627 */
11628 static void
11629f_sin(typval_T *argvars, typval_T *rettv)
11630{
11631 float_T f = 0.0;
11632
11633 rettv->v_type = VAR_FLOAT;
11634 if (get_float_arg(argvars, &f) == OK)
11635 rettv->vval.v_float = sin(f);
11636 else
11637 rettv->vval.v_float = 0.0;
11638}
11639
11640/*
11641 * "sinh()" function
11642 */
11643 static void
11644f_sinh(typval_T *argvars, typval_T *rettv)
11645{
11646 float_T f = 0.0;
11647
11648 rettv->v_type = VAR_FLOAT;
11649 if (get_float_arg(argvars, &f) == OK)
11650 rettv->vval.v_float = sinh(f);
11651 else
11652 rettv->vval.v_float = 0.0;
11653}
11654#endif
11655
11656static int
11657#ifdef __BORLANDC__
11658 _RTLENTRYF
11659#endif
11660 item_compare(const void *s1, const void *s2);
11661static int
11662#ifdef __BORLANDC__
11663 _RTLENTRYF
11664#endif
11665 item_compare2(const void *s1, const void *s2);
11666
11667/* struct used in the array that's given to qsort() */
11668typedef struct
11669{
11670 listitem_T *item;
11671 int idx;
11672} sortItem_T;
11673
11674/* struct storing information about current sort */
11675typedef struct
11676{
11677 int item_compare_ic;
11678 int item_compare_numeric;
11679 int item_compare_numbers;
11680#ifdef FEAT_FLOAT
11681 int item_compare_float;
11682#endif
11683 char_u *item_compare_func;
11684 partial_T *item_compare_partial;
11685 dict_T *item_compare_selfdict;
11686 int item_compare_func_err;
11687 int item_compare_keep_zero;
11688} sortinfo_T;
11689static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011690#define ITEM_COMPARE_FAIL 999
11691
11692/*
11693 * Compare functions for f_sort() and f_uniq() below.
11694 */
11695 static int
11696#ifdef __BORLANDC__
11697_RTLENTRYF
11698#endif
11699item_compare(const void *s1, const void *s2)
11700{
11701 sortItem_T *si1, *si2;
11702 typval_T *tv1, *tv2;
11703 char_u *p1, *p2;
11704 char_u *tofree1 = NULL, *tofree2 = NULL;
11705 int res;
11706 char_u numbuf1[NUMBUFLEN];
11707 char_u numbuf2[NUMBUFLEN];
11708
11709 si1 = (sortItem_T *)s1;
11710 si2 = (sortItem_T *)s2;
11711 tv1 = &si1->item->li_tv;
11712 tv2 = &si2->item->li_tv;
11713
11714 if (sortinfo->item_compare_numbers)
11715 {
11716 varnumber_T v1 = get_tv_number(tv1);
11717 varnumber_T v2 = get_tv_number(tv2);
11718
11719 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11720 }
11721
11722#ifdef FEAT_FLOAT
11723 if (sortinfo->item_compare_float)
11724 {
11725 float_T v1 = get_tv_float(tv1);
11726 float_T v2 = get_tv_float(tv2);
11727
11728 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11729 }
11730#endif
11731
11732 /* tv2string() puts quotes around a string and allocates memory. Don't do
11733 * that for string variables. Use a single quote when comparing with a
11734 * non-string to do what the docs promise. */
11735 if (tv1->v_type == VAR_STRING)
11736 {
11737 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11738 p1 = (char_u *)"'";
11739 else
11740 p1 = tv1->vval.v_string;
11741 }
11742 else
11743 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11744 if (tv2->v_type == VAR_STRING)
11745 {
11746 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11747 p2 = (char_u *)"'";
11748 else
11749 p2 = tv2->vval.v_string;
11750 }
11751 else
11752 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11753 if (p1 == NULL)
11754 p1 = (char_u *)"";
11755 if (p2 == NULL)
11756 p2 = (char_u *)"";
11757 if (!sortinfo->item_compare_numeric)
11758 {
11759 if (sortinfo->item_compare_ic)
11760 res = STRICMP(p1, p2);
11761 else
11762 res = STRCMP(p1, p2);
11763 }
11764 else
11765 {
11766 double n1, n2;
11767 n1 = strtod((char *)p1, (char **)&p1);
11768 n2 = strtod((char *)p2, (char **)&p2);
11769 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11770 }
11771
11772 /* When the result would be zero, compare the item indexes. Makes the
11773 * sort stable. */
11774 if (res == 0 && !sortinfo->item_compare_keep_zero)
11775 res = si1->idx > si2->idx ? 1 : -1;
11776
11777 vim_free(tofree1);
11778 vim_free(tofree2);
11779 return res;
11780}
11781
11782 static int
11783#ifdef __BORLANDC__
11784_RTLENTRYF
11785#endif
11786item_compare2(const void *s1, const void *s2)
11787{
11788 sortItem_T *si1, *si2;
11789 int res;
11790 typval_T rettv;
11791 typval_T argv[3];
11792 int dummy;
11793 char_u *func_name;
11794 partial_T *partial = sortinfo->item_compare_partial;
11795
11796 /* shortcut after failure in previous call; compare all items equal */
11797 if (sortinfo->item_compare_func_err)
11798 return 0;
11799
11800 si1 = (sortItem_T *)s1;
11801 si2 = (sortItem_T *)s2;
11802
11803 if (partial == NULL)
11804 func_name = sortinfo->item_compare_func;
11805 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011806 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011807
11808 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11809 * in the copy without changing the original list items. */
11810 copy_tv(&si1->item->li_tv, &argv[0]);
11811 copy_tv(&si2->item->li_tv, &argv[1]);
11812
11813 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11814 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011815 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011816 partial, sortinfo->item_compare_selfdict);
11817 clear_tv(&argv[0]);
11818 clear_tv(&argv[1]);
11819
11820 if (res == FAIL)
11821 res = ITEM_COMPARE_FAIL;
11822 else
11823 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11824 if (sortinfo->item_compare_func_err)
11825 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11826 clear_tv(&rettv);
11827
11828 /* When the result would be zero, compare the pointers themselves. Makes
11829 * the sort stable. */
11830 if (res == 0 && !sortinfo->item_compare_keep_zero)
11831 res = si1->idx > si2->idx ? 1 : -1;
11832
11833 return res;
11834}
11835
11836/*
11837 * "sort({list})" function
11838 */
11839 static void
11840do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11841{
11842 list_T *l;
11843 listitem_T *li;
11844 sortItem_T *ptrs;
11845 sortinfo_T *old_sortinfo;
11846 sortinfo_T info;
11847 long len;
11848 long i;
11849
11850 /* Pointer to current info struct used in compare function. Save and
11851 * restore the current one for nested calls. */
11852 old_sortinfo = sortinfo;
11853 sortinfo = &info;
11854
11855 if (argvars[0].v_type != VAR_LIST)
11856 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11857 else
11858 {
11859 l = argvars[0].vval.v_list;
11860 if (l == NULL || tv_check_lock(l->lv_lock,
11861 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11862 TRUE))
11863 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011864 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011865
11866 len = list_len(l);
11867 if (len <= 1)
11868 goto theend; /* short list sorts pretty quickly */
11869
11870 info.item_compare_ic = FALSE;
11871 info.item_compare_numeric = FALSE;
11872 info.item_compare_numbers = FALSE;
11873#ifdef FEAT_FLOAT
11874 info.item_compare_float = FALSE;
11875#endif
11876 info.item_compare_func = NULL;
11877 info.item_compare_partial = NULL;
11878 info.item_compare_selfdict = NULL;
11879 if (argvars[1].v_type != VAR_UNKNOWN)
11880 {
11881 /* optional second argument: {func} */
11882 if (argvars[1].v_type == VAR_FUNC)
11883 info.item_compare_func = argvars[1].vval.v_string;
11884 else if (argvars[1].v_type == VAR_PARTIAL)
11885 info.item_compare_partial = argvars[1].vval.v_partial;
11886 else
11887 {
11888 int error = FALSE;
11889
11890 i = (long)get_tv_number_chk(&argvars[1], &error);
11891 if (error)
11892 goto theend; /* type error; errmsg already given */
11893 if (i == 1)
11894 info.item_compare_ic = TRUE;
11895 else if (argvars[1].v_type != VAR_NUMBER)
11896 info.item_compare_func = get_tv_string(&argvars[1]);
11897 else if (i != 0)
11898 {
11899 EMSG(_(e_invarg));
11900 goto theend;
11901 }
11902 if (info.item_compare_func != NULL)
11903 {
11904 if (*info.item_compare_func == NUL)
11905 {
11906 /* empty string means default sort */
11907 info.item_compare_func = NULL;
11908 }
11909 else if (STRCMP(info.item_compare_func, "n") == 0)
11910 {
11911 info.item_compare_func = NULL;
11912 info.item_compare_numeric = TRUE;
11913 }
11914 else if (STRCMP(info.item_compare_func, "N") == 0)
11915 {
11916 info.item_compare_func = NULL;
11917 info.item_compare_numbers = TRUE;
11918 }
11919#ifdef FEAT_FLOAT
11920 else if (STRCMP(info.item_compare_func, "f") == 0)
11921 {
11922 info.item_compare_func = NULL;
11923 info.item_compare_float = TRUE;
11924 }
11925#endif
11926 else if (STRCMP(info.item_compare_func, "i") == 0)
11927 {
11928 info.item_compare_func = NULL;
11929 info.item_compare_ic = TRUE;
11930 }
11931 }
11932 }
11933
11934 if (argvars[2].v_type != VAR_UNKNOWN)
11935 {
11936 /* optional third argument: {dict} */
11937 if (argvars[2].v_type != VAR_DICT)
11938 {
11939 EMSG(_(e_dictreq));
11940 goto theend;
11941 }
11942 info.item_compare_selfdict = argvars[2].vval.v_dict;
11943 }
11944 }
11945
11946 /* Make an array with each entry pointing to an item in the List. */
11947 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11948 if (ptrs == NULL)
11949 goto theend;
11950
11951 i = 0;
11952 if (sort)
11953 {
11954 /* sort(): ptrs will be the list to sort */
11955 for (li = l->lv_first; li != NULL; li = li->li_next)
11956 {
11957 ptrs[i].item = li;
11958 ptrs[i].idx = i;
11959 ++i;
11960 }
11961
11962 info.item_compare_func_err = FALSE;
11963 info.item_compare_keep_zero = FALSE;
11964 /* test the compare function */
11965 if ((info.item_compare_func != NULL
11966 || info.item_compare_partial != NULL)
11967 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11968 == ITEM_COMPARE_FAIL)
11969 EMSG(_("E702: Sort compare function failed"));
11970 else
11971 {
11972 /* Sort the array with item pointers. */
11973 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11974 info.item_compare_func == NULL
11975 && info.item_compare_partial == NULL
11976 ? item_compare : item_compare2);
11977
11978 if (!info.item_compare_func_err)
11979 {
11980 /* Clear the List and append the items in sorted order. */
11981 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11982 l->lv_len = 0;
11983 for (i = 0; i < len; ++i)
11984 list_append(l, ptrs[i].item);
11985 }
11986 }
11987 }
11988 else
11989 {
11990 int (*item_compare_func_ptr)(const void *, const void *);
11991
11992 /* f_uniq(): ptrs will be a stack of items to remove */
11993 info.item_compare_func_err = FALSE;
11994 info.item_compare_keep_zero = TRUE;
11995 item_compare_func_ptr = info.item_compare_func != NULL
11996 || info.item_compare_partial != NULL
11997 ? item_compare2 : item_compare;
11998
11999 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12000 li = li->li_next)
12001 {
12002 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12003 == 0)
12004 ptrs[i++].item = li;
12005 if (info.item_compare_func_err)
12006 {
12007 EMSG(_("E882: Uniq compare function failed"));
12008 break;
12009 }
12010 }
12011
12012 if (!info.item_compare_func_err)
12013 {
12014 while (--i >= 0)
12015 {
12016 li = ptrs[i].item->li_next;
12017 ptrs[i].item->li_next = li->li_next;
12018 if (li->li_next != NULL)
12019 li->li_next->li_prev = ptrs[i].item;
12020 else
12021 l->lv_last = ptrs[i].item;
12022 list_fix_watch(l, li);
12023 listitem_free(li);
12024 l->lv_len--;
12025 }
12026 }
12027 }
12028
12029 vim_free(ptrs);
12030 }
12031theend:
12032 sortinfo = old_sortinfo;
12033}
12034
12035/*
12036 * "sort({list})" function
12037 */
12038 static void
12039f_sort(typval_T *argvars, typval_T *rettv)
12040{
12041 do_sort_uniq(argvars, rettv, TRUE);
12042}
12043
12044/*
12045 * "uniq({list})" function
12046 */
12047 static void
12048f_uniq(typval_T *argvars, typval_T *rettv)
12049{
12050 do_sort_uniq(argvars, rettv, FALSE);
12051}
12052
12053/*
12054 * "soundfold({word})" function
12055 */
12056 static void
12057f_soundfold(typval_T *argvars, typval_T *rettv)
12058{
12059 char_u *s;
12060
12061 rettv->v_type = VAR_STRING;
12062 s = get_tv_string(&argvars[0]);
12063#ifdef FEAT_SPELL
12064 rettv->vval.v_string = eval_soundfold(s);
12065#else
12066 rettv->vval.v_string = vim_strsave(s);
12067#endif
12068}
12069
12070/*
12071 * "spellbadword()" function
12072 */
12073 static void
12074f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12075{
12076 char_u *word = (char_u *)"";
12077 hlf_T attr = HLF_COUNT;
12078 int len = 0;
12079
12080 if (rettv_list_alloc(rettv) == FAIL)
12081 return;
12082
12083#ifdef FEAT_SPELL
12084 if (argvars[0].v_type == VAR_UNKNOWN)
12085 {
12086 /* Find the start and length of the badly spelled word. */
12087 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12088 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012089 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012090 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012091 curwin->w_set_curswant = TRUE;
12092 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012093 }
12094 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12095 {
12096 char_u *str = get_tv_string_chk(&argvars[0]);
12097 int capcol = -1;
12098
12099 if (str != NULL)
12100 {
12101 /* Check the argument for spelling. */
12102 while (*str != NUL)
12103 {
12104 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12105 if (attr != HLF_COUNT)
12106 {
12107 word = str;
12108 break;
12109 }
12110 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012111 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012112 }
12113 }
12114 }
12115#endif
12116
12117 list_append_string(rettv->vval.v_list, word, len);
12118 list_append_string(rettv->vval.v_list, (char_u *)(
12119 attr == HLF_SPB ? "bad" :
12120 attr == HLF_SPR ? "rare" :
12121 attr == HLF_SPL ? "local" :
12122 attr == HLF_SPC ? "caps" :
12123 ""), -1);
12124}
12125
12126/*
12127 * "spellsuggest()" function
12128 */
12129 static void
12130f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12131{
12132#ifdef FEAT_SPELL
12133 char_u *str;
12134 int typeerr = FALSE;
12135 int maxcount;
12136 garray_T ga;
12137 int i;
12138 listitem_T *li;
12139 int need_capital = FALSE;
12140#endif
12141
12142 if (rettv_list_alloc(rettv) == FAIL)
12143 return;
12144
12145#ifdef FEAT_SPELL
12146 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12147 {
12148 str = get_tv_string(&argvars[0]);
12149 if (argvars[1].v_type != VAR_UNKNOWN)
12150 {
12151 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
12152 if (maxcount <= 0)
12153 return;
12154 if (argvars[2].v_type != VAR_UNKNOWN)
12155 {
12156 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
12157 if (typeerr)
12158 return;
12159 }
12160 }
12161 else
12162 maxcount = 25;
12163
12164 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12165
12166 for (i = 0; i < ga.ga_len; ++i)
12167 {
12168 str = ((char_u **)ga.ga_data)[i];
12169
12170 li = listitem_alloc();
12171 if (li == NULL)
12172 vim_free(str);
12173 else
12174 {
12175 li->li_tv.v_type = VAR_STRING;
12176 li->li_tv.v_lock = 0;
12177 li->li_tv.vval.v_string = str;
12178 list_append(rettv->vval.v_list, li);
12179 }
12180 }
12181 ga_clear(&ga);
12182 }
12183#endif
12184}
12185
12186 static void
12187f_split(typval_T *argvars, typval_T *rettv)
12188{
12189 char_u *str;
12190 char_u *end;
12191 char_u *pat = NULL;
12192 regmatch_T regmatch;
12193 char_u patbuf[NUMBUFLEN];
12194 char_u *save_cpo;
12195 int match;
12196 colnr_T col = 0;
12197 int keepempty = FALSE;
12198 int typeerr = FALSE;
12199
12200 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12201 save_cpo = p_cpo;
12202 p_cpo = (char_u *)"";
12203
12204 str = get_tv_string(&argvars[0]);
12205 if (argvars[1].v_type != VAR_UNKNOWN)
12206 {
12207 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
12208 if (pat == NULL)
12209 typeerr = TRUE;
12210 if (argvars[2].v_type != VAR_UNKNOWN)
12211 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
12212 }
12213 if (pat == NULL || *pat == NUL)
12214 pat = (char_u *)"[\\x01- ]\\+";
12215
12216 if (rettv_list_alloc(rettv) == FAIL)
12217 return;
12218 if (typeerr)
12219 return;
12220
12221 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12222 if (regmatch.regprog != NULL)
12223 {
12224 regmatch.rm_ic = FALSE;
12225 while (*str != NUL || keepempty)
12226 {
12227 if (*str == NUL)
12228 match = FALSE; /* empty item at the end */
12229 else
12230 match = vim_regexec_nl(&regmatch, str, col);
12231 if (match)
12232 end = regmatch.startp[0];
12233 else
12234 end = str + STRLEN(str);
12235 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12236 && *str != NUL && match && end < regmatch.endp[0]))
12237 {
12238 if (list_append_string(rettv->vval.v_list, str,
12239 (int)(end - str)) == FAIL)
12240 break;
12241 }
12242 if (!match)
12243 break;
12244 /* Advance to just after the match. */
12245 if (regmatch.endp[0] > str)
12246 col = 0;
12247 else
12248 {
12249 /* Don't get stuck at the same match. */
12250#ifdef FEAT_MBYTE
12251 col = (*mb_ptr2len)(regmatch.endp[0]);
12252#else
12253 col = 1;
12254#endif
12255 }
12256 str = regmatch.endp[0];
12257 }
12258
12259 vim_regfree(regmatch.regprog);
12260 }
12261
12262 p_cpo = save_cpo;
12263}
12264
12265#ifdef FEAT_FLOAT
12266/*
12267 * "sqrt()" function
12268 */
12269 static void
12270f_sqrt(typval_T *argvars, typval_T *rettv)
12271{
12272 float_T f = 0.0;
12273
12274 rettv->v_type = VAR_FLOAT;
12275 if (get_float_arg(argvars, &f) == OK)
12276 rettv->vval.v_float = sqrt(f);
12277 else
12278 rettv->vval.v_float = 0.0;
12279}
12280
12281/*
12282 * "str2float()" function
12283 */
12284 static void
12285f_str2float(typval_T *argvars, typval_T *rettv)
12286{
12287 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012288 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012289
Bram Moolenaar08243d22017-01-10 16:12:29 +010012290 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012291 p = skipwhite(p + 1);
12292 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012293 if (isneg)
12294 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012295 rettv->v_type = VAR_FLOAT;
12296}
12297#endif
12298
12299/*
12300 * "str2nr()" function
12301 */
12302 static void
12303f_str2nr(typval_T *argvars, typval_T *rettv)
12304{
12305 int base = 10;
12306 char_u *p;
12307 varnumber_T n;
12308 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012309 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012310
12311 if (argvars[1].v_type != VAR_UNKNOWN)
12312 {
12313 base = (int)get_tv_number(&argvars[1]);
12314 if (base != 2 && base != 8 && base != 10 && base != 16)
12315 {
12316 EMSG(_(e_invarg));
12317 return;
12318 }
12319 }
12320
12321 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012322 isneg = (*p == '-');
12323 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012324 p = skipwhite(p + 1);
12325 switch (base)
12326 {
12327 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12328 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12329 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12330 default: what = 0;
12331 }
12332 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012333 if (isneg)
12334 rettv->vval.v_number = -n;
12335 else
12336 rettv->vval.v_number = n;
12337
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012338}
12339
12340#ifdef HAVE_STRFTIME
12341/*
12342 * "strftime({format}[, {time}])" function
12343 */
12344 static void
12345f_strftime(typval_T *argvars, typval_T *rettv)
12346{
12347 char_u result_buf[256];
12348 struct tm *curtime;
12349 time_t seconds;
12350 char_u *p;
12351
12352 rettv->v_type = VAR_STRING;
12353
12354 p = get_tv_string(&argvars[0]);
12355 if (argvars[1].v_type == VAR_UNKNOWN)
12356 seconds = time(NULL);
12357 else
12358 seconds = (time_t)get_tv_number(&argvars[1]);
12359 curtime = localtime(&seconds);
12360 /* MSVC returns NULL for an invalid value of seconds. */
12361 if (curtime == NULL)
12362 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12363 else
12364 {
12365# ifdef FEAT_MBYTE
12366 vimconv_T conv;
12367 char_u *enc;
12368
12369 conv.vc_type = CONV_NONE;
12370 enc = enc_locale();
12371 convert_setup(&conv, p_enc, enc);
12372 if (conv.vc_type != CONV_NONE)
12373 p = string_convert(&conv, p, NULL);
12374# endif
12375 if (p != NULL)
12376 (void)strftime((char *)result_buf, sizeof(result_buf),
12377 (char *)p, curtime);
12378 else
12379 result_buf[0] = NUL;
12380
12381# ifdef FEAT_MBYTE
12382 if (conv.vc_type != CONV_NONE)
12383 vim_free(p);
12384 convert_setup(&conv, enc, p_enc);
12385 if (conv.vc_type != CONV_NONE)
12386 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12387 else
12388# endif
12389 rettv->vval.v_string = vim_strsave(result_buf);
12390
12391# ifdef FEAT_MBYTE
12392 /* Release conversion descriptors */
12393 convert_setup(&conv, NULL, NULL);
12394 vim_free(enc);
12395# endif
12396 }
12397}
12398#endif
12399
12400/*
12401 * "strgetchar()" function
12402 */
12403 static void
12404f_strgetchar(typval_T *argvars, typval_T *rettv)
12405{
12406 char_u *str;
12407 int len;
12408 int error = FALSE;
12409 int charidx;
12410
12411 rettv->vval.v_number = -1;
12412 str = get_tv_string_chk(&argvars[0]);
12413 if (str == NULL)
12414 return;
12415 len = (int)STRLEN(str);
12416 charidx = (int)get_tv_number_chk(&argvars[1], &error);
12417 if (error)
12418 return;
12419#ifdef FEAT_MBYTE
12420 {
12421 int byteidx = 0;
12422
12423 while (charidx >= 0 && byteidx < len)
12424 {
12425 if (charidx == 0)
12426 {
12427 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12428 break;
12429 }
12430 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012431 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012432 }
12433 }
12434#else
12435 if (charidx < len)
12436 rettv->vval.v_number = str[charidx];
12437#endif
12438}
12439
12440/*
12441 * "stridx()" function
12442 */
12443 static void
12444f_stridx(typval_T *argvars, typval_T *rettv)
12445{
12446 char_u buf[NUMBUFLEN];
12447 char_u *needle;
12448 char_u *haystack;
12449 char_u *save_haystack;
12450 char_u *pos;
12451 int start_idx;
12452
12453 needle = get_tv_string_chk(&argvars[1]);
12454 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
12455 rettv->vval.v_number = -1;
12456 if (needle == NULL || haystack == NULL)
12457 return; /* type error; errmsg already given */
12458
12459 if (argvars[2].v_type != VAR_UNKNOWN)
12460 {
12461 int error = FALSE;
12462
12463 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
12464 if (error || start_idx >= (int)STRLEN(haystack))
12465 return;
12466 if (start_idx >= 0)
12467 haystack += start_idx;
12468 }
12469
12470 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12471 if (pos != NULL)
12472 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12473}
12474
12475/*
12476 * "string()" function
12477 */
12478 static void
12479f_string(typval_T *argvars, typval_T *rettv)
12480{
12481 char_u *tofree;
12482 char_u numbuf[NUMBUFLEN];
12483
12484 rettv->v_type = VAR_STRING;
12485 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12486 get_copyID());
12487 /* Make a copy if we have a value but it's not in allocated memory. */
12488 if (rettv->vval.v_string != NULL && tofree == NULL)
12489 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12490}
12491
12492/*
12493 * "strlen()" function
12494 */
12495 static void
12496f_strlen(typval_T *argvars, typval_T *rettv)
12497{
12498 rettv->vval.v_number = (varnumber_T)(STRLEN(
12499 get_tv_string(&argvars[0])));
12500}
12501
12502/*
12503 * "strchars()" function
12504 */
12505 static void
12506f_strchars(typval_T *argvars, typval_T *rettv)
12507{
12508 char_u *s = get_tv_string(&argvars[0]);
12509 int skipcc = 0;
12510#ifdef FEAT_MBYTE
12511 varnumber_T len = 0;
12512 int (*func_mb_ptr2char_adv)(char_u **pp);
12513#endif
12514
12515 if (argvars[1].v_type != VAR_UNKNOWN)
12516 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
12517 if (skipcc < 0 || skipcc > 1)
12518 EMSG(_(e_invarg));
12519 else
12520 {
12521#ifdef FEAT_MBYTE
12522 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12523 while (*s != NUL)
12524 {
12525 func_mb_ptr2char_adv(&s);
12526 ++len;
12527 }
12528 rettv->vval.v_number = len;
12529#else
12530 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12531#endif
12532 }
12533}
12534
12535/*
12536 * "strdisplaywidth()" function
12537 */
12538 static void
12539f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12540{
12541 char_u *s = get_tv_string(&argvars[0]);
12542 int col = 0;
12543
12544 if (argvars[1].v_type != VAR_UNKNOWN)
12545 col = (int)get_tv_number(&argvars[1]);
12546
12547 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12548}
12549
12550/*
12551 * "strwidth()" function
12552 */
12553 static void
12554f_strwidth(typval_T *argvars, typval_T *rettv)
12555{
12556 char_u *s = get_tv_string(&argvars[0]);
12557
12558 rettv->vval.v_number = (varnumber_T)(
12559#ifdef FEAT_MBYTE
12560 mb_string2cells(s, -1)
12561#else
12562 STRLEN(s)
12563#endif
12564 );
12565}
12566
12567/*
12568 * "strcharpart()" function
12569 */
12570 static void
12571f_strcharpart(typval_T *argvars, typval_T *rettv)
12572{
12573#ifdef FEAT_MBYTE
12574 char_u *p;
12575 int nchar;
12576 int nbyte = 0;
12577 int charlen;
12578 int len = 0;
12579 int slen;
12580 int error = FALSE;
12581
12582 p = get_tv_string(&argvars[0]);
12583 slen = (int)STRLEN(p);
12584
12585 nchar = (int)get_tv_number_chk(&argvars[1], &error);
12586 if (!error)
12587 {
12588 if (nchar > 0)
12589 while (nchar > 0 && nbyte < slen)
12590 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012591 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012592 --nchar;
12593 }
12594 else
12595 nbyte = nchar;
12596 if (argvars[2].v_type != VAR_UNKNOWN)
12597 {
12598 charlen = (int)get_tv_number(&argvars[2]);
12599 while (charlen > 0 && nbyte + len < slen)
12600 {
12601 int off = nbyte + len;
12602
12603 if (off < 0)
12604 len += 1;
12605 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012606 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012607 --charlen;
12608 }
12609 }
12610 else
12611 len = slen - nbyte; /* default: all bytes that are available. */
12612 }
12613
12614 /*
12615 * Only return the overlap between the specified part and the actual
12616 * string.
12617 */
12618 if (nbyte < 0)
12619 {
12620 len += nbyte;
12621 nbyte = 0;
12622 }
12623 else if (nbyte > slen)
12624 nbyte = slen;
12625 if (len < 0)
12626 len = 0;
12627 else if (nbyte + len > slen)
12628 len = slen - nbyte;
12629
12630 rettv->v_type = VAR_STRING;
12631 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12632#else
12633 f_strpart(argvars, rettv);
12634#endif
12635}
12636
12637/*
12638 * "strpart()" function
12639 */
12640 static void
12641f_strpart(typval_T *argvars, typval_T *rettv)
12642{
12643 char_u *p;
12644 int n;
12645 int len;
12646 int slen;
12647 int error = FALSE;
12648
12649 p = get_tv_string(&argvars[0]);
12650 slen = (int)STRLEN(p);
12651
12652 n = (int)get_tv_number_chk(&argvars[1], &error);
12653 if (error)
12654 len = 0;
12655 else if (argvars[2].v_type != VAR_UNKNOWN)
12656 len = (int)get_tv_number(&argvars[2]);
12657 else
12658 len = slen - n; /* default len: all bytes that are available. */
12659
12660 /*
12661 * Only return the overlap between the specified part and the actual
12662 * string.
12663 */
12664 if (n < 0)
12665 {
12666 len += n;
12667 n = 0;
12668 }
12669 else if (n > slen)
12670 n = slen;
12671 if (len < 0)
12672 len = 0;
12673 else if (n + len > slen)
12674 len = slen - n;
12675
12676 rettv->v_type = VAR_STRING;
12677 rettv->vval.v_string = vim_strnsave(p + n, len);
12678}
12679
12680/*
12681 * "strridx()" function
12682 */
12683 static void
12684f_strridx(typval_T *argvars, typval_T *rettv)
12685{
12686 char_u buf[NUMBUFLEN];
12687 char_u *needle;
12688 char_u *haystack;
12689 char_u *rest;
12690 char_u *lastmatch = NULL;
12691 int haystack_len, end_idx;
12692
12693 needle = get_tv_string_chk(&argvars[1]);
12694 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12695
12696 rettv->vval.v_number = -1;
12697 if (needle == NULL || haystack == NULL)
12698 return; /* type error; errmsg already given */
12699
12700 haystack_len = (int)STRLEN(haystack);
12701 if (argvars[2].v_type != VAR_UNKNOWN)
12702 {
12703 /* Third argument: upper limit for index */
12704 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12705 if (end_idx < 0)
12706 return; /* can never find a match */
12707 }
12708 else
12709 end_idx = haystack_len;
12710
12711 if (*needle == NUL)
12712 {
12713 /* Empty string matches past the end. */
12714 lastmatch = haystack + end_idx;
12715 }
12716 else
12717 {
12718 for (rest = haystack; *rest != '\0'; ++rest)
12719 {
12720 rest = (char_u *)strstr((char *)rest, (char *)needle);
12721 if (rest == NULL || rest > haystack + end_idx)
12722 break;
12723 lastmatch = rest;
12724 }
12725 }
12726
12727 if (lastmatch == NULL)
12728 rettv->vval.v_number = -1;
12729 else
12730 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12731}
12732
12733/*
12734 * "strtrans()" function
12735 */
12736 static void
12737f_strtrans(typval_T *argvars, typval_T *rettv)
12738{
12739 rettv->v_type = VAR_STRING;
12740 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12741}
12742
12743/*
12744 * "submatch()" function
12745 */
12746 static void
12747f_submatch(typval_T *argvars, typval_T *rettv)
12748{
12749 int error = FALSE;
12750 int no;
12751 int retList = 0;
12752
12753 no = (int)get_tv_number_chk(&argvars[0], &error);
12754 if (error)
12755 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012756 if (no < 0 || no >= NSUBEXP)
12757 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012758 EMSGN(_("E935: invalid submatch number: %d"), no);
12759 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012760 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 if (argvars[1].v_type != VAR_UNKNOWN)
12762 retList = (int)get_tv_number_chk(&argvars[1], &error);
12763 if (error)
12764 return;
12765
12766 if (retList == 0)
12767 {
12768 rettv->v_type = VAR_STRING;
12769 rettv->vval.v_string = reg_submatch(no);
12770 }
12771 else
12772 {
12773 rettv->v_type = VAR_LIST;
12774 rettv->vval.v_list = reg_submatch_list(no);
12775 }
12776}
12777
12778/*
12779 * "substitute()" function
12780 */
12781 static void
12782f_substitute(typval_T *argvars, typval_T *rettv)
12783{
12784 char_u patbuf[NUMBUFLEN];
12785 char_u subbuf[NUMBUFLEN];
12786 char_u flagsbuf[NUMBUFLEN];
12787
12788 char_u *str = get_tv_string_chk(&argvars[0]);
12789 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012790 char_u *sub = NULL;
12791 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012792 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12793
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012794 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12795 expr = &argvars[2];
12796 else
12797 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12798
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012799 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012800 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12801 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012802 rettv->vval.v_string = NULL;
12803 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012804 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012805}
12806
12807/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012808 * "swapinfo(swap_filename)" function
12809 */
12810 static void
12811f_swapinfo(typval_T *argvars, typval_T *rettv)
12812{
12813 if (rettv_dict_alloc(rettv) == OK)
12814 get_b0_dict(get_tv_string(argvars), rettv->vval.v_dict);
12815}
12816
12817/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020012818 * "swapname(expr)" function
12819 */
12820 static void
12821f_swapname(typval_T *argvars, typval_T *rettv)
12822{
12823 buf_T *buf;
12824
12825 rettv->v_type = VAR_STRING;
12826 buf = get_buf_tv(&argvars[0], FALSE);
12827 if (buf == NULL || buf->b_ml.ml_mfp == NULL
12828 || buf->b_ml.ml_mfp->mf_fname == NULL)
12829 rettv->vval.v_string = NULL;
12830 else
12831 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
12832}
12833
12834/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012835 * "synID(lnum, col, trans)" function
12836 */
12837 static void
12838f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12839{
12840 int id = 0;
12841#ifdef FEAT_SYN_HL
12842 linenr_T lnum;
12843 colnr_T col;
12844 int trans;
12845 int transerr = FALSE;
12846
12847 lnum = get_tv_lnum(argvars); /* -1 on type error */
12848 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12849 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12850
12851 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12852 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12853 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12854#endif
12855
12856 rettv->vval.v_number = id;
12857}
12858
12859/*
12860 * "synIDattr(id, what [, mode])" function
12861 */
12862 static void
12863f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12864{
12865 char_u *p = NULL;
12866#ifdef FEAT_SYN_HL
12867 int id;
12868 char_u *what;
12869 char_u *mode;
12870 char_u modebuf[NUMBUFLEN];
12871 int modec;
12872
12873 id = (int)get_tv_number(&argvars[0]);
12874 what = get_tv_string(&argvars[1]);
12875 if (argvars[2].v_type != VAR_UNKNOWN)
12876 {
12877 mode = get_tv_string_buf(&argvars[2], modebuf);
12878 modec = TOLOWER_ASC(mode[0]);
12879 if (modec != 't' && modec != 'c' && modec != 'g')
12880 modec = 0; /* replace invalid with current */
12881 }
12882 else
12883 {
12884#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12885 if (USE_24BIT)
12886 modec = 'g';
12887 else
12888#endif
12889 if (t_colors > 1)
12890 modec = 'c';
12891 else
12892 modec = 't';
12893 }
12894
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012895 switch (TOLOWER_ASC(what[0]))
12896 {
12897 case 'b':
12898 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12899 p = highlight_color(id, what, modec);
12900 else /* bold */
12901 p = highlight_has_attr(id, HL_BOLD, modec);
12902 break;
12903
12904 case 'f': /* fg[#] or font */
12905 p = highlight_color(id, what, modec);
12906 break;
12907
12908 case 'i':
12909 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12910 p = highlight_has_attr(id, HL_INVERSE, modec);
12911 else /* italic */
12912 p = highlight_has_attr(id, HL_ITALIC, modec);
12913 break;
12914
12915 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012916 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012917 break;
12918
12919 case 'r': /* reverse */
12920 p = highlight_has_attr(id, HL_INVERSE, modec);
12921 break;
12922
12923 case 's':
12924 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12925 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012926 /* strikeout */
12927 else if (TOLOWER_ASC(what[1]) == 't' &&
12928 TOLOWER_ASC(what[2]) == 'r')
12929 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012930 else /* standout */
12931 p = highlight_has_attr(id, HL_STANDOUT, modec);
12932 break;
12933
12934 case 'u':
12935 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12936 /* underline */
12937 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12938 else
12939 /* undercurl */
12940 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12941 break;
12942 }
12943
12944 if (p != NULL)
12945 p = vim_strsave(p);
12946#endif
12947 rettv->v_type = VAR_STRING;
12948 rettv->vval.v_string = p;
12949}
12950
12951/*
12952 * "synIDtrans(id)" function
12953 */
12954 static void
12955f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12956{
12957 int id;
12958
12959#ifdef FEAT_SYN_HL
12960 id = (int)get_tv_number(&argvars[0]);
12961
12962 if (id > 0)
12963 id = syn_get_final_id(id);
12964 else
12965#endif
12966 id = 0;
12967
12968 rettv->vval.v_number = id;
12969}
12970
12971/*
12972 * "synconcealed(lnum, col)" function
12973 */
12974 static void
12975f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12976{
12977#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12978 linenr_T lnum;
12979 colnr_T col;
12980 int syntax_flags = 0;
12981 int cchar;
12982 int matchid = 0;
12983 char_u str[NUMBUFLEN];
12984#endif
12985
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012986 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012987
12988#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12989 lnum = get_tv_lnum(argvars); /* -1 on type error */
12990 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12991
12992 vim_memset(str, NUL, sizeof(str));
12993
12994 if (rettv_list_alloc(rettv) != FAIL)
12995 {
12996 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12997 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12998 && curwin->w_p_cole > 0)
12999 {
13000 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13001 syntax_flags = get_syntax_info(&matchid);
13002
13003 /* get the conceal character */
13004 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13005 {
13006 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013007 if (cchar == NUL && curwin->w_p_cole == 1)
13008 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013009 if (cchar != NUL)
13010 {
13011# ifdef FEAT_MBYTE
13012 if (has_mbyte)
13013 (*mb_char2bytes)(cchar, str);
13014 else
13015# endif
13016 str[0] = cchar;
13017 }
13018 }
13019 }
13020
13021 list_append_number(rettv->vval.v_list,
13022 (syntax_flags & HL_CONCEAL) != 0);
13023 /* -1 to auto-determine strlen */
13024 list_append_string(rettv->vval.v_list, str, -1);
13025 list_append_number(rettv->vval.v_list, matchid);
13026 }
13027#endif
13028}
13029
13030/*
13031 * "synstack(lnum, col)" function
13032 */
13033 static void
13034f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13035{
13036#ifdef FEAT_SYN_HL
13037 linenr_T lnum;
13038 colnr_T col;
13039 int i;
13040 int id;
13041#endif
13042
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013043 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013044
13045#ifdef FEAT_SYN_HL
13046 lnum = get_tv_lnum(argvars); /* -1 on type error */
13047 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
13048
13049 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13050 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13051 && rettv_list_alloc(rettv) != FAIL)
13052 {
13053 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13054 for (i = 0; ; ++i)
13055 {
13056 id = syn_get_stack_item(i);
13057 if (id < 0)
13058 break;
13059 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13060 break;
13061 }
13062 }
13063#endif
13064}
13065
13066 static void
13067get_cmd_output_as_rettv(
13068 typval_T *argvars,
13069 typval_T *rettv,
13070 int retlist)
13071{
13072 char_u *res = NULL;
13073 char_u *p;
13074 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013075 int err = FALSE;
13076 FILE *fd;
13077 list_T *list = NULL;
13078 int flags = SHELL_SILENT;
13079
13080 rettv->v_type = VAR_STRING;
13081 rettv->vval.v_string = NULL;
13082 if (check_restricted() || check_secure())
13083 goto errret;
13084
13085 if (argvars[1].v_type != VAR_UNKNOWN)
13086 {
13087 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013088 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013089 * command.
13090 */
13091 if ((infile = vim_tempname('i', TRUE)) == NULL)
13092 {
13093 EMSG(_(e_notmp));
13094 goto errret;
13095 }
13096
13097 fd = mch_fopen((char *)infile, WRITEBIN);
13098 if (fd == NULL)
13099 {
13100 EMSG2(_(e_notopen), infile);
13101 goto errret;
13102 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013103 if (argvars[1].v_type == VAR_NUMBER)
13104 {
13105 linenr_T lnum;
13106 buf_T *buf;
13107
13108 buf = buflist_findnr(argvars[1].vval.v_number);
13109 if (buf == NULL)
13110 {
13111 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013112 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013113 goto errret;
13114 }
13115
13116 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13117 {
13118 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13119 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13120 {
13121 err = TRUE;
13122 break;
13123 }
13124 if (putc(NL, fd) == EOF)
13125 {
13126 err = TRUE;
13127 break;
13128 }
13129 }
13130 }
13131 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013132 {
13133 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13134 err = TRUE;
13135 }
13136 else
13137 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013138 size_t len;
13139 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013140
13141 p = get_tv_string_buf_chk(&argvars[1], buf);
13142 if (p == NULL)
13143 {
13144 fclose(fd);
13145 goto errret; /* type error; errmsg already given */
13146 }
13147 len = STRLEN(p);
13148 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13149 err = TRUE;
13150 }
13151 if (fclose(fd) != 0)
13152 err = TRUE;
13153 if (err)
13154 {
13155 EMSG(_("E677: Error writing temp file"));
13156 goto errret;
13157 }
13158 }
13159
13160 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13161 * echoes typeahead, that messes up the display. */
13162 if (!msg_silent)
13163 flags += SHELL_COOKED;
13164
13165 if (retlist)
13166 {
13167 int len;
13168 listitem_T *li;
13169 char_u *s = NULL;
13170 char_u *start;
13171 char_u *end;
13172 int i;
13173
13174 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
13175 if (res == NULL)
13176 goto errret;
13177
13178 list = list_alloc();
13179 if (list == NULL)
13180 goto errret;
13181
13182 for (i = 0; i < len; ++i)
13183 {
13184 start = res + i;
13185 while (i < len && res[i] != NL)
13186 ++i;
13187 end = res + i;
13188
13189 s = alloc((unsigned)(end - start + 1));
13190 if (s == NULL)
13191 goto errret;
13192
13193 for (p = s; start < end; ++p, ++start)
13194 *p = *start == NUL ? NL : *start;
13195 *p = NUL;
13196
13197 li = listitem_alloc();
13198 if (li == NULL)
13199 {
13200 vim_free(s);
13201 goto errret;
13202 }
13203 li->li_tv.v_type = VAR_STRING;
13204 li->li_tv.v_lock = 0;
13205 li->li_tv.vval.v_string = s;
13206 list_append(list, li);
13207 }
13208
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013209 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013210 list = NULL;
13211 }
13212 else
13213 {
13214 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
13215#ifdef USE_CR
13216 /* translate <CR> into <NL> */
13217 if (res != NULL)
13218 {
13219 char_u *s;
13220
13221 for (s = res; *s; ++s)
13222 {
13223 if (*s == CAR)
13224 *s = NL;
13225 }
13226 }
13227#else
13228# ifdef USE_CRNL
13229 /* translate <CR><NL> into <NL> */
13230 if (res != NULL)
13231 {
13232 char_u *s, *d;
13233
13234 d = res;
13235 for (s = res; *s; ++s)
13236 {
13237 if (s[0] == CAR && s[1] == NL)
13238 ++s;
13239 *d++ = *s;
13240 }
13241 *d = NUL;
13242 }
13243# endif
13244#endif
13245 rettv->vval.v_string = res;
13246 res = NULL;
13247 }
13248
13249errret:
13250 if (infile != NULL)
13251 {
13252 mch_remove(infile);
13253 vim_free(infile);
13254 }
13255 if (res != NULL)
13256 vim_free(res);
13257 if (list != NULL)
13258 list_free(list);
13259}
13260
13261/*
13262 * "system()" function
13263 */
13264 static void
13265f_system(typval_T *argvars, typval_T *rettv)
13266{
13267 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13268}
13269
13270/*
13271 * "systemlist()" function
13272 */
13273 static void
13274f_systemlist(typval_T *argvars, typval_T *rettv)
13275{
13276 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13277}
13278
13279/*
13280 * "tabpagebuflist()" function
13281 */
13282 static void
13283f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13284{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013285 tabpage_T *tp;
13286 win_T *wp = NULL;
13287
13288 if (argvars[0].v_type == VAR_UNKNOWN)
13289 wp = firstwin;
13290 else
13291 {
13292 tp = find_tabpage((int)get_tv_number(&argvars[0]));
13293 if (tp != NULL)
13294 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13295 }
13296 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13297 {
13298 for (; wp != NULL; wp = wp->w_next)
13299 if (list_append_number(rettv->vval.v_list,
13300 wp->w_buffer->b_fnum) == FAIL)
13301 break;
13302 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013303}
13304
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013305/*
13306 * "tabpagenr()" function
13307 */
13308 static void
13309f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13310{
13311 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013312 char_u *arg;
13313
13314 if (argvars[0].v_type != VAR_UNKNOWN)
13315 {
13316 arg = get_tv_string_chk(&argvars[0]);
13317 nr = 0;
13318 if (arg != NULL)
13319 {
13320 if (STRCMP(arg, "$") == 0)
13321 nr = tabpage_index(NULL) - 1;
13322 else
13323 EMSG2(_(e_invexpr2), arg);
13324 }
13325 }
13326 else
13327 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013328 rettv->vval.v_number = nr;
13329}
13330
13331
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013332/*
13333 * Common code for tabpagewinnr() and winnr().
13334 */
13335 static int
13336get_winnr(tabpage_T *tp, typval_T *argvar)
13337{
13338 win_T *twin;
13339 int nr = 1;
13340 win_T *wp;
13341 char_u *arg;
13342
13343 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13344 if (argvar->v_type != VAR_UNKNOWN)
13345 {
13346 arg = get_tv_string_chk(argvar);
13347 if (arg == NULL)
13348 nr = 0; /* type error; errmsg already given */
13349 else if (STRCMP(arg, "$") == 0)
13350 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13351 else if (STRCMP(arg, "#") == 0)
13352 {
13353 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13354 if (twin == NULL)
13355 nr = 0;
13356 }
13357 else
13358 {
13359 EMSG2(_(e_invexpr2), arg);
13360 nr = 0;
13361 }
13362 }
13363
13364 if (nr > 0)
13365 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13366 wp != twin; wp = wp->w_next)
13367 {
13368 if (wp == NULL)
13369 {
13370 /* didn't find it in this tabpage */
13371 nr = 0;
13372 break;
13373 }
13374 ++nr;
13375 }
13376 return nr;
13377}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013378
13379/*
13380 * "tabpagewinnr()" function
13381 */
13382 static void
13383f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13384{
13385 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013386 tabpage_T *tp;
13387
13388 tp = find_tabpage((int)get_tv_number(&argvars[0]));
13389 if (tp == NULL)
13390 nr = 0;
13391 else
13392 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013393 rettv->vval.v_number = nr;
13394}
13395
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013396/*
13397 * "tagfiles()" function
13398 */
13399 static void
13400f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13401{
13402 char_u *fname;
13403 tagname_T tn;
13404 int first;
13405
13406 if (rettv_list_alloc(rettv) == FAIL)
13407 return;
13408 fname = alloc(MAXPATHL);
13409 if (fname == NULL)
13410 return;
13411
13412 for (first = TRUE; ; first = FALSE)
13413 if (get_tagfname(&tn, first, fname) == FAIL
13414 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13415 break;
13416 tagname_free(&tn);
13417 vim_free(fname);
13418}
13419
13420/*
13421 * "taglist()" function
13422 */
13423 static void
13424f_taglist(typval_T *argvars, typval_T *rettv)
13425{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013426 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013427 char_u *tag_pattern;
13428
13429 tag_pattern = get_tv_string(&argvars[0]);
13430
13431 rettv->vval.v_number = FALSE;
13432 if (*tag_pattern == NUL)
13433 return;
13434
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013435 if (argvars[1].v_type != VAR_UNKNOWN)
13436 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013437 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013438 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013439}
13440
13441/*
13442 * "tempname()" function
13443 */
13444 static void
13445f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13446{
13447 static int x = 'A';
13448
13449 rettv->v_type = VAR_STRING;
13450 rettv->vval.v_string = vim_tempname(x, FALSE);
13451
13452 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13453 * names. Skip 'I' and 'O', they are used for shell redirection. */
13454 do
13455 {
13456 if (x == 'Z')
13457 x = '0';
13458 else if (x == '9')
13459 x = 'A';
13460 else
13461 {
13462#ifdef EBCDIC
13463 if (x == 'I')
13464 x = 'J';
13465 else if (x == 'R')
13466 x = 'S';
13467 else
13468#endif
13469 ++x;
13470 }
13471 } while (x == 'I' || x == 'O');
13472}
13473
13474#ifdef FEAT_FLOAT
13475/*
13476 * "tan()" function
13477 */
13478 static void
13479f_tan(typval_T *argvars, typval_T *rettv)
13480{
13481 float_T f = 0.0;
13482
13483 rettv->v_type = VAR_FLOAT;
13484 if (get_float_arg(argvars, &f) == OK)
13485 rettv->vval.v_float = tan(f);
13486 else
13487 rettv->vval.v_float = 0.0;
13488}
13489
13490/*
13491 * "tanh()" function
13492 */
13493 static void
13494f_tanh(typval_T *argvars, typval_T *rettv)
13495{
13496 float_T f = 0.0;
13497
13498 rettv->v_type = VAR_FLOAT;
13499 if (get_float_arg(argvars, &f) == OK)
13500 rettv->vval.v_float = tanh(f);
13501 else
13502 rettv->vval.v_float = 0.0;
13503}
13504#endif
13505
13506/*
13507 * "test_alloc_fail(id, countdown, repeat)" function
13508 */
13509 static void
13510f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13511{
13512 if (argvars[0].v_type != VAR_NUMBER
13513 || argvars[0].vval.v_number <= 0
13514 || argvars[1].v_type != VAR_NUMBER
13515 || argvars[1].vval.v_number < 0
13516 || argvars[2].v_type != VAR_NUMBER)
13517 EMSG(_(e_invarg));
13518 else
13519 {
13520 alloc_fail_id = argvars[0].vval.v_number;
13521 if (alloc_fail_id >= aid_last)
13522 EMSG(_(e_invarg));
13523 alloc_fail_countdown = argvars[1].vval.v_number;
13524 alloc_fail_repeat = argvars[2].vval.v_number;
13525 did_outofmem_msg = FALSE;
13526 }
13527}
13528
13529/*
13530 * "test_autochdir()"
13531 */
13532 static void
13533f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13534{
13535#if defined(FEAT_AUTOCHDIR)
13536 test_autochdir = TRUE;
13537#endif
13538}
13539
13540/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013541 * "test_feedinput()"
13542 */
13543 static void
13544f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13545{
13546#ifdef USE_INPUT_BUF
13547 char_u *val = get_tv_string_chk(&argvars[0]);
13548
13549 if (val != NULL)
13550 {
13551 trash_input_buf();
13552 add_to_input_buf_csi(val, (int)STRLEN(val));
13553 }
13554#endif
13555}
13556
13557/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013558 * "test_option_not_set({name})" function
13559 */
13560 static void
13561f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13562{
13563 char_u *name = (char_u *)"";
13564
13565 if (argvars[0].v_type != VAR_STRING)
13566 EMSG(_(e_invarg));
13567 else
13568 {
Bram Moolenaarbf1c1b82018-09-13 21:30:05 +020013569 name = get_tv_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013570 if (reset_option_was_set(name) == FAIL)
13571 EMSG2(_(e_invarg2), name);
13572 }
13573}
13574
13575/*
13576 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013577 */
13578 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013579f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013580{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013581 char_u *name = (char_u *)"";
13582 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013583 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013584
13585 if (argvars[0].v_type != VAR_STRING
13586 || (argvars[1].v_type) != VAR_NUMBER)
13587 EMSG(_(e_invarg));
13588 else
13589 {
13590 name = get_tv_string_chk(&argvars[0]);
13591 val = (int)get_tv_number(&argvars[1]);
13592
13593 if (STRCMP(name, (char_u *)"redraw") == 0)
13594 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013595 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13596 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013597 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13598 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013599 else if (STRCMP(name, (char_u *)"starting") == 0)
13600 {
13601 if (val)
13602 {
13603 if (save_starting < 0)
13604 save_starting = starting;
13605 starting = 0;
13606 }
13607 else
13608 {
13609 starting = save_starting;
13610 save_starting = -1;
13611 }
13612 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013613 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13614 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013615 else if (STRCMP(name, (char_u *)"ALL") == 0)
13616 {
13617 disable_char_avail_for_testing = FALSE;
13618 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013619 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013620 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013621 if (save_starting >= 0)
13622 {
13623 starting = save_starting;
13624 save_starting = -1;
13625 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013626 }
13627 else
13628 EMSG2(_(e_invarg2), name);
13629 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013630}
13631
13632/*
13633 * "test_garbagecollect_now()" function
13634 */
13635 static void
13636f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13637{
13638 /* This is dangerous, any Lists and Dicts used internally may be freed
13639 * while still in use. */
13640 garbage_collect(TRUE);
13641}
13642
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013643/*
13644 * "test_ignore_error()" function
13645 */
13646 static void
13647f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13648{
13649 ignore_error_for_testing(get_tv_string(&argvars[0]));
13650}
13651
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013652#ifdef FEAT_JOB_CHANNEL
13653 static void
13654f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13655{
13656 rettv->v_type = VAR_CHANNEL;
13657 rettv->vval.v_channel = NULL;
13658}
13659#endif
13660
13661 static void
13662f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13663{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013664 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013665}
13666
13667#ifdef FEAT_JOB_CHANNEL
13668 static void
13669f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13670{
13671 rettv->v_type = VAR_JOB;
13672 rettv->vval.v_job = NULL;
13673}
13674#endif
13675
13676 static void
13677f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13678{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013679 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013680}
13681
13682 static void
13683f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13684{
13685 rettv->v_type = VAR_PARTIAL;
13686 rettv->vval.v_partial = NULL;
13687}
13688
13689 static void
13690f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13691{
13692 rettv->v_type = VAR_STRING;
13693 rettv->vval.v_string = NULL;
13694}
13695
Bram Moolenaarab186732018-09-14 21:27:06 +020013696#ifdef FEAT_GUI
13697 static void
13698f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13699{
13700 char_u *which;
13701 long value;
13702 int dragging;
13703 scrollbar_T *sb = NULL;
13704
13705 if (argvars[0].v_type != VAR_STRING
13706 || (argvars[1].v_type) != VAR_NUMBER
13707 || (argvars[2].v_type) != VAR_NUMBER)
13708 {
13709 EMSG(_(e_invarg));
13710 return;
13711 }
13712 which = get_tv_string(&argvars[0]);
13713 value = get_tv_number(&argvars[1]);
13714 dragging = get_tv_number(&argvars[2]);
13715
13716 if (STRCMP(which, "left") == 0)
13717 sb = &curwin->w_scrollbars[SBAR_LEFT];
13718 else if (STRCMP(which, "right") == 0)
13719 sb = &curwin->w_scrollbars[SBAR_RIGHT];
13720 else if (STRCMP(which, "hor") == 0)
13721 sb = &gui.bottom_sbar;
13722 if (sb == NULL)
13723 {
13724 EMSG2(_(e_invarg2), which);
13725 return;
13726 }
13727 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020013728# ifndef USE_ON_FLY_SCROLL
13729 // need to loop through normal_cmd() to handle the scroll events
13730 exec_normal(FALSE, TRUE, FALSE);
13731# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020013732}
13733#endif
13734
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013735 static void
13736f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13737{
13738 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13739}
13740
13741#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13742/*
13743 * Get a callback from "arg". It can be a Funcref or a function name.
13744 * When "arg" is zero return an empty string.
13745 * Return NULL for an invalid argument.
13746 */
13747 char_u *
13748get_callback(typval_T *arg, partial_T **pp)
13749{
13750 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13751 {
13752 *pp = arg->vval.v_partial;
13753 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013754 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013755 }
13756 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013757 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013758 {
13759 func_ref(arg->vval.v_string);
13760 return arg->vval.v_string;
13761 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013762 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13763 return (char_u *)"";
13764 EMSG(_("E921: Invalid callback argument"));
13765 return NULL;
13766}
13767
13768/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013769 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013770 */
13771 void
13772free_callback(char_u *callback, partial_T *partial)
13773{
13774 if (partial != NULL)
13775 partial_unref(partial);
13776 else if (callback != NULL)
13777 {
13778 func_unref(callback);
13779 vim_free(callback);
13780 }
13781}
13782#endif
13783
13784#ifdef FEAT_TIMERS
13785/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013786 * "timer_info([timer])" function
13787 */
13788 static void
13789f_timer_info(typval_T *argvars, typval_T *rettv)
13790{
13791 timer_T *timer = NULL;
13792
13793 if (rettv_list_alloc(rettv) != OK)
13794 return;
13795 if (argvars[0].v_type != VAR_UNKNOWN)
13796 {
13797 if (argvars[0].v_type != VAR_NUMBER)
13798 EMSG(_(e_number_exp));
13799 else
13800 {
13801 timer = find_timer((int)get_tv_number(&argvars[0]));
13802 if (timer != NULL)
13803 add_timer_info(rettv, timer);
13804 }
13805 }
13806 else
13807 add_timer_info_all(rettv);
13808}
13809
13810/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013811 * "timer_pause(timer, paused)" function
13812 */
13813 static void
13814f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13815{
13816 timer_T *timer = NULL;
13817 int paused = (int)get_tv_number(&argvars[1]);
13818
13819 if (argvars[0].v_type != VAR_NUMBER)
13820 EMSG(_(e_number_exp));
13821 else
13822 {
13823 timer = find_timer((int)get_tv_number(&argvars[0]));
13824 if (timer != NULL)
13825 timer->tr_paused = paused;
13826 }
13827}
13828
13829/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013830 * "timer_start(time, callback [, options])" function
13831 */
13832 static void
13833f_timer_start(typval_T *argvars, typval_T *rettv)
13834{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013835 long msec = (long)get_tv_number(&argvars[0]);
13836 timer_T *timer;
13837 int repeat = 0;
13838 char_u *callback;
13839 dict_T *dict;
13840 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013841
Bram Moolenaar75537a92016-09-05 22:45:28 +020013842 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013843 if (check_secure())
13844 return;
13845 if (argvars[2].v_type != VAR_UNKNOWN)
13846 {
13847 if (argvars[2].v_type != VAR_DICT
13848 || (dict = argvars[2].vval.v_dict) == NULL)
13849 {
13850 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13851 return;
13852 }
13853 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013854 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013855 }
13856
Bram Moolenaar75537a92016-09-05 22:45:28 +020013857 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013858 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013859 return;
13860
13861 timer = create_timer(msec, repeat);
13862 if (timer == NULL)
13863 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013864 else
13865 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013866 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013867 timer->tr_callback = vim_strsave(callback);
13868 else
13869 /* pointer into the partial */
13870 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013871 timer->tr_partial = partial;
13872 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013873 }
13874}
13875
13876/*
13877 * "timer_stop(timer)" function
13878 */
13879 static void
13880f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13881{
13882 timer_T *timer;
13883
13884 if (argvars[0].v_type != VAR_NUMBER)
13885 {
13886 EMSG(_(e_number_exp));
13887 return;
13888 }
13889 timer = find_timer((int)get_tv_number(&argvars[0]));
13890 if (timer != NULL)
13891 stop_timer(timer);
13892}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013893
13894/*
13895 * "timer_stopall()" function
13896 */
13897 static void
13898f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13899{
13900 stop_all_timers();
13901}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013902#endif
13903
13904/*
13905 * "tolower(string)" function
13906 */
13907 static void
13908f_tolower(typval_T *argvars, typval_T *rettv)
13909{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013910 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013911 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013912}
13913
13914/*
13915 * "toupper(string)" function
13916 */
13917 static void
13918f_toupper(typval_T *argvars, typval_T *rettv)
13919{
13920 rettv->v_type = VAR_STRING;
13921 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13922}
13923
13924/*
13925 * "tr(string, fromstr, tostr)" function
13926 */
13927 static void
13928f_tr(typval_T *argvars, typval_T *rettv)
13929{
13930 char_u *in_str;
13931 char_u *fromstr;
13932 char_u *tostr;
13933 char_u *p;
13934#ifdef FEAT_MBYTE
13935 int inlen;
13936 int fromlen;
13937 int tolen;
13938 int idx;
13939 char_u *cpstr;
13940 int cplen;
13941 int first = TRUE;
13942#endif
13943 char_u buf[NUMBUFLEN];
13944 char_u buf2[NUMBUFLEN];
13945 garray_T ga;
13946
13947 in_str = get_tv_string(&argvars[0]);
13948 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13949 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13950
13951 /* Default return value: empty string. */
13952 rettv->v_type = VAR_STRING;
13953 rettv->vval.v_string = NULL;
13954 if (fromstr == NULL || tostr == NULL)
13955 return; /* type error; errmsg already given */
13956 ga_init2(&ga, (int)sizeof(char), 80);
13957
13958#ifdef FEAT_MBYTE
13959 if (!has_mbyte)
13960#endif
13961 /* not multi-byte: fromstr and tostr must be the same length */
13962 if (STRLEN(fromstr) != STRLEN(tostr))
13963 {
13964#ifdef FEAT_MBYTE
13965error:
13966#endif
13967 EMSG2(_(e_invarg2), fromstr);
13968 ga_clear(&ga);
13969 return;
13970 }
13971
13972 /* fromstr and tostr have to contain the same number of chars */
13973 while (*in_str != NUL)
13974 {
13975#ifdef FEAT_MBYTE
13976 if (has_mbyte)
13977 {
13978 inlen = (*mb_ptr2len)(in_str);
13979 cpstr = in_str;
13980 cplen = inlen;
13981 idx = 0;
13982 for (p = fromstr; *p != NUL; p += fromlen)
13983 {
13984 fromlen = (*mb_ptr2len)(p);
13985 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13986 {
13987 for (p = tostr; *p != NUL; p += tolen)
13988 {
13989 tolen = (*mb_ptr2len)(p);
13990 if (idx-- == 0)
13991 {
13992 cplen = tolen;
13993 cpstr = p;
13994 break;
13995 }
13996 }
13997 if (*p == NUL) /* tostr is shorter than fromstr */
13998 goto error;
13999 break;
14000 }
14001 ++idx;
14002 }
14003
14004 if (first && cpstr == in_str)
14005 {
14006 /* Check that fromstr and tostr have the same number of
14007 * (multi-byte) characters. Done only once when a character
14008 * of in_str doesn't appear in fromstr. */
14009 first = FALSE;
14010 for (p = tostr; *p != NUL; p += tolen)
14011 {
14012 tolen = (*mb_ptr2len)(p);
14013 --idx;
14014 }
14015 if (idx != 0)
14016 goto error;
14017 }
14018
14019 (void)ga_grow(&ga, cplen);
14020 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14021 ga.ga_len += cplen;
14022
14023 in_str += inlen;
14024 }
14025 else
14026#endif
14027 {
14028 /* When not using multi-byte chars we can do it faster. */
14029 p = vim_strchr(fromstr, *in_str);
14030 if (p != NULL)
14031 ga_append(&ga, tostr[p - fromstr]);
14032 else
14033 ga_append(&ga, *in_str);
14034 ++in_str;
14035 }
14036 }
14037
14038 /* add a terminating NUL */
14039 (void)ga_grow(&ga, 1);
14040 ga_append(&ga, NUL);
14041
14042 rettv->vval.v_string = ga.ga_data;
14043}
14044
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014045/*
14046 * "trim({expr})" function
14047 */
14048 static void
14049f_trim(typval_T *argvars, typval_T *rettv)
14050{
14051 char_u buf1[NUMBUFLEN];
14052 char_u buf2[NUMBUFLEN];
14053 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
14054 char_u *mask = NULL;
14055 char_u *tail;
14056 char_u *prev;
14057 char_u *p;
14058 int c1;
14059
14060 rettv->v_type = VAR_STRING;
14061 if (head == NULL)
14062 {
14063 rettv->vval.v_string = NULL;
14064 return;
14065 }
14066
14067 if (argvars[1].v_type == VAR_STRING)
14068 mask = get_tv_string_buf_chk(&argvars[1], buf2);
14069
14070 while (*head != NUL)
14071 {
14072 c1 = PTR2CHAR(head);
14073 if (mask == NULL)
14074 {
14075 if (c1 > ' ' && c1 != 0xa0)
14076 break;
14077 }
14078 else
14079 {
14080 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14081 if (c1 == PTR2CHAR(p))
14082 break;
14083 if (*p == NUL)
14084 break;
14085 }
14086 MB_PTR_ADV(head);
14087 }
14088
14089 for (tail = head + STRLEN(head); tail > head; tail = prev)
14090 {
14091 prev = tail;
14092 MB_PTR_BACK(head, prev);
14093 c1 = PTR2CHAR(prev);
14094 if (mask == NULL)
14095 {
14096 if (c1 > ' ' && c1 != 0xa0)
14097 break;
14098 }
14099 else
14100 {
14101 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14102 if (c1 == PTR2CHAR(p))
14103 break;
14104 if (*p == NUL)
14105 break;
14106 }
14107 }
14108 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14109}
14110
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014111#ifdef FEAT_FLOAT
14112/*
14113 * "trunc({float})" function
14114 */
14115 static void
14116f_trunc(typval_T *argvars, typval_T *rettv)
14117{
14118 float_T f = 0.0;
14119
14120 rettv->v_type = VAR_FLOAT;
14121 if (get_float_arg(argvars, &f) == OK)
14122 /* trunc() is not in C90, use floor() or ceil() instead. */
14123 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14124 else
14125 rettv->vval.v_float = 0.0;
14126}
14127#endif
14128
14129/*
14130 * "type(expr)" function
14131 */
14132 static void
14133f_type(typval_T *argvars, typval_T *rettv)
14134{
14135 int n = -1;
14136
14137 switch (argvars[0].v_type)
14138 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014139 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14140 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014141 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014142 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14143 case VAR_LIST: n = VAR_TYPE_LIST; break;
14144 case VAR_DICT: n = VAR_TYPE_DICT; break;
14145 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014146 case VAR_SPECIAL:
14147 if (argvars[0].vval.v_number == VVAL_FALSE
14148 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014149 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014150 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014151 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014152 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014153 case VAR_JOB: n = VAR_TYPE_JOB; break;
14154 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014155 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014156 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014157 n = -1;
14158 break;
14159 }
14160 rettv->vval.v_number = n;
14161}
14162
14163/*
14164 * "undofile(name)" function
14165 */
14166 static void
14167f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14168{
14169 rettv->v_type = VAR_STRING;
14170#ifdef FEAT_PERSISTENT_UNDO
14171 {
14172 char_u *fname = get_tv_string(&argvars[0]);
14173
14174 if (*fname == NUL)
14175 {
14176 /* If there is no file name there will be no undo file. */
14177 rettv->vval.v_string = NULL;
14178 }
14179 else
14180 {
14181 char_u *ffname = FullName_save(fname, FALSE);
14182
14183 if (ffname != NULL)
14184 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14185 vim_free(ffname);
14186 }
14187 }
14188#else
14189 rettv->vval.v_string = NULL;
14190#endif
14191}
14192
14193/*
14194 * "undotree()" function
14195 */
14196 static void
14197f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14198{
14199 if (rettv_dict_alloc(rettv) == OK)
14200 {
14201 dict_T *dict = rettv->vval.v_dict;
14202 list_T *list;
14203
Bram Moolenaare0be1672018-07-08 16:50:37 +020014204 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14205 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14206 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14207 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14208 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14209 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014210
14211 list = list_alloc();
14212 if (list != NULL)
14213 {
14214 u_eval_tree(curbuf->b_u_oldhead, list);
14215 dict_add_list(dict, "entries", list);
14216 }
14217 }
14218}
14219
14220/*
14221 * "values(dict)" function
14222 */
14223 static void
14224f_values(typval_T *argvars, typval_T *rettv)
14225{
14226 dict_list(argvars, rettv, 1);
14227}
14228
14229/*
14230 * "virtcol(string)" function
14231 */
14232 static void
14233f_virtcol(typval_T *argvars, typval_T *rettv)
14234{
14235 colnr_T vcol = 0;
14236 pos_T *fp;
14237 int fnum = curbuf->b_fnum;
14238
14239 fp = var2fpos(&argvars[0], FALSE, &fnum);
14240 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14241 && fnum == curbuf->b_fnum)
14242 {
14243 getvvcol(curwin, fp, NULL, NULL, &vcol);
14244 ++vcol;
14245 }
14246
14247 rettv->vval.v_number = vcol;
14248}
14249
14250/*
14251 * "visualmode()" function
14252 */
14253 static void
14254f_visualmode(typval_T *argvars, typval_T *rettv)
14255{
14256 char_u str[2];
14257
14258 rettv->v_type = VAR_STRING;
14259 str[0] = curbuf->b_visual_mode_eval;
14260 str[1] = NUL;
14261 rettv->vval.v_string = vim_strsave(str);
14262
14263 /* A non-zero number or non-empty string argument: reset mode. */
14264 if (non_zero_arg(&argvars[0]))
14265 curbuf->b_visual_mode_eval = NUL;
14266}
14267
14268/*
14269 * "wildmenumode()" function
14270 */
14271 static void
14272f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14273{
14274#ifdef FEAT_WILDMENU
14275 if (wild_menu_showing)
14276 rettv->vval.v_number = 1;
14277#endif
14278}
14279
14280/*
14281 * "winbufnr(nr)" function
14282 */
14283 static void
14284f_winbufnr(typval_T *argvars, typval_T *rettv)
14285{
14286 win_T *wp;
14287
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014288 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014289 if (wp == NULL)
14290 rettv->vval.v_number = -1;
14291 else
14292 rettv->vval.v_number = wp->w_buffer->b_fnum;
14293}
14294
14295/*
14296 * "wincol()" function
14297 */
14298 static void
14299f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14300{
14301 validate_cursor();
14302 rettv->vval.v_number = curwin->w_wcol + 1;
14303}
14304
14305/*
14306 * "winheight(nr)" function
14307 */
14308 static void
14309f_winheight(typval_T *argvars, typval_T *rettv)
14310{
14311 win_T *wp;
14312
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014313 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014314 if (wp == NULL)
14315 rettv->vval.v_number = -1;
14316 else
14317 rettv->vval.v_number = wp->w_height;
14318}
14319
14320/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014321 * "winlayout()" function
14322 */
14323 static void
14324f_winlayout(typval_T *argvars, typval_T *rettv)
14325{
14326 tabpage_T *tp;
14327
14328 if (rettv_list_alloc(rettv) != OK)
14329 return;
14330
14331 if (argvars[0].v_type == VAR_UNKNOWN)
14332 tp = curtab;
14333 else
14334 {
14335 tp = find_tabpage((int)get_tv_number(&argvars[0]));
14336 if (tp == NULL)
14337 return;
14338 }
14339
14340 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14341}
14342
14343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014344 * "winline()" function
14345 */
14346 static void
14347f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14348{
14349 validate_cursor();
14350 rettv->vval.v_number = curwin->w_wrow + 1;
14351}
14352
14353/*
14354 * "winnr()" function
14355 */
14356 static void
14357f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14358{
14359 int nr = 1;
14360
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014361 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014362 rettv->vval.v_number = nr;
14363}
14364
14365/*
14366 * "winrestcmd()" function
14367 */
14368 static void
14369f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14370{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014371 win_T *wp;
14372 int winnr = 1;
14373 garray_T ga;
14374 char_u buf[50];
14375
14376 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014377 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014378 {
14379 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14380 ga_concat(&ga, buf);
14381 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14382 ga_concat(&ga, buf);
14383 ++winnr;
14384 }
14385 ga_append(&ga, NUL);
14386
14387 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014388 rettv->v_type = VAR_STRING;
14389}
14390
14391/*
14392 * "winrestview()" function
14393 */
14394 static void
14395f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14396{
14397 dict_T *dict;
14398
14399 if (argvars[0].v_type != VAR_DICT
14400 || (dict = argvars[0].vval.v_dict) == NULL)
14401 EMSG(_(e_invarg));
14402 else
14403 {
14404 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014405 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014406 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014407 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014408#ifdef FEAT_VIRTUALEDIT
14409 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014410 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014411#endif
14412 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14413 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014414 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014415 curwin->w_set_curswant = FALSE;
14416 }
14417
14418 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014419 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014420#ifdef FEAT_DIFF
14421 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014422 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014423#endif
14424 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014425 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014426 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014427 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014428
14429 check_cursor();
14430 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014431 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014432 changed_window_setting();
14433
14434 if (curwin->w_topline <= 0)
14435 curwin->w_topline = 1;
14436 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14437 curwin->w_topline = curbuf->b_ml.ml_line_count;
14438#ifdef FEAT_DIFF
14439 check_topfill(curwin, TRUE);
14440#endif
14441 }
14442}
14443
14444/*
14445 * "winsaveview()" function
14446 */
14447 static void
14448f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14449{
14450 dict_T *dict;
14451
14452 if (rettv_dict_alloc(rettv) == FAIL)
14453 return;
14454 dict = rettv->vval.v_dict;
14455
Bram Moolenaare0be1672018-07-08 16:50:37 +020014456 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14457 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014458#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020014459 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014460#endif
14461 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014462 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014463
Bram Moolenaare0be1672018-07-08 16:50:37 +020014464 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014465#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014466 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014467#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014468 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14469 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014470}
14471
14472/*
14473 * "winwidth(nr)" function
14474 */
14475 static void
14476f_winwidth(typval_T *argvars, typval_T *rettv)
14477{
14478 win_T *wp;
14479
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014480 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014481 if (wp == NULL)
14482 rettv->vval.v_number = -1;
14483 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014484 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014485}
14486
14487/*
14488 * "wordcount()" function
14489 */
14490 static void
14491f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14492{
14493 if (rettv_dict_alloc(rettv) == FAIL)
14494 return;
14495 cursor_pos_info(rettv->vval.v_dict);
14496}
14497
14498/*
14499 * "writefile()" function
14500 */
14501 static void
14502f_writefile(typval_T *argvars, typval_T *rettv)
14503{
14504 int binary = FALSE;
14505 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014506#ifdef HAVE_FSYNC
14507 int do_fsync = p_fs;
14508#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014509 char_u *fname;
14510 FILE *fd;
14511 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014512 listitem_T *li;
14513 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014514
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014515 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014516 if (check_restricted() || check_secure())
14517 return;
14518
14519 if (argvars[0].v_type != VAR_LIST)
14520 {
14521 EMSG2(_(e_listarg), "writefile()");
14522 return;
14523 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014524 list = argvars[0].vval.v_list;
14525 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014526 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014527 for (li = list->lv_first; li != NULL; li = li->li_next)
14528 if (get_tv_string_chk(&li->li_tv) == NULL)
14529 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014530
14531 if (argvars[2].v_type != VAR_UNKNOWN)
14532 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014533 char_u *arg2 = get_tv_string_chk(&argvars[2]);
14534
14535 if (arg2 == NULL)
14536 return;
14537 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014538 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014539 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014540 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014541#ifdef HAVE_FSYNC
14542 if (vim_strchr(arg2, 's') != NULL)
14543 do_fsync = TRUE;
14544 else if (vim_strchr(arg2, 'S') != NULL)
14545 do_fsync = FALSE;
14546#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014547 }
14548
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014549 fname = get_tv_string_chk(&argvars[1]);
14550 if (fname == NULL)
14551 return;
14552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014553 /* Always open the file in binary mode, library functions have a mind of
14554 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014555 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14556 append ? APPENDBIN : WRITEBIN)) == NULL)
14557 {
14558 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14559 ret = -1;
14560 }
14561 else
14562 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014563 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014564 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014565#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014566 else if (do_fsync)
14567 /* Ignore the error, the user wouldn't know what to do about it.
14568 * May happen for a device. */
Bram Moolenaar42335f52018-09-13 15:33:43 +020014569 vim_ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014570#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014571 fclose(fd);
14572 }
14573
14574 rettv->vval.v_number = ret;
14575}
14576
14577/*
14578 * "xor(expr, expr)" function
14579 */
14580 static void
14581f_xor(typval_T *argvars, typval_T *rettv)
14582{
14583 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
14584 ^ get_tv_number_chk(&argvars[1], NULL);
14585}
14586
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014587#endif /* FEAT_EVAL */