blob: a9a92d2ee30fe463c73862cbe0884ed9b4938d25 [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
1922/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001923 * Get the buffer from "arg" and give an error and return NULL if it is not
1924 * valid.
1925 */
1926 static buf_T *
1927get_buf_arg(typval_T *arg)
1928{
1929 buf_T *buf;
1930
1931 ++emsg_off;
1932 buf = tv_get_buf(arg, FALSE);
1933 --emsg_off;
1934 if (buf == NULL)
1935 EMSG2(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
1936 return buf;
1937}
1938
1939/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001940 * "bufname(expr)" function
1941 */
1942 static void
1943f_bufname(typval_T *argvars, typval_T *rettv)
1944{
1945 buf_T *buf;
1946
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001947 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001948 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001949 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001950 rettv->v_type = VAR_STRING;
1951 if (buf != NULL && buf->b_fname != NULL)
1952 rettv->vval.v_string = vim_strsave(buf->b_fname);
1953 else
1954 rettv->vval.v_string = NULL;
1955 --emsg_off;
1956}
1957
1958/*
1959 * "bufnr(expr)" function
1960 */
1961 static void
1962f_bufnr(typval_T *argvars, typval_T *rettv)
1963{
1964 buf_T *buf;
1965 int error = FALSE;
1966 char_u *name;
1967
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001968 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001969 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001970 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001971 --emsg_off;
1972
1973 /* If the buffer isn't found and the second argument is not zero create a
1974 * new buffer. */
1975 if (buf == NULL
1976 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001977 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001979 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 && !error)
1981 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1982
1983 if (buf != NULL)
1984 rettv->vval.v_number = buf->b_fnum;
1985 else
1986 rettv->vval.v_number = -1;
1987}
1988
1989 static void
1990buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1991{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001992 win_T *wp;
1993 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001994 buf_T *buf;
1995
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001996 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001997 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001998 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001999 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002000 {
2001 ++winnr;
2002 if (wp->w_buffer == buf)
2003 break;
2004 }
2005 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006 --emsg_off;
2007}
2008
2009/*
2010 * "bufwinid(nr)" function
2011 */
2012 static void
2013f_bufwinid(typval_T *argvars, typval_T *rettv)
2014{
2015 buf_win_common(argvars, rettv, FALSE);
2016}
2017
2018/*
2019 * "bufwinnr(nr)" function
2020 */
2021 static void
2022f_bufwinnr(typval_T *argvars, typval_T *rettv)
2023{
2024 buf_win_common(argvars, rettv, TRUE);
2025}
2026
2027/*
2028 * "byte2line(byte)" function
2029 */
2030 static void
2031f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2032{
2033#ifndef FEAT_BYTEOFF
2034 rettv->vval.v_number = -1;
2035#else
2036 long boff = 0;
2037
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002038 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039 if (boff < 0)
2040 rettv->vval.v_number = -1;
2041 else
2042 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2043 (linenr_T)0, &boff);
2044#endif
2045}
2046
2047 static void
2048byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2049{
2050#ifdef FEAT_MBYTE
2051 char_u *t;
2052#endif
2053 char_u *str;
2054 varnumber_T idx;
2055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002056 str = tv_get_string_chk(&argvars[0]);
2057 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058 rettv->vval.v_number = -1;
2059 if (str == NULL || idx < 0)
2060 return;
2061
2062#ifdef FEAT_MBYTE
2063 t = str;
2064 for ( ; idx > 0; idx--)
2065 {
2066 if (*t == NUL) /* EOL reached */
2067 return;
2068 if (enc_utf8 && comp)
2069 t += utf_ptr2len(t);
2070 else
2071 t += (*mb_ptr2len)(t);
2072 }
2073 rettv->vval.v_number = (varnumber_T)(t - str);
2074#else
2075 if ((size_t)idx <= STRLEN(str))
2076 rettv->vval.v_number = idx;
2077#endif
2078}
2079
2080/*
2081 * "byteidx()" function
2082 */
2083 static void
2084f_byteidx(typval_T *argvars, typval_T *rettv)
2085{
2086 byteidx(argvars, rettv, FALSE);
2087}
2088
2089/*
2090 * "byteidxcomp()" function
2091 */
2092 static void
2093f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2094{
2095 byteidx(argvars, rettv, TRUE);
2096}
2097
2098/*
2099 * "call(func, arglist [, dict])" function
2100 */
2101 static void
2102f_call(typval_T *argvars, typval_T *rettv)
2103{
2104 char_u *func;
2105 partial_T *partial = NULL;
2106 dict_T *selfdict = NULL;
2107
2108 if (argvars[1].v_type != VAR_LIST)
2109 {
2110 EMSG(_(e_listreq));
2111 return;
2112 }
2113 if (argvars[1].vval.v_list == NULL)
2114 return;
2115
2116 if (argvars[0].v_type == VAR_FUNC)
2117 func = argvars[0].vval.v_string;
2118 else if (argvars[0].v_type == VAR_PARTIAL)
2119 {
2120 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002121 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 }
2123 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002124 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002125 if (*func == NUL)
2126 return; /* type error or empty name */
2127
2128 if (argvars[2].v_type != VAR_UNKNOWN)
2129 {
2130 if (argvars[2].v_type != VAR_DICT)
2131 {
2132 EMSG(_(e_dictreq));
2133 return;
2134 }
2135 selfdict = argvars[2].vval.v_dict;
2136 }
2137
2138 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2139}
2140
2141#ifdef FEAT_FLOAT
2142/*
2143 * "ceil({float})" function
2144 */
2145 static void
2146f_ceil(typval_T *argvars, typval_T *rettv)
2147{
2148 float_T f = 0.0;
2149
2150 rettv->v_type = VAR_FLOAT;
2151 if (get_float_arg(argvars, &f) == OK)
2152 rettv->vval.v_float = ceil(f);
2153 else
2154 rettv->vval.v_float = 0.0;
2155}
2156#endif
2157
2158#ifdef FEAT_JOB_CHANNEL
2159/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002160 * "ch_canread()" function
2161 */
2162 static void
2163f_ch_canread(typval_T *argvars, typval_T *rettv)
2164{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002165 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002166
2167 rettv->vval.v_number = 0;
2168 if (channel != NULL)
2169 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2170 || channel_has_readahead(channel, PART_OUT)
2171 || channel_has_readahead(channel, PART_ERR);
2172}
2173
2174/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 * "ch_close()" function
2176 */
2177 static void
2178f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2179{
2180 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2181
2182 if (channel != NULL)
2183 {
2184 channel_close(channel, FALSE);
2185 channel_clear(channel);
2186 }
2187}
2188
2189/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002190 * "ch_close()" function
2191 */
2192 static void
2193f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2194{
2195 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2196
2197 if (channel != NULL)
2198 channel_close_in(channel);
2199}
2200
2201/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002202 * "ch_getbufnr()" function
2203 */
2204 static void
2205f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2206{
2207 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2208
2209 rettv->vval.v_number = -1;
2210 if (channel != NULL)
2211 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002212 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002213 int part;
2214
2215 if (STRCMP(what, "err") == 0)
2216 part = PART_ERR;
2217 else if (STRCMP(what, "out") == 0)
2218 part = PART_OUT;
2219 else if (STRCMP(what, "in") == 0)
2220 part = PART_IN;
2221 else
2222 part = PART_SOCK;
2223 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2224 rettv->vval.v_number =
2225 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2226 }
2227}
2228
2229/*
2230 * "ch_getjob()" function
2231 */
2232 static void
2233f_ch_getjob(typval_T *argvars, typval_T *rettv)
2234{
2235 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2236
2237 if (channel != NULL)
2238 {
2239 rettv->v_type = VAR_JOB;
2240 rettv->vval.v_job = channel->ch_job;
2241 if (channel->ch_job != NULL)
2242 ++channel->ch_job->jv_refcount;
2243 }
2244}
2245
2246/*
2247 * "ch_info()" function
2248 */
2249 static void
2250f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2251{
2252 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2253
2254 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2255 channel_info(channel, rettv->vval.v_dict);
2256}
2257
2258/*
2259 * "ch_log()" function
2260 */
2261 static void
2262f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2263{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002264 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002265 channel_T *channel = NULL;
2266
2267 if (argvars[1].v_type != VAR_UNKNOWN)
2268 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2269
Bram Moolenaard5359b22018-04-05 22:44:39 +02002270 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002271}
2272
2273/*
2274 * "ch_logfile()" function
2275 */
2276 static void
2277f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2278{
2279 char_u *fname;
2280 char_u *opt = (char_u *)"";
2281 char_u buf[NUMBUFLEN];
2282
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002283 /* Don't open a file in restricted mode. */
2284 if (check_restricted() || check_secure())
2285 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002286 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002287 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002288 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002289 ch_logfile(fname, opt);
2290}
2291
2292/*
2293 * "ch_open()" function
2294 */
2295 static void
2296f_ch_open(typval_T *argvars, typval_T *rettv)
2297{
2298 rettv->v_type = VAR_CHANNEL;
2299 if (check_restricted() || check_secure())
2300 return;
2301 rettv->vval.v_channel = channel_open_func(argvars);
2302}
2303
2304/*
2305 * "ch_read()" function
2306 */
2307 static void
2308f_ch_read(typval_T *argvars, typval_T *rettv)
2309{
2310 common_channel_read(argvars, rettv, FALSE);
2311}
2312
2313/*
2314 * "ch_readraw()" function
2315 */
2316 static void
2317f_ch_readraw(typval_T *argvars, typval_T *rettv)
2318{
2319 common_channel_read(argvars, rettv, TRUE);
2320}
2321
2322/*
2323 * "ch_evalexpr()" function
2324 */
2325 static void
2326f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2327{
2328 ch_expr_common(argvars, rettv, TRUE);
2329}
2330
2331/*
2332 * "ch_sendexpr()" function
2333 */
2334 static void
2335f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2336{
2337 ch_expr_common(argvars, rettv, FALSE);
2338}
2339
2340/*
2341 * "ch_evalraw()" function
2342 */
2343 static void
2344f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2345{
2346 ch_raw_common(argvars, rettv, TRUE);
2347}
2348
2349/*
2350 * "ch_sendraw()" function
2351 */
2352 static void
2353f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2354{
2355 ch_raw_common(argvars, rettv, FALSE);
2356}
2357
2358/*
2359 * "ch_setoptions()" function
2360 */
2361 static void
2362f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2363{
2364 channel_T *channel;
2365 jobopt_T opt;
2366
2367 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2368 if (channel == NULL)
2369 return;
2370 clear_job_options(&opt);
2371 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002372 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002373 channel_set_options(channel, &opt);
2374 free_job_options(&opt);
2375}
2376
2377/*
2378 * "ch_status()" function
2379 */
2380 static void
2381f_ch_status(typval_T *argvars, typval_T *rettv)
2382{
2383 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002384 jobopt_T opt;
2385 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002386
2387 /* return an empty string by default */
2388 rettv->v_type = VAR_STRING;
2389 rettv->vval.v_string = NULL;
2390
2391 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002392
2393 if (argvars[1].v_type != VAR_UNKNOWN)
2394 {
2395 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002396 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002397 && (opt.jo_set & JO_PART))
2398 part = opt.jo_part;
2399 }
2400
2401 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002402}
2403#endif
2404
2405/*
2406 * "changenr()" function
2407 */
2408 static void
2409f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2410{
2411 rettv->vval.v_number = curbuf->b_u_seq_cur;
2412}
2413
2414/*
2415 * "char2nr(string)" function
2416 */
2417 static void
2418f_char2nr(typval_T *argvars, typval_T *rettv)
2419{
2420#ifdef FEAT_MBYTE
2421 if (has_mbyte)
2422 {
2423 int utf8 = 0;
2424
2425 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002426 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002427
2428 if (utf8)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002429 rettv->vval.v_number = (*utf_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002430 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002431 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432 }
2433 else
2434#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002435 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436}
2437
2438/*
2439 * "cindent(lnum)" function
2440 */
2441 static void
2442f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2443{
2444#ifdef FEAT_CINDENT
2445 pos_T pos;
2446 linenr_T lnum;
2447
2448 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002449 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2451 {
2452 curwin->w_cursor.lnum = lnum;
2453 rettv->vval.v_number = get_c_indent();
2454 curwin->w_cursor = pos;
2455 }
2456 else
2457#endif
2458 rettv->vval.v_number = -1;
2459}
2460
2461/*
2462 * "clearmatches()" function
2463 */
2464 static void
2465f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2466{
2467#ifdef FEAT_SEARCH_EXTRA
2468 clear_matches(curwin);
2469#endif
2470}
2471
2472/*
2473 * "col(string)" function
2474 */
2475 static void
2476f_col(typval_T *argvars, typval_T *rettv)
2477{
2478 colnr_T col = 0;
2479 pos_T *fp;
2480 int fnum = curbuf->b_fnum;
2481
2482 fp = var2fpos(&argvars[0], FALSE, &fnum);
2483 if (fp != NULL && fnum == curbuf->b_fnum)
2484 {
2485 if (fp->col == MAXCOL)
2486 {
2487 /* '> can be MAXCOL, get the length of the line then */
2488 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2489 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2490 else
2491 col = MAXCOL;
2492 }
2493 else
2494 {
2495 col = fp->col + 1;
2496#ifdef FEAT_VIRTUALEDIT
2497 /* col(".") when the cursor is on the NUL at the end of the line
2498 * because of "coladd" can be seen as an extra column. */
2499 if (virtual_active() && fp == &curwin->w_cursor)
2500 {
2501 char_u *p = ml_get_cursor();
2502
2503 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2504 curwin->w_virtcol - curwin->w_cursor.coladd))
2505 {
2506# ifdef FEAT_MBYTE
2507 int l;
2508
2509 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2510 col += l;
2511# else
2512 if (*p != NUL && p[1] == NUL)
2513 ++col;
2514# endif
2515 }
2516 }
2517#endif
2518 }
2519 }
2520 rettv->vval.v_number = col;
2521}
2522
2523#if defined(FEAT_INS_EXPAND)
2524/*
2525 * "complete()" function
2526 */
2527 static void
2528f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2529{
2530 int startcol;
2531
2532 if ((State & INSERT) == 0)
2533 {
2534 EMSG(_("E785: complete() can only be used in Insert mode"));
2535 return;
2536 }
2537
2538 /* Check for undo allowed here, because if something was already inserted
2539 * the line was already saved for undo and this check isn't done. */
2540 if (!undo_allowed())
2541 return;
2542
2543 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2544 {
2545 EMSG(_(e_invarg));
2546 return;
2547 }
2548
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002549 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002550 if (startcol <= 0)
2551 return;
2552
2553 set_completion(startcol - 1, argvars[1].vval.v_list);
2554}
2555
2556/*
2557 * "complete_add()" function
2558 */
2559 static void
2560f_complete_add(typval_T *argvars, typval_T *rettv)
2561{
2562 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2563}
2564
2565/*
2566 * "complete_check()" function
2567 */
2568 static void
2569f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2570{
2571 int saved = RedrawingDisabled;
2572
2573 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002574 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002575 rettv->vval.v_number = compl_interrupted;
2576 RedrawingDisabled = saved;
2577}
2578#endif
2579
2580/*
2581 * "confirm(message, buttons[, default [, type]])" function
2582 */
2583 static void
2584f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2585{
2586#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2587 char_u *message;
2588 char_u *buttons = NULL;
2589 char_u buf[NUMBUFLEN];
2590 char_u buf2[NUMBUFLEN];
2591 int def = 1;
2592 int type = VIM_GENERIC;
2593 char_u *typestr;
2594 int error = FALSE;
2595
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002596 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002597 if (message == NULL)
2598 error = TRUE;
2599 if (argvars[1].v_type != VAR_UNKNOWN)
2600 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002601 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 if (buttons == NULL)
2603 error = TRUE;
2604 if (argvars[2].v_type != VAR_UNKNOWN)
2605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002606 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002607 if (argvars[3].v_type != VAR_UNKNOWN)
2608 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002609 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002610 if (typestr == NULL)
2611 error = TRUE;
2612 else
2613 {
2614 switch (TOUPPER_ASC(*typestr))
2615 {
2616 case 'E': type = VIM_ERROR; break;
2617 case 'Q': type = VIM_QUESTION; break;
2618 case 'I': type = VIM_INFO; break;
2619 case 'W': type = VIM_WARNING; break;
2620 case 'G': type = VIM_GENERIC; break;
2621 }
2622 }
2623 }
2624 }
2625 }
2626
2627 if (buttons == NULL || *buttons == NUL)
2628 buttons = (char_u *)_("&Ok");
2629
2630 if (!error)
2631 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2632 def, NULL, FALSE);
2633#endif
2634}
2635
2636/*
2637 * "copy()" function
2638 */
2639 static void
2640f_copy(typval_T *argvars, typval_T *rettv)
2641{
2642 item_copy(&argvars[0], rettv, FALSE, 0);
2643}
2644
2645#ifdef FEAT_FLOAT
2646/*
2647 * "cos()" function
2648 */
2649 static void
2650f_cos(typval_T *argvars, typval_T *rettv)
2651{
2652 float_T f = 0.0;
2653
2654 rettv->v_type = VAR_FLOAT;
2655 if (get_float_arg(argvars, &f) == OK)
2656 rettv->vval.v_float = cos(f);
2657 else
2658 rettv->vval.v_float = 0.0;
2659}
2660
2661/*
2662 * "cosh()" function
2663 */
2664 static void
2665f_cosh(typval_T *argvars, typval_T *rettv)
2666{
2667 float_T f = 0.0;
2668
2669 rettv->v_type = VAR_FLOAT;
2670 if (get_float_arg(argvars, &f) == OK)
2671 rettv->vval.v_float = cosh(f);
2672 else
2673 rettv->vval.v_float = 0.0;
2674}
2675#endif
2676
2677/*
2678 * "count()" function
2679 */
2680 static void
2681f_count(typval_T *argvars, typval_T *rettv)
2682{
2683 long n = 0;
2684 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002685 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002686
Bram Moolenaar9966b212017-07-28 16:46:57 +02002687 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002688 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002689
2690 if (argvars[0].v_type == VAR_STRING)
2691 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002692 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002693 char_u *p = argvars[0].vval.v_string;
2694 char_u *next;
2695
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002696 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002697 {
2698 if (ic)
2699 {
2700 size_t len = STRLEN(expr);
2701
2702 while (*p != NUL)
2703 {
2704 if (MB_STRNICMP(p, expr, len) == 0)
2705 {
2706 ++n;
2707 p += len;
2708 }
2709 else
2710 MB_PTR_ADV(p);
2711 }
2712 }
2713 else
2714 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2715 != NULL)
2716 {
2717 ++n;
2718 p = next + STRLEN(expr);
2719 }
2720 }
2721
2722 }
2723 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002724 {
2725 listitem_T *li;
2726 list_T *l;
2727 long idx;
2728
2729 if ((l = argvars[0].vval.v_list) != NULL)
2730 {
2731 li = l->lv_first;
2732 if (argvars[2].v_type != VAR_UNKNOWN)
2733 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002734 if (argvars[3].v_type != VAR_UNKNOWN)
2735 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002736 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002737 if (!error)
2738 {
2739 li = list_find(l, idx);
2740 if (li == NULL)
2741 EMSGN(_(e_listidx), idx);
2742 }
2743 }
2744 if (error)
2745 li = NULL;
2746 }
2747
2748 for ( ; li != NULL; li = li->li_next)
2749 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2750 ++n;
2751 }
2752 }
2753 else if (argvars[0].v_type == VAR_DICT)
2754 {
2755 int todo;
2756 dict_T *d;
2757 hashitem_T *hi;
2758
2759 if ((d = argvars[0].vval.v_dict) != NULL)
2760 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002761 if (argvars[2].v_type != VAR_UNKNOWN)
2762 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 if (argvars[3].v_type != VAR_UNKNOWN)
2764 EMSG(_(e_invarg));
2765 }
2766
2767 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2768 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2769 {
2770 if (!HASHITEM_EMPTY(hi))
2771 {
2772 --todo;
2773 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2774 ++n;
2775 }
2776 }
2777 }
2778 }
2779 else
2780 EMSG2(_(e_listdictarg), "count()");
2781 rettv->vval.v_number = n;
2782}
2783
2784/*
2785 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2786 *
2787 * Checks the existence of a cscope connection.
2788 */
2789 static void
2790f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2791{
2792#ifdef FEAT_CSCOPE
2793 int num = 0;
2794 char_u *dbpath = NULL;
2795 char_u *prepend = NULL;
2796 char_u buf[NUMBUFLEN];
2797
2798 if (argvars[0].v_type != VAR_UNKNOWN
2799 && argvars[1].v_type != VAR_UNKNOWN)
2800 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002801 num = (int)tv_get_number(&argvars[0]);
2802 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002803 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002804 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002805 }
2806
2807 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2808#endif
2809}
2810
2811/*
2812 * "cursor(lnum, col)" function, or
2813 * "cursor(list)"
2814 *
2815 * Moves the cursor to the specified line and column.
2816 * Returns 0 when the position could be set, -1 otherwise.
2817 */
2818 static void
2819f_cursor(typval_T *argvars, typval_T *rettv)
2820{
2821 long line, col;
2822#ifdef FEAT_VIRTUALEDIT
2823 long coladd = 0;
2824#endif
2825 int set_curswant = TRUE;
2826
2827 rettv->vval.v_number = -1;
2828 if (argvars[1].v_type == VAR_UNKNOWN)
2829 {
2830 pos_T pos;
2831 colnr_T curswant = -1;
2832
2833 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2834 {
2835 EMSG(_(e_invarg));
2836 return;
2837 }
2838 line = pos.lnum;
2839 col = pos.col;
2840#ifdef FEAT_VIRTUALEDIT
2841 coladd = pos.coladd;
2842#endif
2843 if (curswant >= 0)
2844 {
2845 curwin->w_curswant = curswant - 1;
2846 set_curswant = FALSE;
2847 }
2848 }
2849 else
2850 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002851 line = tv_get_lnum(argvars);
2852 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002853#ifdef FEAT_VIRTUALEDIT
2854 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002855 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002856#endif
2857 }
2858 if (line < 0 || col < 0
2859#ifdef FEAT_VIRTUALEDIT
2860 || coladd < 0
2861#endif
2862 )
2863 return; /* type error; errmsg already given */
2864 if (line > 0)
2865 curwin->w_cursor.lnum = line;
2866 if (col > 0)
2867 curwin->w_cursor.col = col - 1;
2868#ifdef FEAT_VIRTUALEDIT
2869 curwin->w_cursor.coladd = coladd;
2870#endif
2871
2872 /* Make sure the cursor is in a valid position. */
2873 check_cursor();
2874#ifdef FEAT_MBYTE
2875 /* Correct cursor for multi-byte character. */
2876 if (has_mbyte)
2877 mb_adjust_cursor();
2878#endif
2879
2880 curwin->w_set_curswant = set_curswant;
2881 rettv->vval.v_number = 0;
2882}
2883
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002884#ifdef WIN3264
2885/*
2886 * "debugbreak()" function
2887 */
2888 static void
2889f_debugbreak(typval_T *argvars, typval_T *rettv)
2890{
2891 int pid;
2892
2893 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002894 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002895 if (pid == 0)
2896 EMSG(_(e_invarg));
2897 else
2898 {
2899 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2900
2901 if (hProcess != NULL)
2902 {
2903 DebugBreakProcess(hProcess);
2904 CloseHandle(hProcess);
2905 rettv->vval.v_number = OK;
2906 }
2907 }
2908}
2909#endif
2910
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002911/*
2912 * "deepcopy()" function
2913 */
2914 static void
2915f_deepcopy(typval_T *argvars, typval_T *rettv)
2916{
2917 int noref = 0;
2918 int copyID;
2919
2920 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002921 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922 if (noref < 0 || noref > 1)
2923 EMSG(_(e_invarg));
2924 else
2925 {
2926 copyID = get_copyID();
2927 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2928 }
2929}
2930
2931/*
2932 * "delete()" function
2933 */
2934 static void
2935f_delete(typval_T *argvars, typval_T *rettv)
2936{
2937 char_u nbuf[NUMBUFLEN];
2938 char_u *name;
2939 char_u *flags;
2940
2941 rettv->vval.v_number = -1;
2942 if (check_restricted() || check_secure())
2943 return;
2944
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002945 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002946 if (name == NULL || *name == NUL)
2947 {
2948 EMSG(_(e_invarg));
2949 return;
2950 }
2951
2952 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002953 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002954 else
2955 flags = (char_u *)"";
2956
2957 if (*flags == NUL)
2958 /* delete a file */
2959 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2960 else if (STRCMP(flags, "d") == 0)
2961 /* delete an empty directory */
2962 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2963 else if (STRCMP(flags, "rf") == 0)
2964 /* delete a directory recursively */
2965 rettv->vval.v_number = delete_recursive(name);
2966 else
2967 EMSG2(_(e_invexpr2), flags);
2968}
2969
2970/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002971 * "deletebufline()" function
2972 */
2973 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002974f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002975{
2976 buf_T *buf;
2977 linenr_T first, last;
2978 linenr_T lnum;
2979 long count;
2980 int is_curbuf;
2981 buf_T *curbuf_save = NULL;
2982 win_T *curwin_save = NULL;
2983 tabpage_T *tp;
2984 win_T *wp;
2985
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002986 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002987 if (buf == NULL)
2988 {
2989 rettv->vval.v_number = 1; /* FAIL */
2990 return;
2991 }
2992 is_curbuf = buf == curbuf;
2993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002994 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002995 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002996 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002997 else
2998 last = first;
2999
3000 if (buf->b_ml.ml_mfp == NULL || first < 1
3001 || first > buf->b_ml.ml_line_count || last < first)
3002 {
3003 rettv->vval.v_number = 1; /* FAIL */
3004 return;
3005 }
3006
3007 if (!is_curbuf)
3008 {
3009 curbuf_save = curbuf;
3010 curwin_save = curwin;
3011 curbuf = buf;
3012 find_win_for_curbuf();
3013 }
3014 if (last > curbuf->b_ml.ml_line_count)
3015 last = curbuf->b_ml.ml_line_count;
3016 count = last - first + 1;
3017
3018 // When coming here from Insert mode, sync undo, so that this can be
3019 // undone separately from what was previously inserted.
3020 if (u_sync_once == 2)
3021 {
3022 u_sync_once = 1; // notify that u_sync() was called
3023 u_sync(TRUE);
3024 }
3025
3026 if (u_save(first - 1, last + 1) == FAIL)
3027 {
3028 rettv->vval.v_number = 1; /* FAIL */
3029 return;
3030 }
3031
3032 for (lnum = first; lnum <= last; ++lnum)
3033 ml_delete(first, TRUE);
3034
3035 FOR_ALL_TAB_WINDOWS(tp, wp)
3036 if (wp->w_buffer == buf)
3037 {
3038 if (wp->w_cursor.lnum > last)
3039 wp->w_cursor.lnum -= count;
3040 else if (wp->w_cursor.lnum> first)
3041 wp->w_cursor.lnum = first;
3042 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3043 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3044 }
3045 check_cursor_col();
3046 deleted_lines_mark(first, count);
3047
3048 if (!is_curbuf)
3049 {
3050 curbuf = curbuf_save;
3051 curwin = curwin_save;
3052 }
3053}
3054
3055/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003056 * "did_filetype()" function
3057 */
3058 static void
3059f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3060{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003061 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062}
3063
3064/*
3065 * "diff_filler()" function
3066 */
3067 static void
3068f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3069{
3070#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003071 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003072#endif
3073}
3074
3075/*
3076 * "diff_hlID()" function
3077 */
3078 static void
3079f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3080{
3081#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003082 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003084 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003085 static int fnum = 0;
3086 static int change_start = 0;
3087 static int change_end = 0;
3088 static hlf_T hlID = (hlf_T)0;
3089 int filler_lines;
3090 int col;
3091
3092 if (lnum < 0) /* ignore type error in {lnum} arg */
3093 lnum = 0;
3094 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003095 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 || fnum != curbuf->b_fnum)
3097 {
3098 /* New line, buffer, change: need to get the values. */
3099 filler_lines = diff_check(curwin, lnum);
3100 if (filler_lines < 0)
3101 {
3102 if (filler_lines == -1)
3103 {
3104 change_start = MAXCOL;
3105 change_end = -1;
3106 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3107 hlID = HLF_ADD; /* added line */
3108 else
3109 hlID = HLF_CHD; /* changed line */
3110 }
3111 else
3112 hlID = HLF_ADD; /* added line */
3113 }
3114 else
3115 hlID = (hlf_T)0;
3116 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003117 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003118 fnum = curbuf->b_fnum;
3119 }
3120
3121 if (hlID == HLF_CHD || hlID == HLF_TXD)
3122 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003123 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003124 if (col >= change_start && col <= change_end)
3125 hlID = HLF_TXD; /* changed text */
3126 else
3127 hlID = HLF_CHD; /* changed line */
3128 }
3129 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3130#endif
3131}
3132
3133/*
3134 * "empty({expr})" function
3135 */
3136 static void
3137f_empty(typval_T *argvars, typval_T *rettv)
3138{
3139 int n = FALSE;
3140
3141 switch (argvars[0].v_type)
3142 {
3143 case VAR_STRING:
3144 case VAR_FUNC:
3145 n = argvars[0].vval.v_string == NULL
3146 || *argvars[0].vval.v_string == NUL;
3147 break;
3148 case VAR_PARTIAL:
3149 n = FALSE;
3150 break;
3151 case VAR_NUMBER:
3152 n = argvars[0].vval.v_number == 0;
3153 break;
3154 case VAR_FLOAT:
3155#ifdef FEAT_FLOAT
3156 n = argvars[0].vval.v_float == 0.0;
3157 break;
3158#endif
3159 case VAR_LIST:
3160 n = argvars[0].vval.v_list == NULL
3161 || argvars[0].vval.v_list->lv_first == NULL;
3162 break;
3163 case VAR_DICT:
3164 n = argvars[0].vval.v_dict == NULL
3165 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3166 break;
3167 case VAR_SPECIAL:
3168 n = argvars[0].vval.v_number != VVAL_TRUE;
3169 break;
3170
3171 case VAR_JOB:
3172#ifdef FEAT_JOB_CHANNEL
3173 n = argvars[0].vval.v_job == NULL
3174 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3175 break;
3176#endif
3177 case VAR_CHANNEL:
3178#ifdef FEAT_JOB_CHANNEL
3179 n = argvars[0].vval.v_channel == NULL
3180 || !channel_is_open(argvars[0].vval.v_channel);
3181 break;
3182#endif
3183 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003184 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003185 n = TRUE;
3186 break;
3187 }
3188
3189 rettv->vval.v_number = n;
3190}
3191
3192/*
3193 * "escape({string}, {chars})" function
3194 */
3195 static void
3196f_escape(typval_T *argvars, typval_T *rettv)
3197{
3198 char_u buf[NUMBUFLEN];
3199
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003200 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3201 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003202 rettv->v_type = VAR_STRING;
3203}
3204
3205/*
3206 * "eval()" function
3207 */
3208 static void
3209f_eval(typval_T *argvars, typval_T *rettv)
3210{
3211 char_u *s, *p;
3212
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003213 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003214 if (s != NULL)
3215 s = skipwhite(s);
3216
3217 p = s;
3218 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3219 {
3220 if (p != NULL && !aborting())
3221 EMSG2(_(e_invexpr2), p);
3222 need_clr_eos = FALSE;
3223 rettv->v_type = VAR_NUMBER;
3224 rettv->vval.v_number = 0;
3225 }
3226 else if (*s != NUL)
3227 EMSG(_(e_trailing));
3228}
3229
3230/*
3231 * "eventhandler()" function
3232 */
3233 static void
3234f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3235{
3236 rettv->vval.v_number = vgetc_busy;
3237}
3238
3239/*
3240 * "executable()" function
3241 */
3242 static void
3243f_executable(typval_T *argvars, typval_T *rettv)
3244{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003245 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003246
3247 /* Check in $PATH and also check directly if there is a directory name. */
3248 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3249 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3250}
3251
3252static garray_T redir_execute_ga;
3253
3254/*
3255 * Append "value[value_len]" to the execute() output.
3256 */
3257 void
3258execute_redir_str(char_u *value, int value_len)
3259{
3260 int len;
3261
3262 if (value_len == -1)
3263 len = (int)STRLEN(value); /* Append the entire string */
3264 else
3265 len = value_len; /* Append only "value_len" characters */
3266 if (ga_grow(&redir_execute_ga, len) == OK)
3267 {
3268 mch_memmove((char *)redir_execute_ga.ga_data
3269 + redir_execute_ga.ga_len, value, len);
3270 redir_execute_ga.ga_len += len;
3271 }
3272}
3273
3274/*
3275 * Get next line from a list.
3276 * Called by do_cmdline() to get the next line.
3277 * Returns allocated string, or NULL for end of function.
3278 */
3279
3280 static char_u *
3281get_list_line(
3282 int c UNUSED,
3283 void *cookie,
3284 int indent UNUSED)
3285{
3286 listitem_T **p = (listitem_T **)cookie;
3287 listitem_T *item = *p;
3288 char_u buf[NUMBUFLEN];
3289 char_u *s;
3290
3291 if (item == NULL)
3292 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003293 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003294 *p = item->li_next;
3295 return s == NULL ? NULL : vim_strsave(s);
3296}
3297
3298/*
3299 * "execute()" function
3300 */
3301 static void
3302f_execute(typval_T *argvars, typval_T *rettv)
3303{
3304 char_u *cmd = NULL;
3305 list_T *list = NULL;
3306 int save_msg_silent = msg_silent;
3307 int save_emsg_silent = emsg_silent;
3308 int save_emsg_noredir = emsg_noredir;
3309 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003310 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003311 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003312 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003313 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003314
3315 rettv->vval.v_string = NULL;
3316 rettv->v_type = VAR_STRING;
3317
3318 if (argvars[0].v_type == VAR_LIST)
3319 {
3320 list = argvars[0].vval.v_list;
3321 if (list == NULL || list->lv_first == NULL)
3322 /* empty list, no commands, empty output */
3323 return;
3324 ++list->lv_refcount;
3325 }
3326 else
3327 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003328 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003329 if (cmd == NULL)
3330 return;
3331 }
3332
3333 if (argvars[1].v_type != VAR_UNKNOWN)
3334 {
3335 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003336 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003337
3338 if (s == NULL)
3339 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003340 if (*s == NUL)
3341 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342 if (STRNCMP(s, "silent", 6) == 0)
3343 ++msg_silent;
3344 if (STRCMP(s, "silent!") == 0)
3345 {
3346 emsg_silent = TRUE;
3347 emsg_noredir = TRUE;
3348 }
3349 }
3350 else
3351 ++msg_silent;
3352
3353 if (redir_execute)
3354 save_ga = redir_execute_ga;
3355 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3356 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003357 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003358 if (!echo_output)
3359 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360
3361 if (cmd != NULL)
3362 do_cmdline_cmd(cmd);
3363 else
3364 {
3365 listitem_T *item = list->lv_first;
3366
3367 do_cmdline(NULL, get_list_line, (void *)&item,
3368 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3369 --list->lv_refcount;
3370 }
3371
Bram Moolenaard297f352017-01-29 20:31:21 +01003372 /* Need to append a NUL to the result. */
3373 if (ga_grow(&redir_execute_ga, 1) == OK)
3374 {
3375 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3376 rettv->vval.v_string = redir_execute_ga.ga_data;
3377 }
3378 else
3379 {
3380 ga_clear(&redir_execute_ga);
3381 rettv->vval.v_string = NULL;
3382 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003383 msg_silent = save_msg_silent;
3384 emsg_silent = save_emsg_silent;
3385 emsg_noredir = save_emsg_noredir;
3386
3387 redir_execute = save_redir_execute;
3388 if (redir_execute)
3389 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003390 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003392 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003393 if (echo_output)
3394 // When not working silently: put it in column zero. A following
3395 // "echon" will overwrite the message, unavoidably.
3396 msg_col = 0;
3397 else
3398 // When working silently: Put it back where it was, since nothing
3399 // should have been written.
3400 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003401}
3402
3403/*
3404 * "exepath()" function
3405 */
3406 static void
3407f_exepath(typval_T *argvars, typval_T *rettv)
3408{
3409 char_u *p = NULL;
3410
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003411 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003412 rettv->v_type = VAR_STRING;
3413 rettv->vval.v_string = p;
3414}
3415
3416/*
3417 * "exists()" function
3418 */
3419 static void
3420f_exists(typval_T *argvars, typval_T *rettv)
3421{
3422 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003423 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003424
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003425 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426 if (*p == '$') /* environment variable */
3427 {
3428 /* first try "normal" environment variables (fast) */
3429 if (mch_getenv(p + 1) != NULL)
3430 n = TRUE;
3431 else
3432 {
3433 /* try expanding things like $VIM and ${HOME} */
3434 p = expand_env_save(p);
3435 if (p != NULL && *p != '$')
3436 n = TRUE;
3437 vim_free(p);
3438 }
3439 }
3440 else if (*p == '&' || *p == '+') /* option */
3441 {
3442 n = (get_option_tv(&p, NULL, TRUE) == OK);
3443 if (*skipwhite(p) != NUL)
3444 n = FALSE; /* trailing garbage */
3445 }
3446 else if (*p == '*') /* internal or user defined function */
3447 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003448 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 }
3450 else if (*p == ':')
3451 {
3452 n = cmd_exists(p + 1);
3453 }
3454 else if (*p == '#')
3455 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003456 if (p[1] == '#')
3457 n = autocmd_supported(p + 2);
3458 else
3459 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003460 }
3461 else /* internal variable */
3462 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003463 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003464 }
3465
3466 rettv->vval.v_number = n;
3467}
3468
3469#ifdef FEAT_FLOAT
3470/*
3471 * "exp()" function
3472 */
3473 static void
3474f_exp(typval_T *argvars, typval_T *rettv)
3475{
3476 float_T f = 0.0;
3477
3478 rettv->v_type = VAR_FLOAT;
3479 if (get_float_arg(argvars, &f) == OK)
3480 rettv->vval.v_float = exp(f);
3481 else
3482 rettv->vval.v_float = 0.0;
3483}
3484#endif
3485
3486/*
3487 * "expand()" function
3488 */
3489 static void
3490f_expand(typval_T *argvars, typval_T *rettv)
3491{
3492 char_u *s;
3493 int len;
3494 char_u *errormsg;
3495 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3496 expand_T xpc;
3497 int error = FALSE;
3498 char_u *result;
3499
3500 rettv->v_type = VAR_STRING;
3501 if (argvars[1].v_type != VAR_UNKNOWN
3502 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003503 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003504 && !error)
3505 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003506 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003507 }
3508
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003509 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003510 if (*s == '%' || *s == '#' || *s == '<')
3511 {
3512 ++emsg_off;
3513 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3514 --emsg_off;
3515 if (rettv->v_type == VAR_LIST)
3516 {
3517 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3518 list_append_string(rettv->vval.v_list, result, -1);
3519 else
3520 vim_free(result);
3521 }
3522 else
3523 rettv->vval.v_string = result;
3524 }
3525 else
3526 {
3527 /* When the optional second argument is non-zero, don't remove matches
3528 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3529 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003530 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003531 options |= WILD_KEEP_ALL;
3532 if (!error)
3533 {
3534 ExpandInit(&xpc);
3535 xpc.xp_context = EXPAND_FILES;
3536 if (p_wic)
3537 options += WILD_ICASE;
3538 if (rettv->v_type == VAR_STRING)
3539 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3540 options, WILD_ALL);
3541 else if (rettv_list_alloc(rettv) != FAIL)
3542 {
3543 int i;
3544
3545 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3546 for (i = 0; i < xpc.xp_numfiles; i++)
3547 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3548 ExpandCleanup(&xpc);
3549 }
3550 }
3551 else
3552 rettv->vval.v_string = NULL;
3553 }
3554}
3555
3556/*
3557 * "extend(list, list [, idx])" function
3558 * "extend(dict, dict [, action])" function
3559 */
3560 static void
3561f_extend(typval_T *argvars, typval_T *rettv)
3562{
3563 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3564
3565 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3566 {
3567 list_T *l1, *l2;
3568 listitem_T *item;
3569 long before;
3570 int error = FALSE;
3571
3572 l1 = argvars[0].vval.v_list;
3573 l2 = argvars[1].vval.v_list;
3574 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3575 && l2 != NULL)
3576 {
3577 if (argvars[2].v_type != VAR_UNKNOWN)
3578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003579 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003580 if (error)
3581 return; /* type error; errmsg already given */
3582
3583 if (before == l1->lv_len)
3584 item = NULL;
3585 else
3586 {
3587 item = list_find(l1, before);
3588 if (item == NULL)
3589 {
3590 EMSGN(_(e_listidx), before);
3591 return;
3592 }
3593 }
3594 }
3595 else
3596 item = NULL;
3597 list_extend(l1, l2, item);
3598
3599 copy_tv(&argvars[0], rettv);
3600 }
3601 }
3602 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3603 {
3604 dict_T *d1, *d2;
3605 char_u *action;
3606 int i;
3607
3608 d1 = argvars[0].vval.v_dict;
3609 d2 = argvars[1].vval.v_dict;
3610 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3611 && d2 != NULL)
3612 {
3613 /* Check the third argument. */
3614 if (argvars[2].v_type != VAR_UNKNOWN)
3615 {
3616 static char *(av[]) = {"keep", "force", "error"};
3617
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003618 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003619 if (action == NULL)
3620 return; /* type error; errmsg already given */
3621 for (i = 0; i < 3; ++i)
3622 if (STRCMP(action, av[i]) == 0)
3623 break;
3624 if (i == 3)
3625 {
3626 EMSG2(_(e_invarg2), action);
3627 return;
3628 }
3629 }
3630 else
3631 action = (char_u *)"force";
3632
3633 dict_extend(d1, d2, action);
3634
3635 copy_tv(&argvars[0], rettv);
3636 }
3637 }
3638 else
3639 EMSG2(_(e_listdictarg), "extend()");
3640}
3641
3642/*
3643 * "feedkeys()" function
3644 */
3645 static void
3646f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3647{
3648 int remap = TRUE;
3649 int insert = FALSE;
3650 char_u *keys, *flags;
3651 char_u nbuf[NUMBUFLEN];
3652 int typed = FALSE;
3653 int execute = FALSE;
3654 int dangerous = FALSE;
3655 char_u *keys_esc;
3656
3657 /* This is not allowed in the sandbox. If the commands would still be
3658 * executed in the sandbox it would be OK, but it probably happens later,
3659 * when "sandbox" is no longer set. */
3660 if (check_secure())
3661 return;
3662
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003663 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003664
3665 if (argvars[1].v_type != VAR_UNKNOWN)
3666 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003667 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003668 for ( ; *flags != NUL; ++flags)
3669 {
3670 switch (*flags)
3671 {
3672 case 'n': remap = FALSE; break;
3673 case 'm': remap = TRUE; break;
3674 case 't': typed = TRUE; break;
3675 case 'i': insert = TRUE; break;
3676 case 'x': execute = TRUE; break;
3677 case '!': dangerous = TRUE; break;
3678 }
3679 }
3680 }
3681
3682 if (*keys != NUL || execute)
3683 {
3684 /* Need to escape K_SPECIAL and CSI before putting the string in the
3685 * typeahead buffer. */
3686 keys_esc = vim_strsave_escape_csi(keys);
3687 if (keys_esc != NULL)
3688 {
3689 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3690 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3691 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003692 if (vgetc_busy
3693#ifdef FEAT_TIMERS
3694 || timer_busy
3695#endif
3696 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003697 typebuf_was_filled = TRUE;
3698 if (execute)
3699 {
3700 int save_msg_scroll = msg_scroll;
3701
3702 /* Avoid a 1 second delay when the keys start Insert mode. */
3703 msg_scroll = FALSE;
3704
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003705 if (!dangerous)
3706 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003707 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003708 if (!dangerous)
3709 --ex_normal_busy;
3710
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003711 msg_scroll |= save_msg_scroll;
3712 }
3713 }
3714 }
3715}
3716
3717/*
3718 * "filereadable()" function
3719 */
3720 static void
3721f_filereadable(typval_T *argvars, typval_T *rettv)
3722{
3723 int fd;
3724 char_u *p;
3725 int n;
3726
3727#ifndef O_NONBLOCK
3728# define O_NONBLOCK 0
3729#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003730 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003731 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3732 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3733 {
3734 n = TRUE;
3735 close(fd);
3736 }
3737 else
3738 n = FALSE;
3739
3740 rettv->vval.v_number = n;
3741}
3742
3743/*
3744 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3745 * rights to write into.
3746 */
3747 static void
3748f_filewritable(typval_T *argvars, typval_T *rettv)
3749{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003750 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003751}
3752
3753 static void
3754findfilendir(
3755 typval_T *argvars UNUSED,
3756 typval_T *rettv,
3757 int find_what UNUSED)
3758{
3759#ifdef FEAT_SEARCHPATH
3760 char_u *fname;
3761 char_u *fresult = NULL;
3762 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3763 char_u *p;
3764 char_u pathbuf[NUMBUFLEN];
3765 int count = 1;
3766 int first = TRUE;
3767 int error = FALSE;
3768#endif
3769
3770 rettv->vval.v_string = NULL;
3771 rettv->v_type = VAR_STRING;
3772
3773#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003774 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775
3776 if (argvars[1].v_type != VAR_UNKNOWN)
3777 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003778 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003779 if (p == NULL)
3780 error = TRUE;
3781 else
3782 {
3783 if (*p != NUL)
3784 path = p;
3785
3786 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003787 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003788 }
3789 }
3790
3791 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3792 error = TRUE;
3793
3794 if (*fname != NUL && !error)
3795 {
3796 do
3797 {
3798 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3799 vim_free(fresult);
3800 fresult = find_file_in_path_option(first ? fname : NULL,
3801 first ? (int)STRLEN(fname) : 0,
3802 0, first, path,
3803 find_what,
3804 curbuf->b_ffname,
3805 find_what == FINDFILE_DIR
3806 ? (char_u *)"" : curbuf->b_p_sua);
3807 first = FALSE;
3808
3809 if (fresult != NULL && rettv->v_type == VAR_LIST)
3810 list_append_string(rettv->vval.v_list, fresult, -1);
3811
3812 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3813 }
3814
3815 if (rettv->v_type == VAR_STRING)
3816 rettv->vval.v_string = fresult;
3817#endif
3818}
3819
3820/*
3821 * "filter()" function
3822 */
3823 static void
3824f_filter(typval_T *argvars, typval_T *rettv)
3825{
3826 filter_map(argvars, rettv, FALSE);
3827}
3828
3829/*
3830 * "finddir({fname}[, {path}[, {count}]])" function
3831 */
3832 static void
3833f_finddir(typval_T *argvars, typval_T *rettv)
3834{
3835 findfilendir(argvars, rettv, FINDFILE_DIR);
3836}
3837
3838/*
3839 * "findfile({fname}[, {path}[, {count}]])" function
3840 */
3841 static void
3842f_findfile(typval_T *argvars, typval_T *rettv)
3843{
3844 findfilendir(argvars, rettv, FINDFILE_FILE);
3845}
3846
3847#ifdef FEAT_FLOAT
3848/*
3849 * "float2nr({float})" function
3850 */
3851 static void
3852f_float2nr(typval_T *argvars, typval_T *rettv)
3853{
3854 float_T f = 0.0;
3855
3856 if (get_float_arg(argvars, &f) == OK)
3857 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003858 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003859 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003860 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003861 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003862 else
3863 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 }
3865}
3866
3867/*
3868 * "floor({float})" function
3869 */
3870 static void
3871f_floor(typval_T *argvars, typval_T *rettv)
3872{
3873 float_T f = 0.0;
3874
3875 rettv->v_type = VAR_FLOAT;
3876 if (get_float_arg(argvars, &f) == OK)
3877 rettv->vval.v_float = floor(f);
3878 else
3879 rettv->vval.v_float = 0.0;
3880}
3881
3882/*
3883 * "fmod()" function
3884 */
3885 static void
3886f_fmod(typval_T *argvars, typval_T *rettv)
3887{
3888 float_T fx = 0.0, fy = 0.0;
3889
3890 rettv->v_type = VAR_FLOAT;
3891 if (get_float_arg(argvars, &fx) == OK
3892 && get_float_arg(&argvars[1], &fy) == OK)
3893 rettv->vval.v_float = fmod(fx, fy);
3894 else
3895 rettv->vval.v_float = 0.0;
3896}
3897#endif
3898
3899/*
3900 * "fnameescape({string})" function
3901 */
3902 static void
3903f_fnameescape(typval_T *argvars, typval_T *rettv)
3904{
3905 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003906 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003907 rettv->v_type = VAR_STRING;
3908}
3909
3910/*
3911 * "fnamemodify({fname}, {mods})" function
3912 */
3913 static void
3914f_fnamemodify(typval_T *argvars, typval_T *rettv)
3915{
3916 char_u *fname;
3917 char_u *mods;
3918 int usedlen = 0;
3919 int len;
3920 char_u *fbuf = NULL;
3921 char_u buf[NUMBUFLEN];
3922
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003923 fname = tv_get_string_chk(&argvars[0]);
3924 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003925 if (fname == NULL || mods == NULL)
3926 fname = NULL;
3927 else
3928 {
3929 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003930 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931 }
3932
3933 rettv->v_type = VAR_STRING;
3934 if (fname == NULL)
3935 rettv->vval.v_string = NULL;
3936 else
3937 rettv->vval.v_string = vim_strnsave(fname, len);
3938 vim_free(fbuf);
3939}
3940
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941/*
3942 * "foldclosed()" function
3943 */
3944 static void
3945foldclosed_both(
3946 typval_T *argvars UNUSED,
3947 typval_T *rettv,
3948 int end UNUSED)
3949{
3950#ifdef FEAT_FOLDING
3951 linenr_T lnum;
3952 linenr_T first, last;
3953
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003954 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003955 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3956 {
3957 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3958 {
3959 if (end)
3960 rettv->vval.v_number = (varnumber_T)last;
3961 else
3962 rettv->vval.v_number = (varnumber_T)first;
3963 return;
3964 }
3965 }
3966#endif
3967 rettv->vval.v_number = -1;
3968}
3969
3970/*
3971 * "foldclosed()" function
3972 */
3973 static void
3974f_foldclosed(typval_T *argvars, typval_T *rettv)
3975{
3976 foldclosed_both(argvars, rettv, FALSE);
3977}
3978
3979/*
3980 * "foldclosedend()" function
3981 */
3982 static void
3983f_foldclosedend(typval_T *argvars, typval_T *rettv)
3984{
3985 foldclosed_both(argvars, rettv, TRUE);
3986}
3987
3988/*
3989 * "foldlevel()" function
3990 */
3991 static void
3992f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3993{
3994#ifdef FEAT_FOLDING
3995 linenr_T lnum;
3996
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003997 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003998 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3999 rettv->vval.v_number = foldLevel(lnum);
4000#endif
4001}
4002
4003/*
4004 * "foldtext()" function
4005 */
4006 static void
4007f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4008{
4009#ifdef FEAT_FOLDING
4010 linenr_T foldstart;
4011 linenr_T foldend;
4012 char_u *dashes;
4013 linenr_T lnum;
4014 char_u *s;
4015 char_u *r;
4016 int len;
4017 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004018 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004019#endif
4020
4021 rettv->v_type = VAR_STRING;
4022 rettv->vval.v_string = NULL;
4023#ifdef FEAT_FOLDING
4024 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4025 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4026 dashes = get_vim_var_str(VV_FOLDDASHES);
4027 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4028 && dashes != NULL)
4029 {
4030 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004031 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004032 if (!linewhite(lnum))
4033 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034
4035 /* Find interesting text in this line. */
4036 s = skipwhite(ml_get(lnum));
4037 /* skip C comment-start */
4038 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4039 {
4040 s = skipwhite(s + 2);
4041 if (*skipwhite(s) == NUL
4042 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4043 {
4044 s = skipwhite(ml_get(lnum + 1));
4045 if (*s == '*')
4046 s = skipwhite(s + 1);
4047 }
4048 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004049 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004050 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004051 r = alloc((unsigned)(STRLEN(txt)
4052 + STRLEN(dashes) /* for %s */
4053 + 20 /* for %3ld */
4054 + STRLEN(s))); /* concatenated */
4055 if (r != NULL)
4056 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004057 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004058 len = (int)STRLEN(r);
4059 STRCAT(r, s);
4060 /* remove 'foldmarker' and 'commentstring' */
4061 foldtext_cleanup(r + len);
4062 rettv->vval.v_string = r;
4063 }
4064 }
4065#endif
4066}
4067
4068/*
4069 * "foldtextresult(lnum)" function
4070 */
4071 static void
4072f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4073{
4074#ifdef FEAT_FOLDING
4075 linenr_T lnum;
4076 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004077 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078 foldinfo_T foldinfo;
4079 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004080 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004081#endif
4082
4083 rettv->v_type = VAR_STRING;
4084 rettv->vval.v_string = NULL;
4085#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004086 if (entered)
4087 return; /* reject recursive use */
4088 entered = TRUE;
4089
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004090 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091 /* treat illegal types and illegal string values for {lnum} the same */
4092 if (lnum < 0)
4093 lnum = 0;
4094 fold_count = foldedCount(curwin, lnum, &foldinfo);
4095 if (fold_count > 0)
4096 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004097 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4098 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099 if (text == buf)
4100 text = vim_strsave(text);
4101 rettv->vval.v_string = text;
4102 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004103
4104 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004105#endif
4106}
4107
4108/*
4109 * "foreground()" function
4110 */
4111 static void
4112f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4113{
4114#ifdef FEAT_GUI
4115 if (gui.in_use)
4116 gui_mch_set_foreground();
4117#else
4118# ifdef WIN32
4119 win32_set_foreground();
4120# endif
4121#endif
4122}
4123
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004124 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004125common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004126{
4127 char_u *s;
4128 char_u *name;
4129 int use_string = FALSE;
4130 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004131 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004132
4133 if (argvars[0].v_type == VAR_FUNC)
4134 {
4135 /* function(MyFunc, [arg], dict) */
4136 s = argvars[0].vval.v_string;
4137 }
4138 else if (argvars[0].v_type == VAR_PARTIAL
4139 && argvars[0].vval.v_partial != NULL)
4140 {
4141 /* function(dict.MyFunc, [arg]) */
4142 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004143 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004144 }
4145 else
4146 {
4147 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004148 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004149 use_string = TRUE;
4150 }
4151
Bram Moolenaar843b8842016-08-21 14:36:15 +02004152 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004153 {
4154 name = s;
4155 trans_name = trans_function_name(&name, FALSE,
4156 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4157 if (*name != NUL)
4158 s = NULL;
4159 }
4160
Bram Moolenaar843b8842016-08-21 14:36:15 +02004161 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4162 || (is_funcref && trans_name == NULL))
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004163 EMSG2(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004164 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004165 else if (trans_name != NULL && (is_funcref
4166 ? find_func(trans_name) == NULL
4167 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004168 EMSG2(_("E700: Unknown function: %s"), s);
4169 else
4170 {
4171 int dict_idx = 0;
4172 int arg_idx = 0;
4173 list_T *list = NULL;
4174
4175 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4176 {
4177 char sid_buf[25];
4178 int off = *s == 's' ? 2 : 5;
4179
4180 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4181 * also be called from another script. Using trans_function_name()
4182 * would also work, but some plugins depend on the name being
4183 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004184 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004185 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4186 if (name != NULL)
4187 {
4188 STRCPY(name, sid_buf);
4189 STRCAT(name, s + off);
4190 }
4191 }
4192 else
4193 name = vim_strsave(s);
4194
4195 if (argvars[1].v_type != VAR_UNKNOWN)
4196 {
4197 if (argvars[2].v_type != VAR_UNKNOWN)
4198 {
4199 /* function(name, [args], dict) */
4200 arg_idx = 1;
4201 dict_idx = 2;
4202 }
4203 else if (argvars[1].v_type == VAR_DICT)
4204 /* function(name, dict) */
4205 dict_idx = 1;
4206 else
4207 /* function(name, [args]) */
4208 arg_idx = 1;
4209 if (dict_idx > 0)
4210 {
4211 if (argvars[dict_idx].v_type != VAR_DICT)
4212 {
4213 EMSG(_("E922: expected a dict"));
4214 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004215 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004216 }
4217 if (argvars[dict_idx].vval.v_dict == NULL)
4218 dict_idx = 0;
4219 }
4220 if (arg_idx > 0)
4221 {
4222 if (argvars[arg_idx].v_type != VAR_LIST)
4223 {
4224 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4225 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004226 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004227 }
4228 list = argvars[arg_idx].vval.v_list;
4229 if (list == NULL || list->lv_len == 0)
4230 arg_idx = 0;
4231 }
4232 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004233 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004234 {
4235 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4236
4237 /* result is a VAR_PARTIAL */
4238 if (pt == NULL)
4239 vim_free(name);
4240 else
4241 {
4242 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4243 {
4244 listitem_T *li;
4245 int i = 0;
4246 int arg_len = 0;
4247 int lv_len = 0;
4248
4249 if (arg_pt != NULL)
4250 arg_len = arg_pt->pt_argc;
4251 if (list != NULL)
4252 lv_len = list->lv_len;
4253 pt->pt_argc = arg_len + lv_len;
4254 pt->pt_argv = (typval_T *)alloc(
4255 sizeof(typval_T) * pt->pt_argc);
4256 if (pt->pt_argv == NULL)
4257 {
4258 vim_free(pt);
4259 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004260 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004261 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004262 for (i = 0; i < arg_len; i++)
4263 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4264 if (lv_len > 0)
4265 for (li = list->lv_first; li != NULL;
4266 li = li->li_next)
4267 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004268 }
4269
4270 /* For "function(dict.func, [], dict)" and "func" is a partial
4271 * use "dict". That is backwards compatible. */
4272 if (dict_idx > 0)
4273 {
4274 /* The dict is bound explicitly, pt_auto is FALSE. */
4275 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4276 ++pt->pt_dict->dv_refcount;
4277 }
4278 else if (arg_pt != NULL)
4279 {
4280 /* If the dict was bound automatically the result is also
4281 * bound automatically. */
4282 pt->pt_dict = arg_pt->pt_dict;
4283 pt->pt_auto = arg_pt->pt_auto;
4284 if (pt->pt_dict != NULL)
4285 ++pt->pt_dict->dv_refcount;
4286 }
4287
4288 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004289 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4290 {
4291 pt->pt_func = arg_pt->pt_func;
4292 func_ptr_ref(pt->pt_func);
4293 vim_free(name);
4294 }
4295 else if (is_funcref)
4296 {
4297 pt->pt_func = find_func(trans_name);
4298 func_ptr_ref(pt->pt_func);
4299 vim_free(name);
4300 }
4301 else
4302 {
4303 pt->pt_name = name;
4304 func_ref(name);
4305 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004306 }
4307 rettv->v_type = VAR_PARTIAL;
4308 rettv->vval.v_partial = pt;
4309 }
4310 else
4311 {
4312 /* result is a VAR_FUNC */
4313 rettv->v_type = VAR_FUNC;
4314 rettv->vval.v_string = name;
4315 func_ref(name);
4316 }
4317 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004318theend:
4319 vim_free(trans_name);
4320}
4321
4322/*
4323 * "funcref()" function
4324 */
4325 static void
4326f_funcref(typval_T *argvars, typval_T *rettv)
4327{
4328 common_function(argvars, rettv, TRUE);
4329}
4330
4331/*
4332 * "function()" function
4333 */
4334 static void
4335f_function(typval_T *argvars, typval_T *rettv)
4336{
4337 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004338}
4339
4340/*
4341 * "garbagecollect()" function
4342 */
4343 static void
4344f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4345{
4346 /* This is postponed until we are back at the toplevel, because we may be
4347 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4348 want_garbage_collect = TRUE;
4349
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004350 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004351 garbage_collect_at_exit = TRUE;
4352}
4353
4354/*
4355 * "get()" function
4356 */
4357 static void
4358f_get(typval_T *argvars, typval_T *rettv)
4359{
4360 listitem_T *li;
4361 list_T *l;
4362 dictitem_T *di;
4363 dict_T *d;
4364 typval_T *tv = NULL;
4365
4366 if (argvars[0].v_type == VAR_LIST)
4367 {
4368 if ((l = argvars[0].vval.v_list) != NULL)
4369 {
4370 int error = FALSE;
4371
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004372 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004373 if (!error && li != NULL)
4374 tv = &li->li_tv;
4375 }
4376 }
4377 else if (argvars[0].v_type == VAR_DICT)
4378 {
4379 if ((d = argvars[0].vval.v_dict) != NULL)
4380 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004381 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004382 if (di != NULL)
4383 tv = &di->di_tv;
4384 }
4385 }
4386 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4387 {
4388 partial_T *pt;
4389 partial_T fref_pt;
4390
4391 if (argvars[0].v_type == VAR_PARTIAL)
4392 pt = argvars[0].vval.v_partial;
4393 else
4394 {
4395 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4396 fref_pt.pt_name = argvars[0].vval.v_string;
4397 pt = &fref_pt;
4398 }
4399
4400 if (pt != NULL)
4401 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004402 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004403 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004404
4405 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4406 {
4407 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004408 n = partial_name(pt);
4409 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004410 rettv->vval.v_string = NULL;
4411 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004412 {
4413 rettv->vval.v_string = vim_strsave(n);
4414 if (rettv->v_type == VAR_FUNC)
4415 func_ref(rettv->vval.v_string);
4416 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004417 }
4418 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004419 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004420 else if (STRCMP(what, "args") == 0)
4421 {
4422 rettv->v_type = VAR_LIST;
4423 if (rettv_list_alloc(rettv) == OK)
4424 {
4425 int i;
4426
4427 for (i = 0; i < pt->pt_argc; ++i)
4428 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4429 }
4430 }
4431 else
4432 EMSG2(_(e_invarg2), what);
4433 return;
4434 }
4435 }
4436 else
4437 EMSG2(_(e_listdictarg), "get()");
4438
4439 if (tv == NULL)
4440 {
4441 if (argvars[2].v_type != VAR_UNKNOWN)
4442 copy_tv(&argvars[2], rettv);
4443 }
4444 else
4445 copy_tv(tv, rettv);
4446}
4447
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004448/*
4449 * Returns buffer options, variables and other attributes in a dictionary.
4450 */
4451 static dict_T *
4452get_buffer_info(buf_T *buf)
4453{
4454 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004455 tabpage_T *tp;
4456 win_T *wp;
4457 list_T *windows;
4458
4459 dict = dict_alloc();
4460 if (dict == NULL)
4461 return NULL;
4462
Bram Moolenaare0be1672018-07-08 16:50:37 +02004463 dict_add_number(dict, "bufnr", buf->b_fnum);
4464 dict_add_string(dict, "name", buf->b_ffname);
4465 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4466 : buflist_findlnum(buf));
4467 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4468 dict_add_number(dict, "listed", buf->b_p_bl);
4469 dict_add_number(dict, "changed", bufIsChanged(buf));
4470 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4471 dict_add_number(dict, "hidden",
4472 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004473
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004474 /* Get a reference to buffer variables */
4475 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004476
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004477 /* List of windows displaying this buffer */
4478 windows = list_alloc();
4479 if (windows != NULL)
4480 {
4481 FOR_ALL_TAB_WINDOWS(tp, wp)
4482 if (wp->w_buffer == buf)
4483 list_append_number(windows, (varnumber_T)wp->w_id);
4484 dict_add_list(dict, "windows", windows);
4485 }
4486
4487#ifdef FEAT_SIGNS
4488 if (buf->b_signlist != NULL)
4489 {
4490 /* List of signs placed in this buffer */
4491 list_T *signs = list_alloc();
4492 if (signs != NULL)
4493 {
4494 get_buffer_signs(buf, signs);
4495 dict_add_list(dict, "signs", signs);
4496 }
4497 }
4498#endif
4499
4500 return dict;
4501}
4502
4503/*
4504 * "getbufinfo()" function
4505 */
4506 static void
4507f_getbufinfo(typval_T *argvars, typval_T *rettv)
4508{
4509 buf_T *buf = NULL;
4510 buf_T *argbuf = NULL;
4511 dict_T *d;
4512 int filtered = FALSE;
4513 int sel_buflisted = FALSE;
4514 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004515 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004516
4517 if (rettv_list_alloc(rettv) != OK)
4518 return;
4519
4520 /* List of all the buffers or selected buffers */
4521 if (argvars[0].v_type == VAR_DICT)
4522 {
4523 dict_T *sel_d = argvars[0].vval.v_dict;
4524
4525 if (sel_d != NULL)
4526 {
4527 dictitem_T *di;
4528
4529 filtered = TRUE;
4530
4531 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004532 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004533 sel_buflisted = TRUE;
4534
4535 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004536 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004537 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004538
4539 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004540 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004541 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004542 }
4543 }
4544 else if (argvars[0].v_type != VAR_UNKNOWN)
4545 {
4546 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004547 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004548 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004549 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004550 --emsg_off;
4551 if (argbuf == NULL)
4552 return;
4553 }
4554
4555 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004556 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004557 {
4558 if (argbuf != NULL && argbuf != buf)
4559 continue;
4560 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004561 || (sel_buflisted && !buf->b_p_bl)
4562 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004563 continue;
4564
4565 d = get_buffer_info(buf);
4566 if (d != NULL)
4567 list_append_dict(rettv->vval.v_list, d);
4568 if (argbuf != NULL)
4569 return;
4570 }
4571}
4572
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004573/*
4574 * Get line or list of lines from buffer "buf" into "rettv".
4575 * Return a range (from start to end) of lines in rettv from the specified
4576 * buffer.
4577 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4578 */
4579 static void
4580get_buffer_lines(
4581 buf_T *buf,
4582 linenr_T start,
4583 linenr_T end,
4584 int retlist,
4585 typval_T *rettv)
4586{
4587 char_u *p;
4588
4589 rettv->v_type = VAR_STRING;
4590 rettv->vval.v_string = NULL;
4591 if (retlist && rettv_list_alloc(rettv) == FAIL)
4592 return;
4593
4594 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4595 return;
4596
4597 if (!retlist)
4598 {
4599 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4600 p = ml_get_buf(buf, start, FALSE);
4601 else
4602 p = (char_u *)"";
4603 rettv->vval.v_string = vim_strsave(p);
4604 }
4605 else
4606 {
4607 if (end < start)
4608 return;
4609
4610 if (start < 1)
4611 start = 1;
4612 if (end > buf->b_ml.ml_line_count)
4613 end = buf->b_ml.ml_line_count;
4614 while (start <= end)
4615 if (list_append_string(rettv->vval.v_list,
4616 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4617 break;
4618 }
4619}
4620
4621/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622 * "getbufline()" function
4623 */
4624 static void
4625f_getbufline(typval_T *argvars, typval_T *rettv)
4626{
4627 linenr_T lnum;
4628 linenr_T end;
4629 buf_T *buf;
4630
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004631 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004632 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004633 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004634 --emsg_off;
4635
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004636 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004637 if (argvars[2].v_type == VAR_UNKNOWN)
4638 end = lnum;
4639 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004640 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004641
4642 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4643}
4644
4645/*
4646 * "getbufvar()" function
4647 */
4648 static void
4649f_getbufvar(typval_T *argvars, typval_T *rettv)
4650{
4651 buf_T *buf;
4652 buf_T *save_curbuf;
4653 char_u *varname;
4654 dictitem_T *v;
4655 int done = FALSE;
4656
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004657 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4658 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004659 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004660 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661
4662 rettv->v_type = VAR_STRING;
4663 rettv->vval.v_string = NULL;
4664
4665 if (buf != NULL && varname != NULL)
4666 {
4667 /* set curbuf to be our buf, temporarily */
4668 save_curbuf = curbuf;
4669 curbuf = buf;
4670
Bram Moolenaar30567352016-08-27 21:25:44 +02004671 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004672 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004673 if (varname[1] == NUL)
4674 {
4675 /* get all buffer-local options in a dict */
4676 dict_T *opts = get_winbuf_options(TRUE);
4677
4678 if (opts != NULL)
4679 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004680 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004681 done = TRUE;
4682 }
4683 }
4684 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4685 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686 done = TRUE;
4687 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004688 else
4689 {
4690 /* Look up the variable. */
4691 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4692 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4693 'b', varname, FALSE);
4694 if (v != NULL)
4695 {
4696 copy_tv(&v->di_tv, rettv);
4697 done = TRUE;
4698 }
4699 }
4700
4701 /* restore previous notion of curbuf */
4702 curbuf = save_curbuf;
4703 }
4704
4705 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4706 /* use the default value */
4707 copy_tv(&argvars[2], rettv);
4708
4709 --emsg_off;
4710}
4711
4712/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004713 * "getchangelist()" function
4714 */
4715 static void
4716f_getchangelist(typval_T *argvars, typval_T *rettv)
4717{
4718#ifdef FEAT_JUMPLIST
4719 buf_T *buf;
4720 int i;
4721 list_T *l;
4722 dict_T *d;
4723#endif
4724
4725 if (rettv_list_alloc(rettv) != OK)
4726 return;
4727
4728#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004729 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004730 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004731 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004732 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004733 if (buf == NULL)
4734 return;
4735
4736 l = list_alloc();
4737 if (l == NULL)
4738 return;
4739
4740 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4741 return;
4742 /*
4743 * The current window change list index tracks only the position in the
4744 * current buffer change list. For other buffers, use the change list
4745 * length as the current index.
4746 */
4747 list_append_number(rettv->vval.v_list,
4748 (varnumber_T)((buf == curwin->w_buffer)
4749 ? curwin->w_changelistidx : buf->b_changelistlen));
4750
4751 for (i = 0; i < buf->b_changelistlen; ++i)
4752 {
4753 if (buf->b_changelist[i].lnum == 0)
4754 continue;
4755 if ((d = dict_alloc()) == NULL)
4756 return;
4757 if (list_append_dict(l, d) == FAIL)
4758 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004759 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4760 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004761# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004762 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004763# endif
4764 }
4765#endif
4766}
4767/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768 * "getchar()" function
4769 */
4770 static void
4771f_getchar(typval_T *argvars, typval_T *rettv)
4772{
4773 varnumber_T n;
4774 int error = FALSE;
4775
Bram Moolenaar84d93902018-09-11 20:10:20 +02004776#ifdef MESSAGE_QUEUE
4777 // vpeekc() used to check for messages, but that caused problems, invoking
4778 // a callback where it was not expected. Some plugins use getchar(1) in a
4779 // loop to await a message, therefore make sure we check for messages here.
4780 parse_queued_messages();
4781#endif
4782
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004783 /* Position the cursor. Needed after a message that ends in a space. */
4784 windgoto(msg_row, msg_col);
4785
4786 ++no_mapping;
4787 ++allow_keys;
4788 for (;;)
4789 {
4790 if (argvars[0].v_type == VAR_UNKNOWN)
4791 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004792 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004793 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004794 /* getchar(1): only check if char avail */
4795 n = vpeekc_any();
4796 else if (error || vpeekc_any() == NUL)
4797 /* illegal argument or getchar(0) and no char avail: return zero */
4798 n = 0;
4799 else
4800 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004801 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004802
4803 if (n == K_IGNORE)
4804 continue;
4805 break;
4806 }
4807 --no_mapping;
4808 --allow_keys;
4809
4810 set_vim_var_nr(VV_MOUSE_WIN, 0);
4811 set_vim_var_nr(VV_MOUSE_WINID, 0);
4812 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4813 set_vim_var_nr(VV_MOUSE_COL, 0);
4814
4815 rettv->vval.v_number = n;
4816 if (IS_SPECIAL(n) || mod_mask != 0)
4817 {
4818 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4819 int i = 0;
4820
4821 /* Turn a special key into three bytes, plus modifier. */
4822 if (mod_mask != 0)
4823 {
4824 temp[i++] = K_SPECIAL;
4825 temp[i++] = KS_MODIFIER;
4826 temp[i++] = mod_mask;
4827 }
4828 if (IS_SPECIAL(n))
4829 {
4830 temp[i++] = K_SPECIAL;
4831 temp[i++] = K_SECOND(n);
4832 temp[i++] = K_THIRD(n);
4833 }
4834#ifdef FEAT_MBYTE
4835 else if (has_mbyte)
4836 i += (*mb_char2bytes)(n, temp + i);
4837#endif
4838 else
4839 temp[i++] = n;
4840 temp[i++] = NUL;
4841 rettv->v_type = VAR_STRING;
4842 rettv->vval.v_string = vim_strsave(temp);
4843
4844#ifdef FEAT_MOUSE
4845 if (is_mouse_key(n))
4846 {
4847 int row = mouse_row;
4848 int col = mouse_col;
4849 win_T *win;
4850 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004851 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852 int winnr = 1;
4853
4854 if (row >= 0 && col >= 0)
4855 {
4856 /* Find the window at the mouse coordinates and compute the
4857 * text position. */
4858 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004859 if (win == NULL)
4860 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004862 for (wp = firstwin; wp != win; wp = wp->w_next)
4863 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004864 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4865 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4866 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4867 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4868 }
4869 }
4870#endif
4871 }
4872}
4873
4874/*
4875 * "getcharmod()" function
4876 */
4877 static void
4878f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4879{
4880 rettv->vval.v_number = mod_mask;
4881}
4882
4883/*
4884 * "getcharsearch()" function
4885 */
4886 static void
4887f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4888{
4889 if (rettv_dict_alloc(rettv) != FAIL)
4890 {
4891 dict_T *dict = rettv->vval.v_dict;
4892
Bram Moolenaare0be1672018-07-08 16:50:37 +02004893 dict_add_string(dict, "char", last_csearch());
4894 dict_add_number(dict, "forward", last_csearch_forward());
4895 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004896 }
4897}
4898
4899/*
4900 * "getcmdline()" function
4901 */
4902 static void
4903f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4904{
4905 rettv->v_type = VAR_STRING;
4906 rettv->vval.v_string = get_cmdline_str();
4907}
4908
4909/*
4910 * "getcmdpos()" function
4911 */
4912 static void
4913f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4914{
4915 rettv->vval.v_number = get_cmdline_pos() + 1;
4916}
4917
4918/*
4919 * "getcmdtype()" function
4920 */
4921 static void
4922f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4923{
4924 rettv->v_type = VAR_STRING;
4925 rettv->vval.v_string = alloc(2);
4926 if (rettv->vval.v_string != NULL)
4927 {
4928 rettv->vval.v_string[0] = get_cmdline_type();
4929 rettv->vval.v_string[1] = NUL;
4930 }
4931}
4932
4933/*
4934 * "getcmdwintype()" function
4935 */
4936 static void
4937f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4938{
4939 rettv->v_type = VAR_STRING;
4940 rettv->vval.v_string = NULL;
4941#ifdef FEAT_CMDWIN
4942 rettv->vval.v_string = alloc(2);
4943 if (rettv->vval.v_string != NULL)
4944 {
4945 rettv->vval.v_string[0] = cmdwin_type;
4946 rettv->vval.v_string[1] = NUL;
4947 }
4948#endif
4949}
4950
4951#if defined(FEAT_CMDL_COMPL)
4952/*
4953 * "getcompletion()" function
4954 */
4955 static void
4956f_getcompletion(typval_T *argvars, typval_T *rettv)
4957{
4958 char_u *pat;
4959 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004960 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004961 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4962 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004963
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004964 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004965 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004966
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004967 if (p_wic)
4968 options |= WILD_ICASE;
4969
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004970 /* For filtered results, 'wildignore' is used */
4971 if (!filtered)
4972 options |= WILD_KEEP_ALL;
4973
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004974 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004975 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004977 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004978 if (xpc.xp_context == EXPAND_NOTHING)
4979 {
4980 if (argvars[1].v_type == VAR_STRING)
4981 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4982 else
4983 EMSG(_(e_invarg));
4984 return;
4985 }
4986
4987# if defined(FEAT_MENU)
4988 if (xpc.xp_context == EXPAND_MENUS)
4989 {
4990 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4991 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4992 }
4993# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004994#ifdef FEAT_CSCOPE
4995 if (xpc.xp_context == EXPAND_CSCOPE)
4996 {
4997 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4998 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4999 }
5000#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005001#ifdef FEAT_SIGNS
5002 if (xpc.xp_context == EXPAND_SIGN)
5003 {
5004 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5005 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5006 }
5007#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005008
5009 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5010 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5011 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005012 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005013
5014 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5015
5016 for (i = 0; i < xpc.xp_numfiles; i++)
5017 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5018 }
5019 vim_free(pat);
5020 ExpandCleanup(&xpc);
5021}
5022#endif
5023
5024/*
5025 * "getcwd()" function
5026 */
5027 static void
5028f_getcwd(typval_T *argvars, typval_T *rettv)
5029{
5030 win_T *wp = NULL;
5031 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005032 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005033
5034 rettv->v_type = VAR_STRING;
5035 rettv->vval.v_string = NULL;
5036
Bram Moolenaar54591292018-02-09 20:53:59 +01005037 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5038 global = TRUE;
5039 else
5040 wp = find_tabwin(&argvars[0], &argvars[1]);
5041
5042 if (wp != NULL && wp->w_localdir != NULL)
5043 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5044 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005045 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005046 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005047 rettv->vval.v_string = vim_strsave(globaldir);
5048 else
5049 {
5050 cwd = alloc(MAXPATHL);
5051 if (cwd != NULL)
5052 {
5053 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5054 rettv->vval.v_string = vim_strsave(cwd);
5055 vim_free(cwd);
5056 }
5057 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005058 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005059#ifdef BACKSLASH_IN_FILENAME
5060 if (rettv->vval.v_string != NULL)
5061 slash_adjust(rettv->vval.v_string);
5062#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005063}
5064
5065/*
5066 * "getfontname()" function
5067 */
5068 static void
5069f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5070{
5071 rettv->v_type = VAR_STRING;
5072 rettv->vval.v_string = NULL;
5073#ifdef FEAT_GUI
5074 if (gui.in_use)
5075 {
5076 GuiFont font;
5077 char_u *name = NULL;
5078
5079 if (argvars[0].v_type == VAR_UNKNOWN)
5080 {
5081 /* Get the "Normal" font. Either the name saved by
5082 * hl_set_font_name() or from the font ID. */
5083 font = gui.norm_font;
5084 name = hl_get_font_name();
5085 }
5086 else
5087 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005088 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005089 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5090 return;
5091 font = gui_mch_get_font(name, FALSE);
5092 if (font == NOFONT)
5093 return; /* Invalid font name, return empty string. */
5094 }
5095 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5096 if (argvars[0].v_type != VAR_UNKNOWN)
5097 gui_mch_free_font(font);
5098 }
5099#endif
5100}
5101
5102/*
5103 * "getfperm({fname})" function
5104 */
5105 static void
5106f_getfperm(typval_T *argvars, typval_T *rettv)
5107{
5108 char_u *fname;
5109 stat_T st;
5110 char_u *perm = NULL;
5111 char_u flags[] = "rwx";
5112 int i;
5113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005114 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115
5116 rettv->v_type = VAR_STRING;
5117 if (mch_stat((char *)fname, &st) >= 0)
5118 {
5119 perm = vim_strsave((char_u *)"---------");
5120 if (perm != NULL)
5121 {
5122 for (i = 0; i < 9; i++)
5123 {
5124 if (st.st_mode & (1 << (8 - i)))
5125 perm[i] = flags[i % 3];
5126 }
5127 }
5128 }
5129 rettv->vval.v_string = perm;
5130}
5131
5132/*
5133 * "getfsize({fname})" function
5134 */
5135 static void
5136f_getfsize(typval_T *argvars, typval_T *rettv)
5137{
5138 char_u *fname;
5139 stat_T st;
5140
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005141 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005142
5143 rettv->v_type = VAR_NUMBER;
5144
5145 if (mch_stat((char *)fname, &st) >= 0)
5146 {
5147 if (mch_isdir(fname))
5148 rettv->vval.v_number = 0;
5149 else
5150 {
5151 rettv->vval.v_number = (varnumber_T)st.st_size;
5152
5153 /* non-perfect check for overflow */
5154 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5155 rettv->vval.v_number = -2;
5156 }
5157 }
5158 else
5159 rettv->vval.v_number = -1;
5160}
5161
5162/*
5163 * "getftime({fname})" function
5164 */
5165 static void
5166f_getftime(typval_T *argvars, typval_T *rettv)
5167{
5168 char_u *fname;
5169 stat_T st;
5170
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005171 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005172
5173 if (mch_stat((char *)fname, &st) >= 0)
5174 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5175 else
5176 rettv->vval.v_number = -1;
5177}
5178
5179/*
5180 * "getftype({fname})" function
5181 */
5182 static void
5183f_getftype(typval_T *argvars, typval_T *rettv)
5184{
5185 char_u *fname;
5186 stat_T st;
5187 char_u *type = NULL;
5188 char *t;
5189
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005190 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005191
5192 rettv->v_type = VAR_STRING;
5193 if (mch_lstat((char *)fname, &st) >= 0)
5194 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005195 if (S_ISREG(st.st_mode))
5196 t = "file";
5197 else if (S_ISDIR(st.st_mode))
5198 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 else if (S_ISLNK(st.st_mode))
5200 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 else if (S_ISBLK(st.st_mode))
5202 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 else if (S_ISCHR(st.st_mode))
5204 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005205 else if (S_ISFIFO(st.st_mode))
5206 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005207 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005208 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 else
5210 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005211 type = vim_strsave((char_u *)t);
5212 }
5213 rettv->vval.v_string = type;
5214}
5215
5216/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005217 * "getjumplist()" function
5218 */
5219 static void
5220f_getjumplist(typval_T *argvars, typval_T *rettv)
5221{
5222#ifdef FEAT_JUMPLIST
5223 win_T *wp;
5224 int i;
5225 list_T *l;
5226 dict_T *d;
5227#endif
5228
5229 if (rettv_list_alloc(rettv) != OK)
5230 return;
5231
5232#ifdef FEAT_JUMPLIST
5233 wp = find_tabwin(&argvars[0], &argvars[1]);
5234 if (wp == NULL)
5235 return;
5236
5237 l = list_alloc();
5238 if (l == NULL)
5239 return;
5240
5241 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5242 return;
5243 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5244
Bram Moolenaar48679742018-02-13 13:33:29 +01005245 cleanup_jumplist(wp, TRUE);
5246
Bram Moolenaar4f505882018-02-10 21:06:32 +01005247 for (i = 0; i < wp->w_jumplistlen; ++i)
5248 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005249 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5250 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005251 if ((d = dict_alloc()) == NULL)
5252 return;
5253 if (list_append_dict(l, d) == FAIL)
5254 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005255 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5256 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005257# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005258 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005259# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005260 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005261 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005262 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005263 }
5264#endif
5265}
5266
5267/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005268 * "getline(lnum, [end])" function
5269 */
5270 static void
5271f_getline(typval_T *argvars, typval_T *rettv)
5272{
5273 linenr_T lnum;
5274 linenr_T end;
5275 int retlist;
5276
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005277 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005278 if (argvars[1].v_type == VAR_UNKNOWN)
5279 {
5280 end = 0;
5281 retlist = FALSE;
5282 }
5283 else
5284 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005285 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005286 retlist = TRUE;
5287 }
5288
5289 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5290}
5291
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005292#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005293 static void
5294get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5295{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005296 if (what_arg->v_type == VAR_UNKNOWN)
5297 {
5298 if (rettv_list_alloc(rettv) == OK)
5299 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005300 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005301 }
5302 else
5303 {
5304 if (rettv_dict_alloc(rettv) == OK)
5305 if (is_qf || (wp != NULL))
5306 {
5307 if (what_arg->v_type == VAR_DICT)
5308 {
5309 dict_T *d = what_arg->vval.v_dict;
5310
5311 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005312 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005313 }
5314 else
5315 EMSG(_(e_dictreq));
5316 }
5317 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005318}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005319#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005320
5321/*
5322 * "getloclist()" function
5323 */
5324 static void
5325f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5326{
5327#ifdef FEAT_QUICKFIX
5328 win_T *wp;
5329
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005330 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005331 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5332#endif
5333}
5334
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005335/*
5336 * "getmatches()" function
5337 */
5338 static void
5339f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5340{
5341#ifdef FEAT_SEARCH_EXTRA
5342 dict_T *dict;
5343 matchitem_T *cur = curwin->w_match_head;
5344 int i;
5345
5346 if (rettv_list_alloc(rettv) == OK)
5347 {
5348 while (cur != NULL)
5349 {
5350 dict = dict_alloc();
5351 if (dict == NULL)
5352 return;
5353 if (cur->match.regprog == NULL)
5354 {
5355 /* match added with matchaddpos() */
5356 for (i = 0; i < MAXPOSMATCH; ++i)
5357 {
5358 llpos_T *llpos;
5359 char buf[6];
5360 list_T *l;
5361
5362 llpos = &cur->pos.pos[i];
5363 if (llpos->lnum == 0)
5364 break;
5365 l = list_alloc();
5366 if (l == NULL)
5367 break;
5368 list_append_number(l, (varnumber_T)llpos->lnum);
5369 if (llpos->col > 0)
5370 {
5371 list_append_number(l, (varnumber_T)llpos->col);
5372 list_append_number(l, (varnumber_T)llpos->len);
5373 }
5374 sprintf(buf, "pos%d", i + 1);
5375 dict_add_list(dict, buf, l);
5376 }
5377 }
5378 else
5379 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005380 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005381 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005382 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5383 dict_add_number(dict, "priority", (long)cur->priority);
5384 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005385# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5386 if (cur->conceal_char)
5387 {
5388 char_u buf[MB_MAXBYTES + 1];
5389
5390 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005391 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005392 }
5393# endif
5394 list_append_dict(rettv->vval.v_list, dict);
5395 cur = cur->next;
5396 }
5397 }
5398#endif
5399}
5400
5401/*
5402 * "getpid()" function
5403 */
5404 static void
5405f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5406{
5407 rettv->vval.v_number = mch_get_pid();
5408}
5409
5410 static void
5411getpos_both(
5412 typval_T *argvars,
5413 typval_T *rettv,
5414 int getcurpos)
5415{
5416 pos_T *fp;
5417 list_T *l;
5418 int fnum = -1;
5419
5420 if (rettv_list_alloc(rettv) == OK)
5421 {
5422 l = rettv->vval.v_list;
5423 if (getcurpos)
5424 fp = &curwin->w_cursor;
5425 else
5426 fp = var2fpos(&argvars[0], TRUE, &fnum);
5427 if (fnum != -1)
5428 list_append_number(l, (varnumber_T)fnum);
5429 else
5430 list_append_number(l, (varnumber_T)0);
5431 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5432 : (varnumber_T)0);
5433 list_append_number(l, (fp != NULL)
5434 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5435 : (varnumber_T)0);
5436 list_append_number(l,
5437#ifdef FEAT_VIRTUALEDIT
5438 (fp != NULL) ? (varnumber_T)fp->coladd :
5439#endif
5440 (varnumber_T)0);
5441 if (getcurpos)
5442 {
5443 update_curswant();
5444 list_append_number(l, curwin->w_curswant == MAXCOL ?
5445 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5446 }
5447 }
5448 else
5449 rettv->vval.v_number = FALSE;
5450}
5451
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452/*
5453 * "getcurpos()" function
5454 */
5455 static void
5456f_getcurpos(typval_T *argvars, typval_T *rettv)
5457{
5458 getpos_both(argvars, rettv, TRUE);
5459}
5460
5461/*
5462 * "getpos(string)" function
5463 */
5464 static void
5465f_getpos(typval_T *argvars, typval_T *rettv)
5466{
5467 getpos_both(argvars, rettv, FALSE);
5468}
5469
5470/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005471 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005472 */
5473 static void
5474f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5475{
5476#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005477 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005478#endif
5479}
5480
5481/*
5482 * "getreg()" function
5483 */
5484 static void
5485f_getreg(typval_T *argvars, typval_T *rettv)
5486{
5487 char_u *strregname;
5488 int regname;
5489 int arg2 = FALSE;
5490 int return_list = FALSE;
5491 int error = FALSE;
5492
5493 if (argvars[0].v_type != VAR_UNKNOWN)
5494 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005495 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005496 error = strregname == NULL;
5497 if (argvars[1].v_type != VAR_UNKNOWN)
5498 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005499 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005500 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005501 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502 }
5503 }
5504 else
5505 strregname = get_vim_var_str(VV_REG);
5506
5507 if (error)
5508 return;
5509
5510 regname = (strregname == NULL ? '"' : *strregname);
5511 if (regname == 0)
5512 regname = '"';
5513
5514 if (return_list)
5515 {
5516 rettv->v_type = VAR_LIST;
5517 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5518 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5519 if (rettv->vval.v_list == NULL)
5520 (void)rettv_list_alloc(rettv);
5521 else
5522 ++rettv->vval.v_list->lv_refcount;
5523 }
5524 else
5525 {
5526 rettv->v_type = VAR_STRING;
5527 rettv->vval.v_string = get_reg_contents(regname,
5528 arg2 ? GREG_EXPR_SRC : 0);
5529 }
5530}
5531
5532/*
5533 * "getregtype()" function
5534 */
5535 static void
5536f_getregtype(typval_T *argvars, typval_T *rettv)
5537{
5538 char_u *strregname;
5539 int regname;
5540 char_u buf[NUMBUFLEN + 2];
5541 long reglen = 0;
5542
5543 if (argvars[0].v_type != VAR_UNKNOWN)
5544 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005545 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005546 if (strregname == NULL) /* type error; errmsg already given */
5547 {
5548 rettv->v_type = VAR_STRING;
5549 rettv->vval.v_string = NULL;
5550 return;
5551 }
5552 }
5553 else
5554 /* Default to v:register */
5555 strregname = get_vim_var_str(VV_REG);
5556
5557 regname = (strregname == NULL ? '"' : *strregname);
5558 if (regname == 0)
5559 regname = '"';
5560
5561 buf[0] = NUL;
5562 buf[1] = NUL;
5563 switch (get_reg_type(regname, &reglen))
5564 {
5565 case MLINE: buf[0] = 'V'; break;
5566 case MCHAR: buf[0] = 'v'; break;
5567 case MBLOCK:
5568 buf[0] = Ctrl_V;
5569 sprintf((char *)buf + 1, "%ld", reglen + 1);
5570 break;
5571 }
5572 rettv->v_type = VAR_STRING;
5573 rettv->vval.v_string = vim_strsave(buf);
5574}
5575
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005576/*
5577 * Returns information (variables, options, etc.) about a tab page
5578 * as a dictionary.
5579 */
5580 static dict_T *
5581get_tabpage_info(tabpage_T *tp, int tp_idx)
5582{
5583 win_T *wp;
5584 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005585 list_T *l;
5586
5587 dict = dict_alloc();
5588 if (dict == NULL)
5589 return NULL;
5590
Bram Moolenaare0be1672018-07-08 16:50:37 +02005591 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005592
5593 l = list_alloc();
5594 if (l != NULL)
5595 {
5596 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5597 wp; wp = wp->w_next)
5598 list_append_number(l, (varnumber_T)wp->w_id);
5599 dict_add_list(dict, "windows", l);
5600 }
5601
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005602 /* Make a reference to tabpage variables */
5603 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005604
5605 return dict;
5606}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005607
5608/*
5609 * "gettabinfo()" function
5610 */
5611 static void
5612f_gettabinfo(typval_T *argvars, typval_T *rettv)
5613{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005614 tabpage_T *tp, *tparg = NULL;
5615 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005616 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005617
5618 if (rettv_list_alloc(rettv) != OK)
5619 return;
5620
5621 if (argvars[0].v_type != VAR_UNKNOWN)
5622 {
5623 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005624 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005625 if (tparg == NULL)
5626 return;
5627 }
5628
5629 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005630 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005631 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005632 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005633 if (tparg != NULL && tp != tparg)
5634 continue;
5635 d = get_tabpage_info(tp, tpnr);
5636 if (d != NULL)
5637 list_append_dict(rettv->vval.v_list, d);
5638 if (tparg != NULL)
5639 return;
5640 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005641}
5642
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005643/*
5644 * "gettabvar()" function
5645 */
5646 static void
5647f_gettabvar(typval_T *argvars, typval_T *rettv)
5648{
5649 win_T *oldcurwin;
5650 tabpage_T *tp, *oldtabpage;
5651 dictitem_T *v;
5652 char_u *varname;
5653 int done = FALSE;
5654
5655 rettv->v_type = VAR_STRING;
5656 rettv->vval.v_string = NULL;
5657
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005658 varname = tv_get_string_chk(&argvars[1]);
5659 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005660 if (tp != NULL && varname != NULL)
5661 {
5662 /* Set tp to be our tabpage, temporarily. Also set the window to the
5663 * first window in the tabpage, otherwise the window is not valid. */
5664 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005665 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5666 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005667 {
5668 /* look up the variable */
5669 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5670 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5671 if (v != NULL)
5672 {
5673 copy_tv(&v->di_tv, rettv);
5674 done = TRUE;
5675 }
5676 }
5677
5678 /* restore previous notion of curwin */
5679 restore_win(oldcurwin, oldtabpage, TRUE);
5680 }
5681
5682 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5683 copy_tv(&argvars[2], rettv);
5684}
5685
5686/*
5687 * "gettabwinvar()" function
5688 */
5689 static void
5690f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5691{
5692 getwinvar(argvars, rettv, 1);
5693}
5694
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005695/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005696 * "gettagstack()" function
5697 */
5698 static void
5699f_gettagstack(typval_T *argvars, typval_T *rettv)
5700{
5701 win_T *wp = curwin; // default is current window
5702
5703 if (rettv_dict_alloc(rettv) != OK)
5704 return;
5705
5706 if (argvars[0].v_type != VAR_UNKNOWN)
5707 {
5708 wp = find_win_by_nr_or_id(&argvars[0]);
5709 if (wp == NULL)
5710 return;
5711 }
5712
5713 get_tagstack(wp, rettv->vval.v_dict);
5714}
5715
5716/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005717 * Returns information about a window as a dictionary.
5718 */
5719 static dict_T *
5720get_win_info(win_T *wp, short tpnr, short winnr)
5721{
5722 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005723
5724 dict = dict_alloc();
5725 if (dict == NULL)
5726 return NULL;
5727
Bram Moolenaare0be1672018-07-08 16:50:37 +02005728 dict_add_number(dict, "tabnr", tpnr);
5729 dict_add_number(dict, "winnr", winnr);
5730 dict_add_number(dict, "winid", wp->w_id);
5731 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005732 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005733#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005734 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005735#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005736 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005737 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005738 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005739
Bram Moolenaar69905d12017-08-13 18:14:47 +02005740#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005741 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005742#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005743#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005744 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5745 dict_add_number(dict, "loclist",
5746 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005747#endif
5748
Bram Moolenaar30567352016-08-27 21:25:44 +02005749 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005750 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005751
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005752 return dict;
5753}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005754
5755/*
5756 * "getwininfo()" function
5757 */
5758 static void
5759f_getwininfo(typval_T *argvars, typval_T *rettv)
5760{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005761 tabpage_T *tp;
5762 win_T *wp = NULL, *wparg = NULL;
5763 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005764 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005765
5766 if (rettv_list_alloc(rettv) != OK)
5767 return;
5768
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005769 if (argvars[0].v_type != VAR_UNKNOWN)
5770 {
5771 wparg = win_id2wp(argvars);
5772 if (wparg == NULL)
5773 return;
5774 }
5775
5776 /* Collect information about either all the windows across all the tab
5777 * pages or one particular window.
5778 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005779 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005780 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005781 tabnr++;
5782 winnr = 0;
5783 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005784 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005785 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005786 if (wparg != NULL && wp != wparg)
5787 continue;
5788 d = get_win_info(wp, tabnr, winnr);
5789 if (d != NULL)
5790 list_append_dict(rettv->vval.v_list, d);
5791 if (wparg != NULL)
5792 /* found information about a specific window */
5793 return;
5794 }
5795 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005796}
5797
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005798/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 * "win_findbuf()" function
5800 */
5801 static void
5802f_win_findbuf(typval_T *argvars, typval_T *rettv)
5803{
5804 if (rettv_list_alloc(rettv) != FAIL)
5805 win_findbuf(argvars, rettv->vval.v_list);
5806}
5807
5808/*
5809 * "win_getid()" function
5810 */
5811 static void
5812f_win_getid(typval_T *argvars, typval_T *rettv)
5813{
5814 rettv->vval.v_number = win_getid(argvars);
5815}
5816
5817/*
5818 * "win_gotoid()" function
5819 */
5820 static void
5821f_win_gotoid(typval_T *argvars, typval_T *rettv)
5822{
5823 rettv->vval.v_number = win_gotoid(argvars);
5824}
5825
5826/*
5827 * "win_id2tabwin()" function
5828 */
5829 static void
5830f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5831{
5832 if (rettv_list_alloc(rettv) != FAIL)
5833 win_id2tabwin(argvars, rettv->vval.v_list);
5834}
5835
5836/*
5837 * "win_id2win()" function
5838 */
5839 static void
5840f_win_id2win(typval_T *argvars, typval_T *rettv)
5841{
5842 rettv->vval.v_number = win_id2win(argvars);
5843}
5844
5845/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005846 * "win_screenpos()" function
5847 */
5848 static void
5849f_win_screenpos(typval_T *argvars, typval_T *rettv)
5850{
5851 win_T *wp;
5852
5853 if (rettv_list_alloc(rettv) == FAIL)
5854 return;
5855
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005856 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005857 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5858 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5859}
5860
5861/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005862 * "getwinpos({timeout})" function
5863 */
5864 static void
5865f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5866{
5867 int x = -1;
5868 int y = -1;
5869
5870 if (rettv_list_alloc(rettv) == FAIL)
5871 return;
5872#ifdef FEAT_GUI
5873 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005874 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005875# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5876 else
5877# endif
5878#endif
5879#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5880 {
5881 varnumber_T timeout = 100;
5882
5883 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005884 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005885 term_get_winpos(&x, &y, timeout);
5886 }
5887#endif
5888 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5889 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5890}
5891
5892
5893/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005894 * "getwinposx()" function
5895 */
5896 static void
5897f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5898{
5899 rettv->vval.v_number = -1;
5900#ifdef FEAT_GUI
5901 if (gui.in_use)
5902 {
5903 int x, y;
5904
5905 if (gui_mch_get_winpos(&x, &y) == OK)
5906 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005907 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005908 }
5909#endif
5910#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5911 {
5912 int x, y;
5913
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005914 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005915 rettv->vval.v_number = x;
5916 }
5917#endif
5918}
5919
5920/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005921 * "getwinposy()" function
5922 */
5923 static void
5924f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5925{
5926 rettv->vval.v_number = -1;
5927#ifdef FEAT_GUI
5928 if (gui.in_use)
5929 {
5930 int x, y;
5931
5932 if (gui_mch_get_winpos(&x, &y) == OK)
5933 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005934 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005935 }
5936#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005937#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5938 {
5939 int x, y;
5940
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005941 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005942 rettv->vval.v_number = y;
5943 }
5944#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005945}
5946
5947/*
5948 * "getwinvar()" function
5949 */
5950 static void
5951f_getwinvar(typval_T *argvars, typval_T *rettv)
5952{
5953 getwinvar(argvars, rettv, 0);
5954}
5955
5956/*
5957 * "glob()" function
5958 */
5959 static void
5960f_glob(typval_T *argvars, typval_T *rettv)
5961{
5962 int options = WILD_SILENT|WILD_USE_NL;
5963 expand_T xpc;
5964 int error = FALSE;
5965
5966 /* When the optional second argument is non-zero, don't remove matches
5967 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5968 rettv->v_type = VAR_STRING;
5969 if (argvars[1].v_type != VAR_UNKNOWN)
5970 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005971 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972 options |= WILD_KEEP_ALL;
5973 if (argvars[2].v_type != VAR_UNKNOWN)
5974 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005975 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005977 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978 }
5979 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005980 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005981 options |= WILD_ALLLINKS;
5982 }
5983 }
5984 if (!error)
5985 {
5986 ExpandInit(&xpc);
5987 xpc.xp_context = EXPAND_FILES;
5988 if (p_wic)
5989 options += WILD_ICASE;
5990 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005991 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005992 NULL, options, WILD_ALL);
5993 else if (rettv_list_alloc(rettv) != FAIL)
5994 {
5995 int i;
5996
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005997 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005998 NULL, options, WILD_ALL_KEEP);
5999 for (i = 0; i < xpc.xp_numfiles; i++)
6000 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6001
6002 ExpandCleanup(&xpc);
6003 }
6004 }
6005 else
6006 rettv->vval.v_string = NULL;
6007}
6008
6009/*
6010 * "globpath()" function
6011 */
6012 static void
6013f_globpath(typval_T *argvars, typval_T *rettv)
6014{
6015 int flags = 0;
6016 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006017 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 int error = FALSE;
6019 garray_T ga;
6020 int i;
6021
6022 /* When the optional second argument is non-zero, don't remove matches
6023 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6024 rettv->v_type = VAR_STRING;
6025 if (argvars[2].v_type != VAR_UNKNOWN)
6026 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006027 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006028 flags |= WILD_KEEP_ALL;
6029 if (argvars[3].v_type != VAR_UNKNOWN)
6030 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006031 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006032 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006033 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006034 }
6035 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006036 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006037 flags |= WILD_ALLLINKS;
6038 }
6039 }
6040 if (file != NULL && !error)
6041 {
6042 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006043 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006044 if (rettv->v_type == VAR_STRING)
6045 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6046 else if (rettv_list_alloc(rettv) != FAIL)
6047 for (i = 0; i < ga.ga_len; ++i)
6048 list_append_string(rettv->vval.v_list,
6049 ((char_u **)(ga.ga_data))[i], -1);
6050 ga_clear_strings(&ga);
6051 }
6052 else
6053 rettv->vval.v_string = NULL;
6054}
6055
6056/*
6057 * "glob2regpat()" function
6058 */
6059 static void
6060f_glob2regpat(typval_T *argvars, typval_T *rettv)
6061{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006062 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063
6064 rettv->v_type = VAR_STRING;
6065 rettv->vval.v_string = (pat == NULL)
6066 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6067}
6068
6069/* for VIM_VERSION_ defines */
6070#include "version.h"
6071
6072/*
6073 * "has()" function
6074 */
6075 static void
6076f_has(typval_T *argvars, typval_T *rettv)
6077{
6078 int i;
6079 char_u *name;
6080 int n = FALSE;
6081 static char *(has_list[]) =
6082 {
6083#ifdef AMIGA
6084 "amiga",
6085# ifdef FEAT_ARP
6086 "arp",
6087# endif
6088#endif
6089#ifdef __BEOS__
6090 "beos",
6091#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006092#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006093 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6094 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006095# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006096 "macunix", /* Mac OS X, with the darwin feature */
6097 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006098# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006099#endif
6100#ifdef __QNX__
6101 "qnx",
6102#endif
6103#ifdef UNIX
6104 "unix",
6105#endif
6106#ifdef VMS
6107 "vms",
6108#endif
6109#ifdef WIN32
6110 "win32",
6111#endif
6112#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6113 "win32unix",
6114#endif
6115#if defined(WIN64) || defined(_WIN64)
6116 "win64",
6117#endif
6118#ifdef EBCDIC
6119 "ebcdic",
6120#endif
6121#ifndef CASE_INSENSITIVE_FILENAME
6122 "fname_case",
6123#endif
6124#ifdef HAVE_ACL
6125 "acl",
6126#endif
6127#ifdef FEAT_ARABIC
6128 "arabic",
6129#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006130 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006131#ifdef FEAT_AUTOCHDIR
6132 "autochdir",
6133#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006134#ifdef FEAT_AUTOSERVERNAME
6135 "autoservername",
6136#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006137#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006138 "balloon_eval",
6139# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6140 "balloon_multiline",
6141# endif
6142#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006143#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006144 "balloon_eval_term",
6145#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006146#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6147 "builtin_terms",
6148# ifdef ALL_BUILTIN_TCAPS
6149 "all_builtin_terms",
6150# endif
6151#endif
6152#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6153 || defined(FEAT_GUI_W32) \
6154 || defined(FEAT_GUI_MOTIF))
6155 "browsefilter",
6156#endif
6157#ifdef FEAT_BYTEOFF
6158 "byte_offset",
6159#endif
6160#ifdef FEAT_JOB_CHANNEL
6161 "channel",
6162#endif
6163#ifdef FEAT_CINDENT
6164 "cindent",
6165#endif
6166#ifdef FEAT_CLIENTSERVER
6167 "clientserver",
6168#endif
6169#ifdef FEAT_CLIPBOARD
6170 "clipboard",
6171#endif
6172#ifdef FEAT_CMDL_COMPL
6173 "cmdline_compl",
6174#endif
6175#ifdef FEAT_CMDHIST
6176 "cmdline_hist",
6177#endif
6178#ifdef FEAT_COMMENTS
6179 "comments",
6180#endif
6181#ifdef FEAT_CONCEAL
6182 "conceal",
6183#endif
6184#ifdef FEAT_CRYPT
6185 "cryptv",
6186 "crypt-blowfish",
6187 "crypt-blowfish2",
6188#endif
6189#ifdef FEAT_CSCOPE
6190 "cscope",
6191#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006192 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006193#ifdef CURSOR_SHAPE
6194 "cursorshape",
6195#endif
6196#ifdef DEBUG
6197 "debug",
6198#endif
6199#ifdef FEAT_CON_DIALOG
6200 "dialog_con",
6201#endif
6202#ifdef FEAT_GUI_DIALOG
6203 "dialog_gui",
6204#endif
6205#ifdef FEAT_DIFF
6206 "diff",
6207#endif
6208#ifdef FEAT_DIGRAPHS
6209 "digraphs",
6210#endif
6211#ifdef FEAT_DIRECTX
6212 "directx",
6213#endif
6214#ifdef FEAT_DND
6215 "dnd",
6216#endif
6217#ifdef FEAT_EMACS_TAGS
6218 "emacs_tags",
6219#endif
6220 "eval", /* always present, of course! */
6221 "ex_extra", /* graduated feature */
6222#ifdef FEAT_SEARCH_EXTRA
6223 "extra_search",
6224#endif
6225#ifdef FEAT_FKMAP
6226 "farsi",
6227#endif
6228#ifdef FEAT_SEARCHPATH
6229 "file_in_path",
6230#endif
6231#ifdef FEAT_FILTERPIPE
6232 "filterpipe",
6233#endif
6234#ifdef FEAT_FIND_ID
6235 "find_in_path",
6236#endif
6237#ifdef FEAT_FLOAT
6238 "float",
6239#endif
6240#ifdef FEAT_FOLDING
6241 "folding",
6242#endif
6243#ifdef FEAT_FOOTER
6244 "footer",
6245#endif
6246#if !defined(USE_SYSTEM) && defined(UNIX)
6247 "fork",
6248#endif
6249#ifdef FEAT_GETTEXT
6250 "gettext",
6251#endif
6252#ifdef FEAT_GUI
6253 "gui",
6254#endif
6255#ifdef FEAT_GUI_ATHENA
6256# ifdef FEAT_GUI_NEXTAW
6257 "gui_neXtaw",
6258# else
6259 "gui_athena",
6260# endif
6261#endif
6262#ifdef FEAT_GUI_GTK
6263 "gui_gtk",
6264# ifdef USE_GTK3
6265 "gui_gtk3",
6266# else
6267 "gui_gtk2",
6268# endif
6269#endif
6270#ifdef FEAT_GUI_GNOME
6271 "gui_gnome",
6272#endif
6273#ifdef FEAT_GUI_MAC
6274 "gui_mac",
6275#endif
6276#ifdef FEAT_GUI_MOTIF
6277 "gui_motif",
6278#endif
6279#ifdef FEAT_GUI_PHOTON
6280 "gui_photon",
6281#endif
6282#ifdef FEAT_GUI_W32
6283 "gui_win32",
6284#endif
6285#ifdef FEAT_HANGULIN
6286 "hangul_input",
6287#endif
6288#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6289 "iconv",
6290#endif
6291#ifdef FEAT_INS_EXPAND
6292 "insert_expand",
6293#endif
6294#ifdef FEAT_JOB_CHANNEL
6295 "job",
6296#endif
6297#ifdef FEAT_JUMPLIST
6298 "jumplist",
6299#endif
6300#ifdef FEAT_KEYMAP
6301 "keymap",
6302#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006303 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006304#ifdef FEAT_LANGMAP
6305 "langmap",
6306#endif
6307#ifdef FEAT_LIBCALL
6308 "libcall",
6309#endif
6310#ifdef FEAT_LINEBREAK
6311 "linebreak",
6312#endif
6313#ifdef FEAT_LISP
6314 "lispindent",
6315#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006316 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006317#ifdef FEAT_LOCALMAP
6318 "localmap",
6319#endif
6320#ifdef FEAT_LUA
6321# ifndef DYNAMIC_LUA
6322 "lua",
6323# endif
6324#endif
6325#ifdef FEAT_MENU
6326 "menu",
6327#endif
6328#ifdef FEAT_SESSION
6329 "mksession",
6330#endif
6331#ifdef FEAT_MODIFY_FNAME
6332 "modify_fname",
6333#endif
6334#ifdef FEAT_MOUSE
6335 "mouse",
6336#endif
6337#ifdef FEAT_MOUSESHAPE
6338 "mouseshape",
6339#endif
6340#if defined(UNIX) || defined(VMS)
6341# ifdef FEAT_MOUSE_DEC
6342 "mouse_dec",
6343# endif
6344# ifdef FEAT_MOUSE_GPM
6345 "mouse_gpm",
6346# endif
6347# ifdef FEAT_MOUSE_JSB
6348 "mouse_jsbterm",
6349# endif
6350# ifdef FEAT_MOUSE_NET
6351 "mouse_netterm",
6352# endif
6353# ifdef FEAT_MOUSE_PTERM
6354 "mouse_pterm",
6355# endif
6356# ifdef FEAT_MOUSE_SGR
6357 "mouse_sgr",
6358# endif
6359# ifdef FEAT_SYSMOUSE
6360 "mouse_sysmouse",
6361# endif
6362# ifdef FEAT_MOUSE_URXVT
6363 "mouse_urxvt",
6364# endif
6365# ifdef FEAT_MOUSE_XTERM
6366 "mouse_xterm",
6367# endif
6368#endif
6369#ifdef FEAT_MBYTE
6370 "multi_byte",
6371#endif
6372#ifdef FEAT_MBYTE_IME
6373 "multi_byte_ime",
6374#endif
6375#ifdef FEAT_MULTI_LANG
6376 "multi_lang",
6377#endif
6378#ifdef FEAT_MZSCHEME
6379#ifndef DYNAMIC_MZSCHEME
6380 "mzscheme",
6381#endif
6382#endif
6383#ifdef FEAT_NUM64
6384 "num64",
6385#endif
6386#ifdef FEAT_OLE
6387 "ole",
6388#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006389#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006390 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006391#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392#ifdef FEAT_PATH_EXTRA
6393 "path_extra",
6394#endif
6395#ifdef FEAT_PERL
6396#ifndef DYNAMIC_PERL
6397 "perl",
6398#endif
6399#endif
6400#ifdef FEAT_PERSISTENT_UNDO
6401 "persistent_undo",
6402#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006403#if defined(FEAT_PYTHON)
6404 "python_compiled",
6405# if defined(DYNAMIC_PYTHON)
6406 "python_dynamic",
6407# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006408 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006409 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006410# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006411#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006412#if defined(FEAT_PYTHON3)
6413 "python3_compiled",
6414# if defined(DYNAMIC_PYTHON3)
6415 "python3_dynamic",
6416# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006418 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006419# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420#endif
6421#ifdef FEAT_POSTSCRIPT
6422 "postscript",
6423#endif
6424#ifdef FEAT_PRINTER
6425 "printer",
6426#endif
6427#ifdef FEAT_PROFILE
6428 "profile",
6429#endif
6430#ifdef FEAT_RELTIME
6431 "reltime",
6432#endif
6433#ifdef FEAT_QUICKFIX
6434 "quickfix",
6435#endif
6436#ifdef FEAT_RIGHTLEFT
6437 "rightleft",
6438#endif
6439#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6440 "ruby",
6441#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443#ifdef FEAT_CMDL_INFO
6444 "showcmd",
6445 "cmdline_info",
6446#endif
6447#ifdef FEAT_SIGNS
6448 "signs",
6449#endif
6450#ifdef FEAT_SMARTINDENT
6451 "smartindent",
6452#endif
6453#ifdef STARTUPTIME
6454 "startuptime",
6455#endif
6456#ifdef FEAT_STL_OPT
6457 "statusline",
6458#endif
6459#ifdef FEAT_SUN_WORKSHOP
6460 "sun_workshop",
6461#endif
6462#ifdef FEAT_NETBEANS_INTG
6463 "netbeans_intg",
6464#endif
6465#ifdef FEAT_SPELL
6466 "spell",
6467#endif
6468#ifdef FEAT_SYN_HL
6469 "syntax",
6470#endif
6471#if defined(USE_SYSTEM) || !defined(UNIX)
6472 "system",
6473#endif
6474#ifdef FEAT_TAG_BINS
6475 "tag_binary",
6476#endif
6477#ifdef FEAT_TAG_OLDSTATIC
6478 "tag_old_static",
6479#endif
6480#ifdef FEAT_TAG_ANYWHITE
6481 "tag_any_white",
6482#endif
6483#ifdef FEAT_TCL
6484# ifndef DYNAMIC_TCL
6485 "tcl",
6486# endif
6487#endif
6488#ifdef FEAT_TERMGUICOLORS
6489 "termguicolors",
6490#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006491#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006492 "terminal",
6493#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006494#ifdef TERMINFO
6495 "terminfo",
6496#endif
6497#ifdef FEAT_TERMRESPONSE
6498 "termresponse",
6499#endif
6500#ifdef FEAT_TEXTOBJ
6501 "textobjects",
6502#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006503#ifdef FEAT_TEXT_PROP
6504 "textprop",
6505#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006506#ifdef HAVE_TGETENT
6507 "tgetent",
6508#endif
6509#ifdef FEAT_TIMERS
6510 "timers",
6511#endif
6512#ifdef FEAT_TITLE
6513 "title",
6514#endif
6515#ifdef FEAT_TOOLBAR
6516 "toolbar",
6517#endif
6518#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6519 "unnamedplus",
6520#endif
6521#ifdef FEAT_USR_CMDS
6522 "user-commands", /* was accidentally included in 5.4 */
6523 "user_commands",
6524#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006525#ifdef FEAT_VARTABS
6526 "vartabs",
6527#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006528#ifdef FEAT_VIMINFO
6529 "viminfo",
6530#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006531 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006532#ifdef FEAT_VIRTUALEDIT
6533 "virtualedit",
6534#endif
6535 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006536 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006538#ifdef FEAT_VTP
6539 "vtp",
6540#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541#ifdef FEAT_WILDIGN
6542 "wildignore",
6543#endif
6544#ifdef FEAT_WILDMENU
6545 "wildmenu",
6546#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006547 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006548#ifdef FEAT_WAK
6549 "winaltkeys",
6550#endif
6551#ifdef FEAT_WRITEBACKUP
6552 "writebackup",
6553#endif
6554#ifdef FEAT_XIM
6555 "xim",
6556#endif
6557#ifdef FEAT_XFONTSET
6558 "xfontset",
6559#endif
6560#ifdef FEAT_XPM_W32
6561 "xpm",
6562 "xpm_w32", /* for backward compatibility */
6563#else
6564# if defined(HAVE_XPM)
6565 "xpm",
6566# endif
6567#endif
6568#ifdef USE_XSMP
6569 "xsmp",
6570#endif
6571#ifdef USE_XSMP_INTERACT
6572 "xsmp_interact",
6573#endif
6574#ifdef FEAT_XCLIPBOARD
6575 "xterm_clipboard",
6576#endif
6577#ifdef FEAT_XTERM_SAVE
6578 "xterm_save",
6579#endif
6580#if defined(UNIX) && defined(FEAT_X11)
6581 "X11",
6582#endif
6583 NULL
6584 };
6585
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006586 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006587 for (i = 0; has_list[i] != NULL; ++i)
6588 if (STRICMP(name, has_list[i]) == 0)
6589 {
6590 n = TRUE;
6591 break;
6592 }
6593
6594 if (n == FALSE)
6595 {
6596 if (STRNICMP(name, "patch", 5) == 0)
6597 {
6598 if (name[5] == '-'
6599 && STRLEN(name) >= 11
6600 && vim_isdigit(name[6])
6601 && vim_isdigit(name[8])
6602 && vim_isdigit(name[10]))
6603 {
6604 int major = atoi((char *)name + 6);
6605 int minor = atoi((char *)name + 8);
6606
6607 /* Expect "patch-9.9.01234". */
6608 n = (major < VIM_VERSION_MAJOR
6609 || (major == VIM_VERSION_MAJOR
6610 && (minor < VIM_VERSION_MINOR
6611 || (minor == VIM_VERSION_MINOR
6612 && has_patch(atoi((char *)name + 10))))));
6613 }
6614 else
6615 n = has_patch(atoi((char *)name + 5));
6616 }
6617 else if (STRICMP(name, "vim_starting") == 0)
6618 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006619 else if (STRICMP(name, "ttyin") == 0)
6620 n = mch_input_isatty();
6621 else if (STRICMP(name, "ttyout") == 0)
6622 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006623#ifdef FEAT_MBYTE
6624 else if (STRICMP(name, "multi_byte_encoding") == 0)
6625 n = has_mbyte;
6626#endif
6627#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6628 else if (STRICMP(name, "balloon_multiline") == 0)
6629 n = multiline_balloon_available();
6630#endif
6631#ifdef DYNAMIC_TCL
6632 else if (STRICMP(name, "tcl") == 0)
6633 n = tcl_enabled(FALSE);
6634#endif
6635#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6636 else if (STRICMP(name, "iconv") == 0)
6637 n = iconv_enabled(FALSE);
6638#endif
6639#ifdef DYNAMIC_LUA
6640 else if (STRICMP(name, "lua") == 0)
6641 n = lua_enabled(FALSE);
6642#endif
6643#ifdef DYNAMIC_MZSCHEME
6644 else if (STRICMP(name, "mzscheme") == 0)
6645 n = mzscheme_enabled(FALSE);
6646#endif
6647#ifdef DYNAMIC_RUBY
6648 else if (STRICMP(name, "ruby") == 0)
6649 n = ruby_enabled(FALSE);
6650#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651#ifdef DYNAMIC_PYTHON
6652 else if (STRICMP(name, "python") == 0)
6653 n = python_enabled(FALSE);
6654#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006655#ifdef DYNAMIC_PYTHON3
6656 else if (STRICMP(name, "python3") == 0)
6657 n = python3_enabled(FALSE);
6658#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006659#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6660 else if (STRICMP(name, "pythonx") == 0)
6661 {
6662# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6663 if (p_pyx == 0)
6664 n = python3_enabled(FALSE) || python_enabled(FALSE);
6665 else if (p_pyx == 3)
6666 n = python3_enabled(FALSE);
6667 else if (p_pyx == 2)
6668 n = python_enabled(FALSE);
6669# elif defined(DYNAMIC_PYTHON)
6670 n = python_enabled(FALSE);
6671# elif defined(DYNAMIC_PYTHON3)
6672 n = python3_enabled(FALSE);
6673# endif
6674 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675#endif
6676#ifdef DYNAMIC_PERL
6677 else if (STRICMP(name, "perl") == 0)
6678 n = perl_enabled(FALSE);
6679#endif
6680#ifdef FEAT_GUI
6681 else if (STRICMP(name, "gui_running") == 0)
6682 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683# ifdef FEAT_BROWSE
6684 else if (STRICMP(name, "browse") == 0)
6685 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6686# endif
6687#endif
6688#ifdef FEAT_SYN_HL
6689 else if (STRICMP(name, "syntax_items") == 0)
6690 n = syntax_present(curwin);
6691#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006692#ifdef FEAT_VTP
6693 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006694 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006695#endif
6696#ifdef FEAT_NETBEANS_INTG
6697 else if (STRICMP(name, "netbeans_enabled") == 0)
6698 n = netbeans_active();
6699#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006700#if defined(FEAT_TERMINAL) && defined(WIN3264)
6701 else if (STRICMP(name, "terminal") == 0)
6702 n = terminal_enabled();
6703#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006704 }
6705
6706 rettv->vval.v_number = n;
6707}
6708
6709/*
6710 * "has_key()" function
6711 */
6712 static void
6713f_has_key(typval_T *argvars, typval_T *rettv)
6714{
6715 if (argvars[0].v_type != VAR_DICT)
6716 {
6717 EMSG(_(e_dictreq));
6718 return;
6719 }
6720 if (argvars[0].vval.v_dict == NULL)
6721 return;
6722
6723 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006724 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006725}
6726
6727/*
6728 * "haslocaldir()" function
6729 */
6730 static void
6731f_haslocaldir(typval_T *argvars, typval_T *rettv)
6732{
6733 win_T *wp = NULL;
6734
6735 wp = find_tabwin(&argvars[0], &argvars[1]);
6736 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6737}
6738
6739/*
6740 * "hasmapto()" function
6741 */
6742 static void
6743f_hasmapto(typval_T *argvars, typval_T *rettv)
6744{
6745 char_u *name;
6746 char_u *mode;
6747 char_u buf[NUMBUFLEN];
6748 int abbr = FALSE;
6749
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006750 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006751 if (argvars[1].v_type == VAR_UNKNOWN)
6752 mode = (char_u *)"nvo";
6753 else
6754 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006755 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006756 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006757 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 }
6759
6760 if (map_to_exists(name, mode, abbr))
6761 rettv->vval.v_number = TRUE;
6762 else
6763 rettv->vval.v_number = FALSE;
6764}
6765
6766/*
6767 * "histadd()" function
6768 */
6769 static void
6770f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6771{
6772#ifdef FEAT_CMDHIST
6773 int histype;
6774 char_u *str;
6775 char_u buf[NUMBUFLEN];
6776#endif
6777
6778 rettv->vval.v_number = FALSE;
6779 if (check_restricted() || check_secure())
6780 return;
6781#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006782 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006783 histype = str != NULL ? get_histtype(str) : -1;
6784 if (histype >= 0)
6785 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006786 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006787 if (*str != NUL)
6788 {
6789 init_history();
6790 add_to_history(histype, str, FALSE, NUL);
6791 rettv->vval.v_number = TRUE;
6792 return;
6793 }
6794 }
6795#endif
6796}
6797
6798/*
6799 * "histdel()" function
6800 */
6801 static void
6802f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6803{
6804#ifdef FEAT_CMDHIST
6805 int n;
6806 char_u buf[NUMBUFLEN];
6807 char_u *str;
6808
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006809 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006810 if (str == NULL)
6811 n = 0;
6812 else if (argvars[1].v_type == VAR_UNKNOWN)
6813 /* only one argument: clear entire history */
6814 n = clr_history(get_histtype(str));
6815 else if (argvars[1].v_type == VAR_NUMBER)
6816 /* index given: remove that entry */
6817 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006818 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006819 else
6820 /* string given: remove all matching entries */
6821 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006822 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006823 rettv->vval.v_number = n;
6824#endif
6825}
6826
6827/*
6828 * "histget()" function
6829 */
6830 static void
6831f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6832{
6833#ifdef FEAT_CMDHIST
6834 int type;
6835 int idx;
6836 char_u *str;
6837
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006838 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006839 if (str == NULL)
6840 rettv->vval.v_string = NULL;
6841 else
6842 {
6843 type = get_histtype(str);
6844 if (argvars[1].v_type == VAR_UNKNOWN)
6845 idx = get_history_idx(type);
6846 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006847 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006848 /* -1 on type error */
6849 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6850 }
6851#else
6852 rettv->vval.v_string = NULL;
6853#endif
6854 rettv->v_type = VAR_STRING;
6855}
6856
6857/*
6858 * "histnr()" function
6859 */
6860 static void
6861f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6862{
6863 int i;
6864
6865#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006866 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006867
6868 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6869 if (i >= HIST_CMD && i < HIST_COUNT)
6870 i = get_history_idx(i);
6871 else
6872#endif
6873 i = -1;
6874 rettv->vval.v_number = i;
6875}
6876
6877/*
6878 * "highlightID(name)" function
6879 */
6880 static void
6881f_hlID(typval_T *argvars, typval_T *rettv)
6882{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006883 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006884}
6885
6886/*
6887 * "highlight_exists()" function
6888 */
6889 static void
6890f_hlexists(typval_T *argvars, typval_T *rettv)
6891{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006892 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893}
6894
6895/*
6896 * "hostname()" function
6897 */
6898 static void
6899f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6900{
6901 char_u hostname[256];
6902
6903 mch_get_host_name(hostname, 256);
6904 rettv->v_type = VAR_STRING;
6905 rettv->vval.v_string = vim_strsave(hostname);
6906}
6907
6908/*
6909 * iconv() function
6910 */
6911 static void
6912f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6913{
6914#ifdef FEAT_MBYTE
6915 char_u buf1[NUMBUFLEN];
6916 char_u buf2[NUMBUFLEN];
6917 char_u *from, *to, *str;
6918 vimconv_T vimconv;
6919#endif
6920
6921 rettv->v_type = VAR_STRING;
6922 rettv->vval.v_string = NULL;
6923
6924#ifdef FEAT_MBYTE
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006925 str = tv_get_string(&argvars[0]);
6926 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6927 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006928 vimconv.vc_type = CONV_NONE;
6929 convert_setup(&vimconv, from, to);
6930
6931 /* If the encodings are equal, no conversion needed. */
6932 if (vimconv.vc_type == CONV_NONE)
6933 rettv->vval.v_string = vim_strsave(str);
6934 else
6935 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6936
6937 convert_setup(&vimconv, NULL, NULL);
6938 vim_free(from);
6939 vim_free(to);
6940#endif
6941}
6942
6943/*
6944 * "indent()" function
6945 */
6946 static void
6947f_indent(typval_T *argvars, typval_T *rettv)
6948{
6949 linenr_T lnum;
6950
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006951 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006952 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6953 rettv->vval.v_number = get_indent_lnum(lnum);
6954 else
6955 rettv->vval.v_number = -1;
6956}
6957
6958/*
6959 * "index()" function
6960 */
6961 static void
6962f_index(typval_T *argvars, typval_T *rettv)
6963{
6964 list_T *l;
6965 listitem_T *item;
6966 long idx = 0;
6967 int ic = FALSE;
6968
6969 rettv->vval.v_number = -1;
6970 if (argvars[0].v_type != VAR_LIST)
6971 {
6972 EMSG(_(e_listreq));
6973 return;
6974 }
6975 l = argvars[0].vval.v_list;
6976 if (l != NULL)
6977 {
6978 item = l->lv_first;
6979 if (argvars[2].v_type != VAR_UNKNOWN)
6980 {
6981 int error = FALSE;
6982
6983 /* Start at specified item. Use the cached index that list_find()
6984 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006985 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986 idx = l->lv_idx;
6987 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006988 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006989 if (error)
6990 item = NULL;
6991 }
6992
6993 for ( ; item != NULL; item = item->li_next, ++idx)
6994 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6995 {
6996 rettv->vval.v_number = idx;
6997 break;
6998 }
6999 }
7000}
7001
7002static int inputsecret_flag = 0;
7003
7004/*
7005 * "input()" function
7006 * Also handles inputsecret() when inputsecret is set.
7007 */
7008 static void
7009f_input(typval_T *argvars, typval_T *rettv)
7010{
7011 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7012}
7013
7014/*
7015 * "inputdialog()" function
7016 */
7017 static void
7018f_inputdialog(typval_T *argvars, typval_T *rettv)
7019{
7020#if defined(FEAT_GUI_TEXTDIALOG)
7021 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7022 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7023 {
7024 char_u *message;
7025 char_u buf[NUMBUFLEN];
7026 char_u *defstr = (char_u *)"";
7027
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007028 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007030 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007031 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7032 else
7033 IObuff[0] = NUL;
7034 if (message != NULL && defstr != NULL
7035 && do_dialog(VIM_QUESTION, NULL, message,
7036 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7037 rettv->vval.v_string = vim_strsave(IObuff);
7038 else
7039 {
7040 if (message != NULL && defstr != NULL
7041 && argvars[1].v_type != VAR_UNKNOWN
7042 && argvars[2].v_type != VAR_UNKNOWN)
7043 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007044 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007045 else
7046 rettv->vval.v_string = NULL;
7047 }
7048 rettv->v_type = VAR_STRING;
7049 }
7050 else
7051#endif
7052 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7053}
7054
7055/*
7056 * "inputlist()" function
7057 */
7058 static void
7059f_inputlist(typval_T *argvars, typval_T *rettv)
7060{
7061 listitem_T *li;
7062 int selected;
7063 int mouse_used;
7064
7065#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007066 /* While starting up, there is no place to enter text. When running tests
7067 * with --not-a-term we assume feedkeys() will be used. */
7068 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069 return;
7070#endif
7071 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7072 {
7073 EMSG2(_(e_listarg), "inputlist()");
7074 return;
7075 }
7076
7077 msg_start();
7078 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7079 lines_left = Rows; /* avoid more prompt */
7080 msg_scroll = TRUE;
7081 msg_clr_eos();
7082
7083 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7084 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007085 msg_puts(tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007086 msg_putchar('\n');
7087 }
7088
7089 /* Ask for choice. */
7090 selected = prompt_for_number(&mouse_used);
7091 if (mouse_used)
7092 selected -= lines_left;
7093
7094 rettv->vval.v_number = selected;
7095}
7096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007097static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7098
7099/*
7100 * "inputrestore()" function
7101 */
7102 static void
7103f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7104{
7105 if (ga_userinput.ga_len > 0)
7106 {
7107 --ga_userinput.ga_len;
7108 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7109 + ga_userinput.ga_len);
7110 /* default return is zero == OK */
7111 }
7112 else if (p_verbose > 1)
7113 {
7114 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
7115 rettv->vval.v_number = 1; /* Failed */
7116 }
7117}
7118
7119/*
7120 * "inputsave()" function
7121 */
7122 static void
7123f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7124{
7125 /* Add an entry to the stack of typeahead storage. */
7126 if (ga_grow(&ga_userinput, 1) == OK)
7127 {
7128 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7129 + ga_userinput.ga_len);
7130 ++ga_userinput.ga_len;
7131 /* default return is zero == OK */
7132 }
7133 else
7134 rettv->vval.v_number = 1; /* Failed */
7135}
7136
7137/*
7138 * "inputsecret()" function
7139 */
7140 static void
7141f_inputsecret(typval_T *argvars, typval_T *rettv)
7142{
7143 ++cmdline_star;
7144 ++inputsecret_flag;
7145 f_input(argvars, rettv);
7146 --cmdline_star;
7147 --inputsecret_flag;
7148}
7149
7150/*
7151 * "insert()" function
7152 */
7153 static void
7154f_insert(typval_T *argvars, typval_T *rettv)
7155{
7156 long before = 0;
7157 listitem_T *item;
7158 list_T *l;
7159 int error = FALSE;
7160
7161 if (argvars[0].v_type != VAR_LIST)
7162 EMSG2(_(e_listarg), "insert()");
7163 else if ((l = argvars[0].vval.v_list) != NULL
7164 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7165 {
7166 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007167 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007168 if (error)
7169 return; /* type error; errmsg already given */
7170
7171 if (before == l->lv_len)
7172 item = NULL;
7173 else
7174 {
7175 item = list_find(l, before);
7176 if (item == NULL)
7177 {
7178 EMSGN(_(e_listidx), before);
7179 l = NULL;
7180 }
7181 }
7182 if (l != NULL)
7183 {
7184 list_insert_tv(l, &argvars[1], item);
7185 copy_tv(&argvars[0], rettv);
7186 }
7187 }
7188}
7189
7190/*
7191 * "invert(expr)" function
7192 */
7193 static void
7194f_invert(typval_T *argvars, typval_T *rettv)
7195{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007196 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197}
7198
7199/*
7200 * "isdirectory()" function
7201 */
7202 static void
7203f_isdirectory(typval_T *argvars, typval_T *rettv)
7204{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007205 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206}
7207
7208/*
7209 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7210 * or it refers to a List or Dictionary that is locked.
7211 */
7212 static int
7213tv_islocked(typval_T *tv)
7214{
7215 return (tv->v_lock & VAR_LOCKED)
7216 || (tv->v_type == VAR_LIST
7217 && tv->vval.v_list != NULL
7218 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7219 || (tv->v_type == VAR_DICT
7220 && tv->vval.v_dict != NULL
7221 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7222}
7223
7224/*
7225 * "islocked()" function
7226 */
7227 static void
7228f_islocked(typval_T *argvars, typval_T *rettv)
7229{
7230 lval_T lv;
7231 char_u *end;
7232 dictitem_T *di;
7233
7234 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007235 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007236 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007237 if (end != NULL && lv.ll_name != NULL)
7238 {
7239 if (*end != NUL)
7240 EMSG(_(e_trailing));
7241 else
7242 {
7243 if (lv.ll_tv == NULL)
7244 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007245 di = find_var(lv.ll_name, NULL, TRUE);
7246 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007248 /* Consider a variable locked when:
7249 * 1. the variable itself is locked
7250 * 2. the value of the variable is locked.
7251 * 3. the List or Dict value is locked.
7252 */
7253 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7254 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 }
7256 }
7257 else if (lv.ll_range)
7258 EMSG(_("E786: Range not allowed"));
7259 else if (lv.ll_newkey != NULL)
7260 EMSG2(_(e_dictkey), lv.ll_newkey);
7261 else if (lv.ll_list != NULL)
7262 /* List item. */
7263 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7264 else
7265 /* Dictionary item. */
7266 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7267 }
7268 }
7269
7270 clear_lval(&lv);
7271}
7272
7273#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7274/*
7275 * "isnan()" function
7276 */
7277 static void
7278f_isnan(typval_T *argvars, typval_T *rettv)
7279{
7280 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7281 && isnan(argvars[0].vval.v_float);
7282}
7283#endif
7284
7285/*
7286 * "items(dict)" function
7287 */
7288 static void
7289f_items(typval_T *argvars, typval_T *rettv)
7290{
7291 dict_list(argvars, rettv, 2);
7292}
7293
7294#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7295/*
7296 * Get the job from the argument.
7297 * Returns NULL if the job is invalid.
7298 */
7299 static job_T *
7300get_job_arg(typval_T *tv)
7301{
7302 job_T *job;
7303
7304 if (tv->v_type != VAR_JOB)
7305 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007306 EMSG2(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007307 return NULL;
7308 }
7309 job = tv->vval.v_job;
7310
7311 if (job == NULL)
7312 EMSG(_("E916: not a valid job"));
7313 return job;
7314}
7315
7316/*
7317 * "job_getchannel()" function
7318 */
7319 static void
7320f_job_getchannel(typval_T *argvars, typval_T *rettv)
7321{
7322 job_T *job = get_job_arg(&argvars[0]);
7323
7324 if (job != NULL)
7325 {
7326 rettv->v_type = VAR_CHANNEL;
7327 rettv->vval.v_channel = job->jv_channel;
7328 if (job->jv_channel != NULL)
7329 ++job->jv_channel->ch_refcount;
7330 }
7331}
7332
7333/*
7334 * "job_info()" function
7335 */
7336 static void
7337f_job_info(typval_T *argvars, typval_T *rettv)
7338{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007339 if (argvars[0].v_type != VAR_UNKNOWN)
7340 {
7341 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007343 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7344 job_info(job, rettv->vval.v_dict);
7345 }
7346 else if (rettv_list_alloc(rettv) == OK)
7347 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007348}
7349
7350/*
7351 * "job_setoptions()" function
7352 */
7353 static void
7354f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7355{
7356 job_T *job = get_job_arg(&argvars[0]);
7357 jobopt_T opt;
7358
7359 if (job == NULL)
7360 return;
7361 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007362 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007363 job_set_options(job, &opt);
7364 free_job_options(&opt);
7365}
7366
7367/*
7368 * "job_start()" function
7369 */
7370 static void
7371f_job_start(typval_T *argvars, typval_T *rettv)
7372{
7373 rettv->v_type = VAR_JOB;
7374 if (check_restricted() || check_secure())
7375 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007376 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377}
7378
7379/*
7380 * "job_status()" function
7381 */
7382 static void
7383f_job_status(typval_T *argvars, typval_T *rettv)
7384{
7385 job_T *job = get_job_arg(&argvars[0]);
7386
7387 if (job != NULL)
7388 {
7389 rettv->v_type = VAR_STRING;
7390 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7391 }
7392}
7393
7394/*
7395 * "job_stop()" function
7396 */
7397 static void
7398f_job_stop(typval_T *argvars, typval_T *rettv)
7399{
7400 job_T *job = get_job_arg(&argvars[0]);
7401
7402 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007403 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007404}
7405#endif
7406
7407/*
7408 * "join()" function
7409 */
7410 static void
7411f_join(typval_T *argvars, typval_T *rettv)
7412{
7413 garray_T ga;
7414 char_u *sep;
7415
7416 if (argvars[0].v_type != VAR_LIST)
7417 {
7418 EMSG(_(e_listreq));
7419 return;
7420 }
7421 if (argvars[0].vval.v_list == NULL)
7422 return;
7423 if (argvars[1].v_type == VAR_UNKNOWN)
7424 sep = (char_u *)" ";
7425 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007426 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427
7428 rettv->v_type = VAR_STRING;
7429
7430 if (sep != NULL)
7431 {
7432 ga_init2(&ga, (int)sizeof(char), 80);
7433 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7434 ga_append(&ga, NUL);
7435 rettv->vval.v_string = (char_u *)ga.ga_data;
7436 }
7437 else
7438 rettv->vval.v_string = NULL;
7439}
7440
7441/*
7442 * "js_decode()" function
7443 */
7444 static void
7445f_js_decode(typval_T *argvars, typval_T *rettv)
7446{
7447 js_read_T reader;
7448
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007449 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007450 reader.js_fill = NULL;
7451 reader.js_used = 0;
7452 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7453 EMSG(_(e_invarg));
7454}
7455
7456/*
7457 * "js_encode()" function
7458 */
7459 static void
7460f_js_encode(typval_T *argvars, typval_T *rettv)
7461{
7462 rettv->v_type = VAR_STRING;
7463 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7464}
7465
7466/*
7467 * "json_decode()" function
7468 */
7469 static void
7470f_json_decode(typval_T *argvars, typval_T *rettv)
7471{
7472 js_read_T reader;
7473
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007474 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007475 reader.js_fill = NULL;
7476 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007477 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478}
7479
7480/*
7481 * "json_encode()" function
7482 */
7483 static void
7484f_json_encode(typval_T *argvars, typval_T *rettv)
7485{
7486 rettv->v_type = VAR_STRING;
7487 rettv->vval.v_string = json_encode(&argvars[0], 0);
7488}
7489
7490/*
7491 * "keys()" function
7492 */
7493 static void
7494f_keys(typval_T *argvars, typval_T *rettv)
7495{
7496 dict_list(argvars, rettv, 0);
7497}
7498
7499/*
7500 * "last_buffer_nr()" function.
7501 */
7502 static void
7503f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7504{
7505 int n = 0;
7506 buf_T *buf;
7507
Bram Moolenaar29323592016-07-24 22:04:11 +02007508 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007509 if (n < buf->b_fnum)
7510 n = buf->b_fnum;
7511
7512 rettv->vval.v_number = n;
7513}
7514
7515/*
7516 * "len()" function
7517 */
7518 static void
7519f_len(typval_T *argvars, typval_T *rettv)
7520{
7521 switch (argvars[0].v_type)
7522 {
7523 case VAR_STRING:
7524 case VAR_NUMBER:
7525 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007526 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527 break;
7528 case VAR_LIST:
7529 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7530 break;
7531 case VAR_DICT:
7532 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7533 break;
7534 case VAR_UNKNOWN:
7535 case VAR_SPECIAL:
7536 case VAR_FLOAT:
7537 case VAR_FUNC:
7538 case VAR_PARTIAL:
7539 case VAR_JOB:
7540 case VAR_CHANNEL:
7541 EMSG(_("E701: Invalid type for len()"));
7542 break;
7543 }
7544}
7545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007547libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007548{
7549#ifdef FEAT_LIBCALL
7550 char_u *string_in;
7551 char_u **string_result;
7552 int nr_result;
7553#endif
7554
7555 rettv->v_type = type;
7556 if (type != VAR_NUMBER)
7557 rettv->vval.v_string = NULL;
7558
7559 if (check_restricted() || check_secure())
7560 return;
7561
7562#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007563 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007564 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7565 {
7566 string_in = NULL;
7567 if (argvars[2].v_type == VAR_STRING)
7568 string_in = argvars[2].vval.v_string;
7569 if (type == VAR_NUMBER)
7570 string_result = NULL;
7571 else
7572 string_result = &rettv->vval.v_string;
7573 if (mch_libcall(argvars[0].vval.v_string,
7574 argvars[1].vval.v_string,
7575 string_in,
7576 argvars[2].vval.v_number,
7577 string_result,
7578 &nr_result) == OK
7579 && type == VAR_NUMBER)
7580 rettv->vval.v_number = nr_result;
7581 }
7582#endif
7583}
7584
7585/*
7586 * "libcall()" function
7587 */
7588 static void
7589f_libcall(typval_T *argvars, typval_T *rettv)
7590{
7591 libcall_common(argvars, rettv, VAR_STRING);
7592}
7593
7594/*
7595 * "libcallnr()" function
7596 */
7597 static void
7598f_libcallnr(typval_T *argvars, typval_T *rettv)
7599{
7600 libcall_common(argvars, rettv, VAR_NUMBER);
7601}
7602
7603/*
7604 * "line(string)" function
7605 */
7606 static void
7607f_line(typval_T *argvars, typval_T *rettv)
7608{
7609 linenr_T lnum = 0;
7610 pos_T *fp;
7611 int fnum;
7612
7613 fp = var2fpos(&argvars[0], TRUE, &fnum);
7614 if (fp != NULL)
7615 lnum = fp->lnum;
7616 rettv->vval.v_number = lnum;
7617}
7618
7619/*
7620 * "line2byte(lnum)" function
7621 */
7622 static void
7623f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7624{
7625#ifndef FEAT_BYTEOFF
7626 rettv->vval.v_number = -1;
7627#else
7628 linenr_T lnum;
7629
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007630 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007631 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7632 rettv->vval.v_number = -1;
7633 else
7634 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7635 if (rettv->vval.v_number >= 0)
7636 ++rettv->vval.v_number;
7637#endif
7638}
7639
7640/*
7641 * "lispindent(lnum)" function
7642 */
7643 static void
7644f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7645{
7646#ifdef FEAT_LISP
7647 pos_T pos;
7648 linenr_T lnum;
7649
7650 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007651 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7653 {
7654 curwin->w_cursor.lnum = lnum;
7655 rettv->vval.v_number = get_lisp_indent();
7656 curwin->w_cursor = pos;
7657 }
7658 else
7659#endif
7660 rettv->vval.v_number = -1;
7661}
7662
7663/*
7664 * "localtime()" function
7665 */
7666 static void
7667f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7668{
7669 rettv->vval.v_number = (varnumber_T)time(NULL);
7670}
7671
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 static void
7673get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7674{
7675 char_u *keys;
7676 char_u *which;
7677 char_u buf[NUMBUFLEN];
7678 char_u *keys_buf = NULL;
7679 char_u *rhs;
7680 int mode;
7681 int abbr = FALSE;
7682 int get_dict = FALSE;
7683 mapblock_T *mp;
7684 int buffer_local;
7685
7686 /* return empty string for failure */
7687 rettv->v_type = VAR_STRING;
7688 rettv->vval.v_string = NULL;
7689
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007690 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007691 if (*keys == NUL)
7692 return;
7693
7694 if (argvars[1].v_type != VAR_UNKNOWN)
7695 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007696 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007697 if (argvars[2].v_type != VAR_UNKNOWN)
7698 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007699 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007700 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007701 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007702 }
7703 }
7704 else
7705 which = (char_u *)"";
7706 if (which == NULL)
7707 return;
7708
7709 mode = get_map_mode(&which, 0);
7710
7711 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7712 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7713 vim_free(keys_buf);
7714
7715 if (!get_dict)
7716 {
7717 /* Return a string. */
7718 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007719 {
7720 if (*rhs == NUL)
7721 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7722 else
7723 rettv->vval.v_string = str2special_save(rhs, FALSE);
7724 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725
7726 }
7727 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7728 {
7729 /* Return a dictionary. */
7730 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7731 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7732 dict_T *dict = rettv->vval.v_dict;
7733
Bram Moolenaare0be1672018-07-08 16:50:37 +02007734 dict_add_string(dict, "lhs", lhs);
7735 dict_add_string(dict, "rhs", mp->m_orig_str);
7736 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7737 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7738 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007739 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7740 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007741 dict_add_number(dict, "buffer", (long)buffer_local);
7742 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7743 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744
7745 vim_free(lhs);
7746 vim_free(mapmode);
7747 }
7748}
7749
7750#ifdef FEAT_FLOAT
7751/*
7752 * "log()" function
7753 */
7754 static void
7755f_log(typval_T *argvars, typval_T *rettv)
7756{
7757 float_T f = 0.0;
7758
7759 rettv->v_type = VAR_FLOAT;
7760 if (get_float_arg(argvars, &f) == OK)
7761 rettv->vval.v_float = log(f);
7762 else
7763 rettv->vval.v_float = 0.0;
7764}
7765
7766/*
7767 * "log10()" function
7768 */
7769 static void
7770f_log10(typval_T *argvars, typval_T *rettv)
7771{
7772 float_T f = 0.0;
7773
7774 rettv->v_type = VAR_FLOAT;
7775 if (get_float_arg(argvars, &f) == OK)
7776 rettv->vval.v_float = log10(f);
7777 else
7778 rettv->vval.v_float = 0.0;
7779}
7780#endif
7781
7782#ifdef FEAT_LUA
7783/*
7784 * "luaeval()" function
7785 */
7786 static void
7787f_luaeval(typval_T *argvars, typval_T *rettv)
7788{
7789 char_u *str;
7790 char_u buf[NUMBUFLEN];
7791
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007792 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007793 do_luaeval(str, argvars + 1, rettv);
7794}
7795#endif
7796
7797/*
7798 * "map()" function
7799 */
7800 static void
7801f_map(typval_T *argvars, typval_T *rettv)
7802{
7803 filter_map(argvars, rettv, TRUE);
7804}
7805
7806/*
7807 * "maparg()" function
7808 */
7809 static void
7810f_maparg(typval_T *argvars, typval_T *rettv)
7811{
7812 get_maparg(argvars, rettv, TRUE);
7813}
7814
7815/*
7816 * "mapcheck()" function
7817 */
7818 static void
7819f_mapcheck(typval_T *argvars, typval_T *rettv)
7820{
7821 get_maparg(argvars, rettv, FALSE);
7822}
7823
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007824typedef enum
7825{
7826 MATCH_END, /* matchend() */
7827 MATCH_MATCH, /* match() */
7828 MATCH_STR, /* matchstr() */
7829 MATCH_LIST, /* matchlist() */
7830 MATCH_POS /* matchstrpos() */
7831} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832
7833 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007834find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007835{
7836 char_u *str = NULL;
7837 long len = 0;
7838 char_u *expr = NULL;
7839 char_u *pat;
7840 regmatch_T regmatch;
7841 char_u patbuf[NUMBUFLEN];
7842 char_u strbuf[NUMBUFLEN];
7843 char_u *save_cpo;
7844 long start = 0;
7845 long nth = 1;
7846 colnr_T startcol = 0;
7847 int match = 0;
7848 list_T *l = NULL;
7849 listitem_T *li = NULL;
7850 long idx = 0;
7851 char_u *tofree = NULL;
7852
7853 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7854 save_cpo = p_cpo;
7855 p_cpo = (char_u *)"";
7856
7857 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007858 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007860 /* type MATCH_LIST: return empty list when there are no matches.
7861 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007862 if (rettv_list_alloc(rettv) == FAIL)
7863 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007864 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007865 && (list_append_string(rettv->vval.v_list,
7866 (char_u *)"", 0) == FAIL
7867 || list_append_number(rettv->vval.v_list,
7868 (varnumber_T)-1) == FAIL
7869 || list_append_number(rettv->vval.v_list,
7870 (varnumber_T)-1) == FAIL
7871 || list_append_number(rettv->vval.v_list,
7872 (varnumber_T)-1) == FAIL))
7873 {
7874 list_free(rettv->vval.v_list);
7875 rettv->vval.v_list = NULL;
7876 goto theend;
7877 }
7878 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007879 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 {
7881 rettv->v_type = VAR_STRING;
7882 rettv->vval.v_string = NULL;
7883 }
7884
7885 if (argvars[0].v_type == VAR_LIST)
7886 {
7887 if ((l = argvars[0].vval.v_list) == NULL)
7888 goto theend;
7889 li = l->lv_first;
7890 }
7891 else
7892 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007893 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007894 len = (long)STRLEN(str);
7895 }
7896
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007897 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007898 if (pat == NULL)
7899 goto theend;
7900
7901 if (argvars[2].v_type != VAR_UNKNOWN)
7902 {
7903 int error = FALSE;
7904
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007905 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007906 if (error)
7907 goto theend;
7908 if (l != NULL)
7909 {
7910 li = list_find(l, start);
7911 if (li == NULL)
7912 goto theend;
7913 idx = l->lv_idx; /* use the cached index */
7914 }
7915 else
7916 {
7917 if (start < 0)
7918 start = 0;
7919 if (start > len)
7920 goto theend;
7921 /* When "count" argument is there ignore matches before "start",
7922 * otherwise skip part of the string. Differs when pattern is "^"
7923 * or "\<". */
7924 if (argvars[3].v_type != VAR_UNKNOWN)
7925 startcol = start;
7926 else
7927 {
7928 str += start;
7929 len -= start;
7930 }
7931 }
7932
7933 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007934 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007935 if (error)
7936 goto theend;
7937 }
7938
7939 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7940 if (regmatch.regprog != NULL)
7941 {
7942 regmatch.rm_ic = p_ic;
7943
7944 for (;;)
7945 {
7946 if (l != NULL)
7947 {
7948 if (li == NULL)
7949 {
7950 match = FALSE;
7951 break;
7952 }
7953 vim_free(tofree);
7954 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7955 if (str == NULL)
7956 break;
7957 }
7958
7959 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7960
7961 if (match && --nth <= 0)
7962 break;
7963 if (l == NULL && !match)
7964 break;
7965
7966 /* Advance to just after the match. */
7967 if (l != NULL)
7968 {
7969 li = li->li_next;
7970 ++idx;
7971 }
7972 else
7973 {
7974#ifdef FEAT_MBYTE
7975 startcol = (colnr_T)(regmatch.startp[0]
7976 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7977#else
7978 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7979#endif
7980 if (startcol > (colnr_T)len
7981 || str + startcol <= regmatch.startp[0])
7982 {
7983 match = FALSE;
7984 break;
7985 }
7986 }
7987 }
7988
7989 if (match)
7990 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007991 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992 {
7993 listitem_T *li1 = rettv->vval.v_list->lv_first;
7994 listitem_T *li2 = li1->li_next;
7995 listitem_T *li3 = li2->li_next;
7996 listitem_T *li4 = li3->li_next;
7997
7998 vim_free(li1->li_tv.vval.v_string);
7999 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8000 (int)(regmatch.endp[0] - regmatch.startp[0]));
8001 li3->li_tv.vval.v_number =
8002 (varnumber_T)(regmatch.startp[0] - expr);
8003 li4->li_tv.vval.v_number =
8004 (varnumber_T)(regmatch.endp[0] - expr);
8005 if (l != NULL)
8006 li2->li_tv.vval.v_number = (varnumber_T)idx;
8007 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008008 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 {
8010 int i;
8011
8012 /* return list with matched string and submatches */
8013 for (i = 0; i < NSUBEXP; ++i)
8014 {
8015 if (regmatch.endp[i] == NULL)
8016 {
8017 if (list_append_string(rettv->vval.v_list,
8018 (char_u *)"", 0) == FAIL)
8019 break;
8020 }
8021 else if (list_append_string(rettv->vval.v_list,
8022 regmatch.startp[i],
8023 (int)(regmatch.endp[i] - regmatch.startp[i]))
8024 == FAIL)
8025 break;
8026 }
8027 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008028 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029 {
8030 /* return matched string */
8031 if (l != NULL)
8032 copy_tv(&li->li_tv, rettv);
8033 else
8034 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8035 (int)(regmatch.endp[0] - regmatch.startp[0]));
8036 }
8037 else if (l != NULL)
8038 rettv->vval.v_number = idx;
8039 else
8040 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008041 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 rettv->vval.v_number =
8043 (varnumber_T)(regmatch.startp[0] - str);
8044 else
8045 rettv->vval.v_number =
8046 (varnumber_T)(regmatch.endp[0] - str);
8047 rettv->vval.v_number += (varnumber_T)(str - expr);
8048 }
8049 }
8050 vim_regfree(regmatch.regprog);
8051 }
8052
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008053theend:
8054 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008055 /* matchstrpos() without a list: drop the second item. */
8056 listitem_remove(rettv->vval.v_list,
8057 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008058 vim_free(tofree);
8059 p_cpo = save_cpo;
8060}
8061
8062/*
8063 * "match()" function
8064 */
8065 static void
8066f_match(typval_T *argvars, typval_T *rettv)
8067{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008068 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069}
8070
Bram Moolenaar95e51472018-07-28 16:55:56 +02008071#ifdef FEAT_SEARCH_EXTRA
8072 static int
8073matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8074{
8075 dictitem_T *di;
8076
8077 if (tv->v_type != VAR_DICT)
8078 {
8079 EMSG(_(e_dictreq));
8080 return FAIL;
8081 }
8082
8083 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008084 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008085 (char_u *)"conceal", FALSE);
8086
8087 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8088 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008089 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008090 if (*win == NULL)
8091 {
8092 EMSG(_("E957: Invalid window number"));
8093 return FAIL;
8094 }
8095 }
8096
8097 return OK;
8098}
8099#endif
8100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008101/*
8102 * "matchadd()" function
8103 */
8104 static void
8105f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8106{
8107#ifdef FEAT_SEARCH_EXTRA
8108 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008109 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8110 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111 int prio = 10; /* default priority */
8112 int id = -1;
8113 int error = FALSE;
8114 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008115 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116
8117 rettv->vval.v_number = -1;
8118
8119 if (grp == NULL || pat == NULL)
8120 return;
8121 if (argvars[2].v_type != VAR_UNKNOWN)
8122 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008123 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008124 if (argvars[3].v_type != VAR_UNKNOWN)
8125 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008126 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008127 if (argvars[4].v_type != VAR_UNKNOWN
8128 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8129 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 }
8131 }
8132 if (error == TRUE)
8133 return;
8134 if (id >= 1 && id <= 3)
8135 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008136 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137 return;
8138 }
8139
Bram Moolenaar95e51472018-07-28 16:55:56 +02008140 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141 conceal_char);
8142#endif
8143}
8144
8145/*
8146 * "matchaddpos()" function
8147 */
8148 static void
8149f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8150{
8151#ifdef FEAT_SEARCH_EXTRA
8152 char_u buf[NUMBUFLEN];
8153 char_u *group;
8154 int prio = 10;
8155 int id = -1;
8156 int error = FALSE;
8157 list_T *l;
8158 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008159 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160
8161 rettv->vval.v_number = -1;
8162
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008163 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164 if (group == NULL)
8165 return;
8166
8167 if (argvars[1].v_type != VAR_LIST)
8168 {
8169 EMSG2(_(e_listarg), "matchaddpos()");
8170 return;
8171 }
8172 l = argvars[1].vval.v_list;
8173 if (l == NULL)
8174 return;
8175
8176 if (argvars[2].v_type != VAR_UNKNOWN)
8177 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008178 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 if (argvars[3].v_type != VAR_UNKNOWN)
8180 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008181 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008182
8183 if (argvars[4].v_type != VAR_UNKNOWN
8184 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8185 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 }
8187 }
8188 if (error == TRUE)
8189 return;
8190
8191 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8192 if (id == 1 || id == 2)
8193 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008194 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 return;
8196 }
8197
Bram Moolenaar95e51472018-07-28 16:55:56 +02008198 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008199 conceal_char);
8200#endif
8201}
8202
8203/*
8204 * "matcharg()" function
8205 */
8206 static void
8207f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8208{
8209 if (rettv_list_alloc(rettv) == OK)
8210 {
8211#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008212 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 matchitem_T *m;
8214
8215 if (id >= 1 && id <= 3)
8216 {
8217 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8218 {
8219 list_append_string(rettv->vval.v_list,
8220 syn_id2name(m->hlg_id), -1);
8221 list_append_string(rettv->vval.v_list, m->pattern, -1);
8222 }
8223 else
8224 {
8225 list_append_string(rettv->vval.v_list, NULL, -1);
8226 list_append_string(rettv->vval.v_list, NULL, -1);
8227 }
8228 }
8229#endif
8230 }
8231}
8232
8233/*
8234 * "matchdelete()" function
8235 */
8236 static void
8237f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8238{
8239#ifdef FEAT_SEARCH_EXTRA
8240 rettv->vval.v_number = match_delete(curwin,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008241 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008242#endif
8243}
8244
8245/*
8246 * "matchend()" function
8247 */
8248 static void
8249f_matchend(typval_T *argvars, typval_T *rettv)
8250{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008251 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008252}
8253
8254/*
8255 * "matchlist()" function
8256 */
8257 static void
8258f_matchlist(typval_T *argvars, typval_T *rettv)
8259{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008260 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008261}
8262
8263/*
8264 * "matchstr()" function
8265 */
8266 static void
8267f_matchstr(typval_T *argvars, typval_T *rettv)
8268{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008269 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008270}
8271
8272/*
8273 * "matchstrpos()" function
8274 */
8275 static void
8276f_matchstrpos(typval_T *argvars, typval_T *rettv)
8277{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008278 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008279}
8280
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281 static void
8282max_min(typval_T *argvars, typval_T *rettv, int domax)
8283{
8284 varnumber_T n = 0;
8285 varnumber_T i;
8286 int error = FALSE;
8287
8288 if (argvars[0].v_type == VAR_LIST)
8289 {
8290 list_T *l;
8291 listitem_T *li;
8292
8293 l = argvars[0].vval.v_list;
8294 if (l != NULL)
8295 {
8296 li = l->lv_first;
8297 if (li != NULL)
8298 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008299 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008300 for (;;)
8301 {
8302 li = li->li_next;
8303 if (li == NULL)
8304 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008305 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008306 if (domax ? i > n : i < n)
8307 n = i;
8308 }
8309 }
8310 }
8311 }
8312 else if (argvars[0].v_type == VAR_DICT)
8313 {
8314 dict_T *d;
8315 int first = TRUE;
8316 hashitem_T *hi;
8317 int todo;
8318
8319 d = argvars[0].vval.v_dict;
8320 if (d != NULL)
8321 {
8322 todo = (int)d->dv_hashtab.ht_used;
8323 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8324 {
8325 if (!HASHITEM_EMPTY(hi))
8326 {
8327 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008328 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329 if (first)
8330 {
8331 n = i;
8332 first = FALSE;
8333 }
8334 else if (domax ? i > n : i < n)
8335 n = i;
8336 }
8337 }
8338 }
8339 }
8340 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008341 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 rettv->vval.v_number = error ? 0 : n;
8343}
8344
8345/*
8346 * "max()" function
8347 */
8348 static void
8349f_max(typval_T *argvars, typval_T *rettv)
8350{
8351 max_min(argvars, rettv, TRUE);
8352}
8353
8354/*
8355 * "min()" function
8356 */
8357 static void
8358f_min(typval_T *argvars, typval_T *rettv)
8359{
8360 max_min(argvars, rettv, FALSE);
8361}
8362
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008363/*
8364 * Create the directory in which "dir" is located, and higher levels when
8365 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008366 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008367 */
8368 static int
8369mkdir_recurse(char_u *dir, int prot)
8370{
8371 char_u *p;
8372 char_u *updir;
8373 int r = FAIL;
8374
8375 /* Get end of directory name in "dir".
8376 * We're done when it's "/" or "c:/". */
8377 p = gettail_sep(dir);
8378 if (p <= get_past_head(dir))
8379 return OK;
8380
8381 /* If the directory exists we're done. Otherwise: create it.*/
8382 updir = vim_strnsave(dir, (int)(p - dir));
8383 if (updir == NULL)
8384 return FAIL;
8385 if (mch_isdir(updir))
8386 r = OK;
8387 else if (mkdir_recurse(updir, prot) == OK)
8388 r = vim_mkdir_emsg(updir, prot);
8389 vim_free(updir);
8390 return r;
8391}
8392
8393#ifdef vim_mkdir
8394/*
8395 * "mkdir()" function
8396 */
8397 static void
8398f_mkdir(typval_T *argvars, typval_T *rettv)
8399{
8400 char_u *dir;
8401 char_u buf[NUMBUFLEN];
8402 int prot = 0755;
8403
8404 rettv->vval.v_number = FAIL;
8405 if (check_restricted() || check_secure())
8406 return;
8407
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008408 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008409 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008410 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008411
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008412 if (*gettail(dir) == NUL)
8413 /* remove trailing slashes */
8414 *gettail_sep(dir) = NUL;
8415
8416 if (argvars[1].v_type != VAR_UNKNOWN)
8417 {
8418 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008419 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008420 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008421 if (prot == -1)
8422 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008423 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008424 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008425 {
8426 if (mch_isdir(dir))
8427 {
8428 /* With the "p" flag it's OK if the dir already exists. */
8429 rettv->vval.v_number = OK;
8430 return;
8431 }
8432 mkdir_recurse(dir, prot);
8433 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008434 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008435 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008436}
8437#endif
8438
8439/*
8440 * "mode()" function
8441 */
8442 static void
8443f_mode(typval_T *argvars, typval_T *rettv)
8444{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008445 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008446
Bram Moolenaar612cc382018-07-29 15:34:26 +02008447 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448
8449 if (time_for_testing == 93784)
8450 {
8451 /* Testing the two-character code. */
8452 buf[0] = 'x';
8453 buf[1] = '!';
8454 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008455#ifdef FEAT_TERMINAL
8456 else if (term_use_loop())
8457 buf[0] = 't';
8458#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459 else if (VIsual_active)
8460 {
8461 if (VIsual_select)
8462 buf[0] = VIsual_mode + 's' - 'v';
8463 else
8464 buf[0] = VIsual_mode;
8465 }
8466 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8467 || State == CONFIRM)
8468 {
8469 buf[0] = 'r';
8470 if (State == ASKMORE)
8471 buf[1] = 'm';
8472 else if (State == CONFIRM)
8473 buf[1] = '?';
8474 }
8475 else if (State == EXTERNCMD)
8476 buf[0] = '!';
8477 else if (State & INSERT)
8478 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008479 if (State & VREPLACE_FLAG)
8480 {
8481 buf[0] = 'R';
8482 buf[1] = 'v';
8483 }
8484 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008485 {
8486 if (State & REPLACE_FLAG)
8487 buf[0] = 'R';
8488 else
8489 buf[0] = 'i';
8490#ifdef FEAT_INS_EXPAND
8491 if (ins_compl_active())
8492 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008493 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008494 buf[1] = 'x';
8495#endif
8496 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008497 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008498 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008499 {
8500 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008501 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008502 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008503 else if (exmode_active == EXMODE_NORMAL)
8504 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008505 }
8506 else
8507 {
8508 buf[0] = 'n';
8509 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008510 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008511 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008512 // to be able to detect force-linewise/blockwise/characterwise operations
8513 buf[2] = motion_force;
8514 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008515 else if (restart_edit == 'I' || restart_edit == 'R'
8516 || restart_edit == 'V')
8517 {
8518 buf[1] = 'i';
8519 buf[2] = restart_edit;
8520 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008521 }
8522
8523 /* Clear out the minor mode when the argument is not a non-zero number or
8524 * non-empty string. */
8525 if (!non_zero_arg(&argvars[0]))
8526 buf[1] = NUL;
8527
8528 rettv->vval.v_string = vim_strsave(buf);
8529 rettv->v_type = VAR_STRING;
8530}
8531
8532#if defined(FEAT_MZSCHEME) || defined(PROTO)
8533/*
8534 * "mzeval()" function
8535 */
8536 static void
8537f_mzeval(typval_T *argvars, typval_T *rettv)
8538{
8539 char_u *str;
8540 char_u buf[NUMBUFLEN];
8541
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008542 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008543 do_mzeval(str, rettv);
8544}
8545
8546 void
8547mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8548{
8549 typval_T argvars[3];
8550
8551 argvars[0].v_type = VAR_STRING;
8552 argvars[0].vval.v_string = name;
8553 copy_tv(args, &argvars[1]);
8554 argvars[2].v_type = VAR_UNKNOWN;
8555 f_call(argvars, rettv);
8556 clear_tv(&argvars[1]);
8557}
8558#endif
8559
8560/*
8561 * "nextnonblank()" function
8562 */
8563 static void
8564f_nextnonblank(typval_T *argvars, typval_T *rettv)
8565{
8566 linenr_T lnum;
8567
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008568 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008569 {
8570 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8571 {
8572 lnum = 0;
8573 break;
8574 }
8575 if (*skipwhite(ml_get(lnum)) != NUL)
8576 break;
8577 }
8578 rettv->vval.v_number = lnum;
8579}
8580
8581/*
8582 * "nr2char()" function
8583 */
8584 static void
8585f_nr2char(typval_T *argvars, typval_T *rettv)
8586{
8587 char_u buf[NUMBUFLEN];
8588
8589#ifdef FEAT_MBYTE
8590 if (has_mbyte)
8591 {
8592 int utf8 = 0;
8593
8594 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008595 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596 if (utf8)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008597 buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008598 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008599 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008600 }
8601 else
8602#endif
8603 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008604 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008605 buf[1] = NUL;
8606 }
8607 rettv->v_type = VAR_STRING;
8608 rettv->vval.v_string = vim_strsave(buf);
8609}
8610
8611/*
8612 * "or(expr, expr)" function
8613 */
8614 static void
8615f_or(typval_T *argvars, typval_T *rettv)
8616{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008617 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8618 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008619}
8620
8621/*
8622 * "pathshorten()" function
8623 */
8624 static void
8625f_pathshorten(typval_T *argvars, typval_T *rettv)
8626{
8627 char_u *p;
8628
8629 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008630 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008631 if (p == NULL)
8632 rettv->vval.v_string = NULL;
8633 else
8634 {
8635 p = vim_strsave(p);
8636 rettv->vval.v_string = p;
8637 if (p != NULL)
8638 shorten_dir(p);
8639 }
8640}
8641
8642#ifdef FEAT_PERL
8643/*
8644 * "perleval()" function
8645 */
8646 static void
8647f_perleval(typval_T *argvars, typval_T *rettv)
8648{
8649 char_u *str;
8650 char_u buf[NUMBUFLEN];
8651
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008652 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008653 do_perleval(str, rettv);
8654}
8655#endif
8656
8657#ifdef FEAT_FLOAT
8658/*
8659 * "pow()" function
8660 */
8661 static void
8662f_pow(typval_T *argvars, typval_T *rettv)
8663{
8664 float_T fx = 0.0, fy = 0.0;
8665
8666 rettv->v_type = VAR_FLOAT;
8667 if (get_float_arg(argvars, &fx) == OK
8668 && get_float_arg(&argvars[1], &fy) == OK)
8669 rettv->vval.v_float = pow(fx, fy);
8670 else
8671 rettv->vval.v_float = 0.0;
8672}
8673#endif
8674
8675/*
8676 * "prevnonblank()" function
8677 */
8678 static void
8679f_prevnonblank(typval_T *argvars, typval_T *rettv)
8680{
8681 linenr_T lnum;
8682
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008683 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008684 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8685 lnum = 0;
8686 else
8687 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8688 --lnum;
8689 rettv->vval.v_number = lnum;
8690}
8691
8692/* This dummy va_list is here because:
8693 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8694 * - locally in the function results in a "used before set" warning
8695 * - using va_start() to initialize it gives "function with fixed args" error */
8696static va_list ap;
8697
8698/*
8699 * "printf()" function
8700 */
8701 static void
8702f_printf(typval_T *argvars, typval_T *rettv)
8703{
8704 char_u buf[NUMBUFLEN];
8705 int len;
8706 char_u *s;
8707 int saved_did_emsg = did_emsg;
8708 char *fmt;
8709
8710 rettv->v_type = VAR_STRING;
8711 rettv->vval.v_string = NULL;
8712
8713 /* Get the required length, allocate the buffer and do it for real. */
8714 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008715 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008716 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008717 if (!did_emsg)
8718 {
8719 s = alloc(len + 1);
8720 if (s != NULL)
8721 {
8722 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008723 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8724 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725 }
8726 }
8727 did_emsg |= saved_did_emsg;
8728}
8729
Bram Moolenaarf2732452018-06-03 14:47:35 +02008730#ifdef FEAT_JOB_CHANNEL
8731/*
8732 * "prompt_setcallback({buffer}, {callback})" function
8733 */
8734 static void
8735f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8736{
8737 buf_T *buf;
8738 char_u *callback;
8739 partial_T *partial;
8740
8741 if (check_secure())
8742 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008743 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008744 if (buf == NULL)
8745 return;
8746
8747 callback = get_callback(&argvars[1], &partial);
8748 if (callback == NULL)
8749 return;
8750
8751 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8752 if (partial == NULL)
8753 buf->b_prompt_callback = vim_strsave(callback);
8754 else
8755 /* pointer into the partial */
8756 buf->b_prompt_callback = callback;
8757 buf->b_prompt_partial = partial;
8758}
8759
8760/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008761 * "prompt_setinterrupt({buffer}, {callback})" function
8762 */
8763 static void
8764f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8765{
8766 buf_T *buf;
8767 char_u *callback;
8768 partial_T *partial;
8769
8770 if (check_secure())
8771 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008772 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008773 if (buf == NULL)
8774 return;
8775
8776 callback = get_callback(&argvars[1], &partial);
8777 if (callback == NULL)
8778 return;
8779
8780 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8781 if (partial == NULL)
8782 buf->b_prompt_interrupt = vim_strsave(callback);
8783 else
8784 /* pointer into the partial */
8785 buf->b_prompt_interrupt = callback;
8786 buf->b_prompt_int_partial = partial;
8787}
8788
8789/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008790 * "prompt_setprompt({buffer}, {text})" function
8791 */
8792 static void
8793f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8794{
8795 buf_T *buf;
8796 char_u *text;
8797
8798 if (check_secure())
8799 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008800 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008801 if (buf == NULL)
8802 return;
8803
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008804 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008805 vim_free(buf->b_prompt_text);
8806 buf->b_prompt_text = vim_strsave(text);
8807}
8808#endif
8809
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008810/*
8811 * "pumvisible()" function
8812 */
8813 static void
8814f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8815{
8816#ifdef FEAT_INS_EXPAND
8817 if (pum_visible())
8818 rettv->vval.v_number = 1;
8819#endif
8820}
8821
8822#ifdef FEAT_PYTHON3
8823/*
8824 * "py3eval()" function
8825 */
8826 static void
8827f_py3eval(typval_T *argvars, typval_T *rettv)
8828{
8829 char_u *str;
8830 char_u buf[NUMBUFLEN];
8831
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008832 if (p_pyx == 0)
8833 p_pyx = 3;
8834
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008835 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008836 do_py3eval(str, rettv);
8837}
8838#endif
8839
8840#ifdef FEAT_PYTHON
8841/*
8842 * "pyeval()" function
8843 */
8844 static void
8845f_pyeval(typval_T *argvars, typval_T *rettv)
8846{
8847 char_u *str;
8848 char_u buf[NUMBUFLEN];
8849
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008850 if (p_pyx == 0)
8851 p_pyx = 2;
8852
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008853 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854 do_pyeval(str, rettv);
8855}
8856#endif
8857
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008858#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8859/*
8860 * "pyxeval()" function
8861 */
8862 static void
8863f_pyxeval(typval_T *argvars, typval_T *rettv)
8864{
8865# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8866 init_pyxversion();
8867 if (p_pyx == 2)
8868 f_pyeval(argvars, rettv);
8869 else
8870 f_py3eval(argvars, rettv);
8871# elif defined(FEAT_PYTHON)
8872 f_pyeval(argvars, rettv);
8873# elif defined(FEAT_PYTHON3)
8874 f_py3eval(argvars, rettv);
8875# endif
8876}
8877#endif
8878
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008879/*
8880 * "range()" function
8881 */
8882 static void
8883f_range(typval_T *argvars, typval_T *rettv)
8884{
8885 varnumber_T start;
8886 varnumber_T end;
8887 varnumber_T stride = 1;
8888 varnumber_T i;
8889 int error = FALSE;
8890
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008891 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008892 if (argvars[1].v_type == VAR_UNKNOWN)
8893 {
8894 end = start - 1;
8895 start = 0;
8896 }
8897 else
8898 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008899 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008900 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008901 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902 }
8903
8904 if (error)
8905 return; /* type error; errmsg already given */
8906 if (stride == 0)
8907 EMSG(_("E726: Stride is zero"));
8908 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8909 EMSG(_("E727: Start past end"));
8910 else
8911 {
8912 if (rettv_list_alloc(rettv) == OK)
8913 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8914 if (list_append_number(rettv->vval.v_list,
8915 (varnumber_T)i) == FAIL)
8916 break;
8917 }
8918}
8919
8920/*
8921 * "readfile()" function
8922 */
8923 static void
8924f_readfile(typval_T *argvars, typval_T *rettv)
8925{
8926 int binary = FALSE;
8927 int failed = FALSE;
8928 char_u *fname;
8929 FILE *fd;
8930 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8931 int io_size = sizeof(buf);
8932 int readlen; /* size of last fread() */
8933 char_u *prev = NULL; /* previously read bytes, if any */
8934 long prevlen = 0; /* length of data in prev */
8935 long prevsize = 0; /* size of prev buffer */
8936 long maxline = MAXLNUM;
8937 long cnt = 0;
8938 char_u *p; /* position in buf */
8939 char_u *start; /* start of current line */
8940
8941 if (argvars[1].v_type != VAR_UNKNOWN)
8942 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008943 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008944 binary = TRUE;
8945 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008946 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008947 }
8948
8949 if (rettv_list_alloc(rettv) == FAIL)
8950 return;
8951
8952 /* Always open the file in binary mode, library functions have a mind of
8953 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008954 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008955 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8956 {
8957 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8958 return;
8959 }
8960
8961 while (cnt < maxline || maxline < 0)
8962 {
8963 readlen = (int)fread(buf, 1, io_size, fd);
8964
8965 /* This for loop processes what was read, but is also entered at end
8966 * of file so that either:
8967 * - an incomplete line gets written
8968 * - a "binary" file gets an empty line at the end if it ends in a
8969 * newline. */
8970 for (p = buf, start = buf;
8971 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8972 ++p)
8973 {
8974 if (*p == '\n' || readlen <= 0)
8975 {
8976 listitem_T *li;
8977 char_u *s = NULL;
8978 long_u len = p - start;
8979
8980 /* Finished a line. Remove CRs before NL. */
8981 if (readlen > 0 && !binary)
8982 {
8983 while (len > 0 && start[len - 1] == '\r')
8984 --len;
8985 /* removal may cross back to the "prev" string */
8986 if (len == 0)
8987 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8988 --prevlen;
8989 }
8990 if (prevlen == 0)
8991 s = vim_strnsave(start, (int)len);
8992 else
8993 {
8994 /* Change "prev" buffer to be the right size. This way
8995 * the bytes are only copied once, and very long lines are
8996 * allocated only once. */
8997 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8998 {
8999 mch_memmove(s + prevlen, start, len);
9000 s[prevlen + len] = NUL;
9001 prev = NULL; /* the list will own the string */
9002 prevlen = prevsize = 0;
9003 }
9004 }
9005 if (s == NULL)
9006 {
9007 do_outofmem_msg((long_u) prevlen + len + 1);
9008 failed = TRUE;
9009 break;
9010 }
9011
9012 if ((li = listitem_alloc()) == NULL)
9013 {
9014 vim_free(s);
9015 failed = TRUE;
9016 break;
9017 }
9018 li->li_tv.v_type = VAR_STRING;
9019 li->li_tv.v_lock = 0;
9020 li->li_tv.vval.v_string = s;
9021 list_append(rettv->vval.v_list, li);
9022
9023 start = p + 1; /* step over newline */
9024 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9025 break;
9026 }
9027 else if (*p == NUL)
9028 *p = '\n';
9029#ifdef FEAT_MBYTE
9030 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9031 * when finding the BF and check the previous two bytes. */
9032 else if (*p == 0xbf && enc_utf8 && !binary)
9033 {
9034 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9035 * + 1, these may be in the "prev" string. */
9036 char_u back1 = p >= buf + 1 ? p[-1]
9037 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9038 char_u back2 = p >= buf + 2 ? p[-2]
9039 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9040 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9041
9042 if (back2 == 0xef && back1 == 0xbb)
9043 {
9044 char_u *dest = p - 2;
9045
9046 /* Usually a BOM is at the beginning of a file, and so at
9047 * the beginning of a line; then we can just step over it.
9048 */
9049 if (start == dest)
9050 start = p + 1;
9051 else
9052 {
9053 /* have to shuffle buf to close gap */
9054 int adjust_prevlen = 0;
9055
9056 if (dest < buf)
9057 {
9058 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9059 dest = buf;
9060 }
9061 if (readlen > p - buf + 1)
9062 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9063 readlen -= 3 - adjust_prevlen;
9064 prevlen -= adjust_prevlen;
9065 p = dest - 1;
9066 }
9067 }
9068 }
9069#endif
9070 } /* for */
9071
9072 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9073 break;
9074 if (start < p)
9075 {
9076 /* There's part of a line in buf, store it in "prev". */
9077 if (p - start + prevlen >= prevsize)
9078 {
9079 /* need bigger "prev" buffer */
9080 char_u *newprev;
9081
9082 /* A common use case is ordinary text files and "prev" gets a
9083 * fragment of a line, so the first allocation is made
9084 * small, to avoid repeatedly 'allocing' large and
9085 * 'reallocing' small. */
9086 if (prevsize == 0)
9087 prevsize = (long)(p - start);
9088 else
9089 {
9090 long grow50pc = (prevsize * 3) / 2;
9091 long growmin = (long)((p - start) * 2 + prevlen);
9092 prevsize = grow50pc > growmin ? grow50pc : growmin;
9093 }
9094 newprev = prev == NULL ? alloc(prevsize)
9095 : vim_realloc(prev, prevsize);
9096 if (newprev == NULL)
9097 {
9098 do_outofmem_msg((long_u)prevsize);
9099 failed = TRUE;
9100 break;
9101 }
9102 prev = newprev;
9103 }
9104 /* Add the line part to end of "prev". */
9105 mch_memmove(prev + prevlen, start, p - start);
9106 prevlen += (long)(p - start);
9107 }
9108 } /* while */
9109
9110 /*
9111 * For a negative line count use only the lines at the end of the file,
9112 * free the rest.
9113 */
9114 if (!failed && maxline < 0)
9115 while (cnt > -maxline)
9116 {
9117 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9118 --cnt;
9119 }
9120
9121 if (failed)
9122 {
9123 list_free(rettv->vval.v_list);
9124 /* readfile doc says an empty list is returned on error */
9125 rettv->vval.v_list = list_alloc();
9126 }
9127
9128 vim_free(prev);
9129 fclose(fd);
9130}
9131
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009132 static void
9133return_register(int regname, typval_T *rettv)
9134{
9135 char_u buf[2] = {0, 0};
9136
9137 buf[0] = (char_u)regname;
9138 rettv->v_type = VAR_STRING;
9139 rettv->vval.v_string = vim_strsave(buf);
9140}
9141
9142/*
9143 * "reg_executing()" function
9144 */
9145 static void
9146f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9147{
9148 return_register(reg_executing, rettv);
9149}
9150
9151/*
9152 * "reg_recording()" function
9153 */
9154 static void
9155f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9156{
9157 return_register(reg_recording, rettv);
9158}
9159
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009160#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009161/*
9162 * Convert a List to proftime_T.
9163 * Return FAIL when there is something wrong.
9164 */
9165 static int
9166list2proftime(typval_T *arg, proftime_T *tm)
9167{
9168 long n1, n2;
9169 int error = FALSE;
9170
9171 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9172 || arg->vval.v_list->lv_len != 2)
9173 return FAIL;
9174 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9175 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9176# ifdef WIN3264
9177 tm->HighPart = n1;
9178 tm->LowPart = n2;
9179# else
9180 tm->tv_sec = n1;
9181 tm->tv_usec = n2;
9182# endif
9183 return error ? FAIL : OK;
9184}
9185#endif /* FEAT_RELTIME */
9186
9187/*
9188 * "reltime()" function
9189 */
9190 static void
9191f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9192{
9193#ifdef FEAT_RELTIME
9194 proftime_T res;
9195 proftime_T start;
9196
9197 if (argvars[0].v_type == VAR_UNKNOWN)
9198 {
9199 /* No arguments: get current time. */
9200 profile_start(&res);
9201 }
9202 else if (argvars[1].v_type == VAR_UNKNOWN)
9203 {
9204 if (list2proftime(&argvars[0], &res) == FAIL)
9205 return;
9206 profile_end(&res);
9207 }
9208 else
9209 {
9210 /* Two arguments: compute the difference. */
9211 if (list2proftime(&argvars[0], &start) == FAIL
9212 || list2proftime(&argvars[1], &res) == FAIL)
9213 return;
9214 profile_sub(&res, &start);
9215 }
9216
9217 if (rettv_list_alloc(rettv) == OK)
9218 {
9219 long n1, n2;
9220
9221# ifdef WIN3264
9222 n1 = res.HighPart;
9223 n2 = res.LowPart;
9224# else
9225 n1 = res.tv_sec;
9226 n2 = res.tv_usec;
9227# endif
9228 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9229 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9230 }
9231#endif
9232}
9233
9234#ifdef FEAT_FLOAT
9235/*
9236 * "reltimefloat()" function
9237 */
9238 static void
9239f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9240{
9241# ifdef FEAT_RELTIME
9242 proftime_T tm;
9243# endif
9244
9245 rettv->v_type = VAR_FLOAT;
9246 rettv->vval.v_float = 0;
9247# ifdef FEAT_RELTIME
9248 if (list2proftime(&argvars[0], &tm) == OK)
9249 rettv->vval.v_float = profile_float(&tm);
9250# endif
9251}
9252#endif
9253
9254/*
9255 * "reltimestr()" function
9256 */
9257 static void
9258f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9259{
9260#ifdef FEAT_RELTIME
9261 proftime_T tm;
9262#endif
9263
9264 rettv->v_type = VAR_STRING;
9265 rettv->vval.v_string = NULL;
9266#ifdef FEAT_RELTIME
9267 if (list2proftime(&argvars[0], &tm) == OK)
9268 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9269#endif
9270}
9271
9272#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009273 static void
9274make_connection(void)
9275{
9276 if (X_DISPLAY == NULL
9277# ifdef FEAT_GUI
9278 && !gui.in_use
9279# endif
9280 )
9281 {
9282 x_force_connect = TRUE;
9283 setup_term_clip();
9284 x_force_connect = FALSE;
9285 }
9286}
9287
9288 static int
9289check_connection(void)
9290{
9291 make_connection();
9292 if (X_DISPLAY == NULL)
9293 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009294 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009295 return FAIL;
9296 }
9297 return OK;
9298}
9299#endif
9300
9301#ifdef FEAT_CLIENTSERVER
9302 static void
9303remote_common(typval_T *argvars, typval_T *rettv, int expr)
9304{
9305 char_u *server_name;
9306 char_u *keys;
9307 char_u *r = NULL;
9308 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009309 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009310# ifdef WIN32
9311 HWND w;
9312# else
9313 Window w;
9314# endif
9315
9316 if (check_restricted() || check_secure())
9317 return;
9318
9319# ifdef FEAT_X11
9320 if (check_connection() == FAIL)
9321 return;
9322# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009323 if (argvars[2].v_type != VAR_UNKNOWN
9324 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009325 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009326
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009327 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009328 if (server_name == NULL)
9329 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009330 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009331# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009332 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009334 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9335 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009336# endif
9337 {
9338 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009339 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009340 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009341 vim_free(r);
9342 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009343 else
9344 EMSG2(_("E241: Unable to send to %s"), server_name);
9345 return;
9346 }
9347
9348 rettv->vval.v_string = r;
9349
9350 if (argvars[2].v_type != VAR_UNKNOWN)
9351 {
9352 dictitem_T v;
9353 char_u str[30];
9354 char_u *idvar;
9355
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009356 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009357 if (idvar != NULL && *idvar != NUL)
9358 {
9359 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9360 v.di_tv.v_type = VAR_STRING;
9361 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009362 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009363 vim_free(v.di_tv.vval.v_string);
9364 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009365 }
9366}
9367#endif
9368
9369/*
9370 * "remote_expr()" function
9371 */
9372 static void
9373f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9374{
9375 rettv->v_type = VAR_STRING;
9376 rettv->vval.v_string = NULL;
9377#ifdef FEAT_CLIENTSERVER
9378 remote_common(argvars, rettv, TRUE);
9379#endif
9380}
9381
9382/*
9383 * "remote_foreground()" function
9384 */
9385 static void
9386f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9387{
9388#ifdef FEAT_CLIENTSERVER
9389# ifdef WIN32
9390 /* On Win32 it's done in this application. */
9391 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009392 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009393
9394 if (server_name != NULL)
9395 serverForeground(server_name);
9396 }
9397# else
9398 /* Send a foreground() expression to the server. */
9399 argvars[1].v_type = VAR_STRING;
9400 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9401 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009402 rettv->v_type = VAR_STRING;
9403 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009404 remote_common(argvars, rettv, TRUE);
9405 vim_free(argvars[1].vval.v_string);
9406# endif
9407#endif
9408}
9409
9410 static void
9411f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9412{
9413#ifdef FEAT_CLIENTSERVER
9414 dictitem_T v;
9415 char_u *s = NULL;
9416# ifdef WIN32
9417 long_u n = 0;
9418# endif
9419 char_u *serverid;
9420
9421 if (check_restricted() || check_secure())
9422 {
9423 rettv->vval.v_number = -1;
9424 return;
9425 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009426 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009427 if (serverid == NULL)
9428 {
9429 rettv->vval.v_number = -1;
9430 return; /* type error; errmsg already given */
9431 }
9432# ifdef WIN32
9433 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9434 if (n == 0)
9435 rettv->vval.v_number = -1;
9436 else
9437 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009438 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009439 rettv->vval.v_number = (s != NULL);
9440 }
9441# else
9442 if (check_connection() == FAIL)
9443 return;
9444
9445 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9446 serverStrToWin(serverid), &s);
9447# endif
9448
9449 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9450 {
9451 char_u *retvar;
9452
9453 v.di_tv.v_type = VAR_STRING;
9454 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009455 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009456 if (retvar != NULL)
9457 set_var(retvar, &v.di_tv, FALSE);
9458 vim_free(v.di_tv.vval.v_string);
9459 }
9460#else
9461 rettv->vval.v_number = -1;
9462#endif
9463}
9464
9465 static void
9466f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9467{
9468 char_u *r = NULL;
9469
9470#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009471 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009472
9473 if (serverid != NULL && !check_restricted() && !check_secure())
9474 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009475 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009476# ifdef WIN32
9477 /* The server's HWND is encoded in the 'id' parameter */
9478 long_u n = 0;
9479# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009480
9481 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009482 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009483
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009484# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009485 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9486 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009487 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009488 if (r == NULL)
9489# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009490 if (check_connection() == FAIL
9491 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9492 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009493# endif
9494 EMSG(_("E277: Unable to read a server reply"));
9495 }
9496#endif
9497 rettv->v_type = VAR_STRING;
9498 rettv->vval.v_string = r;
9499}
9500
9501/*
9502 * "remote_send()" function
9503 */
9504 static void
9505f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9506{
9507 rettv->v_type = VAR_STRING;
9508 rettv->vval.v_string = NULL;
9509#ifdef FEAT_CLIENTSERVER
9510 remote_common(argvars, rettv, FALSE);
9511#endif
9512}
9513
9514/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009515 * "remote_startserver()" function
9516 */
9517 static void
9518f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9519{
9520#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009521 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009522
9523 if (server == NULL)
9524 return; /* type error; errmsg already given */
9525 if (serverName != NULL)
9526 EMSG(_("E941: already started a server"));
9527 else
9528 {
9529# ifdef FEAT_X11
9530 if (check_connection() == OK)
9531 serverRegisterName(X_DISPLAY, server);
9532# else
9533 serverSetName(server);
9534# endif
9535 }
9536#else
9537 EMSG(_("E942: +clientserver feature not available"));
9538#endif
9539}
9540
9541/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009542 * "remove()" function
9543 */
9544 static void
9545f_remove(typval_T *argvars, typval_T *rettv)
9546{
9547 list_T *l;
9548 listitem_T *item, *item2;
9549 listitem_T *li;
9550 long idx;
9551 long end;
9552 char_u *key;
9553 dict_T *d;
9554 dictitem_T *di;
9555 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9556
9557 if (argvars[0].v_type == VAR_DICT)
9558 {
9559 if (argvars[2].v_type != VAR_UNKNOWN)
9560 EMSG2(_(e_toomanyarg), "remove()");
9561 else if ((d = argvars[0].vval.v_dict) != NULL
9562 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9563 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009564 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009565 if (key != NULL)
9566 {
9567 di = dict_find(d, key, -1);
9568 if (di == NULL)
9569 EMSG2(_(e_dictkey), key);
9570 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9571 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9572 {
9573 *rettv = di->di_tv;
9574 init_tv(&di->di_tv);
9575 dictitem_remove(d, di);
9576 }
9577 }
9578 }
9579 }
9580 else if (argvars[0].v_type != VAR_LIST)
9581 EMSG2(_(e_listdictarg), "remove()");
9582 else if ((l = argvars[0].vval.v_list) != NULL
9583 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9584 {
9585 int error = FALSE;
9586
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009587 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009588 if (error)
9589 ; /* type error: do nothing, errmsg already given */
9590 else if ((item = list_find(l, idx)) == NULL)
9591 EMSGN(_(e_listidx), idx);
9592 else
9593 {
9594 if (argvars[2].v_type == VAR_UNKNOWN)
9595 {
9596 /* Remove one item, return its value. */
9597 vimlist_remove(l, item, item);
9598 *rettv = item->li_tv;
9599 vim_free(item);
9600 }
9601 else
9602 {
9603 /* Remove range of items, return list with values. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009604 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009605 if (error)
9606 ; /* type error: do nothing */
9607 else if ((item2 = list_find(l, end)) == NULL)
9608 EMSGN(_(e_listidx), end);
9609 else
9610 {
9611 int cnt = 0;
9612
9613 for (li = item; li != NULL; li = li->li_next)
9614 {
9615 ++cnt;
9616 if (li == item2)
9617 break;
9618 }
9619 if (li == NULL) /* didn't find "item2" after "item" */
9620 EMSG(_(e_invrange));
9621 else
9622 {
9623 vimlist_remove(l, item, item2);
9624 if (rettv_list_alloc(rettv) == OK)
9625 {
9626 l = rettv->vval.v_list;
9627 l->lv_first = item;
9628 l->lv_last = item2;
9629 item->li_prev = NULL;
9630 item2->li_next = NULL;
9631 l->lv_len = cnt;
9632 }
9633 }
9634 }
9635 }
9636 }
9637 }
9638}
9639
9640/*
9641 * "rename({from}, {to})" function
9642 */
9643 static void
9644f_rename(typval_T *argvars, typval_T *rettv)
9645{
9646 char_u buf[NUMBUFLEN];
9647
9648 if (check_restricted() || check_secure())
9649 rettv->vval.v_number = -1;
9650 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009651 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9652 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009653}
9654
9655/*
9656 * "repeat()" function
9657 */
9658 static void
9659f_repeat(typval_T *argvars, typval_T *rettv)
9660{
9661 char_u *p;
9662 int n;
9663 int slen;
9664 int len;
9665 char_u *r;
9666 int i;
9667
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009668 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009669 if (argvars[0].v_type == VAR_LIST)
9670 {
9671 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9672 while (n-- > 0)
9673 if (list_extend(rettv->vval.v_list,
9674 argvars[0].vval.v_list, NULL) == FAIL)
9675 break;
9676 }
9677 else
9678 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009679 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009680 rettv->v_type = VAR_STRING;
9681 rettv->vval.v_string = NULL;
9682
9683 slen = (int)STRLEN(p);
9684 len = slen * n;
9685 if (len <= 0)
9686 return;
9687
9688 r = alloc(len + 1);
9689 if (r != NULL)
9690 {
9691 for (i = 0; i < n; i++)
9692 mch_memmove(r + i * slen, p, (size_t)slen);
9693 r[len] = NUL;
9694 }
9695
9696 rettv->vval.v_string = r;
9697 }
9698}
9699
9700/*
9701 * "resolve()" function
9702 */
9703 static void
9704f_resolve(typval_T *argvars, typval_T *rettv)
9705{
9706 char_u *p;
9707#ifdef HAVE_READLINK
9708 char_u *buf = NULL;
9709#endif
9710
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009711 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009712#ifdef FEAT_SHORTCUT
9713 {
9714 char_u *v = NULL;
9715
9716 v = mch_resolve_shortcut(p);
9717 if (v != NULL)
9718 rettv->vval.v_string = v;
9719 else
9720 rettv->vval.v_string = vim_strsave(p);
9721 }
9722#else
9723# ifdef HAVE_READLINK
9724 {
9725 char_u *cpy;
9726 int len;
9727 char_u *remain = NULL;
9728 char_u *q;
9729 int is_relative_to_current = FALSE;
9730 int has_trailing_pathsep = FALSE;
9731 int limit = 100;
9732
9733 p = vim_strsave(p);
9734
9735 if (p[0] == '.' && (vim_ispathsep(p[1])
9736 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9737 is_relative_to_current = TRUE;
9738
9739 len = STRLEN(p);
9740 if (len > 0 && after_pathsep(p, p + len))
9741 {
9742 has_trailing_pathsep = TRUE;
9743 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9744 }
9745
9746 q = getnextcomp(p);
9747 if (*q != NUL)
9748 {
9749 /* Separate the first path component in "p", and keep the
9750 * remainder (beginning with the path separator). */
9751 remain = vim_strsave(q - 1);
9752 q[-1] = NUL;
9753 }
9754
9755 buf = alloc(MAXPATHL + 1);
9756 if (buf == NULL)
9757 goto fail;
9758
9759 for (;;)
9760 {
9761 for (;;)
9762 {
9763 len = readlink((char *)p, (char *)buf, MAXPATHL);
9764 if (len <= 0)
9765 break;
9766 buf[len] = NUL;
9767
9768 if (limit-- == 0)
9769 {
9770 vim_free(p);
9771 vim_free(remain);
9772 EMSG(_("E655: Too many symbolic links (cycle?)"));
9773 rettv->vval.v_string = NULL;
9774 goto fail;
9775 }
9776
9777 /* Ensure that the result will have a trailing path separator
9778 * if the argument has one. */
9779 if (remain == NULL && has_trailing_pathsep)
9780 add_pathsep(buf);
9781
9782 /* Separate the first path component in the link value and
9783 * concatenate the remainders. */
9784 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9785 if (*q != NUL)
9786 {
9787 if (remain == NULL)
9788 remain = vim_strsave(q - 1);
9789 else
9790 {
9791 cpy = concat_str(q - 1, remain);
9792 if (cpy != NULL)
9793 {
9794 vim_free(remain);
9795 remain = cpy;
9796 }
9797 }
9798 q[-1] = NUL;
9799 }
9800
9801 q = gettail(p);
9802 if (q > p && *q == NUL)
9803 {
9804 /* Ignore trailing path separator. */
9805 q[-1] = NUL;
9806 q = gettail(p);
9807 }
9808 if (q > p && !mch_isFullName(buf))
9809 {
9810 /* symlink is relative to directory of argument */
9811 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9812 if (cpy != NULL)
9813 {
9814 STRCPY(cpy, p);
9815 STRCPY(gettail(cpy), buf);
9816 vim_free(p);
9817 p = cpy;
9818 }
9819 }
9820 else
9821 {
9822 vim_free(p);
9823 p = vim_strsave(buf);
9824 }
9825 }
9826
9827 if (remain == NULL)
9828 break;
9829
9830 /* Append the first path component of "remain" to "p". */
9831 q = getnextcomp(remain + 1);
9832 len = q - remain - (*q != NUL);
9833 cpy = vim_strnsave(p, STRLEN(p) + len);
9834 if (cpy != NULL)
9835 {
9836 STRNCAT(cpy, remain, len);
9837 vim_free(p);
9838 p = cpy;
9839 }
9840 /* Shorten "remain". */
9841 if (*q != NUL)
9842 STRMOVE(remain, q - 1);
9843 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009844 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009845 }
9846
9847 /* If the result is a relative path name, make it explicitly relative to
9848 * the current directory if and only if the argument had this form. */
9849 if (!vim_ispathsep(*p))
9850 {
9851 if (is_relative_to_current
9852 && *p != NUL
9853 && !(p[0] == '.'
9854 && (p[1] == NUL
9855 || vim_ispathsep(p[1])
9856 || (p[1] == '.'
9857 && (p[2] == NUL
9858 || vim_ispathsep(p[2]))))))
9859 {
9860 /* Prepend "./". */
9861 cpy = concat_str((char_u *)"./", p);
9862 if (cpy != NULL)
9863 {
9864 vim_free(p);
9865 p = cpy;
9866 }
9867 }
9868 else if (!is_relative_to_current)
9869 {
9870 /* Strip leading "./". */
9871 q = p;
9872 while (q[0] == '.' && vim_ispathsep(q[1]))
9873 q += 2;
9874 if (q > p)
9875 STRMOVE(p, p + 2);
9876 }
9877 }
9878
9879 /* Ensure that the result will have no trailing path separator
9880 * if the argument had none. But keep "/" or "//". */
9881 if (!has_trailing_pathsep)
9882 {
9883 q = p + STRLEN(p);
9884 if (after_pathsep(p, q))
9885 *gettail_sep(p) = NUL;
9886 }
9887
9888 rettv->vval.v_string = p;
9889 }
9890# else
9891 rettv->vval.v_string = vim_strsave(p);
9892# endif
9893#endif
9894
9895 simplify_filename(rettv->vval.v_string);
9896
9897#ifdef HAVE_READLINK
9898fail:
9899 vim_free(buf);
9900#endif
9901 rettv->v_type = VAR_STRING;
9902}
9903
9904/*
9905 * "reverse({list})" function
9906 */
9907 static void
9908f_reverse(typval_T *argvars, typval_T *rettv)
9909{
9910 list_T *l;
9911 listitem_T *li, *ni;
9912
9913 if (argvars[0].v_type != VAR_LIST)
9914 EMSG2(_(e_listarg), "reverse()");
9915 else if ((l = argvars[0].vval.v_list) != NULL
9916 && !tv_check_lock(l->lv_lock,
9917 (char_u *)N_("reverse() argument"), TRUE))
9918 {
9919 li = l->lv_last;
9920 l->lv_first = l->lv_last = NULL;
9921 l->lv_len = 0;
9922 while (li != NULL)
9923 {
9924 ni = li->li_prev;
9925 list_append(l, li);
9926 li = ni;
9927 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009928 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009929 l->lv_idx = l->lv_len - l->lv_idx - 1;
9930 }
9931}
9932
9933#define SP_NOMOVE 0x01 /* don't move cursor */
9934#define SP_REPEAT 0x02 /* repeat to find outer pair */
9935#define SP_RETCOUNT 0x04 /* return matchcount */
9936#define SP_SETPCMARK 0x08 /* set previous context mark */
9937#define SP_START 0x10 /* accept match at start position */
9938#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9939#define SP_END 0x40 /* leave cursor at end of match */
9940#define SP_COLUMN 0x80 /* start at cursor column */
9941
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009942/*
9943 * Get flags for a search function.
9944 * Possibly sets "p_ws".
9945 * Returns BACKWARD, FORWARD or zero (for an error).
9946 */
9947 static int
9948get_search_arg(typval_T *varp, int *flagsp)
9949{
9950 int dir = FORWARD;
9951 char_u *flags;
9952 char_u nbuf[NUMBUFLEN];
9953 int mask;
9954
9955 if (varp->v_type != VAR_UNKNOWN)
9956 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009957 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009958 if (flags == NULL)
9959 return 0; /* type error; errmsg already given */
9960 while (*flags != NUL)
9961 {
9962 switch (*flags)
9963 {
9964 case 'b': dir = BACKWARD; break;
9965 case 'w': p_ws = TRUE; break;
9966 case 'W': p_ws = FALSE; break;
9967 default: mask = 0;
9968 if (flagsp != NULL)
9969 switch (*flags)
9970 {
9971 case 'c': mask = SP_START; break;
9972 case 'e': mask = SP_END; break;
9973 case 'm': mask = SP_RETCOUNT; break;
9974 case 'n': mask = SP_NOMOVE; break;
9975 case 'p': mask = SP_SUBPAT; break;
9976 case 'r': mask = SP_REPEAT; break;
9977 case 's': mask = SP_SETPCMARK; break;
9978 case 'z': mask = SP_COLUMN; break;
9979 }
9980 if (mask == 0)
9981 {
9982 EMSG2(_(e_invarg2), flags);
9983 dir = 0;
9984 }
9985 else
9986 *flagsp |= mask;
9987 }
9988 if (dir == 0)
9989 break;
9990 ++flags;
9991 }
9992 }
9993 return dir;
9994}
9995
9996/*
9997 * Shared by search() and searchpos() functions.
9998 */
9999 static int
10000search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10001{
10002 int flags;
10003 char_u *pat;
10004 pos_T pos;
10005 pos_T save_cursor;
10006 int save_p_ws = p_ws;
10007 int dir;
10008 int retval = 0; /* default: FAIL */
10009 long lnum_stop = 0;
10010 proftime_T tm;
10011#ifdef FEAT_RELTIME
10012 long time_limit = 0;
10013#endif
10014 int options = SEARCH_KEEP;
10015 int subpatnum;
10016
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010017 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010018 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10019 if (dir == 0)
10020 goto theend;
10021 flags = *flagsp;
10022 if (flags & SP_START)
10023 options |= SEARCH_START;
10024 if (flags & SP_END)
10025 options |= SEARCH_END;
10026 if (flags & SP_COLUMN)
10027 options |= SEARCH_COL;
10028
10029 /* Optional arguments: line number to stop searching and timeout. */
10030 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10031 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010032 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010033 if (lnum_stop < 0)
10034 goto theend;
10035#ifdef FEAT_RELTIME
10036 if (argvars[3].v_type != VAR_UNKNOWN)
10037 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010038 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010039 if (time_limit < 0)
10040 goto theend;
10041 }
10042#endif
10043 }
10044
10045#ifdef FEAT_RELTIME
10046 /* Set the time limit, if there is one. */
10047 profile_setlimit(time_limit, &tm);
10048#endif
10049
10050 /*
10051 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10052 * Check to make sure only those flags are set.
10053 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10054 * flags cannot be set. Check for that condition also.
10055 */
10056 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10057 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10058 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010059 EMSG2(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010060 goto theend;
10061 }
10062
10063 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010064 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010065 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010066 if (subpatnum != FAIL)
10067 {
10068 if (flags & SP_SUBPAT)
10069 retval = subpatnum;
10070 else
10071 retval = pos.lnum;
10072 if (flags & SP_SETPCMARK)
10073 setpcmark();
10074 curwin->w_cursor = pos;
10075 if (match_pos != NULL)
10076 {
10077 /* Store the match cursor position */
10078 match_pos->lnum = pos.lnum;
10079 match_pos->col = pos.col + 1;
10080 }
10081 /* "/$" will put the cursor after the end of the line, may need to
10082 * correct that here */
10083 check_cursor();
10084 }
10085
10086 /* If 'n' flag is used: restore cursor position. */
10087 if (flags & SP_NOMOVE)
10088 curwin->w_cursor = save_cursor;
10089 else
10090 curwin->w_set_curswant = TRUE;
10091theend:
10092 p_ws = save_p_ws;
10093
10094 return retval;
10095}
10096
10097#ifdef FEAT_FLOAT
10098
10099/*
10100 * round() is not in C90, use ceil() or floor() instead.
10101 */
10102 float_T
10103vim_round(float_T f)
10104{
10105 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10106}
10107
10108/*
10109 * "round({float})" function
10110 */
10111 static void
10112f_round(typval_T *argvars, typval_T *rettv)
10113{
10114 float_T f = 0.0;
10115
10116 rettv->v_type = VAR_FLOAT;
10117 if (get_float_arg(argvars, &f) == OK)
10118 rettv->vval.v_float = vim_round(f);
10119 else
10120 rettv->vval.v_float = 0.0;
10121}
10122#endif
10123
10124/*
10125 * "screenattr()" function
10126 */
10127 static void
10128f_screenattr(typval_T *argvars, typval_T *rettv)
10129{
10130 int row;
10131 int col;
10132 int c;
10133
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010134 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10135 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010136 if (row < 0 || row >= screen_Rows
10137 || col < 0 || col >= screen_Columns)
10138 c = -1;
10139 else
10140 c = ScreenAttrs[LineOffset[row] + col];
10141 rettv->vval.v_number = c;
10142}
10143
10144/*
10145 * "screenchar()" function
10146 */
10147 static void
10148f_screenchar(typval_T *argvars, typval_T *rettv)
10149{
10150 int row;
10151 int col;
10152 int off;
10153 int c;
10154
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010155 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10156 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010157 if (row < 0 || row >= screen_Rows
10158 || col < 0 || col >= screen_Columns)
10159 c = -1;
10160 else
10161 {
10162 off = LineOffset[row] + col;
10163#ifdef FEAT_MBYTE
10164 if (enc_utf8 && ScreenLinesUC[off] != 0)
10165 c = ScreenLinesUC[off];
10166 else
10167#endif
10168 c = ScreenLines[off];
10169 }
10170 rettv->vval.v_number = c;
10171}
10172
10173/*
10174 * "screencol()" function
10175 *
10176 * First column is 1 to be consistent with virtcol().
10177 */
10178 static void
10179f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10180{
10181 rettv->vval.v_number = screen_screencol() + 1;
10182}
10183
10184/*
10185 * "screenrow()" function
10186 */
10187 static void
10188f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10189{
10190 rettv->vval.v_number = screen_screenrow() + 1;
10191}
10192
10193/*
10194 * "search()" function
10195 */
10196 static void
10197f_search(typval_T *argvars, typval_T *rettv)
10198{
10199 int flags = 0;
10200
10201 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10202}
10203
10204/*
10205 * "searchdecl()" function
10206 */
10207 static void
10208f_searchdecl(typval_T *argvars, typval_T *rettv)
10209{
10210 int locally = 1;
10211 int thisblock = 0;
10212 int error = FALSE;
10213 char_u *name;
10214
10215 rettv->vval.v_number = 1; /* default: FAIL */
10216
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010217 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010218 if (argvars[1].v_type != VAR_UNKNOWN)
10219 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010220 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010221 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010222 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010223 }
10224 if (!error && name != NULL)
10225 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10226 locally, thisblock, SEARCH_KEEP) == FAIL;
10227}
10228
10229/*
10230 * Used by searchpair() and searchpairpos()
10231 */
10232 static int
10233searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10234{
10235 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010236 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010237 int save_p_ws = p_ws;
10238 int dir;
10239 int flags = 0;
10240 char_u nbuf1[NUMBUFLEN];
10241 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010242 int retval = 0; /* default: FAIL */
10243 long lnum_stop = 0;
10244 long time_limit = 0;
10245
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010246 /* Get the three pattern arguments: start, middle, end. Will result in an
10247 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010248 spat = tv_get_string_chk(&argvars[0]);
10249 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10250 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010251 if (spat == NULL || mpat == NULL || epat == NULL)
10252 goto theend; /* type error */
10253
10254 /* Handle the optional fourth argument: flags */
10255 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10256 if (dir == 0)
10257 goto theend;
10258
10259 /* Don't accept SP_END or SP_SUBPAT.
10260 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10261 */
10262 if ((flags & (SP_END | SP_SUBPAT)) != 0
10263 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10264 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010265 EMSG2(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010266 goto theend;
10267 }
10268
10269 /* Using 'r' implies 'W', otherwise it doesn't work. */
10270 if (flags & SP_REPEAT)
10271 p_ws = FALSE;
10272
10273 /* Optional fifth argument: skip expression */
10274 if (argvars[3].v_type == VAR_UNKNOWN
10275 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010276 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010277 else
10278 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010279 skip = &argvars[4];
10280 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10281 && skip->v_type != VAR_STRING)
10282 {
10283 /* Type error */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010284 EMSG2(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010285 goto theend;
10286 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010287 if (argvars[5].v_type != VAR_UNKNOWN)
10288 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010289 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010290 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010291 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010292 EMSG2(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010293 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010294 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010295#ifdef FEAT_RELTIME
10296 if (argvars[6].v_type != VAR_UNKNOWN)
10297 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010298 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010299 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010300 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010301 EMSG2(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010302 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010303 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010304 }
10305#endif
10306 }
10307 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010308
10309 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10310 match_pos, lnum_stop, time_limit);
10311
10312theend:
10313 p_ws = save_p_ws;
10314
10315 return retval;
10316}
10317
10318/*
10319 * "searchpair()" function
10320 */
10321 static void
10322f_searchpair(typval_T *argvars, typval_T *rettv)
10323{
10324 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10325}
10326
10327/*
10328 * "searchpairpos()" function
10329 */
10330 static void
10331f_searchpairpos(typval_T *argvars, typval_T *rettv)
10332{
10333 pos_T match_pos;
10334 int lnum = 0;
10335 int col = 0;
10336
10337 if (rettv_list_alloc(rettv) == FAIL)
10338 return;
10339
10340 if (searchpair_cmn(argvars, &match_pos) > 0)
10341 {
10342 lnum = match_pos.lnum;
10343 col = match_pos.col;
10344 }
10345
10346 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10347 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10348}
10349
10350/*
10351 * Search for a start/middle/end thing.
10352 * Used by searchpair(), see its documentation for the details.
10353 * Returns 0 or -1 for no match,
10354 */
10355 long
10356do_searchpair(
10357 char_u *spat, /* start pattern */
10358 char_u *mpat, /* middle pattern */
10359 char_u *epat, /* end pattern */
10360 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010361 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010362 int flags, /* SP_SETPCMARK and other SP_ values */
10363 pos_T *match_pos,
10364 linenr_T lnum_stop, /* stop at this line if not zero */
10365 long time_limit UNUSED) /* stop after this many msec */
10366{
10367 char_u *save_cpo;
10368 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10369 long retval = 0;
10370 pos_T pos;
10371 pos_T firstpos;
10372 pos_T foundpos;
10373 pos_T save_cursor;
10374 pos_T save_pos;
10375 int n;
10376 int r;
10377 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010378 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010379 int err;
10380 int options = SEARCH_KEEP;
10381 proftime_T tm;
10382
10383 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10384 save_cpo = p_cpo;
10385 p_cpo = empty_option;
10386
10387#ifdef FEAT_RELTIME
10388 /* Set the time limit, if there is one. */
10389 profile_setlimit(time_limit, &tm);
10390#endif
10391
10392 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10393 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010394 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10395 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010396 if (pat2 == NULL || pat3 == NULL)
10397 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010398 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010399 if (*mpat == NUL)
10400 STRCPY(pat3, pat2);
10401 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010402 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010403 spat, epat, mpat);
10404 if (flags & SP_START)
10405 options |= SEARCH_START;
10406
Bram Moolenaar48570482017-10-30 21:48:41 +010010407 if (skip != NULL)
10408 {
10409 /* Empty string means to not use the skip expression. */
10410 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10411 use_skip = skip->vval.v_string != NULL
10412 && *skip->vval.v_string != NUL;
10413 }
10414
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010415 save_cursor = curwin->w_cursor;
10416 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010417 CLEAR_POS(&firstpos);
10418 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010419 pat = pat3;
10420 for (;;)
10421 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010422 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010423 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010424 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010425 /* didn't find it or found the first match again: FAIL */
10426 break;
10427
10428 if (firstpos.lnum == 0)
10429 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010430 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010431 {
10432 /* Found the same position again. Can happen with a pattern that
10433 * has "\zs" at the end and searching backwards. Advance one
10434 * character and try again. */
10435 if (dir == BACKWARD)
10436 decl(&pos);
10437 else
10438 incl(&pos);
10439 }
10440 foundpos = pos;
10441
10442 /* clear the start flag to avoid getting stuck here */
10443 options &= ~SEARCH_START;
10444
10445 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010446 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010447 {
10448 save_pos = curwin->w_cursor;
10449 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010450 err = FALSE;
10451 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010452 curwin->w_cursor = save_pos;
10453 if (err)
10454 {
10455 /* Evaluating {skip} caused an error, break here. */
10456 curwin->w_cursor = save_cursor;
10457 retval = -1;
10458 break;
10459 }
10460 if (r)
10461 continue;
10462 }
10463
10464 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10465 {
10466 /* Found end when searching backwards or start when searching
10467 * forward: nested pair. */
10468 ++nest;
10469 pat = pat2; /* nested, don't search for middle */
10470 }
10471 else
10472 {
10473 /* Found end when searching forward or start when searching
10474 * backward: end of (nested) pair; or found middle in outer pair. */
10475 if (--nest == 1)
10476 pat = pat3; /* outer level, search for middle */
10477 }
10478
10479 if (nest == 0)
10480 {
10481 /* Found the match: return matchcount or line number. */
10482 if (flags & SP_RETCOUNT)
10483 ++retval;
10484 else
10485 retval = pos.lnum;
10486 if (flags & SP_SETPCMARK)
10487 setpcmark();
10488 curwin->w_cursor = pos;
10489 if (!(flags & SP_REPEAT))
10490 break;
10491 nest = 1; /* search for next unmatched */
10492 }
10493 }
10494
10495 if (match_pos != NULL)
10496 {
10497 /* Store the match cursor position */
10498 match_pos->lnum = curwin->w_cursor.lnum;
10499 match_pos->col = curwin->w_cursor.col + 1;
10500 }
10501
10502 /* If 'n' flag is used or search failed: restore cursor position. */
10503 if ((flags & SP_NOMOVE) || retval == 0)
10504 curwin->w_cursor = save_cursor;
10505
10506theend:
10507 vim_free(pat2);
10508 vim_free(pat3);
10509 if (p_cpo == empty_option)
10510 p_cpo = save_cpo;
10511 else
10512 /* Darn, evaluating the {skip} expression changed the value. */
10513 free_string_option(save_cpo);
10514
10515 return retval;
10516}
10517
10518/*
10519 * "searchpos()" function
10520 */
10521 static void
10522f_searchpos(typval_T *argvars, typval_T *rettv)
10523{
10524 pos_T match_pos;
10525 int lnum = 0;
10526 int col = 0;
10527 int n;
10528 int flags = 0;
10529
10530 if (rettv_list_alloc(rettv) == FAIL)
10531 return;
10532
10533 n = search_cmn(argvars, &match_pos, &flags);
10534 if (n > 0)
10535 {
10536 lnum = match_pos.lnum;
10537 col = match_pos.col;
10538 }
10539
10540 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10541 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10542 if (flags & SP_SUBPAT)
10543 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10544}
10545
10546 static void
10547f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10548{
10549#ifdef FEAT_CLIENTSERVER
10550 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010551 char_u *server = tv_get_string_chk(&argvars[0]);
10552 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010553
10554 rettv->vval.v_number = -1;
10555 if (server == NULL || reply == NULL)
10556 return;
10557 if (check_restricted() || check_secure())
10558 return;
10559# ifdef FEAT_X11
10560 if (check_connection() == FAIL)
10561 return;
10562# endif
10563
10564 if (serverSendReply(server, reply) < 0)
10565 {
10566 EMSG(_("E258: Unable to send to client"));
10567 return;
10568 }
10569 rettv->vval.v_number = 0;
10570#else
10571 rettv->vval.v_number = -1;
10572#endif
10573}
10574
10575 static void
10576f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10577{
10578 char_u *r = NULL;
10579
10580#ifdef FEAT_CLIENTSERVER
10581# ifdef WIN32
10582 r = serverGetVimNames();
10583# else
10584 make_connection();
10585 if (X_DISPLAY != NULL)
10586 r = serverGetVimNames(X_DISPLAY);
10587# endif
10588#endif
10589 rettv->v_type = VAR_STRING;
10590 rettv->vval.v_string = r;
10591}
10592
10593/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010594 * "setbufline()" function
10595 */
10596 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010597f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010598{
10599 linenr_T lnum;
10600 buf_T *buf;
10601
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010602 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010603 if (buf == NULL)
10604 rettv->vval.v_number = 1; /* FAIL */
10605 else
10606 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010607 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010608 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010609 }
10610}
10611
10612/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010613 * "setbufvar()" function
10614 */
10615 static void
10616f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10617{
10618 buf_T *buf;
10619 char_u *varname, *bufvarname;
10620 typval_T *varp;
10621 char_u nbuf[NUMBUFLEN];
10622
10623 if (check_restricted() || check_secure())
10624 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010625 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10626 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010627 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010628 varp = &argvars[2];
10629
10630 if (buf != NULL && varname != NULL && varp != NULL)
10631 {
10632 if (*varname == '&')
10633 {
10634 long numval;
10635 char_u *strval;
10636 int error = FALSE;
10637 aco_save_T aco;
10638
10639 /* set curbuf to be our buf, temporarily */
10640 aucmd_prepbuf(&aco, buf);
10641
10642 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010643 numval = (long)tv_get_number_chk(varp, &error);
10644 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010645 if (!error && strval != NULL)
10646 set_option_value(varname, numval, strval, OPT_LOCAL);
10647
10648 /* reset notion of buffer */
10649 aucmd_restbuf(&aco);
10650 }
10651 else
10652 {
10653 buf_T *save_curbuf = curbuf;
10654
10655 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10656 if (bufvarname != NULL)
10657 {
10658 curbuf = buf;
10659 STRCPY(bufvarname, "b:");
10660 STRCPY(bufvarname + 2, varname);
10661 set_var(bufvarname, varp, TRUE);
10662 vim_free(bufvarname);
10663 curbuf = save_curbuf;
10664 }
10665 }
10666 }
10667}
10668
10669 static void
10670f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10671{
10672 dict_T *d;
10673 dictitem_T *di;
10674 char_u *csearch;
10675
10676 if (argvars[0].v_type != VAR_DICT)
10677 {
10678 EMSG(_(e_dictreq));
10679 return;
10680 }
10681
10682 if ((d = argvars[0].vval.v_dict) != NULL)
10683 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010684 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010685 if (csearch != NULL)
10686 {
10687#ifdef FEAT_MBYTE
10688 if (enc_utf8)
10689 {
10690 int pcc[MAX_MCO];
10691 int c = utfc_ptr2char(csearch, pcc);
10692
10693 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10694 }
10695 else
10696#endif
10697 set_last_csearch(PTR2CHAR(csearch),
10698 csearch, MB_PTR2LEN(csearch));
10699 }
10700
10701 di = dict_find(d, (char_u *)"forward", -1);
10702 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010703 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010704 ? FORWARD : BACKWARD);
10705
10706 di = dict_find(d, (char_u *)"until", -1);
10707 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010708 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010709 }
10710}
10711
10712/*
10713 * "setcmdpos()" function
10714 */
10715 static void
10716f_setcmdpos(typval_T *argvars, typval_T *rettv)
10717{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010718 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010719
10720 if (pos >= 0)
10721 rettv->vval.v_number = set_cmdline_pos(pos);
10722}
10723
10724/*
10725 * "setfperm({fname}, {mode})" function
10726 */
10727 static void
10728f_setfperm(typval_T *argvars, typval_T *rettv)
10729{
10730 char_u *fname;
10731 char_u modebuf[NUMBUFLEN];
10732 char_u *mode_str;
10733 int i;
10734 int mask;
10735 int mode = 0;
10736
10737 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010738 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010739 if (fname == NULL)
10740 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010741 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010742 if (mode_str == NULL)
10743 return;
10744 if (STRLEN(mode_str) != 9)
10745 {
10746 EMSG2(_(e_invarg2), mode_str);
10747 return;
10748 }
10749
10750 mask = 1;
10751 for (i = 8; i >= 0; --i)
10752 {
10753 if (mode_str[i] != '-')
10754 mode |= mask;
10755 mask = mask << 1;
10756 }
10757 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10758}
10759
10760/*
10761 * "setline()" function
10762 */
10763 static void
10764f_setline(typval_T *argvars, typval_T *rettv)
10765{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010766 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010767
Bram Moolenaarca851592018-06-06 21:04:07 +020010768 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010769}
10770
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010771/*
10772 * Used by "setqflist()" and "setloclist()" functions
10773 */
10774 static void
10775set_qf_ll_list(
10776 win_T *wp UNUSED,
10777 typval_T *list_arg UNUSED,
10778 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010779 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010780 typval_T *rettv)
10781{
10782#ifdef FEAT_QUICKFIX
10783 static char *e_invact = N_("E927: Invalid action: '%s'");
10784 char_u *act;
10785 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010786 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010787#endif
10788
10789 rettv->vval.v_number = -1;
10790
10791#ifdef FEAT_QUICKFIX
10792 if (list_arg->v_type != VAR_LIST)
10793 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010794 else if (recursive != 0)
10795 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010796 else
10797 {
10798 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010799 dict_T *d = NULL;
10800 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010801
10802 if (action_arg->v_type == VAR_STRING)
10803 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010804 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010805 if (act == NULL)
10806 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010807 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10808 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010809 action = *act;
10810 else
10811 EMSG2(_(e_invact), act);
10812 }
10813 else if (action_arg->v_type == VAR_UNKNOWN)
10814 action = ' ';
10815 else
10816 EMSG(_(e_stringreq));
10817
Bram Moolenaard823fa92016-08-12 16:29:27 +020010818 if (action_arg->v_type != VAR_UNKNOWN
10819 && what_arg->v_type != VAR_UNKNOWN)
10820 {
10821 if (what_arg->v_type == VAR_DICT)
10822 d = what_arg->vval.v_dict;
10823 else
10824 {
10825 EMSG(_(e_dictreq));
10826 valid_dict = FALSE;
10827 }
10828 }
10829
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010830 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010831 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010832 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10833 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010834 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010835 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010836 }
10837#endif
10838}
10839
10840/*
10841 * "setloclist()" function
10842 */
10843 static void
10844f_setloclist(typval_T *argvars, typval_T *rettv)
10845{
10846 win_T *win;
10847
10848 rettv->vval.v_number = -1;
10849
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010850 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010851 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010852 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010853}
10854
10855/*
10856 * "setmatches()" function
10857 */
10858 static void
10859f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10860{
10861#ifdef FEAT_SEARCH_EXTRA
10862 list_T *l;
10863 listitem_T *li;
10864 dict_T *d;
10865 list_T *s = NULL;
10866
10867 rettv->vval.v_number = -1;
10868 if (argvars[0].v_type != VAR_LIST)
10869 {
10870 EMSG(_(e_listreq));
10871 return;
10872 }
10873 if ((l = argvars[0].vval.v_list) != NULL)
10874 {
10875
10876 /* To some extent make sure that we are dealing with a list from
10877 * "getmatches()". */
10878 li = l->lv_first;
10879 while (li != NULL)
10880 {
10881 if (li->li_tv.v_type != VAR_DICT
10882 || (d = li->li_tv.vval.v_dict) == NULL)
10883 {
10884 EMSG(_(e_invarg));
10885 return;
10886 }
10887 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10888 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10889 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10890 && dict_find(d, (char_u *)"priority", -1) != NULL
10891 && dict_find(d, (char_u *)"id", -1) != NULL))
10892 {
10893 EMSG(_(e_invarg));
10894 return;
10895 }
10896 li = li->li_next;
10897 }
10898
10899 clear_matches(curwin);
10900 li = l->lv_first;
10901 while (li != NULL)
10902 {
10903 int i = 0;
10904 char_u buf[5];
10905 dictitem_T *di;
10906 char_u *group;
10907 int priority;
10908 int id;
10909 char_u *conceal;
10910
10911 d = li->li_tv.vval.v_dict;
10912 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10913 {
10914 if (s == NULL)
10915 {
10916 s = list_alloc();
10917 if (s == NULL)
10918 return;
10919 }
10920
10921 /* match from matchaddpos() */
10922 for (i = 1; i < 9; i++)
10923 {
10924 sprintf((char *)buf, (char *)"pos%d", i);
10925 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10926 {
10927 if (di->di_tv.v_type != VAR_LIST)
10928 return;
10929
10930 list_append_tv(s, &di->di_tv);
10931 s->lv_refcount++;
10932 }
10933 else
10934 break;
10935 }
10936 }
10937
Bram Moolenaar8f667172018-12-14 15:38:31 +010010938 group = dict_get_string(d, (char_u *)"group", TRUE);
10939 priority = (int)dict_get_number(d, (char_u *)"priority");
10940 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010941 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010010942 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010943 : NULL;
10944 if (i == 0)
10945 {
10946 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010010947 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010948 priority, id, NULL, conceal);
10949 }
10950 else
10951 {
10952 match_add(curwin, group, NULL, priority, id, s, conceal);
10953 list_unref(s);
10954 s = NULL;
10955 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010956 vim_free(group);
10957 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010958
10959 li = li->li_next;
10960 }
10961 rettv->vval.v_number = 0;
10962 }
10963#endif
10964}
10965
10966/*
10967 * "setpos()" function
10968 */
10969 static void
10970f_setpos(typval_T *argvars, typval_T *rettv)
10971{
10972 pos_T pos;
10973 int fnum;
10974 char_u *name;
10975 colnr_T curswant = -1;
10976
10977 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010978 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010979 if (name != NULL)
10980 {
10981 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10982 {
10983 if (--pos.col < 0)
10984 pos.col = 0;
10985 if (name[0] == '.' && name[1] == NUL)
10986 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010987 /* set cursor; "fnum" is ignored */
10988 curwin->w_cursor = pos;
10989 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010990 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010991 curwin->w_curswant = curswant - 1;
10992 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010993 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010994 check_cursor();
10995 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010996 }
10997 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10998 {
10999 /* set mark */
11000 if (setmark_pos(name[1], &pos, fnum) == OK)
11001 rettv->vval.v_number = 0;
11002 }
11003 else
11004 EMSG(_(e_invarg));
11005 }
11006 }
11007}
11008
11009/*
11010 * "setqflist()" function
11011 */
11012 static void
11013f_setqflist(typval_T *argvars, typval_T *rettv)
11014{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011015 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011016}
11017
11018/*
11019 * "setreg()" function
11020 */
11021 static void
11022f_setreg(typval_T *argvars, typval_T *rettv)
11023{
11024 int regname;
11025 char_u *strregname;
11026 char_u *stropt;
11027 char_u *strval;
11028 int append;
11029 char_u yank_type;
11030 long block_len;
11031
11032 block_len = -1;
11033 yank_type = MAUTO;
11034 append = FALSE;
11035
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011036 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011037 rettv->vval.v_number = 1; /* FAIL is default */
11038
11039 if (strregname == NULL)
11040 return; /* type error; errmsg already given */
11041 regname = *strregname;
11042 if (regname == 0 || regname == '@')
11043 regname = '"';
11044
11045 if (argvars[2].v_type != VAR_UNKNOWN)
11046 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011047 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011048 if (stropt == NULL)
11049 return; /* type error */
11050 for (; *stropt != NUL; ++stropt)
11051 switch (*stropt)
11052 {
11053 case 'a': case 'A': /* append */
11054 append = TRUE;
11055 break;
11056 case 'v': case 'c': /* character-wise selection */
11057 yank_type = MCHAR;
11058 break;
11059 case 'V': case 'l': /* line-wise selection */
11060 yank_type = MLINE;
11061 break;
11062 case 'b': case Ctrl_V: /* block-wise selection */
11063 yank_type = MBLOCK;
11064 if (VIM_ISDIGIT(stropt[1]))
11065 {
11066 ++stropt;
11067 block_len = getdigits(&stropt) - 1;
11068 --stropt;
11069 }
11070 break;
11071 }
11072 }
11073
11074 if (argvars[1].v_type == VAR_LIST)
11075 {
11076 char_u **lstval;
11077 char_u **allocval;
11078 char_u buf[NUMBUFLEN];
11079 char_u **curval;
11080 char_u **curallocval;
11081 list_T *ll = argvars[1].vval.v_list;
11082 listitem_T *li;
11083 int len;
11084
11085 /* If the list is NULL handle like an empty list. */
11086 len = ll == NULL ? 0 : ll->lv_len;
11087
11088 /* First half: use for pointers to result lines; second half: use for
11089 * pointers to allocated copies. */
11090 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11091 if (lstval == NULL)
11092 return;
11093 curval = lstval;
11094 allocval = lstval + len + 2;
11095 curallocval = allocval;
11096
11097 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11098 li = li->li_next)
11099 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011100 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011101 if (strval == NULL)
11102 goto free_lstval;
11103 if (strval == buf)
11104 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011105 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011106 * overwrite the string. */
11107 strval = vim_strsave(buf);
11108 if (strval == NULL)
11109 goto free_lstval;
11110 *curallocval++ = strval;
11111 }
11112 *curval++ = strval;
11113 }
11114 *curval++ = NULL;
11115
11116 write_reg_contents_lst(regname, lstval, -1,
11117 append, yank_type, block_len);
11118free_lstval:
11119 while (curallocval > allocval)
11120 vim_free(*--curallocval);
11121 vim_free(lstval);
11122 }
11123 else
11124 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011125 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011126 if (strval == NULL)
11127 return;
11128 write_reg_contents_ex(regname, strval, -1,
11129 append, yank_type, block_len);
11130 }
11131 rettv->vval.v_number = 0;
11132}
11133
11134/*
11135 * "settabvar()" function
11136 */
11137 static void
11138f_settabvar(typval_T *argvars, typval_T *rettv)
11139{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011140 tabpage_T *save_curtab;
11141 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011142 char_u *varname, *tabvarname;
11143 typval_T *varp;
11144
11145 rettv->vval.v_number = 0;
11146
11147 if (check_restricted() || check_secure())
11148 return;
11149
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011150 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11151 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152 varp = &argvars[2];
11153
Bram Moolenaar4033c552017-09-16 20:54:51 +020011154 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011155 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011156 save_curtab = curtab;
11157 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011158
11159 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11160 if (tabvarname != NULL)
11161 {
11162 STRCPY(tabvarname, "t:");
11163 STRCPY(tabvarname + 2, varname);
11164 set_var(tabvarname, varp, TRUE);
11165 vim_free(tabvarname);
11166 }
11167
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011168 /* Restore current tabpage */
11169 if (valid_tabpage(save_curtab))
11170 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011171 }
11172}
11173
11174/*
11175 * "settabwinvar()" function
11176 */
11177 static void
11178f_settabwinvar(typval_T *argvars, typval_T *rettv)
11179{
11180 setwinvar(argvars, rettv, 1);
11181}
11182
11183/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011184 * "settagstack()" function
11185 */
11186 static void
11187f_settagstack(typval_T *argvars, typval_T *rettv)
11188{
11189 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11190 win_T *wp;
11191 dict_T *d;
11192 int action = 'r';
11193
11194 rettv->vval.v_number = -1;
11195
11196 // first argument: window number or id
11197 wp = find_win_by_nr_or_id(&argvars[0]);
11198 if (wp == NULL)
11199 return;
11200
11201 // second argument: dict with items to set in the tag stack
11202 if (argvars[1].v_type != VAR_DICT)
11203 {
11204 EMSG(_(e_dictreq));
11205 return;
11206 }
11207 d = argvars[1].vval.v_dict;
11208 if (d == NULL)
11209 return;
11210
11211 // third argument: action - 'a' for append and 'r' for replace.
11212 // default is to replace the stack.
11213 if (argvars[2].v_type == VAR_UNKNOWN)
11214 action = 'r';
11215 else if (argvars[2].v_type == VAR_STRING)
11216 {
11217 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011218 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011219 if (actstr == NULL)
11220 return;
11221 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11222 action = *actstr;
11223 else
11224 {
11225 EMSG2(_(e_invact2), actstr);
11226 return;
11227 }
11228 }
11229 else
11230 {
11231 EMSG(_(e_stringreq));
11232 return;
11233 }
11234
11235 if (set_tagstack(wp, d, action) == OK)
11236 rettv->vval.v_number = 0;
11237}
11238
11239/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011240 * "setwinvar()" function
11241 */
11242 static void
11243f_setwinvar(typval_T *argvars, typval_T *rettv)
11244{
11245 setwinvar(argvars, rettv, 0);
11246}
11247
11248#ifdef FEAT_CRYPT
11249/*
11250 * "sha256({string})" function
11251 */
11252 static void
11253f_sha256(typval_T *argvars, typval_T *rettv)
11254{
11255 char_u *p;
11256
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011257 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011258 rettv->vval.v_string = vim_strsave(
11259 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11260 rettv->v_type = VAR_STRING;
11261}
11262#endif /* FEAT_CRYPT */
11263
11264/*
11265 * "shellescape({string})" function
11266 */
11267 static void
11268f_shellescape(typval_T *argvars, typval_T *rettv)
11269{
Bram Moolenaar20615522017-06-05 18:46:26 +020011270 int do_special = non_zero_arg(&argvars[1]);
11271
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011272 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011273 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011274 rettv->v_type = VAR_STRING;
11275}
11276
11277/*
11278 * shiftwidth() function
11279 */
11280 static void
11281f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11282{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011283 rettv->vval.v_number = 0;
11284
11285 if (argvars[0].v_type != VAR_UNKNOWN)
11286 {
11287 long col;
11288
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011289 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011290 if (col < 0)
11291 return; // type error; errmsg already given
11292#ifdef FEAT_VARTABS
11293 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11294 return;
11295#endif
11296 }
11297
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011298 rettv->vval.v_number = get_sw_value(curbuf);
11299}
11300
Bram Moolenaar162b7142018-12-21 15:17:36 +010011301#ifdef FEAT_SIGNS
11302/*
11303 * "sign_define()" function
11304 */
11305 static void
11306f_sign_define(typval_T *argvars, typval_T *rettv)
11307{
11308 char_u *name;
11309 dict_T *dict;
11310 char_u *icon = NULL;
11311 char_u *linehl = NULL;
11312 char_u *text = NULL;
11313 char_u *texthl = NULL;
11314
11315 rettv->vval.v_number = -1;
11316
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011317 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011318 if (name == NULL)
11319 return;
11320
11321 if (argvars[1].v_type != VAR_UNKNOWN)
11322 {
11323 if (argvars[1].v_type != VAR_DICT)
11324 {
11325 EMSG(_(e_dictreq));
11326 return;
11327 }
11328
11329 // sign attributes
11330 dict = argvars[1].vval.v_dict;
11331 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11332 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11333 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11334 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11335 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11336 text = dict_get_string(dict, (char_u *)"text", TRUE);
11337 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11338 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11339 }
11340
11341 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11342 rettv->vval.v_number = 0;
11343
11344 vim_free(icon);
11345 vim_free(linehl);
11346 vim_free(text);
11347 vim_free(texthl);
11348}
11349
11350/*
11351 * "sign_getdefined()" function
11352 */
11353 static void
11354f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11355{
11356 char_u *name = NULL;
11357
11358 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11359 return;
11360
11361 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011362 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011363
11364 sign_getlist(name, rettv->vval.v_list);
11365}
11366
11367/*
11368 * "sign_getplaced()" function
11369 */
11370 static void
11371f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11372{
11373 buf_T *buf = NULL;
11374 dict_T *dict;
11375 dictitem_T *di;
11376 linenr_T lnum = 0;
11377 int sign_id = 0;
11378 char_u *group = NULL;
11379 int notanum = FALSE;
11380
11381 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11382 return;
11383
11384 if (argvars[0].v_type != VAR_UNKNOWN)
11385 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011386 // get signs placed in the specified buffer
11387 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011388 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011389 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011390
11391 if (argvars[1].v_type != VAR_UNKNOWN)
11392 {
11393 if (argvars[1].v_type != VAR_DICT ||
11394 ((dict = argvars[1].vval.v_dict) == NULL))
11395 {
11396 EMSG(_(e_dictreq));
11397 return;
11398 }
11399 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11400 {
11401 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011402 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011403 if (notanum)
11404 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011405 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011406 }
11407 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11408 {
11409 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011410 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011411 if (notanum)
11412 return;
11413 }
11414 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11415 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011416 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011417 if (group == NULL)
11418 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011419 if (*group == '\0') // empty string means global group
11420 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011421 }
11422 }
11423 }
11424
11425 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11426}
11427
11428/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011429 * "sign_jump()" function
11430 */
11431 static void
11432f_sign_jump(typval_T *argvars, typval_T *rettv)
11433{
11434 int sign_id;
11435 char_u *sign_group = NULL;
11436 buf_T *buf;
11437 int notanum = FALSE;
11438
11439 rettv->vval.v_number = -1;
11440
11441 // Sign identifer
11442 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11443 if (notanum)
11444 return;
11445 if (sign_id <= 0)
11446 {
11447 EMSG(_(e_invarg));
11448 return;
11449 }
11450
11451 // Sign group
11452 sign_group = tv_get_string_chk(&argvars[1]);
11453 if (sign_group == NULL)
11454 return;
11455 if (sign_group[0] == '\0')
11456 sign_group = NULL; // global sign group
11457 else
11458 {
11459 sign_group = vim_strsave(sign_group);
11460 if (sign_group == NULL)
11461 return;
11462 }
11463
11464 // Buffer to place the sign
11465 buf = get_buf_arg(&argvars[2]);
11466 if (buf == NULL)
11467 goto cleanup;
11468
11469 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11470
11471cleanup:
11472 vim_free(sign_group);
11473}
11474
11475/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011476 * "sign_place()" function
11477 */
11478 static void
11479f_sign_place(typval_T *argvars, typval_T *rettv)
11480{
11481 int sign_id;
11482 char_u *group = NULL;
11483 char_u *sign_name;
11484 buf_T *buf;
11485 dict_T *dict;
11486 dictitem_T *di;
11487 linenr_T lnum = 0;
11488 int prio = SIGN_DEF_PRIO;
11489 int notanum = FALSE;
11490
11491 rettv->vval.v_number = -1;
11492
11493 // Sign identifer
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011494 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011495 if (notanum)
11496 return;
11497 if (sign_id < 0)
11498 {
11499 EMSG(_(e_invarg));
11500 return;
11501 }
11502
11503 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011504 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011505 if (group == NULL)
11506 return;
11507 if (group[0] == '\0')
11508 group = NULL; // global sign group
11509 else
11510 {
11511 group = vim_strsave(group);
11512 if (group == NULL)
11513 return;
11514 }
11515
11516 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011517 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011518 if (sign_name == NULL)
11519 goto cleanup;
11520
11521 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011522 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011523 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011524 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011525
11526 if (argvars[4].v_type != VAR_UNKNOWN)
11527 {
11528 if (argvars[4].v_type != VAR_DICT ||
11529 ((dict = argvars[4].vval.v_dict) == NULL))
11530 {
11531 EMSG(_(e_dictreq));
11532 goto cleanup;
11533 }
11534
11535 // Line number where the sign is to be placed
11536 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11537 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011538 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011539 if (notanum)
11540 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011541 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011542 }
11543 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11544 {
11545 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011546 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011547 if (notanum)
11548 goto cleanup;
11549 }
11550 }
11551
11552 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11553 rettv->vval.v_number = sign_id;
11554
11555cleanup:
11556 vim_free(group);
11557}
11558
11559/*
11560 * "sign_undefine()" function
11561 */
11562 static void
11563f_sign_undefine(typval_T *argvars, typval_T *rettv)
11564{
11565 char_u *name;
11566
11567 rettv->vval.v_number = -1;
11568
11569 if (argvars[0].v_type == VAR_UNKNOWN)
11570 {
11571 // Free all the signs
11572 free_signs();
11573 rettv->vval.v_number = 0;
11574 }
11575 else
11576 {
11577 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011578 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011579 if (name == NULL)
11580 return;
11581
11582 if (sign_undefine_by_name(name) == OK)
11583 rettv->vval.v_number = 0;
11584 }
11585}
11586
11587/*
11588 * "sign_unplace()" function
11589 */
11590 static void
11591f_sign_unplace(typval_T *argvars, typval_T *rettv)
11592{
11593 dict_T *dict;
11594 dictitem_T *di;
11595 int sign_id = 0;
11596 buf_T *buf = NULL;
11597 char_u *group = NULL;
11598
11599 rettv->vval.v_number = -1;
11600
11601 if (argvars[0].v_type != VAR_STRING)
11602 {
11603 EMSG(_(e_invarg));
11604 return;
11605 }
11606
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011607 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011608 if (group[0] == '\0')
11609 group = NULL; // global sign group
11610 else
11611 {
11612 group = vim_strsave(group);
11613 if (group == NULL)
11614 return;
11615 }
11616
11617 if (argvars[1].v_type != VAR_UNKNOWN)
11618 {
11619 if (argvars[1].v_type != VAR_DICT)
11620 {
11621 EMSG(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011622 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011623 }
11624 dict = argvars[1].vval.v_dict;
11625
11626 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11627 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011628 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011629 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011630 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011631 }
11632 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11633 sign_id = dict_get_number(dict, (char_u *)"id");
11634 }
11635
11636 if (buf == NULL)
11637 {
11638 // Delete the sign in all the buffers
11639 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011640 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011641 rettv->vval.v_number = 0;
11642 }
11643 else
11644 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011645 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011646 rettv->vval.v_number = 0;
11647 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011648
11649cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010011650 vim_free(group);
11651}
11652#endif
11653
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011654/*
11655 * "simplify()" function
11656 */
11657 static void
11658f_simplify(typval_T *argvars, typval_T *rettv)
11659{
11660 char_u *p;
11661
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011662 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011663 rettv->vval.v_string = vim_strsave(p);
11664 simplify_filename(rettv->vval.v_string); /* simplify in place */
11665 rettv->v_type = VAR_STRING;
11666}
11667
11668#ifdef FEAT_FLOAT
11669/*
11670 * "sin()" function
11671 */
11672 static void
11673f_sin(typval_T *argvars, typval_T *rettv)
11674{
11675 float_T f = 0.0;
11676
11677 rettv->v_type = VAR_FLOAT;
11678 if (get_float_arg(argvars, &f) == OK)
11679 rettv->vval.v_float = sin(f);
11680 else
11681 rettv->vval.v_float = 0.0;
11682}
11683
11684/*
11685 * "sinh()" function
11686 */
11687 static void
11688f_sinh(typval_T *argvars, typval_T *rettv)
11689{
11690 float_T f = 0.0;
11691
11692 rettv->v_type = VAR_FLOAT;
11693 if (get_float_arg(argvars, &f) == OK)
11694 rettv->vval.v_float = sinh(f);
11695 else
11696 rettv->vval.v_float = 0.0;
11697}
11698#endif
11699
11700static int
11701#ifdef __BORLANDC__
11702 _RTLENTRYF
11703#endif
11704 item_compare(const void *s1, const void *s2);
11705static int
11706#ifdef __BORLANDC__
11707 _RTLENTRYF
11708#endif
11709 item_compare2(const void *s1, const void *s2);
11710
11711/* struct used in the array that's given to qsort() */
11712typedef struct
11713{
11714 listitem_T *item;
11715 int idx;
11716} sortItem_T;
11717
11718/* struct storing information about current sort */
11719typedef struct
11720{
11721 int item_compare_ic;
11722 int item_compare_numeric;
11723 int item_compare_numbers;
11724#ifdef FEAT_FLOAT
11725 int item_compare_float;
11726#endif
11727 char_u *item_compare_func;
11728 partial_T *item_compare_partial;
11729 dict_T *item_compare_selfdict;
11730 int item_compare_func_err;
11731 int item_compare_keep_zero;
11732} sortinfo_T;
11733static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011734#define ITEM_COMPARE_FAIL 999
11735
11736/*
11737 * Compare functions for f_sort() and f_uniq() below.
11738 */
11739 static int
11740#ifdef __BORLANDC__
11741_RTLENTRYF
11742#endif
11743item_compare(const void *s1, const void *s2)
11744{
11745 sortItem_T *si1, *si2;
11746 typval_T *tv1, *tv2;
11747 char_u *p1, *p2;
11748 char_u *tofree1 = NULL, *tofree2 = NULL;
11749 int res;
11750 char_u numbuf1[NUMBUFLEN];
11751 char_u numbuf2[NUMBUFLEN];
11752
11753 si1 = (sortItem_T *)s1;
11754 si2 = (sortItem_T *)s2;
11755 tv1 = &si1->item->li_tv;
11756 tv2 = &si2->item->li_tv;
11757
11758 if (sortinfo->item_compare_numbers)
11759 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011760 varnumber_T v1 = tv_get_number(tv1);
11761 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011762
11763 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11764 }
11765
11766#ifdef FEAT_FLOAT
11767 if (sortinfo->item_compare_float)
11768 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011769 float_T v1 = tv_get_float(tv1);
11770 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011771
11772 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11773 }
11774#endif
11775
11776 /* tv2string() puts quotes around a string and allocates memory. Don't do
11777 * that for string variables. Use a single quote when comparing with a
11778 * non-string to do what the docs promise. */
11779 if (tv1->v_type == VAR_STRING)
11780 {
11781 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11782 p1 = (char_u *)"'";
11783 else
11784 p1 = tv1->vval.v_string;
11785 }
11786 else
11787 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11788 if (tv2->v_type == VAR_STRING)
11789 {
11790 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11791 p2 = (char_u *)"'";
11792 else
11793 p2 = tv2->vval.v_string;
11794 }
11795 else
11796 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11797 if (p1 == NULL)
11798 p1 = (char_u *)"";
11799 if (p2 == NULL)
11800 p2 = (char_u *)"";
11801 if (!sortinfo->item_compare_numeric)
11802 {
11803 if (sortinfo->item_compare_ic)
11804 res = STRICMP(p1, p2);
11805 else
11806 res = STRCMP(p1, p2);
11807 }
11808 else
11809 {
11810 double n1, n2;
11811 n1 = strtod((char *)p1, (char **)&p1);
11812 n2 = strtod((char *)p2, (char **)&p2);
11813 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11814 }
11815
11816 /* When the result would be zero, compare the item indexes. Makes the
11817 * sort stable. */
11818 if (res == 0 && !sortinfo->item_compare_keep_zero)
11819 res = si1->idx > si2->idx ? 1 : -1;
11820
11821 vim_free(tofree1);
11822 vim_free(tofree2);
11823 return res;
11824}
11825
11826 static int
11827#ifdef __BORLANDC__
11828_RTLENTRYF
11829#endif
11830item_compare2(const void *s1, const void *s2)
11831{
11832 sortItem_T *si1, *si2;
11833 int res;
11834 typval_T rettv;
11835 typval_T argv[3];
11836 int dummy;
11837 char_u *func_name;
11838 partial_T *partial = sortinfo->item_compare_partial;
11839
11840 /* shortcut after failure in previous call; compare all items equal */
11841 if (sortinfo->item_compare_func_err)
11842 return 0;
11843
11844 si1 = (sortItem_T *)s1;
11845 si2 = (sortItem_T *)s2;
11846
11847 if (partial == NULL)
11848 func_name = sortinfo->item_compare_func;
11849 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011850 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011851
11852 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11853 * in the copy without changing the original list items. */
11854 copy_tv(&si1->item->li_tv, &argv[0]);
11855 copy_tv(&si2->item->li_tv, &argv[1]);
11856
11857 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11858 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011859 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011860 partial, sortinfo->item_compare_selfdict);
11861 clear_tv(&argv[0]);
11862 clear_tv(&argv[1]);
11863
11864 if (res == FAIL)
11865 res = ITEM_COMPARE_FAIL;
11866 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011867 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011868 if (sortinfo->item_compare_func_err)
11869 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11870 clear_tv(&rettv);
11871
11872 /* When the result would be zero, compare the pointers themselves. Makes
11873 * the sort stable. */
11874 if (res == 0 && !sortinfo->item_compare_keep_zero)
11875 res = si1->idx > si2->idx ? 1 : -1;
11876
11877 return res;
11878}
11879
11880/*
11881 * "sort({list})" function
11882 */
11883 static void
11884do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11885{
11886 list_T *l;
11887 listitem_T *li;
11888 sortItem_T *ptrs;
11889 sortinfo_T *old_sortinfo;
11890 sortinfo_T info;
11891 long len;
11892 long i;
11893
11894 /* Pointer to current info struct used in compare function. Save and
11895 * restore the current one for nested calls. */
11896 old_sortinfo = sortinfo;
11897 sortinfo = &info;
11898
11899 if (argvars[0].v_type != VAR_LIST)
11900 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11901 else
11902 {
11903 l = argvars[0].vval.v_list;
11904 if (l == NULL || tv_check_lock(l->lv_lock,
11905 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11906 TRUE))
11907 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011908 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011909
11910 len = list_len(l);
11911 if (len <= 1)
11912 goto theend; /* short list sorts pretty quickly */
11913
11914 info.item_compare_ic = FALSE;
11915 info.item_compare_numeric = FALSE;
11916 info.item_compare_numbers = FALSE;
11917#ifdef FEAT_FLOAT
11918 info.item_compare_float = FALSE;
11919#endif
11920 info.item_compare_func = NULL;
11921 info.item_compare_partial = NULL;
11922 info.item_compare_selfdict = NULL;
11923 if (argvars[1].v_type != VAR_UNKNOWN)
11924 {
11925 /* optional second argument: {func} */
11926 if (argvars[1].v_type == VAR_FUNC)
11927 info.item_compare_func = argvars[1].vval.v_string;
11928 else if (argvars[1].v_type == VAR_PARTIAL)
11929 info.item_compare_partial = argvars[1].vval.v_partial;
11930 else
11931 {
11932 int error = FALSE;
11933
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011934 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011935 if (error)
11936 goto theend; /* type error; errmsg already given */
11937 if (i == 1)
11938 info.item_compare_ic = TRUE;
11939 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011940 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011941 else if (i != 0)
11942 {
11943 EMSG(_(e_invarg));
11944 goto theend;
11945 }
11946 if (info.item_compare_func != NULL)
11947 {
11948 if (*info.item_compare_func == NUL)
11949 {
11950 /* empty string means default sort */
11951 info.item_compare_func = NULL;
11952 }
11953 else if (STRCMP(info.item_compare_func, "n") == 0)
11954 {
11955 info.item_compare_func = NULL;
11956 info.item_compare_numeric = TRUE;
11957 }
11958 else if (STRCMP(info.item_compare_func, "N") == 0)
11959 {
11960 info.item_compare_func = NULL;
11961 info.item_compare_numbers = TRUE;
11962 }
11963#ifdef FEAT_FLOAT
11964 else if (STRCMP(info.item_compare_func, "f") == 0)
11965 {
11966 info.item_compare_func = NULL;
11967 info.item_compare_float = TRUE;
11968 }
11969#endif
11970 else if (STRCMP(info.item_compare_func, "i") == 0)
11971 {
11972 info.item_compare_func = NULL;
11973 info.item_compare_ic = TRUE;
11974 }
11975 }
11976 }
11977
11978 if (argvars[2].v_type != VAR_UNKNOWN)
11979 {
11980 /* optional third argument: {dict} */
11981 if (argvars[2].v_type != VAR_DICT)
11982 {
11983 EMSG(_(e_dictreq));
11984 goto theend;
11985 }
11986 info.item_compare_selfdict = argvars[2].vval.v_dict;
11987 }
11988 }
11989
11990 /* Make an array with each entry pointing to an item in the List. */
11991 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11992 if (ptrs == NULL)
11993 goto theend;
11994
11995 i = 0;
11996 if (sort)
11997 {
11998 /* sort(): ptrs will be the list to sort */
11999 for (li = l->lv_first; li != NULL; li = li->li_next)
12000 {
12001 ptrs[i].item = li;
12002 ptrs[i].idx = i;
12003 ++i;
12004 }
12005
12006 info.item_compare_func_err = FALSE;
12007 info.item_compare_keep_zero = FALSE;
12008 /* test the compare function */
12009 if ((info.item_compare_func != NULL
12010 || info.item_compare_partial != NULL)
12011 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12012 == ITEM_COMPARE_FAIL)
12013 EMSG(_("E702: Sort compare function failed"));
12014 else
12015 {
12016 /* Sort the array with item pointers. */
12017 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12018 info.item_compare_func == NULL
12019 && info.item_compare_partial == NULL
12020 ? item_compare : item_compare2);
12021
12022 if (!info.item_compare_func_err)
12023 {
12024 /* Clear the List and append the items in sorted order. */
12025 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12026 l->lv_len = 0;
12027 for (i = 0; i < len; ++i)
12028 list_append(l, ptrs[i].item);
12029 }
12030 }
12031 }
12032 else
12033 {
12034 int (*item_compare_func_ptr)(const void *, const void *);
12035
12036 /* f_uniq(): ptrs will be a stack of items to remove */
12037 info.item_compare_func_err = FALSE;
12038 info.item_compare_keep_zero = TRUE;
12039 item_compare_func_ptr = info.item_compare_func != NULL
12040 || info.item_compare_partial != NULL
12041 ? item_compare2 : item_compare;
12042
12043 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12044 li = li->li_next)
12045 {
12046 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12047 == 0)
12048 ptrs[i++].item = li;
12049 if (info.item_compare_func_err)
12050 {
12051 EMSG(_("E882: Uniq compare function failed"));
12052 break;
12053 }
12054 }
12055
12056 if (!info.item_compare_func_err)
12057 {
12058 while (--i >= 0)
12059 {
12060 li = ptrs[i].item->li_next;
12061 ptrs[i].item->li_next = li->li_next;
12062 if (li->li_next != NULL)
12063 li->li_next->li_prev = ptrs[i].item;
12064 else
12065 l->lv_last = ptrs[i].item;
12066 list_fix_watch(l, li);
12067 listitem_free(li);
12068 l->lv_len--;
12069 }
12070 }
12071 }
12072
12073 vim_free(ptrs);
12074 }
12075theend:
12076 sortinfo = old_sortinfo;
12077}
12078
12079/*
12080 * "sort({list})" function
12081 */
12082 static void
12083f_sort(typval_T *argvars, typval_T *rettv)
12084{
12085 do_sort_uniq(argvars, rettv, TRUE);
12086}
12087
12088/*
12089 * "uniq({list})" function
12090 */
12091 static void
12092f_uniq(typval_T *argvars, typval_T *rettv)
12093{
12094 do_sort_uniq(argvars, rettv, FALSE);
12095}
12096
12097/*
12098 * "soundfold({word})" function
12099 */
12100 static void
12101f_soundfold(typval_T *argvars, typval_T *rettv)
12102{
12103 char_u *s;
12104
12105 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012106 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012107#ifdef FEAT_SPELL
12108 rettv->vval.v_string = eval_soundfold(s);
12109#else
12110 rettv->vval.v_string = vim_strsave(s);
12111#endif
12112}
12113
12114/*
12115 * "spellbadword()" function
12116 */
12117 static void
12118f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12119{
12120 char_u *word = (char_u *)"";
12121 hlf_T attr = HLF_COUNT;
12122 int len = 0;
12123
12124 if (rettv_list_alloc(rettv) == FAIL)
12125 return;
12126
12127#ifdef FEAT_SPELL
12128 if (argvars[0].v_type == VAR_UNKNOWN)
12129 {
12130 /* Find the start and length of the badly spelled word. */
12131 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12132 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012133 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012134 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012135 curwin->w_set_curswant = TRUE;
12136 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012137 }
12138 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12139 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012140 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012141 int capcol = -1;
12142
12143 if (str != NULL)
12144 {
12145 /* Check the argument for spelling. */
12146 while (*str != NUL)
12147 {
12148 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12149 if (attr != HLF_COUNT)
12150 {
12151 word = str;
12152 break;
12153 }
12154 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012155 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012156 }
12157 }
12158 }
12159#endif
12160
12161 list_append_string(rettv->vval.v_list, word, len);
12162 list_append_string(rettv->vval.v_list, (char_u *)(
12163 attr == HLF_SPB ? "bad" :
12164 attr == HLF_SPR ? "rare" :
12165 attr == HLF_SPL ? "local" :
12166 attr == HLF_SPC ? "caps" :
12167 ""), -1);
12168}
12169
12170/*
12171 * "spellsuggest()" function
12172 */
12173 static void
12174f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12175{
12176#ifdef FEAT_SPELL
12177 char_u *str;
12178 int typeerr = FALSE;
12179 int maxcount;
12180 garray_T ga;
12181 int i;
12182 listitem_T *li;
12183 int need_capital = FALSE;
12184#endif
12185
12186 if (rettv_list_alloc(rettv) == FAIL)
12187 return;
12188
12189#ifdef FEAT_SPELL
12190 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12191 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012192 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012193 if (argvars[1].v_type != VAR_UNKNOWN)
12194 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012195 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012196 if (maxcount <= 0)
12197 return;
12198 if (argvars[2].v_type != VAR_UNKNOWN)
12199 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012200 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012201 if (typeerr)
12202 return;
12203 }
12204 }
12205 else
12206 maxcount = 25;
12207
12208 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12209
12210 for (i = 0; i < ga.ga_len; ++i)
12211 {
12212 str = ((char_u **)ga.ga_data)[i];
12213
12214 li = listitem_alloc();
12215 if (li == NULL)
12216 vim_free(str);
12217 else
12218 {
12219 li->li_tv.v_type = VAR_STRING;
12220 li->li_tv.v_lock = 0;
12221 li->li_tv.vval.v_string = str;
12222 list_append(rettv->vval.v_list, li);
12223 }
12224 }
12225 ga_clear(&ga);
12226 }
12227#endif
12228}
12229
12230 static void
12231f_split(typval_T *argvars, typval_T *rettv)
12232{
12233 char_u *str;
12234 char_u *end;
12235 char_u *pat = NULL;
12236 regmatch_T regmatch;
12237 char_u patbuf[NUMBUFLEN];
12238 char_u *save_cpo;
12239 int match;
12240 colnr_T col = 0;
12241 int keepempty = FALSE;
12242 int typeerr = FALSE;
12243
12244 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12245 save_cpo = p_cpo;
12246 p_cpo = (char_u *)"";
12247
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012248 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012249 if (argvars[1].v_type != VAR_UNKNOWN)
12250 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012251 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012252 if (pat == NULL)
12253 typeerr = TRUE;
12254 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012255 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012256 }
12257 if (pat == NULL || *pat == NUL)
12258 pat = (char_u *)"[\\x01- ]\\+";
12259
12260 if (rettv_list_alloc(rettv) == FAIL)
12261 return;
12262 if (typeerr)
12263 return;
12264
12265 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12266 if (regmatch.regprog != NULL)
12267 {
12268 regmatch.rm_ic = FALSE;
12269 while (*str != NUL || keepempty)
12270 {
12271 if (*str == NUL)
12272 match = FALSE; /* empty item at the end */
12273 else
12274 match = vim_regexec_nl(&regmatch, str, col);
12275 if (match)
12276 end = regmatch.startp[0];
12277 else
12278 end = str + STRLEN(str);
12279 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12280 && *str != NUL && match && end < regmatch.endp[0]))
12281 {
12282 if (list_append_string(rettv->vval.v_list, str,
12283 (int)(end - str)) == FAIL)
12284 break;
12285 }
12286 if (!match)
12287 break;
12288 /* Advance to just after the match. */
12289 if (regmatch.endp[0] > str)
12290 col = 0;
12291 else
12292 {
12293 /* Don't get stuck at the same match. */
12294#ifdef FEAT_MBYTE
12295 col = (*mb_ptr2len)(regmatch.endp[0]);
12296#else
12297 col = 1;
12298#endif
12299 }
12300 str = regmatch.endp[0];
12301 }
12302
12303 vim_regfree(regmatch.regprog);
12304 }
12305
12306 p_cpo = save_cpo;
12307}
12308
12309#ifdef FEAT_FLOAT
12310/*
12311 * "sqrt()" function
12312 */
12313 static void
12314f_sqrt(typval_T *argvars, typval_T *rettv)
12315{
12316 float_T f = 0.0;
12317
12318 rettv->v_type = VAR_FLOAT;
12319 if (get_float_arg(argvars, &f) == OK)
12320 rettv->vval.v_float = sqrt(f);
12321 else
12322 rettv->vval.v_float = 0.0;
12323}
12324
12325/*
12326 * "str2float()" function
12327 */
12328 static void
12329f_str2float(typval_T *argvars, typval_T *rettv)
12330{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012331 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012332 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012333
Bram Moolenaar08243d22017-01-10 16:12:29 +010012334 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012335 p = skipwhite(p + 1);
12336 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012337 if (isneg)
12338 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012339 rettv->v_type = VAR_FLOAT;
12340}
12341#endif
12342
12343/*
12344 * "str2nr()" function
12345 */
12346 static void
12347f_str2nr(typval_T *argvars, typval_T *rettv)
12348{
12349 int base = 10;
12350 char_u *p;
12351 varnumber_T n;
12352 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012353 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012354
12355 if (argvars[1].v_type != VAR_UNKNOWN)
12356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012357 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012358 if (base != 2 && base != 8 && base != 10 && base != 16)
12359 {
12360 EMSG(_(e_invarg));
12361 return;
12362 }
12363 }
12364
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012365 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012366 isneg = (*p == '-');
12367 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012368 p = skipwhite(p + 1);
12369 switch (base)
12370 {
12371 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12372 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12373 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12374 default: what = 0;
12375 }
12376 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012377 if (isneg)
12378 rettv->vval.v_number = -n;
12379 else
12380 rettv->vval.v_number = n;
12381
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012382}
12383
12384#ifdef HAVE_STRFTIME
12385/*
12386 * "strftime({format}[, {time}])" function
12387 */
12388 static void
12389f_strftime(typval_T *argvars, typval_T *rettv)
12390{
12391 char_u result_buf[256];
12392 struct tm *curtime;
12393 time_t seconds;
12394 char_u *p;
12395
12396 rettv->v_type = VAR_STRING;
12397
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012398 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012399 if (argvars[1].v_type == VAR_UNKNOWN)
12400 seconds = time(NULL);
12401 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012402 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012403 curtime = localtime(&seconds);
12404 /* MSVC returns NULL for an invalid value of seconds. */
12405 if (curtime == NULL)
12406 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12407 else
12408 {
12409# ifdef FEAT_MBYTE
12410 vimconv_T conv;
12411 char_u *enc;
12412
12413 conv.vc_type = CONV_NONE;
12414 enc = enc_locale();
12415 convert_setup(&conv, p_enc, enc);
12416 if (conv.vc_type != CONV_NONE)
12417 p = string_convert(&conv, p, NULL);
12418# endif
12419 if (p != NULL)
12420 (void)strftime((char *)result_buf, sizeof(result_buf),
12421 (char *)p, curtime);
12422 else
12423 result_buf[0] = NUL;
12424
12425# ifdef FEAT_MBYTE
12426 if (conv.vc_type != CONV_NONE)
12427 vim_free(p);
12428 convert_setup(&conv, enc, p_enc);
12429 if (conv.vc_type != CONV_NONE)
12430 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12431 else
12432# endif
12433 rettv->vval.v_string = vim_strsave(result_buf);
12434
12435# ifdef FEAT_MBYTE
12436 /* Release conversion descriptors */
12437 convert_setup(&conv, NULL, NULL);
12438 vim_free(enc);
12439# endif
12440 }
12441}
12442#endif
12443
12444/*
12445 * "strgetchar()" function
12446 */
12447 static void
12448f_strgetchar(typval_T *argvars, typval_T *rettv)
12449{
12450 char_u *str;
12451 int len;
12452 int error = FALSE;
12453 int charidx;
12454
12455 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012456 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012457 if (str == NULL)
12458 return;
12459 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012460 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012461 if (error)
12462 return;
12463#ifdef FEAT_MBYTE
12464 {
12465 int byteidx = 0;
12466
12467 while (charidx >= 0 && byteidx < len)
12468 {
12469 if (charidx == 0)
12470 {
12471 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12472 break;
12473 }
12474 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012475 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012476 }
12477 }
12478#else
12479 if (charidx < len)
12480 rettv->vval.v_number = str[charidx];
12481#endif
12482}
12483
12484/*
12485 * "stridx()" function
12486 */
12487 static void
12488f_stridx(typval_T *argvars, typval_T *rettv)
12489{
12490 char_u buf[NUMBUFLEN];
12491 char_u *needle;
12492 char_u *haystack;
12493 char_u *save_haystack;
12494 char_u *pos;
12495 int start_idx;
12496
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012497 needle = tv_get_string_chk(&argvars[1]);
12498 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012499 rettv->vval.v_number = -1;
12500 if (needle == NULL || haystack == NULL)
12501 return; /* type error; errmsg already given */
12502
12503 if (argvars[2].v_type != VAR_UNKNOWN)
12504 {
12505 int error = FALSE;
12506
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012507 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012508 if (error || start_idx >= (int)STRLEN(haystack))
12509 return;
12510 if (start_idx >= 0)
12511 haystack += start_idx;
12512 }
12513
12514 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12515 if (pos != NULL)
12516 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12517}
12518
12519/*
12520 * "string()" function
12521 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012522 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012523f_string(typval_T *argvars, typval_T *rettv)
12524{
12525 char_u *tofree;
12526 char_u numbuf[NUMBUFLEN];
12527
12528 rettv->v_type = VAR_STRING;
12529 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12530 get_copyID());
12531 /* Make a copy if we have a value but it's not in allocated memory. */
12532 if (rettv->vval.v_string != NULL && tofree == NULL)
12533 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12534}
12535
12536/*
12537 * "strlen()" function
12538 */
12539 static void
12540f_strlen(typval_T *argvars, typval_T *rettv)
12541{
12542 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012543 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012544}
12545
12546/*
12547 * "strchars()" function
12548 */
12549 static void
12550f_strchars(typval_T *argvars, typval_T *rettv)
12551{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012552 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012553 int skipcc = 0;
12554#ifdef FEAT_MBYTE
12555 varnumber_T len = 0;
12556 int (*func_mb_ptr2char_adv)(char_u **pp);
12557#endif
12558
12559 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012560 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012561 if (skipcc < 0 || skipcc > 1)
12562 EMSG(_(e_invarg));
12563 else
12564 {
12565#ifdef FEAT_MBYTE
12566 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12567 while (*s != NUL)
12568 {
12569 func_mb_ptr2char_adv(&s);
12570 ++len;
12571 }
12572 rettv->vval.v_number = len;
12573#else
12574 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12575#endif
12576 }
12577}
12578
12579/*
12580 * "strdisplaywidth()" function
12581 */
12582 static void
12583f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12584{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012585 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012586 int col = 0;
12587
12588 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012589 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012590
12591 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12592}
12593
12594/*
12595 * "strwidth()" function
12596 */
12597 static void
12598f_strwidth(typval_T *argvars, typval_T *rettv)
12599{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012600 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012601
12602 rettv->vval.v_number = (varnumber_T)(
12603#ifdef FEAT_MBYTE
12604 mb_string2cells(s, -1)
12605#else
12606 STRLEN(s)
12607#endif
12608 );
12609}
12610
12611/*
12612 * "strcharpart()" function
12613 */
12614 static void
12615f_strcharpart(typval_T *argvars, typval_T *rettv)
12616{
12617#ifdef FEAT_MBYTE
12618 char_u *p;
12619 int nchar;
12620 int nbyte = 0;
12621 int charlen;
12622 int len = 0;
12623 int slen;
12624 int error = FALSE;
12625
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012626 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012627 slen = (int)STRLEN(p);
12628
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012629 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012630 if (!error)
12631 {
12632 if (nchar > 0)
12633 while (nchar > 0 && nbyte < slen)
12634 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012635 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012636 --nchar;
12637 }
12638 else
12639 nbyte = nchar;
12640 if (argvars[2].v_type != VAR_UNKNOWN)
12641 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012642 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012643 while (charlen > 0 && nbyte + len < slen)
12644 {
12645 int off = nbyte + len;
12646
12647 if (off < 0)
12648 len += 1;
12649 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012650 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012651 --charlen;
12652 }
12653 }
12654 else
12655 len = slen - nbyte; /* default: all bytes that are available. */
12656 }
12657
12658 /*
12659 * Only return the overlap between the specified part and the actual
12660 * string.
12661 */
12662 if (nbyte < 0)
12663 {
12664 len += nbyte;
12665 nbyte = 0;
12666 }
12667 else if (nbyte > slen)
12668 nbyte = slen;
12669 if (len < 0)
12670 len = 0;
12671 else if (nbyte + len > slen)
12672 len = slen - nbyte;
12673
12674 rettv->v_type = VAR_STRING;
12675 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12676#else
12677 f_strpart(argvars, rettv);
12678#endif
12679}
12680
12681/*
12682 * "strpart()" function
12683 */
12684 static void
12685f_strpart(typval_T *argvars, typval_T *rettv)
12686{
12687 char_u *p;
12688 int n;
12689 int len;
12690 int slen;
12691 int error = FALSE;
12692
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012693 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012694 slen = (int)STRLEN(p);
12695
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012696 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012697 if (error)
12698 len = 0;
12699 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012700 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012701 else
12702 len = slen - n; /* default len: all bytes that are available. */
12703
12704 /*
12705 * Only return the overlap between the specified part and the actual
12706 * string.
12707 */
12708 if (n < 0)
12709 {
12710 len += n;
12711 n = 0;
12712 }
12713 else if (n > slen)
12714 n = slen;
12715 if (len < 0)
12716 len = 0;
12717 else if (n + len > slen)
12718 len = slen - n;
12719
12720 rettv->v_type = VAR_STRING;
12721 rettv->vval.v_string = vim_strnsave(p + n, len);
12722}
12723
12724/*
12725 * "strridx()" function
12726 */
12727 static void
12728f_strridx(typval_T *argvars, typval_T *rettv)
12729{
12730 char_u buf[NUMBUFLEN];
12731 char_u *needle;
12732 char_u *haystack;
12733 char_u *rest;
12734 char_u *lastmatch = NULL;
12735 int haystack_len, end_idx;
12736
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012737 needle = tv_get_string_chk(&argvars[1]);
12738 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012739
12740 rettv->vval.v_number = -1;
12741 if (needle == NULL || haystack == NULL)
12742 return; /* type error; errmsg already given */
12743
12744 haystack_len = (int)STRLEN(haystack);
12745 if (argvars[2].v_type != VAR_UNKNOWN)
12746 {
12747 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012748 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012749 if (end_idx < 0)
12750 return; /* can never find a match */
12751 }
12752 else
12753 end_idx = haystack_len;
12754
12755 if (*needle == NUL)
12756 {
12757 /* Empty string matches past the end. */
12758 lastmatch = haystack + end_idx;
12759 }
12760 else
12761 {
12762 for (rest = haystack; *rest != '\0'; ++rest)
12763 {
12764 rest = (char_u *)strstr((char *)rest, (char *)needle);
12765 if (rest == NULL || rest > haystack + end_idx)
12766 break;
12767 lastmatch = rest;
12768 }
12769 }
12770
12771 if (lastmatch == NULL)
12772 rettv->vval.v_number = -1;
12773 else
12774 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12775}
12776
12777/*
12778 * "strtrans()" function
12779 */
12780 static void
12781f_strtrans(typval_T *argvars, typval_T *rettv)
12782{
12783 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012784 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012785}
12786
12787/*
12788 * "submatch()" function
12789 */
12790 static void
12791f_submatch(typval_T *argvars, typval_T *rettv)
12792{
12793 int error = FALSE;
12794 int no;
12795 int retList = 0;
12796
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012797 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012798 if (error)
12799 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012800 if (no < 0 || no >= NSUBEXP)
12801 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012802 EMSGN(_("E935: invalid submatch number: %d"), no);
12803 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012804 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012805 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012806 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012807 if (error)
12808 return;
12809
12810 if (retList == 0)
12811 {
12812 rettv->v_type = VAR_STRING;
12813 rettv->vval.v_string = reg_submatch(no);
12814 }
12815 else
12816 {
12817 rettv->v_type = VAR_LIST;
12818 rettv->vval.v_list = reg_submatch_list(no);
12819 }
12820}
12821
12822/*
12823 * "substitute()" function
12824 */
12825 static void
12826f_substitute(typval_T *argvars, typval_T *rettv)
12827{
12828 char_u patbuf[NUMBUFLEN];
12829 char_u subbuf[NUMBUFLEN];
12830 char_u flagsbuf[NUMBUFLEN];
12831
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012832 char_u *str = tv_get_string_chk(&argvars[0]);
12833 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012834 char_u *sub = NULL;
12835 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012836 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012837
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012838 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12839 expr = &argvars[2];
12840 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012841 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012842
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012843 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012844 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12845 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012846 rettv->vval.v_string = NULL;
12847 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012848 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012849}
12850
12851/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012852 * "swapinfo(swap_filename)" function
12853 */
12854 static void
12855f_swapinfo(typval_T *argvars, typval_T *rettv)
12856{
12857 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012858 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012859}
12860
12861/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020012862 * "swapname(expr)" function
12863 */
12864 static void
12865f_swapname(typval_T *argvars, typval_T *rettv)
12866{
12867 buf_T *buf;
12868
12869 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010012870 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020012871 if (buf == NULL || buf->b_ml.ml_mfp == NULL
12872 || buf->b_ml.ml_mfp->mf_fname == NULL)
12873 rettv->vval.v_string = NULL;
12874 else
12875 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
12876}
12877
12878/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012879 * "synID(lnum, col, trans)" function
12880 */
12881 static void
12882f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12883{
12884 int id = 0;
12885#ifdef FEAT_SYN_HL
12886 linenr_T lnum;
12887 colnr_T col;
12888 int trans;
12889 int transerr = FALSE;
12890
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012891 lnum = tv_get_lnum(argvars); /* -1 on type error */
12892 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
12893 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012894
12895 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12896 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12897 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12898#endif
12899
12900 rettv->vval.v_number = id;
12901}
12902
12903/*
12904 * "synIDattr(id, what [, mode])" function
12905 */
12906 static void
12907f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12908{
12909 char_u *p = NULL;
12910#ifdef FEAT_SYN_HL
12911 int id;
12912 char_u *what;
12913 char_u *mode;
12914 char_u modebuf[NUMBUFLEN];
12915 int modec;
12916
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012917 id = (int)tv_get_number(&argvars[0]);
12918 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012919 if (argvars[2].v_type != VAR_UNKNOWN)
12920 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012921 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012922 modec = TOLOWER_ASC(mode[0]);
12923 if (modec != 't' && modec != 'c' && modec != 'g')
12924 modec = 0; /* replace invalid with current */
12925 }
12926 else
12927 {
12928#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12929 if (USE_24BIT)
12930 modec = 'g';
12931 else
12932#endif
12933 if (t_colors > 1)
12934 modec = 'c';
12935 else
12936 modec = 't';
12937 }
12938
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012939 switch (TOLOWER_ASC(what[0]))
12940 {
12941 case 'b':
12942 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12943 p = highlight_color(id, what, modec);
12944 else /* bold */
12945 p = highlight_has_attr(id, HL_BOLD, modec);
12946 break;
12947
12948 case 'f': /* fg[#] or font */
12949 p = highlight_color(id, what, modec);
12950 break;
12951
12952 case 'i':
12953 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12954 p = highlight_has_attr(id, HL_INVERSE, modec);
12955 else /* italic */
12956 p = highlight_has_attr(id, HL_ITALIC, modec);
12957 break;
12958
12959 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012960 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012961 break;
12962
12963 case 'r': /* reverse */
12964 p = highlight_has_attr(id, HL_INVERSE, modec);
12965 break;
12966
12967 case 's':
12968 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12969 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012970 /* strikeout */
12971 else if (TOLOWER_ASC(what[1]) == 't' &&
12972 TOLOWER_ASC(what[2]) == 'r')
12973 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012974 else /* standout */
12975 p = highlight_has_attr(id, HL_STANDOUT, modec);
12976 break;
12977
12978 case 'u':
12979 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12980 /* underline */
12981 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12982 else
12983 /* undercurl */
12984 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12985 break;
12986 }
12987
12988 if (p != NULL)
12989 p = vim_strsave(p);
12990#endif
12991 rettv->v_type = VAR_STRING;
12992 rettv->vval.v_string = p;
12993}
12994
12995/*
12996 * "synIDtrans(id)" function
12997 */
12998 static void
12999f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13000{
13001 int id;
13002
13003#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013004 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013005
13006 if (id > 0)
13007 id = syn_get_final_id(id);
13008 else
13009#endif
13010 id = 0;
13011
13012 rettv->vval.v_number = id;
13013}
13014
13015/*
13016 * "synconcealed(lnum, col)" function
13017 */
13018 static void
13019f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13020{
13021#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13022 linenr_T lnum;
13023 colnr_T col;
13024 int syntax_flags = 0;
13025 int cchar;
13026 int matchid = 0;
13027 char_u str[NUMBUFLEN];
13028#endif
13029
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013030 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013031
13032#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013033 lnum = tv_get_lnum(argvars); /* -1 on type error */
13034 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013035
13036 vim_memset(str, NUL, sizeof(str));
13037
13038 if (rettv_list_alloc(rettv) != FAIL)
13039 {
13040 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13041 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13042 && curwin->w_p_cole > 0)
13043 {
13044 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13045 syntax_flags = get_syntax_info(&matchid);
13046
13047 /* get the conceal character */
13048 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13049 {
13050 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013051 if (cchar == NUL && curwin->w_p_cole == 1)
13052 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013053 if (cchar != NUL)
13054 {
13055# ifdef FEAT_MBYTE
13056 if (has_mbyte)
13057 (*mb_char2bytes)(cchar, str);
13058 else
13059# endif
13060 str[0] = cchar;
13061 }
13062 }
13063 }
13064
13065 list_append_number(rettv->vval.v_list,
13066 (syntax_flags & HL_CONCEAL) != 0);
13067 /* -1 to auto-determine strlen */
13068 list_append_string(rettv->vval.v_list, str, -1);
13069 list_append_number(rettv->vval.v_list, matchid);
13070 }
13071#endif
13072}
13073
13074/*
13075 * "synstack(lnum, col)" function
13076 */
13077 static void
13078f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13079{
13080#ifdef FEAT_SYN_HL
13081 linenr_T lnum;
13082 colnr_T col;
13083 int i;
13084 int id;
13085#endif
13086
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013087 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013088
13089#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013090 lnum = tv_get_lnum(argvars); /* -1 on type error */
13091 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013092
13093 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13094 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13095 && rettv_list_alloc(rettv) != FAIL)
13096 {
13097 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13098 for (i = 0; ; ++i)
13099 {
13100 id = syn_get_stack_item(i);
13101 if (id < 0)
13102 break;
13103 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13104 break;
13105 }
13106 }
13107#endif
13108}
13109
13110 static void
13111get_cmd_output_as_rettv(
13112 typval_T *argvars,
13113 typval_T *rettv,
13114 int retlist)
13115{
13116 char_u *res = NULL;
13117 char_u *p;
13118 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013119 int err = FALSE;
13120 FILE *fd;
13121 list_T *list = NULL;
13122 int flags = SHELL_SILENT;
13123
13124 rettv->v_type = VAR_STRING;
13125 rettv->vval.v_string = NULL;
13126 if (check_restricted() || check_secure())
13127 goto errret;
13128
13129 if (argvars[1].v_type != VAR_UNKNOWN)
13130 {
13131 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013132 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013133 * command.
13134 */
13135 if ((infile = vim_tempname('i', TRUE)) == NULL)
13136 {
13137 EMSG(_(e_notmp));
13138 goto errret;
13139 }
13140
13141 fd = mch_fopen((char *)infile, WRITEBIN);
13142 if (fd == NULL)
13143 {
13144 EMSG2(_(e_notopen), infile);
13145 goto errret;
13146 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013147 if (argvars[1].v_type == VAR_NUMBER)
13148 {
13149 linenr_T lnum;
13150 buf_T *buf;
13151
13152 buf = buflist_findnr(argvars[1].vval.v_number);
13153 if (buf == NULL)
13154 {
13155 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013156 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013157 goto errret;
13158 }
13159
13160 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13161 {
13162 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13163 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13164 {
13165 err = TRUE;
13166 break;
13167 }
13168 if (putc(NL, fd) == EOF)
13169 {
13170 err = TRUE;
13171 break;
13172 }
13173 }
13174 }
13175 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013176 {
13177 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13178 err = TRUE;
13179 }
13180 else
13181 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013182 size_t len;
13183 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013184
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013185 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013186 if (p == NULL)
13187 {
13188 fclose(fd);
13189 goto errret; /* type error; errmsg already given */
13190 }
13191 len = STRLEN(p);
13192 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13193 err = TRUE;
13194 }
13195 if (fclose(fd) != 0)
13196 err = TRUE;
13197 if (err)
13198 {
13199 EMSG(_("E677: Error writing temp file"));
13200 goto errret;
13201 }
13202 }
13203
13204 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13205 * echoes typeahead, that messes up the display. */
13206 if (!msg_silent)
13207 flags += SHELL_COOKED;
13208
13209 if (retlist)
13210 {
13211 int len;
13212 listitem_T *li;
13213 char_u *s = NULL;
13214 char_u *start;
13215 char_u *end;
13216 int i;
13217
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013218 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013219 if (res == NULL)
13220 goto errret;
13221
13222 list = list_alloc();
13223 if (list == NULL)
13224 goto errret;
13225
13226 for (i = 0; i < len; ++i)
13227 {
13228 start = res + i;
13229 while (i < len && res[i] != NL)
13230 ++i;
13231 end = res + i;
13232
13233 s = alloc((unsigned)(end - start + 1));
13234 if (s == NULL)
13235 goto errret;
13236
13237 for (p = s; start < end; ++p, ++start)
13238 *p = *start == NUL ? NL : *start;
13239 *p = NUL;
13240
13241 li = listitem_alloc();
13242 if (li == NULL)
13243 {
13244 vim_free(s);
13245 goto errret;
13246 }
13247 li->li_tv.v_type = VAR_STRING;
13248 li->li_tv.v_lock = 0;
13249 li->li_tv.vval.v_string = s;
13250 list_append(list, li);
13251 }
13252
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013253 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013254 list = NULL;
13255 }
13256 else
13257 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013258 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013259#ifdef USE_CR
13260 /* translate <CR> into <NL> */
13261 if (res != NULL)
13262 {
13263 char_u *s;
13264
13265 for (s = res; *s; ++s)
13266 {
13267 if (*s == CAR)
13268 *s = NL;
13269 }
13270 }
13271#else
13272# ifdef USE_CRNL
13273 /* translate <CR><NL> into <NL> */
13274 if (res != NULL)
13275 {
13276 char_u *s, *d;
13277
13278 d = res;
13279 for (s = res; *s; ++s)
13280 {
13281 if (s[0] == CAR && s[1] == NL)
13282 ++s;
13283 *d++ = *s;
13284 }
13285 *d = NUL;
13286 }
13287# endif
13288#endif
13289 rettv->vval.v_string = res;
13290 res = NULL;
13291 }
13292
13293errret:
13294 if (infile != NULL)
13295 {
13296 mch_remove(infile);
13297 vim_free(infile);
13298 }
13299 if (res != NULL)
13300 vim_free(res);
13301 if (list != NULL)
13302 list_free(list);
13303}
13304
13305/*
13306 * "system()" function
13307 */
13308 static void
13309f_system(typval_T *argvars, typval_T *rettv)
13310{
13311 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13312}
13313
13314/*
13315 * "systemlist()" function
13316 */
13317 static void
13318f_systemlist(typval_T *argvars, typval_T *rettv)
13319{
13320 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13321}
13322
13323/*
13324 * "tabpagebuflist()" function
13325 */
13326 static void
13327f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13328{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013329 tabpage_T *tp;
13330 win_T *wp = NULL;
13331
13332 if (argvars[0].v_type == VAR_UNKNOWN)
13333 wp = firstwin;
13334 else
13335 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013336 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013337 if (tp != NULL)
13338 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13339 }
13340 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13341 {
13342 for (; wp != NULL; wp = wp->w_next)
13343 if (list_append_number(rettv->vval.v_list,
13344 wp->w_buffer->b_fnum) == FAIL)
13345 break;
13346 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013347}
13348
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013349/*
13350 * "tabpagenr()" function
13351 */
13352 static void
13353f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13354{
13355 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013356 char_u *arg;
13357
13358 if (argvars[0].v_type != VAR_UNKNOWN)
13359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013360 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013361 nr = 0;
13362 if (arg != NULL)
13363 {
13364 if (STRCMP(arg, "$") == 0)
13365 nr = tabpage_index(NULL) - 1;
13366 else
13367 EMSG2(_(e_invexpr2), arg);
13368 }
13369 }
13370 else
13371 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013372 rettv->vval.v_number = nr;
13373}
13374
13375
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013376/*
13377 * Common code for tabpagewinnr() and winnr().
13378 */
13379 static int
13380get_winnr(tabpage_T *tp, typval_T *argvar)
13381{
13382 win_T *twin;
13383 int nr = 1;
13384 win_T *wp;
13385 char_u *arg;
13386
13387 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13388 if (argvar->v_type != VAR_UNKNOWN)
13389 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013390 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013391 if (arg == NULL)
13392 nr = 0; /* type error; errmsg already given */
13393 else if (STRCMP(arg, "$") == 0)
13394 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13395 else if (STRCMP(arg, "#") == 0)
13396 {
13397 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13398 if (twin == NULL)
13399 nr = 0;
13400 }
13401 else
13402 {
13403 EMSG2(_(e_invexpr2), arg);
13404 nr = 0;
13405 }
13406 }
13407
13408 if (nr > 0)
13409 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13410 wp != twin; wp = wp->w_next)
13411 {
13412 if (wp == NULL)
13413 {
13414 /* didn't find it in this tabpage */
13415 nr = 0;
13416 break;
13417 }
13418 ++nr;
13419 }
13420 return nr;
13421}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013422
13423/*
13424 * "tabpagewinnr()" function
13425 */
13426 static void
13427f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13428{
13429 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013430 tabpage_T *tp;
13431
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013432 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013433 if (tp == NULL)
13434 nr = 0;
13435 else
13436 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013437 rettv->vval.v_number = nr;
13438}
13439
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013440/*
13441 * "tagfiles()" function
13442 */
13443 static void
13444f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13445{
13446 char_u *fname;
13447 tagname_T tn;
13448 int first;
13449
13450 if (rettv_list_alloc(rettv) == FAIL)
13451 return;
13452 fname = alloc(MAXPATHL);
13453 if (fname == NULL)
13454 return;
13455
13456 for (first = TRUE; ; first = FALSE)
13457 if (get_tagfname(&tn, first, fname) == FAIL
13458 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13459 break;
13460 tagname_free(&tn);
13461 vim_free(fname);
13462}
13463
13464/*
13465 * "taglist()" function
13466 */
13467 static void
13468f_taglist(typval_T *argvars, typval_T *rettv)
13469{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013470 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013471 char_u *tag_pattern;
13472
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013473 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013474
13475 rettv->vval.v_number = FALSE;
13476 if (*tag_pattern == NUL)
13477 return;
13478
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013479 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013480 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013481 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013482 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013483}
13484
13485/*
13486 * "tempname()" function
13487 */
13488 static void
13489f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13490{
13491 static int x = 'A';
13492
13493 rettv->v_type = VAR_STRING;
13494 rettv->vval.v_string = vim_tempname(x, FALSE);
13495
13496 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13497 * names. Skip 'I' and 'O', they are used for shell redirection. */
13498 do
13499 {
13500 if (x == 'Z')
13501 x = '0';
13502 else if (x == '9')
13503 x = 'A';
13504 else
13505 {
13506#ifdef EBCDIC
13507 if (x == 'I')
13508 x = 'J';
13509 else if (x == 'R')
13510 x = 'S';
13511 else
13512#endif
13513 ++x;
13514 }
13515 } while (x == 'I' || x == 'O');
13516}
13517
13518#ifdef FEAT_FLOAT
13519/*
13520 * "tan()" function
13521 */
13522 static void
13523f_tan(typval_T *argvars, typval_T *rettv)
13524{
13525 float_T f = 0.0;
13526
13527 rettv->v_type = VAR_FLOAT;
13528 if (get_float_arg(argvars, &f) == OK)
13529 rettv->vval.v_float = tan(f);
13530 else
13531 rettv->vval.v_float = 0.0;
13532}
13533
13534/*
13535 * "tanh()" function
13536 */
13537 static void
13538f_tanh(typval_T *argvars, typval_T *rettv)
13539{
13540 float_T f = 0.0;
13541
13542 rettv->v_type = VAR_FLOAT;
13543 if (get_float_arg(argvars, &f) == OK)
13544 rettv->vval.v_float = tanh(f);
13545 else
13546 rettv->vval.v_float = 0.0;
13547}
13548#endif
13549
13550/*
13551 * "test_alloc_fail(id, countdown, repeat)" function
13552 */
13553 static void
13554f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13555{
13556 if (argvars[0].v_type != VAR_NUMBER
13557 || argvars[0].vval.v_number <= 0
13558 || argvars[1].v_type != VAR_NUMBER
13559 || argvars[1].vval.v_number < 0
13560 || argvars[2].v_type != VAR_NUMBER)
13561 EMSG(_(e_invarg));
13562 else
13563 {
13564 alloc_fail_id = argvars[0].vval.v_number;
13565 if (alloc_fail_id >= aid_last)
13566 EMSG(_(e_invarg));
13567 alloc_fail_countdown = argvars[1].vval.v_number;
13568 alloc_fail_repeat = argvars[2].vval.v_number;
13569 did_outofmem_msg = FALSE;
13570 }
13571}
13572
13573/*
13574 * "test_autochdir()"
13575 */
13576 static void
13577f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13578{
13579#if defined(FEAT_AUTOCHDIR)
13580 test_autochdir = TRUE;
13581#endif
13582}
13583
13584/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013585 * "test_feedinput()"
13586 */
13587 static void
13588f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13589{
13590#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013591 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013592
13593 if (val != NULL)
13594 {
13595 trash_input_buf();
13596 add_to_input_buf_csi(val, (int)STRLEN(val));
13597 }
13598#endif
13599}
13600
13601/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013602 * "test_option_not_set({name})" function
13603 */
13604 static void
13605f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13606{
13607 char_u *name = (char_u *)"";
13608
13609 if (argvars[0].v_type != VAR_STRING)
13610 EMSG(_(e_invarg));
13611 else
13612 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013613 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013614 if (reset_option_was_set(name) == FAIL)
13615 EMSG2(_(e_invarg2), name);
13616 }
13617}
13618
13619/*
13620 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013621 */
13622 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013623f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013624{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013625 char_u *name = (char_u *)"";
13626 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013627 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013628
13629 if (argvars[0].v_type != VAR_STRING
13630 || (argvars[1].v_type) != VAR_NUMBER)
13631 EMSG(_(e_invarg));
13632 else
13633 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013634 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013635 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013636
13637 if (STRCMP(name, (char_u *)"redraw") == 0)
13638 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013639 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13640 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013641 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13642 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013643 else if (STRCMP(name, (char_u *)"starting") == 0)
13644 {
13645 if (val)
13646 {
13647 if (save_starting < 0)
13648 save_starting = starting;
13649 starting = 0;
13650 }
13651 else
13652 {
13653 starting = save_starting;
13654 save_starting = -1;
13655 }
13656 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013657 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13658 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013659 else if (STRCMP(name, (char_u *)"ALL") == 0)
13660 {
13661 disable_char_avail_for_testing = FALSE;
13662 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013663 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013664 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013665 if (save_starting >= 0)
13666 {
13667 starting = save_starting;
13668 save_starting = -1;
13669 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013670 }
13671 else
13672 EMSG2(_(e_invarg2), name);
13673 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013674}
13675
13676/*
13677 * "test_garbagecollect_now()" function
13678 */
13679 static void
13680f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13681{
13682 /* This is dangerous, any Lists and Dicts used internally may be freed
13683 * while still in use. */
13684 garbage_collect(TRUE);
13685}
13686
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013687/*
13688 * "test_ignore_error()" function
13689 */
13690 static void
13691f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13692{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013693 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013694}
13695
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013696#ifdef FEAT_JOB_CHANNEL
13697 static void
13698f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13699{
13700 rettv->v_type = VAR_CHANNEL;
13701 rettv->vval.v_channel = NULL;
13702}
13703#endif
13704
13705 static void
13706f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13707{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013708 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013709}
13710
13711#ifdef FEAT_JOB_CHANNEL
13712 static void
13713f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13714{
13715 rettv->v_type = VAR_JOB;
13716 rettv->vval.v_job = NULL;
13717}
13718#endif
13719
13720 static void
13721f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13722{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013723 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013724}
13725
13726 static void
13727f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13728{
13729 rettv->v_type = VAR_PARTIAL;
13730 rettv->vval.v_partial = NULL;
13731}
13732
13733 static void
13734f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13735{
13736 rettv->v_type = VAR_STRING;
13737 rettv->vval.v_string = NULL;
13738}
13739
Bram Moolenaarab186732018-09-14 21:27:06 +020013740#ifdef FEAT_GUI
13741 static void
13742f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13743{
13744 char_u *which;
13745 long value;
13746 int dragging;
13747 scrollbar_T *sb = NULL;
13748
13749 if (argvars[0].v_type != VAR_STRING
13750 || (argvars[1].v_type) != VAR_NUMBER
13751 || (argvars[2].v_type) != VAR_NUMBER)
13752 {
13753 EMSG(_(e_invarg));
13754 return;
13755 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013756 which = tv_get_string(&argvars[0]);
13757 value = tv_get_number(&argvars[1]);
13758 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020013759
13760 if (STRCMP(which, "left") == 0)
13761 sb = &curwin->w_scrollbars[SBAR_LEFT];
13762 else if (STRCMP(which, "right") == 0)
13763 sb = &curwin->w_scrollbars[SBAR_RIGHT];
13764 else if (STRCMP(which, "hor") == 0)
13765 sb = &gui.bottom_sbar;
13766 if (sb == NULL)
13767 {
13768 EMSG2(_(e_invarg2), which);
13769 return;
13770 }
13771 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020013772# ifndef USE_ON_FLY_SCROLL
13773 // need to loop through normal_cmd() to handle the scroll events
13774 exec_normal(FALSE, TRUE, FALSE);
13775# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020013776}
13777#endif
13778
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013779 static void
13780f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13781{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013782 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013783}
13784
13785#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13786/*
13787 * Get a callback from "arg". It can be a Funcref or a function name.
13788 * When "arg" is zero return an empty string.
13789 * Return NULL for an invalid argument.
13790 */
13791 char_u *
13792get_callback(typval_T *arg, partial_T **pp)
13793{
13794 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13795 {
13796 *pp = arg->vval.v_partial;
13797 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013798 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013799 }
13800 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013801 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013802 {
13803 func_ref(arg->vval.v_string);
13804 return arg->vval.v_string;
13805 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013806 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13807 return (char_u *)"";
13808 EMSG(_("E921: Invalid callback argument"));
13809 return NULL;
13810}
13811
13812/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013813 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013814 */
13815 void
13816free_callback(char_u *callback, partial_T *partial)
13817{
13818 if (partial != NULL)
13819 partial_unref(partial);
13820 else if (callback != NULL)
13821 {
13822 func_unref(callback);
13823 vim_free(callback);
13824 }
13825}
13826#endif
13827
13828#ifdef FEAT_TIMERS
13829/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013830 * "timer_info([timer])" function
13831 */
13832 static void
13833f_timer_info(typval_T *argvars, typval_T *rettv)
13834{
13835 timer_T *timer = NULL;
13836
13837 if (rettv_list_alloc(rettv) != OK)
13838 return;
13839 if (argvars[0].v_type != VAR_UNKNOWN)
13840 {
13841 if (argvars[0].v_type != VAR_NUMBER)
13842 EMSG(_(e_number_exp));
13843 else
13844 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013845 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013846 if (timer != NULL)
13847 add_timer_info(rettv, timer);
13848 }
13849 }
13850 else
13851 add_timer_info_all(rettv);
13852}
13853
13854/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013855 * "timer_pause(timer, paused)" function
13856 */
13857 static void
13858f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13859{
13860 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013861 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013862
13863 if (argvars[0].v_type != VAR_NUMBER)
13864 EMSG(_(e_number_exp));
13865 else
13866 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013867 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013868 if (timer != NULL)
13869 timer->tr_paused = paused;
13870 }
13871}
13872
13873/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013874 * "timer_start(time, callback [, options])" function
13875 */
13876 static void
13877f_timer_start(typval_T *argvars, typval_T *rettv)
13878{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013879 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020013880 timer_T *timer;
13881 int repeat = 0;
13882 char_u *callback;
13883 dict_T *dict;
13884 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013885
Bram Moolenaar75537a92016-09-05 22:45:28 +020013886 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013887 if (check_secure())
13888 return;
13889 if (argvars[2].v_type != VAR_UNKNOWN)
13890 {
13891 if (argvars[2].v_type != VAR_DICT
13892 || (dict = argvars[2].vval.v_dict) == NULL)
13893 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013894 EMSG2(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013895 return;
13896 }
13897 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013898 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013899 }
13900
Bram Moolenaar75537a92016-09-05 22:45:28 +020013901 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013902 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013903 return;
13904
13905 timer = create_timer(msec, repeat);
13906 if (timer == NULL)
13907 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013908 else
13909 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013910 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013911 timer->tr_callback = vim_strsave(callback);
13912 else
13913 /* pointer into the partial */
13914 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013915 timer->tr_partial = partial;
13916 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013917 }
13918}
13919
13920/*
13921 * "timer_stop(timer)" function
13922 */
13923 static void
13924f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13925{
13926 timer_T *timer;
13927
13928 if (argvars[0].v_type != VAR_NUMBER)
13929 {
13930 EMSG(_(e_number_exp));
13931 return;
13932 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013933 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013934 if (timer != NULL)
13935 stop_timer(timer);
13936}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013937
13938/*
13939 * "timer_stopall()" function
13940 */
13941 static void
13942f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13943{
13944 stop_all_timers();
13945}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013946#endif
13947
13948/*
13949 * "tolower(string)" function
13950 */
13951 static void
13952f_tolower(typval_T *argvars, typval_T *rettv)
13953{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013954 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013955 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013956}
13957
13958/*
13959 * "toupper(string)" function
13960 */
13961 static void
13962f_toupper(typval_T *argvars, typval_T *rettv)
13963{
13964 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013965 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013966}
13967
13968/*
13969 * "tr(string, fromstr, tostr)" function
13970 */
13971 static void
13972f_tr(typval_T *argvars, typval_T *rettv)
13973{
13974 char_u *in_str;
13975 char_u *fromstr;
13976 char_u *tostr;
13977 char_u *p;
13978#ifdef FEAT_MBYTE
13979 int inlen;
13980 int fromlen;
13981 int tolen;
13982 int idx;
13983 char_u *cpstr;
13984 int cplen;
13985 int first = TRUE;
13986#endif
13987 char_u buf[NUMBUFLEN];
13988 char_u buf2[NUMBUFLEN];
13989 garray_T ga;
13990
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013991 in_str = tv_get_string(&argvars[0]);
13992 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
13993 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013994
13995 /* Default return value: empty string. */
13996 rettv->v_type = VAR_STRING;
13997 rettv->vval.v_string = NULL;
13998 if (fromstr == NULL || tostr == NULL)
13999 return; /* type error; errmsg already given */
14000 ga_init2(&ga, (int)sizeof(char), 80);
14001
14002#ifdef FEAT_MBYTE
14003 if (!has_mbyte)
14004#endif
14005 /* not multi-byte: fromstr and tostr must be the same length */
14006 if (STRLEN(fromstr) != STRLEN(tostr))
14007 {
14008#ifdef FEAT_MBYTE
14009error:
14010#endif
14011 EMSG2(_(e_invarg2), fromstr);
14012 ga_clear(&ga);
14013 return;
14014 }
14015
14016 /* fromstr and tostr have to contain the same number of chars */
14017 while (*in_str != NUL)
14018 {
14019#ifdef FEAT_MBYTE
14020 if (has_mbyte)
14021 {
14022 inlen = (*mb_ptr2len)(in_str);
14023 cpstr = in_str;
14024 cplen = inlen;
14025 idx = 0;
14026 for (p = fromstr; *p != NUL; p += fromlen)
14027 {
14028 fromlen = (*mb_ptr2len)(p);
14029 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14030 {
14031 for (p = tostr; *p != NUL; p += tolen)
14032 {
14033 tolen = (*mb_ptr2len)(p);
14034 if (idx-- == 0)
14035 {
14036 cplen = tolen;
14037 cpstr = p;
14038 break;
14039 }
14040 }
14041 if (*p == NUL) /* tostr is shorter than fromstr */
14042 goto error;
14043 break;
14044 }
14045 ++idx;
14046 }
14047
14048 if (first && cpstr == in_str)
14049 {
14050 /* Check that fromstr and tostr have the same number of
14051 * (multi-byte) characters. Done only once when a character
14052 * of in_str doesn't appear in fromstr. */
14053 first = FALSE;
14054 for (p = tostr; *p != NUL; p += tolen)
14055 {
14056 tolen = (*mb_ptr2len)(p);
14057 --idx;
14058 }
14059 if (idx != 0)
14060 goto error;
14061 }
14062
14063 (void)ga_grow(&ga, cplen);
14064 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14065 ga.ga_len += cplen;
14066
14067 in_str += inlen;
14068 }
14069 else
14070#endif
14071 {
14072 /* When not using multi-byte chars we can do it faster. */
14073 p = vim_strchr(fromstr, *in_str);
14074 if (p != NULL)
14075 ga_append(&ga, tostr[p - fromstr]);
14076 else
14077 ga_append(&ga, *in_str);
14078 ++in_str;
14079 }
14080 }
14081
14082 /* add a terminating NUL */
14083 (void)ga_grow(&ga, 1);
14084 ga_append(&ga, NUL);
14085
14086 rettv->vval.v_string = ga.ga_data;
14087}
14088
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014089/*
14090 * "trim({expr})" function
14091 */
14092 static void
14093f_trim(typval_T *argvars, typval_T *rettv)
14094{
14095 char_u buf1[NUMBUFLEN];
14096 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014097 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014098 char_u *mask = NULL;
14099 char_u *tail;
14100 char_u *prev;
14101 char_u *p;
14102 int c1;
14103
14104 rettv->v_type = VAR_STRING;
14105 if (head == NULL)
14106 {
14107 rettv->vval.v_string = NULL;
14108 return;
14109 }
14110
14111 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014112 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014113
14114 while (*head != NUL)
14115 {
14116 c1 = PTR2CHAR(head);
14117 if (mask == NULL)
14118 {
14119 if (c1 > ' ' && c1 != 0xa0)
14120 break;
14121 }
14122 else
14123 {
14124 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14125 if (c1 == PTR2CHAR(p))
14126 break;
14127 if (*p == NUL)
14128 break;
14129 }
14130 MB_PTR_ADV(head);
14131 }
14132
14133 for (tail = head + STRLEN(head); tail > head; tail = prev)
14134 {
14135 prev = tail;
14136 MB_PTR_BACK(head, prev);
14137 c1 = PTR2CHAR(prev);
14138 if (mask == NULL)
14139 {
14140 if (c1 > ' ' && c1 != 0xa0)
14141 break;
14142 }
14143 else
14144 {
14145 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14146 if (c1 == PTR2CHAR(p))
14147 break;
14148 if (*p == NUL)
14149 break;
14150 }
14151 }
14152 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14153}
14154
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014155#ifdef FEAT_FLOAT
14156/*
14157 * "trunc({float})" function
14158 */
14159 static void
14160f_trunc(typval_T *argvars, typval_T *rettv)
14161{
14162 float_T f = 0.0;
14163
14164 rettv->v_type = VAR_FLOAT;
14165 if (get_float_arg(argvars, &f) == OK)
14166 /* trunc() is not in C90, use floor() or ceil() instead. */
14167 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14168 else
14169 rettv->vval.v_float = 0.0;
14170}
14171#endif
14172
14173/*
14174 * "type(expr)" function
14175 */
14176 static void
14177f_type(typval_T *argvars, typval_T *rettv)
14178{
14179 int n = -1;
14180
14181 switch (argvars[0].v_type)
14182 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014183 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14184 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014185 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014186 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14187 case VAR_LIST: n = VAR_TYPE_LIST; break;
14188 case VAR_DICT: n = VAR_TYPE_DICT; break;
14189 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014190 case VAR_SPECIAL:
14191 if (argvars[0].vval.v_number == VVAL_FALSE
14192 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014193 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014194 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014195 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014196 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014197 case VAR_JOB: n = VAR_TYPE_JOB; break;
14198 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014199 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014200 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014201 n = -1;
14202 break;
14203 }
14204 rettv->vval.v_number = n;
14205}
14206
14207/*
14208 * "undofile(name)" function
14209 */
14210 static void
14211f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14212{
14213 rettv->v_type = VAR_STRING;
14214#ifdef FEAT_PERSISTENT_UNDO
14215 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014216 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014217
14218 if (*fname == NUL)
14219 {
14220 /* If there is no file name there will be no undo file. */
14221 rettv->vval.v_string = NULL;
14222 }
14223 else
14224 {
14225 char_u *ffname = FullName_save(fname, FALSE);
14226
14227 if (ffname != NULL)
14228 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14229 vim_free(ffname);
14230 }
14231 }
14232#else
14233 rettv->vval.v_string = NULL;
14234#endif
14235}
14236
14237/*
14238 * "undotree()" function
14239 */
14240 static void
14241f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14242{
14243 if (rettv_dict_alloc(rettv) == OK)
14244 {
14245 dict_T *dict = rettv->vval.v_dict;
14246 list_T *list;
14247
Bram Moolenaare0be1672018-07-08 16:50:37 +020014248 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14249 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14250 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14251 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14252 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14253 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014254
14255 list = list_alloc();
14256 if (list != NULL)
14257 {
14258 u_eval_tree(curbuf->b_u_oldhead, list);
14259 dict_add_list(dict, "entries", list);
14260 }
14261 }
14262}
14263
14264/*
14265 * "values(dict)" function
14266 */
14267 static void
14268f_values(typval_T *argvars, typval_T *rettv)
14269{
14270 dict_list(argvars, rettv, 1);
14271}
14272
14273/*
14274 * "virtcol(string)" function
14275 */
14276 static void
14277f_virtcol(typval_T *argvars, typval_T *rettv)
14278{
14279 colnr_T vcol = 0;
14280 pos_T *fp;
14281 int fnum = curbuf->b_fnum;
14282
14283 fp = var2fpos(&argvars[0], FALSE, &fnum);
14284 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14285 && fnum == curbuf->b_fnum)
14286 {
14287 getvvcol(curwin, fp, NULL, NULL, &vcol);
14288 ++vcol;
14289 }
14290
14291 rettv->vval.v_number = vcol;
14292}
14293
14294/*
14295 * "visualmode()" function
14296 */
14297 static void
14298f_visualmode(typval_T *argvars, typval_T *rettv)
14299{
14300 char_u str[2];
14301
14302 rettv->v_type = VAR_STRING;
14303 str[0] = curbuf->b_visual_mode_eval;
14304 str[1] = NUL;
14305 rettv->vval.v_string = vim_strsave(str);
14306
14307 /* A non-zero number or non-empty string argument: reset mode. */
14308 if (non_zero_arg(&argvars[0]))
14309 curbuf->b_visual_mode_eval = NUL;
14310}
14311
14312/*
14313 * "wildmenumode()" function
14314 */
14315 static void
14316f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14317{
14318#ifdef FEAT_WILDMENU
14319 if (wild_menu_showing)
14320 rettv->vval.v_number = 1;
14321#endif
14322}
14323
14324/*
14325 * "winbufnr(nr)" function
14326 */
14327 static void
14328f_winbufnr(typval_T *argvars, typval_T *rettv)
14329{
14330 win_T *wp;
14331
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014332 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014333 if (wp == NULL)
14334 rettv->vval.v_number = -1;
14335 else
14336 rettv->vval.v_number = wp->w_buffer->b_fnum;
14337}
14338
14339/*
14340 * "wincol()" function
14341 */
14342 static void
14343f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14344{
14345 validate_cursor();
14346 rettv->vval.v_number = curwin->w_wcol + 1;
14347}
14348
14349/*
14350 * "winheight(nr)" function
14351 */
14352 static void
14353f_winheight(typval_T *argvars, typval_T *rettv)
14354{
14355 win_T *wp;
14356
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014357 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014358 if (wp == NULL)
14359 rettv->vval.v_number = -1;
14360 else
14361 rettv->vval.v_number = wp->w_height;
14362}
14363
14364/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014365 * "winlayout()" function
14366 */
14367 static void
14368f_winlayout(typval_T *argvars, typval_T *rettv)
14369{
14370 tabpage_T *tp;
14371
14372 if (rettv_list_alloc(rettv) != OK)
14373 return;
14374
14375 if (argvars[0].v_type == VAR_UNKNOWN)
14376 tp = curtab;
14377 else
14378 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014379 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014380 if (tp == NULL)
14381 return;
14382 }
14383
14384 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14385}
14386
14387/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014388 * "winline()" function
14389 */
14390 static void
14391f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14392{
14393 validate_cursor();
14394 rettv->vval.v_number = curwin->w_wrow + 1;
14395}
14396
14397/*
14398 * "winnr()" function
14399 */
14400 static void
14401f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14402{
14403 int nr = 1;
14404
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014405 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014406 rettv->vval.v_number = nr;
14407}
14408
14409/*
14410 * "winrestcmd()" function
14411 */
14412 static void
14413f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14414{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014415 win_T *wp;
14416 int winnr = 1;
14417 garray_T ga;
14418 char_u buf[50];
14419
14420 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014421 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014422 {
14423 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14424 ga_concat(&ga, buf);
14425 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14426 ga_concat(&ga, buf);
14427 ++winnr;
14428 }
14429 ga_append(&ga, NUL);
14430
14431 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014432 rettv->v_type = VAR_STRING;
14433}
14434
14435/*
14436 * "winrestview()" function
14437 */
14438 static void
14439f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14440{
14441 dict_T *dict;
14442
14443 if (argvars[0].v_type != VAR_DICT
14444 || (dict = argvars[0].vval.v_dict) == NULL)
14445 EMSG(_(e_invarg));
14446 else
14447 {
14448 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014449 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014450 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014451 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014452#ifdef FEAT_VIRTUALEDIT
14453 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014454 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014455#endif
14456 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14457 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014458 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014459 curwin->w_set_curswant = FALSE;
14460 }
14461
14462 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014463 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014464#ifdef FEAT_DIFF
14465 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014466 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014467#endif
14468 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014469 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014470 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014471 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014472
14473 check_cursor();
14474 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014475 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014476 changed_window_setting();
14477
14478 if (curwin->w_topline <= 0)
14479 curwin->w_topline = 1;
14480 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14481 curwin->w_topline = curbuf->b_ml.ml_line_count;
14482#ifdef FEAT_DIFF
14483 check_topfill(curwin, TRUE);
14484#endif
14485 }
14486}
14487
14488/*
14489 * "winsaveview()" function
14490 */
14491 static void
14492f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14493{
14494 dict_T *dict;
14495
14496 if (rettv_dict_alloc(rettv) == FAIL)
14497 return;
14498 dict = rettv->vval.v_dict;
14499
Bram Moolenaare0be1672018-07-08 16:50:37 +020014500 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14501 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014502#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020014503 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014504#endif
14505 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014506 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014507
Bram Moolenaare0be1672018-07-08 16:50:37 +020014508 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014509#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014510 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014511#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014512 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14513 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014514}
14515
14516/*
14517 * "winwidth(nr)" function
14518 */
14519 static void
14520f_winwidth(typval_T *argvars, typval_T *rettv)
14521{
14522 win_T *wp;
14523
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014524 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014525 if (wp == NULL)
14526 rettv->vval.v_number = -1;
14527 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014528 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014529}
14530
14531/*
14532 * "wordcount()" function
14533 */
14534 static void
14535f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14536{
14537 if (rettv_dict_alloc(rettv) == FAIL)
14538 return;
14539 cursor_pos_info(rettv->vval.v_dict);
14540}
14541
14542/*
14543 * "writefile()" function
14544 */
14545 static void
14546f_writefile(typval_T *argvars, typval_T *rettv)
14547{
14548 int binary = FALSE;
14549 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014550#ifdef HAVE_FSYNC
14551 int do_fsync = p_fs;
14552#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014553 char_u *fname;
14554 FILE *fd;
14555 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014556 listitem_T *li;
14557 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014558
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014559 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014560 if (check_restricted() || check_secure())
14561 return;
14562
14563 if (argvars[0].v_type != VAR_LIST)
14564 {
14565 EMSG2(_(e_listarg), "writefile()");
14566 return;
14567 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014568 list = argvars[0].vval.v_list;
14569 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014570 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014571 for (li = list->lv_first; li != NULL; li = li->li_next)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014572 if (tv_get_string_chk(&li->li_tv) == NULL)
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014573 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014574
14575 if (argvars[2].v_type != VAR_UNKNOWN)
14576 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014577 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014578
14579 if (arg2 == NULL)
14580 return;
14581 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014582 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014583 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014584 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014585#ifdef HAVE_FSYNC
14586 if (vim_strchr(arg2, 's') != NULL)
14587 do_fsync = TRUE;
14588 else if (vim_strchr(arg2, 'S') != NULL)
14589 do_fsync = FALSE;
14590#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014591 }
14592
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014593 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014594 if (fname == NULL)
14595 return;
14596
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014597 /* Always open the file in binary mode, library functions have a mind of
14598 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014599 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14600 append ? APPENDBIN : WRITEBIN)) == NULL)
14601 {
14602 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14603 ret = -1;
14604 }
14605 else
14606 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014607 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014608 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014609#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014610 else if (do_fsync)
14611 /* Ignore the error, the user wouldn't know what to do about it.
14612 * May happen for a device. */
Bram Moolenaar42335f52018-09-13 15:33:43 +020014613 vim_ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014614#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014615 fclose(fd);
14616 }
14617
14618 rettv->vval.v_number = ret;
14619}
14620
14621/*
14622 * "xor(expr, expr)" function
14623 */
14624 static void
14625f_xor(typval_T *argvars, typval_T *rettv)
14626{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014627 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14628 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014629}
14630
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014631#endif /* FEAT_EVAL */