blob: 3f8e6152c531c2945461d0d6c556aa5889eaa17b [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);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100374static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100375static void f_sign_place(typval_T *argvars, typval_T *rettv);
376static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
377static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
378#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200379static void f_simplify(typval_T *argvars, typval_T *rettv);
380#ifdef FEAT_FLOAT
381static void f_sin(typval_T *argvars, typval_T *rettv);
382static void f_sinh(typval_T *argvars, typval_T *rettv);
383#endif
384static void f_sort(typval_T *argvars, typval_T *rettv);
385static void f_soundfold(typval_T *argvars, typval_T *rettv);
386static void f_spellbadword(typval_T *argvars, typval_T *rettv);
387static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
388static void f_split(typval_T *argvars, typval_T *rettv);
389#ifdef FEAT_FLOAT
390static void f_sqrt(typval_T *argvars, typval_T *rettv);
391static void f_str2float(typval_T *argvars, typval_T *rettv);
392#endif
393static void f_str2nr(typval_T *argvars, typval_T *rettv);
394static void f_strchars(typval_T *argvars, typval_T *rettv);
395#ifdef HAVE_STRFTIME
396static void f_strftime(typval_T *argvars, typval_T *rettv);
397#endif
398static void f_strgetchar(typval_T *argvars, typval_T *rettv);
399static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200400static 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},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100862 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100863 {"sign_place", 4, 5, f_sign_place},
864 {"sign_undefine", 0, 1, f_sign_undefine},
865 {"sign_unplace", 1, 2, f_sign_unplace},
866#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200867 {"simplify", 1, 1, f_simplify},
868#ifdef FEAT_FLOAT
869 {"sin", 1, 1, f_sin},
870 {"sinh", 1, 1, f_sinh},
871#endif
872 {"sort", 1, 3, f_sort},
873 {"soundfold", 1, 1, f_soundfold},
874 {"spellbadword", 0, 1, f_spellbadword},
875 {"spellsuggest", 1, 3, f_spellsuggest},
876 {"split", 1, 3, f_split},
877#ifdef FEAT_FLOAT
878 {"sqrt", 1, 1, f_sqrt},
879 {"str2float", 1, 1, f_str2float},
880#endif
881 {"str2nr", 1, 2, f_str2nr},
882 {"strcharpart", 2, 3, f_strcharpart},
883 {"strchars", 1, 2, f_strchars},
884 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
885#ifdef HAVE_STRFTIME
886 {"strftime", 1, 2, f_strftime},
887#endif
888 {"strgetchar", 2, 2, f_strgetchar},
889 {"stridx", 2, 3, f_stridx},
890 {"string", 1, 1, f_string},
891 {"strlen", 1, 1, f_strlen},
892 {"strpart", 2, 3, f_strpart},
893 {"strridx", 2, 3, f_strridx},
894 {"strtrans", 1, 1, f_strtrans},
895 {"strwidth", 1, 1, f_strwidth},
896 {"submatch", 1, 2, f_submatch},
897 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200898 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200899 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200900 {"synID", 3, 3, f_synID},
901 {"synIDattr", 2, 3, f_synIDattr},
902 {"synIDtrans", 1, 1, f_synIDtrans},
903 {"synconcealed", 2, 2, f_synconcealed},
904 {"synstack", 2, 2, f_synstack},
905 {"system", 1, 2, f_system},
906 {"systemlist", 1, 2, f_systemlist},
907 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
908 {"tabpagenr", 0, 1, f_tabpagenr},
909 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
910 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100911 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200912#ifdef FEAT_FLOAT
913 {"tan", 1, 1, f_tan},
914 {"tanh", 1, 1, f_tanh},
915#endif
916 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200917#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100918 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
919 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100920 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200921 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200922# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
923 {"term_getansicolors", 1, 1, f_term_getansicolors},
924# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200925 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200926 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200927 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200928 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200929 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200930 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200931 {"term_getstatus", 1, 1, f_term_getstatus},
932 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200933 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200934 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200935 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200936 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200937# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
938 {"term_setansicolors", 2, 2, f_term_setansicolors},
939# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100940 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100941 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200942 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200943 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200944 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200945#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200946 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
947 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200948 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100950 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951#ifdef FEAT_JOB_CHANNEL
952 {"test_null_channel", 0, 0, f_test_null_channel},
953#endif
954 {"test_null_dict", 0, 0, f_test_null_dict},
955#ifdef FEAT_JOB_CHANNEL
956 {"test_null_job", 0, 0, f_test_null_job},
957#endif
958 {"test_null_list", 0, 0, f_test_null_list},
959 {"test_null_partial", 0, 0, f_test_null_partial},
960 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200961 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100962 {"test_override", 2, 2, f_test_override},
Bram Moolenaarab186732018-09-14 21:27:06 +0200963#ifdef FEAT_GUI
964 {"test_scrollbar", 3, 3, f_test_scrollbar},
965#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200966 {"test_settime", 1, 1, f_test_settime},
967#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200968 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200969 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200970 {"timer_start", 2, 3, f_timer_start},
971 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200972 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973#endif
974 {"tolower", 1, 1, f_tolower},
975 {"toupper", 1, 1, f_toupper},
976 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100977 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200978#ifdef FEAT_FLOAT
979 {"trunc", 1, 1, f_trunc},
980#endif
981 {"type", 1, 1, f_type},
982 {"undofile", 1, 1, f_undofile},
983 {"undotree", 0, 0, f_undotree},
984 {"uniq", 1, 3, f_uniq},
985 {"values", 1, 1, f_values},
986 {"virtcol", 1, 1, f_virtcol},
987 {"visualmode", 0, 1, f_visualmode},
988 {"wildmenumode", 0, 0, f_wildmenumode},
989 {"win_findbuf", 1, 1, f_win_findbuf},
990 {"win_getid", 0, 2, f_win_getid},
991 {"win_gotoid", 1, 1, f_win_gotoid},
992 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
993 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100994 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200995 {"winbufnr", 1, 1, f_winbufnr},
996 {"wincol", 0, 0, f_wincol},
997 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200998 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200999 {"winline", 0, 0, f_winline},
1000 {"winnr", 0, 1, f_winnr},
1001 {"winrestcmd", 0, 0, f_winrestcmd},
1002 {"winrestview", 1, 1, f_winrestview},
1003 {"winsaveview", 0, 0, f_winsaveview},
1004 {"winwidth", 1, 1, f_winwidth},
1005 {"wordcount", 0, 0, f_wordcount},
1006 {"writefile", 2, 3, f_writefile},
1007 {"xor", 2, 2, f_xor},
1008};
1009
1010#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1011
1012/*
1013 * Function given to ExpandGeneric() to obtain the list of internal
1014 * or user defined function names.
1015 */
1016 char_u *
1017get_function_name(expand_T *xp, int idx)
1018{
1019 static int intidx = -1;
1020 char_u *name;
1021
1022 if (idx == 0)
1023 intidx = -1;
1024 if (intidx < 0)
1025 {
1026 name = get_user_func_name(xp, idx);
1027 if (name != NULL)
1028 return name;
1029 }
1030 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1031 {
1032 STRCPY(IObuff, functions[intidx].f_name);
1033 STRCAT(IObuff, "(");
1034 if (functions[intidx].f_max_argc == 0)
1035 STRCAT(IObuff, ")");
1036 return IObuff;
1037 }
1038
1039 return NULL;
1040}
1041
1042/*
1043 * Function given to ExpandGeneric() to obtain the list of internal or
1044 * user defined variable or function names.
1045 */
1046 char_u *
1047get_expr_name(expand_T *xp, int idx)
1048{
1049 static int intidx = -1;
1050 char_u *name;
1051
1052 if (idx == 0)
1053 intidx = -1;
1054 if (intidx < 0)
1055 {
1056 name = get_function_name(xp, idx);
1057 if (name != NULL)
1058 return name;
1059 }
1060 return get_user_var_name(xp, ++intidx);
1061}
1062
1063#endif /* FEAT_CMDL_COMPL */
1064
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001065/*
1066 * Find internal function in table above.
1067 * Return index, or -1 if not found
1068 */
1069 int
1070find_internal_func(
1071 char_u *name) /* name of the function */
1072{
1073 int first = 0;
1074 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1075 int cmp;
1076 int x;
1077
1078 /*
1079 * Find the function name in the table. Binary search.
1080 */
1081 while (first <= last)
1082 {
1083 x = first + ((unsigned)(last - first) >> 1);
1084 cmp = STRCMP(name, functions[x].f_name);
1085 if (cmp < 0)
1086 last = x - 1;
1087 else if (cmp > 0)
1088 first = x + 1;
1089 else
1090 return x;
1091 }
1092 return -1;
1093}
1094
1095 int
1096call_internal_func(
1097 char_u *name,
1098 int argcount,
1099 typval_T *argvars,
1100 typval_T *rettv)
1101{
1102 int i;
1103
1104 i = find_internal_func(name);
1105 if (i < 0)
1106 return ERROR_UNKNOWN;
1107 if (argcount < functions[i].f_min_argc)
1108 return ERROR_TOOFEW;
1109 if (argcount > functions[i].f_max_argc)
1110 return ERROR_TOOMANY;
1111 argvars[argcount].v_type = VAR_UNKNOWN;
1112 functions[i].f_func(argvars, rettv);
1113 return ERROR_NONE;
1114}
1115
1116/*
1117 * Return TRUE for a non-zero Number and a non-empty String.
1118 */
1119 static int
1120non_zero_arg(typval_T *argvars)
1121{
1122 return ((argvars[0].v_type == VAR_NUMBER
1123 && argvars[0].vval.v_number != 0)
1124 || (argvars[0].v_type == VAR_SPECIAL
1125 && argvars[0].vval.v_number == VVAL_TRUE)
1126 || (argvars[0].v_type == VAR_STRING
1127 && argvars[0].vval.v_string != NULL
1128 && *argvars[0].vval.v_string != NUL));
1129}
1130
1131/*
1132 * Get the lnum from the first argument.
1133 * Also accepts ".", "$", etc., but that only works for the current buffer.
1134 * Returns -1 on error.
1135 */
1136 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001137tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001138{
1139 typval_T rettv;
1140 linenr_T lnum;
1141
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001142 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001143 if (lnum == 0) /* no valid number, try using line() */
1144 {
1145 rettv.v_type = VAR_NUMBER;
1146 f_line(argvars, &rettv);
1147 lnum = (linenr_T)rettv.vval.v_number;
1148 clear_tv(&rettv);
1149 }
1150 return lnum;
1151}
1152
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001153/*
1154 * Get the lnum from the first argument.
1155 * Also accepts "$", then "buf" is used.
1156 * Returns 0 on error.
1157 */
1158 static linenr_T
1159tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1160{
1161 if (argvars[0].v_type == VAR_STRING
1162 && argvars[0].vval.v_string != NULL
1163 && argvars[0].vval.v_string[0] == '$'
1164 && buf != NULL)
1165 return buf->b_ml.ml_line_count;
1166 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1167}
1168
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001169#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001170/*
1171 * Get the float value of "argvars[0]" into "f".
1172 * Returns FAIL when the argument is not a Number or Float.
1173 */
1174 static int
1175get_float_arg(typval_T *argvars, float_T *f)
1176{
1177 if (argvars[0].v_type == VAR_FLOAT)
1178 {
1179 *f = argvars[0].vval.v_float;
1180 return OK;
1181 }
1182 if (argvars[0].v_type == VAR_NUMBER)
1183 {
1184 *f = (float_T)argvars[0].vval.v_number;
1185 return OK;
1186 }
1187 EMSG(_("E808: Number or Float required"));
1188 return FAIL;
1189}
1190
1191/*
1192 * "abs(expr)" function
1193 */
1194 static void
1195f_abs(typval_T *argvars, typval_T *rettv)
1196{
1197 if (argvars[0].v_type == VAR_FLOAT)
1198 {
1199 rettv->v_type = VAR_FLOAT;
1200 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1201 }
1202 else
1203 {
1204 varnumber_T n;
1205 int error = FALSE;
1206
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001207 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001208 if (error)
1209 rettv->vval.v_number = -1;
1210 else if (n > 0)
1211 rettv->vval.v_number = n;
1212 else
1213 rettv->vval.v_number = -n;
1214 }
1215}
1216
1217/*
1218 * "acos()" function
1219 */
1220 static void
1221f_acos(typval_T *argvars, typval_T *rettv)
1222{
1223 float_T f = 0.0;
1224
1225 rettv->v_type = VAR_FLOAT;
1226 if (get_float_arg(argvars, &f) == OK)
1227 rettv->vval.v_float = acos(f);
1228 else
1229 rettv->vval.v_float = 0.0;
1230}
1231#endif
1232
1233/*
1234 * "add(list, item)" function
1235 */
1236 static void
1237f_add(typval_T *argvars, typval_T *rettv)
1238{
1239 list_T *l;
1240
1241 rettv->vval.v_number = 1; /* Default: Failed */
1242 if (argvars[0].v_type == VAR_LIST)
1243 {
1244 if ((l = argvars[0].vval.v_list) != NULL
1245 && !tv_check_lock(l->lv_lock,
1246 (char_u *)N_("add() argument"), TRUE)
1247 && list_append_tv(l, &argvars[1]) == OK)
1248 copy_tv(&argvars[0], rettv);
1249 }
1250 else
1251 EMSG(_(e_listreq));
1252}
1253
1254/*
1255 * "and(expr, expr)" function
1256 */
1257 static void
1258f_and(typval_T *argvars, typval_T *rettv)
1259{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001260 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1261 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001262}
1263
1264/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001265 * If there is a window for "curbuf", make it the current window.
1266 */
1267 static void
1268find_win_for_curbuf(void)
1269{
1270 wininfo_T *wip;
1271
1272 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1273 {
1274 if (wip->wi_win != NULL)
1275 {
1276 curwin = wip->wi_win;
1277 break;
1278 }
1279 }
1280}
1281
1282/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001283 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001284 */
1285 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001286set_buffer_lines(
1287 buf_T *buf,
1288 linenr_T lnum_arg,
1289 int append,
1290 typval_T *lines,
1291 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001292{
Bram Moolenaarca851592018-06-06 21:04:07 +02001293 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1294 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 list_T *l = NULL;
1296 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001297 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001298 linenr_T append_lnum;
1299 buf_T *curbuf_save = NULL;
1300 win_T *curwin_save = NULL;
1301 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001302
Bram Moolenaarca851592018-06-06 21:04:07 +02001303 /* When using the current buffer ml_mfp will be set if needed. Useful when
1304 * setline() is used on startup. For other buffers the buffer must be
1305 * loaded. */
1306 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001308 rettv->vval.v_number = 1; /* FAIL */
1309 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001310 }
1311
Bram Moolenaarca851592018-06-06 21:04:07 +02001312 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001314 curbuf_save = curbuf;
1315 curwin_save = curwin;
1316 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001317 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001318 }
1319
1320 if (append)
1321 // appendbufline() uses the line number below which we insert
1322 append_lnum = lnum - 1;
1323 else
1324 // setbufline() uses the line number above which we insert, we only
1325 // append if it's below the last line
1326 append_lnum = curbuf->b_ml.ml_line_count;
1327
1328 if (lines->v_type == VAR_LIST)
1329 {
1330 l = lines->vval.v_list;
1331 li = l->lv_first;
1332 }
1333 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001334 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001335
1336 /* default result is zero == OK */
1337 for (;;)
1338 {
1339 if (l != NULL)
1340 {
1341 /* list argument, get next string */
1342 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001344 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001345 li = li->li_next;
1346 }
1347
Bram Moolenaarca851592018-06-06 21:04:07 +02001348 rettv->vval.v_number = 1; /* FAIL */
1349 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1350 break;
1351
1352 /* When coming here from Insert mode, sync undo, so that this can be
1353 * undone separately from what was previously inserted. */
1354 if (u_sync_once == 2)
1355 {
1356 u_sync_once = 1; /* notify that u_sync() was called */
1357 u_sync(TRUE);
1358 }
1359
1360 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1361 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001362 // Existing line, replace it.
1363 // Removes any existing text properties.
1364 if (u_savesub(lnum) == OK && ml_replace_len(
1365 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001366 {
1367 changed_bytes(lnum, 0);
1368 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1369 check_cursor_col();
1370 rettv->vval.v_number = 0; /* OK */
1371 }
1372 }
1373 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1374 {
1375 /* append the line */
1376 ++added;
1377 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1378 rettv->vval.v_number = 0; /* OK */
1379 }
1380
1381 if (l == NULL) /* only one string argument */
1382 break;
1383 ++lnum;
1384 }
1385
1386 if (added > 0)
1387 {
1388 win_T *wp;
1389 tabpage_T *tp;
1390
1391 appended_lines_mark(append_lnum, added);
1392 FOR_ALL_TAB_WINDOWS(tp, wp)
1393 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1394 wp->w_cursor.lnum += added;
1395 check_cursor_col();
1396
Bram Moolenaarf2732452018-06-03 14:47:35 +02001397#ifdef FEAT_JOB_CHANNEL
1398 if (bt_prompt(curbuf) && (State & INSERT))
1399 // show the line with the prompt
1400 update_topline();
1401#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001402 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001403
1404 if (!is_curbuf)
1405 {
1406 curbuf = curbuf_save;
1407 curwin = curwin_save;
1408 }
1409}
1410
1411/*
1412 * "append(lnum, string/list)" function
1413 */
1414 static void
1415f_append(typval_T *argvars, typval_T *rettv)
1416{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001417 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001418
1419 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1420}
1421
1422/*
1423 * "appendbufline(buf, lnum, string/list)" function
1424 */
1425 static void
1426f_appendbufline(typval_T *argvars, typval_T *rettv)
1427{
1428 linenr_T lnum;
1429 buf_T *buf;
1430
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001431 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001432 if (buf == NULL)
1433 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001435 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001436 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001437 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1438 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001439}
1440
1441/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001442 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001443 */
1444 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001445f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001446{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001447 win_T *wp;
1448
1449 if (argvars[0].v_type == VAR_UNKNOWN)
1450 // use the current window
1451 rettv->vval.v_number = ARGCOUNT;
1452 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001453 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001454 // use the global argument list
1455 rettv->vval.v_number = GARGCOUNT;
1456 else
1457 {
1458 // use the argument list of the specified window
1459 wp = find_win_by_nr_or_id(&argvars[0]);
1460 if (wp != NULL)
1461 rettv->vval.v_number = WARGCOUNT(wp);
1462 else
1463 rettv->vval.v_number = -1;
1464 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001465}
1466
1467/*
1468 * "argidx()" function
1469 */
1470 static void
1471f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1472{
1473 rettv->vval.v_number = curwin->w_arg_idx;
1474}
1475
1476/*
1477 * "arglistid()" function
1478 */
1479 static void
1480f_arglistid(typval_T *argvars, typval_T *rettv)
1481{
1482 win_T *wp;
1483
1484 rettv->vval.v_number = -1;
1485 wp = find_tabwin(&argvars[0], &argvars[1]);
1486 if (wp != NULL)
1487 rettv->vval.v_number = wp->w_alist->id;
1488}
1489
1490/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001491 * Get the argument list for a given window
1492 */
1493 static void
1494get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1495{
1496 int idx;
1497
1498 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1499 for (idx = 0; idx < argcount; ++idx)
1500 list_append_string(rettv->vval.v_list,
1501 alist_name(&arglist[idx]), -1);
1502}
1503
1504/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001505 * "argv(nr)" function
1506 */
1507 static void
1508f_argv(typval_T *argvars, typval_T *rettv)
1509{
1510 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001511 aentry_T *arglist = NULL;
1512 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001513
1514 if (argvars[0].v_type != VAR_UNKNOWN)
1515 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001516 if (argvars[1].v_type == VAR_UNKNOWN)
1517 {
1518 arglist = ARGLIST;
1519 argcount = ARGCOUNT;
1520 }
1521 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001522 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001523 {
1524 arglist = GARGLIST;
1525 argcount = GARGCOUNT;
1526 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001527 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001528 {
1529 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1530
1531 if (wp != NULL)
1532 {
1533 /* Use the argument list of the specified window */
1534 arglist = WARGLIST(wp);
1535 argcount = WARGCOUNT(wp);
1536 }
1537 }
1538
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001539 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001540 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001541 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001542 if (arglist != NULL && idx >= 0 && idx < argcount)
1543 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1544 else if (idx == -1)
1545 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001546 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001547 else
1548 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001549}
1550
1551/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001552 * "assert_beeps(cmd [, error])" function
1553 */
1554 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001555f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001556{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001557 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001558}
1559
1560/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001561 * "assert_equal(expected, actual[, msg])" function
1562 */
1563 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001564f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001565{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001566 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567}
1568
1569/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001570 * "assert_equalfile(fname-one, fname-two)" function
1571 */
1572 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001573f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001574{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001575 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001576}
1577
1578/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001579 * "assert_notequal(expected, actual[, msg])" function
1580 */
1581 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001582f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001583{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001584 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001585}
1586
1587/*
1588 * "assert_exception(string[, msg])" function
1589 */
1590 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001591f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001592{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001593 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001594}
1595
1596/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001597 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598 */
1599 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001600f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001602 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603}
1604
1605/*
1606 * "assert_false(actual[, msg])" function
1607 */
1608 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001609f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001610{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001611 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001612}
1613
1614/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001615 * "assert_inrange(lower, upper[, msg])" function
1616 */
1617 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001618f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001619{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001620 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001621}
1622
1623/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624 * "assert_match(pattern, actual[, msg])" function
1625 */
1626 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001627f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001628{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001629 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630}
1631
1632/*
1633 * "assert_notmatch(pattern, actual[, msg])" function
1634 */
1635 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001636f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001637{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001638 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001639}
1640
1641/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001642 * "assert_report(msg)" function
1643 */
1644 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001645f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001646{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001647 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001648}
1649
1650/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651 * "assert_true(actual[, msg])" function
1652 */
1653 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001654f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001655{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001656 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001657}
1658
1659#ifdef FEAT_FLOAT
1660/*
1661 * "asin()" function
1662 */
1663 static void
1664f_asin(typval_T *argvars, typval_T *rettv)
1665{
1666 float_T f = 0.0;
1667
1668 rettv->v_type = VAR_FLOAT;
1669 if (get_float_arg(argvars, &f) == OK)
1670 rettv->vval.v_float = asin(f);
1671 else
1672 rettv->vval.v_float = 0.0;
1673}
1674
1675/*
1676 * "atan()" function
1677 */
1678 static void
1679f_atan(typval_T *argvars, typval_T *rettv)
1680{
1681 float_T f = 0.0;
1682
1683 rettv->v_type = VAR_FLOAT;
1684 if (get_float_arg(argvars, &f) == OK)
1685 rettv->vval.v_float = atan(f);
1686 else
1687 rettv->vval.v_float = 0.0;
1688}
1689
1690/*
1691 * "atan2()" function
1692 */
1693 static void
1694f_atan2(typval_T *argvars, typval_T *rettv)
1695{
1696 float_T fx = 0.0, fy = 0.0;
1697
1698 rettv->v_type = VAR_FLOAT;
1699 if (get_float_arg(argvars, &fx) == OK
1700 && get_float_arg(&argvars[1], &fy) == OK)
1701 rettv->vval.v_float = atan2(fx, fy);
1702 else
1703 rettv->vval.v_float = 0.0;
1704}
1705#endif
1706
1707/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001708 * "balloon_show()" function
1709 */
1710#ifdef FEAT_BEVAL
1711 static void
1712f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1713{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001714 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001715 {
1716 if (argvars[0].v_type == VAR_LIST
1717# ifdef FEAT_GUI
1718 && !gui.in_use
1719# endif
1720 )
1721 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1722 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001723 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001724 }
1725}
1726
Bram Moolenaar669a8282017-11-19 20:13:05 +01001727# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001728 static void
1729f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1730{
1731 if (rettv_list_alloc(rettv) == OK)
1732 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001733 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001734
1735 if (msg != NULL)
1736 {
1737 pumitem_T *array;
1738 int size = split_message(msg, &array);
1739 int i;
1740
1741 /* Skip the first and last item, they are always empty. */
1742 for (i = 1; i < size - 1; ++i)
1743 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001744 while (size > 0)
1745 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001746 vim_free(array);
1747 }
1748 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001749}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001750# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001751#endif
1752
1753/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001754 * "browse(save, title, initdir, default)" function
1755 */
1756 static void
1757f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1758{
1759#ifdef FEAT_BROWSE
1760 int save;
1761 char_u *title;
1762 char_u *initdir;
1763 char_u *defname;
1764 char_u buf[NUMBUFLEN];
1765 char_u buf2[NUMBUFLEN];
1766 int error = FALSE;
1767
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001768 save = (int)tv_get_number_chk(&argvars[0], &error);
1769 title = tv_get_string_chk(&argvars[1]);
1770 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1771 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001772
1773 if (error || title == NULL || initdir == NULL || defname == NULL)
1774 rettv->vval.v_string = NULL;
1775 else
1776 rettv->vval.v_string =
1777 do_browse(save ? BROWSE_SAVE : 0,
1778 title, defname, NULL, initdir, NULL, curbuf);
1779#else
1780 rettv->vval.v_string = NULL;
1781#endif
1782 rettv->v_type = VAR_STRING;
1783}
1784
1785/*
1786 * "browsedir(title, initdir)" function
1787 */
1788 static void
1789f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1790{
1791#ifdef FEAT_BROWSE
1792 char_u *title;
1793 char_u *initdir;
1794 char_u buf[NUMBUFLEN];
1795
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001796 title = tv_get_string_chk(&argvars[0]);
1797 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001798
1799 if (title == NULL || initdir == NULL)
1800 rettv->vval.v_string = NULL;
1801 else
1802 rettv->vval.v_string = do_browse(BROWSE_DIR,
1803 title, NULL, NULL, initdir, NULL, curbuf);
1804#else
1805 rettv->vval.v_string = NULL;
1806#endif
1807 rettv->v_type = VAR_STRING;
1808}
1809
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001810/*
1811 * Find a buffer by number or exact name.
1812 */
1813 static buf_T *
1814find_buffer(typval_T *avar)
1815{
1816 buf_T *buf = NULL;
1817
1818 if (avar->v_type == VAR_NUMBER)
1819 buf = buflist_findnr((int)avar->vval.v_number);
1820 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1821 {
1822 buf = buflist_findname_exp(avar->vval.v_string);
1823 if (buf == NULL)
1824 {
1825 /* No full path name match, try a match with a URL or a "nofile"
1826 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001827 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828 if (buf->b_fname != NULL
1829 && (path_with_url(buf->b_fname)
1830#ifdef FEAT_QUICKFIX
1831 || bt_nofile(buf)
1832#endif
1833 )
1834 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1835 break;
1836 }
1837 }
1838 return buf;
1839}
1840
1841/*
1842 * "bufexists(expr)" function
1843 */
1844 static void
1845f_bufexists(typval_T *argvars, typval_T *rettv)
1846{
1847 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1848}
1849
1850/*
1851 * "buflisted(expr)" function
1852 */
1853 static void
1854f_buflisted(typval_T *argvars, typval_T *rettv)
1855{
1856 buf_T *buf;
1857
1858 buf = find_buffer(&argvars[0]);
1859 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1860}
1861
1862/*
1863 * "bufloaded(expr)" function
1864 */
1865 static void
1866f_bufloaded(typval_T *argvars, typval_T *rettv)
1867{
1868 buf_T *buf;
1869
1870 buf = find_buffer(&argvars[0]);
1871 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1872}
1873
1874 buf_T *
1875buflist_find_by_name(char_u *name, int curtab_only)
1876{
1877 int save_magic;
1878 char_u *save_cpo;
1879 buf_T *buf;
1880
1881 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1882 save_magic = p_magic;
1883 p_magic = TRUE;
1884 save_cpo = p_cpo;
1885 p_cpo = (char_u *)"";
1886
1887 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1888 TRUE, FALSE, curtab_only));
1889
1890 p_magic = save_magic;
1891 p_cpo = save_cpo;
1892 return buf;
1893}
1894
1895/*
1896 * Get buffer by number or pattern.
1897 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001898 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001899tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900{
1901 char_u *name = tv->vval.v_string;
1902 buf_T *buf;
1903
1904 if (tv->v_type == VAR_NUMBER)
1905 return buflist_findnr((int)tv->vval.v_number);
1906 if (tv->v_type != VAR_STRING)
1907 return NULL;
1908 if (name == NULL || *name == NUL)
1909 return curbuf;
1910 if (name[0] == '$' && name[1] == NUL)
1911 return lastbuf;
1912
1913 buf = buflist_find_by_name(name, curtab_only);
1914
1915 /* If not found, try expanding the name, like done for bufexists(). */
1916 if (buf == NULL)
1917 buf = find_buffer(tv);
1918
1919 return buf;
1920}
1921
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001922#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001924 * Get the buffer from "arg" and give an error and return NULL if it is not
1925 * valid.
1926 */
1927 static buf_T *
1928get_buf_arg(typval_T *arg)
1929{
1930 buf_T *buf;
1931
1932 ++emsg_off;
1933 buf = tv_get_buf(arg, FALSE);
1934 --emsg_off;
1935 if (buf == NULL)
1936 EMSG2(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
1937 return buf;
1938}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001939#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001940
1941/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942 * "bufname(expr)" function
1943 */
1944 static void
1945f_bufname(typval_T *argvars, typval_T *rettv)
1946{
1947 buf_T *buf;
1948
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001949 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001950 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001951 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001952 rettv->v_type = VAR_STRING;
1953 if (buf != NULL && buf->b_fname != NULL)
1954 rettv->vval.v_string = vim_strsave(buf->b_fname);
1955 else
1956 rettv->vval.v_string = NULL;
1957 --emsg_off;
1958}
1959
1960/*
1961 * "bufnr(expr)" function
1962 */
1963 static void
1964f_bufnr(typval_T *argvars, typval_T *rettv)
1965{
1966 buf_T *buf;
1967 int error = FALSE;
1968 char_u *name;
1969
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001970 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001971 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001972 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001973 --emsg_off;
1974
1975 /* If the buffer isn't found and the second argument is not zero create a
1976 * new buffer. */
1977 if (buf == NULL
1978 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001979 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001981 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001982 && !error)
1983 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1984
1985 if (buf != NULL)
1986 rettv->vval.v_number = buf->b_fnum;
1987 else
1988 rettv->vval.v_number = -1;
1989}
1990
1991 static void
1992buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1993{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001994 win_T *wp;
1995 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996 buf_T *buf;
1997
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001998 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001999 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002000 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002001 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002 {
2003 ++winnr;
2004 if (wp->w_buffer == buf)
2005 break;
2006 }
2007 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002008 --emsg_off;
2009}
2010
2011/*
2012 * "bufwinid(nr)" function
2013 */
2014 static void
2015f_bufwinid(typval_T *argvars, typval_T *rettv)
2016{
2017 buf_win_common(argvars, rettv, FALSE);
2018}
2019
2020/*
2021 * "bufwinnr(nr)" function
2022 */
2023 static void
2024f_bufwinnr(typval_T *argvars, typval_T *rettv)
2025{
2026 buf_win_common(argvars, rettv, TRUE);
2027}
2028
2029/*
2030 * "byte2line(byte)" function
2031 */
2032 static void
2033f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2034{
2035#ifndef FEAT_BYTEOFF
2036 rettv->vval.v_number = -1;
2037#else
2038 long boff = 0;
2039
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002040 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002041 if (boff < 0)
2042 rettv->vval.v_number = -1;
2043 else
2044 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2045 (linenr_T)0, &boff);
2046#endif
2047}
2048
2049 static void
2050byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2051{
2052#ifdef FEAT_MBYTE
2053 char_u *t;
2054#endif
2055 char_u *str;
2056 varnumber_T idx;
2057
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002058 str = tv_get_string_chk(&argvars[0]);
2059 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002060 rettv->vval.v_number = -1;
2061 if (str == NULL || idx < 0)
2062 return;
2063
2064#ifdef FEAT_MBYTE
2065 t = str;
2066 for ( ; idx > 0; idx--)
2067 {
2068 if (*t == NUL) /* EOL reached */
2069 return;
2070 if (enc_utf8 && comp)
2071 t += utf_ptr2len(t);
2072 else
2073 t += (*mb_ptr2len)(t);
2074 }
2075 rettv->vval.v_number = (varnumber_T)(t - str);
2076#else
2077 if ((size_t)idx <= STRLEN(str))
2078 rettv->vval.v_number = idx;
2079#endif
2080}
2081
2082/*
2083 * "byteidx()" function
2084 */
2085 static void
2086f_byteidx(typval_T *argvars, typval_T *rettv)
2087{
2088 byteidx(argvars, rettv, FALSE);
2089}
2090
2091/*
2092 * "byteidxcomp()" function
2093 */
2094 static void
2095f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2096{
2097 byteidx(argvars, rettv, TRUE);
2098}
2099
2100/*
2101 * "call(func, arglist [, dict])" function
2102 */
2103 static void
2104f_call(typval_T *argvars, typval_T *rettv)
2105{
2106 char_u *func;
2107 partial_T *partial = NULL;
2108 dict_T *selfdict = NULL;
2109
2110 if (argvars[1].v_type != VAR_LIST)
2111 {
2112 EMSG(_(e_listreq));
2113 return;
2114 }
2115 if (argvars[1].vval.v_list == NULL)
2116 return;
2117
2118 if (argvars[0].v_type == VAR_FUNC)
2119 func = argvars[0].vval.v_string;
2120 else if (argvars[0].v_type == VAR_PARTIAL)
2121 {
2122 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002123 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002124 }
2125 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002126 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002127 if (*func == NUL)
2128 return; /* type error or empty name */
2129
2130 if (argvars[2].v_type != VAR_UNKNOWN)
2131 {
2132 if (argvars[2].v_type != VAR_DICT)
2133 {
2134 EMSG(_(e_dictreq));
2135 return;
2136 }
2137 selfdict = argvars[2].vval.v_dict;
2138 }
2139
2140 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2141}
2142
2143#ifdef FEAT_FLOAT
2144/*
2145 * "ceil({float})" function
2146 */
2147 static void
2148f_ceil(typval_T *argvars, typval_T *rettv)
2149{
2150 float_T f = 0.0;
2151
2152 rettv->v_type = VAR_FLOAT;
2153 if (get_float_arg(argvars, &f) == OK)
2154 rettv->vval.v_float = ceil(f);
2155 else
2156 rettv->vval.v_float = 0.0;
2157}
2158#endif
2159
2160#ifdef FEAT_JOB_CHANNEL
2161/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002162 * "ch_canread()" function
2163 */
2164 static void
2165f_ch_canread(typval_T *argvars, typval_T *rettv)
2166{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002167 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002168
2169 rettv->vval.v_number = 0;
2170 if (channel != NULL)
2171 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2172 || channel_has_readahead(channel, PART_OUT)
2173 || channel_has_readahead(channel, PART_ERR);
2174}
2175
2176/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 * "ch_close()" function
2178 */
2179 static void
2180f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2181{
2182 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2183
2184 if (channel != NULL)
2185 {
2186 channel_close(channel, FALSE);
2187 channel_clear(channel);
2188 }
2189}
2190
2191/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002192 * "ch_close()" function
2193 */
2194 static void
2195f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2196{
2197 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2198
2199 if (channel != NULL)
2200 channel_close_in(channel);
2201}
2202
2203/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204 * "ch_getbufnr()" function
2205 */
2206 static void
2207f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2208{
2209 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2210
2211 rettv->vval.v_number = -1;
2212 if (channel != NULL)
2213 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002214 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002215 int part;
2216
2217 if (STRCMP(what, "err") == 0)
2218 part = PART_ERR;
2219 else if (STRCMP(what, "out") == 0)
2220 part = PART_OUT;
2221 else if (STRCMP(what, "in") == 0)
2222 part = PART_IN;
2223 else
2224 part = PART_SOCK;
2225 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2226 rettv->vval.v_number =
2227 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2228 }
2229}
2230
2231/*
2232 * "ch_getjob()" function
2233 */
2234 static void
2235f_ch_getjob(typval_T *argvars, typval_T *rettv)
2236{
2237 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2238
2239 if (channel != NULL)
2240 {
2241 rettv->v_type = VAR_JOB;
2242 rettv->vval.v_job = channel->ch_job;
2243 if (channel->ch_job != NULL)
2244 ++channel->ch_job->jv_refcount;
2245 }
2246}
2247
2248/*
2249 * "ch_info()" function
2250 */
2251 static void
2252f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2253{
2254 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2255
2256 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2257 channel_info(channel, rettv->vval.v_dict);
2258}
2259
2260/*
2261 * "ch_log()" function
2262 */
2263 static void
2264f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2265{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002266 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002267 channel_T *channel = NULL;
2268
2269 if (argvars[1].v_type != VAR_UNKNOWN)
2270 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2271
Bram Moolenaard5359b22018-04-05 22:44:39 +02002272 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002273}
2274
2275/*
2276 * "ch_logfile()" function
2277 */
2278 static void
2279f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2280{
2281 char_u *fname;
2282 char_u *opt = (char_u *)"";
2283 char_u buf[NUMBUFLEN];
2284
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002285 /* Don't open a file in restricted mode. */
2286 if (check_restricted() || check_secure())
2287 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002288 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002289 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002290 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002291 ch_logfile(fname, opt);
2292}
2293
2294/*
2295 * "ch_open()" function
2296 */
2297 static void
2298f_ch_open(typval_T *argvars, typval_T *rettv)
2299{
2300 rettv->v_type = VAR_CHANNEL;
2301 if (check_restricted() || check_secure())
2302 return;
2303 rettv->vval.v_channel = channel_open_func(argvars);
2304}
2305
2306/*
2307 * "ch_read()" function
2308 */
2309 static void
2310f_ch_read(typval_T *argvars, typval_T *rettv)
2311{
2312 common_channel_read(argvars, rettv, FALSE);
2313}
2314
2315/*
2316 * "ch_readraw()" function
2317 */
2318 static void
2319f_ch_readraw(typval_T *argvars, typval_T *rettv)
2320{
2321 common_channel_read(argvars, rettv, TRUE);
2322}
2323
2324/*
2325 * "ch_evalexpr()" function
2326 */
2327 static void
2328f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2329{
2330 ch_expr_common(argvars, rettv, TRUE);
2331}
2332
2333/*
2334 * "ch_sendexpr()" function
2335 */
2336 static void
2337f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2338{
2339 ch_expr_common(argvars, rettv, FALSE);
2340}
2341
2342/*
2343 * "ch_evalraw()" function
2344 */
2345 static void
2346f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2347{
2348 ch_raw_common(argvars, rettv, TRUE);
2349}
2350
2351/*
2352 * "ch_sendraw()" function
2353 */
2354 static void
2355f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2356{
2357 ch_raw_common(argvars, rettv, FALSE);
2358}
2359
2360/*
2361 * "ch_setoptions()" function
2362 */
2363 static void
2364f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2365{
2366 channel_T *channel;
2367 jobopt_T opt;
2368
2369 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2370 if (channel == NULL)
2371 return;
2372 clear_job_options(&opt);
2373 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002374 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002375 channel_set_options(channel, &opt);
2376 free_job_options(&opt);
2377}
2378
2379/*
2380 * "ch_status()" function
2381 */
2382 static void
2383f_ch_status(typval_T *argvars, typval_T *rettv)
2384{
2385 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002386 jobopt_T opt;
2387 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002388
2389 /* return an empty string by default */
2390 rettv->v_type = VAR_STRING;
2391 rettv->vval.v_string = NULL;
2392
2393 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002394
2395 if (argvars[1].v_type != VAR_UNKNOWN)
2396 {
2397 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002398 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002399 && (opt.jo_set & JO_PART))
2400 part = opt.jo_part;
2401 }
2402
2403 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002404}
2405#endif
2406
2407/*
2408 * "changenr()" function
2409 */
2410 static void
2411f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2412{
2413 rettv->vval.v_number = curbuf->b_u_seq_cur;
2414}
2415
2416/*
2417 * "char2nr(string)" function
2418 */
2419 static void
2420f_char2nr(typval_T *argvars, typval_T *rettv)
2421{
2422#ifdef FEAT_MBYTE
2423 if (has_mbyte)
2424 {
2425 int utf8 = 0;
2426
2427 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002428 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002429
2430 if (utf8)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002431 rettv->vval.v_number = (*utf_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002433 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 }
2435 else
2436#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002437 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002438}
2439
2440/*
2441 * "cindent(lnum)" function
2442 */
2443 static void
2444f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2445{
2446#ifdef FEAT_CINDENT
2447 pos_T pos;
2448 linenr_T lnum;
2449
2450 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002451 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2453 {
2454 curwin->w_cursor.lnum = lnum;
2455 rettv->vval.v_number = get_c_indent();
2456 curwin->w_cursor = pos;
2457 }
2458 else
2459#endif
2460 rettv->vval.v_number = -1;
2461}
2462
2463/*
2464 * "clearmatches()" function
2465 */
2466 static void
2467f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2468{
2469#ifdef FEAT_SEARCH_EXTRA
2470 clear_matches(curwin);
2471#endif
2472}
2473
2474/*
2475 * "col(string)" function
2476 */
2477 static void
2478f_col(typval_T *argvars, typval_T *rettv)
2479{
2480 colnr_T col = 0;
2481 pos_T *fp;
2482 int fnum = curbuf->b_fnum;
2483
2484 fp = var2fpos(&argvars[0], FALSE, &fnum);
2485 if (fp != NULL && fnum == curbuf->b_fnum)
2486 {
2487 if (fp->col == MAXCOL)
2488 {
2489 /* '> can be MAXCOL, get the length of the line then */
2490 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2491 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2492 else
2493 col = MAXCOL;
2494 }
2495 else
2496 {
2497 col = fp->col + 1;
2498#ifdef FEAT_VIRTUALEDIT
2499 /* col(".") when the cursor is on the NUL at the end of the line
2500 * because of "coladd" can be seen as an extra column. */
2501 if (virtual_active() && fp == &curwin->w_cursor)
2502 {
2503 char_u *p = ml_get_cursor();
2504
2505 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2506 curwin->w_virtcol - curwin->w_cursor.coladd))
2507 {
2508# ifdef FEAT_MBYTE
2509 int l;
2510
2511 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2512 col += l;
2513# else
2514 if (*p != NUL && p[1] == NUL)
2515 ++col;
2516# endif
2517 }
2518 }
2519#endif
2520 }
2521 }
2522 rettv->vval.v_number = col;
2523}
2524
2525#if defined(FEAT_INS_EXPAND)
2526/*
2527 * "complete()" function
2528 */
2529 static void
2530f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2531{
2532 int startcol;
2533
2534 if ((State & INSERT) == 0)
2535 {
2536 EMSG(_("E785: complete() can only be used in Insert mode"));
2537 return;
2538 }
2539
2540 /* Check for undo allowed here, because if something was already inserted
2541 * the line was already saved for undo and this check isn't done. */
2542 if (!undo_allowed())
2543 return;
2544
2545 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2546 {
2547 EMSG(_(e_invarg));
2548 return;
2549 }
2550
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002551 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 if (startcol <= 0)
2553 return;
2554
2555 set_completion(startcol - 1, argvars[1].vval.v_list);
2556}
2557
2558/*
2559 * "complete_add()" function
2560 */
2561 static void
2562f_complete_add(typval_T *argvars, typval_T *rettv)
2563{
2564 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2565}
2566
2567/*
2568 * "complete_check()" function
2569 */
2570 static void
2571f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2572{
2573 int saved = RedrawingDisabled;
2574
2575 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002576 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002577 rettv->vval.v_number = compl_interrupted;
2578 RedrawingDisabled = saved;
2579}
2580#endif
2581
2582/*
2583 * "confirm(message, buttons[, default [, type]])" function
2584 */
2585 static void
2586f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2587{
2588#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2589 char_u *message;
2590 char_u *buttons = NULL;
2591 char_u buf[NUMBUFLEN];
2592 char_u buf2[NUMBUFLEN];
2593 int def = 1;
2594 int type = VIM_GENERIC;
2595 char_u *typestr;
2596 int error = FALSE;
2597
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002598 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002599 if (message == NULL)
2600 error = TRUE;
2601 if (argvars[1].v_type != VAR_UNKNOWN)
2602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002603 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002604 if (buttons == NULL)
2605 error = TRUE;
2606 if (argvars[2].v_type != VAR_UNKNOWN)
2607 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002608 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609 if (argvars[3].v_type != VAR_UNKNOWN)
2610 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002611 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002612 if (typestr == NULL)
2613 error = TRUE;
2614 else
2615 {
2616 switch (TOUPPER_ASC(*typestr))
2617 {
2618 case 'E': type = VIM_ERROR; break;
2619 case 'Q': type = VIM_QUESTION; break;
2620 case 'I': type = VIM_INFO; break;
2621 case 'W': type = VIM_WARNING; break;
2622 case 'G': type = VIM_GENERIC; break;
2623 }
2624 }
2625 }
2626 }
2627 }
2628
2629 if (buttons == NULL || *buttons == NUL)
2630 buttons = (char_u *)_("&Ok");
2631
2632 if (!error)
2633 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2634 def, NULL, FALSE);
2635#endif
2636}
2637
2638/*
2639 * "copy()" function
2640 */
2641 static void
2642f_copy(typval_T *argvars, typval_T *rettv)
2643{
2644 item_copy(&argvars[0], rettv, FALSE, 0);
2645}
2646
2647#ifdef FEAT_FLOAT
2648/*
2649 * "cos()" function
2650 */
2651 static void
2652f_cos(typval_T *argvars, typval_T *rettv)
2653{
2654 float_T f = 0.0;
2655
2656 rettv->v_type = VAR_FLOAT;
2657 if (get_float_arg(argvars, &f) == OK)
2658 rettv->vval.v_float = cos(f);
2659 else
2660 rettv->vval.v_float = 0.0;
2661}
2662
2663/*
2664 * "cosh()" function
2665 */
2666 static void
2667f_cosh(typval_T *argvars, typval_T *rettv)
2668{
2669 float_T f = 0.0;
2670
2671 rettv->v_type = VAR_FLOAT;
2672 if (get_float_arg(argvars, &f) == OK)
2673 rettv->vval.v_float = cosh(f);
2674 else
2675 rettv->vval.v_float = 0.0;
2676}
2677#endif
2678
2679/*
2680 * "count()" function
2681 */
2682 static void
2683f_count(typval_T *argvars, typval_T *rettv)
2684{
2685 long n = 0;
2686 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002687 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002688
Bram Moolenaar9966b212017-07-28 16:46:57 +02002689 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002690 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002691
2692 if (argvars[0].v_type == VAR_STRING)
2693 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002694 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002695 char_u *p = argvars[0].vval.v_string;
2696 char_u *next;
2697
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002698 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002699 {
2700 if (ic)
2701 {
2702 size_t len = STRLEN(expr);
2703
2704 while (*p != NUL)
2705 {
2706 if (MB_STRNICMP(p, expr, len) == 0)
2707 {
2708 ++n;
2709 p += len;
2710 }
2711 else
2712 MB_PTR_ADV(p);
2713 }
2714 }
2715 else
2716 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2717 != NULL)
2718 {
2719 ++n;
2720 p = next + STRLEN(expr);
2721 }
2722 }
2723
2724 }
2725 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002726 {
2727 listitem_T *li;
2728 list_T *l;
2729 long idx;
2730
2731 if ((l = argvars[0].vval.v_list) != NULL)
2732 {
2733 li = l->lv_first;
2734 if (argvars[2].v_type != VAR_UNKNOWN)
2735 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002736 if (argvars[3].v_type != VAR_UNKNOWN)
2737 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002738 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002739 if (!error)
2740 {
2741 li = list_find(l, idx);
2742 if (li == NULL)
2743 EMSGN(_(e_listidx), idx);
2744 }
2745 }
2746 if (error)
2747 li = NULL;
2748 }
2749
2750 for ( ; li != NULL; li = li->li_next)
2751 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2752 ++n;
2753 }
2754 }
2755 else if (argvars[0].v_type == VAR_DICT)
2756 {
2757 int todo;
2758 dict_T *d;
2759 hashitem_T *hi;
2760
2761 if ((d = argvars[0].vval.v_dict) != NULL)
2762 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 if (argvars[2].v_type != VAR_UNKNOWN)
2764 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002765 if (argvars[3].v_type != VAR_UNKNOWN)
2766 EMSG(_(e_invarg));
2767 }
2768
2769 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2770 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2771 {
2772 if (!HASHITEM_EMPTY(hi))
2773 {
2774 --todo;
2775 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2776 ++n;
2777 }
2778 }
2779 }
2780 }
2781 else
2782 EMSG2(_(e_listdictarg), "count()");
2783 rettv->vval.v_number = n;
2784}
2785
2786/*
2787 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2788 *
2789 * Checks the existence of a cscope connection.
2790 */
2791 static void
2792f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2793{
2794#ifdef FEAT_CSCOPE
2795 int num = 0;
2796 char_u *dbpath = NULL;
2797 char_u *prepend = NULL;
2798 char_u buf[NUMBUFLEN];
2799
2800 if (argvars[0].v_type != VAR_UNKNOWN
2801 && argvars[1].v_type != VAR_UNKNOWN)
2802 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002803 num = (int)tv_get_number(&argvars[0]);
2804 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002805 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002806 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002807 }
2808
2809 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2810#endif
2811}
2812
2813/*
2814 * "cursor(lnum, col)" function, or
2815 * "cursor(list)"
2816 *
2817 * Moves the cursor to the specified line and column.
2818 * Returns 0 when the position could be set, -1 otherwise.
2819 */
2820 static void
2821f_cursor(typval_T *argvars, typval_T *rettv)
2822{
2823 long line, col;
2824#ifdef FEAT_VIRTUALEDIT
2825 long coladd = 0;
2826#endif
2827 int set_curswant = TRUE;
2828
2829 rettv->vval.v_number = -1;
2830 if (argvars[1].v_type == VAR_UNKNOWN)
2831 {
2832 pos_T pos;
2833 colnr_T curswant = -1;
2834
2835 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2836 {
2837 EMSG(_(e_invarg));
2838 return;
2839 }
2840 line = pos.lnum;
2841 col = pos.col;
2842#ifdef FEAT_VIRTUALEDIT
2843 coladd = pos.coladd;
2844#endif
2845 if (curswant >= 0)
2846 {
2847 curwin->w_curswant = curswant - 1;
2848 set_curswant = FALSE;
2849 }
2850 }
2851 else
2852 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002853 line = tv_get_lnum(argvars);
2854 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855#ifdef FEAT_VIRTUALEDIT
2856 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002857 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002858#endif
2859 }
2860 if (line < 0 || col < 0
2861#ifdef FEAT_VIRTUALEDIT
2862 || coladd < 0
2863#endif
2864 )
2865 return; /* type error; errmsg already given */
2866 if (line > 0)
2867 curwin->w_cursor.lnum = line;
2868 if (col > 0)
2869 curwin->w_cursor.col = col - 1;
2870#ifdef FEAT_VIRTUALEDIT
2871 curwin->w_cursor.coladd = coladd;
2872#endif
2873
2874 /* Make sure the cursor is in a valid position. */
2875 check_cursor();
2876#ifdef FEAT_MBYTE
2877 /* Correct cursor for multi-byte character. */
2878 if (has_mbyte)
2879 mb_adjust_cursor();
2880#endif
2881
2882 curwin->w_set_curswant = set_curswant;
2883 rettv->vval.v_number = 0;
2884}
2885
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002886#ifdef WIN3264
2887/*
2888 * "debugbreak()" function
2889 */
2890 static void
2891f_debugbreak(typval_T *argvars, typval_T *rettv)
2892{
2893 int pid;
2894
2895 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002896 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002897 if (pid == 0)
2898 EMSG(_(e_invarg));
2899 else
2900 {
2901 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2902
2903 if (hProcess != NULL)
2904 {
2905 DebugBreakProcess(hProcess);
2906 CloseHandle(hProcess);
2907 rettv->vval.v_number = OK;
2908 }
2909 }
2910}
2911#endif
2912
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002913/*
2914 * "deepcopy()" function
2915 */
2916 static void
2917f_deepcopy(typval_T *argvars, typval_T *rettv)
2918{
2919 int noref = 0;
2920 int copyID;
2921
2922 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002923 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002924 if (noref < 0 || noref > 1)
2925 EMSG(_(e_invarg));
2926 else
2927 {
2928 copyID = get_copyID();
2929 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2930 }
2931}
2932
2933/*
2934 * "delete()" function
2935 */
2936 static void
2937f_delete(typval_T *argvars, typval_T *rettv)
2938{
2939 char_u nbuf[NUMBUFLEN];
2940 char_u *name;
2941 char_u *flags;
2942
2943 rettv->vval.v_number = -1;
2944 if (check_restricted() || check_secure())
2945 return;
2946
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002947 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002948 if (name == NULL || *name == NUL)
2949 {
2950 EMSG(_(e_invarg));
2951 return;
2952 }
2953
2954 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002955 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002956 else
2957 flags = (char_u *)"";
2958
2959 if (*flags == NUL)
2960 /* delete a file */
2961 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2962 else if (STRCMP(flags, "d") == 0)
2963 /* delete an empty directory */
2964 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2965 else if (STRCMP(flags, "rf") == 0)
2966 /* delete a directory recursively */
2967 rettv->vval.v_number = delete_recursive(name);
2968 else
2969 EMSG2(_(e_invexpr2), flags);
2970}
2971
2972/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002973 * "deletebufline()" function
2974 */
2975 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002976f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002977{
2978 buf_T *buf;
2979 linenr_T first, last;
2980 linenr_T lnum;
2981 long count;
2982 int is_curbuf;
2983 buf_T *curbuf_save = NULL;
2984 win_T *curwin_save = NULL;
2985 tabpage_T *tp;
2986 win_T *wp;
2987
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002988 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002989 if (buf == NULL)
2990 {
2991 rettv->vval.v_number = 1; /* FAIL */
2992 return;
2993 }
2994 is_curbuf = buf == curbuf;
2995
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002996 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002997 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002998 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002999 else
3000 last = first;
3001
3002 if (buf->b_ml.ml_mfp == NULL || first < 1
3003 || first > buf->b_ml.ml_line_count || last < first)
3004 {
3005 rettv->vval.v_number = 1; /* FAIL */
3006 return;
3007 }
3008
3009 if (!is_curbuf)
3010 {
3011 curbuf_save = curbuf;
3012 curwin_save = curwin;
3013 curbuf = buf;
3014 find_win_for_curbuf();
3015 }
3016 if (last > curbuf->b_ml.ml_line_count)
3017 last = curbuf->b_ml.ml_line_count;
3018 count = last - first + 1;
3019
3020 // When coming here from Insert mode, sync undo, so that this can be
3021 // undone separately from what was previously inserted.
3022 if (u_sync_once == 2)
3023 {
3024 u_sync_once = 1; // notify that u_sync() was called
3025 u_sync(TRUE);
3026 }
3027
3028 if (u_save(first - 1, last + 1) == FAIL)
3029 {
3030 rettv->vval.v_number = 1; /* FAIL */
3031 return;
3032 }
3033
3034 for (lnum = first; lnum <= last; ++lnum)
3035 ml_delete(first, TRUE);
3036
3037 FOR_ALL_TAB_WINDOWS(tp, wp)
3038 if (wp->w_buffer == buf)
3039 {
3040 if (wp->w_cursor.lnum > last)
3041 wp->w_cursor.lnum -= count;
3042 else if (wp->w_cursor.lnum> first)
3043 wp->w_cursor.lnum = first;
3044 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3045 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3046 }
3047 check_cursor_col();
3048 deleted_lines_mark(first, count);
3049
3050 if (!is_curbuf)
3051 {
3052 curbuf = curbuf_save;
3053 curwin = curwin_save;
3054 }
3055}
3056
3057/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 * "did_filetype()" function
3059 */
3060 static void
3061f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3062{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003063 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003064}
3065
3066/*
3067 * "diff_filler()" function
3068 */
3069 static void
3070f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3071{
3072#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003073 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003074#endif
3075}
3076
3077/*
3078 * "diff_hlID()" function
3079 */
3080 static void
3081f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3082{
3083#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003084 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003085 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003086 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003087 static int fnum = 0;
3088 static int change_start = 0;
3089 static int change_end = 0;
3090 static hlf_T hlID = (hlf_T)0;
3091 int filler_lines;
3092 int col;
3093
3094 if (lnum < 0) /* ignore type error in {lnum} arg */
3095 lnum = 0;
3096 if (lnum != prev_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 /* New line, buffer, change: need to get the values. */
3101 filler_lines = diff_check(curwin, lnum);
3102 if (filler_lines < 0)
3103 {
3104 if (filler_lines == -1)
3105 {
3106 change_start = MAXCOL;
3107 change_end = -1;
3108 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3109 hlID = HLF_ADD; /* added line */
3110 else
3111 hlID = HLF_CHD; /* changed line */
3112 }
3113 else
3114 hlID = HLF_ADD; /* added line */
3115 }
3116 else
3117 hlID = (hlf_T)0;
3118 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003119 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003120 fnum = curbuf->b_fnum;
3121 }
3122
3123 if (hlID == HLF_CHD || hlID == HLF_TXD)
3124 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003125 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003126 if (col >= change_start && col <= change_end)
3127 hlID = HLF_TXD; /* changed text */
3128 else
3129 hlID = HLF_CHD; /* changed line */
3130 }
3131 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3132#endif
3133}
3134
3135/*
3136 * "empty({expr})" function
3137 */
3138 static void
3139f_empty(typval_T *argvars, typval_T *rettv)
3140{
3141 int n = FALSE;
3142
3143 switch (argvars[0].v_type)
3144 {
3145 case VAR_STRING:
3146 case VAR_FUNC:
3147 n = argvars[0].vval.v_string == NULL
3148 || *argvars[0].vval.v_string == NUL;
3149 break;
3150 case VAR_PARTIAL:
3151 n = FALSE;
3152 break;
3153 case VAR_NUMBER:
3154 n = argvars[0].vval.v_number == 0;
3155 break;
3156 case VAR_FLOAT:
3157#ifdef FEAT_FLOAT
3158 n = argvars[0].vval.v_float == 0.0;
3159 break;
3160#endif
3161 case VAR_LIST:
3162 n = argvars[0].vval.v_list == NULL
3163 || argvars[0].vval.v_list->lv_first == NULL;
3164 break;
3165 case VAR_DICT:
3166 n = argvars[0].vval.v_dict == NULL
3167 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3168 break;
3169 case VAR_SPECIAL:
3170 n = argvars[0].vval.v_number != VVAL_TRUE;
3171 break;
3172
3173 case VAR_JOB:
3174#ifdef FEAT_JOB_CHANNEL
3175 n = argvars[0].vval.v_job == NULL
3176 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3177 break;
3178#endif
3179 case VAR_CHANNEL:
3180#ifdef FEAT_JOB_CHANNEL
3181 n = argvars[0].vval.v_channel == NULL
3182 || !channel_is_open(argvars[0].vval.v_channel);
3183 break;
3184#endif
3185 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003186 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003187 n = TRUE;
3188 break;
3189 }
3190
3191 rettv->vval.v_number = n;
3192}
3193
3194/*
3195 * "escape({string}, {chars})" function
3196 */
3197 static void
3198f_escape(typval_T *argvars, typval_T *rettv)
3199{
3200 char_u buf[NUMBUFLEN];
3201
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003202 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3203 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003204 rettv->v_type = VAR_STRING;
3205}
3206
3207/*
3208 * "eval()" function
3209 */
3210 static void
3211f_eval(typval_T *argvars, typval_T *rettv)
3212{
3213 char_u *s, *p;
3214
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003215 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216 if (s != NULL)
3217 s = skipwhite(s);
3218
3219 p = s;
3220 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3221 {
3222 if (p != NULL && !aborting())
3223 EMSG2(_(e_invexpr2), p);
3224 need_clr_eos = FALSE;
3225 rettv->v_type = VAR_NUMBER;
3226 rettv->vval.v_number = 0;
3227 }
3228 else if (*s != NUL)
3229 EMSG(_(e_trailing));
3230}
3231
3232/*
3233 * "eventhandler()" function
3234 */
3235 static void
3236f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3237{
3238 rettv->vval.v_number = vgetc_busy;
3239}
3240
3241/*
3242 * "executable()" function
3243 */
3244 static void
3245f_executable(typval_T *argvars, typval_T *rettv)
3246{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003247 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003248
3249 /* Check in $PATH and also check directly if there is a directory name. */
3250 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3251 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3252}
3253
3254static garray_T redir_execute_ga;
3255
3256/*
3257 * Append "value[value_len]" to the execute() output.
3258 */
3259 void
3260execute_redir_str(char_u *value, int value_len)
3261{
3262 int len;
3263
3264 if (value_len == -1)
3265 len = (int)STRLEN(value); /* Append the entire string */
3266 else
3267 len = value_len; /* Append only "value_len" characters */
3268 if (ga_grow(&redir_execute_ga, len) == OK)
3269 {
3270 mch_memmove((char *)redir_execute_ga.ga_data
3271 + redir_execute_ga.ga_len, value, len);
3272 redir_execute_ga.ga_len += len;
3273 }
3274}
3275
3276/*
3277 * Get next line from a list.
3278 * Called by do_cmdline() to get the next line.
3279 * Returns allocated string, or NULL for end of function.
3280 */
3281
3282 static char_u *
3283get_list_line(
3284 int c UNUSED,
3285 void *cookie,
3286 int indent UNUSED)
3287{
3288 listitem_T **p = (listitem_T **)cookie;
3289 listitem_T *item = *p;
3290 char_u buf[NUMBUFLEN];
3291 char_u *s;
3292
3293 if (item == NULL)
3294 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003295 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003296 *p = item->li_next;
3297 return s == NULL ? NULL : vim_strsave(s);
3298}
3299
3300/*
3301 * "execute()" function
3302 */
3303 static void
3304f_execute(typval_T *argvars, typval_T *rettv)
3305{
3306 char_u *cmd = NULL;
3307 list_T *list = NULL;
3308 int save_msg_silent = msg_silent;
3309 int save_emsg_silent = emsg_silent;
3310 int save_emsg_noredir = emsg_noredir;
3311 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003312 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003313 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003314 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003315 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316
3317 rettv->vval.v_string = NULL;
3318 rettv->v_type = VAR_STRING;
3319
3320 if (argvars[0].v_type == VAR_LIST)
3321 {
3322 list = argvars[0].vval.v_list;
3323 if (list == NULL || list->lv_first == NULL)
3324 /* empty list, no commands, empty output */
3325 return;
3326 ++list->lv_refcount;
3327 }
3328 else
3329 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003330 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003331 if (cmd == NULL)
3332 return;
3333 }
3334
3335 if (argvars[1].v_type != VAR_UNKNOWN)
3336 {
3337 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003338 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003339
3340 if (s == NULL)
3341 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003342 if (*s == NUL)
3343 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003344 if (STRNCMP(s, "silent", 6) == 0)
3345 ++msg_silent;
3346 if (STRCMP(s, "silent!") == 0)
3347 {
3348 emsg_silent = TRUE;
3349 emsg_noredir = TRUE;
3350 }
3351 }
3352 else
3353 ++msg_silent;
3354
3355 if (redir_execute)
3356 save_ga = redir_execute_ga;
3357 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3358 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003359 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003360 if (!echo_output)
3361 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003362
3363 if (cmd != NULL)
3364 do_cmdline_cmd(cmd);
3365 else
3366 {
3367 listitem_T *item = list->lv_first;
3368
3369 do_cmdline(NULL, get_list_line, (void *)&item,
3370 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3371 --list->lv_refcount;
3372 }
3373
Bram Moolenaard297f352017-01-29 20:31:21 +01003374 /* Need to append a NUL to the result. */
3375 if (ga_grow(&redir_execute_ga, 1) == OK)
3376 {
3377 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3378 rettv->vval.v_string = redir_execute_ga.ga_data;
3379 }
3380 else
3381 {
3382 ga_clear(&redir_execute_ga);
3383 rettv->vval.v_string = NULL;
3384 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003385 msg_silent = save_msg_silent;
3386 emsg_silent = save_emsg_silent;
3387 emsg_noredir = save_emsg_noredir;
3388
3389 redir_execute = save_redir_execute;
3390 if (redir_execute)
3391 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003392 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003393
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003394 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003395 if (echo_output)
3396 // When not working silently: put it in column zero. A following
3397 // "echon" will overwrite the message, unavoidably.
3398 msg_col = 0;
3399 else
3400 // When working silently: Put it back where it was, since nothing
3401 // should have been written.
3402 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403}
3404
3405/*
3406 * "exepath()" function
3407 */
3408 static void
3409f_exepath(typval_T *argvars, typval_T *rettv)
3410{
3411 char_u *p = NULL;
3412
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003413 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414 rettv->v_type = VAR_STRING;
3415 rettv->vval.v_string = p;
3416}
3417
3418/*
3419 * "exists()" function
3420 */
3421 static void
3422f_exists(typval_T *argvars, typval_T *rettv)
3423{
3424 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003427 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428 if (*p == '$') /* environment variable */
3429 {
3430 /* first try "normal" environment variables (fast) */
3431 if (mch_getenv(p + 1) != NULL)
3432 n = TRUE;
3433 else
3434 {
3435 /* try expanding things like $VIM and ${HOME} */
3436 p = expand_env_save(p);
3437 if (p != NULL && *p != '$')
3438 n = TRUE;
3439 vim_free(p);
3440 }
3441 }
3442 else if (*p == '&' || *p == '+') /* option */
3443 {
3444 n = (get_option_tv(&p, NULL, TRUE) == OK);
3445 if (*skipwhite(p) != NUL)
3446 n = FALSE; /* trailing garbage */
3447 }
3448 else if (*p == '*') /* internal or user defined function */
3449 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003450 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003451 }
3452 else if (*p == ':')
3453 {
3454 n = cmd_exists(p + 1);
3455 }
3456 else if (*p == '#')
3457 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003458 if (p[1] == '#')
3459 n = autocmd_supported(p + 2);
3460 else
3461 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003462 }
3463 else /* internal variable */
3464 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003465 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003466 }
3467
3468 rettv->vval.v_number = n;
3469}
3470
3471#ifdef FEAT_FLOAT
3472/*
3473 * "exp()" function
3474 */
3475 static void
3476f_exp(typval_T *argvars, typval_T *rettv)
3477{
3478 float_T f = 0.0;
3479
3480 rettv->v_type = VAR_FLOAT;
3481 if (get_float_arg(argvars, &f) == OK)
3482 rettv->vval.v_float = exp(f);
3483 else
3484 rettv->vval.v_float = 0.0;
3485}
3486#endif
3487
3488/*
3489 * "expand()" function
3490 */
3491 static void
3492f_expand(typval_T *argvars, typval_T *rettv)
3493{
3494 char_u *s;
3495 int len;
3496 char_u *errormsg;
3497 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3498 expand_T xpc;
3499 int error = FALSE;
3500 char_u *result;
3501
3502 rettv->v_type = VAR_STRING;
3503 if (argvars[1].v_type != VAR_UNKNOWN
3504 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003505 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506 && !error)
3507 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003508 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003509 }
3510
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003511 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003512 if (*s == '%' || *s == '#' || *s == '<')
3513 {
3514 ++emsg_off;
3515 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3516 --emsg_off;
3517 if (rettv->v_type == VAR_LIST)
3518 {
3519 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3520 list_append_string(rettv->vval.v_list, result, -1);
3521 else
3522 vim_free(result);
3523 }
3524 else
3525 rettv->vval.v_string = result;
3526 }
3527 else
3528 {
3529 /* When the optional second argument is non-zero, don't remove matches
3530 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3531 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003532 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003533 options |= WILD_KEEP_ALL;
3534 if (!error)
3535 {
3536 ExpandInit(&xpc);
3537 xpc.xp_context = EXPAND_FILES;
3538 if (p_wic)
3539 options += WILD_ICASE;
3540 if (rettv->v_type == VAR_STRING)
3541 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3542 options, WILD_ALL);
3543 else if (rettv_list_alloc(rettv) != FAIL)
3544 {
3545 int i;
3546
3547 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3548 for (i = 0; i < xpc.xp_numfiles; i++)
3549 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3550 ExpandCleanup(&xpc);
3551 }
3552 }
3553 else
3554 rettv->vval.v_string = NULL;
3555 }
3556}
3557
3558/*
3559 * "extend(list, list [, idx])" function
3560 * "extend(dict, dict [, action])" function
3561 */
3562 static void
3563f_extend(typval_T *argvars, typval_T *rettv)
3564{
3565 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3566
3567 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3568 {
3569 list_T *l1, *l2;
3570 listitem_T *item;
3571 long before;
3572 int error = FALSE;
3573
3574 l1 = argvars[0].vval.v_list;
3575 l2 = argvars[1].vval.v_list;
3576 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3577 && l2 != NULL)
3578 {
3579 if (argvars[2].v_type != VAR_UNKNOWN)
3580 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003581 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582 if (error)
3583 return; /* type error; errmsg already given */
3584
3585 if (before == l1->lv_len)
3586 item = NULL;
3587 else
3588 {
3589 item = list_find(l1, before);
3590 if (item == NULL)
3591 {
3592 EMSGN(_(e_listidx), before);
3593 return;
3594 }
3595 }
3596 }
3597 else
3598 item = NULL;
3599 list_extend(l1, l2, item);
3600
3601 copy_tv(&argvars[0], rettv);
3602 }
3603 }
3604 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3605 {
3606 dict_T *d1, *d2;
3607 char_u *action;
3608 int i;
3609
3610 d1 = argvars[0].vval.v_dict;
3611 d2 = argvars[1].vval.v_dict;
3612 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3613 && d2 != NULL)
3614 {
3615 /* Check the third argument. */
3616 if (argvars[2].v_type != VAR_UNKNOWN)
3617 {
3618 static char *(av[]) = {"keep", "force", "error"};
3619
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003620 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003621 if (action == NULL)
3622 return; /* type error; errmsg already given */
3623 for (i = 0; i < 3; ++i)
3624 if (STRCMP(action, av[i]) == 0)
3625 break;
3626 if (i == 3)
3627 {
3628 EMSG2(_(e_invarg2), action);
3629 return;
3630 }
3631 }
3632 else
3633 action = (char_u *)"force";
3634
3635 dict_extend(d1, d2, action);
3636
3637 copy_tv(&argvars[0], rettv);
3638 }
3639 }
3640 else
3641 EMSG2(_(e_listdictarg), "extend()");
3642}
3643
3644/*
3645 * "feedkeys()" function
3646 */
3647 static void
3648f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3649{
3650 int remap = TRUE;
3651 int insert = FALSE;
3652 char_u *keys, *flags;
3653 char_u nbuf[NUMBUFLEN];
3654 int typed = FALSE;
3655 int execute = FALSE;
3656 int dangerous = FALSE;
3657 char_u *keys_esc;
3658
3659 /* This is not allowed in the sandbox. If the commands would still be
3660 * executed in the sandbox it would be OK, but it probably happens later,
3661 * when "sandbox" is no longer set. */
3662 if (check_secure())
3663 return;
3664
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003665 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003666
3667 if (argvars[1].v_type != VAR_UNKNOWN)
3668 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003669 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003670 for ( ; *flags != NUL; ++flags)
3671 {
3672 switch (*flags)
3673 {
3674 case 'n': remap = FALSE; break;
3675 case 'm': remap = TRUE; break;
3676 case 't': typed = TRUE; break;
3677 case 'i': insert = TRUE; break;
3678 case 'x': execute = TRUE; break;
3679 case '!': dangerous = TRUE; break;
3680 }
3681 }
3682 }
3683
3684 if (*keys != NUL || execute)
3685 {
3686 /* Need to escape K_SPECIAL and CSI before putting the string in the
3687 * typeahead buffer. */
3688 keys_esc = vim_strsave_escape_csi(keys);
3689 if (keys_esc != NULL)
3690 {
3691 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3692 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3693 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003694 if (vgetc_busy
3695#ifdef FEAT_TIMERS
3696 || timer_busy
3697#endif
3698 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003699 typebuf_was_filled = TRUE;
3700 if (execute)
3701 {
3702 int save_msg_scroll = msg_scroll;
3703
3704 /* Avoid a 1 second delay when the keys start Insert mode. */
3705 msg_scroll = FALSE;
3706
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003707 if (!dangerous)
3708 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003709 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003710 if (!dangerous)
3711 --ex_normal_busy;
3712
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003713 msg_scroll |= save_msg_scroll;
3714 }
3715 }
3716 }
3717}
3718
3719/*
3720 * "filereadable()" function
3721 */
3722 static void
3723f_filereadable(typval_T *argvars, typval_T *rettv)
3724{
3725 int fd;
3726 char_u *p;
3727 int n;
3728
3729#ifndef O_NONBLOCK
3730# define O_NONBLOCK 0
3731#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003732 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003733 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3734 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3735 {
3736 n = TRUE;
3737 close(fd);
3738 }
3739 else
3740 n = FALSE;
3741
3742 rettv->vval.v_number = n;
3743}
3744
3745/*
3746 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3747 * rights to write into.
3748 */
3749 static void
3750f_filewritable(typval_T *argvars, typval_T *rettv)
3751{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003752 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003753}
3754
3755 static void
3756findfilendir(
3757 typval_T *argvars UNUSED,
3758 typval_T *rettv,
3759 int find_what UNUSED)
3760{
3761#ifdef FEAT_SEARCHPATH
3762 char_u *fname;
3763 char_u *fresult = NULL;
3764 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3765 char_u *p;
3766 char_u pathbuf[NUMBUFLEN];
3767 int count = 1;
3768 int first = TRUE;
3769 int error = FALSE;
3770#endif
3771
3772 rettv->vval.v_string = NULL;
3773 rettv->v_type = VAR_STRING;
3774
3775#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003776 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777
3778 if (argvars[1].v_type != VAR_UNKNOWN)
3779 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003780 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781 if (p == NULL)
3782 error = TRUE;
3783 else
3784 {
3785 if (*p != NUL)
3786 path = p;
3787
3788 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003789 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003790 }
3791 }
3792
3793 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3794 error = TRUE;
3795
3796 if (*fname != NUL && !error)
3797 {
3798 do
3799 {
3800 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3801 vim_free(fresult);
3802 fresult = find_file_in_path_option(first ? fname : NULL,
3803 first ? (int)STRLEN(fname) : 0,
3804 0, first, path,
3805 find_what,
3806 curbuf->b_ffname,
3807 find_what == FINDFILE_DIR
3808 ? (char_u *)"" : curbuf->b_p_sua);
3809 first = FALSE;
3810
3811 if (fresult != NULL && rettv->v_type == VAR_LIST)
3812 list_append_string(rettv->vval.v_list, fresult, -1);
3813
3814 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3815 }
3816
3817 if (rettv->v_type == VAR_STRING)
3818 rettv->vval.v_string = fresult;
3819#endif
3820}
3821
3822/*
3823 * "filter()" function
3824 */
3825 static void
3826f_filter(typval_T *argvars, typval_T *rettv)
3827{
3828 filter_map(argvars, rettv, FALSE);
3829}
3830
3831/*
3832 * "finddir({fname}[, {path}[, {count}]])" function
3833 */
3834 static void
3835f_finddir(typval_T *argvars, typval_T *rettv)
3836{
3837 findfilendir(argvars, rettv, FINDFILE_DIR);
3838}
3839
3840/*
3841 * "findfile({fname}[, {path}[, {count}]])" function
3842 */
3843 static void
3844f_findfile(typval_T *argvars, typval_T *rettv)
3845{
3846 findfilendir(argvars, rettv, FINDFILE_FILE);
3847}
3848
3849#ifdef FEAT_FLOAT
3850/*
3851 * "float2nr({float})" function
3852 */
3853 static void
3854f_float2nr(typval_T *argvars, typval_T *rettv)
3855{
3856 float_T f = 0.0;
3857
3858 if (get_float_arg(argvars, &f) == OK)
3859 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003860 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003861 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003862 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003863 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 else
3865 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003866 }
3867}
3868
3869/*
3870 * "floor({float})" function
3871 */
3872 static void
3873f_floor(typval_T *argvars, typval_T *rettv)
3874{
3875 float_T f = 0.0;
3876
3877 rettv->v_type = VAR_FLOAT;
3878 if (get_float_arg(argvars, &f) == OK)
3879 rettv->vval.v_float = floor(f);
3880 else
3881 rettv->vval.v_float = 0.0;
3882}
3883
3884/*
3885 * "fmod()" function
3886 */
3887 static void
3888f_fmod(typval_T *argvars, typval_T *rettv)
3889{
3890 float_T fx = 0.0, fy = 0.0;
3891
3892 rettv->v_type = VAR_FLOAT;
3893 if (get_float_arg(argvars, &fx) == OK
3894 && get_float_arg(&argvars[1], &fy) == OK)
3895 rettv->vval.v_float = fmod(fx, fy);
3896 else
3897 rettv->vval.v_float = 0.0;
3898}
3899#endif
3900
3901/*
3902 * "fnameescape({string})" function
3903 */
3904 static void
3905f_fnameescape(typval_T *argvars, typval_T *rettv)
3906{
3907 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003908 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 rettv->v_type = VAR_STRING;
3910}
3911
3912/*
3913 * "fnamemodify({fname}, {mods})" function
3914 */
3915 static void
3916f_fnamemodify(typval_T *argvars, typval_T *rettv)
3917{
3918 char_u *fname;
3919 char_u *mods;
3920 int usedlen = 0;
3921 int len;
3922 char_u *fbuf = NULL;
3923 char_u buf[NUMBUFLEN];
3924
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003925 fname = tv_get_string_chk(&argvars[0]);
3926 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003927 if (fname == NULL || mods == NULL)
3928 fname = NULL;
3929 else
3930 {
3931 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003932 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933 }
3934
3935 rettv->v_type = VAR_STRING;
3936 if (fname == NULL)
3937 rettv->vval.v_string = NULL;
3938 else
3939 rettv->vval.v_string = vim_strnsave(fname, len);
3940 vim_free(fbuf);
3941}
3942
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003943/*
3944 * "foldclosed()" function
3945 */
3946 static void
3947foldclosed_both(
3948 typval_T *argvars UNUSED,
3949 typval_T *rettv,
3950 int end UNUSED)
3951{
3952#ifdef FEAT_FOLDING
3953 linenr_T lnum;
3954 linenr_T first, last;
3955
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003956 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003957 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3958 {
3959 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3960 {
3961 if (end)
3962 rettv->vval.v_number = (varnumber_T)last;
3963 else
3964 rettv->vval.v_number = (varnumber_T)first;
3965 return;
3966 }
3967 }
3968#endif
3969 rettv->vval.v_number = -1;
3970}
3971
3972/*
3973 * "foldclosed()" function
3974 */
3975 static void
3976f_foldclosed(typval_T *argvars, typval_T *rettv)
3977{
3978 foldclosed_both(argvars, rettv, FALSE);
3979}
3980
3981/*
3982 * "foldclosedend()" function
3983 */
3984 static void
3985f_foldclosedend(typval_T *argvars, typval_T *rettv)
3986{
3987 foldclosed_both(argvars, rettv, TRUE);
3988}
3989
3990/*
3991 * "foldlevel()" function
3992 */
3993 static void
3994f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3995{
3996#ifdef FEAT_FOLDING
3997 linenr_T lnum;
3998
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003999 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004000 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4001 rettv->vval.v_number = foldLevel(lnum);
4002#endif
4003}
4004
4005/*
4006 * "foldtext()" function
4007 */
4008 static void
4009f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4010{
4011#ifdef FEAT_FOLDING
4012 linenr_T foldstart;
4013 linenr_T foldend;
4014 char_u *dashes;
4015 linenr_T lnum;
4016 char_u *s;
4017 char_u *r;
4018 int len;
4019 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004020 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021#endif
4022
4023 rettv->v_type = VAR_STRING;
4024 rettv->vval.v_string = NULL;
4025#ifdef FEAT_FOLDING
4026 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4027 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4028 dashes = get_vim_var_str(VV_FOLDDASHES);
4029 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4030 && dashes != NULL)
4031 {
4032 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004033 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034 if (!linewhite(lnum))
4035 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004036
4037 /* Find interesting text in this line. */
4038 s = skipwhite(ml_get(lnum));
4039 /* skip C comment-start */
4040 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4041 {
4042 s = skipwhite(s + 2);
4043 if (*skipwhite(s) == NUL
4044 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4045 {
4046 s = skipwhite(ml_get(lnum + 1));
4047 if (*s == '*')
4048 s = skipwhite(s + 1);
4049 }
4050 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004051 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004052 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004053 r = alloc((unsigned)(STRLEN(txt)
4054 + STRLEN(dashes) /* for %s */
4055 + 20 /* for %3ld */
4056 + STRLEN(s))); /* concatenated */
4057 if (r != NULL)
4058 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004059 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004060 len = (int)STRLEN(r);
4061 STRCAT(r, s);
4062 /* remove 'foldmarker' and 'commentstring' */
4063 foldtext_cleanup(r + len);
4064 rettv->vval.v_string = r;
4065 }
4066 }
4067#endif
4068}
4069
4070/*
4071 * "foldtextresult(lnum)" function
4072 */
4073 static void
4074f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4075{
4076#ifdef FEAT_FOLDING
4077 linenr_T lnum;
4078 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004079 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004080 foldinfo_T foldinfo;
4081 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004082 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004083#endif
4084
4085 rettv->v_type = VAR_STRING;
4086 rettv->vval.v_string = NULL;
4087#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004088 if (entered)
4089 return; /* reject recursive use */
4090 entered = TRUE;
4091
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004092 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004093 /* treat illegal types and illegal string values for {lnum} the same */
4094 if (lnum < 0)
4095 lnum = 0;
4096 fold_count = foldedCount(curwin, lnum, &foldinfo);
4097 if (fold_count > 0)
4098 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004099 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4100 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004101 if (text == buf)
4102 text = vim_strsave(text);
4103 rettv->vval.v_string = text;
4104 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004105
4106 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107#endif
4108}
4109
4110/*
4111 * "foreground()" function
4112 */
4113 static void
4114f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4115{
4116#ifdef FEAT_GUI
4117 if (gui.in_use)
4118 gui_mch_set_foreground();
4119#else
4120# ifdef WIN32
4121 win32_set_foreground();
4122# endif
4123#endif
4124}
4125
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004126 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004127common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004128{
4129 char_u *s;
4130 char_u *name;
4131 int use_string = FALSE;
4132 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004133 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134
4135 if (argvars[0].v_type == VAR_FUNC)
4136 {
4137 /* function(MyFunc, [arg], dict) */
4138 s = argvars[0].vval.v_string;
4139 }
4140 else if (argvars[0].v_type == VAR_PARTIAL
4141 && argvars[0].vval.v_partial != NULL)
4142 {
4143 /* function(dict.MyFunc, [arg]) */
4144 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004145 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004146 }
4147 else
4148 {
4149 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004150 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004151 use_string = TRUE;
4152 }
4153
Bram Moolenaar843b8842016-08-21 14:36:15 +02004154 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004155 {
4156 name = s;
4157 trans_name = trans_function_name(&name, FALSE,
4158 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4159 if (*name != NUL)
4160 s = NULL;
4161 }
4162
Bram Moolenaar843b8842016-08-21 14:36:15 +02004163 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4164 || (is_funcref && trans_name == NULL))
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004165 EMSG2(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004166 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004167 else if (trans_name != NULL && (is_funcref
4168 ? find_func(trans_name) == NULL
4169 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004170 EMSG2(_("E700: Unknown function: %s"), s);
4171 else
4172 {
4173 int dict_idx = 0;
4174 int arg_idx = 0;
4175 list_T *list = NULL;
4176
4177 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4178 {
4179 char sid_buf[25];
4180 int off = *s == 's' ? 2 : 5;
4181
4182 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4183 * also be called from another script. Using trans_function_name()
4184 * would also work, but some plugins depend on the name being
4185 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004186 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004187 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4188 if (name != NULL)
4189 {
4190 STRCPY(name, sid_buf);
4191 STRCAT(name, s + off);
4192 }
4193 }
4194 else
4195 name = vim_strsave(s);
4196
4197 if (argvars[1].v_type != VAR_UNKNOWN)
4198 {
4199 if (argvars[2].v_type != VAR_UNKNOWN)
4200 {
4201 /* function(name, [args], dict) */
4202 arg_idx = 1;
4203 dict_idx = 2;
4204 }
4205 else if (argvars[1].v_type == VAR_DICT)
4206 /* function(name, dict) */
4207 dict_idx = 1;
4208 else
4209 /* function(name, [args]) */
4210 arg_idx = 1;
4211 if (dict_idx > 0)
4212 {
4213 if (argvars[dict_idx].v_type != VAR_DICT)
4214 {
4215 EMSG(_("E922: expected a dict"));
4216 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004217 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004218 }
4219 if (argvars[dict_idx].vval.v_dict == NULL)
4220 dict_idx = 0;
4221 }
4222 if (arg_idx > 0)
4223 {
4224 if (argvars[arg_idx].v_type != VAR_LIST)
4225 {
4226 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4227 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004228 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004229 }
4230 list = argvars[arg_idx].vval.v_list;
4231 if (list == NULL || list->lv_len == 0)
4232 arg_idx = 0;
4233 }
4234 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004235 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004236 {
4237 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4238
4239 /* result is a VAR_PARTIAL */
4240 if (pt == NULL)
4241 vim_free(name);
4242 else
4243 {
4244 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4245 {
4246 listitem_T *li;
4247 int i = 0;
4248 int arg_len = 0;
4249 int lv_len = 0;
4250
4251 if (arg_pt != NULL)
4252 arg_len = arg_pt->pt_argc;
4253 if (list != NULL)
4254 lv_len = list->lv_len;
4255 pt->pt_argc = arg_len + lv_len;
4256 pt->pt_argv = (typval_T *)alloc(
4257 sizeof(typval_T) * pt->pt_argc);
4258 if (pt->pt_argv == NULL)
4259 {
4260 vim_free(pt);
4261 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004262 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004263 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004264 for (i = 0; i < arg_len; i++)
4265 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4266 if (lv_len > 0)
4267 for (li = list->lv_first; li != NULL;
4268 li = li->li_next)
4269 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004270 }
4271
4272 /* For "function(dict.func, [], dict)" and "func" is a partial
4273 * use "dict". That is backwards compatible. */
4274 if (dict_idx > 0)
4275 {
4276 /* The dict is bound explicitly, pt_auto is FALSE. */
4277 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4278 ++pt->pt_dict->dv_refcount;
4279 }
4280 else if (arg_pt != NULL)
4281 {
4282 /* If the dict was bound automatically the result is also
4283 * bound automatically. */
4284 pt->pt_dict = arg_pt->pt_dict;
4285 pt->pt_auto = arg_pt->pt_auto;
4286 if (pt->pt_dict != NULL)
4287 ++pt->pt_dict->dv_refcount;
4288 }
4289
4290 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004291 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4292 {
4293 pt->pt_func = arg_pt->pt_func;
4294 func_ptr_ref(pt->pt_func);
4295 vim_free(name);
4296 }
4297 else if (is_funcref)
4298 {
4299 pt->pt_func = find_func(trans_name);
4300 func_ptr_ref(pt->pt_func);
4301 vim_free(name);
4302 }
4303 else
4304 {
4305 pt->pt_name = name;
4306 func_ref(name);
4307 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004308 }
4309 rettv->v_type = VAR_PARTIAL;
4310 rettv->vval.v_partial = pt;
4311 }
4312 else
4313 {
4314 /* result is a VAR_FUNC */
4315 rettv->v_type = VAR_FUNC;
4316 rettv->vval.v_string = name;
4317 func_ref(name);
4318 }
4319 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004320theend:
4321 vim_free(trans_name);
4322}
4323
4324/*
4325 * "funcref()" function
4326 */
4327 static void
4328f_funcref(typval_T *argvars, typval_T *rettv)
4329{
4330 common_function(argvars, rettv, TRUE);
4331}
4332
4333/*
4334 * "function()" function
4335 */
4336 static void
4337f_function(typval_T *argvars, typval_T *rettv)
4338{
4339 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004340}
4341
4342/*
4343 * "garbagecollect()" function
4344 */
4345 static void
4346f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4347{
4348 /* This is postponed until we are back at the toplevel, because we may be
4349 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4350 want_garbage_collect = TRUE;
4351
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004352 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004353 garbage_collect_at_exit = TRUE;
4354}
4355
4356/*
4357 * "get()" function
4358 */
4359 static void
4360f_get(typval_T *argvars, typval_T *rettv)
4361{
4362 listitem_T *li;
4363 list_T *l;
4364 dictitem_T *di;
4365 dict_T *d;
4366 typval_T *tv = NULL;
4367
4368 if (argvars[0].v_type == VAR_LIST)
4369 {
4370 if ((l = argvars[0].vval.v_list) != NULL)
4371 {
4372 int error = FALSE;
4373
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004374 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004375 if (!error && li != NULL)
4376 tv = &li->li_tv;
4377 }
4378 }
4379 else if (argvars[0].v_type == VAR_DICT)
4380 {
4381 if ((d = argvars[0].vval.v_dict) != NULL)
4382 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004383 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384 if (di != NULL)
4385 tv = &di->di_tv;
4386 }
4387 }
4388 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4389 {
4390 partial_T *pt;
4391 partial_T fref_pt;
4392
4393 if (argvars[0].v_type == VAR_PARTIAL)
4394 pt = argvars[0].vval.v_partial;
4395 else
4396 {
4397 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4398 fref_pt.pt_name = argvars[0].vval.v_string;
4399 pt = &fref_pt;
4400 }
4401
4402 if (pt != NULL)
4403 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004404 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004405 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004406
4407 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4408 {
4409 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004410 n = partial_name(pt);
4411 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004412 rettv->vval.v_string = NULL;
4413 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004414 {
4415 rettv->vval.v_string = vim_strsave(n);
4416 if (rettv->v_type == VAR_FUNC)
4417 func_ref(rettv->vval.v_string);
4418 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004419 }
4420 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004421 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004422 else if (STRCMP(what, "args") == 0)
4423 {
4424 rettv->v_type = VAR_LIST;
4425 if (rettv_list_alloc(rettv) == OK)
4426 {
4427 int i;
4428
4429 for (i = 0; i < pt->pt_argc; ++i)
4430 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4431 }
4432 }
4433 else
4434 EMSG2(_(e_invarg2), what);
4435 return;
4436 }
4437 }
4438 else
4439 EMSG2(_(e_listdictarg), "get()");
4440
4441 if (tv == NULL)
4442 {
4443 if (argvars[2].v_type != VAR_UNKNOWN)
4444 copy_tv(&argvars[2], rettv);
4445 }
4446 else
4447 copy_tv(tv, rettv);
4448}
4449
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004450/*
4451 * Returns buffer options, variables and other attributes in a dictionary.
4452 */
4453 static dict_T *
4454get_buffer_info(buf_T *buf)
4455{
4456 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004457 tabpage_T *tp;
4458 win_T *wp;
4459 list_T *windows;
4460
4461 dict = dict_alloc();
4462 if (dict == NULL)
4463 return NULL;
4464
Bram Moolenaare0be1672018-07-08 16:50:37 +02004465 dict_add_number(dict, "bufnr", buf->b_fnum);
4466 dict_add_string(dict, "name", buf->b_ffname);
4467 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4468 : buflist_findlnum(buf));
4469 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4470 dict_add_number(dict, "listed", buf->b_p_bl);
4471 dict_add_number(dict, "changed", bufIsChanged(buf));
4472 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4473 dict_add_number(dict, "hidden",
4474 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004475
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004476 /* Get a reference to buffer variables */
4477 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004478
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004479 /* List of windows displaying this buffer */
4480 windows = list_alloc();
4481 if (windows != NULL)
4482 {
4483 FOR_ALL_TAB_WINDOWS(tp, wp)
4484 if (wp->w_buffer == buf)
4485 list_append_number(windows, (varnumber_T)wp->w_id);
4486 dict_add_list(dict, "windows", windows);
4487 }
4488
4489#ifdef FEAT_SIGNS
4490 if (buf->b_signlist != NULL)
4491 {
4492 /* List of signs placed in this buffer */
4493 list_T *signs = list_alloc();
4494 if (signs != NULL)
4495 {
4496 get_buffer_signs(buf, signs);
4497 dict_add_list(dict, "signs", signs);
4498 }
4499 }
4500#endif
4501
4502 return dict;
4503}
4504
4505/*
4506 * "getbufinfo()" function
4507 */
4508 static void
4509f_getbufinfo(typval_T *argvars, typval_T *rettv)
4510{
4511 buf_T *buf = NULL;
4512 buf_T *argbuf = NULL;
4513 dict_T *d;
4514 int filtered = FALSE;
4515 int sel_buflisted = FALSE;
4516 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004517 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004518
4519 if (rettv_list_alloc(rettv) != OK)
4520 return;
4521
4522 /* List of all the buffers or selected buffers */
4523 if (argvars[0].v_type == VAR_DICT)
4524 {
4525 dict_T *sel_d = argvars[0].vval.v_dict;
4526
4527 if (sel_d != NULL)
4528 {
4529 dictitem_T *di;
4530
4531 filtered = TRUE;
4532
4533 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004534 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004535 sel_buflisted = TRUE;
4536
4537 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004538 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004539 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004540
4541 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004542 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004543 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004544 }
4545 }
4546 else if (argvars[0].v_type != VAR_UNKNOWN)
4547 {
4548 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004549 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004550 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004551 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004552 --emsg_off;
4553 if (argbuf == NULL)
4554 return;
4555 }
4556
4557 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004558 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004559 {
4560 if (argbuf != NULL && argbuf != buf)
4561 continue;
4562 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004563 || (sel_buflisted && !buf->b_p_bl)
4564 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004565 continue;
4566
4567 d = get_buffer_info(buf);
4568 if (d != NULL)
4569 list_append_dict(rettv->vval.v_list, d);
4570 if (argbuf != NULL)
4571 return;
4572 }
4573}
4574
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004575/*
4576 * Get line or list of lines from buffer "buf" into "rettv".
4577 * Return a range (from start to end) of lines in rettv from the specified
4578 * buffer.
4579 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4580 */
4581 static void
4582get_buffer_lines(
4583 buf_T *buf,
4584 linenr_T start,
4585 linenr_T end,
4586 int retlist,
4587 typval_T *rettv)
4588{
4589 char_u *p;
4590
4591 rettv->v_type = VAR_STRING;
4592 rettv->vval.v_string = NULL;
4593 if (retlist && rettv_list_alloc(rettv) == FAIL)
4594 return;
4595
4596 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4597 return;
4598
4599 if (!retlist)
4600 {
4601 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4602 p = ml_get_buf(buf, start, FALSE);
4603 else
4604 p = (char_u *)"";
4605 rettv->vval.v_string = vim_strsave(p);
4606 }
4607 else
4608 {
4609 if (end < start)
4610 return;
4611
4612 if (start < 1)
4613 start = 1;
4614 if (end > buf->b_ml.ml_line_count)
4615 end = buf->b_ml.ml_line_count;
4616 while (start <= end)
4617 if (list_append_string(rettv->vval.v_list,
4618 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4619 break;
4620 }
4621}
4622
4623/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004624 * "getbufline()" function
4625 */
4626 static void
4627f_getbufline(typval_T *argvars, typval_T *rettv)
4628{
4629 linenr_T lnum;
4630 linenr_T end;
4631 buf_T *buf;
4632
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004633 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004634 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004635 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004636 --emsg_off;
4637
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004638 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004639 if (argvars[2].v_type == VAR_UNKNOWN)
4640 end = lnum;
4641 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004642 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004643
4644 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4645}
4646
4647/*
4648 * "getbufvar()" function
4649 */
4650 static void
4651f_getbufvar(typval_T *argvars, typval_T *rettv)
4652{
4653 buf_T *buf;
4654 buf_T *save_curbuf;
4655 char_u *varname;
4656 dictitem_T *v;
4657 int done = FALSE;
4658
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004659 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4660 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004662 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663
4664 rettv->v_type = VAR_STRING;
4665 rettv->vval.v_string = NULL;
4666
4667 if (buf != NULL && varname != NULL)
4668 {
4669 /* set curbuf to be our buf, temporarily */
4670 save_curbuf = curbuf;
4671 curbuf = buf;
4672
Bram Moolenaar30567352016-08-27 21:25:44 +02004673 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004674 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004675 if (varname[1] == NUL)
4676 {
4677 /* get all buffer-local options in a dict */
4678 dict_T *opts = get_winbuf_options(TRUE);
4679
4680 if (opts != NULL)
4681 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004682 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004683 done = TRUE;
4684 }
4685 }
4686 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4687 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004688 done = TRUE;
4689 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004690 else
4691 {
4692 /* Look up the variable. */
4693 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4694 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4695 'b', varname, FALSE);
4696 if (v != NULL)
4697 {
4698 copy_tv(&v->di_tv, rettv);
4699 done = TRUE;
4700 }
4701 }
4702
4703 /* restore previous notion of curbuf */
4704 curbuf = save_curbuf;
4705 }
4706
4707 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4708 /* use the default value */
4709 copy_tv(&argvars[2], rettv);
4710
4711 --emsg_off;
4712}
4713
4714/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004715 * "getchangelist()" function
4716 */
4717 static void
4718f_getchangelist(typval_T *argvars, typval_T *rettv)
4719{
4720#ifdef FEAT_JUMPLIST
4721 buf_T *buf;
4722 int i;
4723 list_T *l;
4724 dict_T *d;
4725#endif
4726
4727 if (rettv_list_alloc(rettv) != OK)
4728 return;
4729
4730#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004731 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004732 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004733 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004734 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004735 if (buf == NULL)
4736 return;
4737
4738 l = list_alloc();
4739 if (l == NULL)
4740 return;
4741
4742 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4743 return;
4744 /*
4745 * The current window change list index tracks only the position in the
4746 * current buffer change list. For other buffers, use the change list
4747 * length as the current index.
4748 */
4749 list_append_number(rettv->vval.v_list,
4750 (varnumber_T)((buf == curwin->w_buffer)
4751 ? curwin->w_changelistidx : buf->b_changelistlen));
4752
4753 for (i = 0; i < buf->b_changelistlen; ++i)
4754 {
4755 if (buf->b_changelist[i].lnum == 0)
4756 continue;
4757 if ((d = dict_alloc()) == NULL)
4758 return;
4759 if (list_append_dict(l, d) == FAIL)
4760 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004761 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4762 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004763# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004764 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004765# endif
4766 }
4767#endif
4768}
4769/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004770 * "getchar()" function
4771 */
4772 static void
4773f_getchar(typval_T *argvars, typval_T *rettv)
4774{
4775 varnumber_T n;
4776 int error = FALSE;
4777
Bram Moolenaar84d93902018-09-11 20:10:20 +02004778#ifdef MESSAGE_QUEUE
4779 // vpeekc() used to check for messages, but that caused problems, invoking
4780 // a callback where it was not expected. Some plugins use getchar(1) in a
4781 // loop to await a message, therefore make sure we check for messages here.
4782 parse_queued_messages();
4783#endif
4784
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004785 /* Position the cursor. Needed after a message that ends in a space. */
4786 windgoto(msg_row, msg_col);
4787
4788 ++no_mapping;
4789 ++allow_keys;
4790 for (;;)
4791 {
4792 if (argvars[0].v_type == VAR_UNKNOWN)
4793 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004794 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004795 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796 /* getchar(1): only check if char avail */
4797 n = vpeekc_any();
4798 else if (error || vpeekc_any() == NUL)
4799 /* illegal argument or getchar(0) and no char avail: return zero */
4800 n = 0;
4801 else
4802 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004803 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004804
4805 if (n == K_IGNORE)
4806 continue;
4807 break;
4808 }
4809 --no_mapping;
4810 --allow_keys;
4811
4812 set_vim_var_nr(VV_MOUSE_WIN, 0);
4813 set_vim_var_nr(VV_MOUSE_WINID, 0);
4814 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4815 set_vim_var_nr(VV_MOUSE_COL, 0);
4816
4817 rettv->vval.v_number = n;
4818 if (IS_SPECIAL(n) || mod_mask != 0)
4819 {
4820 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4821 int i = 0;
4822
4823 /* Turn a special key into three bytes, plus modifier. */
4824 if (mod_mask != 0)
4825 {
4826 temp[i++] = K_SPECIAL;
4827 temp[i++] = KS_MODIFIER;
4828 temp[i++] = mod_mask;
4829 }
4830 if (IS_SPECIAL(n))
4831 {
4832 temp[i++] = K_SPECIAL;
4833 temp[i++] = K_SECOND(n);
4834 temp[i++] = K_THIRD(n);
4835 }
4836#ifdef FEAT_MBYTE
4837 else if (has_mbyte)
4838 i += (*mb_char2bytes)(n, temp + i);
4839#endif
4840 else
4841 temp[i++] = n;
4842 temp[i++] = NUL;
4843 rettv->v_type = VAR_STRING;
4844 rettv->vval.v_string = vim_strsave(temp);
4845
4846#ifdef FEAT_MOUSE
4847 if (is_mouse_key(n))
4848 {
4849 int row = mouse_row;
4850 int col = mouse_col;
4851 win_T *win;
4852 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004854 int winnr = 1;
4855
4856 if (row >= 0 && col >= 0)
4857 {
4858 /* Find the window at the mouse coordinates and compute the
4859 * text position. */
4860 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004861 if (win == NULL)
4862 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004863 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004864 for (wp = firstwin; wp != win; wp = wp->w_next)
4865 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004866 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4867 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4868 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4869 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4870 }
4871 }
4872#endif
4873 }
4874}
4875
4876/*
4877 * "getcharmod()" function
4878 */
4879 static void
4880f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4881{
4882 rettv->vval.v_number = mod_mask;
4883}
4884
4885/*
4886 * "getcharsearch()" function
4887 */
4888 static void
4889f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4890{
4891 if (rettv_dict_alloc(rettv) != FAIL)
4892 {
4893 dict_T *dict = rettv->vval.v_dict;
4894
Bram Moolenaare0be1672018-07-08 16:50:37 +02004895 dict_add_string(dict, "char", last_csearch());
4896 dict_add_number(dict, "forward", last_csearch_forward());
4897 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004898 }
4899}
4900
4901/*
4902 * "getcmdline()" function
4903 */
4904 static void
4905f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4906{
4907 rettv->v_type = VAR_STRING;
4908 rettv->vval.v_string = get_cmdline_str();
4909}
4910
4911/*
4912 * "getcmdpos()" function
4913 */
4914 static void
4915f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4916{
4917 rettv->vval.v_number = get_cmdline_pos() + 1;
4918}
4919
4920/*
4921 * "getcmdtype()" function
4922 */
4923 static void
4924f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4925{
4926 rettv->v_type = VAR_STRING;
4927 rettv->vval.v_string = alloc(2);
4928 if (rettv->vval.v_string != NULL)
4929 {
4930 rettv->vval.v_string[0] = get_cmdline_type();
4931 rettv->vval.v_string[1] = NUL;
4932 }
4933}
4934
4935/*
4936 * "getcmdwintype()" function
4937 */
4938 static void
4939f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4940{
4941 rettv->v_type = VAR_STRING;
4942 rettv->vval.v_string = NULL;
4943#ifdef FEAT_CMDWIN
4944 rettv->vval.v_string = alloc(2);
4945 if (rettv->vval.v_string != NULL)
4946 {
4947 rettv->vval.v_string[0] = cmdwin_type;
4948 rettv->vval.v_string[1] = NUL;
4949 }
4950#endif
4951}
4952
4953#if defined(FEAT_CMDL_COMPL)
4954/*
4955 * "getcompletion()" function
4956 */
4957 static void
4958f_getcompletion(typval_T *argvars, typval_T *rettv)
4959{
4960 char_u *pat;
4961 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004962 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004963 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4964 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004966 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004967 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004968
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004969 if (p_wic)
4970 options |= WILD_ICASE;
4971
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004972 /* For filtered results, 'wildignore' is used */
4973 if (!filtered)
4974 options |= WILD_KEEP_ALL;
4975
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004977 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004978 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004979 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004980 if (xpc.xp_context == EXPAND_NOTHING)
4981 {
4982 if (argvars[1].v_type == VAR_STRING)
4983 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4984 else
4985 EMSG(_(e_invarg));
4986 return;
4987 }
4988
4989# if defined(FEAT_MENU)
4990 if (xpc.xp_context == EXPAND_MENUS)
4991 {
4992 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4993 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4994 }
4995# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004996#ifdef FEAT_CSCOPE
4997 if (xpc.xp_context == EXPAND_CSCOPE)
4998 {
4999 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5000 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5001 }
5002#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005003#ifdef FEAT_SIGNS
5004 if (xpc.xp_context == EXPAND_SIGN)
5005 {
5006 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5007 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5008 }
5009#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005010
5011 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5012 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5013 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005014 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005015
5016 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5017
5018 for (i = 0; i < xpc.xp_numfiles; i++)
5019 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5020 }
5021 vim_free(pat);
5022 ExpandCleanup(&xpc);
5023}
5024#endif
5025
5026/*
5027 * "getcwd()" function
5028 */
5029 static void
5030f_getcwd(typval_T *argvars, typval_T *rettv)
5031{
5032 win_T *wp = NULL;
5033 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005034 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035
5036 rettv->v_type = VAR_STRING;
5037 rettv->vval.v_string = NULL;
5038
Bram Moolenaar54591292018-02-09 20:53:59 +01005039 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5040 global = TRUE;
5041 else
5042 wp = find_tabwin(&argvars[0], &argvars[1]);
5043
5044 if (wp != NULL && wp->w_localdir != NULL)
5045 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5046 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005047 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005048 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005049 rettv->vval.v_string = vim_strsave(globaldir);
5050 else
5051 {
5052 cwd = alloc(MAXPATHL);
5053 if (cwd != NULL)
5054 {
5055 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5056 rettv->vval.v_string = vim_strsave(cwd);
5057 vim_free(cwd);
5058 }
5059 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005061#ifdef BACKSLASH_IN_FILENAME
5062 if (rettv->vval.v_string != NULL)
5063 slash_adjust(rettv->vval.v_string);
5064#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065}
5066
5067/*
5068 * "getfontname()" function
5069 */
5070 static void
5071f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5072{
5073 rettv->v_type = VAR_STRING;
5074 rettv->vval.v_string = NULL;
5075#ifdef FEAT_GUI
5076 if (gui.in_use)
5077 {
5078 GuiFont font;
5079 char_u *name = NULL;
5080
5081 if (argvars[0].v_type == VAR_UNKNOWN)
5082 {
5083 /* Get the "Normal" font. Either the name saved by
5084 * hl_set_font_name() or from the font ID. */
5085 font = gui.norm_font;
5086 name = hl_get_font_name();
5087 }
5088 else
5089 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005090 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005091 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5092 return;
5093 font = gui_mch_get_font(name, FALSE);
5094 if (font == NOFONT)
5095 return; /* Invalid font name, return empty string. */
5096 }
5097 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5098 if (argvars[0].v_type != VAR_UNKNOWN)
5099 gui_mch_free_font(font);
5100 }
5101#endif
5102}
5103
5104/*
5105 * "getfperm({fname})" function
5106 */
5107 static void
5108f_getfperm(typval_T *argvars, typval_T *rettv)
5109{
5110 char_u *fname;
5111 stat_T st;
5112 char_u *perm = NULL;
5113 char_u flags[] = "rwx";
5114 int i;
5115
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005116 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117
5118 rettv->v_type = VAR_STRING;
5119 if (mch_stat((char *)fname, &st) >= 0)
5120 {
5121 perm = vim_strsave((char_u *)"---------");
5122 if (perm != NULL)
5123 {
5124 for (i = 0; i < 9; i++)
5125 {
5126 if (st.st_mode & (1 << (8 - i)))
5127 perm[i] = flags[i % 3];
5128 }
5129 }
5130 }
5131 rettv->vval.v_string = perm;
5132}
5133
5134/*
5135 * "getfsize({fname})" function
5136 */
5137 static void
5138f_getfsize(typval_T *argvars, typval_T *rettv)
5139{
5140 char_u *fname;
5141 stat_T st;
5142
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005143 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005144
5145 rettv->v_type = VAR_NUMBER;
5146
5147 if (mch_stat((char *)fname, &st) >= 0)
5148 {
5149 if (mch_isdir(fname))
5150 rettv->vval.v_number = 0;
5151 else
5152 {
5153 rettv->vval.v_number = (varnumber_T)st.st_size;
5154
5155 /* non-perfect check for overflow */
5156 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5157 rettv->vval.v_number = -2;
5158 }
5159 }
5160 else
5161 rettv->vval.v_number = -1;
5162}
5163
5164/*
5165 * "getftime({fname})" function
5166 */
5167 static void
5168f_getftime(typval_T *argvars, typval_T *rettv)
5169{
5170 char_u *fname;
5171 stat_T st;
5172
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005173 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005174
5175 if (mch_stat((char *)fname, &st) >= 0)
5176 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5177 else
5178 rettv->vval.v_number = -1;
5179}
5180
5181/*
5182 * "getftype({fname})" function
5183 */
5184 static void
5185f_getftype(typval_T *argvars, typval_T *rettv)
5186{
5187 char_u *fname;
5188 stat_T st;
5189 char_u *type = NULL;
5190 char *t;
5191
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005192 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193
5194 rettv->v_type = VAR_STRING;
5195 if (mch_lstat((char *)fname, &st) >= 0)
5196 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005197 if (S_ISREG(st.st_mode))
5198 t = "file";
5199 else if (S_ISDIR(st.st_mode))
5200 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 else if (S_ISLNK(st.st_mode))
5202 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 else if (S_ISBLK(st.st_mode))
5204 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005205 else if (S_ISCHR(st.st_mode))
5206 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005207 else if (S_ISFIFO(st.st_mode))
5208 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005210 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005211 else
5212 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005213 type = vim_strsave((char_u *)t);
5214 }
5215 rettv->vval.v_string = type;
5216}
5217
5218/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005219 * "getjumplist()" function
5220 */
5221 static void
5222f_getjumplist(typval_T *argvars, typval_T *rettv)
5223{
5224#ifdef FEAT_JUMPLIST
5225 win_T *wp;
5226 int i;
5227 list_T *l;
5228 dict_T *d;
5229#endif
5230
5231 if (rettv_list_alloc(rettv) != OK)
5232 return;
5233
5234#ifdef FEAT_JUMPLIST
5235 wp = find_tabwin(&argvars[0], &argvars[1]);
5236 if (wp == NULL)
5237 return;
5238
5239 l = list_alloc();
5240 if (l == NULL)
5241 return;
5242
5243 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5244 return;
5245 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5246
Bram Moolenaar48679742018-02-13 13:33:29 +01005247 cleanup_jumplist(wp, TRUE);
5248
Bram Moolenaar4f505882018-02-10 21:06:32 +01005249 for (i = 0; i < wp->w_jumplistlen; ++i)
5250 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005251 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5252 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005253 if ((d = dict_alloc()) == NULL)
5254 return;
5255 if (list_append_dict(l, d) == FAIL)
5256 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005257 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5258 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005259# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005260 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005261# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005262 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005263 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005264 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005265 }
5266#endif
5267}
5268
5269/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005270 * "getline(lnum, [end])" function
5271 */
5272 static void
5273f_getline(typval_T *argvars, typval_T *rettv)
5274{
5275 linenr_T lnum;
5276 linenr_T end;
5277 int retlist;
5278
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005279 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005280 if (argvars[1].v_type == VAR_UNKNOWN)
5281 {
5282 end = 0;
5283 retlist = FALSE;
5284 }
5285 else
5286 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005287 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288 retlist = TRUE;
5289 }
5290
5291 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5292}
5293
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005294#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005295 static void
5296get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5297{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005298 if (what_arg->v_type == VAR_UNKNOWN)
5299 {
5300 if (rettv_list_alloc(rettv) == OK)
5301 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005302 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005303 }
5304 else
5305 {
5306 if (rettv_dict_alloc(rettv) == OK)
5307 if (is_qf || (wp != NULL))
5308 {
5309 if (what_arg->v_type == VAR_DICT)
5310 {
5311 dict_T *d = what_arg->vval.v_dict;
5312
5313 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005314 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005315 }
5316 else
5317 EMSG(_(e_dictreq));
5318 }
5319 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005320}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005321#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005322
5323/*
5324 * "getloclist()" function
5325 */
5326 static void
5327f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5328{
5329#ifdef FEAT_QUICKFIX
5330 win_T *wp;
5331
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005332 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005333 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5334#endif
5335}
5336
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005337/*
5338 * "getmatches()" function
5339 */
5340 static void
5341f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5342{
5343#ifdef FEAT_SEARCH_EXTRA
5344 dict_T *dict;
5345 matchitem_T *cur = curwin->w_match_head;
5346 int i;
5347
5348 if (rettv_list_alloc(rettv) == OK)
5349 {
5350 while (cur != NULL)
5351 {
5352 dict = dict_alloc();
5353 if (dict == NULL)
5354 return;
5355 if (cur->match.regprog == NULL)
5356 {
5357 /* match added with matchaddpos() */
5358 for (i = 0; i < MAXPOSMATCH; ++i)
5359 {
5360 llpos_T *llpos;
5361 char buf[6];
5362 list_T *l;
5363
5364 llpos = &cur->pos.pos[i];
5365 if (llpos->lnum == 0)
5366 break;
5367 l = list_alloc();
5368 if (l == NULL)
5369 break;
5370 list_append_number(l, (varnumber_T)llpos->lnum);
5371 if (llpos->col > 0)
5372 {
5373 list_append_number(l, (varnumber_T)llpos->col);
5374 list_append_number(l, (varnumber_T)llpos->len);
5375 }
5376 sprintf(buf, "pos%d", i + 1);
5377 dict_add_list(dict, buf, l);
5378 }
5379 }
5380 else
5381 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005382 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005383 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005384 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5385 dict_add_number(dict, "priority", (long)cur->priority);
5386 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005387# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5388 if (cur->conceal_char)
5389 {
5390 char_u buf[MB_MAXBYTES + 1];
5391
5392 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005393 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005394 }
5395# endif
5396 list_append_dict(rettv->vval.v_list, dict);
5397 cur = cur->next;
5398 }
5399 }
5400#endif
5401}
5402
5403/*
5404 * "getpid()" function
5405 */
5406 static void
5407f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5408{
5409 rettv->vval.v_number = mch_get_pid();
5410}
5411
5412 static void
5413getpos_both(
5414 typval_T *argvars,
5415 typval_T *rettv,
5416 int getcurpos)
5417{
5418 pos_T *fp;
5419 list_T *l;
5420 int fnum = -1;
5421
5422 if (rettv_list_alloc(rettv) == OK)
5423 {
5424 l = rettv->vval.v_list;
5425 if (getcurpos)
5426 fp = &curwin->w_cursor;
5427 else
5428 fp = var2fpos(&argvars[0], TRUE, &fnum);
5429 if (fnum != -1)
5430 list_append_number(l, (varnumber_T)fnum);
5431 else
5432 list_append_number(l, (varnumber_T)0);
5433 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5434 : (varnumber_T)0);
5435 list_append_number(l, (fp != NULL)
5436 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5437 : (varnumber_T)0);
5438 list_append_number(l,
5439#ifdef FEAT_VIRTUALEDIT
5440 (fp != NULL) ? (varnumber_T)fp->coladd :
5441#endif
5442 (varnumber_T)0);
5443 if (getcurpos)
5444 {
5445 update_curswant();
5446 list_append_number(l, curwin->w_curswant == MAXCOL ?
5447 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5448 }
5449 }
5450 else
5451 rettv->vval.v_number = FALSE;
5452}
5453
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005454/*
5455 * "getcurpos()" function
5456 */
5457 static void
5458f_getcurpos(typval_T *argvars, typval_T *rettv)
5459{
5460 getpos_both(argvars, rettv, TRUE);
5461}
5462
5463/*
5464 * "getpos(string)" function
5465 */
5466 static void
5467f_getpos(typval_T *argvars, typval_T *rettv)
5468{
5469 getpos_both(argvars, rettv, FALSE);
5470}
5471
5472/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005473 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005474 */
5475 static void
5476f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5477{
5478#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005479 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005480#endif
5481}
5482
5483/*
5484 * "getreg()" function
5485 */
5486 static void
5487f_getreg(typval_T *argvars, typval_T *rettv)
5488{
5489 char_u *strregname;
5490 int regname;
5491 int arg2 = FALSE;
5492 int return_list = FALSE;
5493 int error = FALSE;
5494
5495 if (argvars[0].v_type != VAR_UNKNOWN)
5496 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005497 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005498 error = strregname == NULL;
5499 if (argvars[1].v_type != VAR_UNKNOWN)
5500 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005501 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005503 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504 }
5505 }
5506 else
5507 strregname = get_vim_var_str(VV_REG);
5508
5509 if (error)
5510 return;
5511
5512 regname = (strregname == NULL ? '"' : *strregname);
5513 if (regname == 0)
5514 regname = '"';
5515
5516 if (return_list)
5517 {
5518 rettv->v_type = VAR_LIST;
5519 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5520 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5521 if (rettv->vval.v_list == NULL)
5522 (void)rettv_list_alloc(rettv);
5523 else
5524 ++rettv->vval.v_list->lv_refcount;
5525 }
5526 else
5527 {
5528 rettv->v_type = VAR_STRING;
5529 rettv->vval.v_string = get_reg_contents(regname,
5530 arg2 ? GREG_EXPR_SRC : 0);
5531 }
5532}
5533
5534/*
5535 * "getregtype()" function
5536 */
5537 static void
5538f_getregtype(typval_T *argvars, typval_T *rettv)
5539{
5540 char_u *strregname;
5541 int regname;
5542 char_u buf[NUMBUFLEN + 2];
5543 long reglen = 0;
5544
5545 if (argvars[0].v_type != VAR_UNKNOWN)
5546 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005547 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548 if (strregname == NULL) /* type error; errmsg already given */
5549 {
5550 rettv->v_type = VAR_STRING;
5551 rettv->vval.v_string = NULL;
5552 return;
5553 }
5554 }
5555 else
5556 /* Default to v:register */
5557 strregname = get_vim_var_str(VV_REG);
5558
5559 regname = (strregname == NULL ? '"' : *strregname);
5560 if (regname == 0)
5561 regname = '"';
5562
5563 buf[0] = NUL;
5564 buf[1] = NUL;
5565 switch (get_reg_type(regname, &reglen))
5566 {
5567 case MLINE: buf[0] = 'V'; break;
5568 case MCHAR: buf[0] = 'v'; break;
5569 case MBLOCK:
5570 buf[0] = Ctrl_V;
5571 sprintf((char *)buf + 1, "%ld", reglen + 1);
5572 break;
5573 }
5574 rettv->v_type = VAR_STRING;
5575 rettv->vval.v_string = vim_strsave(buf);
5576}
5577
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005578/*
5579 * Returns information (variables, options, etc.) about a tab page
5580 * as a dictionary.
5581 */
5582 static dict_T *
5583get_tabpage_info(tabpage_T *tp, int tp_idx)
5584{
5585 win_T *wp;
5586 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005587 list_T *l;
5588
5589 dict = dict_alloc();
5590 if (dict == NULL)
5591 return NULL;
5592
Bram Moolenaare0be1672018-07-08 16:50:37 +02005593 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005594
5595 l = list_alloc();
5596 if (l != NULL)
5597 {
5598 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5599 wp; wp = wp->w_next)
5600 list_append_number(l, (varnumber_T)wp->w_id);
5601 dict_add_list(dict, "windows", l);
5602 }
5603
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005604 /* Make a reference to tabpage variables */
5605 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005606
5607 return dict;
5608}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005609
5610/*
5611 * "gettabinfo()" function
5612 */
5613 static void
5614f_gettabinfo(typval_T *argvars, typval_T *rettv)
5615{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005616 tabpage_T *tp, *tparg = NULL;
5617 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005618 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005619
5620 if (rettv_list_alloc(rettv) != OK)
5621 return;
5622
5623 if (argvars[0].v_type != VAR_UNKNOWN)
5624 {
5625 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005626 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005627 if (tparg == NULL)
5628 return;
5629 }
5630
5631 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005632 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005633 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005634 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005635 if (tparg != NULL && tp != tparg)
5636 continue;
5637 d = get_tabpage_info(tp, tpnr);
5638 if (d != NULL)
5639 list_append_dict(rettv->vval.v_list, d);
5640 if (tparg != NULL)
5641 return;
5642 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005643}
5644
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005645/*
5646 * "gettabvar()" function
5647 */
5648 static void
5649f_gettabvar(typval_T *argvars, typval_T *rettv)
5650{
5651 win_T *oldcurwin;
5652 tabpage_T *tp, *oldtabpage;
5653 dictitem_T *v;
5654 char_u *varname;
5655 int done = FALSE;
5656
5657 rettv->v_type = VAR_STRING;
5658 rettv->vval.v_string = NULL;
5659
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005660 varname = tv_get_string_chk(&argvars[1]);
5661 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005662 if (tp != NULL && varname != NULL)
5663 {
5664 /* Set tp to be our tabpage, temporarily. Also set the window to the
5665 * first window in the tabpage, otherwise the window is not valid. */
5666 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005667 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5668 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005669 {
5670 /* look up the variable */
5671 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5672 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5673 if (v != NULL)
5674 {
5675 copy_tv(&v->di_tv, rettv);
5676 done = TRUE;
5677 }
5678 }
5679
5680 /* restore previous notion of curwin */
5681 restore_win(oldcurwin, oldtabpage, TRUE);
5682 }
5683
5684 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5685 copy_tv(&argvars[2], rettv);
5686}
5687
5688/*
5689 * "gettabwinvar()" function
5690 */
5691 static void
5692f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5693{
5694 getwinvar(argvars, rettv, 1);
5695}
5696
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005697/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005698 * "gettagstack()" function
5699 */
5700 static void
5701f_gettagstack(typval_T *argvars, typval_T *rettv)
5702{
5703 win_T *wp = curwin; // default is current window
5704
5705 if (rettv_dict_alloc(rettv) != OK)
5706 return;
5707
5708 if (argvars[0].v_type != VAR_UNKNOWN)
5709 {
5710 wp = find_win_by_nr_or_id(&argvars[0]);
5711 if (wp == NULL)
5712 return;
5713 }
5714
5715 get_tagstack(wp, rettv->vval.v_dict);
5716}
5717
5718/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005719 * Returns information about a window as a dictionary.
5720 */
5721 static dict_T *
5722get_win_info(win_T *wp, short tpnr, short winnr)
5723{
5724 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005725
5726 dict = dict_alloc();
5727 if (dict == NULL)
5728 return NULL;
5729
Bram Moolenaare0be1672018-07-08 16:50:37 +02005730 dict_add_number(dict, "tabnr", tpnr);
5731 dict_add_number(dict, "winnr", winnr);
5732 dict_add_number(dict, "winid", wp->w_id);
5733 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005734 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005735#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005736 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005737#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005738 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005739 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005740 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005741
Bram Moolenaar69905d12017-08-13 18:14:47 +02005742#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005743 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005744#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005745#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005746 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5747 dict_add_number(dict, "loclist",
5748 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005749#endif
5750
Bram Moolenaar30567352016-08-27 21:25:44 +02005751 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005752 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005753
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005754 return dict;
5755}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005756
5757/*
5758 * "getwininfo()" function
5759 */
5760 static void
5761f_getwininfo(typval_T *argvars, typval_T *rettv)
5762{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005763 tabpage_T *tp;
5764 win_T *wp = NULL, *wparg = NULL;
5765 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005766 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005767
5768 if (rettv_list_alloc(rettv) != OK)
5769 return;
5770
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005771 if (argvars[0].v_type != VAR_UNKNOWN)
5772 {
5773 wparg = win_id2wp(argvars);
5774 if (wparg == NULL)
5775 return;
5776 }
5777
5778 /* Collect information about either all the windows across all the tab
5779 * pages or one particular window.
5780 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005781 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005782 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005783 tabnr++;
5784 winnr = 0;
5785 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005786 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005787 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005788 if (wparg != NULL && wp != wparg)
5789 continue;
5790 d = get_win_info(wp, tabnr, winnr);
5791 if (d != NULL)
5792 list_append_dict(rettv->vval.v_list, d);
5793 if (wparg != NULL)
5794 /* found information about a specific window */
5795 return;
5796 }
5797 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005798}
5799
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005800/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 * "win_findbuf()" function
5802 */
5803 static void
5804f_win_findbuf(typval_T *argvars, typval_T *rettv)
5805{
5806 if (rettv_list_alloc(rettv) != FAIL)
5807 win_findbuf(argvars, rettv->vval.v_list);
5808}
5809
5810/*
5811 * "win_getid()" function
5812 */
5813 static void
5814f_win_getid(typval_T *argvars, typval_T *rettv)
5815{
5816 rettv->vval.v_number = win_getid(argvars);
5817}
5818
5819/*
5820 * "win_gotoid()" function
5821 */
5822 static void
5823f_win_gotoid(typval_T *argvars, typval_T *rettv)
5824{
5825 rettv->vval.v_number = win_gotoid(argvars);
5826}
5827
5828/*
5829 * "win_id2tabwin()" function
5830 */
5831 static void
5832f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5833{
5834 if (rettv_list_alloc(rettv) != FAIL)
5835 win_id2tabwin(argvars, rettv->vval.v_list);
5836}
5837
5838/*
5839 * "win_id2win()" function
5840 */
5841 static void
5842f_win_id2win(typval_T *argvars, typval_T *rettv)
5843{
5844 rettv->vval.v_number = win_id2win(argvars);
5845}
5846
5847/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005848 * "win_screenpos()" function
5849 */
5850 static void
5851f_win_screenpos(typval_T *argvars, typval_T *rettv)
5852{
5853 win_T *wp;
5854
5855 if (rettv_list_alloc(rettv) == FAIL)
5856 return;
5857
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005858 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005859 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5860 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5861}
5862
5863/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005864 * "getwinpos({timeout})" function
5865 */
5866 static void
5867f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5868{
5869 int x = -1;
5870 int y = -1;
5871
5872 if (rettv_list_alloc(rettv) == FAIL)
5873 return;
5874#ifdef FEAT_GUI
5875 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005876 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005877# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5878 else
5879# endif
5880#endif
5881#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5882 {
5883 varnumber_T timeout = 100;
5884
5885 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005886 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005887 term_get_winpos(&x, &y, timeout);
5888 }
5889#endif
5890 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5891 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5892}
5893
5894
5895/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005896 * "getwinposx()" function
5897 */
5898 static void
5899f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5900{
5901 rettv->vval.v_number = -1;
5902#ifdef FEAT_GUI
5903 if (gui.in_use)
5904 {
5905 int x, y;
5906
5907 if (gui_mch_get_winpos(&x, &y) == OK)
5908 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005909 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005910 }
5911#endif
5912#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5913 {
5914 int x, y;
5915
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005916 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005917 rettv->vval.v_number = x;
5918 }
5919#endif
5920}
5921
5922/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005923 * "getwinposy()" function
5924 */
5925 static void
5926f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5927{
5928 rettv->vval.v_number = -1;
5929#ifdef FEAT_GUI
5930 if (gui.in_use)
5931 {
5932 int x, y;
5933
5934 if (gui_mch_get_winpos(&x, &y) == OK)
5935 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005936 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005937 }
5938#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005939#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5940 {
5941 int x, y;
5942
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005943 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005944 rettv->vval.v_number = y;
5945 }
5946#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005947}
5948
5949/*
5950 * "getwinvar()" function
5951 */
5952 static void
5953f_getwinvar(typval_T *argvars, typval_T *rettv)
5954{
5955 getwinvar(argvars, rettv, 0);
5956}
5957
5958/*
5959 * "glob()" function
5960 */
5961 static void
5962f_glob(typval_T *argvars, typval_T *rettv)
5963{
5964 int options = WILD_SILENT|WILD_USE_NL;
5965 expand_T xpc;
5966 int error = FALSE;
5967
5968 /* When the optional second argument is non-zero, don't remove matches
5969 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5970 rettv->v_type = VAR_STRING;
5971 if (argvars[1].v_type != VAR_UNKNOWN)
5972 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005973 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005974 options |= WILD_KEEP_ALL;
5975 if (argvars[2].v_type != VAR_UNKNOWN)
5976 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005977 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005979 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005980 }
5981 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005982 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005983 options |= WILD_ALLLINKS;
5984 }
5985 }
5986 if (!error)
5987 {
5988 ExpandInit(&xpc);
5989 xpc.xp_context = EXPAND_FILES;
5990 if (p_wic)
5991 options += WILD_ICASE;
5992 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005993 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994 NULL, options, WILD_ALL);
5995 else if (rettv_list_alloc(rettv) != FAIL)
5996 {
5997 int i;
5998
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005999 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006000 NULL, options, WILD_ALL_KEEP);
6001 for (i = 0; i < xpc.xp_numfiles; i++)
6002 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6003
6004 ExpandCleanup(&xpc);
6005 }
6006 }
6007 else
6008 rettv->vval.v_string = NULL;
6009}
6010
6011/*
6012 * "globpath()" function
6013 */
6014 static void
6015f_globpath(typval_T *argvars, typval_T *rettv)
6016{
6017 int flags = 0;
6018 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006019 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006020 int error = FALSE;
6021 garray_T ga;
6022 int i;
6023
6024 /* When the optional second argument is non-zero, don't remove matches
6025 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6026 rettv->v_type = VAR_STRING;
6027 if (argvars[2].v_type != VAR_UNKNOWN)
6028 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006029 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030 flags |= WILD_KEEP_ALL;
6031 if (argvars[3].v_type != VAR_UNKNOWN)
6032 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006033 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006034 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006035 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006036 }
6037 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006038 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006039 flags |= WILD_ALLLINKS;
6040 }
6041 }
6042 if (file != NULL && !error)
6043 {
6044 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006045 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006046 if (rettv->v_type == VAR_STRING)
6047 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6048 else if (rettv_list_alloc(rettv) != FAIL)
6049 for (i = 0; i < ga.ga_len; ++i)
6050 list_append_string(rettv->vval.v_list,
6051 ((char_u **)(ga.ga_data))[i], -1);
6052 ga_clear_strings(&ga);
6053 }
6054 else
6055 rettv->vval.v_string = NULL;
6056}
6057
6058/*
6059 * "glob2regpat()" function
6060 */
6061 static void
6062f_glob2regpat(typval_T *argvars, typval_T *rettv)
6063{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006064 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065
6066 rettv->v_type = VAR_STRING;
6067 rettv->vval.v_string = (pat == NULL)
6068 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6069}
6070
6071/* for VIM_VERSION_ defines */
6072#include "version.h"
6073
6074/*
6075 * "has()" function
6076 */
6077 static void
6078f_has(typval_T *argvars, typval_T *rettv)
6079{
6080 int i;
6081 char_u *name;
6082 int n = FALSE;
6083 static char *(has_list[]) =
6084 {
6085#ifdef AMIGA
6086 "amiga",
6087# ifdef FEAT_ARP
6088 "arp",
6089# endif
6090#endif
6091#ifdef __BEOS__
6092 "beos",
6093#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006094#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006095 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6096 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006097# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006098 "macunix", /* Mac OS X, with the darwin feature */
6099 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006100# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006101#endif
6102#ifdef __QNX__
6103 "qnx",
6104#endif
6105#ifdef UNIX
6106 "unix",
6107#endif
6108#ifdef VMS
6109 "vms",
6110#endif
6111#ifdef WIN32
6112 "win32",
6113#endif
6114#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6115 "win32unix",
6116#endif
6117#if defined(WIN64) || defined(_WIN64)
6118 "win64",
6119#endif
6120#ifdef EBCDIC
6121 "ebcdic",
6122#endif
6123#ifndef CASE_INSENSITIVE_FILENAME
6124 "fname_case",
6125#endif
6126#ifdef HAVE_ACL
6127 "acl",
6128#endif
6129#ifdef FEAT_ARABIC
6130 "arabic",
6131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006132 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006133#ifdef FEAT_AUTOCHDIR
6134 "autochdir",
6135#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006136#ifdef FEAT_AUTOSERVERNAME
6137 "autoservername",
6138#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006139#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006140 "balloon_eval",
6141# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6142 "balloon_multiline",
6143# endif
6144#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006145#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006146 "balloon_eval_term",
6147#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006148#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6149 "builtin_terms",
6150# ifdef ALL_BUILTIN_TCAPS
6151 "all_builtin_terms",
6152# endif
6153#endif
6154#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6155 || defined(FEAT_GUI_W32) \
6156 || defined(FEAT_GUI_MOTIF))
6157 "browsefilter",
6158#endif
6159#ifdef FEAT_BYTEOFF
6160 "byte_offset",
6161#endif
6162#ifdef FEAT_JOB_CHANNEL
6163 "channel",
6164#endif
6165#ifdef FEAT_CINDENT
6166 "cindent",
6167#endif
6168#ifdef FEAT_CLIENTSERVER
6169 "clientserver",
6170#endif
6171#ifdef FEAT_CLIPBOARD
6172 "clipboard",
6173#endif
6174#ifdef FEAT_CMDL_COMPL
6175 "cmdline_compl",
6176#endif
6177#ifdef FEAT_CMDHIST
6178 "cmdline_hist",
6179#endif
6180#ifdef FEAT_COMMENTS
6181 "comments",
6182#endif
6183#ifdef FEAT_CONCEAL
6184 "conceal",
6185#endif
6186#ifdef FEAT_CRYPT
6187 "cryptv",
6188 "crypt-blowfish",
6189 "crypt-blowfish2",
6190#endif
6191#ifdef FEAT_CSCOPE
6192 "cscope",
6193#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195#ifdef CURSOR_SHAPE
6196 "cursorshape",
6197#endif
6198#ifdef DEBUG
6199 "debug",
6200#endif
6201#ifdef FEAT_CON_DIALOG
6202 "dialog_con",
6203#endif
6204#ifdef FEAT_GUI_DIALOG
6205 "dialog_gui",
6206#endif
6207#ifdef FEAT_DIFF
6208 "diff",
6209#endif
6210#ifdef FEAT_DIGRAPHS
6211 "digraphs",
6212#endif
6213#ifdef FEAT_DIRECTX
6214 "directx",
6215#endif
6216#ifdef FEAT_DND
6217 "dnd",
6218#endif
6219#ifdef FEAT_EMACS_TAGS
6220 "emacs_tags",
6221#endif
6222 "eval", /* always present, of course! */
6223 "ex_extra", /* graduated feature */
6224#ifdef FEAT_SEARCH_EXTRA
6225 "extra_search",
6226#endif
6227#ifdef FEAT_FKMAP
6228 "farsi",
6229#endif
6230#ifdef FEAT_SEARCHPATH
6231 "file_in_path",
6232#endif
6233#ifdef FEAT_FILTERPIPE
6234 "filterpipe",
6235#endif
6236#ifdef FEAT_FIND_ID
6237 "find_in_path",
6238#endif
6239#ifdef FEAT_FLOAT
6240 "float",
6241#endif
6242#ifdef FEAT_FOLDING
6243 "folding",
6244#endif
6245#ifdef FEAT_FOOTER
6246 "footer",
6247#endif
6248#if !defined(USE_SYSTEM) && defined(UNIX)
6249 "fork",
6250#endif
6251#ifdef FEAT_GETTEXT
6252 "gettext",
6253#endif
6254#ifdef FEAT_GUI
6255 "gui",
6256#endif
6257#ifdef FEAT_GUI_ATHENA
6258# ifdef FEAT_GUI_NEXTAW
6259 "gui_neXtaw",
6260# else
6261 "gui_athena",
6262# endif
6263#endif
6264#ifdef FEAT_GUI_GTK
6265 "gui_gtk",
6266# ifdef USE_GTK3
6267 "gui_gtk3",
6268# else
6269 "gui_gtk2",
6270# endif
6271#endif
6272#ifdef FEAT_GUI_GNOME
6273 "gui_gnome",
6274#endif
6275#ifdef FEAT_GUI_MAC
6276 "gui_mac",
6277#endif
6278#ifdef FEAT_GUI_MOTIF
6279 "gui_motif",
6280#endif
6281#ifdef FEAT_GUI_PHOTON
6282 "gui_photon",
6283#endif
6284#ifdef FEAT_GUI_W32
6285 "gui_win32",
6286#endif
6287#ifdef FEAT_HANGULIN
6288 "hangul_input",
6289#endif
6290#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6291 "iconv",
6292#endif
6293#ifdef FEAT_INS_EXPAND
6294 "insert_expand",
6295#endif
6296#ifdef FEAT_JOB_CHANNEL
6297 "job",
6298#endif
6299#ifdef FEAT_JUMPLIST
6300 "jumplist",
6301#endif
6302#ifdef FEAT_KEYMAP
6303 "keymap",
6304#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006305 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006306#ifdef FEAT_LANGMAP
6307 "langmap",
6308#endif
6309#ifdef FEAT_LIBCALL
6310 "libcall",
6311#endif
6312#ifdef FEAT_LINEBREAK
6313 "linebreak",
6314#endif
6315#ifdef FEAT_LISP
6316 "lispindent",
6317#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006319#ifdef FEAT_LOCALMAP
6320 "localmap",
6321#endif
6322#ifdef FEAT_LUA
6323# ifndef DYNAMIC_LUA
6324 "lua",
6325# endif
6326#endif
6327#ifdef FEAT_MENU
6328 "menu",
6329#endif
6330#ifdef FEAT_SESSION
6331 "mksession",
6332#endif
6333#ifdef FEAT_MODIFY_FNAME
6334 "modify_fname",
6335#endif
6336#ifdef FEAT_MOUSE
6337 "mouse",
6338#endif
6339#ifdef FEAT_MOUSESHAPE
6340 "mouseshape",
6341#endif
6342#if defined(UNIX) || defined(VMS)
6343# ifdef FEAT_MOUSE_DEC
6344 "mouse_dec",
6345# endif
6346# ifdef FEAT_MOUSE_GPM
6347 "mouse_gpm",
6348# endif
6349# ifdef FEAT_MOUSE_JSB
6350 "mouse_jsbterm",
6351# endif
6352# ifdef FEAT_MOUSE_NET
6353 "mouse_netterm",
6354# endif
6355# ifdef FEAT_MOUSE_PTERM
6356 "mouse_pterm",
6357# endif
6358# ifdef FEAT_MOUSE_SGR
6359 "mouse_sgr",
6360# endif
6361# ifdef FEAT_SYSMOUSE
6362 "mouse_sysmouse",
6363# endif
6364# ifdef FEAT_MOUSE_URXVT
6365 "mouse_urxvt",
6366# endif
6367# ifdef FEAT_MOUSE_XTERM
6368 "mouse_xterm",
6369# endif
6370#endif
6371#ifdef FEAT_MBYTE
6372 "multi_byte",
6373#endif
6374#ifdef FEAT_MBYTE_IME
6375 "multi_byte_ime",
6376#endif
6377#ifdef FEAT_MULTI_LANG
6378 "multi_lang",
6379#endif
6380#ifdef FEAT_MZSCHEME
6381#ifndef DYNAMIC_MZSCHEME
6382 "mzscheme",
6383#endif
6384#endif
6385#ifdef FEAT_NUM64
6386 "num64",
6387#endif
6388#ifdef FEAT_OLE
6389 "ole",
6390#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006391#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006393#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394#ifdef FEAT_PATH_EXTRA
6395 "path_extra",
6396#endif
6397#ifdef FEAT_PERL
6398#ifndef DYNAMIC_PERL
6399 "perl",
6400#endif
6401#endif
6402#ifdef FEAT_PERSISTENT_UNDO
6403 "persistent_undo",
6404#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006405#if defined(FEAT_PYTHON)
6406 "python_compiled",
6407# if defined(DYNAMIC_PYTHON)
6408 "python_dynamic",
6409# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006410 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006411 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006412# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006413#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006414#if defined(FEAT_PYTHON3)
6415 "python3_compiled",
6416# if defined(DYNAMIC_PYTHON3)
6417 "python3_dynamic",
6418# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006419 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006420 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006421# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422#endif
6423#ifdef FEAT_POSTSCRIPT
6424 "postscript",
6425#endif
6426#ifdef FEAT_PRINTER
6427 "printer",
6428#endif
6429#ifdef FEAT_PROFILE
6430 "profile",
6431#endif
6432#ifdef FEAT_RELTIME
6433 "reltime",
6434#endif
6435#ifdef FEAT_QUICKFIX
6436 "quickfix",
6437#endif
6438#ifdef FEAT_RIGHTLEFT
6439 "rightleft",
6440#endif
6441#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6442 "ruby",
6443#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006444 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445#ifdef FEAT_CMDL_INFO
6446 "showcmd",
6447 "cmdline_info",
6448#endif
6449#ifdef FEAT_SIGNS
6450 "signs",
6451#endif
6452#ifdef FEAT_SMARTINDENT
6453 "smartindent",
6454#endif
6455#ifdef STARTUPTIME
6456 "startuptime",
6457#endif
6458#ifdef FEAT_STL_OPT
6459 "statusline",
6460#endif
6461#ifdef FEAT_SUN_WORKSHOP
6462 "sun_workshop",
6463#endif
6464#ifdef FEAT_NETBEANS_INTG
6465 "netbeans_intg",
6466#endif
6467#ifdef FEAT_SPELL
6468 "spell",
6469#endif
6470#ifdef FEAT_SYN_HL
6471 "syntax",
6472#endif
6473#if defined(USE_SYSTEM) || !defined(UNIX)
6474 "system",
6475#endif
6476#ifdef FEAT_TAG_BINS
6477 "tag_binary",
6478#endif
6479#ifdef FEAT_TAG_OLDSTATIC
6480 "tag_old_static",
6481#endif
6482#ifdef FEAT_TAG_ANYWHITE
6483 "tag_any_white",
6484#endif
6485#ifdef FEAT_TCL
6486# ifndef DYNAMIC_TCL
6487 "tcl",
6488# endif
6489#endif
6490#ifdef FEAT_TERMGUICOLORS
6491 "termguicolors",
6492#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006493#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006494 "terminal",
6495#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496#ifdef TERMINFO
6497 "terminfo",
6498#endif
6499#ifdef FEAT_TERMRESPONSE
6500 "termresponse",
6501#endif
6502#ifdef FEAT_TEXTOBJ
6503 "textobjects",
6504#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006505#ifdef FEAT_TEXT_PROP
6506 "textprop",
6507#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508#ifdef HAVE_TGETENT
6509 "tgetent",
6510#endif
6511#ifdef FEAT_TIMERS
6512 "timers",
6513#endif
6514#ifdef FEAT_TITLE
6515 "title",
6516#endif
6517#ifdef FEAT_TOOLBAR
6518 "toolbar",
6519#endif
6520#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6521 "unnamedplus",
6522#endif
6523#ifdef FEAT_USR_CMDS
6524 "user-commands", /* was accidentally included in 5.4 */
6525 "user_commands",
6526#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006527#ifdef FEAT_VARTABS
6528 "vartabs",
6529#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006530#ifdef FEAT_VIMINFO
6531 "viminfo",
6532#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006533 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006534#ifdef FEAT_VIRTUALEDIT
6535 "virtualedit",
6536#endif
6537 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006540#ifdef FEAT_VTP
6541 "vtp",
6542#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006543#ifdef FEAT_WILDIGN
6544 "wildignore",
6545#endif
6546#ifdef FEAT_WILDMENU
6547 "wildmenu",
6548#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006549 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550#ifdef FEAT_WAK
6551 "winaltkeys",
6552#endif
6553#ifdef FEAT_WRITEBACKUP
6554 "writebackup",
6555#endif
6556#ifdef FEAT_XIM
6557 "xim",
6558#endif
6559#ifdef FEAT_XFONTSET
6560 "xfontset",
6561#endif
6562#ifdef FEAT_XPM_W32
6563 "xpm",
6564 "xpm_w32", /* for backward compatibility */
6565#else
6566# if defined(HAVE_XPM)
6567 "xpm",
6568# endif
6569#endif
6570#ifdef USE_XSMP
6571 "xsmp",
6572#endif
6573#ifdef USE_XSMP_INTERACT
6574 "xsmp_interact",
6575#endif
6576#ifdef FEAT_XCLIPBOARD
6577 "xterm_clipboard",
6578#endif
6579#ifdef FEAT_XTERM_SAVE
6580 "xterm_save",
6581#endif
6582#if defined(UNIX) && defined(FEAT_X11)
6583 "X11",
6584#endif
6585 NULL
6586 };
6587
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006588 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589 for (i = 0; has_list[i] != NULL; ++i)
6590 if (STRICMP(name, has_list[i]) == 0)
6591 {
6592 n = TRUE;
6593 break;
6594 }
6595
6596 if (n == FALSE)
6597 {
6598 if (STRNICMP(name, "patch", 5) == 0)
6599 {
6600 if (name[5] == '-'
6601 && STRLEN(name) >= 11
6602 && vim_isdigit(name[6])
6603 && vim_isdigit(name[8])
6604 && vim_isdigit(name[10]))
6605 {
6606 int major = atoi((char *)name + 6);
6607 int minor = atoi((char *)name + 8);
6608
6609 /* Expect "patch-9.9.01234". */
6610 n = (major < VIM_VERSION_MAJOR
6611 || (major == VIM_VERSION_MAJOR
6612 && (minor < VIM_VERSION_MINOR
6613 || (minor == VIM_VERSION_MINOR
6614 && has_patch(atoi((char *)name + 10))))));
6615 }
6616 else
6617 n = has_patch(atoi((char *)name + 5));
6618 }
6619 else if (STRICMP(name, "vim_starting") == 0)
6620 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006621 else if (STRICMP(name, "ttyin") == 0)
6622 n = mch_input_isatty();
6623 else if (STRICMP(name, "ttyout") == 0)
6624 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006625#ifdef FEAT_MBYTE
6626 else if (STRICMP(name, "multi_byte_encoding") == 0)
6627 n = has_mbyte;
6628#endif
6629#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6630 else if (STRICMP(name, "balloon_multiline") == 0)
6631 n = multiline_balloon_available();
6632#endif
6633#ifdef DYNAMIC_TCL
6634 else if (STRICMP(name, "tcl") == 0)
6635 n = tcl_enabled(FALSE);
6636#endif
6637#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6638 else if (STRICMP(name, "iconv") == 0)
6639 n = iconv_enabled(FALSE);
6640#endif
6641#ifdef DYNAMIC_LUA
6642 else if (STRICMP(name, "lua") == 0)
6643 n = lua_enabled(FALSE);
6644#endif
6645#ifdef DYNAMIC_MZSCHEME
6646 else if (STRICMP(name, "mzscheme") == 0)
6647 n = mzscheme_enabled(FALSE);
6648#endif
6649#ifdef DYNAMIC_RUBY
6650 else if (STRICMP(name, "ruby") == 0)
6651 n = ruby_enabled(FALSE);
6652#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006653#ifdef DYNAMIC_PYTHON
6654 else if (STRICMP(name, "python") == 0)
6655 n = python_enabled(FALSE);
6656#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657#ifdef DYNAMIC_PYTHON3
6658 else if (STRICMP(name, "python3") == 0)
6659 n = python3_enabled(FALSE);
6660#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006661#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6662 else if (STRICMP(name, "pythonx") == 0)
6663 {
6664# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6665 if (p_pyx == 0)
6666 n = python3_enabled(FALSE) || python_enabled(FALSE);
6667 else if (p_pyx == 3)
6668 n = python3_enabled(FALSE);
6669 else if (p_pyx == 2)
6670 n = python_enabled(FALSE);
6671# elif defined(DYNAMIC_PYTHON)
6672 n = python_enabled(FALSE);
6673# elif defined(DYNAMIC_PYTHON3)
6674 n = python3_enabled(FALSE);
6675# endif
6676 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006677#endif
6678#ifdef DYNAMIC_PERL
6679 else if (STRICMP(name, "perl") == 0)
6680 n = perl_enabled(FALSE);
6681#endif
6682#ifdef FEAT_GUI
6683 else if (STRICMP(name, "gui_running") == 0)
6684 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685# ifdef FEAT_BROWSE
6686 else if (STRICMP(name, "browse") == 0)
6687 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6688# endif
6689#endif
6690#ifdef FEAT_SYN_HL
6691 else if (STRICMP(name, "syntax_items") == 0)
6692 n = syntax_present(curwin);
6693#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006694#ifdef FEAT_VTP
6695 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006696 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006697#endif
6698#ifdef FEAT_NETBEANS_INTG
6699 else if (STRICMP(name, "netbeans_enabled") == 0)
6700 n = netbeans_active();
6701#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006702#if defined(FEAT_TERMINAL) && defined(WIN3264)
6703 else if (STRICMP(name, "terminal") == 0)
6704 n = terminal_enabled();
6705#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006706 }
6707
6708 rettv->vval.v_number = n;
6709}
6710
6711/*
6712 * "has_key()" function
6713 */
6714 static void
6715f_has_key(typval_T *argvars, typval_T *rettv)
6716{
6717 if (argvars[0].v_type != VAR_DICT)
6718 {
6719 EMSG(_(e_dictreq));
6720 return;
6721 }
6722 if (argvars[0].vval.v_dict == NULL)
6723 return;
6724
6725 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006726 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006727}
6728
6729/*
6730 * "haslocaldir()" function
6731 */
6732 static void
6733f_haslocaldir(typval_T *argvars, typval_T *rettv)
6734{
6735 win_T *wp = NULL;
6736
6737 wp = find_tabwin(&argvars[0], &argvars[1]);
6738 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6739}
6740
6741/*
6742 * "hasmapto()" function
6743 */
6744 static void
6745f_hasmapto(typval_T *argvars, typval_T *rettv)
6746{
6747 char_u *name;
6748 char_u *mode;
6749 char_u buf[NUMBUFLEN];
6750 int abbr = FALSE;
6751
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006752 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006753 if (argvars[1].v_type == VAR_UNKNOWN)
6754 mode = (char_u *)"nvo";
6755 else
6756 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006757 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006759 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006760 }
6761
6762 if (map_to_exists(name, mode, abbr))
6763 rettv->vval.v_number = TRUE;
6764 else
6765 rettv->vval.v_number = FALSE;
6766}
6767
6768/*
6769 * "histadd()" function
6770 */
6771 static void
6772f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6773{
6774#ifdef FEAT_CMDHIST
6775 int histype;
6776 char_u *str;
6777 char_u buf[NUMBUFLEN];
6778#endif
6779
6780 rettv->vval.v_number = FALSE;
6781 if (check_restricted() || check_secure())
6782 return;
6783#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006784 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006785 histype = str != NULL ? get_histtype(str) : -1;
6786 if (histype >= 0)
6787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006788 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006789 if (*str != NUL)
6790 {
6791 init_history();
6792 add_to_history(histype, str, FALSE, NUL);
6793 rettv->vval.v_number = TRUE;
6794 return;
6795 }
6796 }
6797#endif
6798}
6799
6800/*
6801 * "histdel()" function
6802 */
6803 static void
6804f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6805{
6806#ifdef FEAT_CMDHIST
6807 int n;
6808 char_u buf[NUMBUFLEN];
6809 char_u *str;
6810
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006811 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812 if (str == NULL)
6813 n = 0;
6814 else if (argvars[1].v_type == VAR_UNKNOWN)
6815 /* only one argument: clear entire history */
6816 n = clr_history(get_histtype(str));
6817 else if (argvars[1].v_type == VAR_NUMBER)
6818 /* index given: remove that entry */
6819 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006820 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006821 else
6822 /* string given: remove all matching entries */
6823 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006824 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006825 rettv->vval.v_number = n;
6826#endif
6827}
6828
6829/*
6830 * "histget()" function
6831 */
6832 static void
6833f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6834{
6835#ifdef FEAT_CMDHIST
6836 int type;
6837 int idx;
6838 char_u *str;
6839
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006840 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006841 if (str == NULL)
6842 rettv->vval.v_string = NULL;
6843 else
6844 {
6845 type = get_histtype(str);
6846 if (argvars[1].v_type == VAR_UNKNOWN)
6847 idx = get_history_idx(type);
6848 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006849 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850 /* -1 on type error */
6851 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6852 }
6853#else
6854 rettv->vval.v_string = NULL;
6855#endif
6856 rettv->v_type = VAR_STRING;
6857}
6858
6859/*
6860 * "histnr()" function
6861 */
6862 static void
6863f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6864{
6865 int i;
6866
6867#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006868 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869
6870 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6871 if (i >= HIST_CMD && i < HIST_COUNT)
6872 i = get_history_idx(i);
6873 else
6874#endif
6875 i = -1;
6876 rettv->vval.v_number = i;
6877}
6878
6879/*
6880 * "highlightID(name)" function
6881 */
6882 static void
6883f_hlID(typval_T *argvars, typval_T *rettv)
6884{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006885 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006886}
6887
6888/*
6889 * "highlight_exists()" function
6890 */
6891 static void
6892f_hlexists(typval_T *argvars, typval_T *rettv)
6893{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006894 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006895}
6896
6897/*
6898 * "hostname()" function
6899 */
6900 static void
6901f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6902{
6903 char_u hostname[256];
6904
6905 mch_get_host_name(hostname, 256);
6906 rettv->v_type = VAR_STRING;
6907 rettv->vval.v_string = vim_strsave(hostname);
6908}
6909
6910/*
6911 * iconv() function
6912 */
6913 static void
6914f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6915{
6916#ifdef FEAT_MBYTE
6917 char_u buf1[NUMBUFLEN];
6918 char_u buf2[NUMBUFLEN];
6919 char_u *from, *to, *str;
6920 vimconv_T vimconv;
6921#endif
6922
6923 rettv->v_type = VAR_STRING;
6924 rettv->vval.v_string = NULL;
6925
6926#ifdef FEAT_MBYTE
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006927 str = tv_get_string(&argvars[0]);
6928 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6929 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006930 vimconv.vc_type = CONV_NONE;
6931 convert_setup(&vimconv, from, to);
6932
6933 /* If the encodings are equal, no conversion needed. */
6934 if (vimconv.vc_type == CONV_NONE)
6935 rettv->vval.v_string = vim_strsave(str);
6936 else
6937 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6938
6939 convert_setup(&vimconv, NULL, NULL);
6940 vim_free(from);
6941 vim_free(to);
6942#endif
6943}
6944
6945/*
6946 * "indent()" function
6947 */
6948 static void
6949f_indent(typval_T *argvars, typval_T *rettv)
6950{
6951 linenr_T lnum;
6952
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006953 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6955 rettv->vval.v_number = get_indent_lnum(lnum);
6956 else
6957 rettv->vval.v_number = -1;
6958}
6959
6960/*
6961 * "index()" function
6962 */
6963 static void
6964f_index(typval_T *argvars, typval_T *rettv)
6965{
6966 list_T *l;
6967 listitem_T *item;
6968 long idx = 0;
6969 int ic = FALSE;
6970
6971 rettv->vval.v_number = -1;
6972 if (argvars[0].v_type != VAR_LIST)
6973 {
6974 EMSG(_(e_listreq));
6975 return;
6976 }
6977 l = argvars[0].vval.v_list;
6978 if (l != NULL)
6979 {
6980 item = l->lv_first;
6981 if (argvars[2].v_type != VAR_UNKNOWN)
6982 {
6983 int error = FALSE;
6984
6985 /* Start at specified item. Use the cached index that list_find()
6986 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006987 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006988 idx = l->lv_idx;
6989 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006990 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991 if (error)
6992 item = NULL;
6993 }
6994
6995 for ( ; item != NULL; item = item->li_next, ++idx)
6996 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6997 {
6998 rettv->vval.v_number = idx;
6999 break;
7000 }
7001 }
7002}
7003
7004static int inputsecret_flag = 0;
7005
7006/*
7007 * "input()" function
7008 * Also handles inputsecret() when inputsecret is set.
7009 */
7010 static void
7011f_input(typval_T *argvars, typval_T *rettv)
7012{
7013 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7014}
7015
7016/*
7017 * "inputdialog()" function
7018 */
7019 static void
7020f_inputdialog(typval_T *argvars, typval_T *rettv)
7021{
7022#if defined(FEAT_GUI_TEXTDIALOG)
7023 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7024 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7025 {
7026 char_u *message;
7027 char_u buf[NUMBUFLEN];
7028 char_u *defstr = (char_u *)"";
7029
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007030 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007031 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007032 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007033 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7034 else
7035 IObuff[0] = NUL;
7036 if (message != NULL && defstr != NULL
7037 && do_dialog(VIM_QUESTION, NULL, message,
7038 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7039 rettv->vval.v_string = vim_strsave(IObuff);
7040 else
7041 {
7042 if (message != NULL && defstr != NULL
7043 && argvars[1].v_type != VAR_UNKNOWN
7044 && argvars[2].v_type != VAR_UNKNOWN)
7045 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007046 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007047 else
7048 rettv->vval.v_string = NULL;
7049 }
7050 rettv->v_type = VAR_STRING;
7051 }
7052 else
7053#endif
7054 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7055}
7056
7057/*
7058 * "inputlist()" function
7059 */
7060 static void
7061f_inputlist(typval_T *argvars, typval_T *rettv)
7062{
7063 listitem_T *li;
7064 int selected;
7065 int mouse_used;
7066
7067#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007068 /* While starting up, there is no place to enter text. When running tests
7069 * with --not-a-term we assume feedkeys() will be used. */
7070 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 return;
7072#endif
7073 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7074 {
7075 EMSG2(_(e_listarg), "inputlist()");
7076 return;
7077 }
7078
7079 msg_start();
7080 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7081 lines_left = Rows; /* avoid more prompt */
7082 msg_scroll = TRUE;
7083 msg_clr_eos();
7084
7085 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7086 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007087 msg_puts(tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007088 msg_putchar('\n');
7089 }
7090
7091 /* Ask for choice. */
7092 selected = prompt_for_number(&mouse_used);
7093 if (mouse_used)
7094 selected -= lines_left;
7095
7096 rettv->vval.v_number = selected;
7097}
7098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007099static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7100
7101/*
7102 * "inputrestore()" function
7103 */
7104 static void
7105f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7106{
7107 if (ga_userinput.ga_len > 0)
7108 {
7109 --ga_userinput.ga_len;
7110 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7111 + ga_userinput.ga_len);
7112 /* default return is zero == OK */
7113 }
7114 else if (p_verbose > 1)
7115 {
7116 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
7117 rettv->vval.v_number = 1; /* Failed */
7118 }
7119}
7120
7121/*
7122 * "inputsave()" function
7123 */
7124 static void
7125f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7126{
7127 /* Add an entry to the stack of typeahead storage. */
7128 if (ga_grow(&ga_userinput, 1) == OK)
7129 {
7130 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7131 + ga_userinput.ga_len);
7132 ++ga_userinput.ga_len;
7133 /* default return is zero == OK */
7134 }
7135 else
7136 rettv->vval.v_number = 1; /* Failed */
7137}
7138
7139/*
7140 * "inputsecret()" function
7141 */
7142 static void
7143f_inputsecret(typval_T *argvars, typval_T *rettv)
7144{
7145 ++cmdline_star;
7146 ++inputsecret_flag;
7147 f_input(argvars, rettv);
7148 --cmdline_star;
7149 --inputsecret_flag;
7150}
7151
7152/*
7153 * "insert()" function
7154 */
7155 static void
7156f_insert(typval_T *argvars, typval_T *rettv)
7157{
7158 long before = 0;
7159 listitem_T *item;
7160 list_T *l;
7161 int error = FALSE;
7162
7163 if (argvars[0].v_type != VAR_LIST)
7164 EMSG2(_(e_listarg), "insert()");
7165 else if ((l = argvars[0].vval.v_list) != NULL
7166 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7167 {
7168 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007169 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007170 if (error)
7171 return; /* type error; errmsg already given */
7172
7173 if (before == l->lv_len)
7174 item = NULL;
7175 else
7176 {
7177 item = list_find(l, before);
7178 if (item == NULL)
7179 {
7180 EMSGN(_(e_listidx), before);
7181 l = NULL;
7182 }
7183 }
7184 if (l != NULL)
7185 {
7186 list_insert_tv(l, &argvars[1], item);
7187 copy_tv(&argvars[0], rettv);
7188 }
7189 }
7190}
7191
7192/*
7193 * "invert(expr)" function
7194 */
7195 static void
7196f_invert(typval_T *argvars, typval_T *rettv)
7197{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007198 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007199}
7200
7201/*
7202 * "isdirectory()" function
7203 */
7204 static void
7205f_isdirectory(typval_T *argvars, typval_T *rettv)
7206{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007207 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208}
7209
7210/*
7211 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7212 * or it refers to a List or Dictionary that is locked.
7213 */
7214 static int
7215tv_islocked(typval_T *tv)
7216{
7217 return (tv->v_lock & VAR_LOCKED)
7218 || (tv->v_type == VAR_LIST
7219 && tv->vval.v_list != NULL
7220 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7221 || (tv->v_type == VAR_DICT
7222 && tv->vval.v_dict != NULL
7223 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7224}
7225
7226/*
7227 * "islocked()" function
7228 */
7229 static void
7230f_islocked(typval_T *argvars, typval_T *rettv)
7231{
7232 lval_T lv;
7233 char_u *end;
7234 dictitem_T *di;
7235
7236 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007237 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007238 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007239 if (end != NULL && lv.ll_name != NULL)
7240 {
7241 if (*end != NUL)
7242 EMSG(_(e_trailing));
7243 else
7244 {
7245 if (lv.ll_tv == NULL)
7246 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007247 di = find_var(lv.ll_name, NULL, TRUE);
7248 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007249 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007250 /* Consider a variable locked when:
7251 * 1. the variable itself is locked
7252 * 2. the value of the variable is locked.
7253 * 3. the List or Dict value is locked.
7254 */
7255 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7256 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007257 }
7258 }
7259 else if (lv.ll_range)
7260 EMSG(_("E786: Range not allowed"));
7261 else if (lv.ll_newkey != NULL)
7262 EMSG2(_(e_dictkey), lv.ll_newkey);
7263 else if (lv.ll_list != NULL)
7264 /* List item. */
7265 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7266 else
7267 /* Dictionary item. */
7268 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7269 }
7270 }
7271
7272 clear_lval(&lv);
7273}
7274
7275#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7276/*
7277 * "isnan()" function
7278 */
7279 static void
7280f_isnan(typval_T *argvars, typval_T *rettv)
7281{
7282 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7283 && isnan(argvars[0].vval.v_float);
7284}
7285#endif
7286
7287/*
7288 * "items(dict)" function
7289 */
7290 static void
7291f_items(typval_T *argvars, typval_T *rettv)
7292{
7293 dict_list(argvars, rettv, 2);
7294}
7295
7296#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7297/*
7298 * Get the job from the argument.
7299 * Returns NULL if the job is invalid.
7300 */
7301 static job_T *
7302get_job_arg(typval_T *tv)
7303{
7304 job_T *job;
7305
7306 if (tv->v_type != VAR_JOB)
7307 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007308 EMSG2(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007309 return NULL;
7310 }
7311 job = tv->vval.v_job;
7312
7313 if (job == NULL)
7314 EMSG(_("E916: not a valid job"));
7315 return job;
7316}
7317
7318/*
7319 * "job_getchannel()" function
7320 */
7321 static void
7322f_job_getchannel(typval_T *argvars, typval_T *rettv)
7323{
7324 job_T *job = get_job_arg(&argvars[0]);
7325
7326 if (job != NULL)
7327 {
7328 rettv->v_type = VAR_CHANNEL;
7329 rettv->vval.v_channel = job->jv_channel;
7330 if (job->jv_channel != NULL)
7331 ++job->jv_channel->ch_refcount;
7332 }
7333}
7334
7335/*
7336 * "job_info()" function
7337 */
7338 static void
7339f_job_info(typval_T *argvars, typval_T *rettv)
7340{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007341 if (argvars[0].v_type != VAR_UNKNOWN)
7342 {
7343 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007345 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7346 job_info(job, rettv->vval.v_dict);
7347 }
7348 else if (rettv_list_alloc(rettv) == OK)
7349 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350}
7351
7352/*
7353 * "job_setoptions()" function
7354 */
7355 static void
7356f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7357{
7358 job_T *job = get_job_arg(&argvars[0]);
7359 jobopt_T opt;
7360
7361 if (job == NULL)
7362 return;
7363 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007364 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365 job_set_options(job, &opt);
7366 free_job_options(&opt);
7367}
7368
7369/*
7370 * "job_start()" function
7371 */
7372 static void
7373f_job_start(typval_T *argvars, typval_T *rettv)
7374{
7375 rettv->v_type = VAR_JOB;
7376 if (check_restricted() || check_secure())
7377 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007378 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007379}
7380
7381/*
7382 * "job_status()" function
7383 */
7384 static void
7385f_job_status(typval_T *argvars, typval_T *rettv)
7386{
7387 job_T *job = get_job_arg(&argvars[0]);
7388
7389 if (job != NULL)
7390 {
7391 rettv->v_type = VAR_STRING;
7392 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7393 }
7394}
7395
7396/*
7397 * "job_stop()" function
7398 */
7399 static void
7400f_job_stop(typval_T *argvars, typval_T *rettv)
7401{
7402 job_T *job = get_job_arg(&argvars[0]);
7403
7404 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007405 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007406}
7407#endif
7408
7409/*
7410 * "join()" function
7411 */
7412 static void
7413f_join(typval_T *argvars, typval_T *rettv)
7414{
7415 garray_T ga;
7416 char_u *sep;
7417
7418 if (argvars[0].v_type != VAR_LIST)
7419 {
7420 EMSG(_(e_listreq));
7421 return;
7422 }
7423 if (argvars[0].vval.v_list == NULL)
7424 return;
7425 if (argvars[1].v_type == VAR_UNKNOWN)
7426 sep = (char_u *)" ";
7427 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007428 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007429
7430 rettv->v_type = VAR_STRING;
7431
7432 if (sep != NULL)
7433 {
7434 ga_init2(&ga, (int)sizeof(char), 80);
7435 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7436 ga_append(&ga, NUL);
7437 rettv->vval.v_string = (char_u *)ga.ga_data;
7438 }
7439 else
7440 rettv->vval.v_string = NULL;
7441}
7442
7443/*
7444 * "js_decode()" function
7445 */
7446 static void
7447f_js_decode(typval_T *argvars, typval_T *rettv)
7448{
7449 js_read_T reader;
7450
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007451 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007452 reader.js_fill = NULL;
7453 reader.js_used = 0;
7454 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7455 EMSG(_(e_invarg));
7456}
7457
7458/*
7459 * "js_encode()" function
7460 */
7461 static void
7462f_js_encode(typval_T *argvars, typval_T *rettv)
7463{
7464 rettv->v_type = VAR_STRING;
7465 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7466}
7467
7468/*
7469 * "json_decode()" function
7470 */
7471 static void
7472f_json_decode(typval_T *argvars, typval_T *rettv)
7473{
7474 js_read_T reader;
7475
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007476 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007477 reader.js_fill = NULL;
7478 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007479 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007480}
7481
7482/*
7483 * "json_encode()" function
7484 */
7485 static void
7486f_json_encode(typval_T *argvars, typval_T *rettv)
7487{
7488 rettv->v_type = VAR_STRING;
7489 rettv->vval.v_string = json_encode(&argvars[0], 0);
7490}
7491
7492/*
7493 * "keys()" function
7494 */
7495 static void
7496f_keys(typval_T *argvars, typval_T *rettv)
7497{
7498 dict_list(argvars, rettv, 0);
7499}
7500
7501/*
7502 * "last_buffer_nr()" function.
7503 */
7504 static void
7505f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7506{
7507 int n = 0;
7508 buf_T *buf;
7509
Bram Moolenaar29323592016-07-24 22:04:11 +02007510 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511 if (n < buf->b_fnum)
7512 n = buf->b_fnum;
7513
7514 rettv->vval.v_number = n;
7515}
7516
7517/*
7518 * "len()" function
7519 */
7520 static void
7521f_len(typval_T *argvars, typval_T *rettv)
7522{
7523 switch (argvars[0].v_type)
7524 {
7525 case VAR_STRING:
7526 case VAR_NUMBER:
7527 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007528 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 break;
7530 case VAR_LIST:
7531 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7532 break;
7533 case VAR_DICT:
7534 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7535 break;
7536 case VAR_UNKNOWN:
7537 case VAR_SPECIAL:
7538 case VAR_FLOAT:
7539 case VAR_FUNC:
7540 case VAR_PARTIAL:
7541 case VAR_JOB:
7542 case VAR_CHANNEL:
7543 EMSG(_("E701: Invalid type for len()"));
7544 break;
7545 }
7546}
7547
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007548 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007549libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007550{
7551#ifdef FEAT_LIBCALL
7552 char_u *string_in;
7553 char_u **string_result;
7554 int nr_result;
7555#endif
7556
7557 rettv->v_type = type;
7558 if (type != VAR_NUMBER)
7559 rettv->vval.v_string = NULL;
7560
7561 if (check_restricted() || check_secure())
7562 return;
7563
7564#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007565 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007566 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7567 {
7568 string_in = NULL;
7569 if (argvars[2].v_type == VAR_STRING)
7570 string_in = argvars[2].vval.v_string;
7571 if (type == VAR_NUMBER)
7572 string_result = NULL;
7573 else
7574 string_result = &rettv->vval.v_string;
7575 if (mch_libcall(argvars[0].vval.v_string,
7576 argvars[1].vval.v_string,
7577 string_in,
7578 argvars[2].vval.v_number,
7579 string_result,
7580 &nr_result) == OK
7581 && type == VAR_NUMBER)
7582 rettv->vval.v_number = nr_result;
7583 }
7584#endif
7585}
7586
7587/*
7588 * "libcall()" function
7589 */
7590 static void
7591f_libcall(typval_T *argvars, typval_T *rettv)
7592{
7593 libcall_common(argvars, rettv, VAR_STRING);
7594}
7595
7596/*
7597 * "libcallnr()" function
7598 */
7599 static void
7600f_libcallnr(typval_T *argvars, typval_T *rettv)
7601{
7602 libcall_common(argvars, rettv, VAR_NUMBER);
7603}
7604
7605/*
7606 * "line(string)" function
7607 */
7608 static void
7609f_line(typval_T *argvars, typval_T *rettv)
7610{
7611 linenr_T lnum = 0;
7612 pos_T *fp;
7613 int fnum;
7614
7615 fp = var2fpos(&argvars[0], TRUE, &fnum);
7616 if (fp != NULL)
7617 lnum = fp->lnum;
7618 rettv->vval.v_number = lnum;
7619}
7620
7621/*
7622 * "line2byte(lnum)" function
7623 */
7624 static void
7625f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7626{
7627#ifndef FEAT_BYTEOFF
7628 rettv->vval.v_number = -1;
7629#else
7630 linenr_T lnum;
7631
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007632 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7634 rettv->vval.v_number = -1;
7635 else
7636 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7637 if (rettv->vval.v_number >= 0)
7638 ++rettv->vval.v_number;
7639#endif
7640}
7641
7642/*
7643 * "lispindent(lnum)" function
7644 */
7645 static void
7646f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7647{
7648#ifdef FEAT_LISP
7649 pos_T pos;
7650 linenr_T lnum;
7651
7652 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007653 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007654 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7655 {
7656 curwin->w_cursor.lnum = lnum;
7657 rettv->vval.v_number = get_lisp_indent();
7658 curwin->w_cursor = pos;
7659 }
7660 else
7661#endif
7662 rettv->vval.v_number = -1;
7663}
7664
7665/*
7666 * "localtime()" function
7667 */
7668 static void
7669f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7670{
7671 rettv->vval.v_number = (varnumber_T)time(NULL);
7672}
7673
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007674 static void
7675get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7676{
7677 char_u *keys;
7678 char_u *which;
7679 char_u buf[NUMBUFLEN];
7680 char_u *keys_buf = NULL;
7681 char_u *rhs;
7682 int mode;
7683 int abbr = FALSE;
7684 int get_dict = FALSE;
7685 mapblock_T *mp;
7686 int buffer_local;
7687
7688 /* return empty string for failure */
7689 rettv->v_type = VAR_STRING;
7690 rettv->vval.v_string = NULL;
7691
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007692 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007693 if (*keys == NUL)
7694 return;
7695
7696 if (argvars[1].v_type != VAR_UNKNOWN)
7697 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007698 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007699 if (argvars[2].v_type != VAR_UNKNOWN)
7700 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007701 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007702 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007703 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007704 }
7705 }
7706 else
7707 which = (char_u *)"";
7708 if (which == NULL)
7709 return;
7710
7711 mode = get_map_mode(&which, 0);
7712
7713 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7714 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7715 vim_free(keys_buf);
7716
7717 if (!get_dict)
7718 {
7719 /* Return a string. */
7720 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007721 {
7722 if (*rhs == NUL)
7723 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7724 else
7725 rettv->vval.v_string = str2special_save(rhs, FALSE);
7726 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727
7728 }
7729 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7730 {
7731 /* Return a dictionary. */
7732 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7733 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7734 dict_T *dict = rettv->vval.v_dict;
7735
Bram Moolenaare0be1672018-07-08 16:50:37 +02007736 dict_add_string(dict, "lhs", lhs);
7737 dict_add_string(dict, "rhs", mp->m_orig_str);
7738 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7739 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7740 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007741 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7742 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007743 dict_add_number(dict, "buffer", (long)buffer_local);
7744 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7745 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746
7747 vim_free(lhs);
7748 vim_free(mapmode);
7749 }
7750}
7751
7752#ifdef FEAT_FLOAT
7753/*
7754 * "log()" function
7755 */
7756 static void
7757f_log(typval_T *argvars, typval_T *rettv)
7758{
7759 float_T f = 0.0;
7760
7761 rettv->v_type = VAR_FLOAT;
7762 if (get_float_arg(argvars, &f) == OK)
7763 rettv->vval.v_float = log(f);
7764 else
7765 rettv->vval.v_float = 0.0;
7766}
7767
7768/*
7769 * "log10()" function
7770 */
7771 static void
7772f_log10(typval_T *argvars, typval_T *rettv)
7773{
7774 float_T f = 0.0;
7775
7776 rettv->v_type = VAR_FLOAT;
7777 if (get_float_arg(argvars, &f) == OK)
7778 rettv->vval.v_float = log10(f);
7779 else
7780 rettv->vval.v_float = 0.0;
7781}
7782#endif
7783
7784#ifdef FEAT_LUA
7785/*
7786 * "luaeval()" function
7787 */
7788 static void
7789f_luaeval(typval_T *argvars, typval_T *rettv)
7790{
7791 char_u *str;
7792 char_u buf[NUMBUFLEN];
7793
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007794 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795 do_luaeval(str, argvars + 1, rettv);
7796}
7797#endif
7798
7799/*
7800 * "map()" function
7801 */
7802 static void
7803f_map(typval_T *argvars, typval_T *rettv)
7804{
7805 filter_map(argvars, rettv, TRUE);
7806}
7807
7808/*
7809 * "maparg()" function
7810 */
7811 static void
7812f_maparg(typval_T *argvars, typval_T *rettv)
7813{
7814 get_maparg(argvars, rettv, TRUE);
7815}
7816
7817/*
7818 * "mapcheck()" function
7819 */
7820 static void
7821f_mapcheck(typval_T *argvars, typval_T *rettv)
7822{
7823 get_maparg(argvars, rettv, FALSE);
7824}
7825
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007826typedef enum
7827{
7828 MATCH_END, /* matchend() */
7829 MATCH_MATCH, /* match() */
7830 MATCH_STR, /* matchstr() */
7831 MATCH_LIST, /* matchlist() */
7832 MATCH_POS /* matchstrpos() */
7833} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007834
7835 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007836find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007837{
7838 char_u *str = NULL;
7839 long len = 0;
7840 char_u *expr = NULL;
7841 char_u *pat;
7842 regmatch_T regmatch;
7843 char_u patbuf[NUMBUFLEN];
7844 char_u strbuf[NUMBUFLEN];
7845 char_u *save_cpo;
7846 long start = 0;
7847 long nth = 1;
7848 colnr_T startcol = 0;
7849 int match = 0;
7850 list_T *l = NULL;
7851 listitem_T *li = NULL;
7852 long idx = 0;
7853 char_u *tofree = NULL;
7854
7855 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7856 save_cpo = p_cpo;
7857 p_cpo = (char_u *)"";
7858
7859 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007860 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007862 /* type MATCH_LIST: return empty list when there are no matches.
7863 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007864 if (rettv_list_alloc(rettv) == FAIL)
7865 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007866 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867 && (list_append_string(rettv->vval.v_list,
7868 (char_u *)"", 0) == 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 || list_append_number(rettv->vval.v_list,
7874 (varnumber_T)-1) == FAIL))
7875 {
7876 list_free(rettv->vval.v_list);
7877 rettv->vval.v_list = NULL;
7878 goto theend;
7879 }
7880 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007881 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882 {
7883 rettv->v_type = VAR_STRING;
7884 rettv->vval.v_string = NULL;
7885 }
7886
7887 if (argvars[0].v_type == VAR_LIST)
7888 {
7889 if ((l = argvars[0].vval.v_list) == NULL)
7890 goto theend;
7891 li = l->lv_first;
7892 }
7893 else
7894 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007895 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007896 len = (long)STRLEN(str);
7897 }
7898
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007899 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900 if (pat == NULL)
7901 goto theend;
7902
7903 if (argvars[2].v_type != VAR_UNKNOWN)
7904 {
7905 int error = FALSE;
7906
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007907 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908 if (error)
7909 goto theend;
7910 if (l != NULL)
7911 {
7912 li = list_find(l, start);
7913 if (li == NULL)
7914 goto theend;
7915 idx = l->lv_idx; /* use the cached index */
7916 }
7917 else
7918 {
7919 if (start < 0)
7920 start = 0;
7921 if (start > len)
7922 goto theend;
7923 /* When "count" argument is there ignore matches before "start",
7924 * otherwise skip part of the string. Differs when pattern is "^"
7925 * or "\<". */
7926 if (argvars[3].v_type != VAR_UNKNOWN)
7927 startcol = start;
7928 else
7929 {
7930 str += start;
7931 len -= start;
7932 }
7933 }
7934
7935 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007936 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 if (error)
7938 goto theend;
7939 }
7940
7941 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7942 if (regmatch.regprog != NULL)
7943 {
7944 regmatch.rm_ic = p_ic;
7945
7946 for (;;)
7947 {
7948 if (l != NULL)
7949 {
7950 if (li == NULL)
7951 {
7952 match = FALSE;
7953 break;
7954 }
7955 vim_free(tofree);
7956 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7957 if (str == NULL)
7958 break;
7959 }
7960
7961 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7962
7963 if (match && --nth <= 0)
7964 break;
7965 if (l == NULL && !match)
7966 break;
7967
7968 /* Advance to just after the match. */
7969 if (l != NULL)
7970 {
7971 li = li->li_next;
7972 ++idx;
7973 }
7974 else
7975 {
7976#ifdef FEAT_MBYTE
7977 startcol = (colnr_T)(regmatch.startp[0]
7978 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7979#else
7980 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7981#endif
7982 if (startcol > (colnr_T)len
7983 || str + startcol <= regmatch.startp[0])
7984 {
7985 match = FALSE;
7986 break;
7987 }
7988 }
7989 }
7990
7991 if (match)
7992 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007993 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007994 {
7995 listitem_T *li1 = rettv->vval.v_list->lv_first;
7996 listitem_T *li2 = li1->li_next;
7997 listitem_T *li3 = li2->li_next;
7998 listitem_T *li4 = li3->li_next;
7999
8000 vim_free(li1->li_tv.vval.v_string);
8001 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8002 (int)(regmatch.endp[0] - regmatch.startp[0]));
8003 li3->li_tv.vval.v_number =
8004 (varnumber_T)(regmatch.startp[0] - expr);
8005 li4->li_tv.vval.v_number =
8006 (varnumber_T)(regmatch.endp[0] - expr);
8007 if (l != NULL)
8008 li2->li_tv.vval.v_number = (varnumber_T)idx;
8009 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008010 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011 {
8012 int i;
8013
8014 /* return list with matched string and submatches */
8015 for (i = 0; i < NSUBEXP; ++i)
8016 {
8017 if (regmatch.endp[i] == NULL)
8018 {
8019 if (list_append_string(rettv->vval.v_list,
8020 (char_u *)"", 0) == FAIL)
8021 break;
8022 }
8023 else if (list_append_string(rettv->vval.v_list,
8024 regmatch.startp[i],
8025 (int)(regmatch.endp[i] - regmatch.startp[i]))
8026 == FAIL)
8027 break;
8028 }
8029 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008030 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008031 {
8032 /* return matched string */
8033 if (l != NULL)
8034 copy_tv(&li->li_tv, rettv);
8035 else
8036 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8037 (int)(regmatch.endp[0] - regmatch.startp[0]));
8038 }
8039 else if (l != NULL)
8040 rettv->vval.v_number = idx;
8041 else
8042 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008043 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008044 rettv->vval.v_number =
8045 (varnumber_T)(regmatch.startp[0] - str);
8046 else
8047 rettv->vval.v_number =
8048 (varnumber_T)(regmatch.endp[0] - str);
8049 rettv->vval.v_number += (varnumber_T)(str - expr);
8050 }
8051 }
8052 vim_regfree(regmatch.regprog);
8053 }
8054
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008055theend:
8056 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008057 /* matchstrpos() without a list: drop the second item. */
8058 listitem_remove(rettv->vval.v_list,
8059 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008060 vim_free(tofree);
8061 p_cpo = save_cpo;
8062}
8063
8064/*
8065 * "match()" function
8066 */
8067 static void
8068f_match(typval_T *argvars, typval_T *rettv)
8069{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008070 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008071}
8072
Bram Moolenaar95e51472018-07-28 16:55:56 +02008073#ifdef FEAT_SEARCH_EXTRA
8074 static int
8075matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8076{
8077 dictitem_T *di;
8078
8079 if (tv->v_type != VAR_DICT)
8080 {
8081 EMSG(_(e_dictreq));
8082 return FAIL;
8083 }
8084
8085 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008086 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008087 (char_u *)"conceal", FALSE);
8088
8089 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8090 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008091 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008092 if (*win == NULL)
8093 {
8094 EMSG(_("E957: Invalid window number"));
8095 return FAIL;
8096 }
8097 }
8098
8099 return OK;
8100}
8101#endif
8102
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008103/*
8104 * "matchadd()" function
8105 */
8106 static void
8107f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8108{
8109#ifdef FEAT_SEARCH_EXTRA
8110 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008111 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8112 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008113 int prio = 10; /* default priority */
8114 int id = -1;
8115 int error = FALSE;
8116 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008117 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118
8119 rettv->vval.v_number = -1;
8120
8121 if (grp == NULL || pat == NULL)
8122 return;
8123 if (argvars[2].v_type != VAR_UNKNOWN)
8124 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008125 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008126 if (argvars[3].v_type != VAR_UNKNOWN)
8127 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008128 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008129 if (argvars[4].v_type != VAR_UNKNOWN
8130 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8131 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008132 }
8133 }
8134 if (error == TRUE)
8135 return;
8136 if (id >= 1 && id <= 3)
8137 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008138 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008139 return;
8140 }
8141
Bram Moolenaar95e51472018-07-28 16:55:56 +02008142 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008143 conceal_char);
8144#endif
8145}
8146
8147/*
8148 * "matchaddpos()" function
8149 */
8150 static void
8151f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8152{
8153#ifdef FEAT_SEARCH_EXTRA
8154 char_u buf[NUMBUFLEN];
8155 char_u *group;
8156 int prio = 10;
8157 int id = -1;
8158 int error = FALSE;
8159 list_T *l;
8160 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008161 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008162
8163 rettv->vval.v_number = -1;
8164
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008165 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008166 if (group == NULL)
8167 return;
8168
8169 if (argvars[1].v_type != VAR_LIST)
8170 {
8171 EMSG2(_(e_listarg), "matchaddpos()");
8172 return;
8173 }
8174 l = argvars[1].vval.v_list;
8175 if (l == NULL)
8176 return;
8177
8178 if (argvars[2].v_type != VAR_UNKNOWN)
8179 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008180 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008181 if (argvars[3].v_type != VAR_UNKNOWN)
8182 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008183 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008184
8185 if (argvars[4].v_type != VAR_UNKNOWN
8186 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8187 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 }
8189 }
8190 if (error == TRUE)
8191 return;
8192
8193 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8194 if (id == 1 || id == 2)
8195 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008196 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008197 return;
8198 }
8199
Bram Moolenaar95e51472018-07-28 16:55:56 +02008200 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201 conceal_char);
8202#endif
8203}
8204
8205/*
8206 * "matcharg()" function
8207 */
8208 static void
8209f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8210{
8211 if (rettv_list_alloc(rettv) == OK)
8212 {
8213#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008214 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008215 matchitem_T *m;
8216
8217 if (id >= 1 && id <= 3)
8218 {
8219 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8220 {
8221 list_append_string(rettv->vval.v_list,
8222 syn_id2name(m->hlg_id), -1);
8223 list_append_string(rettv->vval.v_list, m->pattern, -1);
8224 }
8225 else
8226 {
8227 list_append_string(rettv->vval.v_list, NULL, -1);
8228 list_append_string(rettv->vval.v_list, NULL, -1);
8229 }
8230 }
8231#endif
8232 }
8233}
8234
8235/*
8236 * "matchdelete()" function
8237 */
8238 static void
8239f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8240{
8241#ifdef FEAT_SEARCH_EXTRA
8242 rettv->vval.v_number = match_delete(curwin,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008243 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008244#endif
8245}
8246
8247/*
8248 * "matchend()" function
8249 */
8250 static void
8251f_matchend(typval_T *argvars, typval_T *rettv)
8252{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008253 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008254}
8255
8256/*
8257 * "matchlist()" function
8258 */
8259 static void
8260f_matchlist(typval_T *argvars, typval_T *rettv)
8261{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008262 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008263}
8264
8265/*
8266 * "matchstr()" function
8267 */
8268 static void
8269f_matchstr(typval_T *argvars, typval_T *rettv)
8270{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008271 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008272}
8273
8274/*
8275 * "matchstrpos()" function
8276 */
8277 static void
8278f_matchstrpos(typval_T *argvars, typval_T *rettv)
8279{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008280 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281}
8282
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283 static void
8284max_min(typval_T *argvars, typval_T *rettv, int domax)
8285{
8286 varnumber_T n = 0;
8287 varnumber_T i;
8288 int error = FALSE;
8289
8290 if (argvars[0].v_type == VAR_LIST)
8291 {
8292 list_T *l;
8293 listitem_T *li;
8294
8295 l = argvars[0].vval.v_list;
8296 if (l != NULL)
8297 {
8298 li = l->lv_first;
8299 if (li != NULL)
8300 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008301 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302 for (;;)
8303 {
8304 li = li->li_next;
8305 if (li == NULL)
8306 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008307 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308 if (domax ? i > n : i < n)
8309 n = i;
8310 }
8311 }
8312 }
8313 }
8314 else if (argvars[0].v_type == VAR_DICT)
8315 {
8316 dict_T *d;
8317 int first = TRUE;
8318 hashitem_T *hi;
8319 int todo;
8320
8321 d = argvars[0].vval.v_dict;
8322 if (d != NULL)
8323 {
8324 todo = (int)d->dv_hashtab.ht_used;
8325 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8326 {
8327 if (!HASHITEM_EMPTY(hi))
8328 {
8329 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008330 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008331 if (first)
8332 {
8333 n = i;
8334 first = FALSE;
8335 }
8336 else if (domax ? i > n : i < n)
8337 n = i;
8338 }
8339 }
8340 }
8341 }
8342 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008343 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008344 rettv->vval.v_number = error ? 0 : n;
8345}
8346
8347/*
8348 * "max()" function
8349 */
8350 static void
8351f_max(typval_T *argvars, typval_T *rettv)
8352{
8353 max_min(argvars, rettv, TRUE);
8354}
8355
8356/*
8357 * "min()" function
8358 */
8359 static void
8360f_min(typval_T *argvars, typval_T *rettv)
8361{
8362 max_min(argvars, rettv, FALSE);
8363}
8364
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008365/*
8366 * Create the directory in which "dir" is located, and higher levels when
8367 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008368 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 */
8370 static int
8371mkdir_recurse(char_u *dir, int prot)
8372{
8373 char_u *p;
8374 char_u *updir;
8375 int r = FAIL;
8376
8377 /* Get end of directory name in "dir".
8378 * We're done when it's "/" or "c:/". */
8379 p = gettail_sep(dir);
8380 if (p <= get_past_head(dir))
8381 return OK;
8382
8383 /* If the directory exists we're done. Otherwise: create it.*/
8384 updir = vim_strnsave(dir, (int)(p - dir));
8385 if (updir == NULL)
8386 return FAIL;
8387 if (mch_isdir(updir))
8388 r = OK;
8389 else if (mkdir_recurse(updir, prot) == OK)
8390 r = vim_mkdir_emsg(updir, prot);
8391 vim_free(updir);
8392 return r;
8393}
8394
8395#ifdef vim_mkdir
8396/*
8397 * "mkdir()" function
8398 */
8399 static void
8400f_mkdir(typval_T *argvars, typval_T *rettv)
8401{
8402 char_u *dir;
8403 char_u buf[NUMBUFLEN];
8404 int prot = 0755;
8405
8406 rettv->vval.v_number = FAIL;
8407 if (check_restricted() || check_secure())
8408 return;
8409
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008410 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008411 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008412 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008413
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008414 if (*gettail(dir) == NUL)
8415 /* remove trailing slashes */
8416 *gettail_sep(dir) = NUL;
8417
8418 if (argvars[1].v_type != VAR_UNKNOWN)
8419 {
8420 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008421 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008422 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008423 if (prot == -1)
8424 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008425 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008426 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008427 {
8428 if (mch_isdir(dir))
8429 {
8430 /* With the "p" flag it's OK if the dir already exists. */
8431 rettv->vval.v_number = OK;
8432 return;
8433 }
8434 mkdir_recurse(dir, prot);
8435 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008436 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008437 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008438}
8439#endif
8440
8441/*
8442 * "mode()" function
8443 */
8444 static void
8445f_mode(typval_T *argvars, typval_T *rettv)
8446{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008447 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448
Bram Moolenaar612cc382018-07-29 15:34:26 +02008449 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008450
8451 if (time_for_testing == 93784)
8452 {
8453 /* Testing the two-character code. */
8454 buf[0] = 'x';
8455 buf[1] = '!';
8456 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008457#ifdef FEAT_TERMINAL
8458 else if (term_use_loop())
8459 buf[0] = 't';
8460#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008461 else if (VIsual_active)
8462 {
8463 if (VIsual_select)
8464 buf[0] = VIsual_mode + 's' - 'v';
8465 else
8466 buf[0] = VIsual_mode;
8467 }
8468 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8469 || State == CONFIRM)
8470 {
8471 buf[0] = 'r';
8472 if (State == ASKMORE)
8473 buf[1] = 'm';
8474 else if (State == CONFIRM)
8475 buf[1] = '?';
8476 }
8477 else if (State == EXTERNCMD)
8478 buf[0] = '!';
8479 else if (State & INSERT)
8480 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008481 if (State & VREPLACE_FLAG)
8482 {
8483 buf[0] = 'R';
8484 buf[1] = 'v';
8485 }
8486 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008487 {
8488 if (State & REPLACE_FLAG)
8489 buf[0] = 'R';
8490 else
8491 buf[0] = 'i';
8492#ifdef FEAT_INS_EXPAND
8493 if (ins_compl_active())
8494 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008495 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008496 buf[1] = 'x';
8497#endif
8498 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008499 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008500 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008501 {
8502 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008503 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008504 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008505 else if (exmode_active == EXMODE_NORMAL)
8506 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008507 }
8508 else
8509 {
8510 buf[0] = 'n';
8511 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008512 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008513 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008514 // to be able to detect force-linewise/blockwise/characterwise operations
8515 buf[2] = motion_force;
8516 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008517 else if (restart_edit == 'I' || restart_edit == 'R'
8518 || restart_edit == 'V')
8519 {
8520 buf[1] = 'i';
8521 buf[2] = restart_edit;
8522 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008523 }
8524
8525 /* Clear out the minor mode when the argument is not a non-zero number or
8526 * non-empty string. */
8527 if (!non_zero_arg(&argvars[0]))
8528 buf[1] = NUL;
8529
8530 rettv->vval.v_string = vim_strsave(buf);
8531 rettv->v_type = VAR_STRING;
8532}
8533
8534#if defined(FEAT_MZSCHEME) || defined(PROTO)
8535/*
8536 * "mzeval()" function
8537 */
8538 static void
8539f_mzeval(typval_T *argvars, typval_T *rettv)
8540{
8541 char_u *str;
8542 char_u buf[NUMBUFLEN];
8543
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008544 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008545 do_mzeval(str, rettv);
8546}
8547
8548 void
8549mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8550{
8551 typval_T argvars[3];
8552
8553 argvars[0].v_type = VAR_STRING;
8554 argvars[0].vval.v_string = name;
8555 copy_tv(args, &argvars[1]);
8556 argvars[2].v_type = VAR_UNKNOWN;
8557 f_call(argvars, rettv);
8558 clear_tv(&argvars[1]);
8559}
8560#endif
8561
8562/*
8563 * "nextnonblank()" function
8564 */
8565 static void
8566f_nextnonblank(typval_T *argvars, typval_T *rettv)
8567{
8568 linenr_T lnum;
8569
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008570 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008571 {
8572 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8573 {
8574 lnum = 0;
8575 break;
8576 }
8577 if (*skipwhite(ml_get(lnum)) != NUL)
8578 break;
8579 }
8580 rettv->vval.v_number = lnum;
8581}
8582
8583/*
8584 * "nr2char()" function
8585 */
8586 static void
8587f_nr2char(typval_T *argvars, typval_T *rettv)
8588{
8589 char_u buf[NUMBUFLEN];
8590
8591#ifdef FEAT_MBYTE
8592 if (has_mbyte)
8593 {
8594 int utf8 = 0;
8595
8596 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008597 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008598 if (utf8)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008599 buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008600 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008601 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008602 }
8603 else
8604#endif
8605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008606 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 buf[1] = NUL;
8608 }
8609 rettv->v_type = VAR_STRING;
8610 rettv->vval.v_string = vim_strsave(buf);
8611}
8612
8613/*
8614 * "or(expr, expr)" function
8615 */
8616 static void
8617f_or(typval_T *argvars, typval_T *rettv)
8618{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008619 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8620 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008621}
8622
8623/*
8624 * "pathshorten()" function
8625 */
8626 static void
8627f_pathshorten(typval_T *argvars, typval_T *rettv)
8628{
8629 char_u *p;
8630
8631 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008632 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008633 if (p == NULL)
8634 rettv->vval.v_string = NULL;
8635 else
8636 {
8637 p = vim_strsave(p);
8638 rettv->vval.v_string = p;
8639 if (p != NULL)
8640 shorten_dir(p);
8641 }
8642}
8643
8644#ifdef FEAT_PERL
8645/*
8646 * "perleval()" function
8647 */
8648 static void
8649f_perleval(typval_T *argvars, typval_T *rettv)
8650{
8651 char_u *str;
8652 char_u buf[NUMBUFLEN];
8653
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008654 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008655 do_perleval(str, rettv);
8656}
8657#endif
8658
8659#ifdef FEAT_FLOAT
8660/*
8661 * "pow()" function
8662 */
8663 static void
8664f_pow(typval_T *argvars, typval_T *rettv)
8665{
8666 float_T fx = 0.0, fy = 0.0;
8667
8668 rettv->v_type = VAR_FLOAT;
8669 if (get_float_arg(argvars, &fx) == OK
8670 && get_float_arg(&argvars[1], &fy) == OK)
8671 rettv->vval.v_float = pow(fx, fy);
8672 else
8673 rettv->vval.v_float = 0.0;
8674}
8675#endif
8676
8677/*
8678 * "prevnonblank()" function
8679 */
8680 static void
8681f_prevnonblank(typval_T *argvars, typval_T *rettv)
8682{
8683 linenr_T lnum;
8684
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008685 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008686 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8687 lnum = 0;
8688 else
8689 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8690 --lnum;
8691 rettv->vval.v_number = lnum;
8692}
8693
8694/* This dummy va_list is here because:
8695 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8696 * - locally in the function results in a "used before set" warning
8697 * - using va_start() to initialize it gives "function with fixed args" error */
8698static va_list ap;
8699
8700/*
8701 * "printf()" function
8702 */
8703 static void
8704f_printf(typval_T *argvars, typval_T *rettv)
8705{
8706 char_u buf[NUMBUFLEN];
8707 int len;
8708 char_u *s;
8709 int saved_did_emsg = did_emsg;
8710 char *fmt;
8711
8712 rettv->v_type = VAR_STRING;
8713 rettv->vval.v_string = NULL;
8714
8715 /* Get the required length, allocate the buffer and do it for real. */
8716 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008717 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008718 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008719 if (!did_emsg)
8720 {
8721 s = alloc(len + 1);
8722 if (s != NULL)
8723 {
8724 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008725 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8726 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008727 }
8728 }
8729 did_emsg |= saved_did_emsg;
8730}
8731
Bram Moolenaarf2732452018-06-03 14:47:35 +02008732#ifdef FEAT_JOB_CHANNEL
8733/*
8734 * "prompt_setcallback({buffer}, {callback})" function
8735 */
8736 static void
8737f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8738{
8739 buf_T *buf;
8740 char_u *callback;
8741 partial_T *partial;
8742
8743 if (check_secure())
8744 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008745 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008746 if (buf == NULL)
8747 return;
8748
8749 callback = get_callback(&argvars[1], &partial);
8750 if (callback == NULL)
8751 return;
8752
8753 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8754 if (partial == NULL)
8755 buf->b_prompt_callback = vim_strsave(callback);
8756 else
8757 /* pointer into the partial */
8758 buf->b_prompt_callback = callback;
8759 buf->b_prompt_partial = partial;
8760}
8761
8762/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008763 * "prompt_setinterrupt({buffer}, {callback})" function
8764 */
8765 static void
8766f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8767{
8768 buf_T *buf;
8769 char_u *callback;
8770 partial_T *partial;
8771
8772 if (check_secure())
8773 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008774 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008775 if (buf == NULL)
8776 return;
8777
8778 callback = get_callback(&argvars[1], &partial);
8779 if (callback == NULL)
8780 return;
8781
8782 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8783 if (partial == NULL)
8784 buf->b_prompt_interrupt = vim_strsave(callback);
8785 else
8786 /* pointer into the partial */
8787 buf->b_prompt_interrupt = callback;
8788 buf->b_prompt_int_partial = partial;
8789}
8790
8791/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008792 * "prompt_setprompt({buffer}, {text})" function
8793 */
8794 static void
8795f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8796{
8797 buf_T *buf;
8798 char_u *text;
8799
8800 if (check_secure())
8801 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008802 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008803 if (buf == NULL)
8804 return;
8805
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008806 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008807 vim_free(buf->b_prompt_text);
8808 buf->b_prompt_text = vim_strsave(text);
8809}
8810#endif
8811
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008812/*
8813 * "pumvisible()" function
8814 */
8815 static void
8816f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8817{
8818#ifdef FEAT_INS_EXPAND
8819 if (pum_visible())
8820 rettv->vval.v_number = 1;
8821#endif
8822}
8823
8824#ifdef FEAT_PYTHON3
8825/*
8826 * "py3eval()" function
8827 */
8828 static void
8829f_py3eval(typval_T *argvars, typval_T *rettv)
8830{
8831 char_u *str;
8832 char_u buf[NUMBUFLEN];
8833
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008834 if (p_pyx == 0)
8835 p_pyx = 3;
8836
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008837 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008838 do_py3eval(str, rettv);
8839}
8840#endif
8841
8842#ifdef FEAT_PYTHON
8843/*
8844 * "pyeval()" function
8845 */
8846 static void
8847f_pyeval(typval_T *argvars, typval_T *rettv)
8848{
8849 char_u *str;
8850 char_u buf[NUMBUFLEN];
8851
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008852 if (p_pyx == 0)
8853 p_pyx = 2;
8854
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008855 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008856 do_pyeval(str, rettv);
8857}
8858#endif
8859
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008860#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8861/*
8862 * "pyxeval()" function
8863 */
8864 static void
8865f_pyxeval(typval_T *argvars, typval_T *rettv)
8866{
8867# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8868 init_pyxversion();
8869 if (p_pyx == 2)
8870 f_pyeval(argvars, rettv);
8871 else
8872 f_py3eval(argvars, rettv);
8873# elif defined(FEAT_PYTHON)
8874 f_pyeval(argvars, rettv);
8875# elif defined(FEAT_PYTHON3)
8876 f_py3eval(argvars, rettv);
8877# endif
8878}
8879#endif
8880
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008881/*
8882 * "range()" function
8883 */
8884 static void
8885f_range(typval_T *argvars, typval_T *rettv)
8886{
8887 varnumber_T start;
8888 varnumber_T end;
8889 varnumber_T stride = 1;
8890 varnumber_T i;
8891 int error = FALSE;
8892
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008893 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008894 if (argvars[1].v_type == VAR_UNKNOWN)
8895 {
8896 end = start - 1;
8897 start = 0;
8898 }
8899 else
8900 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008901 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008903 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008904 }
8905
8906 if (error)
8907 return; /* type error; errmsg already given */
8908 if (stride == 0)
8909 EMSG(_("E726: Stride is zero"));
8910 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8911 EMSG(_("E727: Start past end"));
8912 else
8913 {
8914 if (rettv_list_alloc(rettv) == OK)
8915 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8916 if (list_append_number(rettv->vval.v_list,
8917 (varnumber_T)i) == FAIL)
8918 break;
8919 }
8920}
8921
8922/*
8923 * "readfile()" function
8924 */
8925 static void
8926f_readfile(typval_T *argvars, typval_T *rettv)
8927{
8928 int binary = FALSE;
8929 int failed = FALSE;
8930 char_u *fname;
8931 FILE *fd;
8932 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8933 int io_size = sizeof(buf);
8934 int readlen; /* size of last fread() */
8935 char_u *prev = NULL; /* previously read bytes, if any */
8936 long prevlen = 0; /* length of data in prev */
8937 long prevsize = 0; /* size of prev buffer */
8938 long maxline = MAXLNUM;
8939 long cnt = 0;
8940 char_u *p; /* position in buf */
8941 char_u *start; /* start of current line */
8942
8943 if (argvars[1].v_type != VAR_UNKNOWN)
8944 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008945 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008946 binary = TRUE;
8947 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008948 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008949 }
8950
8951 if (rettv_list_alloc(rettv) == FAIL)
8952 return;
8953
8954 /* Always open the file in binary mode, library functions have a mind of
8955 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008956 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008957 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8958 {
8959 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8960 return;
8961 }
8962
8963 while (cnt < maxline || maxline < 0)
8964 {
8965 readlen = (int)fread(buf, 1, io_size, fd);
8966
8967 /* This for loop processes what was read, but is also entered at end
8968 * of file so that either:
8969 * - an incomplete line gets written
8970 * - a "binary" file gets an empty line at the end if it ends in a
8971 * newline. */
8972 for (p = buf, start = buf;
8973 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8974 ++p)
8975 {
8976 if (*p == '\n' || readlen <= 0)
8977 {
8978 listitem_T *li;
8979 char_u *s = NULL;
8980 long_u len = p - start;
8981
8982 /* Finished a line. Remove CRs before NL. */
8983 if (readlen > 0 && !binary)
8984 {
8985 while (len > 0 && start[len - 1] == '\r')
8986 --len;
8987 /* removal may cross back to the "prev" string */
8988 if (len == 0)
8989 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8990 --prevlen;
8991 }
8992 if (prevlen == 0)
8993 s = vim_strnsave(start, (int)len);
8994 else
8995 {
8996 /* Change "prev" buffer to be the right size. This way
8997 * the bytes are only copied once, and very long lines are
8998 * allocated only once. */
8999 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9000 {
9001 mch_memmove(s + prevlen, start, len);
9002 s[prevlen + len] = NUL;
9003 prev = NULL; /* the list will own the string */
9004 prevlen = prevsize = 0;
9005 }
9006 }
9007 if (s == NULL)
9008 {
9009 do_outofmem_msg((long_u) prevlen + len + 1);
9010 failed = TRUE;
9011 break;
9012 }
9013
9014 if ((li = listitem_alloc()) == NULL)
9015 {
9016 vim_free(s);
9017 failed = TRUE;
9018 break;
9019 }
9020 li->li_tv.v_type = VAR_STRING;
9021 li->li_tv.v_lock = 0;
9022 li->li_tv.vval.v_string = s;
9023 list_append(rettv->vval.v_list, li);
9024
9025 start = p + 1; /* step over newline */
9026 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9027 break;
9028 }
9029 else if (*p == NUL)
9030 *p = '\n';
9031#ifdef FEAT_MBYTE
9032 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9033 * when finding the BF and check the previous two bytes. */
9034 else if (*p == 0xbf && enc_utf8 && !binary)
9035 {
9036 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9037 * + 1, these may be in the "prev" string. */
9038 char_u back1 = p >= buf + 1 ? p[-1]
9039 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9040 char_u back2 = p >= buf + 2 ? p[-2]
9041 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9042 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9043
9044 if (back2 == 0xef && back1 == 0xbb)
9045 {
9046 char_u *dest = p - 2;
9047
9048 /* Usually a BOM is at the beginning of a file, and so at
9049 * the beginning of a line; then we can just step over it.
9050 */
9051 if (start == dest)
9052 start = p + 1;
9053 else
9054 {
9055 /* have to shuffle buf to close gap */
9056 int adjust_prevlen = 0;
9057
9058 if (dest < buf)
9059 {
9060 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9061 dest = buf;
9062 }
9063 if (readlen > p - buf + 1)
9064 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9065 readlen -= 3 - adjust_prevlen;
9066 prevlen -= adjust_prevlen;
9067 p = dest - 1;
9068 }
9069 }
9070 }
9071#endif
9072 } /* for */
9073
9074 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9075 break;
9076 if (start < p)
9077 {
9078 /* There's part of a line in buf, store it in "prev". */
9079 if (p - start + prevlen >= prevsize)
9080 {
9081 /* need bigger "prev" buffer */
9082 char_u *newprev;
9083
9084 /* A common use case is ordinary text files and "prev" gets a
9085 * fragment of a line, so the first allocation is made
9086 * small, to avoid repeatedly 'allocing' large and
9087 * 'reallocing' small. */
9088 if (prevsize == 0)
9089 prevsize = (long)(p - start);
9090 else
9091 {
9092 long grow50pc = (prevsize * 3) / 2;
9093 long growmin = (long)((p - start) * 2 + prevlen);
9094 prevsize = grow50pc > growmin ? grow50pc : growmin;
9095 }
9096 newprev = prev == NULL ? alloc(prevsize)
9097 : vim_realloc(prev, prevsize);
9098 if (newprev == NULL)
9099 {
9100 do_outofmem_msg((long_u)prevsize);
9101 failed = TRUE;
9102 break;
9103 }
9104 prev = newprev;
9105 }
9106 /* Add the line part to end of "prev". */
9107 mch_memmove(prev + prevlen, start, p - start);
9108 prevlen += (long)(p - start);
9109 }
9110 } /* while */
9111
9112 /*
9113 * For a negative line count use only the lines at the end of the file,
9114 * free the rest.
9115 */
9116 if (!failed && maxline < 0)
9117 while (cnt > -maxline)
9118 {
9119 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9120 --cnt;
9121 }
9122
9123 if (failed)
9124 {
9125 list_free(rettv->vval.v_list);
9126 /* readfile doc says an empty list is returned on error */
9127 rettv->vval.v_list = list_alloc();
9128 }
9129
9130 vim_free(prev);
9131 fclose(fd);
9132}
9133
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009134 static void
9135return_register(int regname, typval_T *rettv)
9136{
9137 char_u buf[2] = {0, 0};
9138
9139 buf[0] = (char_u)regname;
9140 rettv->v_type = VAR_STRING;
9141 rettv->vval.v_string = vim_strsave(buf);
9142}
9143
9144/*
9145 * "reg_executing()" function
9146 */
9147 static void
9148f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9149{
9150 return_register(reg_executing, rettv);
9151}
9152
9153/*
9154 * "reg_recording()" function
9155 */
9156 static void
9157f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9158{
9159 return_register(reg_recording, rettv);
9160}
9161
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009162#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009163/*
9164 * Convert a List to proftime_T.
9165 * Return FAIL when there is something wrong.
9166 */
9167 static int
9168list2proftime(typval_T *arg, proftime_T *tm)
9169{
9170 long n1, n2;
9171 int error = FALSE;
9172
9173 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9174 || arg->vval.v_list->lv_len != 2)
9175 return FAIL;
9176 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9177 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9178# ifdef WIN3264
9179 tm->HighPart = n1;
9180 tm->LowPart = n2;
9181# else
9182 tm->tv_sec = n1;
9183 tm->tv_usec = n2;
9184# endif
9185 return error ? FAIL : OK;
9186}
9187#endif /* FEAT_RELTIME */
9188
9189/*
9190 * "reltime()" function
9191 */
9192 static void
9193f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9194{
9195#ifdef FEAT_RELTIME
9196 proftime_T res;
9197 proftime_T start;
9198
9199 if (argvars[0].v_type == VAR_UNKNOWN)
9200 {
9201 /* No arguments: get current time. */
9202 profile_start(&res);
9203 }
9204 else if (argvars[1].v_type == VAR_UNKNOWN)
9205 {
9206 if (list2proftime(&argvars[0], &res) == FAIL)
9207 return;
9208 profile_end(&res);
9209 }
9210 else
9211 {
9212 /* Two arguments: compute the difference. */
9213 if (list2proftime(&argvars[0], &start) == FAIL
9214 || list2proftime(&argvars[1], &res) == FAIL)
9215 return;
9216 profile_sub(&res, &start);
9217 }
9218
9219 if (rettv_list_alloc(rettv) == OK)
9220 {
9221 long n1, n2;
9222
9223# ifdef WIN3264
9224 n1 = res.HighPart;
9225 n2 = res.LowPart;
9226# else
9227 n1 = res.tv_sec;
9228 n2 = res.tv_usec;
9229# endif
9230 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9231 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9232 }
9233#endif
9234}
9235
9236#ifdef FEAT_FLOAT
9237/*
9238 * "reltimefloat()" function
9239 */
9240 static void
9241f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9242{
9243# ifdef FEAT_RELTIME
9244 proftime_T tm;
9245# endif
9246
9247 rettv->v_type = VAR_FLOAT;
9248 rettv->vval.v_float = 0;
9249# ifdef FEAT_RELTIME
9250 if (list2proftime(&argvars[0], &tm) == OK)
9251 rettv->vval.v_float = profile_float(&tm);
9252# endif
9253}
9254#endif
9255
9256/*
9257 * "reltimestr()" function
9258 */
9259 static void
9260f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9261{
9262#ifdef FEAT_RELTIME
9263 proftime_T tm;
9264#endif
9265
9266 rettv->v_type = VAR_STRING;
9267 rettv->vval.v_string = NULL;
9268#ifdef FEAT_RELTIME
9269 if (list2proftime(&argvars[0], &tm) == OK)
9270 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9271#endif
9272}
9273
9274#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009275 static void
9276make_connection(void)
9277{
9278 if (X_DISPLAY == NULL
9279# ifdef FEAT_GUI
9280 && !gui.in_use
9281# endif
9282 )
9283 {
9284 x_force_connect = TRUE;
9285 setup_term_clip();
9286 x_force_connect = FALSE;
9287 }
9288}
9289
9290 static int
9291check_connection(void)
9292{
9293 make_connection();
9294 if (X_DISPLAY == NULL)
9295 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009296 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009297 return FAIL;
9298 }
9299 return OK;
9300}
9301#endif
9302
9303#ifdef FEAT_CLIENTSERVER
9304 static void
9305remote_common(typval_T *argvars, typval_T *rettv, int expr)
9306{
9307 char_u *server_name;
9308 char_u *keys;
9309 char_u *r = NULL;
9310 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009311 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009312# ifdef WIN32
9313 HWND w;
9314# else
9315 Window w;
9316# endif
9317
9318 if (check_restricted() || check_secure())
9319 return;
9320
9321# ifdef FEAT_X11
9322 if (check_connection() == FAIL)
9323 return;
9324# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009325 if (argvars[2].v_type != VAR_UNKNOWN
9326 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009327 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009328
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009329 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009330 if (server_name == NULL)
9331 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009332 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009334 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009335# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009336 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9337 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009338# endif
9339 {
9340 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009341 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009342 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009343 vim_free(r);
9344 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009345 else
9346 EMSG2(_("E241: Unable to send to %s"), server_name);
9347 return;
9348 }
9349
9350 rettv->vval.v_string = r;
9351
9352 if (argvars[2].v_type != VAR_UNKNOWN)
9353 {
9354 dictitem_T v;
9355 char_u str[30];
9356 char_u *idvar;
9357
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009358 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009359 if (idvar != NULL && *idvar != NUL)
9360 {
9361 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9362 v.di_tv.v_type = VAR_STRING;
9363 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009364 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009365 vim_free(v.di_tv.vval.v_string);
9366 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009367 }
9368}
9369#endif
9370
9371/*
9372 * "remote_expr()" function
9373 */
9374 static void
9375f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9376{
9377 rettv->v_type = VAR_STRING;
9378 rettv->vval.v_string = NULL;
9379#ifdef FEAT_CLIENTSERVER
9380 remote_common(argvars, rettv, TRUE);
9381#endif
9382}
9383
9384/*
9385 * "remote_foreground()" function
9386 */
9387 static void
9388f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9389{
9390#ifdef FEAT_CLIENTSERVER
9391# ifdef WIN32
9392 /* On Win32 it's done in this application. */
9393 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009394 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009395
9396 if (server_name != NULL)
9397 serverForeground(server_name);
9398 }
9399# else
9400 /* Send a foreground() expression to the server. */
9401 argvars[1].v_type = VAR_STRING;
9402 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9403 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009404 rettv->v_type = VAR_STRING;
9405 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009406 remote_common(argvars, rettv, TRUE);
9407 vim_free(argvars[1].vval.v_string);
9408# endif
9409#endif
9410}
9411
9412 static void
9413f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9414{
9415#ifdef FEAT_CLIENTSERVER
9416 dictitem_T v;
9417 char_u *s = NULL;
9418# ifdef WIN32
9419 long_u n = 0;
9420# endif
9421 char_u *serverid;
9422
9423 if (check_restricted() || check_secure())
9424 {
9425 rettv->vval.v_number = -1;
9426 return;
9427 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009428 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009429 if (serverid == NULL)
9430 {
9431 rettv->vval.v_number = -1;
9432 return; /* type error; errmsg already given */
9433 }
9434# ifdef WIN32
9435 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9436 if (n == 0)
9437 rettv->vval.v_number = -1;
9438 else
9439 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009440 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009441 rettv->vval.v_number = (s != NULL);
9442 }
9443# else
9444 if (check_connection() == FAIL)
9445 return;
9446
9447 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9448 serverStrToWin(serverid), &s);
9449# endif
9450
9451 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9452 {
9453 char_u *retvar;
9454
9455 v.di_tv.v_type = VAR_STRING;
9456 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009457 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009458 if (retvar != NULL)
9459 set_var(retvar, &v.di_tv, FALSE);
9460 vim_free(v.di_tv.vval.v_string);
9461 }
9462#else
9463 rettv->vval.v_number = -1;
9464#endif
9465}
9466
9467 static void
9468f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9469{
9470 char_u *r = NULL;
9471
9472#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009473 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009474
9475 if (serverid != NULL && !check_restricted() && !check_secure())
9476 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009477 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009478# ifdef WIN32
9479 /* The server's HWND is encoded in the 'id' parameter */
9480 long_u n = 0;
9481# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009482
9483 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009484 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009485
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009486# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9488 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009489 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009490 if (r == NULL)
9491# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009492 if (check_connection() == FAIL
9493 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9494 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009495# endif
9496 EMSG(_("E277: Unable to read a server reply"));
9497 }
9498#endif
9499 rettv->v_type = VAR_STRING;
9500 rettv->vval.v_string = r;
9501}
9502
9503/*
9504 * "remote_send()" function
9505 */
9506 static void
9507f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9508{
9509 rettv->v_type = VAR_STRING;
9510 rettv->vval.v_string = NULL;
9511#ifdef FEAT_CLIENTSERVER
9512 remote_common(argvars, rettv, FALSE);
9513#endif
9514}
9515
9516/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009517 * "remote_startserver()" function
9518 */
9519 static void
9520f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9521{
9522#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009523 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009524
9525 if (server == NULL)
9526 return; /* type error; errmsg already given */
9527 if (serverName != NULL)
9528 EMSG(_("E941: already started a server"));
9529 else
9530 {
9531# ifdef FEAT_X11
9532 if (check_connection() == OK)
9533 serverRegisterName(X_DISPLAY, server);
9534# else
9535 serverSetName(server);
9536# endif
9537 }
9538#else
9539 EMSG(_("E942: +clientserver feature not available"));
9540#endif
9541}
9542
9543/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009544 * "remove()" function
9545 */
9546 static void
9547f_remove(typval_T *argvars, typval_T *rettv)
9548{
9549 list_T *l;
9550 listitem_T *item, *item2;
9551 listitem_T *li;
9552 long idx;
9553 long end;
9554 char_u *key;
9555 dict_T *d;
9556 dictitem_T *di;
9557 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9558
9559 if (argvars[0].v_type == VAR_DICT)
9560 {
9561 if (argvars[2].v_type != VAR_UNKNOWN)
9562 EMSG2(_(e_toomanyarg), "remove()");
9563 else if ((d = argvars[0].vval.v_dict) != NULL
9564 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9565 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009566 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009567 if (key != NULL)
9568 {
9569 di = dict_find(d, key, -1);
9570 if (di == NULL)
9571 EMSG2(_(e_dictkey), key);
9572 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9573 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9574 {
9575 *rettv = di->di_tv;
9576 init_tv(&di->di_tv);
9577 dictitem_remove(d, di);
9578 }
9579 }
9580 }
9581 }
9582 else if (argvars[0].v_type != VAR_LIST)
9583 EMSG2(_(e_listdictarg), "remove()");
9584 else if ((l = argvars[0].vval.v_list) != NULL
9585 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9586 {
9587 int error = FALSE;
9588
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009589 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009590 if (error)
9591 ; /* type error: do nothing, errmsg already given */
9592 else if ((item = list_find(l, idx)) == NULL)
9593 EMSGN(_(e_listidx), idx);
9594 else
9595 {
9596 if (argvars[2].v_type == VAR_UNKNOWN)
9597 {
9598 /* Remove one item, return its value. */
9599 vimlist_remove(l, item, item);
9600 *rettv = item->li_tv;
9601 vim_free(item);
9602 }
9603 else
9604 {
9605 /* Remove range of items, return list with values. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009606 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009607 if (error)
9608 ; /* type error: do nothing */
9609 else if ((item2 = list_find(l, end)) == NULL)
9610 EMSGN(_(e_listidx), end);
9611 else
9612 {
9613 int cnt = 0;
9614
9615 for (li = item; li != NULL; li = li->li_next)
9616 {
9617 ++cnt;
9618 if (li == item2)
9619 break;
9620 }
9621 if (li == NULL) /* didn't find "item2" after "item" */
9622 EMSG(_(e_invrange));
9623 else
9624 {
9625 vimlist_remove(l, item, item2);
9626 if (rettv_list_alloc(rettv) == OK)
9627 {
9628 l = rettv->vval.v_list;
9629 l->lv_first = item;
9630 l->lv_last = item2;
9631 item->li_prev = NULL;
9632 item2->li_next = NULL;
9633 l->lv_len = cnt;
9634 }
9635 }
9636 }
9637 }
9638 }
9639 }
9640}
9641
9642/*
9643 * "rename({from}, {to})" function
9644 */
9645 static void
9646f_rename(typval_T *argvars, typval_T *rettv)
9647{
9648 char_u buf[NUMBUFLEN];
9649
9650 if (check_restricted() || check_secure())
9651 rettv->vval.v_number = -1;
9652 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009653 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9654 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009655}
9656
9657/*
9658 * "repeat()" function
9659 */
9660 static void
9661f_repeat(typval_T *argvars, typval_T *rettv)
9662{
9663 char_u *p;
9664 int n;
9665 int slen;
9666 int len;
9667 char_u *r;
9668 int i;
9669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009670 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671 if (argvars[0].v_type == VAR_LIST)
9672 {
9673 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9674 while (n-- > 0)
9675 if (list_extend(rettv->vval.v_list,
9676 argvars[0].vval.v_list, NULL) == FAIL)
9677 break;
9678 }
9679 else
9680 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009681 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009682 rettv->v_type = VAR_STRING;
9683 rettv->vval.v_string = NULL;
9684
9685 slen = (int)STRLEN(p);
9686 len = slen * n;
9687 if (len <= 0)
9688 return;
9689
9690 r = alloc(len + 1);
9691 if (r != NULL)
9692 {
9693 for (i = 0; i < n; i++)
9694 mch_memmove(r + i * slen, p, (size_t)slen);
9695 r[len] = NUL;
9696 }
9697
9698 rettv->vval.v_string = r;
9699 }
9700}
9701
9702/*
9703 * "resolve()" function
9704 */
9705 static void
9706f_resolve(typval_T *argvars, typval_T *rettv)
9707{
9708 char_u *p;
9709#ifdef HAVE_READLINK
9710 char_u *buf = NULL;
9711#endif
9712
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009713 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009714#ifdef FEAT_SHORTCUT
9715 {
9716 char_u *v = NULL;
9717
9718 v = mch_resolve_shortcut(p);
9719 if (v != NULL)
9720 rettv->vval.v_string = v;
9721 else
9722 rettv->vval.v_string = vim_strsave(p);
9723 }
9724#else
9725# ifdef HAVE_READLINK
9726 {
9727 char_u *cpy;
9728 int len;
9729 char_u *remain = NULL;
9730 char_u *q;
9731 int is_relative_to_current = FALSE;
9732 int has_trailing_pathsep = FALSE;
9733 int limit = 100;
9734
9735 p = vim_strsave(p);
9736
9737 if (p[0] == '.' && (vim_ispathsep(p[1])
9738 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9739 is_relative_to_current = TRUE;
9740
9741 len = STRLEN(p);
9742 if (len > 0 && after_pathsep(p, p + len))
9743 {
9744 has_trailing_pathsep = TRUE;
9745 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9746 }
9747
9748 q = getnextcomp(p);
9749 if (*q != NUL)
9750 {
9751 /* Separate the first path component in "p", and keep the
9752 * remainder (beginning with the path separator). */
9753 remain = vim_strsave(q - 1);
9754 q[-1] = NUL;
9755 }
9756
9757 buf = alloc(MAXPATHL + 1);
9758 if (buf == NULL)
9759 goto fail;
9760
9761 for (;;)
9762 {
9763 for (;;)
9764 {
9765 len = readlink((char *)p, (char *)buf, MAXPATHL);
9766 if (len <= 0)
9767 break;
9768 buf[len] = NUL;
9769
9770 if (limit-- == 0)
9771 {
9772 vim_free(p);
9773 vim_free(remain);
9774 EMSG(_("E655: Too many symbolic links (cycle?)"));
9775 rettv->vval.v_string = NULL;
9776 goto fail;
9777 }
9778
9779 /* Ensure that the result will have a trailing path separator
9780 * if the argument has one. */
9781 if (remain == NULL && has_trailing_pathsep)
9782 add_pathsep(buf);
9783
9784 /* Separate the first path component in the link value and
9785 * concatenate the remainders. */
9786 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9787 if (*q != NUL)
9788 {
9789 if (remain == NULL)
9790 remain = vim_strsave(q - 1);
9791 else
9792 {
9793 cpy = concat_str(q - 1, remain);
9794 if (cpy != NULL)
9795 {
9796 vim_free(remain);
9797 remain = cpy;
9798 }
9799 }
9800 q[-1] = NUL;
9801 }
9802
9803 q = gettail(p);
9804 if (q > p && *q == NUL)
9805 {
9806 /* Ignore trailing path separator. */
9807 q[-1] = NUL;
9808 q = gettail(p);
9809 }
9810 if (q > p && !mch_isFullName(buf))
9811 {
9812 /* symlink is relative to directory of argument */
9813 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9814 if (cpy != NULL)
9815 {
9816 STRCPY(cpy, p);
9817 STRCPY(gettail(cpy), buf);
9818 vim_free(p);
9819 p = cpy;
9820 }
9821 }
9822 else
9823 {
9824 vim_free(p);
9825 p = vim_strsave(buf);
9826 }
9827 }
9828
9829 if (remain == NULL)
9830 break;
9831
9832 /* Append the first path component of "remain" to "p". */
9833 q = getnextcomp(remain + 1);
9834 len = q - remain - (*q != NUL);
9835 cpy = vim_strnsave(p, STRLEN(p) + len);
9836 if (cpy != NULL)
9837 {
9838 STRNCAT(cpy, remain, len);
9839 vim_free(p);
9840 p = cpy;
9841 }
9842 /* Shorten "remain". */
9843 if (*q != NUL)
9844 STRMOVE(remain, q - 1);
9845 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009846 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009847 }
9848
9849 /* If the result is a relative path name, make it explicitly relative to
9850 * the current directory if and only if the argument had this form. */
9851 if (!vim_ispathsep(*p))
9852 {
9853 if (is_relative_to_current
9854 && *p != NUL
9855 && !(p[0] == '.'
9856 && (p[1] == NUL
9857 || vim_ispathsep(p[1])
9858 || (p[1] == '.'
9859 && (p[2] == NUL
9860 || vim_ispathsep(p[2]))))))
9861 {
9862 /* Prepend "./". */
9863 cpy = concat_str((char_u *)"./", p);
9864 if (cpy != NULL)
9865 {
9866 vim_free(p);
9867 p = cpy;
9868 }
9869 }
9870 else if (!is_relative_to_current)
9871 {
9872 /* Strip leading "./". */
9873 q = p;
9874 while (q[0] == '.' && vim_ispathsep(q[1]))
9875 q += 2;
9876 if (q > p)
9877 STRMOVE(p, p + 2);
9878 }
9879 }
9880
9881 /* Ensure that the result will have no trailing path separator
9882 * if the argument had none. But keep "/" or "//". */
9883 if (!has_trailing_pathsep)
9884 {
9885 q = p + STRLEN(p);
9886 if (after_pathsep(p, q))
9887 *gettail_sep(p) = NUL;
9888 }
9889
9890 rettv->vval.v_string = p;
9891 }
9892# else
9893 rettv->vval.v_string = vim_strsave(p);
9894# endif
9895#endif
9896
9897 simplify_filename(rettv->vval.v_string);
9898
9899#ifdef HAVE_READLINK
9900fail:
9901 vim_free(buf);
9902#endif
9903 rettv->v_type = VAR_STRING;
9904}
9905
9906/*
9907 * "reverse({list})" function
9908 */
9909 static void
9910f_reverse(typval_T *argvars, typval_T *rettv)
9911{
9912 list_T *l;
9913 listitem_T *li, *ni;
9914
9915 if (argvars[0].v_type != VAR_LIST)
9916 EMSG2(_(e_listarg), "reverse()");
9917 else if ((l = argvars[0].vval.v_list) != NULL
9918 && !tv_check_lock(l->lv_lock,
9919 (char_u *)N_("reverse() argument"), TRUE))
9920 {
9921 li = l->lv_last;
9922 l->lv_first = l->lv_last = NULL;
9923 l->lv_len = 0;
9924 while (li != NULL)
9925 {
9926 ni = li->li_prev;
9927 list_append(l, li);
9928 li = ni;
9929 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009930 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009931 l->lv_idx = l->lv_len - l->lv_idx - 1;
9932 }
9933}
9934
9935#define SP_NOMOVE 0x01 /* don't move cursor */
9936#define SP_REPEAT 0x02 /* repeat to find outer pair */
9937#define SP_RETCOUNT 0x04 /* return matchcount */
9938#define SP_SETPCMARK 0x08 /* set previous context mark */
9939#define SP_START 0x10 /* accept match at start position */
9940#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9941#define SP_END 0x40 /* leave cursor at end of match */
9942#define SP_COLUMN 0x80 /* start at cursor column */
9943
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009944/*
9945 * Get flags for a search function.
9946 * Possibly sets "p_ws".
9947 * Returns BACKWARD, FORWARD or zero (for an error).
9948 */
9949 static int
9950get_search_arg(typval_T *varp, int *flagsp)
9951{
9952 int dir = FORWARD;
9953 char_u *flags;
9954 char_u nbuf[NUMBUFLEN];
9955 int mask;
9956
9957 if (varp->v_type != VAR_UNKNOWN)
9958 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009959 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009960 if (flags == NULL)
9961 return 0; /* type error; errmsg already given */
9962 while (*flags != NUL)
9963 {
9964 switch (*flags)
9965 {
9966 case 'b': dir = BACKWARD; break;
9967 case 'w': p_ws = TRUE; break;
9968 case 'W': p_ws = FALSE; break;
9969 default: mask = 0;
9970 if (flagsp != NULL)
9971 switch (*flags)
9972 {
9973 case 'c': mask = SP_START; break;
9974 case 'e': mask = SP_END; break;
9975 case 'm': mask = SP_RETCOUNT; break;
9976 case 'n': mask = SP_NOMOVE; break;
9977 case 'p': mask = SP_SUBPAT; break;
9978 case 'r': mask = SP_REPEAT; break;
9979 case 's': mask = SP_SETPCMARK; break;
9980 case 'z': mask = SP_COLUMN; break;
9981 }
9982 if (mask == 0)
9983 {
9984 EMSG2(_(e_invarg2), flags);
9985 dir = 0;
9986 }
9987 else
9988 *flagsp |= mask;
9989 }
9990 if (dir == 0)
9991 break;
9992 ++flags;
9993 }
9994 }
9995 return dir;
9996}
9997
9998/*
9999 * Shared by search() and searchpos() functions.
10000 */
10001 static int
10002search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10003{
10004 int flags;
10005 char_u *pat;
10006 pos_T pos;
10007 pos_T save_cursor;
10008 int save_p_ws = p_ws;
10009 int dir;
10010 int retval = 0; /* default: FAIL */
10011 long lnum_stop = 0;
10012 proftime_T tm;
10013#ifdef FEAT_RELTIME
10014 long time_limit = 0;
10015#endif
10016 int options = SEARCH_KEEP;
10017 int subpatnum;
10018
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010019 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010020 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10021 if (dir == 0)
10022 goto theend;
10023 flags = *flagsp;
10024 if (flags & SP_START)
10025 options |= SEARCH_START;
10026 if (flags & SP_END)
10027 options |= SEARCH_END;
10028 if (flags & SP_COLUMN)
10029 options |= SEARCH_COL;
10030
10031 /* Optional arguments: line number to stop searching and timeout. */
10032 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10033 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010034 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010035 if (lnum_stop < 0)
10036 goto theend;
10037#ifdef FEAT_RELTIME
10038 if (argvars[3].v_type != VAR_UNKNOWN)
10039 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010040 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010041 if (time_limit < 0)
10042 goto theend;
10043 }
10044#endif
10045 }
10046
10047#ifdef FEAT_RELTIME
10048 /* Set the time limit, if there is one. */
10049 profile_setlimit(time_limit, &tm);
10050#endif
10051
10052 /*
10053 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10054 * Check to make sure only those flags are set.
10055 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10056 * flags cannot be set. Check for that condition also.
10057 */
10058 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10059 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10060 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010061 EMSG2(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010062 goto theend;
10063 }
10064
10065 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010066 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010067 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010068 if (subpatnum != FAIL)
10069 {
10070 if (flags & SP_SUBPAT)
10071 retval = subpatnum;
10072 else
10073 retval = pos.lnum;
10074 if (flags & SP_SETPCMARK)
10075 setpcmark();
10076 curwin->w_cursor = pos;
10077 if (match_pos != NULL)
10078 {
10079 /* Store the match cursor position */
10080 match_pos->lnum = pos.lnum;
10081 match_pos->col = pos.col + 1;
10082 }
10083 /* "/$" will put the cursor after the end of the line, may need to
10084 * correct that here */
10085 check_cursor();
10086 }
10087
10088 /* If 'n' flag is used: restore cursor position. */
10089 if (flags & SP_NOMOVE)
10090 curwin->w_cursor = save_cursor;
10091 else
10092 curwin->w_set_curswant = TRUE;
10093theend:
10094 p_ws = save_p_ws;
10095
10096 return retval;
10097}
10098
10099#ifdef FEAT_FLOAT
10100
10101/*
10102 * round() is not in C90, use ceil() or floor() instead.
10103 */
10104 float_T
10105vim_round(float_T f)
10106{
10107 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10108}
10109
10110/*
10111 * "round({float})" function
10112 */
10113 static void
10114f_round(typval_T *argvars, typval_T *rettv)
10115{
10116 float_T f = 0.0;
10117
10118 rettv->v_type = VAR_FLOAT;
10119 if (get_float_arg(argvars, &f) == OK)
10120 rettv->vval.v_float = vim_round(f);
10121 else
10122 rettv->vval.v_float = 0.0;
10123}
10124#endif
10125
10126/*
10127 * "screenattr()" function
10128 */
10129 static void
10130f_screenattr(typval_T *argvars, typval_T *rettv)
10131{
10132 int row;
10133 int col;
10134 int c;
10135
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010136 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10137 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010138 if (row < 0 || row >= screen_Rows
10139 || col < 0 || col >= screen_Columns)
10140 c = -1;
10141 else
10142 c = ScreenAttrs[LineOffset[row] + col];
10143 rettv->vval.v_number = c;
10144}
10145
10146/*
10147 * "screenchar()" function
10148 */
10149 static void
10150f_screenchar(typval_T *argvars, typval_T *rettv)
10151{
10152 int row;
10153 int col;
10154 int off;
10155 int c;
10156
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010157 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10158 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010159 if (row < 0 || row >= screen_Rows
10160 || col < 0 || col >= screen_Columns)
10161 c = -1;
10162 else
10163 {
10164 off = LineOffset[row] + col;
10165#ifdef FEAT_MBYTE
10166 if (enc_utf8 && ScreenLinesUC[off] != 0)
10167 c = ScreenLinesUC[off];
10168 else
10169#endif
10170 c = ScreenLines[off];
10171 }
10172 rettv->vval.v_number = c;
10173}
10174
10175/*
10176 * "screencol()" function
10177 *
10178 * First column is 1 to be consistent with virtcol().
10179 */
10180 static void
10181f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10182{
10183 rettv->vval.v_number = screen_screencol() + 1;
10184}
10185
10186/*
10187 * "screenrow()" function
10188 */
10189 static void
10190f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10191{
10192 rettv->vval.v_number = screen_screenrow() + 1;
10193}
10194
10195/*
10196 * "search()" function
10197 */
10198 static void
10199f_search(typval_T *argvars, typval_T *rettv)
10200{
10201 int flags = 0;
10202
10203 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10204}
10205
10206/*
10207 * "searchdecl()" function
10208 */
10209 static void
10210f_searchdecl(typval_T *argvars, typval_T *rettv)
10211{
10212 int locally = 1;
10213 int thisblock = 0;
10214 int error = FALSE;
10215 char_u *name;
10216
10217 rettv->vval.v_number = 1; /* default: FAIL */
10218
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010219 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010220 if (argvars[1].v_type != VAR_UNKNOWN)
10221 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010222 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010223 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010224 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010225 }
10226 if (!error && name != NULL)
10227 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10228 locally, thisblock, SEARCH_KEEP) == FAIL;
10229}
10230
10231/*
10232 * Used by searchpair() and searchpairpos()
10233 */
10234 static int
10235searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10236{
10237 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010238 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010239 int save_p_ws = p_ws;
10240 int dir;
10241 int flags = 0;
10242 char_u nbuf1[NUMBUFLEN];
10243 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 int retval = 0; /* default: FAIL */
10245 long lnum_stop = 0;
10246 long time_limit = 0;
10247
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010248 /* Get the three pattern arguments: start, middle, end. Will result in an
10249 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010250 spat = tv_get_string_chk(&argvars[0]);
10251 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10252 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010253 if (spat == NULL || mpat == NULL || epat == NULL)
10254 goto theend; /* type error */
10255
10256 /* Handle the optional fourth argument: flags */
10257 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10258 if (dir == 0)
10259 goto theend;
10260
10261 /* Don't accept SP_END or SP_SUBPAT.
10262 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10263 */
10264 if ((flags & (SP_END | SP_SUBPAT)) != 0
10265 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10266 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010267 EMSG2(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010268 goto theend;
10269 }
10270
10271 /* Using 'r' implies 'W', otherwise it doesn't work. */
10272 if (flags & SP_REPEAT)
10273 p_ws = FALSE;
10274
10275 /* Optional fifth argument: skip expression */
10276 if (argvars[3].v_type == VAR_UNKNOWN
10277 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010278 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010279 else
10280 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010281 skip = &argvars[4];
10282 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10283 && skip->v_type != VAR_STRING)
10284 {
10285 /* Type error */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010286 EMSG2(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010287 goto theend;
10288 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010289 if (argvars[5].v_type != VAR_UNKNOWN)
10290 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010291 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010292 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010293 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010294 EMSG2(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010295 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010296 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010297#ifdef FEAT_RELTIME
10298 if (argvars[6].v_type != VAR_UNKNOWN)
10299 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010300 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010301 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010302 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010303 EMSG2(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010304 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010305 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010306 }
10307#endif
10308 }
10309 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010310
10311 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10312 match_pos, lnum_stop, time_limit);
10313
10314theend:
10315 p_ws = save_p_ws;
10316
10317 return retval;
10318}
10319
10320/*
10321 * "searchpair()" function
10322 */
10323 static void
10324f_searchpair(typval_T *argvars, typval_T *rettv)
10325{
10326 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10327}
10328
10329/*
10330 * "searchpairpos()" function
10331 */
10332 static void
10333f_searchpairpos(typval_T *argvars, typval_T *rettv)
10334{
10335 pos_T match_pos;
10336 int lnum = 0;
10337 int col = 0;
10338
10339 if (rettv_list_alloc(rettv) == FAIL)
10340 return;
10341
10342 if (searchpair_cmn(argvars, &match_pos) > 0)
10343 {
10344 lnum = match_pos.lnum;
10345 col = match_pos.col;
10346 }
10347
10348 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10349 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10350}
10351
10352/*
10353 * Search for a start/middle/end thing.
10354 * Used by searchpair(), see its documentation for the details.
10355 * Returns 0 or -1 for no match,
10356 */
10357 long
10358do_searchpair(
10359 char_u *spat, /* start pattern */
10360 char_u *mpat, /* middle pattern */
10361 char_u *epat, /* end pattern */
10362 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010363 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010364 int flags, /* SP_SETPCMARK and other SP_ values */
10365 pos_T *match_pos,
10366 linenr_T lnum_stop, /* stop at this line if not zero */
10367 long time_limit UNUSED) /* stop after this many msec */
10368{
10369 char_u *save_cpo;
10370 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10371 long retval = 0;
10372 pos_T pos;
10373 pos_T firstpos;
10374 pos_T foundpos;
10375 pos_T save_cursor;
10376 pos_T save_pos;
10377 int n;
10378 int r;
10379 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010380 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010381 int err;
10382 int options = SEARCH_KEEP;
10383 proftime_T tm;
10384
10385 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10386 save_cpo = p_cpo;
10387 p_cpo = empty_option;
10388
10389#ifdef FEAT_RELTIME
10390 /* Set the time limit, if there is one. */
10391 profile_setlimit(time_limit, &tm);
10392#endif
10393
10394 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10395 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010396 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10397 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010398 if (pat2 == NULL || pat3 == NULL)
10399 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010400 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010401 if (*mpat == NUL)
10402 STRCPY(pat3, pat2);
10403 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010404 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010405 spat, epat, mpat);
10406 if (flags & SP_START)
10407 options |= SEARCH_START;
10408
Bram Moolenaar48570482017-10-30 21:48:41 +010010409 if (skip != NULL)
10410 {
10411 /* Empty string means to not use the skip expression. */
10412 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10413 use_skip = skip->vval.v_string != NULL
10414 && *skip->vval.v_string != NUL;
10415 }
10416
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010417 save_cursor = curwin->w_cursor;
10418 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010419 CLEAR_POS(&firstpos);
10420 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010421 pat = pat3;
10422 for (;;)
10423 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010424 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010425 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010426 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010427 /* didn't find it or found the first match again: FAIL */
10428 break;
10429
10430 if (firstpos.lnum == 0)
10431 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010432 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010433 {
10434 /* Found the same position again. Can happen with a pattern that
10435 * has "\zs" at the end and searching backwards. Advance one
10436 * character and try again. */
10437 if (dir == BACKWARD)
10438 decl(&pos);
10439 else
10440 incl(&pos);
10441 }
10442 foundpos = pos;
10443
10444 /* clear the start flag to avoid getting stuck here */
10445 options &= ~SEARCH_START;
10446
10447 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010448 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010449 {
10450 save_pos = curwin->w_cursor;
10451 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010452 err = FALSE;
10453 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010454 curwin->w_cursor = save_pos;
10455 if (err)
10456 {
10457 /* Evaluating {skip} caused an error, break here. */
10458 curwin->w_cursor = save_cursor;
10459 retval = -1;
10460 break;
10461 }
10462 if (r)
10463 continue;
10464 }
10465
10466 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10467 {
10468 /* Found end when searching backwards or start when searching
10469 * forward: nested pair. */
10470 ++nest;
10471 pat = pat2; /* nested, don't search for middle */
10472 }
10473 else
10474 {
10475 /* Found end when searching forward or start when searching
10476 * backward: end of (nested) pair; or found middle in outer pair. */
10477 if (--nest == 1)
10478 pat = pat3; /* outer level, search for middle */
10479 }
10480
10481 if (nest == 0)
10482 {
10483 /* Found the match: return matchcount or line number. */
10484 if (flags & SP_RETCOUNT)
10485 ++retval;
10486 else
10487 retval = pos.lnum;
10488 if (flags & SP_SETPCMARK)
10489 setpcmark();
10490 curwin->w_cursor = pos;
10491 if (!(flags & SP_REPEAT))
10492 break;
10493 nest = 1; /* search for next unmatched */
10494 }
10495 }
10496
10497 if (match_pos != NULL)
10498 {
10499 /* Store the match cursor position */
10500 match_pos->lnum = curwin->w_cursor.lnum;
10501 match_pos->col = curwin->w_cursor.col + 1;
10502 }
10503
10504 /* If 'n' flag is used or search failed: restore cursor position. */
10505 if ((flags & SP_NOMOVE) || retval == 0)
10506 curwin->w_cursor = save_cursor;
10507
10508theend:
10509 vim_free(pat2);
10510 vim_free(pat3);
10511 if (p_cpo == empty_option)
10512 p_cpo = save_cpo;
10513 else
10514 /* Darn, evaluating the {skip} expression changed the value. */
10515 free_string_option(save_cpo);
10516
10517 return retval;
10518}
10519
10520/*
10521 * "searchpos()" function
10522 */
10523 static void
10524f_searchpos(typval_T *argvars, typval_T *rettv)
10525{
10526 pos_T match_pos;
10527 int lnum = 0;
10528 int col = 0;
10529 int n;
10530 int flags = 0;
10531
10532 if (rettv_list_alloc(rettv) == FAIL)
10533 return;
10534
10535 n = search_cmn(argvars, &match_pos, &flags);
10536 if (n > 0)
10537 {
10538 lnum = match_pos.lnum;
10539 col = match_pos.col;
10540 }
10541
10542 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10543 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10544 if (flags & SP_SUBPAT)
10545 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10546}
10547
10548 static void
10549f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10550{
10551#ifdef FEAT_CLIENTSERVER
10552 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010553 char_u *server = tv_get_string_chk(&argvars[0]);
10554 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010555
10556 rettv->vval.v_number = -1;
10557 if (server == NULL || reply == NULL)
10558 return;
10559 if (check_restricted() || check_secure())
10560 return;
10561# ifdef FEAT_X11
10562 if (check_connection() == FAIL)
10563 return;
10564# endif
10565
10566 if (serverSendReply(server, reply) < 0)
10567 {
10568 EMSG(_("E258: Unable to send to client"));
10569 return;
10570 }
10571 rettv->vval.v_number = 0;
10572#else
10573 rettv->vval.v_number = -1;
10574#endif
10575}
10576
10577 static void
10578f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10579{
10580 char_u *r = NULL;
10581
10582#ifdef FEAT_CLIENTSERVER
10583# ifdef WIN32
10584 r = serverGetVimNames();
10585# else
10586 make_connection();
10587 if (X_DISPLAY != NULL)
10588 r = serverGetVimNames(X_DISPLAY);
10589# endif
10590#endif
10591 rettv->v_type = VAR_STRING;
10592 rettv->vval.v_string = r;
10593}
10594
10595/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010596 * "setbufline()" function
10597 */
10598 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010599f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010600{
10601 linenr_T lnum;
10602 buf_T *buf;
10603
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010604 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010605 if (buf == NULL)
10606 rettv->vval.v_number = 1; /* FAIL */
10607 else
10608 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010609 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010610 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010611 }
10612}
10613
10614/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010615 * "setbufvar()" function
10616 */
10617 static void
10618f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10619{
10620 buf_T *buf;
10621 char_u *varname, *bufvarname;
10622 typval_T *varp;
10623 char_u nbuf[NUMBUFLEN];
10624
10625 if (check_restricted() || check_secure())
10626 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010627 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10628 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010629 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010630 varp = &argvars[2];
10631
10632 if (buf != NULL && varname != NULL && varp != NULL)
10633 {
10634 if (*varname == '&')
10635 {
10636 long numval;
10637 char_u *strval;
10638 int error = FALSE;
10639 aco_save_T aco;
10640
10641 /* set curbuf to be our buf, temporarily */
10642 aucmd_prepbuf(&aco, buf);
10643
10644 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010645 numval = (long)tv_get_number_chk(varp, &error);
10646 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010647 if (!error && strval != NULL)
10648 set_option_value(varname, numval, strval, OPT_LOCAL);
10649
10650 /* reset notion of buffer */
10651 aucmd_restbuf(&aco);
10652 }
10653 else
10654 {
10655 buf_T *save_curbuf = curbuf;
10656
10657 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10658 if (bufvarname != NULL)
10659 {
10660 curbuf = buf;
10661 STRCPY(bufvarname, "b:");
10662 STRCPY(bufvarname + 2, varname);
10663 set_var(bufvarname, varp, TRUE);
10664 vim_free(bufvarname);
10665 curbuf = save_curbuf;
10666 }
10667 }
10668 }
10669}
10670
10671 static void
10672f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10673{
10674 dict_T *d;
10675 dictitem_T *di;
10676 char_u *csearch;
10677
10678 if (argvars[0].v_type != VAR_DICT)
10679 {
10680 EMSG(_(e_dictreq));
10681 return;
10682 }
10683
10684 if ((d = argvars[0].vval.v_dict) != NULL)
10685 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010686 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010687 if (csearch != NULL)
10688 {
10689#ifdef FEAT_MBYTE
10690 if (enc_utf8)
10691 {
10692 int pcc[MAX_MCO];
10693 int c = utfc_ptr2char(csearch, pcc);
10694
10695 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10696 }
10697 else
10698#endif
10699 set_last_csearch(PTR2CHAR(csearch),
10700 csearch, MB_PTR2LEN(csearch));
10701 }
10702
10703 di = dict_find(d, (char_u *)"forward", -1);
10704 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010705 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010706 ? FORWARD : BACKWARD);
10707
10708 di = dict_find(d, (char_u *)"until", -1);
10709 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010710 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010711 }
10712}
10713
10714/*
10715 * "setcmdpos()" function
10716 */
10717 static void
10718f_setcmdpos(typval_T *argvars, typval_T *rettv)
10719{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010720 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010721
10722 if (pos >= 0)
10723 rettv->vval.v_number = set_cmdline_pos(pos);
10724}
10725
10726/*
10727 * "setfperm({fname}, {mode})" function
10728 */
10729 static void
10730f_setfperm(typval_T *argvars, typval_T *rettv)
10731{
10732 char_u *fname;
10733 char_u modebuf[NUMBUFLEN];
10734 char_u *mode_str;
10735 int i;
10736 int mask;
10737 int mode = 0;
10738
10739 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010740 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010741 if (fname == NULL)
10742 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010743 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010744 if (mode_str == NULL)
10745 return;
10746 if (STRLEN(mode_str) != 9)
10747 {
10748 EMSG2(_(e_invarg2), mode_str);
10749 return;
10750 }
10751
10752 mask = 1;
10753 for (i = 8; i >= 0; --i)
10754 {
10755 if (mode_str[i] != '-')
10756 mode |= mask;
10757 mask = mask << 1;
10758 }
10759 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10760}
10761
10762/*
10763 * "setline()" function
10764 */
10765 static void
10766f_setline(typval_T *argvars, typval_T *rettv)
10767{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010768 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010769
Bram Moolenaarca851592018-06-06 21:04:07 +020010770 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010771}
10772
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010773/*
10774 * Used by "setqflist()" and "setloclist()" functions
10775 */
10776 static void
10777set_qf_ll_list(
10778 win_T *wp UNUSED,
10779 typval_T *list_arg UNUSED,
10780 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010781 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782 typval_T *rettv)
10783{
10784#ifdef FEAT_QUICKFIX
10785 static char *e_invact = N_("E927: Invalid action: '%s'");
10786 char_u *act;
10787 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010788 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010789#endif
10790
10791 rettv->vval.v_number = -1;
10792
10793#ifdef FEAT_QUICKFIX
10794 if (list_arg->v_type != VAR_LIST)
10795 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010796 else if (recursive != 0)
10797 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010798 else
10799 {
10800 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010801 dict_T *d = NULL;
10802 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010803
10804 if (action_arg->v_type == VAR_STRING)
10805 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010806 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010807 if (act == NULL)
10808 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010809 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10810 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010811 action = *act;
10812 else
10813 EMSG2(_(e_invact), act);
10814 }
10815 else if (action_arg->v_type == VAR_UNKNOWN)
10816 action = ' ';
10817 else
10818 EMSG(_(e_stringreq));
10819
Bram Moolenaard823fa92016-08-12 16:29:27 +020010820 if (action_arg->v_type != VAR_UNKNOWN
10821 && what_arg->v_type != VAR_UNKNOWN)
10822 {
10823 if (what_arg->v_type == VAR_DICT)
10824 d = what_arg->vval.v_dict;
10825 else
10826 {
10827 EMSG(_(e_dictreq));
10828 valid_dict = FALSE;
10829 }
10830 }
10831
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010832 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010833 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010834 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10835 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010836 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010837 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010838 }
10839#endif
10840}
10841
10842/*
10843 * "setloclist()" function
10844 */
10845 static void
10846f_setloclist(typval_T *argvars, typval_T *rettv)
10847{
10848 win_T *win;
10849
10850 rettv->vval.v_number = -1;
10851
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010852 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010853 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010854 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010855}
10856
10857/*
10858 * "setmatches()" function
10859 */
10860 static void
10861f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10862{
10863#ifdef FEAT_SEARCH_EXTRA
10864 list_T *l;
10865 listitem_T *li;
10866 dict_T *d;
10867 list_T *s = NULL;
10868
10869 rettv->vval.v_number = -1;
10870 if (argvars[0].v_type != VAR_LIST)
10871 {
10872 EMSG(_(e_listreq));
10873 return;
10874 }
10875 if ((l = argvars[0].vval.v_list) != NULL)
10876 {
10877
10878 /* To some extent make sure that we are dealing with a list from
10879 * "getmatches()". */
10880 li = l->lv_first;
10881 while (li != NULL)
10882 {
10883 if (li->li_tv.v_type != VAR_DICT
10884 || (d = li->li_tv.vval.v_dict) == NULL)
10885 {
10886 EMSG(_(e_invarg));
10887 return;
10888 }
10889 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10890 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10891 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10892 && dict_find(d, (char_u *)"priority", -1) != NULL
10893 && dict_find(d, (char_u *)"id", -1) != NULL))
10894 {
10895 EMSG(_(e_invarg));
10896 return;
10897 }
10898 li = li->li_next;
10899 }
10900
10901 clear_matches(curwin);
10902 li = l->lv_first;
10903 while (li != NULL)
10904 {
10905 int i = 0;
10906 char_u buf[5];
10907 dictitem_T *di;
10908 char_u *group;
10909 int priority;
10910 int id;
10911 char_u *conceal;
10912
10913 d = li->li_tv.vval.v_dict;
10914 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10915 {
10916 if (s == NULL)
10917 {
10918 s = list_alloc();
10919 if (s == NULL)
10920 return;
10921 }
10922
10923 /* match from matchaddpos() */
10924 for (i = 1; i < 9; i++)
10925 {
10926 sprintf((char *)buf, (char *)"pos%d", i);
10927 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10928 {
10929 if (di->di_tv.v_type != VAR_LIST)
10930 return;
10931
10932 list_append_tv(s, &di->di_tv);
10933 s->lv_refcount++;
10934 }
10935 else
10936 break;
10937 }
10938 }
10939
Bram Moolenaar8f667172018-12-14 15:38:31 +010010940 group = dict_get_string(d, (char_u *)"group", TRUE);
10941 priority = (int)dict_get_number(d, (char_u *)"priority");
10942 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010943 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010010944 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010945 : NULL;
10946 if (i == 0)
10947 {
10948 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010010949 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010950 priority, id, NULL, conceal);
10951 }
10952 else
10953 {
10954 match_add(curwin, group, NULL, priority, id, s, conceal);
10955 list_unref(s);
10956 s = NULL;
10957 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010958 vim_free(group);
10959 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010960
10961 li = li->li_next;
10962 }
10963 rettv->vval.v_number = 0;
10964 }
10965#endif
10966}
10967
10968/*
10969 * "setpos()" function
10970 */
10971 static void
10972f_setpos(typval_T *argvars, typval_T *rettv)
10973{
10974 pos_T pos;
10975 int fnum;
10976 char_u *name;
10977 colnr_T curswant = -1;
10978
10979 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010980 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010981 if (name != NULL)
10982 {
10983 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10984 {
10985 if (--pos.col < 0)
10986 pos.col = 0;
10987 if (name[0] == '.' && name[1] == NUL)
10988 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010989 /* set cursor; "fnum" is ignored */
10990 curwin->w_cursor = pos;
10991 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010992 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010993 curwin->w_curswant = curswant - 1;
10994 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010995 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010996 check_cursor();
10997 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010998 }
10999 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11000 {
11001 /* set mark */
11002 if (setmark_pos(name[1], &pos, fnum) == OK)
11003 rettv->vval.v_number = 0;
11004 }
11005 else
11006 EMSG(_(e_invarg));
11007 }
11008 }
11009}
11010
11011/*
11012 * "setqflist()" function
11013 */
11014 static void
11015f_setqflist(typval_T *argvars, typval_T *rettv)
11016{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011017 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011018}
11019
11020/*
11021 * "setreg()" function
11022 */
11023 static void
11024f_setreg(typval_T *argvars, typval_T *rettv)
11025{
11026 int regname;
11027 char_u *strregname;
11028 char_u *stropt;
11029 char_u *strval;
11030 int append;
11031 char_u yank_type;
11032 long block_len;
11033
11034 block_len = -1;
11035 yank_type = MAUTO;
11036 append = FALSE;
11037
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011038 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011039 rettv->vval.v_number = 1; /* FAIL is default */
11040
11041 if (strregname == NULL)
11042 return; /* type error; errmsg already given */
11043 regname = *strregname;
11044 if (regname == 0 || regname == '@')
11045 regname = '"';
11046
11047 if (argvars[2].v_type != VAR_UNKNOWN)
11048 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011049 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011050 if (stropt == NULL)
11051 return; /* type error */
11052 for (; *stropt != NUL; ++stropt)
11053 switch (*stropt)
11054 {
11055 case 'a': case 'A': /* append */
11056 append = TRUE;
11057 break;
11058 case 'v': case 'c': /* character-wise selection */
11059 yank_type = MCHAR;
11060 break;
11061 case 'V': case 'l': /* line-wise selection */
11062 yank_type = MLINE;
11063 break;
11064 case 'b': case Ctrl_V: /* block-wise selection */
11065 yank_type = MBLOCK;
11066 if (VIM_ISDIGIT(stropt[1]))
11067 {
11068 ++stropt;
11069 block_len = getdigits(&stropt) - 1;
11070 --stropt;
11071 }
11072 break;
11073 }
11074 }
11075
11076 if (argvars[1].v_type == VAR_LIST)
11077 {
11078 char_u **lstval;
11079 char_u **allocval;
11080 char_u buf[NUMBUFLEN];
11081 char_u **curval;
11082 char_u **curallocval;
11083 list_T *ll = argvars[1].vval.v_list;
11084 listitem_T *li;
11085 int len;
11086
11087 /* If the list is NULL handle like an empty list. */
11088 len = ll == NULL ? 0 : ll->lv_len;
11089
11090 /* First half: use for pointers to result lines; second half: use for
11091 * pointers to allocated copies. */
11092 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11093 if (lstval == NULL)
11094 return;
11095 curval = lstval;
11096 allocval = lstval + len + 2;
11097 curallocval = allocval;
11098
11099 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11100 li = li->li_next)
11101 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011102 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011103 if (strval == NULL)
11104 goto free_lstval;
11105 if (strval == buf)
11106 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011107 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011108 * overwrite the string. */
11109 strval = vim_strsave(buf);
11110 if (strval == NULL)
11111 goto free_lstval;
11112 *curallocval++ = strval;
11113 }
11114 *curval++ = strval;
11115 }
11116 *curval++ = NULL;
11117
11118 write_reg_contents_lst(regname, lstval, -1,
11119 append, yank_type, block_len);
11120free_lstval:
11121 while (curallocval > allocval)
11122 vim_free(*--curallocval);
11123 vim_free(lstval);
11124 }
11125 else
11126 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011127 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011128 if (strval == NULL)
11129 return;
11130 write_reg_contents_ex(regname, strval, -1,
11131 append, yank_type, block_len);
11132 }
11133 rettv->vval.v_number = 0;
11134}
11135
11136/*
11137 * "settabvar()" function
11138 */
11139 static void
11140f_settabvar(typval_T *argvars, typval_T *rettv)
11141{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011142 tabpage_T *save_curtab;
11143 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011144 char_u *varname, *tabvarname;
11145 typval_T *varp;
11146
11147 rettv->vval.v_number = 0;
11148
11149 if (check_restricted() || check_secure())
11150 return;
11151
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011152 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11153 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011154 varp = &argvars[2];
11155
Bram Moolenaar4033c552017-09-16 20:54:51 +020011156 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011157 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011158 save_curtab = curtab;
11159 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011160
11161 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11162 if (tabvarname != NULL)
11163 {
11164 STRCPY(tabvarname, "t:");
11165 STRCPY(tabvarname + 2, varname);
11166 set_var(tabvarname, varp, TRUE);
11167 vim_free(tabvarname);
11168 }
11169
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011170 /* Restore current tabpage */
11171 if (valid_tabpage(save_curtab))
11172 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011173 }
11174}
11175
11176/*
11177 * "settabwinvar()" function
11178 */
11179 static void
11180f_settabwinvar(typval_T *argvars, typval_T *rettv)
11181{
11182 setwinvar(argvars, rettv, 1);
11183}
11184
11185/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011186 * "settagstack()" function
11187 */
11188 static void
11189f_settagstack(typval_T *argvars, typval_T *rettv)
11190{
11191 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11192 win_T *wp;
11193 dict_T *d;
11194 int action = 'r';
11195
11196 rettv->vval.v_number = -1;
11197
11198 // first argument: window number or id
11199 wp = find_win_by_nr_or_id(&argvars[0]);
11200 if (wp == NULL)
11201 return;
11202
11203 // second argument: dict with items to set in the tag stack
11204 if (argvars[1].v_type != VAR_DICT)
11205 {
11206 EMSG(_(e_dictreq));
11207 return;
11208 }
11209 d = argvars[1].vval.v_dict;
11210 if (d == NULL)
11211 return;
11212
11213 // third argument: action - 'a' for append and 'r' for replace.
11214 // default is to replace the stack.
11215 if (argvars[2].v_type == VAR_UNKNOWN)
11216 action = 'r';
11217 else if (argvars[2].v_type == VAR_STRING)
11218 {
11219 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011220 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011221 if (actstr == NULL)
11222 return;
11223 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11224 action = *actstr;
11225 else
11226 {
11227 EMSG2(_(e_invact2), actstr);
11228 return;
11229 }
11230 }
11231 else
11232 {
11233 EMSG(_(e_stringreq));
11234 return;
11235 }
11236
11237 if (set_tagstack(wp, d, action) == OK)
11238 rettv->vval.v_number = 0;
11239}
11240
11241/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011242 * "setwinvar()" function
11243 */
11244 static void
11245f_setwinvar(typval_T *argvars, typval_T *rettv)
11246{
11247 setwinvar(argvars, rettv, 0);
11248}
11249
11250#ifdef FEAT_CRYPT
11251/*
11252 * "sha256({string})" function
11253 */
11254 static void
11255f_sha256(typval_T *argvars, typval_T *rettv)
11256{
11257 char_u *p;
11258
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011259 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011260 rettv->vval.v_string = vim_strsave(
11261 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11262 rettv->v_type = VAR_STRING;
11263}
11264#endif /* FEAT_CRYPT */
11265
11266/*
11267 * "shellescape({string})" function
11268 */
11269 static void
11270f_shellescape(typval_T *argvars, typval_T *rettv)
11271{
Bram Moolenaar20615522017-06-05 18:46:26 +020011272 int do_special = non_zero_arg(&argvars[1]);
11273
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011274 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011275 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011276 rettv->v_type = VAR_STRING;
11277}
11278
11279/*
11280 * shiftwidth() function
11281 */
11282 static void
11283f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11284{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011285 rettv->vval.v_number = 0;
11286
11287 if (argvars[0].v_type != VAR_UNKNOWN)
11288 {
11289 long col;
11290
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011291 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011292 if (col < 0)
11293 return; // type error; errmsg already given
11294#ifdef FEAT_VARTABS
11295 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11296 return;
11297#endif
11298 }
11299
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011300 rettv->vval.v_number = get_sw_value(curbuf);
11301}
11302
Bram Moolenaar162b7142018-12-21 15:17:36 +010011303#ifdef FEAT_SIGNS
11304/*
11305 * "sign_define()" function
11306 */
11307 static void
11308f_sign_define(typval_T *argvars, typval_T *rettv)
11309{
11310 char_u *name;
11311 dict_T *dict;
11312 char_u *icon = NULL;
11313 char_u *linehl = NULL;
11314 char_u *text = NULL;
11315 char_u *texthl = NULL;
11316
11317 rettv->vval.v_number = -1;
11318
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011319 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011320 if (name == NULL)
11321 return;
11322
11323 if (argvars[1].v_type != VAR_UNKNOWN)
11324 {
11325 if (argvars[1].v_type != VAR_DICT)
11326 {
11327 EMSG(_(e_dictreq));
11328 return;
11329 }
11330
11331 // sign attributes
11332 dict = argvars[1].vval.v_dict;
11333 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11334 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11335 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11336 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11337 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11338 text = dict_get_string(dict, (char_u *)"text", TRUE);
11339 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11340 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11341 }
11342
11343 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11344 rettv->vval.v_number = 0;
11345
11346 vim_free(icon);
11347 vim_free(linehl);
11348 vim_free(text);
11349 vim_free(texthl);
11350}
11351
11352/*
11353 * "sign_getdefined()" function
11354 */
11355 static void
11356f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11357{
11358 char_u *name = NULL;
11359
11360 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11361 return;
11362
11363 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011364 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011365
11366 sign_getlist(name, rettv->vval.v_list);
11367}
11368
11369/*
11370 * "sign_getplaced()" function
11371 */
11372 static void
11373f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11374{
11375 buf_T *buf = NULL;
11376 dict_T *dict;
11377 dictitem_T *di;
11378 linenr_T lnum = 0;
11379 int sign_id = 0;
11380 char_u *group = NULL;
11381 int notanum = FALSE;
11382
11383 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11384 return;
11385
11386 if (argvars[0].v_type != VAR_UNKNOWN)
11387 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011388 // get signs placed in the specified buffer
11389 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011390 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011391 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011392
11393 if (argvars[1].v_type != VAR_UNKNOWN)
11394 {
11395 if (argvars[1].v_type != VAR_DICT ||
11396 ((dict = argvars[1].vval.v_dict) == NULL))
11397 {
11398 EMSG(_(e_dictreq));
11399 return;
11400 }
11401 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11402 {
11403 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011404 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011405 if (notanum)
11406 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011407 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011408 }
11409 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11410 {
11411 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011412 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011413 if (notanum)
11414 return;
11415 }
11416 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11417 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011418 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011419 if (group == NULL)
11420 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011421 if (*group == '\0') // empty string means global group
11422 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011423 }
11424 }
11425 }
11426
11427 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11428}
11429
11430/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011431 * "sign_jump()" function
11432 */
11433 static void
11434f_sign_jump(typval_T *argvars, typval_T *rettv)
11435{
11436 int sign_id;
11437 char_u *sign_group = NULL;
11438 buf_T *buf;
11439 int notanum = FALSE;
11440
11441 rettv->vval.v_number = -1;
11442
11443 // Sign identifer
11444 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11445 if (notanum)
11446 return;
11447 if (sign_id <= 0)
11448 {
11449 EMSG(_(e_invarg));
11450 return;
11451 }
11452
11453 // Sign group
11454 sign_group = tv_get_string_chk(&argvars[1]);
11455 if (sign_group == NULL)
11456 return;
11457 if (sign_group[0] == '\0')
11458 sign_group = NULL; // global sign group
11459 else
11460 {
11461 sign_group = vim_strsave(sign_group);
11462 if (sign_group == NULL)
11463 return;
11464 }
11465
11466 // Buffer to place the sign
11467 buf = get_buf_arg(&argvars[2]);
11468 if (buf == NULL)
11469 goto cleanup;
11470
11471 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11472
11473cleanup:
11474 vim_free(sign_group);
11475}
11476
11477/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011478 * "sign_place()" function
11479 */
11480 static void
11481f_sign_place(typval_T *argvars, typval_T *rettv)
11482{
11483 int sign_id;
11484 char_u *group = NULL;
11485 char_u *sign_name;
11486 buf_T *buf;
11487 dict_T *dict;
11488 dictitem_T *di;
11489 linenr_T lnum = 0;
11490 int prio = SIGN_DEF_PRIO;
11491 int notanum = FALSE;
11492
11493 rettv->vval.v_number = -1;
11494
11495 // Sign identifer
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011496 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011497 if (notanum)
11498 return;
11499 if (sign_id < 0)
11500 {
11501 EMSG(_(e_invarg));
11502 return;
11503 }
11504
11505 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011506 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011507 if (group == NULL)
11508 return;
11509 if (group[0] == '\0')
11510 group = NULL; // global sign group
11511 else
11512 {
11513 group = vim_strsave(group);
11514 if (group == NULL)
11515 return;
11516 }
11517
11518 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011519 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011520 if (sign_name == NULL)
11521 goto cleanup;
11522
11523 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011524 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011525 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011526 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011527
11528 if (argvars[4].v_type != VAR_UNKNOWN)
11529 {
11530 if (argvars[4].v_type != VAR_DICT ||
11531 ((dict = argvars[4].vval.v_dict) == NULL))
11532 {
11533 EMSG(_(e_dictreq));
11534 goto cleanup;
11535 }
11536
11537 // Line number where the sign is to be placed
11538 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11539 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011540 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011541 if (notanum)
11542 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011543 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011544 }
11545 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11546 {
11547 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011548 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011549 if (notanum)
11550 goto cleanup;
11551 }
11552 }
11553
11554 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11555 rettv->vval.v_number = sign_id;
11556
11557cleanup:
11558 vim_free(group);
11559}
11560
11561/*
11562 * "sign_undefine()" function
11563 */
11564 static void
11565f_sign_undefine(typval_T *argvars, typval_T *rettv)
11566{
11567 char_u *name;
11568
11569 rettv->vval.v_number = -1;
11570
11571 if (argvars[0].v_type == VAR_UNKNOWN)
11572 {
11573 // Free all the signs
11574 free_signs();
11575 rettv->vval.v_number = 0;
11576 }
11577 else
11578 {
11579 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011580 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011581 if (name == NULL)
11582 return;
11583
11584 if (sign_undefine_by_name(name) == OK)
11585 rettv->vval.v_number = 0;
11586 }
11587}
11588
11589/*
11590 * "sign_unplace()" function
11591 */
11592 static void
11593f_sign_unplace(typval_T *argvars, typval_T *rettv)
11594{
11595 dict_T *dict;
11596 dictitem_T *di;
11597 int sign_id = 0;
11598 buf_T *buf = NULL;
11599 char_u *group = NULL;
11600
11601 rettv->vval.v_number = -1;
11602
11603 if (argvars[0].v_type != VAR_STRING)
11604 {
11605 EMSG(_(e_invarg));
11606 return;
11607 }
11608
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011609 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011610 if (group[0] == '\0')
11611 group = NULL; // global sign group
11612 else
11613 {
11614 group = vim_strsave(group);
11615 if (group == NULL)
11616 return;
11617 }
11618
11619 if (argvars[1].v_type != VAR_UNKNOWN)
11620 {
11621 if (argvars[1].v_type != VAR_DICT)
11622 {
11623 EMSG(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011624 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011625 }
11626 dict = argvars[1].vval.v_dict;
11627
11628 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11629 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011630 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011631 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011632 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011633 }
11634 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11635 sign_id = dict_get_number(dict, (char_u *)"id");
11636 }
11637
11638 if (buf == NULL)
11639 {
11640 // Delete the sign in all the buffers
11641 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011642 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011643 rettv->vval.v_number = 0;
11644 }
11645 else
11646 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011647 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011648 rettv->vval.v_number = 0;
11649 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011650
11651cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010011652 vim_free(group);
11653}
11654#endif
11655
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011656/*
11657 * "simplify()" function
11658 */
11659 static void
11660f_simplify(typval_T *argvars, typval_T *rettv)
11661{
11662 char_u *p;
11663
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011664 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011665 rettv->vval.v_string = vim_strsave(p);
11666 simplify_filename(rettv->vval.v_string); /* simplify in place */
11667 rettv->v_type = VAR_STRING;
11668}
11669
11670#ifdef FEAT_FLOAT
11671/*
11672 * "sin()" function
11673 */
11674 static void
11675f_sin(typval_T *argvars, typval_T *rettv)
11676{
11677 float_T f = 0.0;
11678
11679 rettv->v_type = VAR_FLOAT;
11680 if (get_float_arg(argvars, &f) == OK)
11681 rettv->vval.v_float = sin(f);
11682 else
11683 rettv->vval.v_float = 0.0;
11684}
11685
11686/*
11687 * "sinh()" function
11688 */
11689 static void
11690f_sinh(typval_T *argvars, typval_T *rettv)
11691{
11692 float_T f = 0.0;
11693
11694 rettv->v_type = VAR_FLOAT;
11695 if (get_float_arg(argvars, &f) == OK)
11696 rettv->vval.v_float = sinh(f);
11697 else
11698 rettv->vval.v_float = 0.0;
11699}
11700#endif
11701
11702static int
11703#ifdef __BORLANDC__
11704 _RTLENTRYF
11705#endif
11706 item_compare(const void *s1, const void *s2);
11707static int
11708#ifdef __BORLANDC__
11709 _RTLENTRYF
11710#endif
11711 item_compare2(const void *s1, const void *s2);
11712
11713/* struct used in the array that's given to qsort() */
11714typedef struct
11715{
11716 listitem_T *item;
11717 int idx;
11718} sortItem_T;
11719
11720/* struct storing information about current sort */
11721typedef struct
11722{
11723 int item_compare_ic;
11724 int item_compare_numeric;
11725 int item_compare_numbers;
11726#ifdef FEAT_FLOAT
11727 int item_compare_float;
11728#endif
11729 char_u *item_compare_func;
11730 partial_T *item_compare_partial;
11731 dict_T *item_compare_selfdict;
11732 int item_compare_func_err;
11733 int item_compare_keep_zero;
11734} sortinfo_T;
11735static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011736#define ITEM_COMPARE_FAIL 999
11737
11738/*
11739 * Compare functions for f_sort() and f_uniq() below.
11740 */
11741 static int
11742#ifdef __BORLANDC__
11743_RTLENTRYF
11744#endif
11745item_compare(const void *s1, const void *s2)
11746{
11747 sortItem_T *si1, *si2;
11748 typval_T *tv1, *tv2;
11749 char_u *p1, *p2;
11750 char_u *tofree1 = NULL, *tofree2 = NULL;
11751 int res;
11752 char_u numbuf1[NUMBUFLEN];
11753 char_u numbuf2[NUMBUFLEN];
11754
11755 si1 = (sortItem_T *)s1;
11756 si2 = (sortItem_T *)s2;
11757 tv1 = &si1->item->li_tv;
11758 tv2 = &si2->item->li_tv;
11759
11760 if (sortinfo->item_compare_numbers)
11761 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011762 varnumber_T v1 = tv_get_number(tv1);
11763 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011764
11765 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11766 }
11767
11768#ifdef FEAT_FLOAT
11769 if (sortinfo->item_compare_float)
11770 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011771 float_T v1 = tv_get_float(tv1);
11772 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011773
11774 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11775 }
11776#endif
11777
11778 /* tv2string() puts quotes around a string and allocates memory. Don't do
11779 * that for string variables. Use a single quote when comparing with a
11780 * non-string to do what the docs promise. */
11781 if (tv1->v_type == VAR_STRING)
11782 {
11783 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11784 p1 = (char_u *)"'";
11785 else
11786 p1 = tv1->vval.v_string;
11787 }
11788 else
11789 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11790 if (tv2->v_type == VAR_STRING)
11791 {
11792 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11793 p2 = (char_u *)"'";
11794 else
11795 p2 = tv2->vval.v_string;
11796 }
11797 else
11798 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11799 if (p1 == NULL)
11800 p1 = (char_u *)"";
11801 if (p2 == NULL)
11802 p2 = (char_u *)"";
11803 if (!sortinfo->item_compare_numeric)
11804 {
11805 if (sortinfo->item_compare_ic)
11806 res = STRICMP(p1, p2);
11807 else
11808 res = STRCMP(p1, p2);
11809 }
11810 else
11811 {
11812 double n1, n2;
11813 n1 = strtod((char *)p1, (char **)&p1);
11814 n2 = strtod((char *)p2, (char **)&p2);
11815 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11816 }
11817
11818 /* When the result would be zero, compare the item indexes. Makes the
11819 * sort stable. */
11820 if (res == 0 && !sortinfo->item_compare_keep_zero)
11821 res = si1->idx > si2->idx ? 1 : -1;
11822
11823 vim_free(tofree1);
11824 vim_free(tofree2);
11825 return res;
11826}
11827
11828 static int
11829#ifdef __BORLANDC__
11830_RTLENTRYF
11831#endif
11832item_compare2(const void *s1, const void *s2)
11833{
11834 sortItem_T *si1, *si2;
11835 int res;
11836 typval_T rettv;
11837 typval_T argv[3];
11838 int dummy;
11839 char_u *func_name;
11840 partial_T *partial = sortinfo->item_compare_partial;
11841
11842 /* shortcut after failure in previous call; compare all items equal */
11843 if (sortinfo->item_compare_func_err)
11844 return 0;
11845
11846 si1 = (sortItem_T *)s1;
11847 si2 = (sortItem_T *)s2;
11848
11849 if (partial == NULL)
11850 func_name = sortinfo->item_compare_func;
11851 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011852 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011853
11854 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11855 * in the copy without changing the original list items. */
11856 copy_tv(&si1->item->li_tv, &argv[0]);
11857 copy_tv(&si2->item->li_tv, &argv[1]);
11858
11859 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11860 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011861 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011862 partial, sortinfo->item_compare_selfdict);
11863 clear_tv(&argv[0]);
11864 clear_tv(&argv[1]);
11865
11866 if (res == FAIL)
11867 res = ITEM_COMPARE_FAIL;
11868 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011869 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011870 if (sortinfo->item_compare_func_err)
11871 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11872 clear_tv(&rettv);
11873
11874 /* When the result would be zero, compare the pointers themselves. Makes
11875 * the sort stable. */
11876 if (res == 0 && !sortinfo->item_compare_keep_zero)
11877 res = si1->idx > si2->idx ? 1 : -1;
11878
11879 return res;
11880}
11881
11882/*
11883 * "sort({list})" function
11884 */
11885 static void
11886do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11887{
11888 list_T *l;
11889 listitem_T *li;
11890 sortItem_T *ptrs;
11891 sortinfo_T *old_sortinfo;
11892 sortinfo_T info;
11893 long len;
11894 long i;
11895
11896 /* Pointer to current info struct used in compare function. Save and
11897 * restore the current one for nested calls. */
11898 old_sortinfo = sortinfo;
11899 sortinfo = &info;
11900
11901 if (argvars[0].v_type != VAR_LIST)
11902 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11903 else
11904 {
11905 l = argvars[0].vval.v_list;
11906 if (l == NULL || tv_check_lock(l->lv_lock,
11907 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11908 TRUE))
11909 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011910 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011911
11912 len = list_len(l);
11913 if (len <= 1)
11914 goto theend; /* short list sorts pretty quickly */
11915
11916 info.item_compare_ic = FALSE;
11917 info.item_compare_numeric = FALSE;
11918 info.item_compare_numbers = FALSE;
11919#ifdef FEAT_FLOAT
11920 info.item_compare_float = FALSE;
11921#endif
11922 info.item_compare_func = NULL;
11923 info.item_compare_partial = NULL;
11924 info.item_compare_selfdict = NULL;
11925 if (argvars[1].v_type != VAR_UNKNOWN)
11926 {
11927 /* optional second argument: {func} */
11928 if (argvars[1].v_type == VAR_FUNC)
11929 info.item_compare_func = argvars[1].vval.v_string;
11930 else if (argvars[1].v_type == VAR_PARTIAL)
11931 info.item_compare_partial = argvars[1].vval.v_partial;
11932 else
11933 {
11934 int error = FALSE;
11935
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011936 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011937 if (error)
11938 goto theend; /* type error; errmsg already given */
11939 if (i == 1)
11940 info.item_compare_ic = TRUE;
11941 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011942 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011943 else if (i != 0)
11944 {
11945 EMSG(_(e_invarg));
11946 goto theend;
11947 }
11948 if (info.item_compare_func != NULL)
11949 {
11950 if (*info.item_compare_func == NUL)
11951 {
11952 /* empty string means default sort */
11953 info.item_compare_func = NULL;
11954 }
11955 else if (STRCMP(info.item_compare_func, "n") == 0)
11956 {
11957 info.item_compare_func = NULL;
11958 info.item_compare_numeric = TRUE;
11959 }
11960 else if (STRCMP(info.item_compare_func, "N") == 0)
11961 {
11962 info.item_compare_func = NULL;
11963 info.item_compare_numbers = TRUE;
11964 }
11965#ifdef FEAT_FLOAT
11966 else if (STRCMP(info.item_compare_func, "f") == 0)
11967 {
11968 info.item_compare_func = NULL;
11969 info.item_compare_float = TRUE;
11970 }
11971#endif
11972 else if (STRCMP(info.item_compare_func, "i") == 0)
11973 {
11974 info.item_compare_func = NULL;
11975 info.item_compare_ic = TRUE;
11976 }
11977 }
11978 }
11979
11980 if (argvars[2].v_type != VAR_UNKNOWN)
11981 {
11982 /* optional third argument: {dict} */
11983 if (argvars[2].v_type != VAR_DICT)
11984 {
11985 EMSG(_(e_dictreq));
11986 goto theend;
11987 }
11988 info.item_compare_selfdict = argvars[2].vval.v_dict;
11989 }
11990 }
11991
11992 /* Make an array with each entry pointing to an item in the List. */
11993 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11994 if (ptrs == NULL)
11995 goto theend;
11996
11997 i = 0;
11998 if (sort)
11999 {
12000 /* sort(): ptrs will be the list to sort */
12001 for (li = l->lv_first; li != NULL; li = li->li_next)
12002 {
12003 ptrs[i].item = li;
12004 ptrs[i].idx = i;
12005 ++i;
12006 }
12007
12008 info.item_compare_func_err = FALSE;
12009 info.item_compare_keep_zero = FALSE;
12010 /* test the compare function */
12011 if ((info.item_compare_func != NULL
12012 || info.item_compare_partial != NULL)
12013 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12014 == ITEM_COMPARE_FAIL)
12015 EMSG(_("E702: Sort compare function failed"));
12016 else
12017 {
12018 /* Sort the array with item pointers. */
12019 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12020 info.item_compare_func == NULL
12021 && info.item_compare_partial == NULL
12022 ? item_compare : item_compare2);
12023
12024 if (!info.item_compare_func_err)
12025 {
12026 /* Clear the List and append the items in sorted order. */
12027 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12028 l->lv_len = 0;
12029 for (i = 0; i < len; ++i)
12030 list_append(l, ptrs[i].item);
12031 }
12032 }
12033 }
12034 else
12035 {
12036 int (*item_compare_func_ptr)(const void *, const void *);
12037
12038 /* f_uniq(): ptrs will be a stack of items to remove */
12039 info.item_compare_func_err = FALSE;
12040 info.item_compare_keep_zero = TRUE;
12041 item_compare_func_ptr = info.item_compare_func != NULL
12042 || info.item_compare_partial != NULL
12043 ? item_compare2 : item_compare;
12044
12045 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12046 li = li->li_next)
12047 {
12048 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12049 == 0)
12050 ptrs[i++].item = li;
12051 if (info.item_compare_func_err)
12052 {
12053 EMSG(_("E882: Uniq compare function failed"));
12054 break;
12055 }
12056 }
12057
12058 if (!info.item_compare_func_err)
12059 {
12060 while (--i >= 0)
12061 {
12062 li = ptrs[i].item->li_next;
12063 ptrs[i].item->li_next = li->li_next;
12064 if (li->li_next != NULL)
12065 li->li_next->li_prev = ptrs[i].item;
12066 else
12067 l->lv_last = ptrs[i].item;
12068 list_fix_watch(l, li);
12069 listitem_free(li);
12070 l->lv_len--;
12071 }
12072 }
12073 }
12074
12075 vim_free(ptrs);
12076 }
12077theend:
12078 sortinfo = old_sortinfo;
12079}
12080
12081/*
12082 * "sort({list})" function
12083 */
12084 static void
12085f_sort(typval_T *argvars, typval_T *rettv)
12086{
12087 do_sort_uniq(argvars, rettv, TRUE);
12088}
12089
12090/*
12091 * "uniq({list})" function
12092 */
12093 static void
12094f_uniq(typval_T *argvars, typval_T *rettv)
12095{
12096 do_sort_uniq(argvars, rettv, FALSE);
12097}
12098
12099/*
12100 * "soundfold({word})" function
12101 */
12102 static void
12103f_soundfold(typval_T *argvars, typval_T *rettv)
12104{
12105 char_u *s;
12106
12107 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012108 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012109#ifdef FEAT_SPELL
12110 rettv->vval.v_string = eval_soundfold(s);
12111#else
12112 rettv->vval.v_string = vim_strsave(s);
12113#endif
12114}
12115
12116/*
12117 * "spellbadword()" function
12118 */
12119 static void
12120f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12121{
12122 char_u *word = (char_u *)"";
12123 hlf_T attr = HLF_COUNT;
12124 int len = 0;
12125
12126 if (rettv_list_alloc(rettv) == FAIL)
12127 return;
12128
12129#ifdef FEAT_SPELL
12130 if (argvars[0].v_type == VAR_UNKNOWN)
12131 {
12132 /* Find the start and length of the badly spelled word. */
12133 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12134 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012135 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012136 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012137 curwin->w_set_curswant = TRUE;
12138 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012139 }
12140 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12141 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012142 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012143 int capcol = -1;
12144
12145 if (str != NULL)
12146 {
12147 /* Check the argument for spelling. */
12148 while (*str != NUL)
12149 {
12150 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12151 if (attr != HLF_COUNT)
12152 {
12153 word = str;
12154 break;
12155 }
12156 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012157 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012158 }
12159 }
12160 }
12161#endif
12162
12163 list_append_string(rettv->vval.v_list, word, len);
12164 list_append_string(rettv->vval.v_list, (char_u *)(
12165 attr == HLF_SPB ? "bad" :
12166 attr == HLF_SPR ? "rare" :
12167 attr == HLF_SPL ? "local" :
12168 attr == HLF_SPC ? "caps" :
12169 ""), -1);
12170}
12171
12172/*
12173 * "spellsuggest()" function
12174 */
12175 static void
12176f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12177{
12178#ifdef FEAT_SPELL
12179 char_u *str;
12180 int typeerr = FALSE;
12181 int maxcount;
12182 garray_T ga;
12183 int i;
12184 listitem_T *li;
12185 int need_capital = FALSE;
12186#endif
12187
12188 if (rettv_list_alloc(rettv) == FAIL)
12189 return;
12190
12191#ifdef FEAT_SPELL
12192 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12193 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012194 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012195 if (argvars[1].v_type != VAR_UNKNOWN)
12196 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012197 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012198 if (maxcount <= 0)
12199 return;
12200 if (argvars[2].v_type != VAR_UNKNOWN)
12201 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012202 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012203 if (typeerr)
12204 return;
12205 }
12206 }
12207 else
12208 maxcount = 25;
12209
12210 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12211
12212 for (i = 0; i < ga.ga_len; ++i)
12213 {
12214 str = ((char_u **)ga.ga_data)[i];
12215
12216 li = listitem_alloc();
12217 if (li == NULL)
12218 vim_free(str);
12219 else
12220 {
12221 li->li_tv.v_type = VAR_STRING;
12222 li->li_tv.v_lock = 0;
12223 li->li_tv.vval.v_string = str;
12224 list_append(rettv->vval.v_list, li);
12225 }
12226 }
12227 ga_clear(&ga);
12228 }
12229#endif
12230}
12231
12232 static void
12233f_split(typval_T *argvars, typval_T *rettv)
12234{
12235 char_u *str;
12236 char_u *end;
12237 char_u *pat = NULL;
12238 regmatch_T regmatch;
12239 char_u patbuf[NUMBUFLEN];
12240 char_u *save_cpo;
12241 int match;
12242 colnr_T col = 0;
12243 int keepempty = FALSE;
12244 int typeerr = FALSE;
12245
12246 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12247 save_cpo = p_cpo;
12248 p_cpo = (char_u *)"";
12249
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012250 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012251 if (argvars[1].v_type != VAR_UNKNOWN)
12252 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012253 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012254 if (pat == NULL)
12255 typeerr = TRUE;
12256 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012257 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012258 }
12259 if (pat == NULL || *pat == NUL)
12260 pat = (char_u *)"[\\x01- ]\\+";
12261
12262 if (rettv_list_alloc(rettv) == FAIL)
12263 return;
12264 if (typeerr)
12265 return;
12266
12267 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12268 if (regmatch.regprog != NULL)
12269 {
12270 regmatch.rm_ic = FALSE;
12271 while (*str != NUL || keepempty)
12272 {
12273 if (*str == NUL)
12274 match = FALSE; /* empty item at the end */
12275 else
12276 match = vim_regexec_nl(&regmatch, str, col);
12277 if (match)
12278 end = regmatch.startp[0];
12279 else
12280 end = str + STRLEN(str);
12281 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12282 && *str != NUL && match && end < regmatch.endp[0]))
12283 {
12284 if (list_append_string(rettv->vval.v_list, str,
12285 (int)(end - str)) == FAIL)
12286 break;
12287 }
12288 if (!match)
12289 break;
12290 /* Advance to just after the match. */
12291 if (regmatch.endp[0] > str)
12292 col = 0;
12293 else
12294 {
12295 /* Don't get stuck at the same match. */
12296#ifdef FEAT_MBYTE
12297 col = (*mb_ptr2len)(regmatch.endp[0]);
12298#else
12299 col = 1;
12300#endif
12301 }
12302 str = regmatch.endp[0];
12303 }
12304
12305 vim_regfree(regmatch.regprog);
12306 }
12307
12308 p_cpo = save_cpo;
12309}
12310
12311#ifdef FEAT_FLOAT
12312/*
12313 * "sqrt()" function
12314 */
12315 static void
12316f_sqrt(typval_T *argvars, typval_T *rettv)
12317{
12318 float_T f = 0.0;
12319
12320 rettv->v_type = VAR_FLOAT;
12321 if (get_float_arg(argvars, &f) == OK)
12322 rettv->vval.v_float = sqrt(f);
12323 else
12324 rettv->vval.v_float = 0.0;
12325}
12326
12327/*
12328 * "str2float()" function
12329 */
12330 static void
12331f_str2float(typval_T *argvars, typval_T *rettv)
12332{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012333 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012334 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012335
Bram Moolenaar08243d22017-01-10 16:12:29 +010012336 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012337 p = skipwhite(p + 1);
12338 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012339 if (isneg)
12340 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012341 rettv->v_type = VAR_FLOAT;
12342}
12343#endif
12344
12345/*
12346 * "str2nr()" function
12347 */
12348 static void
12349f_str2nr(typval_T *argvars, typval_T *rettv)
12350{
12351 int base = 10;
12352 char_u *p;
12353 varnumber_T n;
12354 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012355 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012356
12357 if (argvars[1].v_type != VAR_UNKNOWN)
12358 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012359 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012360 if (base != 2 && base != 8 && base != 10 && base != 16)
12361 {
12362 EMSG(_(e_invarg));
12363 return;
12364 }
12365 }
12366
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012367 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012368 isneg = (*p == '-');
12369 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012370 p = skipwhite(p + 1);
12371 switch (base)
12372 {
12373 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12374 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12375 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12376 default: what = 0;
12377 }
12378 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012379 if (isneg)
12380 rettv->vval.v_number = -n;
12381 else
12382 rettv->vval.v_number = n;
12383
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012384}
12385
12386#ifdef HAVE_STRFTIME
12387/*
12388 * "strftime({format}[, {time}])" function
12389 */
12390 static void
12391f_strftime(typval_T *argvars, typval_T *rettv)
12392{
12393 char_u result_buf[256];
12394 struct tm *curtime;
12395 time_t seconds;
12396 char_u *p;
12397
12398 rettv->v_type = VAR_STRING;
12399
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012400 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012401 if (argvars[1].v_type == VAR_UNKNOWN)
12402 seconds = time(NULL);
12403 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012404 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012405 curtime = localtime(&seconds);
12406 /* MSVC returns NULL for an invalid value of seconds. */
12407 if (curtime == NULL)
12408 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12409 else
12410 {
12411# ifdef FEAT_MBYTE
12412 vimconv_T conv;
12413 char_u *enc;
12414
12415 conv.vc_type = CONV_NONE;
12416 enc = enc_locale();
12417 convert_setup(&conv, p_enc, enc);
12418 if (conv.vc_type != CONV_NONE)
12419 p = string_convert(&conv, p, NULL);
12420# endif
12421 if (p != NULL)
12422 (void)strftime((char *)result_buf, sizeof(result_buf),
12423 (char *)p, curtime);
12424 else
12425 result_buf[0] = NUL;
12426
12427# ifdef FEAT_MBYTE
12428 if (conv.vc_type != CONV_NONE)
12429 vim_free(p);
12430 convert_setup(&conv, enc, p_enc);
12431 if (conv.vc_type != CONV_NONE)
12432 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12433 else
12434# endif
12435 rettv->vval.v_string = vim_strsave(result_buf);
12436
12437# ifdef FEAT_MBYTE
12438 /* Release conversion descriptors */
12439 convert_setup(&conv, NULL, NULL);
12440 vim_free(enc);
12441# endif
12442 }
12443}
12444#endif
12445
12446/*
12447 * "strgetchar()" function
12448 */
12449 static void
12450f_strgetchar(typval_T *argvars, typval_T *rettv)
12451{
12452 char_u *str;
12453 int len;
12454 int error = FALSE;
12455 int charidx;
12456
12457 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012458 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012459 if (str == NULL)
12460 return;
12461 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012462 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012463 if (error)
12464 return;
12465#ifdef FEAT_MBYTE
12466 {
12467 int byteidx = 0;
12468
12469 while (charidx >= 0 && byteidx < len)
12470 {
12471 if (charidx == 0)
12472 {
12473 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12474 break;
12475 }
12476 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012477 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012478 }
12479 }
12480#else
12481 if (charidx < len)
12482 rettv->vval.v_number = str[charidx];
12483#endif
12484}
12485
12486/*
12487 * "stridx()" function
12488 */
12489 static void
12490f_stridx(typval_T *argvars, typval_T *rettv)
12491{
12492 char_u buf[NUMBUFLEN];
12493 char_u *needle;
12494 char_u *haystack;
12495 char_u *save_haystack;
12496 char_u *pos;
12497 int start_idx;
12498
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012499 needle = tv_get_string_chk(&argvars[1]);
12500 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012501 rettv->vval.v_number = -1;
12502 if (needle == NULL || haystack == NULL)
12503 return; /* type error; errmsg already given */
12504
12505 if (argvars[2].v_type != VAR_UNKNOWN)
12506 {
12507 int error = FALSE;
12508
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012509 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012510 if (error || start_idx >= (int)STRLEN(haystack))
12511 return;
12512 if (start_idx >= 0)
12513 haystack += start_idx;
12514 }
12515
12516 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12517 if (pos != NULL)
12518 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12519}
12520
12521/*
12522 * "string()" function
12523 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012524 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012525f_string(typval_T *argvars, typval_T *rettv)
12526{
12527 char_u *tofree;
12528 char_u numbuf[NUMBUFLEN];
12529
12530 rettv->v_type = VAR_STRING;
12531 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12532 get_copyID());
12533 /* Make a copy if we have a value but it's not in allocated memory. */
12534 if (rettv->vval.v_string != NULL && tofree == NULL)
12535 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12536}
12537
12538/*
12539 * "strlen()" function
12540 */
12541 static void
12542f_strlen(typval_T *argvars, typval_T *rettv)
12543{
12544 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012545 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012546}
12547
12548/*
12549 * "strchars()" function
12550 */
12551 static void
12552f_strchars(typval_T *argvars, typval_T *rettv)
12553{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012554 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012555 int skipcc = 0;
12556#ifdef FEAT_MBYTE
12557 varnumber_T len = 0;
12558 int (*func_mb_ptr2char_adv)(char_u **pp);
12559#endif
12560
12561 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012562 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012563 if (skipcc < 0 || skipcc > 1)
12564 EMSG(_(e_invarg));
12565 else
12566 {
12567#ifdef FEAT_MBYTE
12568 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12569 while (*s != NUL)
12570 {
12571 func_mb_ptr2char_adv(&s);
12572 ++len;
12573 }
12574 rettv->vval.v_number = len;
12575#else
12576 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12577#endif
12578 }
12579}
12580
12581/*
12582 * "strdisplaywidth()" function
12583 */
12584 static void
12585f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12586{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012587 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012588 int col = 0;
12589
12590 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012591 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012592
12593 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12594}
12595
12596/*
12597 * "strwidth()" function
12598 */
12599 static void
12600f_strwidth(typval_T *argvars, typval_T *rettv)
12601{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012602 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012603
12604 rettv->vval.v_number = (varnumber_T)(
12605#ifdef FEAT_MBYTE
12606 mb_string2cells(s, -1)
12607#else
12608 STRLEN(s)
12609#endif
12610 );
12611}
12612
12613/*
12614 * "strcharpart()" function
12615 */
12616 static void
12617f_strcharpart(typval_T *argvars, typval_T *rettv)
12618{
12619#ifdef FEAT_MBYTE
12620 char_u *p;
12621 int nchar;
12622 int nbyte = 0;
12623 int charlen;
12624 int len = 0;
12625 int slen;
12626 int error = FALSE;
12627
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012628 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012629 slen = (int)STRLEN(p);
12630
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012631 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012632 if (!error)
12633 {
12634 if (nchar > 0)
12635 while (nchar > 0 && nbyte < slen)
12636 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012637 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012638 --nchar;
12639 }
12640 else
12641 nbyte = nchar;
12642 if (argvars[2].v_type != VAR_UNKNOWN)
12643 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012644 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012645 while (charlen > 0 && nbyte + len < slen)
12646 {
12647 int off = nbyte + len;
12648
12649 if (off < 0)
12650 len += 1;
12651 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012652 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012653 --charlen;
12654 }
12655 }
12656 else
12657 len = slen - nbyte; /* default: all bytes that are available. */
12658 }
12659
12660 /*
12661 * Only return the overlap between the specified part and the actual
12662 * string.
12663 */
12664 if (nbyte < 0)
12665 {
12666 len += nbyte;
12667 nbyte = 0;
12668 }
12669 else if (nbyte > slen)
12670 nbyte = slen;
12671 if (len < 0)
12672 len = 0;
12673 else if (nbyte + len > slen)
12674 len = slen - nbyte;
12675
12676 rettv->v_type = VAR_STRING;
12677 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12678#else
12679 f_strpart(argvars, rettv);
12680#endif
12681}
12682
12683/*
12684 * "strpart()" function
12685 */
12686 static void
12687f_strpart(typval_T *argvars, typval_T *rettv)
12688{
12689 char_u *p;
12690 int n;
12691 int len;
12692 int slen;
12693 int error = FALSE;
12694
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012695 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012696 slen = (int)STRLEN(p);
12697
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012698 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012699 if (error)
12700 len = 0;
12701 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012702 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012703 else
12704 len = slen - n; /* default len: all bytes that are available. */
12705
12706 /*
12707 * Only return the overlap between the specified part and the actual
12708 * string.
12709 */
12710 if (n < 0)
12711 {
12712 len += n;
12713 n = 0;
12714 }
12715 else if (n > slen)
12716 n = slen;
12717 if (len < 0)
12718 len = 0;
12719 else if (n + len > slen)
12720 len = slen - n;
12721
12722 rettv->v_type = VAR_STRING;
12723 rettv->vval.v_string = vim_strnsave(p + n, len);
12724}
12725
12726/*
12727 * "strridx()" function
12728 */
12729 static void
12730f_strridx(typval_T *argvars, typval_T *rettv)
12731{
12732 char_u buf[NUMBUFLEN];
12733 char_u *needle;
12734 char_u *haystack;
12735 char_u *rest;
12736 char_u *lastmatch = NULL;
12737 int haystack_len, end_idx;
12738
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012739 needle = tv_get_string_chk(&argvars[1]);
12740 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012741
12742 rettv->vval.v_number = -1;
12743 if (needle == NULL || haystack == NULL)
12744 return; /* type error; errmsg already given */
12745
12746 haystack_len = (int)STRLEN(haystack);
12747 if (argvars[2].v_type != VAR_UNKNOWN)
12748 {
12749 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012750 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012751 if (end_idx < 0)
12752 return; /* can never find a match */
12753 }
12754 else
12755 end_idx = haystack_len;
12756
12757 if (*needle == NUL)
12758 {
12759 /* Empty string matches past the end. */
12760 lastmatch = haystack + end_idx;
12761 }
12762 else
12763 {
12764 for (rest = haystack; *rest != '\0'; ++rest)
12765 {
12766 rest = (char_u *)strstr((char *)rest, (char *)needle);
12767 if (rest == NULL || rest > haystack + end_idx)
12768 break;
12769 lastmatch = rest;
12770 }
12771 }
12772
12773 if (lastmatch == NULL)
12774 rettv->vval.v_number = -1;
12775 else
12776 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12777}
12778
12779/*
12780 * "strtrans()" function
12781 */
12782 static void
12783f_strtrans(typval_T *argvars, typval_T *rettv)
12784{
12785 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012786 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012787}
12788
12789/*
12790 * "submatch()" function
12791 */
12792 static void
12793f_submatch(typval_T *argvars, typval_T *rettv)
12794{
12795 int error = FALSE;
12796 int no;
12797 int retList = 0;
12798
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012799 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012800 if (error)
12801 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012802 if (no < 0 || no >= NSUBEXP)
12803 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012804 EMSGN(_("E935: invalid submatch number: %d"), no);
12805 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012806 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012807 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012808 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012809 if (error)
12810 return;
12811
12812 if (retList == 0)
12813 {
12814 rettv->v_type = VAR_STRING;
12815 rettv->vval.v_string = reg_submatch(no);
12816 }
12817 else
12818 {
12819 rettv->v_type = VAR_LIST;
12820 rettv->vval.v_list = reg_submatch_list(no);
12821 }
12822}
12823
12824/*
12825 * "substitute()" function
12826 */
12827 static void
12828f_substitute(typval_T *argvars, typval_T *rettv)
12829{
12830 char_u patbuf[NUMBUFLEN];
12831 char_u subbuf[NUMBUFLEN];
12832 char_u flagsbuf[NUMBUFLEN];
12833
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012834 char_u *str = tv_get_string_chk(&argvars[0]);
12835 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012836 char_u *sub = NULL;
12837 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012838 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012839
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012840 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12841 expr = &argvars[2];
12842 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012843 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012844
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012845 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012846 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12847 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012848 rettv->vval.v_string = NULL;
12849 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012850 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012851}
12852
12853/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012854 * "swapinfo(swap_filename)" function
12855 */
12856 static void
12857f_swapinfo(typval_T *argvars, typval_T *rettv)
12858{
12859 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012860 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012861}
12862
12863/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020012864 * "swapname(expr)" function
12865 */
12866 static void
12867f_swapname(typval_T *argvars, typval_T *rettv)
12868{
12869 buf_T *buf;
12870
12871 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010012872 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020012873 if (buf == NULL || buf->b_ml.ml_mfp == NULL
12874 || buf->b_ml.ml_mfp->mf_fname == NULL)
12875 rettv->vval.v_string = NULL;
12876 else
12877 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
12878}
12879
12880/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012881 * "synID(lnum, col, trans)" function
12882 */
12883 static void
12884f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12885{
12886 int id = 0;
12887#ifdef FEAT_SYN_HL
12888 linenr_T lnum;
12889 colnr_T col;
12890 int trans;
12891 int transerr = FALSE;
12892
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012893 lnum = tv_get_lnum(argvars); /* -1 on type error */
12894 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
12895 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012896
12897 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12898 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12899 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12900#endif
12901
12902 rettv->vval.v_number = id;
12903}
12904
12905/*
12906 * "synIDattr(id, what [, mode])" function
12907 */
12908 static void
12909f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12910{
12911 char_u *p = NULL;
12912#ifdef FEAT_SYN_HL
12913 int id;
12914 char_u *what;
12915 char_u *mode;
12916 char_u modebuf[NUMBUFLEN];
12917 int modec;
12918
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012919 id = (int)tv_get_number(&argvars[0]);
12920 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012921 if (argvars[2].v_type != VAR_UNKNOWN)
12922 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012923 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012924 modec = TOLOWER_ASC(mode[0]);
12925 if (modec != 't' && modec != 'c' && modec != 'g')
12926 modec = 0; /* replace invalid with current */
12927 }
12928 else
12929 {
12930#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12931 if (USE_24BIT)
12932 modec = 'g';
12933 else
12934#endif
12935 if (t_colors > 1)
12936 modec = 'c';
12937 else
12938 modec = 't';
12939 }
12940
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012941 switch (TOLOWER_ASC(what[0]))
12942 {
12943 case 'b':
12944 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12945 p = highlight_color(id, what, modec);
12946 else /* bold */
12947 p = highlight_has_attr(id, HL_BOLD, modec);
12948 break;
12949
12950 case 'f': /* fg[#] or font */
12951 p = highlight_color(id, what, modec);
12952 break;
12953
12954 case 'i':
12955 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12956 p = highlight_has_attr(id, HL_INVERSE, modec);
12957 else /* italic */
12958 p = highlight_has_attr(id, HL_ITALIC, modec);
12959 break;
12960
12961 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012962 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012963 break;
12964
12965 case 'r': /* reverse */
12966 p = highlight_has_attr(id, HL_INVERSE, modec);
12967 break;
12968
12969 case 's':
12970 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12971 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012972 /* strikeout */
12973 else if (TOLOWER_ASC(what[1]) == 't' &&
12974 TOLOWER_ASC(what[2]) == 'r')
12975 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012976 else /* standout */
12977 p = highlight_has_attr(id, HL_STANDOUT, modec);
12978 break;
12979
12980 case 'u':
12981 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12982 /* underline */
12983 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12984 else
12985 /* undercurl */
12986 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12987 break;
12988 }
12989
12990 if (p != NULL)
12991 p = vim_strsave(p);
12992#endif
12993 rettv->v_type = VAR_STRING;
12994 rettv->vval.v_string = p;
12995}
12996
12997/*
12998 * "synIDtrans(id)" function
12999 */
13000 static void
13001f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13002{
13003 int id;
13004
13005#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013006 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013007
13008 if (id > 0)
13009 id = syn_get_final_id(id);
13010 else
13011#endif
13012 id = 0;
13013
13014 rettv->vval.v_number = id;
13015}
13016
13017/*
13018 * "synconcealed(lnum, col)" function
13019 */
13020 static void
13021f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13022{
13023#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13024 linenr_T lnum;
13025 colnr_T col;
13026 int syntax_flags = 0;
13027 int cchar;
13028 int matchid = 0;
13029 char_u str[NUMBUFLEN];
13030#endif
13031
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013032 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013033
13034#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013035 lnum = tv_get_lnum(argvars); /* -1 on type error */
13036 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013037
13038 vim_memset(str, NUL, sizeof(str));
13039
13040 if (rettv_list_alloc(rettv) != FAIL)
13041 {
13042 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13043 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13044 && curwin->w_p_cole > 0)
13045 {
13046 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13047 syntax_flags = get_syntax_info(&matchid);
13048
13049 /* get the conceal character */
13050 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13051 {
13052 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013053 if (cchar == NUL && curwin->w_p_cole == 1)
13054 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013055 if (cchar != NUL)
13056 {
13057# ifdef FEAT_MBYTE
13058 if (has_mbyte)
13059 (*mb_char2bytes)(cchar, str);
13060 else
13061# endif
13062 str[0] = cchar;
13063 }
13064 }
13065 }
13066
13067 list_append_number(rettv->vval.v_list,
13068 (syntax_flags & HL_CONCEAL) != 0);
13069 /* -1 to auto-determine strlen */
13070 list_append_string(rettv->vval.v_list, str, -1);
13071 list_append_number(rettv->vval.v_list, matchid);
13072 }
13073#endif
13074}
13075
13076/*
13077 * "synstack(lnum, col)" function
13078 */
13079 static void
13080f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13081{
13082#ifdef FEAT_SYN_HL
13083 linenr_T lnum;
13084 colnr_T col;
13085 int i;
13086 int id;
13087#endif
13088
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013089 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013090
13091#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013092 lnum = tv_get_lnum(argvars); /* -1 on type error */
13093 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013094
13095 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13096 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13097 && rettv_list_alloc(rettv) != FAIL)
13098 {
13099 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13100 for (i = 0; ; ++i)
13101 {
13102 id = syn_get_stack_item(i);
13103 if (id < 0)
13104 break;
13105 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13106 break;
13107 }
13108 }
13109#endif
13110}
13111
13112 static void
13113get_cmd_output_as_rettv(
13114 typval_T *argvars,
13115 typval_T *rettv,
13116 int retlist)
13117{
13118 char_u *res = NULL;
13119 char_u *p;
13120 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013121 int err = FALSE;
13122 FILE *fd;
13123 list_T *list = NULL;
13124 int flags = SHELL_SILENT;
13125
13126 rettv->v_type = VAR_STRING;
13127 rettv->vval.v_string = NULL;
13128 if (check_restricted() || check_secure())
13129 goto errret;
13130
13131 if (argvars[1].v_type != VAR_UNKNOWN)
13132 {
13133 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013134 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013135 * command.
13136 */
13137 if ((infile = vim_tempname('i', TRUE)) == NULL)
13138 {
13139 EMSG(_(e_notmp));
13140 goto errret;
13141 }
13142
13143 fd = mch_fopen((char *)infile, WRITEBIN);
13144 if (fd == NULL)
13145 {
13146 EMSG2(_(e_notopen), infile);
13147 goto errret;
13148 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013149 if (argvars[1].v_type == VAR_NUMBER)
13150 {
13151 linenr_T lnum;
13152 buf_T *buf;
13153
13154 buf = buflist_findnr(argvars[1].vval.v_number);
13155 if (buf == NULL)
13156 {
13157 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013158 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013159 goto errret;
13160 }
13161
13162 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13163 {
13164 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13165 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13166 {
13167 err = TRUE;
13168 break;
13169 }
13170 if (putc(NL, fd) == EOF)
13171 {
13172 err = TRUE;
13173 break;
13174 }
13175 }
13176 }
13177 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013178 {
13179 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13180 err = TRUE;
13181 }
13182 else
13183 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013184 size_t len;
13185 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013186
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013187 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013188 if (p == NULL)
13189 {
13190 fclose(fd);
13191 goto errret; /* type error; errmsg already given */
13192 }
13193 len = STRLEN(p);
13194 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13195 err = TRUE;
13196 }
13197 if (fclose(fd) != 0)
13198 err = TRUE;
13199 if (err)
13200 {
13201 EMSG(_("E677: Error writing temp file"));
13202 goto errret;
13203 }
13204 }
13205
13206 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13207 * echoes typeahead, that messes up the display. */
13208 if (!msg_silent)
13209 flags += SHELL_COOKED;
13210
13211 if (retlist)
13212 {
13213 int len;
13214 listitem_T *li;
13215 char_u *s = NULL;
13216 char_u *start;
13217 char_u *end;
13218 int i;
13219
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013220 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013221 if (res == NULL)
13222 goto errret;
13223
13224 list = list_alloc();
13225 if (list == NULL)
13226 goto errret;
13227
13228 for (i = 0; i < len; ++i)
13229 {
13230 start = res + i;
13231 while (i < len && res[i] != NL)
13232 ++i;
13233 end = res + i;
13234
13235 s = alloc((unsigned)(end - start + 1));
13236 if (s == NULL)
13237 goto errret;
13238
13239 for (p = s; start < end; ++p, ++start)
13240 *p = *start == NUL ? NL : *start;
13241 *p = NUL;
13242
13243 li = listitem_alloc();
13244 if (li == NULL)
13245 {
13246 vim_free(s);
13247 goto errret;
13248 }
13249 li->li_tv.v_type = VAR_STRING;
13250 li->li_tv.v_lock = 0;
13251 li->li_tv.vval.v_string = s;
13252 list_append(list, li);
13253 }
13254
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013255 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013256 list = NULL;
13257 }
13258 else
13259 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013260 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013261#ifdef USE_CR
13262 /* translate <CR> into <NL> */
13263 if (res != NULL)
13264 {
13265 char_u *s;
13266
13267 for (s = res; *s; ++s)
13268 {
13269 if (*s == CAR)
13270 *s = NL;
13271 }
13272 }
13273#else
13274# ifdef USE_CRNL
13275 /* translate <CR><NL> into <NL> */
13276 if (res != NULL)
13277 {
13278 char_u *s, *d;
13279
13280 d = res;
13281 for (s = res; *s; ++s)
13282 {
13283 if (s[0] == CAR && s[1] == NL)
13284 ++s;
13285 *d++ = *s;
13286 }
13287 *d = NUL;
13288 }
13289# endif
13290#endif
13291 rettv->vval.v_string = res;
13292 res = NULL;
13293 }
13294
13295errret:
13296 if (infile != NULL)
13297 {
13298 mch_remove(infile);
13299 vim_free(infile);
13300 }
13301 if (res != NULL)
13302 vim_free(res);
13303 if (list != NULL)
13304 list_free(list);
13305}
13306
13307/*
13308 * "system()" function
13309 */
13310 static void
13311f_system(typval_T *argvars, typval_T *rettv)
13312{
13313 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13314}
13315
13316/*
13317 * "systemlist()" function
13318 */
13319 static void
13320f_systemlist(typval_T *argvars, typval_T *rettv)
13321{
13322 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13323}
13324
13325/*
13326 * "tabpagebuflist()" function
13327 */
13328 static void
13329f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13330{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013331 tabpage_T *tp;
13332 win_T *wp = NULL;
13333
13334 if (argvars[0].v_type == VAR_UNKNOWN)
13335 wp = firstwin;
13336 else
13337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013338 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013339 if (tp != NULL)
13340 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13341 }
13342 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13343 {
13344 for (; wp != NULL; wp = wp->w_next)
13345 if (list_append_number(rettv->vval.v_list,
13346 wp->w_buffer->b_fnum) == FAIL)
13347 break;
13348 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013349}
13350
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013351/*
13352 * "tabpagenr()" function
13353 */
13354 static void
13355f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13356{
13357 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013358 char_u *arg;
13359
13360 if (argvars[0].v_type != VAR_UNKNOWN)
13361 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013362 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013363 nr = 0;
13364 if (arg != NULL)
13365 {
13366 if (STRCMP(arg, "$") == 0)
13367 nr = tabpage_index(NULL) - 1;
13368 else
13369 EMSG2(_(e_invexpr2), arg);
13370 }
13371 }
13372 else
13373 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013374 rettv->vval.v_number = nr;
13375}
13376
13377
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013378/*
13379 * Common code for tabpagewinnr() and winnr().
13380 */
13381 static int
13382get_winnr(tabpage_T *tp, typval_T *argvar)
13383{
13384 win_T *twin;
13385 int nr = 1;
13386 win_T *wp;
13387 char_u *arg;
13388
13389 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13390 if (argvar->v_type != VAR_UNKNOWN)
13391 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013392 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013393 if (arg == NULL)
13394 nr = 0; /* type error; errmsg already given */
13395 else if (STRCMP(arg, "$") == 0)
13396 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13397 else if (STRCMP(arg, "#") == 0)
13398 {
13399 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13400 if (twin == NULL)
13401 nr = 0;
13402 }
13403 else
13404 {
13405 EMSG2(_(e_invexpr2), arg);
13406 nr = 0;
13407 }
13408 }
13409
13410 if (nr > 0)
13411 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13412 wp != twin; wp = wp->w_next)
13413 {
13414 if (wp == NULL)
13415 {
13416 /* didn't find it in this tabpage */
13417 nr = 0;
13418 break;
13419 }
13420 ++nr;
13421 }
13422 return nr;
13423}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013424
13425/*
13426 * "tabpagewinnr()" function
13427 */
13428 static void
13429f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13430{
13431 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013432 tabpage_T *tp;
13433
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013434 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013435 if (tp == NULL)
13436 nr = 0;
13437 else
13438 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013439 rettv->vval.v_number = nr;
13440}
13441
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013442/*
13443 * "tagfiles()" function
13444 */
13445 static void
13446f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13447{
13448 char_u *fname;
13449 tagname_T tn;
13450 int first;
13451
13452 if (rettv_list_alloc(rettv) == FAIL)
13453 return;
13454 fname = alloc(MAXPATHL);
13455 if (fname == NULL)
13456 return;
13457
13458 for (first = TRUE; ; first = FALSE)
13459 if (get_tagfname(&tn, first, fname) == FAIL
13460 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13461 break;
13462 tagname_free(&tn);
13463 vim_free(fname);
13464}
13465
13466/*
13467 * "taglist()" function
13468 */
13469 static void
13470f_taglist(typval_T *argvars, typval_T *rettv)
13471{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013472 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013473 char_u *tag_pattern;
13474
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013475 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013476
13477 rettv->vval.v_number = FALSE;
13478 if (*tag_pattern == NUL)
13479 return;
13480
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013481 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013482 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013483 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013484 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013485}
13486
13487/*
13488 * "tempname()" function
13489 */
13490 static void
13491f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13492{
13493 static int x = 'A';
13494
13495 rettv->v_type = VAR_STRING;
13496 rettv->vval.v_string = vim_tempname(x, FALSE);
13497
13498 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13499 * names. Skip 'I' and 'O', they are used for shell redirection. */
13500 do
13501 {
13502 if (x == 'Z')
13503 x = '0';
13504 else if (x == '9')
13505 x = 'A';
13506 else
13507 {
13508#ifdef EBCDIC
13509 if (x == 'I')
13510 x = 'J';
13511 else if (x == 'R')
13512 x = 'S';
13513 else
13514#endif
13515 ++x;
13516 }
13517 } while (x == 'I' || x == 'O');
13518}
13519
13520#ifdef FEAT_FLOAT
13521/*
13522 * "tan()" function
13523 */
13524 static void
13525f_tan(typval_T *argvars, typval_T *rettv)
13526{
13527 float_T f = 0.0;
13528
13529 rettv->v_type = VAR_FLOAT;
13530 if (get_float_arg(argvars, &f) == OK)
13531 rettv->vval.v_float = tan(f);
13532 else
13533 rettv->vval.v_float = 0.0;
13534}
13535
13536/*
13537 * "tanh()" function
13538 */
13539 static void
13540f_tanh(typval_T *argvars, typval_T *rettv)
13541{
13542 float_T f = 0.0;
13543
13544 rettv->v_type = VAR_FLOAT;
13545 if (get_float_arg(argvars, &f) == OK)
13546 rettv->vval.v_float = tanh(f);
13547 else
13548 rettv->vval.v_float = 0.0;
13549}
13550#endif
13551
13552/*
13553 * "test_alloc_fail(id, countdown, repeat)" function
13554 */
13555 static void
13556f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13557{
13558 if (argvars[0].v_type != VAR_NUMBER
13559 || argvars[0].vval.v_number <= 0
13560 || argvars[1].v_type != VAR_NUMBER
13561 || argvars[1].vval.v_number < 0
13562 || argvars[2].v_type != VAR_NUMBER)
13563 EMSG(_(e_invarg));
13564 else
13565 {
13566 alloc_fail_id = argvars[0].vval.v_number;
13567 if (alloc_fail_id >= aid_last)
13568 EMSG(_(e_invarg));
13569 alloc_fail_countdown = argvars[1].vval.v_number;
13570 alloc_fail_repeat = argvars[2].vval.v_number;
13571 did_outofmem_msg = FALSE;
13572 }
13573}
13574
13575/*
13576 * "test_autochdir()"
13577 */
13578 static void
13579f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13580{
13581#if defined(FEAT_AUTOCHDIR)
13582 test_autochdir = TRUE;
13583#endif
13584}
13585
13586/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013587 * "test_feedinput()"
13588 */
13589 static void
13590f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13591{
13592#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013593 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013594
13595 if (val != NULL)
13596 {
13597 trash_input_buf();
13598 add_to_input_buf_csi(val, (int)STRLEN(val));
13599 }
13600#endif
13601}
13602
13603/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013604 * "test_option_not_set({name})" function
13605 */
13606 static void
13607f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13608{
13609 char_u *name = (char_u *)"";
13610
13611 if (argvars[0].v_type != VAR_STRING)
13612 EMSG(_(e_invarg));
13613 else
13614 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013615 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013616 if (reset_option_was_set(name) == FAIL)
13617 EMSG2(_(e_invarg2), name);
13618 }
13619}
13620
13621/*
13622 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013623 */
13624 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013625f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013626{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013627 char_u *name = (char_u *)"";
13628 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013629 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013630
13631 if (argvars[0].v_type != VAR_STRING
13632 || (argvars[1].v_type) != VAR_NUMBER)
13633 EMSG(_(e_invarg));
13634 else
13635 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013636 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013637 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013638
13639 if (STRCMP(name, (char_u *)"redraw") == 0)
13640 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013641 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13642 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013643 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13644 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013645 else if (STRCMP(name, (char_u *)"starting") == 0)
13646 {
13647 if (val)
13648 {
13649 if (save_starting < 0)
13650 save_starting = starting;
13651 starting = 0;
13652 }
13653 else
13654 {
13655 starting = save_starting;
13656 save_starting = -1;
13657 }
13658 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013659 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13660 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013661 else if (STRCMP(name, (char_u *)"ALL") == 0)
13662 {
13663 disable_char_avail_for_testing = FALSE;
13664 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013665 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013666 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013667 if (save_starting >= 0)
13668 {
13669 starting = save_starting;
13670 save_starting = -1;
13671 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013672 }
13673 else
13674 EMSG2(_(e_invarg2), name);
13675 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013676}
13677
13678/*
13679 * "test_garbagecollect_now()" function
13680 */
13681 static void
13682f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13683{
13684 /* This is dangerous, any Lists and Dicts used internally may be freed
13685 * while still in use. */
13686 garbage_collect(TRUE);
13687}
13688
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013689/*
13690 * "test_ignore_error()" function
13691 */
13692 static void
13693f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13694{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013695 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013696}
13697
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013698#ifdef FEAT_JOB_CHANNEL
13699 static void
13700f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13701{
13702 rettv->v_type = VAR_CHANNEL;
13703 rettv->vval.v_channel = NULL;
13704}
13705#endif
13706
13707 static void
13708f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13709{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013710 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013711}
13712
13713#ifdef FEAT_JOB_CHANNEL
13714 static void
13715f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13716{
13717 rettv->v_type = VAR_JOB;
13718 rettv->vval.v_job = NULL;
13719}
13720#endif
13721
13722 static void
13723f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13724{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013725 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013726}
13727
13728 static void
13729f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13730{
13731 rettv->v_type = VAR_PARTIAL;
13732 rettv->vval.v_partial = NULL;
13733}
13734
13735 static void
13736f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13737{
13738 rettv->v_type = VAR_STRING;
13739 rettv->vval.v_string = NULL;
13740}
13741
Bram Moolenaarab186732018-09-14 21:27:06 +020013742#ifdef FEAT_GUI
13743 static void
13744f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13745{
13746 char_u *which;
13747 long value;
13748 int dragging;
13749 scrollbar_T *sb = NULL;
13750
13751 if (argvars[0].v_type != VAR_STRING
13752 || (argvars[1].v_type) != VAR_NUMBER
13753 || (argvars[2].v_type) != VAR_NUMBER)
13754 {
13755 EMSG(_(e_invarg));
13756 return;
13757 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013758 which = tv_get_string(&argvars[0]);
13759 value = tv_get_number(&argvars[1]);
13760 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020013761
13762 if (STRCMP(which, "left") == 0)
13763 sb = &curwin->w_scrollbars[SBAR_LEFT];
13764 else if (STRCMP(which, "right") == 0)
13765 sb = &curwin->w_scrollbars[SBAR_RIGHT];
13766 else if (STRCMP(which, "hor") == 0)
13767 sb = &gui.bottom_sbar;
13768 if (sb == NULL)
13769 {
13770 EMSG2(_(e_invarg2), which);
13771 return;
13772 }
13773 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020013774# ifndef USE_ON_FLY_SCROLL
13775 // need to loop through normal_cmd() to handle the scroll events
13776 exec_normal(FALSE, TRUE, FALSE);
13777# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020013778}
13779#endif
13780
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013781 static void
13782f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13783{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013784 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013785}
13786
13787#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13788/*
13789 * Get a callback from "arg". It can be a Funcref or a function name.
13790 * When "arg" is zero return an empty string.
13791 * Return NULL for an invalid argument.
13792 */
13793 char_u *
13794get_callback(typval_T *arg, partial_T **pp)
13795{
13796 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13797 {
13798 *pp = arg->vval.v_partial;
13799 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013800 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013801 }
13802 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013803 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013804 {
13805 func_ref(arg->vval.v_string);
13806 return arg->vval.v_string;
13807 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013808 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13809 return (char_u *)"";
13810 EMSG(_("E921: Invalid callback argument"));
13811 return NULL;
13812}
13813
13814/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013815 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013816 */
13817 void
13818free_callback(char_u *callback, partial_T *partial)
13819{
13820 if (partial != NULL)
13821 partial_unref(partial);
13822 else if (callback != NULL)
13823 {
13824 func_unref(callback);
13825 vim_free(callback);
13826 }
13827}
13828#endif
13829
13830#ifdef FEAT_TIMERS
13831/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013832 * "timer_info([timer])" function
13833 */
13834 static void
13835f_timer_info(typval_T *argvars, typval_T *rettv)
13836{
13837 timer_T *timer = NULL;
13838
13839 if (rettv_list_alloc(rettv) != OK)
13840 return;
13841 if (argvars[0].v_type != VAR_UNKNOWN)
13842 {
13843 if (argvars[0].v_type != VAR_NUMBER)
13844 EMSG(_(e_number_exp));
13845 else
13846 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013847 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013848 if (timer != NULL)
13849 add_timer_info(rettv, timer);
13850 }
13851 }
13852 else
13853 add_timer_info_all(rettv);
13854}
13855
13856/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013857 * "timer_pause(timer, paused)" function
13858 */
13859 static void
13860f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13861{
13862 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013863 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013864
13865 if (argvars[0].v_type != VAR_NUMBER)
13866 EMSG(_(e_number_exp));
13867 else
13868 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013869 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013870 if (timer != NULL)
13871 timer->tr_paused = paused;
13872 }
13873}
13874
13875/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013876 * "timer_start(time, callback [, options])" function
13877 */
13878 static void
13879f_timer_start(typval_T *argvars, typval_T *rettv)
13880{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013881 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020013882 timer_T *timer;
13883 int repeat = 0;
13884 char_u *callback;
13885 dict_T *dict;
13886 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013887
Bram Moolenaar75537a92016-09-05 22:45:28 +020013888 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013889 if (check_secure())
13890 return;
13891 if (argvars[2].v_type != VAR_UNKNOWN)
13892 {
13893 if (argvars[2].v_type != VAR_DICT
13894 || (dict = argvars[2].vval.v_dict) == NULL)
13895 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013896 EMSG2(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013897 return;
13898 }
13899 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013900 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013901 }
13902
Bram Moolenaar75537a92016-09-05 22:45:28 +020013903 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013904 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013905 return;
13906
13907 timer = create_timer(msec, repeat);
13908 if (timer == NULL)
13909 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013910 else
13911 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013912 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013913 timer->tr_callback = vim_strsave(callback);
13914 else
13915 /* pointer into the partial */
13916 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013917 timer->tr_partial = partial;
13918 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013919 }
13920}
13921
13922/*
13923 * "timer_stop(timer)" function
13924 */
13925 static void
13926f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13927{
13928 timer_T *timer;
13929
13930 if (argvars[0].v_type != VAR_NUMBER)
13931 {
13932 EMSG(_(e_number_exp));
13933 return;
13934 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013935 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013936 if (timer != NULL)
13937 stop_timer(timer);
13938}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013939
13940/*
13941 * "timer_stopall()" function
13942 */
13943 static void
13944f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13945{
13946 stop_all_timers();
13947}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013948#endif
13949
13950/*
13951 * "tolower(string)" function
13952 */
13953 static void
13954f_tolower(typval_T *argvars, typval_T *rettv)
13955{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013956 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013957 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013958}
13959
13960/*
13961 * "toupper(string)" function
13962 */
13963 static void
13964f_toupper(typval_T *argvars, typval_T *rettv)
13965{
13966 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013967 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013968}
13969
13970/*
13971 * "tr(string, fromstr, tostr)" function
13972 */
13973 static void
13974f_tr(typval_T *argvars, typval_T *rettv)
13975{
13976 char_u *in_str;
13977 char_u *fromstr;
13978 char_u *tostr;
13979 char_u *p;
13980#ifdef FEAT_MBYTE
13981 int inlen;
13982 int fromlen;
13983 int tolen;
13984 int idx;
13985 char_u *cpstr;
13986 int cplen;
13987 int first = TRUE;
13988#endif
13989 char_u buf[NUMBUFLEN];
13990 char_u buf2[NUMBUFLEN];
13991 garray_T ga;
13992
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013993 in_str = tv_get_string(&argvars[0]);
13994 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
13995 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013996
13997 /* Default return value: empty string. */
13998 rettv->v_type = VAR_STRING;
13999 rettv->vval.v_string = NULL;
14000 if (fromstr == NULL || tostr == NULL)
14001 return; /* type error; errmsg already given */
14002 ga_init2(&ga, (int)sizeof(char), 80);
14003
14004#ifdef FEAT_MBYTE
14005 if (!has_mbyte)
14006#endif
14007 /* not multi-byte: fromstr and tostr must be the same length */
14008 if (STRLEN(fromstr) != STRLEN(tostr))
14009 {
14010#ifdef FEAT_MBYTE
14011error:
14012#endif
14013 EMSG2(_(e_invarg2), fromstr);
14014 ga_clear(&ga);
14015 return;
14016 }
14017
14018 /* fromstr and tostr have to contain the same number of chars */
14019 while (*in_str != NUL)
14020 {
14021#ifdef FEAT_MBYTE
14022 if (has_mbyte)
14023 {
14024 inlen = (*mb_ptr2len)(in_str);
14025 cpstr = in_str;
14026 cplen = inlen;
14027 idx = 0;
14028 for (p = fromstr; *p != NUL; p += fromlen)
14029 {
14030 fromlen = (*mb_ptr2len)(p);
14031 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14032 {
14033 for (p = tostr; *p != NUL; p += tolen)
14034 {
14035 tolen = (*mb_ptr2len)(p);
14036 if (idx-- == 0)
14037 {
14038 cplen = tolen;
14039 cpstr = p;
14040 break;
14041 }
14042 }
14043 if (*p == NUL) /* tostr is shorter than fromstr */
14044 goto error;
14045 break;
14046 }
14047 ++idx;
14048 }
14049
14050 if (first && cpstr == in_str)
14051 {
14052 /* Check that fromstr and tostr have the same number of
14053 * (multi-byte) characters. Done only once when a character
14054 * of in_str doesn't appear in fromstr. */
14055 first = FALSE;
14056 for (p = tostr; *p != NUL; p += tolen)
14057 {
14058 tolen = (*mb_ptr2len)(p);
14059 --idx;
14060 }
14061 if (idx != 0)
14062 goto error;
14063 }
14064
14065 (void)ga_grow(&ga, cplen);
14066 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14067 ga.ga_len += cplen;
14068
14069 in_str += inlen;
14070 }
14071 else
14072#endif
14073 {
14074 /* When not using multi-byte chars we can do it faster. */
14075 p = vim_strchr(fromstr, *in_str);
14076 if (p != NULL)
14077 ga_append(&ga, tostr[p - fromstr]);
14078 else
14079 ga_append(&ga, *in_str);
14080 ++in_str;
14081 }
14082 }
14083
14084 /* add a terminating NUL */
14085 (void)ga_grow(&ga, 1);
14086 ga_append(&ga, NUL);
14087
14088 rettv->vval.v_string = ga.ga_data;
14089}
14090
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014091/*
14092 * "trim({expr})" function
14093 */
14094 static void
14095f_trim(typval_T *argvars, typval_T *rettv)
14096{
14097 char_u buf1[NUMBUFLEN];
14098 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014099 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014100 char_u *mask = NULL;
14101 char_u *tail;
14102 char_u *prev;
14103 char_u *p;
14104 int c1;
14105
14106 rettv->v_type = VAR_STRING;
14107 if (head == NULL)
14108 {
14109 rettv->vval.v_string = NULL;
14110 return;
14111 }
14112
14113 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014114 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014115
14116 while (*head != NUL)
14117 {
14118 c1 = PTR2CHAR(head);
14119 if (mask == NULL)
14120 {
14121 if (c1 > ' ' && c1 != 0xa0)
14122 break;
14123 }
14124 else
14125 {
14126 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14127 if (c1 == PTR2CHAR(p))
14128 break;
14129 if (*p == NUL)
14130 break;
14131 }
14132 MB_PTR_ADV(head);
14133 }
14134
14135 for (tail = head + STRLEN(head); tail > head; tail = prev)
14136 {
14137 prev = tail;
14138 MB_PTR_BACK(head, prev);
14139 c1 = PTR2CHAR(prev);
14140 if (mask == NULL)
14141 {
14142 if (c1 > ' ' && c1 != 0xa0)
14143 break;
14144 }
14145 else
14146 {
14147 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14148 if (c1 == PTR2CHAR(p))
14149 break;
14150 if (*p == NUL)
14151 break;
14152 }
14153 }
14154 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14155}
14156
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014157#ifdef FEAT_FLOAT
14158/*
14159 * "trunc({float})" function
14160 */
14161 static void
14162f_trunc(typval_T *argvars, typval_T *rettv)
14163{
14164 float_T f = 0.0;
14165
14166 rettv->v_type = VAR_FLOAT;
14167 if (get_float_arg(argvars, &f) == OK)
14168 /* trunc() is not in C90, use floor() or ceil() instead. */
14169 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14170 else
14171 rettv->vval.v_float = 0.0;
14172}
14173#endif
14174
14175/*
14176 * "type(expr)" function
14177 */
14178 static void
14179f_type(typval_T *argvars, typval_T *rettv)
14180{
14181 int n = -1;
14182
14183 switch (argvars[0].v_type)
14184 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014185 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14186 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014187 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014188 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14189 case VAR_LIST: n = VAR_TYPE_LIST; break;
14190 case VAR_DICT: n = VAR_TYPE_DICT; break;
14191 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014192 case VAR_SPECIAL:
14193 if (argvars[0].vval.v_number == VVAL_FALSE
14194 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014195 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014196 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014197 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014198 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014199 case VAR_JOB: n = VAR_TYPE_JOB; break;
14200 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014201 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014202 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014203 n = -1;
14204 break;
14205 }
14206 rettv->vval.v_number = n;
14207}
14208
14209/*
14210 * "undofile(name)" function
14211 */
14212 static void
14213f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14214{
14215 rettv->v_type = VAR_STRING;
14216#ifdef FEAT_PERSISTENT_UNDO
14217 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014218 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014219
14220 if (*fname == NUL)
14221 {
14222 /* If there is no file name there will be no undo file. */
14223 rettv->vval.v_string = NULL;
14224 }
14225 else
14226 {
14227 char_u *ffname = FullName_save(fname, FALSE);
14228
14229 if (ffname != NULL)
14230 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14231 vim_free(ffname);
14232 }
14233 }
14234#else
14235 rettv->vval.v_string = NULL;
14236#endif
14237}
14238
14239/*
14240 * "undotree()" function
14241 */
14242 static void
14243f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14244{
14245 if (rettv_dict_alloc(rettv) == OK)
14246 {
14247 dict_T *dict = rettv->vval.v_dict;
14248 list_T *list;
14249
Bram Moolenaare0be1672018-07-08 16:50:37 +020014250 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14251 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14252 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14253 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14254 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14255 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014256
14257 list = list_alloc();
14258 if (list != NULL)
14259 {
14260 u_eval_tree(curbuf->b_u_oldhead, list);
14261 dict_add_list(dict, "entries", list);
14262 }
14263 }
14264}
14265
14266/*
14267 * "values(dict)" function
14268 */
14269 static void
14270f_values(typval_T *argvars, typval_T *rettv)
14271{
14272 dict_list(argvars, rettv, 1);
14273}
14274
14275/*
14276 * "virtcol(string)" function
14277 */
14278 static void
14279f_virtcol(typval_T *argvars, typval_T *rettv)
14280{
14281 colnr_T vcol = 0;
14282 pos_T *fp;
14283 int fnum = curbuf->b_fnum;
14284
14285 fp = var2fpos(&argvars[0], FALSE, &fnum);
14286 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14287 && fnum == curbuf->b_fnum)
14288 {
14289 getvvcol(curwin, fp, NULL, NULL, &vcol);
14290 ++vcol;
14291 }
14292
14293 rettv->vval.v_number = vcol;
14294}
14295
14296/*
14297 * "visualmode()" function
14298 */
14299 static void
14300f_visualmode(typval_T *argvars, typval_T *rettv)
14301{
14302 char_u str[2];
14303
14304 rettv->v_type = VAR_STRING;
14305 str[0] = curbuf->b_visual_mode_eval;
14306 str[1] = NUL;
14307 rettv->vval.v_string = vim_strsave(str);
14308
14309 /* A non-zero number or non-empty string argument: reset mode. */
14310 if (non_zero_arg(&argvars[0]))
14311 curbuf->b_visual_mode_eval = NUL;
14312}
14313
14314/*
14315 * "wildmenumode()" function
14316 */
14317 static void
14318f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14319{
14320#ifdef FEAT_WILDMENU
14321 if (wild_menu_showing)
14322 rettv->vval.v_number = 1;
14323#endif
14324}
14325
14326/*
14327 * "winbufnr(nr)" function
14328 */
14329 static void
14330f_winbufnr(typval_T *argvars, typval_T *rettv)
14331{
14332 win_T *wp;
14333
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014334 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014335 if (wp == NULL)
14336 rettv->vval.v_number = -1;
14337 else
14338 rettv->vval.v_number = wp->w_buffer->b_fnum;
14339}
14340
14341/*
14342 * "wincol()" function
14343 */
14344 static void
14345f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14346{
14347 validate_cursor();
14348 rettv->vval.v_number = curwin->w_wcol + 1;
14349}
14350
14351/*
14352 * "winheight(nr)" function
14353 */
14354 static void
14355f_winheight(typval_T *argvars, typval_T *rettv)
14356{
14357 win_T *wp;
14358
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014359 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014360 if (wp == NULL)
14361 rettv->vval.v_number = -1;
14362 else
14363 rettv->vval.v_number = wp->w_height;
14364}
14365
14366/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014367 * "winlayout()" function
14368 */
14369 static void
14370f_winlayout(typval_T *argvars, typval_T *rettv)
14371{
14372 tabpage_T *tp;
14373
14374 if (rettv_list_alloc(rettv) != OK)
14375 return;
14376
14377 if (argvars[0].v_type == VAR_UNKNOWN)
14378 tp = curtab;
14379 else
14380 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014381 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014382 if (tp == NULL)
14383 return;
14384 }
14385
14386 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14387}
14388
14389/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014390 * "winline()" function
14391 */
14392 static void
14393f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14394{
14395 validate_cursor();
14396 rettv->vval.v_number = curwin->w_wrow + 1;
14397}
14398
14399/*
14400 * "winnr()" function
14401 */
14402 static void
14403f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14404{
14405 int nr = 1;
14406
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014407 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014408 rettv->vval.v_number = nr;
14409}
14410
14411/*
14412 * "winrestcmd()" function
14413 */
14414 static void
14415f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14416{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014417 win_T *wp;
14418 int winnr = 1;
14419 garray_T ga;
14420 char_u buf[50];
14421
14422 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014423 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014424 {
14425 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14426 ga_concat(&ga, buf);
14427 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14428 ga_concat(&ga, buf);
14429 ++winnr;
14430 }
14431 ga_append(&ga, NUL);
14432
14433 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014434 rettv->v_type = VAR_STRING;
14435}
14436
14437/*
14438 * "winrestview()" function
14439 */
14440 static void
14441f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14442{
14443 dict_T *dict;
14444
14445 if (argvars[0].v_type != VAR_DICT
14446 || (dict = argvars[0].vval.v_dict) == NULL)
14447 EMSG(_(e_invarg));
14448 else
14449 {
14450 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014451 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014452 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014453 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014454#ifdef FEAT_VIRTUALEDIT
14455 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014456 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014457#endif
14458 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14459 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014460 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014461 curwin->w_set_curswant = FALSE;
14462 }
14463
14464 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014465 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014466#ifdef FEAT_DIFF
14467 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014468 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014469#endif
14470 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014471 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014472 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014473 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014474
14475 check_cursor();
14476 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014477 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014478 changed_window_setting();
14479
14480 if (curwin->w_topline <= 0)
14481 curwin->w_topline = 1;
14482 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14483 curwin->w_topline = curbuf->b_ml.ml_line_count;
14484#ifdef FEAT_DIFF
14485 check_topfill(curwin, TRUE);
14486#endif
14487 }
14488}
14489
14490/*
14491 * "winsaveview()" function
14492 */
14493 static void
14494f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14495{
14496 dict_T *dict;
14497
14498 if (rettv_dict_alloc(rettv) == FAIL)
14499 return;
14500 dict = rettv->vval.v_dict;
14501
Bram Moolenaare0be1672018-07-08 16:50:37 +020014502 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14503 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014504#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020014505 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014506#endif
14507 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014508 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014509
Bram Moolenaare0be1672018-07-08 16:50:37 +020014510 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014511#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014512 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014513#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014514 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14515 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014516}
14517
14518/*
14519 * "winwidth(nr)" function
14520 */
14521 static void
14522f_winwidth(typval_T *argvars, typval_T *rettv)
14523{
14524 win_T *wp;
14525
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014526 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014527 if (wp == NULL)
14528 rettv->vval.v_number = -1;
14529 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014530 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014531}
14532
14533/*
14534 * "wordcount()" function
14535 */
14536 static void
14537f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14538{
14539 if (rettv_dict_alloc(rettv) == FAIL)
14540 return;
14541 cursor_pos_info(rettv->vval.v_dict);
14542}
14543
14544/*
14545 * "writefile()" function
14546 */
14547 static void
14548f_writefile(typval_T *argvars, typval_T *rettv)
14549{
14550 int binary = FALSE;
14551 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014552#ifdef HAVE_FSYNC
14553 int do_fsync = p_fs;
14554#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014555 char_u *fname;
14556 FILE *fd;
14557 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014558 listitem_T *li;
14559 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014560
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014561 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014562 if (check_restricted() || check_secure())
14563 return;
14564
14565 if (argvars[0].v_type != VAR_LIST)
14566 {
14567 EMSG2(_(e_listarg), "writefile()");
14568 return;
14569 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014570 list = argvars[0].vval.v_list;
14571 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014572 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014573 for (li = list->lv_first; li != NULL; li = li->li_next)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014574 if (tv_get_string_chk(&li->li_tv) == NULL)
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014575 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014576
14577 if (argvars[2].v_type != VAR_UNKNOWN)
14578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014579 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014580
14581 if (arg2 == NULL)
14582 return;
14583 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014584 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014585 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014586 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014587#ifdef HAVE_FSYNC
14588 if (vim_strchr(arg2, 's') != NULL)
14589 do_fsync = TRUE;
14590 else if (vim_strchr(arg2, 'S') != NULL)
14591 do_fsync = FALSE;
14592#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014593 }
14594
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014595 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014596 if (fname == NULL)
14597 return;
14598
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014599 /* Always open the file in binary mode, library functions have a mind of
14600 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014601 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14602 append ? APPENDBIN : WRITEBIN)) == NULL)
14603 {
14604 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14605 ret = -1;
14606 }
14607 else
14608 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014609 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014610 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014611#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014612 else if (do_fsync)
14613 /* Ignore the error, the user wouldn't know what to do about it.
14614 * May happen for a device. */
Bram Moolenaar42335f52018-09-13 15:33:43 +020014615 vim_ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014616#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014617 fclose(fd);
14618 }
14619
14620 rettv->vval.v_number = ret;
14621}
14622
14623/*
14624 * "xor(expr, expr)" function
14625 */
14626 static void
14627f_xor(typval_T *argvars, typval_T *rettv)
14628{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014629 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14630 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014631}
14632
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014633#endif /* FEAT_EVAL */