blob: 3c6421206102a474582b3f0f3688c5a0bbeea2ab [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");
32#ifdef FEAT_QUICKFIX
33static char *e_stringreq = N_("E928: String required");
34#endif
35
36#ifdef FEAT_FLOAT
37static void f_abs(typval_T *argvars, typval_T *rettv);
38static void f_acos(typval_T *argvars, typval_T *rettv);
39#endif
40static void f_add(typval_T *argvars, typval_T *rettv);
41static void f_and(typval_T *argvars, typval_T *rettv);
42static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020043static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_argc(typval_T *argvars, typval_T *rettv);
45static void f_argidx(typval_T *argvars, typval_T *rettv);
46static void f_arglistid(typval_T *argvars, typval_T *rettv);
47static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010048static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010050static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_assert_exception(typval_T *argvars, typval_T *rettv);
52static void f_assert_fails(typval_T *argvars, typval_T *rettv);
53static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020054static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_assert_match(typval_T *argvars, typval_T *rettv);
56static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
57static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010058static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020059static void f_assert_true(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_asin(typval_T *argvars, typval_T *rettv);
62static void f_atan(typval_T *argvars, typval_T *rettv);
63static void f_atan2(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010065#ifdef FEAT_BEVAL
66static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010067# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010068static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010069# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010070#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020071static void f_browse(typval_T *argvars, typval_T *rettv);
72static void f_browsedir(typval_T *argvars, typval_T *rettv);
73static void f_bufexists(typval_T *argvars, typval_T *rettv);
74static void f_buflisted(typval_T *argvars, typval_T *rettv);
75static void f_bufloaded(typval_T *argvars, typval_T *rettv);
76static void f_bufname(typval_T *argvars, typval_T *rettv);
77static void f_bufnr(typval_T *argvars, typval_T *rettv);
78static void f_bufwinid(typval_T *argvars, typval_T *rettv);
79static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
80static void f_byte2line(typval_T *argvars, typval_T *rettv);
81static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
82static void f_byteidx(typval_T *argvars, typval_T *rettv);
83static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
84static void f_call(typval_T *argvars, typval_T *rettv);
85#ifdef FEAT_FLOAT
86static void f_ceil(typval_T *argvars, typval_T *rettv);
87#endif
88#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010089static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020090static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020091static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
93static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
94static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
95static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
96static void f_ch_info(typval_T *argvars, typval_T *rettv);
97static void f_ch_log(typval_T *argvars, typval_T *rettv);
98static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
99static void f_ch_open(typval_T *argvars, typval_T *rettv);
100static void f_ch_read(typval_T *argvars, typval_T *rettv);
101static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
102static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
103static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
104static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
105static void f_ch_status(typval_T *argvars, typval_T *rettv);
106#endif
107static void f_changenr(typval_T *argvars, typval_T *rettv);
108static void f_char2nr(typval_T *argvars, typval_T *rettv);
109static void f_cindent(typval_T *argvars, typval_T *rettv);
110static void f_clearmatches(typval_T *argvars, typval_T *rettv);
111static void f_col(typval_T *argvars, typval_T *rettv);
112#if defined(FEAT_INS_EXPAND)
113static void f_complete(typval_T *argvars, typval_T *rettv);
114static void f_complete_add(typval_T *argvars, typval_T *rettv);
115static void f_complete_check(typval_T *argvars, typval_T *rettv);
116#endif
117static void f_confirm(typval_T *argvars, typval_T *rettv);
118static void f_copy(typval_T *argvars, typval_T *rettv);
119#ifdef FEAT_FLOAT
120static void f_cos(typval_T *argvars, typval_T *rettv);
121static void f_cosh(typval_T *argvars, typval_T *rettv);
122#endif
123static void f_count(typval_T *argvars, typval_T *rettv);
124static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
125static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200126#ifdef WIN3264
127static void f_debugbreak(typval_T *argvars, typval_T *rettv);
128#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_deepcopy(typval_T *argvars, typval_T *rettv);
130static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200131static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_did_filetype(typval_T *argvars, typval_T *rettv);
133static void f_diff_filler(typval_T *argvars, typval_T *rettv);
134static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
135static void f_empty(typval_T *argvars, typval_T *rettv);
136static void f_escape(typval_T *argvars, typval_T *rettv);
137static void f_eval(typval_T *argvars, typval_T *rettv);
138static void f_eventhandler(typval_T *argvars, typval_T *rettv);
139static void f_executable(typval_T *argvars, typval_T *rettv);
140static void f_execute(typval_T *argvars, typval_T *rettv);
141static void f_exepath(typval_T *argvars, typval_T *rettv);
142static void f_exists(typval_T *argvars, typval_T *rettv);
143#ifdef FEAT_FLOAT
144static void f_exp(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_expand(typval_T *argvars, typval_T *rettv);
147static void f_extend(typval_T *argvars, typval_T *rettv);
148static void f_feedkeys(typval_T *argvars, typval_T *rettv);
149static void f_filereadable(typval_T *argvars, typval_T *rettv);
150static void f_filewritable(typval_T *argvars, typval_T *rettv);
151static void f_filter(typval_T *argvars, typval_T *rettv);
152static void f_finddir(typval_T *argvars, typval_T *rettv);
153static void f_findfile(typval_T *argvars, typval_T *rettv);
154#ifdef FEAT_FLOAT
155static void f_float2nr(typval_T *argvars, typval_T *rettv);
156static void f_floor(typval_T *argvars, typval_T *rettv);
157static void f_fmod(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_fnameescape(typval_T *argvars, typval_T *rettv);
160static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
161static void f_foldclosed(typval_T *argvars, typval_T *rettv);
162static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
163static void f_foldlevel(typval_T *argvars, typval_T *rettv);
164static void f_foldtext(typval_T *argvars, typval_T *rettv);
165static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
166static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200167static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_function(typval_T *argvars, typval_T *rettv);
169static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
170static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200171static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_getbufline(typval_T *argvars, typval_T *rettv);
173static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100174static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_getchar(typval_T *argvars, typval_T *rettv);
176static void f_getcharmod(typval_T *argvars, typval_T *rettv);
177static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
178static void f_getcmdline(typval_T *argvars, typval_T *rettv);
179#if defined(FEAT_CMDL_COMPL)
180static void f_getcompletion(typval_T *argvars, typval_T *rettv);
181#endif
182static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
183static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
184static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
185static void f_getcwd(typval_T *argvars, typval_T *rettv);
186static void f_getfontname(typval_T *argvars, typval_T *rettv);
187static void f_getfperm(typval_T *argvars, typval_T *rettv);
188static void f_getfsize(typval_T *argvars, typval_T *rettv);
189static void f_getftime(typval_T *argvars, typval_T *rettv);
190static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100191static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200193static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getmatches(typval_T *argvars, typval_T *rettv);
195static void f_getpid(typval_T *argvars, typval_T *rettv);
196static void f_getcurpos(typval_T *argvars, typval_T *rettv);
197static void f_getpos(typval_T *argvars, typval_T *rettv);
198static void f_getqflist(typval_T *argvars, typval_T *rettv);
199static void f_getreg(typval_T *argvars, typval_T *rettv);
200static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200201static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_gettabvar(typval_T *argvars, typval_T *rettv);
203static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200204static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100205static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200206static void f_getwinposx(typval_T *argvars, typval_T *rettv);
207static void f_getwinposy(typval_T *argvars, typval_T *rettv);
208static void f_getwinvar(typval_T *argvars, typval_T *rettv);
209static void f_glob(typval_T *argvars, typval_T *rettv);
210static void f_globpath(typval_T *argvars, typval_T *rettv);
211static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
212static void f_has(typval_T *argvars, typval_T *rettv);
213static void f_has_key(typval_T *argvars, typval_T *rettv);
214static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
215static void f_hasmapto(typval_T *argvars, typval_T *rettv);
216static void f_histadd(typval_T *argvars, typval_T *rettv);
217static void f_histdel(typval_T *argvars, typval_T *rettv);
218static void f_histget(typval_T *argvars, typval_T *rettv);
219static void f_histnr(typval_T *argvars, typval_T *rettv);
220static void f_hlID(typval_T *argvars, typval_T *rettv);
221static void f_hlexists(typval_T *argvars, typval_T *rettv);
222static void f_hostname(typval_T *argvars, typval_T *rettv);
223static void f_iconv(typval_T *argvars, typval_T *rettv);
224static void f_indent(typval_T *argvars, typval_T *rettv);
225static void f_index(typval_T *argvars, typval_T *rettv);
226static void f_input(typval_T *argvars, typval_T *rettv);
227static void f_inputdialog(typval_T *argvars, typval_T *rettv);
228static void f_inputlist(typval_T *argvars, typval_T *rettv);
229static void f_inputrestore(typval_T *argvars, typval_T *rettv);
230static void f_inputsave(typval_T *argvars, typval_T *rettv);
231static void f_inputsecret(typval_T *argvars, typval_T *rettv);
232static void f_insert(typval_T *argvars, typval_T *rettv);
233static void f_invert(typval_T *argvars, typval_T *rettv);
234static void f_isdirectory(typval_T *argvars, typval_T *rettv);
235static void f_islocked(typval_T *argvars, typval_T *rettv);
236#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
237static void f_isnan(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_items(typval_T *argvars, typval_T *rettv);
240#ifdef FEAT_JOB_CHANNEL
241static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
242static void f_job_info(typval_T *argvars, typval_T *rettv);
243static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
244static void f_job_start(typval_T *argvars, typval_T *rettv);
245static void f_job_stop(typval_T *argvars, typval_T *rettv);
246static void f_job_status(typval_T *argvars, typval_T *rettv);
247#endif
248static void f_join(typval_T *argvars, typval_T *rettv);
249static void f_js_decode(typval_T *argvars, typval_T *rettv);
250static void f_js_encode(typval_T *argvars, typval_T *rettv);
251static void f_json_decode(typval_T *argvars, typval_T *rettv);
252static void f_json_encode(typval_T *argvars, typval_T *rettv);
253static void f_keys(typval_T *argvars, typval_T *rettv);
254static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
255static void f_len(typval_T *argvars, typval_T *rettv);
256static void f_libcall(typval_T *argvars, typval_T *rettv);
257static void f_libcallnr(typval_T *argvars, typval_T *rettv);
258static void f_line(typval_T *argvars, typval_T *rettv);
259static void f_line2byte(typval_T *argvars, typval_T *rettv);
260static void f_lispindent(typval_T *argvars, typval_T *rettv);
261static void f_localtime(typval_T *argvars, typval_T *rettv);
262#ifdef FEAT_FLOAT
263static void f_log(typval_T *argvars, typval_T *rettv);
264static void f_log10(typval_T *argvars, typval_T *rettv);
265#endif
266#ifdef FEAT_LUA
267static void f_luaeval(typval_T *argvars, typval_T *rettv);
268#endif
269static void f_map(typval_T *argvars, typval_T *rettv);
270static void f_maparg(typval_T *argvars, typval_T *rettv);
271static void f_mapcheck(typval_T *argvars, typval_T *rettv);
272static void f_match(typval_T *argvars, typval_T *rettv);
273static void f_matchadd(typval_T *argvars, typval_T *rettv);
274static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
275static void f_matcharg(typval_T *argvars, typval_T *rettv);
276static void f_matchdelete(typval_T *argvars, typval_T *rettv);
277static void f_matchend(typval_T *argvars, typval_T *rettv);
278static void f_matchlist(typval_T *argvars, typval_T *rettv);
279static void f_matchstr(typval_T *argvars, typval_T *rettv);
280static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
281static void f_max(typval_T *argvars, typval_T *rettv);
282static void f_min(typval_T *argvars, typval_T *rettv);
283#ifdef vim_mkdir
284static void f_mkdir(typval_T *argvars, typval_T *rettv);
285#endif
286static void f_mode(typval_T *argvars, typval_T *rettv);
287#ifdef FEAT_MZSCHEME
288static void f_mzeval(typval_T *argvars, typval_T *rettv);
289#endif
290static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
291static void f_nr2char(typval_T *argvars, typval_T *rettv);
292static void f_or(typval_T *argvars, typval_T *rettv);
293static void f_pathshorten(typval_T *argvars, typval_T *rettv);
294#ifdef FEAT_PERL
295static void f_perleval(typval_T *argvars, typval_T *rettv);
296#endif
297#ifdef FEAT_FLOAT
298static void f_pow(typval_T *argvars, typval_T *rettv);
299#endif
300static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
301static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200302#ifdef FEAT_JOB_CHANNEL
303static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200304static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200305static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
306#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200307static void f_pumvisible(typval_T *argvars, typval_T *rettv);
308#ifdef FEAT_PYTHON3
309static void f_py3eval(typval_T *argvars, typval_T *rettv);
310#endif
311#ifdef FEAT_PYTHON
312static void f_pyeval(typval_T *argvars, typval_T *rettv);
313#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100314#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
315static void f_pyxeval(typval_T *argvars, typval_T *rettv);
316#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317static void f_range(typval_T *argvars, typval_T *rettv);
318static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200319static void f_reg_executing(typval_T *argvars, typval_T *rettv);
320static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200321static void f_reltime(typval_T *argvars, typval_T *rettv);
322#ifdef FEAT_FLOAT
323static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
324#endif
325static void f_reltimestr(typval_T *argvars, typval_T *rettv);
326static void f_remote_expr(typval_T *argvars, typval_T *rettv);
327static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
328static void f_remote_peek(typval_T *argvars, typval_T *rettv);
329static void f_remote_read(typval_T *argvars, typval_T *rettv);
330static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100331static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200332static void f_remove(typval_T *argvars, typval_T *rettv);
333static void f_rename(typval_T *argvars, typval_T *rettv);
334static void f_repeat(typval_T *argvars, typval_T *rettv);
335static void f_resolve(typval_T *argvars, typval_T *rettv);
336static void f_reverse(typval_T *argvars, typval_T *rettv);
337#ifdef FEAT_FLOAT
338static void f_round(typval_T *argvars, typval_T *rettv);
339#endif
340static void f_screenattr(typval_T *argvars, typval_T *rettv);
341static void f_screenchar(typval_T *argvars, typval_T *rettv);
342static void f_screencol(typval_T *argvars, typval_T *rettv);
343static void f_screenrow(typval_T *argvars, typval_T *rettv);
344static void f_search(typval_T *argvars, typval_T *rettv);
345static void f_searchdecl(typval_T *argvars, typval_T *rettv);
346static void f_searchpair(typval_T *argvars, typval_T *rettv);
347static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
348static void f_searchpos(typval_T *argvars, typval_T *rettv);
349static void f_server2client(typval_T *argvars, typval_T *rettv);
350static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200351static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352static void f_setbufvar(typval_T *argvars, typval_T *rettv);
353static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
354static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
355static void f_setfperm(typval_T *argvars, typval_T *rettv);
356static void f_setline(typval_T *argvars, typval_T *rettv);
357static void f_setloclist(typval_T *argvars, typval_T *rettv);
358static void f_setmatches(typval_T *argvars, typval_T *rettv);
359static void f_setpos(typval_T *argvars, typval_T *rettv);
360static void f_setqflist(typval_T *argvars, typval_T *rettv);
361static void f_setreg(typval_T *argvars, typval_T *rettv);
362static void f_settabvar(typval_T *argvars, typval_T *rettv);
363static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
364static 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);
370static void f_simplify(typval_T *argvars, typval_T *rettv);
371#ifdef FEAT_FLOAT
372static void f_sin(typval_T *argvars, typval_T *rettv);
373static void f_sinh(typval_T *argvars, typval_T *rettv);
374#endif
375static void f_sort(typval_T *argvars, typval_T *rettv);
376static void f_soundfold(typval_T *argvars, typval_T *rettv);
377static void f_spellbadword(typval_T *argvars, typval_T *rettv);
378static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
379static void f_split(typval_T *argvars, typval_T *rettv);
380#ifdef FEAT_FLOAT
381static void f_sqrt(typval_T *argvars, typval_T *rettv);
382static void f_str2float(typval_T *argvars, typval_T *rettv);
383#endif
384static void f_str2nr(typval_T *argvars, typval_T *rettv);
385static void f_strchars(typval_T *argvars, typval_T *rettv);
386#ifdef HAVE_STRFTIME
387static void f_strftime(typval_T *argvars, typval_T *rettv);
388#endif
389static void f_strgetchar(typval_T *argvars, typval_T *rettv);
390static void f_stridx(typval_T *argvars, typval_T *rettv);
391static void f_string(typval_T *argvars, typval_T *rettv);
392static void f_strlen(typval_T *argvars, typval_T *rettv);
393static void f_strcharpart(typval_T *argvars, typval_T *rettv);
394static void f_strpart(typval_T *argvars, typval_T *rettv);
395static void f_strridx(typval_T *argvars, typval_T *rettv);
396static void f_strtrans(typval_T *argvars, typval_T *rettv);
397static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
398static void f_strwidth(typval_T *argvars, typval_T *rettv);
399static void f_submatch(typval_T *argvars, typval_T *rettv);
400static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200401static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200402static void f_synID(typval_T *argvars, typval_T *rettv);
403static void f_synIDattr(typval_T *argvars, typval_T *rettv);
404static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
405static void f_synstack(typval_T *argvars, typval_T *rettv);
406static void f_synconcealed(typval_T *argvars, typval_T *rettv);
407static void f_system(typval_T *argvars, typval_T *rettv);
408static void f_systemlist(typval_T *argvars, typval_T *rettv);
409static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
410static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
411static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
412static void f_taglist(typval_T *argvars, typval_T *rettv);
413static void f_tagfiles(typval_T *argvars, typval_T *rettv);
414static void f_tempname(typval_T *argvars, typval_T *rettv);
415static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
416static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200417static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100418static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100420static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421#ifdef FEAT_JOB_CHANNEL
422static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
423#endif
424static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
425#ifdef FEAT_JOB_CHANNEL
426static void f_test_null_job(typval_T *argvars, typval_T *rettv);
427#endif
428static void f_test_null_list(typval_T *argvars, typval_T *rettv);
429static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
430static void f_test_null_string(typval_T *argvars, typval_T *rettv);
431static void f_test_settime(typval_T *argvars, typval_T *rettv);
432#ifdef FEAT_FLOAT
433static void f_tan(typval_T *argvars, typval_T *rettv);
434static void f_tanh(typval_T *argvars, typval_T *rettv);
435#endif
436#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200437static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200438static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439static void f_timer_start(typval_T *argvars, typval_T *rettv);
440static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200441static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442#endif
443static void f_tolower(typval_T *argvars, typval_T *rettv);
444static void f_toupper(typval_T *argvars, typval_T *rettv);
445static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100446static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447#ifdef FEAT_FLOAT
448static void f_trunc(typval_T *argvars, typval_T *rettv);
449#endif
450static void f_type(typval_T *argvars, typval_T *rettv);
451static void f_undofile(typval_T *argvars, typval_T *rettv);
452static void f_undotree(typval_T *argvars, typval_T *rettv);
453static void f_uniq(typval_T *argvars, typval_T *rettv);
454static void f_values(typval_T *argvars, typval_T *rettv);
455static void f_virtcol(typval_T *argvars, typval_T *rettv);
456static void f_visualmode(typval_T *argvars, typval_T *rettv);
457static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
458static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
459static void f_win_getid(typval_T *argvars, typval_T *rettv);
460static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
461static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
462static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100463static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200464static void f_winbufnr(typval_T *argvars, typval_T *rettv);
465static void f_wincol(typval_T *argvars, typval_T *rettv);
466static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200467static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200468static void f_winline(typval_T *argvars, typval_T *rettv);
469static void f_winnr(typval_T *argvars, typval_T *rettv);
470static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
471static void f_winrestview(typval_T *argvars, typval_T *rettv);
472static void f_winsaveview(typval_T *argvars, typval_T *rettv);
473static void f_winwidth(typval_T *argvars, typval_T *rettv);
474static void f_writefile(typval_T *argvars, typval_T *rettv);
475static void f_wordcount(typval_T *argvars, typval_T *rettv);
476static void f_xor(typval_T *argvars, typval_T *rettv);
477
478/*
479 * Array with names and number of arguments of all internal functions
480 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
481 */
482static struct fst
483{
484 char *f_name; /* function name */
485 char f_min_argc; /* minimal number of arguments */
486 char f_max_argc; /* maximal number of arguments */
487 void (*f_func)(typval_T *args, typval_T *rvar);
488 /* implementation of function */
489} functions[] =
490{
491#ifdef FEAT_FLOAT
492 {"abs", 1, 1, f_abs},
493 {"acos", 1, 1, f_acos}, /* WJMc */
494#endif
495 {"add", 2, 2, f_add},
496 {"and", 2, 2, f_and},
497 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200498 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200499 {"argc", 0, 0, f_argc},
500 {"argidx", 0, 0, f_argidx},
501 {"arglistid", 0, 2, f_arglistid},
502 {"argv", 0, 1, f_argv},
503#ifdef FEAT_FLOAT
504 {"asin", 1, 1, f_asin}, /* WJMc */
505#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100506 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200507 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100508 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509 {"assert_exception", 1, 2, f_assert_exception},
510 {"assert_fails", 1, 2, f_assert_fails},
511 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100512 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513 {"assert_match", 2, 3, f_assert_match},
514 {"assert_notequal", 2, 3, f_assert_notequal},
515 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100516 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517 {"assert_true", 1, 2, f_assert_true},
518#ifdef FEAT_FLOAT
519 {"atan", 1, 1, f_atan},
520 {"atan2", 2, 2, f_atan2},
521#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100522#ifdef FEAT_BEVAL
523 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100524# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100525 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100526# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100527#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528 {"browse", 4, 4, f_browse},
529 {"browsedir", 2, 2, f_browsedir},
530 {"bufexists", 1, 1, f_bufexists},
531 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
532 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
533 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
534 {"buflisted", 1, 1, f_buflisted},
535 {"bufloaded", 1, 1, f_bufloaded},
536 {"bufname", 1, 1, f_bufname},
537 {"bufnr", 1, 2, f_bufnr},
538 {"bufwinid", 1, 1, f_bufwinid},
539 {"bufwinnr", 1, 1, f_bufwinnr},
540 {"byte2line", 1, 1, f_byte2line},
541 {"byteidx", 2, 2, f_byteidx},
542 {"byteidxcomp", 2, 2, f_byteidxcomp},
543 {"call", 2, 3, f_call},
544#ifdef FEAT_FLOAT
545 {"ceil", 1, 1, f_ceil},
546#endif
547#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100548 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200549 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200550 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200551 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
552 {"ch_evalraw", 2, 3, f_ch_evalraw},
553 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
554 {"ch_getjob", 1, 1, f_ch_getjob},
555 {"ch_info", 1, 1, f_ch_info},
556 {"ch_log", 1, 2, f_ch_log},
557 {"ch_logfile", 1, 2, f_ch_logfile},
558 {"ch_open", 1, 2, f_ch_open},
559 {"ch_read", 1, 2, f_ch_read},
560 {"ch_readraw", 1, 2, f_ch_readraw},
561 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
562 {"ch_sendraw", 2, 3, f_ch_sendraw},
563 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200564 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200565#endif
566 {"changenr", 0, 0, f_changenr},
567 {"char2nr", 1, 2, f_char2nr},
568 {"cindent", 1, 1, f_cindent},
569 {"clearmatches", 0, 0, f_clearmatches},
570 {"col", 1, 1, f_col},
571#if defined(FEAT_INS_EXPAND)
572 {"complete", 2, 2, f_complete},
573 {"complete_add", 1, 1, f_complete_add},
574 {"complete_check", 0, 0, f_complete_check},
575#endif
576 {"confirm", 1, 4, f_confirm},
577 {"copy", 1, 1, f_copy},
578#ifdef FEAT_FLOAT
579 {"cos", 1, 1, f_cos},
580 {"cosh", 1, 1, f_cosh},
581#endif
582 {"count", 2, 4, f_count},
583 {"cscope_connection",0,3, f_cscope_connection},
584 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200585#ifdef WIN3264
586 {"debugbreak", 1, 1, f_debugbreak},
587#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588 {"deepcopy", 1, 2, f_deepcopy},
589 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200590 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200591 {"did_filetype", 0, 0, f_did_filetype},
592 {"diff_filler", 1, 1, f_diff_filler},
593 {"diff_hlID", 2, 2, f_diff_hlID},
594 {"empty", 1, 1, f_empty},
595 {"escape", 2, 2, f_escape},
596 {"eval", 1, 1, f_eval},
597 {"eventhandler", 0, 0, f_eventhandler},
598 {"executable", 1, 1, f_executable},
599 {"execute", 1, 2, f_execute},
600 {"exepath", 1, 1, f_exepath},
601 {"exists", 1, 1, f_exists},
602#ifdef FEAT_FLOAT
603 {"exp", 1, 1, f_exp},
604#endif
605 {"expand", 1, 3, f_expand},
606 {"extend", 2, 3, f_extend},
607 {"feedkeys", 1, 2, f_feedkeys},
608 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
609 {"filereadable", 1, 1, f_filereadable},
610 {"filewritable", 1, 1, f_filewritable},
611 {"filter", 2, 2, f_filter},
612 {"finddir", 1, 3, f_finddir},
613 {"findfile", 1, 3, f_findfile},
614#ifdef FEAT_FLOAT
615 {"float2nr", 1, 1, f_float2nr},
616 {"floor", 1, 1, f_floor},
617 {"fmod", 2, 2, f_fmod},
618#endif
619 {"fnameescape", 1, 1, f_fnameescape},
620 {"fnamemodify", 2, 2, f_fnamemodify},
621 {"foldclosed", 1, 1, f_foldclosed},
622 {"foldclosedend", 1, 1, f_foldclosedend},
623 {"foldlevel", 1, 1, f_foldlevel},
624 {"foldtext", 0, 0, f_foldtext},
625 {"foldtextresult", 1, 1, f_foldtextresult},
626 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200627 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200628 {"function", 1, 3, f_function},
629 {"garbagecollect", 0, 1, f_garbagecollect},
630 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200631 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632 {"getbufline", 2, 3, f_getbufline},
633 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100634 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635 {"getchar", 0, 1, f_getchar},
636 {"getcharmod", 0, 0, f_getcharmod},
637 {"getcharsearch", 0, 0, f_getcharsearch},
638 {"getcmdline", 0, 0, f_getcmdline},
639 {"getcmdpos", 0, 0, f_getcmdpos},
640 {"getcmdtype", 0, 0, f_getcmdtype},
641 {"getcmdwintype", 0, 0, f_getcmdwintype},
642#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200643 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644#endif
645 {"getcurpos", 0, 0, f_getcurpos},
646 {"getcwd", 0, 2, f_getcwd},
647 {"getfontname", 0, 1, f_getfontname},
648 {"getfperm", 1, 1, f_getfperm},
649 {"getfsize", 1, 1, f_getfsize},
650 {"getftime", 1, 1, f_getftime},
651 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100652 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200654 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655 {"getmatches", 0, 0, f_getmatches},
656 {"getpid", 0, 0, f_getpid},
657 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200658 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200659 {"getreg", 0, 3, f_getreg},
660 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200661 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662 {"gettabvar", 2, 3, f_gettabvar},
663 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200664 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100665 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666 {"getwinposx", 0, 0, f_getwinposx},
667 {"getwinposy", 0, 0, f_getwinposy},
668 {"getwinvar", 2, 3, f_getwinvar},
669 {"glob", 1, 4, f_glob},
670 {"glob2regpat", 1, 1, f_glob2regpat},
671 {"globpath", 2, 5, f_globpath},
672 {"has", 1, 1, f_has},
673 {"has_key", 2, 2, f_has_key},
674 {"haslocaldir", 0, 2, f_haslocaldir},
675 {"hasmapto", 1, 3, f_hasmapto},
676 {"highlightID", 1, 1, f_hlID}, /* obsolete */
677 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
678 {"histadd", 2, 2, f_histadd},
679 {"histdel", 1, 2, f_histdel},
680 {"histget", 1, 2, f_histget},
681 {"histnr", 1, 1, f_histnr},
682 {"hlID", 1, 1, f_hlID},
683 {"hlexists", 1, 1, f_hlexists},
684 {"hostname", 0, 0, f_hostname},
685 {"iconv", 3, 3, f_iconv},
686 {"indent", 1, 1, f_indent},
687 {"index", 2, 4, f_index},
688 {"input", 1, 3, f_input},
689 {"inputdialog", 1, 3, f_inputdialog},
690 {"inputlist", 1, 1, f_inputlist},
691 {"inputrestore", 0, 0, f_inputrestore},
692 {"inputsave", 0, 0, f_inputsave},
693 {"inputsecret", 1, 2, f_inputsecret},
694 {"insert", 2, 3, f_insert},
695 {"invert", 1, 1, f_invert},
696 {"isdirectory", 1, 1, f_isdirectory},
697 {"islocked", 1, 1, f_islocked},
698#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
699 {"isnan", 1, 1, f_isnan},
700#endif
701 {"items", 1, 1, f_items},
702#ifdef FEAT_JOB_CHANNEL
703 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200704 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200705 {"job_setoptions", 2, 2, f_job_setoptions},
706 {"job_start", 1, 2, f_job_start},
707 {"job_status", 1, 1, f_job_status},
708 {"job_stop", 1, 2, f_job_stop},
709#endif
710 {"join", 1, 2, f_join},
711 {"js_decode", 1, 1, f_js_decode},
712 {"js_encode", 1, 1, f_js_encode},
713 {"json_decode", 1, 1, f_json_decode},
714 {"json_encode", 1, 1, f_json_encode},
715 {"keys", 1, 1, f_keys},
716 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
717 {"len", 1, 1, f_len},
718 {"libcall", 3, 3, f_libcall},
719 {"libcallnr", 3, 3, f_libcallnr},
720 {"line", 1, 1, f_line},
721 {"line2byte", 1, 1, f_line2byte},
722 {"lispindent", 1, 1, f_lispindent},
723 {"localtime", 0, 0, f_localtime},
724#ifdef FEAT_FLOAT
725 {"log", 1, 1, f_log},
726 {"log10", 1, 1, f_log10},
727#endif
728#ifdef FEAT_LUA
729 {"luaeval", 1, 2, f_luaeval},
730#endif
731 {"map", 2, 2, f_map},
732 {"maparg", 1, 4, f_maparg},
733 {"mapcheck", 1, 3, f_mapcheck},
734 {"match", 2, 4, f_match},
735 {"matchadd", 2, 5, f_matchadd},
736 {"matchaddpos", 2, 5, f_matchaddpos},
737 {"matcharg", 1, 1, f_matcharg},
738 {"matchdelete", 1, 1, f_matchdelete},
739 {"matchend", 2, 4, f_matchend},
740 {"matchlist", 2, 4, f_matchlist},
741 {"matchstr", 2, 4, f_matchstr},
742 {"matchstrpos", 2, 4, f_matchstrpos},
743 {"max", 1, 1, f_max},
744 {"min", 1, 1, f_min},
745#ifdef vim_mkdir
746 {"mkdir", 1, 3, f_mkdir},
747#endif
748 {"mode", 0, 1, f_mode},
749#ifdef FEAT_MZSCHEME
750 {"mzeval", 1, 1, f_mzeval},
751#endif
752 {"nextnonblank", 1, 1, f_nextnonblank},
753 {"nr2char", 1, 2, f_nr2char},
754 {"or", 2, 2, f_or},
755 {"pathshorten", 1, 1, f_pathshorten},
756#ifdef FEAT_PERL
757 {"perleval", 1, 1, f_perleval},
758#endif
759#ifdef FEAT_FLOAT
760 {"pow", 2, 2, f_pow},
761#endif
762 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100763 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200764#ifdef FEAT_JOB_CHANNEL
765 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200766 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200767 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
768#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200769 {"pumvisible", 0, 0, f_pumvisible},
770#ifdef FEAT_PYTHON3
771 {"py3eval", 1, 1, f_py3eval},
772#endif
773#ifdef FEAT_PYTHON
774 {"pyeval", 1, 1, f_pyeval},
775#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100776#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
777 {"pyxeval", 1, 1, f_pyxeval},
778#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779 {"range", 1, 3, f_range},
780 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200781 {"reg_executing", 0, 0, f_reg_executing},
782 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783 {"reltime", 0, 2, f_reltime},
784#ifdef FEAT_FLOAT
785 {"reltimefloat", 1, 1, f_reltimefloat},
786#endif
787 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100788 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200789 {"remote_foreground", 1, 1, f_remote_foreground},
790 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100791 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200792 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100793 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794 {"remove", 2, 3, f_remove},
795 {"rename", 2, 2, f_rename},
796 {"repeat", 2, 2, f_repeat},
797 {"resolve", 1, 1, f_resolve},
798 {"reverse", 1, 1, f_reverse},
799#ifdef FEAT_FLOAT
800 {"round", 1, 1, f_round},
801#endif
802 {"screenattr", 2, 2, f_screenattr},
803 {"screenchar", 2, 2, f_screenchar},
804 {"screencol", 0, 0, f_screencol},
805 {"screenrow", 0, 0, f_screenrow},
806 {"search", 1, 4, f_search},
807 {"searchdecl", 1, 3, f_searchdecl},
808 {"searchpair", 3, 7, f_searchpair},
809 {"searchpairpos", 3, 7, f_searchpairpos},
810 {"searchpos", 1, 4, f_searchpos},
811 {"server2client", 2, 2, f_server2client},
812 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200813 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814 {"setbufvar", 3, 3, f_setbufvar},
815 {"setcharsearch", 1, 1, f_setcharsearch},
816 {"setcmdpos", 1, 1, f_setcmdpos},
817 {"setfperm", 2, 2, f_setfperm},
818 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200819 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820 {"setmatches", 1, 1, f_setmatches},
821 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200822 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823 {"setreg", 2, 3, f_setreg},
824 {"settabvar", 3, 3, f_settabvar},
825 {"settabwinvar", 4, 4, f_settabwinvar},
826 {"setwinvar", 3, 3, f_setwinvar},
827#ifdef FEAT_CRYPT
828 {"sha256", 1, 1, f_sha256},
829#endif
830 {"shellescape", 1, 2, f_shellescape},
831 {"shiftwidth", 0, 0, f_shiftwidth},
832 {"simplify", 1, 1, f_simplify},
833#ifdef FEAT_FLOAT
834 {"sin", 1, 1, f_sin},
835 {"sinh", 1, 1, f_sinh},
836#endif
837 {"sort", 1, 3, f_sort},
838 {"soundfold", 1, 1, f_soundfold},
839 {"spellbadword", 0, 1, f_spellbadword},
840 {"spellsuggest", 1, 3, f_spellsuggest},
841 {"split", 1, 3, f_split},
842#ifdef FEAT_FLOAT
843 {"sqrt", 1, 1, f_sqrt},
844 {"str2float", 1, 1, f_str2float},
845#endif
846 {"str2nr", 1, 2, f_str2nr},
847 {"strcharpart", 2, 3, f_strcharpart},
848 {"strchars", 1, 2, f_strchars},
849 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
850#ifdef HAVE_STRFTIME
851 {"strftime", 1, 2, f_strftime},
852#endif
853 {"strgetchar", 2, 2, f_strgetchar},
854 {"stridx", 2, 3, f_stridx},
855 {"string", 1, 1, f_string},
856 {"strlen", 1, 1, f_strlen},
857 {"strpart", 2, 3, f_strpart},
858 {"strridx", 2, 3, f_strridx},
859 {"strtrans", 1, 1, f_strtrans},
860 {"strwidth", 1, 1, f_strwidth},
861 {"submatch", 1, 2, f_submatch},
862 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200863 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200864 {"synID", 3, 3, f_synID},
865 {"synIDattr", 2, 3, f_synIDattr},
866 {"synIDtrans", 1, 1, f_synIDtrans},
867 {"synconcealed", 2, 2, f_synconcealed},
868 {"synstack", 2, 2, f_synstack},
869 {"system", 1, 2, f_system},
870 {"systemlist", 1, 2, f_systemlist},
871 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
872 {"tabpagenr", 0, 1, f_tabpagenr},
873 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
874 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100875 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876#ifdef FEAT_FLOAT
877 {"tan", 1, 1, f_tan},
878 {"tanh", 1, 1, f_tanh},
879#endif
880 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200881#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100882 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
883 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100884 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200885 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200886# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
887 {"term_getansicolors", 1, 1, f_term_getansicolors},
888# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200889 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200890 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200891 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200892 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200893 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200894 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200895 {"term_getstatus", 1, 1, f_term_getstatus},
896 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200897 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200898 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200899 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200900 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200901# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
902 {"term_setansicolors", 2, 2, f_term_setansicolors},
903# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100904 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100905 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200906 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200907 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200908 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200909#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200910 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
911 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200912 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200913 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100914 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200915#ifdef FEAT_JOB_CHANNEL
916 {"test_null_channel", 0, 0, f_test_null_channel},
917#endif
918 {"test_null_dict", 0, 0, f_test_null_dict},
919#ifdef FEAT_JOB_CHANNEL
920 {"test_null_job", 0, 0, f_test_null_job},
921#endif
922 {"test_null_list", 0, 0, f_test_null_list},
923 {"test_null_partial", 0, 0, f_test_null_partial},
924 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100925 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926 {"test_settime", 1, 1, f_test_settime},
927#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200928 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200929 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930 {"timer_start", 2, 3, f_timer_start},
931 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200932 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200933#endif
934 {"tolower", 1, 1, f_tolower},
935 {"toupper", 1, 1, f_toupper},
936 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100937 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200938#ifdef FEAT_FLOAT
939 {"trunc", 1, 1, f_trunc},
940#endif
941 {"type", 1, 1, f_type},
942 {"undofile", 1, 1, f_undofile},
943 {"undotree", 0, 0, f_undotree},
944 {"uniq", 1, 3, f_uniq},
945 {"values", 1, 1, f_values},
946 {"virtcol", 1, 1, f_virtcol},
947 {"visualmode", 0, 1, f_visualmode},
948 {"wildmenumode", 0, 0, f_wildmenumode},
949 {"win_findbuf", 1, 1, f_win_findbuf},
950 {"win_getid", 0, 2, f_win_getid},
951 {"win_gotoid", 1, 1, f_win_gotoid},
952 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
953 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100954 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955 {"winbufnr", 1, 1, f_winbufnr},
956 {"wincol", 0, 0, f_wincol},
957 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200958 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200959 {"winline", 0, 0, f_winline},
960 {"winnr", 0, 1, f_winnr},
961 {"winrestcmd", 0, 0, f_winrestcmd},
962 {"winrestview", 1, 1, f_winrestview},
963 {"winsaveview", 0, 0, f_winsaveview},
964 {"winwidth", 1, 1, f_winwidth},
965 {"wordcount", 0, 0, f_wordcount},
966 {"writefile", 2, 3, f_writefile},
967 {"xor", 2, 2, f_xor},
968};
969
970#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
971
972/*
973 * Function given to ExpandGeneric() to obtain the list of internal
974 * or user defined function names.
975 */
976 char_u *
977get_function_name(expand_T *xp, int idx)
978{
979 static int intidx = -1;
980 char_u *name;
981
982 if (idx == 0)
983 intidx = -1;
984 if (intidx < 0)
985 {
986 name = get_user_func_name(xp, idx);
987 if (name != NULL)
988 return name;
989 }
990 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
991 {
992 STRCPY(IObuff, functions[intidx].f_name);
993 STRCAT(IObuff, "(");
994 if (functions[intidx].f_max_argc == 0)
995 STRCAT(IObuff, ")");
996 return IObuff;
997 }
998
999 return NULL;
1000}
1001
1002/*
1003 * Function given to ExpandGeneric() to obtain the list of internal or
1004 * user defined variable or function names.
1005 */
1006 char_u *
1007get_expr_name(expand_T *xp, int idx)
1008{
1009 static int intidx = -1;
1010 char_u *name;
1011
1012 if (idx == 0)
1013 intidx = -1;
1014 if (intidx < 0)
1015 {
1016 name = get_function_name(xp, idx);
1017 if (name != NULL)
1018 return name;
1019 }
1020 return get_user_var_name(xp, ++intidx);
1021}
1022
1023#endif /* FEAT_CMDL_COMPL */
1024
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001025/*
1026 * Find internal function in table above.
1027 * Return index, or -1 if not found
1028 */
1029 int
1030find_internal_func(
1031 char_u *name) /* name of the function */
1032{
1033 int first = 0;
1034 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1035 int cmp;
1036 int x;
1037
1038 /*
1039 * Find the function name in the table. Binary search.
1040 */
1041 while (first <= last)
1042 {
1043 x = first + ((unsigned)(last - first) >> 1);
1044 cmp = STRCMP(name, functions[x].f_name);
1045 if (cmp < 0)
1046 last = x - 1;
1047 else if (cmp > 0)
1048 first = x + 1;
1049 else
1050 return x;
1051 }
1052 return -1;
1053}
1054
1055 int
1056call_internal_func(
1057 char_u *name,
1058 int argcount,
1059 typval_T *argvars,
1060 typval_T *rettv)
1061{
1062 int i;
1063
1064 i = find_internal_func(name);
1065 if (i < 0)
1066 return ERROR_UNKNOWN;
1067 if (argcount < functions[i].f_min_argc)
1068 return ERROR_TOOFEW;
1069 if (argcount > functions[i].f_max_argc)
1070 return ERROR_TOOMANY;
1071 argvars[argcount].v_type = VAR_UNKNOWN;
1072 functions[i].f_func(argvars, rettv);
1073 return ERROR_NONE;
1074}
1075
1076/*
1077 * Return TRUE for a non-zero Number and a non-empty String.
1078 */
1079 static int
1080non_zero_arg(typval_T *argvars)
1081{
1082 return ((argvars[0].v_type == VAR_NUMBER
1083 && argvars[0].vval.v_number != 0)
1084 || (argvars[0].v_type == VAR_SPECIAL
1085 && argvars[0].vval.v_number == VVAL_TRUE)
1086 || (argvars[0].v_type == VAR_STRING
1087 && argvars[0].vval.v_string != NULL
1088 && *argvars[0].vval.v_string != NUL));
1089}
1090
1091/*
1092 * Get the lnum from the first argument.
1093 * Also accepts ".", "$", etc., but that only works for the current buffer.
1094 * Returns -1 on error.
1095 */
1096 static linenr_T
1097get_tv_lnum(typval_T *argvars)
1098{
1099 typval_T rettv;
1100 linenr_T lnum;
1101
1102 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1103 if (lnum == 0) /* no valid number, try using line() */
1104 {
1105 rettv.v_type = VAR_NUMBER;
1106 f_line(argvars, &rettv);
1107 lnum = (linenr_T)rettv.vval.v_number;
1108 clear_tv(&rettv);
1109 }
1110 return lnum;
1111}
1112
1113#ifdef FEAT_FLOAT
1114static int get_float_arg(typval_T *argvars, float_T *f);
1115
1116/*
1117 * Get the float value of "argvars[0]" into "f".
1118 * Returns FAIL when the argument is not a Number or Float.
1119 */
1120 static int
1121get_float_arg(typval_T *argvars, float_T *f)
1122{
1123 if (argvars[0].v_type == VAR_FLOAT)
1124 {
1125 *f = argvars[0].vval.v_float;
1126 return OK;
1127 }
1128 if (argvars[0].v_type == VAR_NUMBER)
1129 {
1130 *f = (float_T)argvars[0].vval.v_number;
1131 return OK;
1132 }
1133 EMSG(_("E808: Number or Float required"));
1134 return FAIL;
1135}
1136
1137/*
1138 * "abs(expr)" function
1139 */
1140 static void
1141f_abs(typval_T *argvars, typval_T *rettv)
1142{
1143 if (argvars[0].v_type == VAR_FLOAT)
1144 {
1145 rettv->v_type = VAR_FLOAT;
1146 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1147 }
1148 else
1149 {
1150 varnumber_T n;
1151 int error = FALSE;
1152
1153 n = get_tv_number_chk(&argvars[0], &error);
1154 if (error)
1155 rettv->vval.v_number = -1;
1156 else if (n > 0)
1157 rettv->vval.v_number = n;
1158 else
1159 rettv->vval.v_number = -n;
1160 }
1161}
1162
1163/*
1164 * "acos()" function
1165 */
1166 static void
1167f_acos(typval_T *argvars, typval_T *rettv)
1168{
1169 float_T f = 0.0;
1170
1171 rettv->v_type = VAR_FLOAT;
1172 if (get_float_arg(argvars, &f) == OK)
1173 rettv->vval.v_float = acos(f);
1174 else
1175 rettv->vval.v_float = 0.0;
1176}
1177#endif
1178
1179/*
1180 * "add(list, item)" function
1181 */
1182 static void
1183f_add(typval_T *argvars, typval_T *rettv)
1184{
1185 list_T *l;
1186
1187 rettv->vval.v_number = 1; /* Default: Failed */
1188 if (argvars[0].v_type == VAR_LIST)
1189 {
1190 if ((l = argvars[0].vval.v_list) != NULL
1191 && !tv_check_lock(l->lv_lock,
1192 (char_u *)N_("add() argument"), TRUE)
1193 && list_append_tv(l, &argvars[1]) == OK)
1194 copy_tv(&argvars[0], rettv);
1195 }
1196 else
1197 EMSG(_(e_listreq));
1198}
1199
1200/*
1201 * "and(expr, expr)" function
1202 */
1203 static void
1204f_and(typval_T *argvars, typval_T *rettv)
1205{
1206 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1207 & get_tv_number_chk(&argvars[1], NULL);
1208}
1209
1210/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001211 * Get the lnum from the first argument.
1212 * Also accepts "$", then "buf" is used.
1213 * Returns 0 on error.
1214 */
1215 static linenr_T
1216get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
1217{
1218 if (argvars[0].v_type == VAR_STRING
1219 && argvars[0].vval.v_string != NULL
1220 && argvars[0].vval.v_string[0] == '$'
1221 && buf != NULL)
1222 return buf->b_ml.ml_line_count;
1223 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1224}
1225
1226/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001227 * If there is a window for "curbuf", make it the current window.
1228 */
1229 static void
1230find_win_for_curbuf(void)
1231{
1232 wininfo_T *wip;
1233
1234 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1235 {
1236 if (wip->wi_win != NULL)
1237 {
1238 curwin = wip->wi_win;
1239 break;
1240 }
1241 }
1242}
1243
1244/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001245 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001246 */
1247 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001248set_buffer_lines(
1249 buf_T *buf,
1250 linenr_T lnum_arg,
1251 int append,
1252 typval_T *lines,
1253 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254{
Bram Moolenaarca851592018-06-06 21:04:07 +02001255 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1256 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001257 list_T *l = NULL;
1258 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001259 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001260 linenr_T append_lnum;
1261 buf_T *curbuf_save = NULL;
1262 win_T *curwin_save = NULL;
1263 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001264
Bram Moolenaarca851592018-06-06 21:04:07 +02001265 /* When using the current buffer ml_mfp will be set if needed. Useful when
1266 * setline() is used on startup. For other buffers the buffer must be
1267 * loaded. */
1268 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001269 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001270 rettv->vval.v_number = 1; /* FAIL */
1271 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001272 }
1273
Bram Moolenaarca851592018-06-06 21:04:07 +02001274 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001275 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001276 curbuf_save = curbuf;
1277 curwin_save = curwin;
1278 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001279 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001280 }
1281
1282 if (append)
1283 // appendbufline() uses the line number below which we insert
1284 append_lnum = lnum - 1;
1285 else
1286 // setbufline() uses the line number above which we insert, we only
1287 // append if it's below the last line
1288 append_lnum = curbuf->b_ml.ml_line_count;
1289
1290 if (lines->v_type == VAR_LIST)
1291 {
1292 l = lines->vval.v_list;
1293 li = l->lv_first;
1294 }
1295 else
1296 line = get_tv_string_chk(lines);
1297
1298 /* default result is zero == OK */
1299 for (;;)
1300 {
1301 if (l != NULL)
1302 {
1303 /* list argument, get next string */
1304 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001305 break;
Bram Moolenaarca851592018-06-06 21:04:07 +02001306 line = get_tv_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 li = li->li_next;
1308 }
1309
Bram Moolenaarca851592018-06-06 21:04:07 +02001310 rettv->vval.v_number = 1; /* FAIL */
1311 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1312 break;
1313
1314 /* When coming here from Insert mode, sync undo, so that this can be
1315 * undone separately from what was previously inserted. */
1316 if (u_sync_once == 2)
1317 {
1318 u_sync_once = 1; /* notify that u_sync() was called */
1319 u_sync(TRUE);
1320 }
1321
1322 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1323 {
1324 /* existing line, replace it */
1325 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1326 {
1327 changed_bytes(lnum, 0);
1328 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1329 check_cursor_col();
1330 rettv->vval.v_number = 0; /* OK */
1331 }
1332 }
1333 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1334 {
1335 /* append the line */
1336 ++added;
1337 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1338 rettv->vval.v_number = 0; /* OK */
1339 }
1340
1341 if (l == NULL) /* only one string argument */
1342 break;
1343 ++lnum;
1344 }
1345
1346 if (added > 0)
1347 {
1348 win_T *wp;
1349 tabpage_T *tp;
1350
1351 appended_lines_mark(append_lnum, added);
1352 FOR_ALL_TAB_WINDOWS(tp, wp)
1353 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1354 wp->w_cursor.lnum += added;
1355 check_cursor_col();
1356
Bram Moolenaarf2732452018-06-03 14:47:35 +02001357#ifdef FEAT_JOB_CHANNEL
1358 if (bt_prompt(curbuf) && (State & INSERT))
1359 // show the line with the prompt
1360 update_topline();
1361#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001363
1364 if (!is_curbuf)
1365 {
1366 curbuf = curbuf_save;
1367 curwin = curwin_save;
1368 }
1369}
1370
1371/*
1372 * "append(lnum, string/list)" function
1373 */
1374 static void
1375f_append(typval_T *argvars, typval_T *rettv)
1376{
1377 linenr_T lnum = get_tv_lnum(&argvars[0]);
1378
1379 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1380}
1381
1382/*
1383 * "appendbufline(buf, lnum, string/list)" function
1384 */
1385 static void
1386f_appendbufline(typval_T *argvars, typval_T *rettv)
1387{
1388 linenr_T lnum;
1389 buf_T *buf;
1390
1391 buf = get_buf_tv(&argvars[0], FALSE);
1392 if (buf == NULL)
1393 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001394 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001395 {
1396 lnum = get_tv_lnum_buf(&argvars[1], buf);
1397 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1398 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001399}
1400
1401/*
1402 * "argc()" function
1403 */
1404 static void
1405f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1406{
1407 rettv->vval.v_number = ARGCOUNT;
1408}
1409
1410/*
1411 * "argidx()" function
1412 */
1413 static void
1414f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1415{
1416 rettv->vval.v_number = curwin->w_arg_idx;
1417}
1418
1419/*
1420 * "arglistid()" function
1421 */
1422 static void
1423f_arglistid(typval_T *argvars, typval_T *rettv)
1424{
1425 win_T *wp;
1426
1427 rettv->vval.v_number = -1;
1428 wp = find_tabwin(&argvars[0], &argvars[1]);
1429 if (wp != NULL)
1430 rettv->vval.v_number = wp->w_alist->id;
1431}
1432
1433/*
1434 * "argv(nr)" function
1435 */
1436 static void
1437f_argv(typval_T *argvars, typval_T *rettv)
1438{
1439 int idx;
1440
1441 if (argvars[0].v_type != VAR_UNKNOWN)
1442 {
1443 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1444 if (idx >= 0 && idx < ARGCOUNT)
1445 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1446 else
1447 rettv->vval.v_string = NULL;
1448 rettv->v_type = VAR_STRING;
1449 }
1450 else if (rettv_list_alloc(rettv) == OK)
1451 for (idx = 0; idx < ARGCOUNT; ++idx)
1452 list_append_string(rettv->vval.v_list,
1453 alist_name(&ARGLIST[idx]), -1);
1454}
1455
1456/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001457 * "assert_beeps(cmd [, error])" function
1458 */
1459 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001460f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001461{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001462 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001463}
1464
1465/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001466 * "assert_equal(expected, actual[, msg])" function
1467 */
1468 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001469f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001470{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001471 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001472}
1473
1474/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001475 * "assert_equalfile(fname-one, fname-two)" function
1476 */
1477 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001478f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001479{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001480 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001481}
1482
1483/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001484 * "assert_notequal(expected, actual[, msg])" function
1485 */
1486 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001487f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001489 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001490}
1491
1492/*
1493 * "assert_exception(string[, msg])" function
1494 */
1495 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001496f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001498 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499}
1500
1501/*
1502 * "assert_fails(cmd [, error])" function
1503 */
1504 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001505f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001507 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508}
1509
1510/*
1511 * "assert_false(actual[, msg])" function
1512 */
1513 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001514f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001515{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001516 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001517}
1518
1519/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001520 * "assert_inrange(lower, upper[, msg])" function
1521 */
1522 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001523f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001524{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001525 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001526}
1527
1528/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529 * "assert_match(pattern, actual[, msg])" function
1530 */
1531 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001532f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001534 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535}
1536
1537/*
1538 * "assert_notmatch(pattern, actual[, msg])" function
1539 */
1540 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001541f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001543 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001544}
1545
1546/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001547 * "assert_report(msg)" function
1548 */
1549 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001550f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001551{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001552 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001553}
1554
1555/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 * "assert_true(actual[, msg])" function
1557 */
1558 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001559f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001560{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001561 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001562}
1563
1564#ifdef FEAT_FLOAT
1565/*
1566 * "asin()" function
1567 */
1568 static void
1569f_asin(typval_T *argvars, typval_T *rettv)
1570{
1571 float_T f = 0.0;
1572
1573 rettv->v_type = VAR_FLOAT;
1574 if (get_float_arg(argvars, &f) == OK)
1575 rettv->vval.v_float = asin(f);
1576 else
1577 rettv->vval.v_float = 0.0;
1578}
1579
1580/*
1581 * "atan()" function
1582 */
1583 static void
1584f_atan(typval_T *argvars, typval_T *rettv)
1585{
1586 float_T f = 0.0;
1587
1588 rettv->v_type = VAR_FLOAT;
1589 if (get_float_arg(argvars, &f) == OK)
1590 rettv->vval.v_float = atan(f);
1591 else
1592 rettv->vval.v_float = 0.0;
1593}
1594
1595/*
1596 * "atan2()" function
1597 */
1598 static void
1599f_atan2(typval_T *argvars, typval_T *rettv)
1600{
1601 float_T fx = 0.0, fy = 0.0;
1602
1603 rettv->v_type = VAR_FLOAT;
1604 if (get_float_arg(argvars, &fx) == OK
1605 && get_float_arg(&argvars[1], &fy) == OK)
1606 rettv->vval.v_float = atan2(fx, fy);
1607 else
1608 rettv->vval.v_float = 0.0;
1609}
1610#endif
1611
1612/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001613 * "balloon_show()" function
1614 */
1615#ifdef FEAT_BEVAL
1616 static void
1617f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1618{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001619 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001620 {
1621 if (argvars[0].v_type == VAR_LIST
1622# ifdef FEAT_GUI
1623 && !gui.in_use
1624# endif
1625 )
1626 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1627 else
1628 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1629 }
1630}
1631
Bram Moolenaar669a8282017-11-19 20:13:05 +01001632# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001633 static void
1634f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1635{
1636 if (rettv_list_alloc(rettv) == OK)
1637 {
1638 char_u *msg = get_tv_string_chk(&argvars[0]);
1639
1640 if (msg != NULL)
1641 {
1642 pumitem_T *array;
1643 int size = split_message(msg, &array);
1644 int i;
1645
1646 /* Skip the first and last item, they are always empty. */
1647 for (i = 1; i < size - 1; ++i)
1648 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001649 while (size > 0)
1650 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001651 vim_free(array);
1652 }
1653 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001654}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001655# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001656#endif
1657
1658/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001659 * "browse(save, title, initdir, default)" function
1660 */
1661 static void
1662f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1663{
1664#ifdef FEAT_BROWSE
1665 int save;
1666 char_u *title;
1667 char_u *initdir;
1668 char_u *defname;
1669 char_u buf[NUMBUFLEN];
1670 char_u buf2[NUMBUFLEN];
1671 int error = FALSE;
1672
1673 save = (int)get_tv_number_chk(&argvars[0], &error);
1674 title = get_tv_string_chk(&argvars[1]);
1675 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1676 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1677
1678 if (error || title == NULL || initdir == NULL || defname == NULL)
1679 rettv->vval.v_string = NULL;
1680 else
1681 rettv->vval.v_string =
1682 do_browse(save ? BROWSE_SAVE : 0,
1683 title, defname, NULL, initdir, NULL, curbuf);
1684#else
1685 rettv->vval.v_string = NULL;
1686#endif
1687 rettv->v_type = VAR_STRING;
1688}
1689
1690/*
1691 * "browsedir(title, initdir)" function
1692 */
1693 static void
1694f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1695{
1696#ifdef FEAT_BROWSE
1697 char_u *title;
1698 char_u *initdir;
1699 char_u buf[NUMBUFLEN];
1700
1701 title = get_tv_string_chk(&argvars[0]);
1702 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1703
1704 if (title == NULL || initdir == NULL)
1705 rettv->vval.v_string = NULL;
1706 else
1707 rettv->vval.v_string = do_browse(BROWSE_DIR,
1708 title, NULL, NULL, initdir, NULL, curbuf);
1709#else
1710 rettv->vval.v_string = NULL;
1711#endif
1712 rettv->v_type = VAR_STRING;
1713}
1714
1715static buf_T *find_buffer(typval_T *avar);
1716
1717/*
1718 * Find a buffer by number or exact name.
1719 */
1720 static buf_T *
1721find_buffer(typval_T *avar)
1722{
1723 buf_T *buf = NULL;
1724
1725 if (avar->v_type == VAR_NUMBER)
1726 buf = buflist_findnr((int)avar->vval.v_number);
1727 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1728 {
1729 buf = buflist_findname_exp(avar->vval.v_string);
1730 if (buf == NULL)
1731 {
1732 /* No full path name match, try a match with a URL or a "nofile"
1733 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001734 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001735 if (buf->b_fname != NULL
1736 && (path_with_url(buf->b_fname)
1737#ifdef FEAT_QUICKFIX
1738 || bt_nofile(buf)
1739#endif
1740 )
1741 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1742 break;
1743 }
1744 }
1745 return buf;
1746}
1747
1748/*
1749 * "bufexists(expr)" function
1750 */
1751 static void
1752f_bufexists(typval_T *argvars, typval_T *rettv)
1753{
1754 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1755}
1756
1757/*
1758 * "buflisted(expr)" function
1759 */
1760 static void
1761f_buflisted(typval_T *argvars, typval_T *rettv)
1762{
1763 buf_T *buf;
1764
1765 buf = find_buffer(&argvars[0]);
1766 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1767}
1768
1769/*
1770 * "bufloaded(expr)" function
1771 */
1772 static void
1773f_bufloaded(typval_T *argvars, typval_T *rettv)
1774{
1775 buf_T *buf;
1776
1777 buf = find_buffer(&argvars[0]);
1778 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1779}
1780
1781 buf_T *
1782buflist_find_by_name(char_u *name, int curtab_only)
1783{
1784 int save_magic;
1785 char_u *save_cpo;
1786 buf_T *buf;
1787
1788 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1789 save_magic = p_magic;
1790 p_magic = TRUE;
1791 save_cpo = p_cpo;
1792 p_cpo = (char_u *)"";
1793
1794 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1795 TRUE, FALSE, curtab_only));
1796
1797 p_magic = save_magic;
1798 p_cpo = save_cpo;
1799 return buf;
1800}
1801
1802/*
1803 * Get buffer by number or pattern.
1804 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001805 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001806get_buf_tv(typval_T *tv, int curtab_only)
1807{
1808 char_u *name = tv->vval.v_string;
1809 buf_T *buf;
1810
1811 if (tv->v_type == VAR_NUMBER)
1812 return buflist_findnr((int)tv->vval.v_number);
1813 if (tv->v_type != VAR_STRING)
1814 return NULL;
1815 if (name == NULL || *name == NUL)
1816 return curbuf;
1817 if (name[0] == '$' && name[1] == NUL)
1818 return lastbuf;
1819
1820 buf = buflist_find_by_name(name, curtab_only);
1821
1822 /* If not found, try expanding the name, like done for bufexists(). */
1823 if (buf == NULL)
1824 buf = find_buffer(tv);
1825
1826 return buf;
1827}
1828
1829/*
1830 * "bufname(expr)" function
1831 */
1832 static void
1833f_bufname(typval_T *argvars, typval_T *rettv)
1834{
1835 buf_T *buf;
1836
1837 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1838 ++emsg_off;
1839 buf = get_buf_tv(&argvars[0], FALSE);
1840 rettv->v_type = VAR_STRING;
1841 if (buf != NULL && buf->b_fname != NULL)
1842 rettv->vval.v_string = vim_strsave(buf->b_fname);
1843 else
1844 rettv->vval.v_string = NULL;
1845 --emsg_off;
1846}
1847
1848/*
1849 * "bufnr(expr)" function
1850 */
1851 static void
1852f_bufnr(typval_T *argvars, typval_T *rettv)
1853{
1854 buf_T *buf;
1855 int error = FALSE;
1856 char_u *name;
1857
1858 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1859 ++emsg_off;
1860 buf = get_buf_tv(&argvars[0], FALSE);
1861 --emsg_off;
1862
1863 /* If the buffer isn't found and the second argument is not zero create a
1864 * new buffer. */
1865 if (buf == NULL
1866 && argvars[1].v_type != VAR_UNKNOWN
1867 && get_tv_number_chk(&argvars[1], &error) != 0
1868 && !error
1869 && (name = get_tv_string_chk(&argvars[0])) != NULL
1870 && !error)
1871 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1872
1873 if (buf != NULL)
1874 rettv->vval.v_number = buf->b_fnum;
1875 else
1876 rettv->vval.v_number = -1;
1877}
1878
1879 static void
1880buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1881{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001882 win_T *wp;
1883 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001884 buf_T *buf;
1885
1886 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1887 ++emsg_off;
1888 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001889 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001890 {
1891 ++winnr;
1892 if (wp->w_buffer == buf)
1893 break;
1894 }
1895 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001896 --emsg_off;
1897}
1898
1899/*
1900 * "bufwinid(nr)" function
1901 */
1902 static void
1903f_bufwinid(typval_T *argvars, typval_T *rettv)
1904{
1905 buf_win_common(argvars, rettv, FALSE);
1906}
1907
1908/*
1909 * "bufwinnr(nr)" function
1910 */
1911 static void
1912f_bufwinnr(typval_T *argvars, typval_T *rettv)
1913{
1914 buf_win_common(argvars, rettv, TRUE);
1915}
1916
1917/*
1918 * "byte2line(byte)" function
1919 */
1920 static void
1921f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1922{
1923#ifndef FEAT_BYTEOFF
1924 rettv->vval.v_number = -1;
1925#else
1926 long boff = 0;
1927
1928 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1929 if (boff < 0)
1930 rettv->vval.v_number = -1;
1931 else
1932 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1933 (linenr_T)0, &boff);
1934#endif
1935}
1936
1937 static void
1938byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1939{
1940#ifdef FEAT_MBYTE
1941 char_u *t;
1942#endif
1943 char_u *str;
1944 varnumber_T idx;
1945
1946 str = get_tv_string_chk(&argvars[0]);
1947 idx = get_tv_number_chk(&argvars[1], NULL);
1948 rettv->vval.v_number = -1;
1949 if (str == NULL || idx < 0)
1950 return;
1951
1952#ifdef FEAT_MBYTE
1953 t = str;
1954 for ( ; idx > 0; idx--)
1955 {
1956 if (*t == NUL) /* EOL reached */
1957 return;
1958 if (enc_utf8 && comp)
1959 t += utf_ptr2len(t);
1960 else
1961 t += (*mb_ptr2len)(t);
1962 }
1963 rettv->vval.v_number = (varnumber_T)(t - str);
1964#else
1965 if ((size_t)idx <= STRLEN(str))
1966 rettv->vval.v_number = idx;
1967#endif
1968}
1969
1970/*
1971 * "byteidx()" function
1972 */
1973 static void
1974f_byteidx(typval_T *argvars, typval_T *rettv)
1975{
1976 byteidx(argvars, rettv, FALSE);
1977}
1978
1979/*
1980 * "byteidxcomp()" function
1981 */
1982 static void
1983f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1984{
1985 byteidx(argvars, rettv, TRUE);
1986}
1987
1988/*
1989 * "call(func, arglist [, dict])" function
1990 */
1991 static void
1992f_call(typval_T *argvars, typval_T *rettv)
1993{
1994 char_u *func;
1995 partial_T *partial = NULL;
1996 dict_T *selfdict = NULL;
1997
1998 if (argvars[1].v_type != VAR_LIST)
1999 {
2000 EMSG(_(e_listreq));
2001 return;
2002 }
2003 if (argvars[1].vval.v_list == NULL)
2004 return;
2005
2006 if (argvars[0].v_type == VAR_FUNC)
2007 func = argvars[0].vval.v_string;
2008 else if (argvars[0].v_type == VAR_PARTIAL)
2009 {
2010 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002011 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 }
2013 else
2014 func = get_tv_string(&argvars[0]);
2015 if (*func == NUL)
2016 return; /* type error or empty name */
2017
2018 if (argvars[2].v_type != VAR_UNKNOWN)
2019 {
2020 if (argvars[2].v_type != VAR_DICT)
2021 {
2022 EMSG(_(e_dictreq));
2023 return;
2024 }
2025 selfdict = argvars[2].vval.v_dict;
2026 }
2027
2028 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2029}
2030
2031#ifdef FEAT_FLOAT
2032/*
2033 * "ceil({float})" function
2034 */
2035 static void
2036f_ceil(typval_T *argvars, typval_T *rettv)
2037{
2038 float_T f = 0.0;
2039
2040 rettv->v_type = VAR_FLOAT;
2041 if (get_float_arg(argvars, &f) == OK)
2042 rettv->vval.v_float = ceil(f);
2043 else
2044 rettv->vval.v_float = 0.0;
2045}
2046#endif
2047
2048#ifdef FEAT_JOB_CHANNEL
2049/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002050 * "ch_canread()" function
2051 */
2052 static void
2053f_ch_canread(typval_T *argvars, typval_T *rettv)
2054{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002055 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002056
2057 rettv->vval.v_number = 0;
2058 if (channel != NULL)
2059 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2060 || channel_has_readahead(channel, PART_OUT)
2061 || channel_has_readahead(channel, PART_ERR);
2062}
2063
2064/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002065 * "ch_close()" function
2066 */
2067 static void
2068f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2069{
2070 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2071
2072 if (channel != NULL)
2073 {
2074 channel_close(channel, FALSE);
2075 channel_clear(channel);
2076 }
2077}
2078
2079/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002080 * "ch_close()" function
2081 */
2082 static void
2083f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2084{
2085 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2086
2087 if (channel != NULL)
2088 channel_close_in(channel);
2089}
2090
2091/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002092 * "ch_getbufnr()" function
2093 */
2094 static void
2095f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2096{
2097 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2098
2099 rettv->vval.v_number = -1;
2100 if (channel != NULL)
2101 {
2102 char_u *what = get_tv_string(&argvars[1]);
2103 int part;
2104
2105 if (STRCMP(what, "err") == 0)
2106 part = PART_ERR;
2107 else if (STRCMP(what, "out") == 0)
2108 part = PART_OUT;
2109 else if (STRCMP(what, "in") == 0)
2110 part = PART_IN;
2111 else
2112 part = PART_SOCK;
2113 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2114 rettv->vval.v_number =
2115 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2116 }
2117}
2118
2119/*
2120 * "ch_getjob()" function
2121 */
2122 static void
2123f_ch_getjob(typval_T *argvars, typval_T *rettv)
2124{
2125 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2126
2127 if (channel != NULL)
2128 {
2129 rettv->v_type = VAR_JOB;
2130 rettv->vval.v_job = channel->ch_job;
2131 if (channel->ch_job != NULL)
2132 ++channel->ch_job->jv_refcount;
2133 }
2134}
2135
2136/*
2137 * "ch_info()" function
2138 */
2139 static void
2140f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2141{
2142 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2143
2144 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2145 channel_info(channel, rettv->vval.v_dict);
2146}
2147
2148/*
2149 * "ch_log()" function
2150 */
2151 static void
2152f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2153{
2154 char_u *msg = get_tv_string(&argvars[0]);
2155 channel_T *channel = NULL;
2156
2157 if (argvars[1].v_type != VAR_UNKNOWN)
2158 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2159
Bram Moolenaard5359b22018-04-05 22:44:39 +02002160 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161}
2162
2163/*
2164 * "ch_logfile()" function
2165 */
2166 static void
2167f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2168{
2169 char_u *fname;
2170 char_u *opt = (char_u *)"";
2171 char_u buf[NUMBUFLEN];
2172
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002173 /* Don't open a file in restricted mode. */
2174 if (check_restricted() || check_secure())
2175 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 fname = get_tv_string(&argvars[0]);
2177 if (argvars[1].v_type == VAR_STRING)
2178 opt = get_tv_string_buf(&argvars[1], buf);
2179 ch_logfile(fname, opt);
2180}
2181
2182/*
2183 * "ch_open()" function
2184 */
2185 static void
2186f_ch_open(typval_T *argvars, typval_T *rettv)
2187{
2188 rettv->v_type = VAR_CHANNEL;
2189 if (check_restricted() || check_secure())
2190 return;
2191 rettv->vval.v_channel = channel_open_func(argvars);
2192}
2193
2194/*
2195 * "ch_read()" function
2196 */
2197 static void
2198f_ch_read(typval_T *argvars, typval_T *rettv)
2199{
2200 common_channel_read(argvars, rettv, FALSE);
2201}
2202
2203/*
2204 * "ch_readraw()" function
2205 */
2206 static void
2207f_ch_readraw(typval_T *argvars, typval_T *rettv)
2208{
2209 common_channel_read(argvars, rettv, TRUE);
2210}
2211
2212/*
2213 * "ch_evalexpr()" function
2214 */
2215 static void
2216f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2217{
2218 ch_expr_common(argvars, rettv, TRUE);
2219}
2220
2221/*
2222 * "ch_sendexpr()" function
2223 */
2224 static void
2225f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2226{
2227 ch_expr_common(argvars, rettv, FALSE);
2228}
2229
2230/*
2231 * "ch_evalraw()" function
2232 */
2233 static void
2234f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2235{
2236 ch_raw_common(argvars, rettv, TRUE);
2237}
2238
2239/*
2240 * "ch_sendraw()" function
2241 */
2242 static void
2243f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2244{
2245 ch_raw_common(argvars, rettv, FALSE);
2246}
2247
2248/*
2249 * "ch_setoptions()" function
2250 */
2251 static void
2252f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2253{
2254 channel_T *channel;
2255 jobopt_T opt;
2256
2257 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2258 if (channel == NULL)
2259 return;
2260 clear_job_options(&opt);
2261 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002262 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263 channel_set_options(channel, &opt);
2264 free_job_options(&opt);
2265}
2266
2267/*
2268 * "ch_status()" function
2269 */
2270 static void
2271f_ch_status(typval_T *argvars, typval_T *rettv)
2272{
2273 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002274 jobopt_T opt;
2275 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002276
2277 /* return an empty string by default */
2278 rettv->v_type = VAR_STRING;
2279 rettv->vval.v_string = NULL;
2280
2281 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002282
2283 if (argvars[1].v_type != VAR_UNKNOWN)
2284 {
2285 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002286 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002287 && (opt.jo_set & JO_PART))
2288 part = opt.jo_part;
2289 }
2290
2291 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292}
2293#endif
2294
2295/*
2296 * "changenr()" function
2297 */
2298 static void
2299f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2300{
2301 rettv->vval.v_number = curbuf->b_u_seq_cur;
2302}
2303
2304/*
2305 * "char2nr(string)" function
2306 */
2307 static void
2308f_char2nr(typval_T *argvars, typval_T *rettv)
2309{
2310#ifdef FEAT_MBYTE
2311 if (has_mbyte)
2312 {
2313 int utf8 = 0;
2314
2315 if (argvars[1].v_type != VAR_UNKNOWN)
2316 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2317
2318 if (utf8)
2319 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2320 else
2321 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2322 }
2323 else
2324#endif
2325 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2326}
2327
2328/*
2329 * "cindent(lnum)" function
2330 */
2331 static void
2332f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2333{
2334#ifdef FEAT_CINDENT
2335 pos_T pos;
2336 linenr_T lnum;
2337
2338 pos = curwin->w_cursor;
2339 lnum = get_tv_lnum(argvars);
2340 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2341 {
2342 curwin->w_cursor.lnum = lnum;
2343 rettv->vval.v_number = get_c_indent();
2344 curwin->w_cursor = pos;
2345 }
2346 else
2347#endif
2348 rettv->vval.v_number = -1;
2349}
2350
2351/*
2352 * "clearmatches()" function
2353 */
2354 static void
2355f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2356{
2357#ifdef FEAT_SEARCH_EXTRA
2358 clear_matches(curwin);
2359#endif
2360}
2361
2362/*
2363 * "col(string)" function
2364 */
2365 static void
2366f_col(typval_T *argvars, typval_T *rettv)
2367{
2368 colnr_T col = 0;
2369 pos_T *fp;
2370 int fnum = curbuf->b_fnum;
2371
2372 fp = var2fpos(&argvars[0], FALSE, &fnum);
2373 if (fp != NULL && fnum == curbuf->b_fnum)
2374 {
2375 if (fp->col == MAXCOL)
2376 {
2377 /* '> can be MAXCOL, get the length of the line then */
2378 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2379 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2380 else
2381 col = MAXCOL;
2382 }
2383 else
2384 {
2385 col = fp->col + 1;
2386#ifdef FEAT_VIRTUALEDIT
2387 /* col(".") when the cursor is on the NUL at the end of the line
2388 * because of "coladd" can be seen as an extra column. */
2389 if (virtual_active() && fp == &curwin->w_cursor)
2390 {
2391 char_u *p = ml_get_cursor();
2392
2393 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2394 curwin->w_virtcol - curwin->w_cursor.coladd))
2395 {
2396# ifdef FEAT_MBYTE
2397 int l;
2398
2399 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2400 col += l;
2401# else
2402 if (*p != NUL && p[1] == NUL)
2403 ++col;
2404# endif
2405 }
2406 }
2407#endif
2408 }
2409 }
2410 rettv->vval.v_number = col;
2411}
2412
2413#if defined(FEAT_INS_EXPAND)
2414/*
2415 * "complete()" function
2416 */
2417 static void
2418f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2419{
2420 int startcol;
2421
2422 if ((State & INSERT) == 0)
2423 {
2424 EMSG(_("E785: complete() can only be used in Insert mode"));
2425 return;
2426 }
2427
2428 /* Check for undo allowed here, because if something was already inserted
2429 * the line was already saved for undo and this check isn't done. */
2430 if (!undo_allowed())
2431 return;
2432
2433 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2434 {
2435 EMSG(_(e_invarg));
2436 return;
2437 }
2438
2439 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2440 if (startcol <= 0)
2441 return;
2442
2443 set_completion(startcol - 1, argvars[1].vval.v_list);
2444}
2445
2446/*
2447 * "complete_add()" function
2448 */
2449 static void
2450f_complete_add(typval_T *argvars, typval_T *rettv)
2451{
2452 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2453}
2454
2455/*
2456 * "complete_check()" function
2457 */
2458 static void
2459f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2460{
2461 int saved = RedrawingDisabled;
2462
2463 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002464 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 rettv->vval.v_number = compl_interrupted;
2466 RedrawingDisabled = saved;
2467}
2468#endif
2469
2470/*
2471 * "confirm(message, buttons[, default [, type]])" function
2472 */
2473 static void
2474f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2475{
2476#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2477 char_u *message;
2478 char_u *buttons = NULL;
2479 char_u buf[NUMBUFLEN];
2480 char_u buf2[NUMBUFLEN];
2481 int def = 1;
2482 int type = VIM_GENERIC;
2483 char_u *typestr;
2484 int error = FALSE;
2485
2486 message = get_tv_string_chk(&argvars[0]);
2487 if (message == NULL)
2488 error = TRUE;
2489 if (argvars[1].v_type != VAR_UNKNOWN)
2490 {
2491 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2492 if (buttons == NULL)
2493 error = TRUE;
2494 if (argvars[2].v_type != VAR_UNKNOWN)
2495 {
2496 def = (int)get_tv_number_chk(&argvars[2], &error);
2497 if (argvars[3].v_type != VAR_UNKNOWN)
2498 {
2499 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2500 if (typestr == NULL)
2501 error = TRUE;
2502 else
2503 {
2504 switch (TOUPPER_ASC(*typestr))
2505 {
2506 case 'E': type = VIM_ERROR; break;
2507 case 'Q': type = VIM_QUESTION; break;
2508 case 'I': type = VIM_INFO; break;
2509 case 'W': type = VIM_WARNING; break;
2510 case 'G': type = VIM_GENERIC; break;
2511 }
2512 }
2513 }
2514 }
2515 }
2516
2517 if (buttons == NULL || *buttons == NUL)
2518 buttons = (char_u *)_("&Ok");
2519
2520 if (!error)
2521 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2522 def, NULL, FALSE);
2523#endif
2524}
2525
2526/*
2527 * "copy()" function
2528 */
2529 static void
2530f_copy(typval_T *argvars, typval_T *rettv)
2531{
2532 item_copy(&argvars[0], rettv, FALSE, 0);
2533}
2534
2535#ifdef FEAT_FLOAT
2536/*
2537 * "cos()" function
2538 */
2539 static void
2540f_cos(typval_T *argvars, typval_T *rettv)
2541{
2542 float_T f = 0.0;
2543
2544 rettv->v_type = VAR_FLOAT;
2545 if (get_float_arg(argvars, &f) == OK)
2546 rettv->vval.v_float = cos(f);
2547 else
2548 rettv->vval.v_float = 0.0;
2549}
2550
2551/*
2552 * "cosh()" function
2553 */
2554 static void
2555f_cosh(typval_T *argvars, typval_T *rettv)
2556{
2557 float_T f = 0.0;
2558
2559 rettv->v_type = VAR_FLOAT;
2560 if (get_float_arg(argvars, &f) == OK)
2561 rettv->vval.v_float = cosh(f);
2562 else
2563 rettv->vval.v_float = 0.0;
2564}
2565#endif
2566
2567/*
2568 * "count()" function
2569 */
2570 static void
2571f_count(typval_T *argvars, typval_T *rettv)
2572{
2573 long n = 0;
2574 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002575 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002576
Bram Moolenaar9966b212017-07-28 16:46:57 +02002577 if (argvars[2].v_type != VAR_UNKNOWN)
2578 ic = (int)get_tv_number_chk(&argvars[2], &error);
2579
2580 if (argvars[0].v_type == VAR_STRING)
2581 {
2582 char_u *expr = get_tv_string_chk(&argvars[1]);
2583 char_u *p = argvars[0].vval.v_string;
2584 char_u *next;
2585
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002586 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002587 {
2588 if (ic)
2589 {
2590 size_t len = STRLEN(expr);
2591
2592 while (*p != NUL)
2593 {
2594 if (MB_STRNICMP(p, expr, len) == 0)
2595 {
2596 ++n;
2597 p += len;
2598 }
2599 else
2600 MB_PTR_ADV(p);
2601 }
2602 }
2603 else
2604 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2605 != NULL)
2606 {
2607 ++n;
2608 p = next + STRLEN(expr);
2609 }
2610 }
2611
2612 }
2613 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614 {
2615 listitem_T *li;
2616 list_T *l;
2617 long idx;
2618
2619 if ((l = argvars[0].vval.v_list) != NULL)
2620 {
2621 li = l->lv_first;
2622 if (argvars[2].v_type != VAR_UNKNOWN)
2623 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002624 if (argvars[3].v_type != VAR_UNKNOWN)
2625 {
2626 idx = (long)get_tv_number_chk(&argvars[3], &error);
2627 if (!error)
2628 {
2629 li = list_find(l, idx);
2630 if (li == NULL)
2631 EMSGN(_(e_listidx), idx);
2632 }
2633 }
2634 if (error)
2635 li = NULL;
2636 }
2637
2638 for ( ; li != NULL; li = li->li_next)
2639 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2640 ++n;
2641 }
2642 }
2643 else if (argvars[0].v_type == VAR_DICT)
2644 {
2645 int todo;
2646 dict_T *d;
2647 hashitem_T *hi;
2648
2649 if ((d = argvars[0].vval.v_dict) != NULL)
2650 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 if (argvars[2].v_type != VAR_UNKNOWN)
2652 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 if (argvars[3].v_type != VAR_UNKNOWN)
2654 EMSG(_(e_invarg));
2655 }
2656
2657 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2658 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2659 {
2660 if (!HASHITEM_EMPTY(hi))
2661 {
2662 --todo;
2663 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2664 ++n;
2665 }
2666 }
2667 }
2668 }
2669 else
2670 EMSG2(_(e_listdictarg), "count()");
2671 rettv->vval.v_number = n;
2672}
2673
2674/*
2675 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2676 *
2677 * Checks the existence of a cscope connection.
2678 */
2679 static void
2680f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2681{
2682#ifdef FEAT_CSCOPE
2683 int num = 0;
2684 char_u *dbpath = NULL;
2685 char_u *prepend = NULL;
2686 char_u buf[NUMBUFLEN];
2687
2688 if (argvars[0].v_type != VAR_UNKNOWN
2689 && argvars[1].v_type != VAR_UNKNOWN)
2690 {
2691 num = (int)get_tv_number(&argvars[0]);
2692 dbpath = get_tv_string(&argvars[1]);
2693 if (argvars[2].v_type != VAR_UNKNOWN)
2694 prepend = get_tv_string_buf(&argvars[2], buf);
2695 }
2696
2697 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2698#endif
2699}
2700
2701/*
2702 * "cursor(lnum, col)" function, or
2703 * "cursor(list)"
2704 *
2705 * Moves the cursor to the specified line and column.
2706 * Returns 0 when the position could be set, -1 otherwise.
2707 */
2708 static void
2709f_cursor(typval_T *argvars, typval_T *rettv)
2710{
2711 long line, col;
2712#ifdef FEAT_VIRTUALEDIT
2713 long coladd = 0;
2714#endif
2715 int set_curswant = TRUE;
2716
2717 rettv->vval.v_number = -1;
2718 if (argvars[1].v_type == VAR_UNKNOWN)
2719 {
2720 pos_T pos;
2721 colnr_T curswant = -1;
2722
2723 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2724 {
2725 EMSG(_(e_invarg));
2726 return;
2727 }
2728 line = pos.lnum;
2729 col = pos.col;
2730#ifdef FEAT_VIRTUALEDIT
2731 coladd = pos.coladd;
2732#endif
2733 if (curswant >= 0)
2734 {
2735 curwin->w_curswant = curswant - 1;
2736 set_curswant = FALSE;
2737 }
2738 }
2739 else
2740 {
2741 line = get_tv_lnum(argvars);
2742 col = (long)get_tv_number_chk(&argvars[1], NULL);
2743#ifdef FEAT_VIRTUALEDIT
2744 if (argvars[2].v_type != VAR_UNKNOWN)
2745 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2746#endif
2747 }
2748 if (line < 0 || col < 0
2749#ifdef FEAT_VIRTUALEDIT
2750 || coladd < 0
2751#endif
2752 )
2753 return; /* type error; errmsg already given */
2754 if (line > 0)
2755 curwin->w_cursor.lnum = line;
2756 if (col > 0)
2757 curwin->w_cursor.col = col - 1;
2758#ifdef FEAT_VIRTUALEDIT
2759 curwin->w_cursor.coladd = coladd;
2760#endif
2761
2762 /* Make sure the cursor is in a valid position. */
2763 check_cursor();
2764#ifdef FEAT_MBYTE
2765 /* Correct cursor for multi-byte character. */
2766 if (has_mbyte)
2767 mb_adjust_cursor();
2768#endif
2769
2770 curwin->w_set_curswant = set_curswant;
2771 rettv->vval.v_number = 0;
2772}
2773
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002774#ifdef WIN3264
2775/*
2776 * "debugbreak()" function
2777 */
2778 static void
2779f_debugbreak(typval_T *argvars, typval_T *rettv)
2780{
2781 int pid;
2782
2783 rettv->vval.v_number = FAIL;
2784 pid = (int)get_tv_number(&argvars[0]);
2785 if (pid == 0)
2786 EMSG(_(e_invarg));
2787 else
2788 {
2789 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2790
2791 if (hProcess != NULL)
2792 {
2793 DebugBreakProcess(hProcess);
2794 CloseHandle(hProcess);
2795 rettv->vval.v_number = OK;
2796 }
2797 }
2798}
2799#endif
2800
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002801/*
2802 * "deepcopy()" function
2803 */
2804 static void
2805f_deepcopy(typval_T *argvars, typval_T *rettv)
2806{
2807 int noref = 0;
2808 int copyID;
2809
2810 if (argvars[1].v_type != VAR_UNKNOWN)
2811 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2812 if (noref < 0 || noref > 1)
2813 EMSG(_(e_invarg));
2814 else
2815 {
2816 copyID = get_copyID();
2817 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2818 }
2819}
2820
2821/*
2822 * "delete()" function
2823 */
2824 static void
2825f_delete(typval_T *argvars, typval_T *rettv)
2826{
2827 char_u nbuf[NUMBUFLEN];
2828 char_u *name;
2829 char_u *flags;
2830
2831 rettv->vval.v_number = -1;
2832 if (check_restricted() || check_secure())
2833 return;
2834
2835 name = get_tv_string(&argvars[0]);
2836 if (name == NULL || *name == NUL)
2837 {
2838 EMSG(_(e_invarg));
2839 return;
2840 }
2841
2842 if (argvars[1].v_type != VAR_UNKNOWN)
2843 flags = get_tv_string_buf(&argvars[1], nbuf);
2844 else
2845 flags = (char_u *)"";
2846
2847 if (*flags == NUL)
2848 /* delete a file */
2849 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2850 else if (STRCMP(flags, "d") == 0)
2851 /* delete an empty directory */
2852 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2853 else if (STRCMP(flags, "rf") == 0)
2854 /* delete a directory recursively */
2855 rettv->vval.v_number = delete_recursive(name);
2856 else
2857 EMSG2(_(e_invexpr2), flags);
2858}
2859
2860/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002861 * "deletebufline()" function
2862 */
2863 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002864f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002865{
2866 buf_T *buf;
2867 linenr_T first, last;
2868 linenr_T lnum;
2869 long count;
2870 int is_curbuf;
2871 buf_T *curbuf_save = NULL;
2872 win_T *curwin_save = NULL;
2873 tabpage_T *tp;
2874 win_T *wp;
2875
2876 buf = get_buf_tv(&argvars[0], FALSE);
2877 if (buf == NULL)
2878 {
2879 rettv->vval.v_number = 1; /* FAIL */
2880 return;
2881 }
2882 is_curbuf = buf == curbuf;
2883
2884 first = get_tv_lnum_buf(&argvars[1], buf);
2885 if (argvars[2].v_type != VAR_UNKNOWN)
2886 last = get_tv_lnum_buf(&argvars[2], buf);
2887 else
2888 last = first;
2889
2890 if (buf->b_ml.ml_mfp == NULL || first < 1
2891 || first > buf->b_ml.ml_line_count || last < first)
2892 {
2893 rettv->vval.v_number = 1; /* FAIL */
2894 return;
2895 }
2896
2897 if (!is_curbuf)
2898 {
2899 curbuf_save = curbuf;
2900 curwin_save = curwin;
2901 curbuf = buf;
2902 find_win_for_curbuf();
2903 }
2904 if (last > curbuf->b_ml.ml_line_count)
2905 last = curbuf->b_ml.ml_line_count;
2906 count = last - first + 1;
2907
2908 // When coming here from Insert mode, sync undo, so that this can be
2909 // undone separately from what was previously inserted.
2910 if (u_sync_once == 2)
2911 {
2912 u_sync_once = 1; // notify that u_sync() was called
2913 u_sync(TRUE);
2914 }
2915
2916 if (u_save(first - 1, last + 1) == FAIL)
2917 {
2918 rettv->vval.v_number = 1; /* FAIL */
2919 return;
2920 }
2921
2922 for (lnum = first; lnum <= last; ++lnum)
2923 ml_delete(first, TRUE);
2924
2925 FOR_ALL_TAB_WINDOWS(tp, wp)
2926 if (wp->w_buffer == buf)
2927 {
2928 if (wp->w_cursor.lnum > last)
2929 wp->w_cursor.lnum -= count;
2930 else if (wp->w_cursor.lnum> first)
2931 wp->w_cursor.lnum = first;
2932 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2933 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2934 }
2935 check_cursor_col();
2936 deleted_lines_mark(first, count);
2937
2938 if (!is_curbuf)
2939 {
2940 curbuf = curbuf_save;
2941 curwin = curwin_save;
2942 }
2943}
2944
2945/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002946 * "did_filetype()" function
2947 */
2948 static void
2949f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2950{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002951 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002952}
2953
2954/*
2955 * "diff_filler()" function
2956 */
2957 static void
2958f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2959{
2960#ifdef FEAT_DIFF
2961 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2962#endif
2963}
2964
2965/*
2966 * "diff_hlID()" function
2967 */
2968 static void
2969f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2970{
2971#ifdef FEAT_DIFF
2972 linenr_T lnum = get_tv_lnum(argvars);
2973 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002974 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975 static int fnum = 0;
2976 static int change_start = 0;
2977 static int change_end = 0;
2978 static hlf_T hlID = (hlf_T)0;
2979 int filler_lines;
2980 int col;
2981
2982 if (lnum < 0) /* ignore type error in {lnum} arg */
2983 lnum = 0;
2984 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002985 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002986 || fnum != curbuf->b_fnum)
2987 {
2988 /* New line, buffer, change: need to get the values. */
2989 filler_lines = diff_check(curwin, lnum);
2990 if (filler_lines < 0)
2991 {
2992 if (filler_lines == -1)
2993 {
2994 change_start = MAXCOL;
2995 change_end = -1;
2996 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2997 hlID = HLF_ADD; /* added line */
2998 else
2999 hlID = HLF_CHD; /* changed line */
3000 }
3001 else
3002 hlID = HLF_ADD; /* added line */
3003 }
3004 else
3005 hlID = (hlf_T)0;
3006 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003007 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003008 fnum = curbuf->b_fnum;
3009 }
3010
3011 if (hlID == HLF_CHD || hlID == HLF_TXD)
3012 {
3013 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
3014 if (col >= change_start && col <= change_end)
3015 hlID = HLF_TXD; /* changed text */
3016 else
3017 hlID = HLF_CHD; /* changed line */
3018 }
3019 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3020#endif
3021}
3022
3023/*
3024 * "empty({expr})" function
3025 */
3026 static void
3027f_empty(typval_T *argvars, typval_T *rettv)
3028{
3029 int n = FALSE;
3030
3031 switch (argvars[0].v_type)
3032 {
3033 case VAR_STRING:
3034 case VAR_FUNC:
3035 n = argvars[0].vval.v_string == NULL
3036 || *argvars[0].vval.v_string == NUL;
3037 break;
3038 case VAR_PARTIAL:
3039 n = FALSE;
3040 break;
3041 case VAR_NUMBER:
3042 n = argvars[0].vval.v_number == 0;
3043 break;
3044 case VAR_FLOAT:
3045#ifdef FEAT_FLOAT
3046 n = argvars[0].vval.v_float == 0.0;
3047 break;
3048#endif
3049 case VAR_LIST:
3050 n = argvars[0].vval.v_list == NULL
3051 || argvars[0].vval.v_list->lv_first == NULL;
3052 break;
3053 case VAR_DICT:
3054 n = argvars[0].vval.v_dict == NULL
3055 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3056 break;
3057 case VAR_SPECIAL:
3058 n = argvars[0].vval.v_number != VVAL_TRUE;
3059 break;
3060
3061 case VAR_JOB:
3062#ifdef FEAT_JOB_CHANNEL
3063 n = argvars[0].vval.v_job == NULL
3064 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3065 break;
3066#endif
3067 case VAR_CHANNEL:
3068#ifdef FEAT_JOB_CHANNEL
3069 n = argvars[0].vval.v_channel == NULL
3070 || !channel_is_open(argvars[0].vval.v_channel);
3071 break;
3072#endif
3073 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003074 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 n = TRUE;
3076 break;
3077 }
3078
3079 rettv->vval.v_number = n;
3080}
3081
3082/*
3083 * "escape({string}, {chars})" function
3084 */
3085 static void
3086f_escape(typval_T *argvars, typval_T *rettv)
3087{
3088 char_u buf[NUMBUFLEN];
3089
3090 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
3091 get_tv_string_buf(&argvars[1], buf));
3092 rettv->v_type = VAR_STRING;
3093}
3094
3095/*
3096 * "eval()" function
3097 */
3098 static void
3099f_eval(typval_T *argvars, typval_T *rettv)
3100{
3101 char_u *s, *p;
3102
3103 s = get_tv_string_chk(&argvars[0]);
3104 if (s != NULL)
3105 s = skipwhite(s);
3106
3107 p = s;
3108 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3109 {
3110 if (p != NULL && !aborting())
3111 EMSG2(_(e_invexpr2), p);
3112 need_clr_eos = FALSE;
3113 rettv->v_type = VAR_NUMBER;
3114 rettv->vval.v_number = 0;
3115 }
3116 else if (*s != NUL)
3117 EMSG(_(e_trailing));
3118}
3119
3120/*
3121 * "eventhandler()" function
3122 */
3123 static void
3124f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3125{
3126 rettv->vval.v_number = vgetc_busy;
3127}
3128
3129/*
3130 * "executable()" function
3131 */
3132 static void
3133f_executable(typval_T *argvars, typval_T *rettv)
3134{
3135 char_u *name = get_tv_string(&argvars[0]);
3136
3137 /* Check in $PATH and also check directly if there is a directory name. */
3138 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3139 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3140}
3141
3142static garray_T redir_execute_ga;
3143
3144/*
3145 * Append "value[value_len]" to the execute() output.
3146 */
3147 void
3148execute_redir_str(char_u *value, int value_len)
3149{
3150 int len;
3151
3152 if (value_len == -1)
3153 len = (int)STRLEN(value); /* Append the entire string */
3154 else
3155 len = value_len; /* Append only "value_len" characters */
3156 if (ga_grow(&redir_execute_ga, len) == OK)
3157 {
3158 mch_memmove((char *)redir_execute_ga.ga_data
3159 + redir_execute_ga.ga_len, value, len);
3160 redir_execute_ga.ga_len += len;
3161 }
3162}
3163
3164/*
3165 * Get next line from a list.
3166 * Called by do_cmdline() to get the next line.
3167 * Returns allocated string, or NULL for end of function.
3168 */
3169
3170 static char_u *
3171get_list_line(
3172 int c UNUSED,
3173 void *cookie,
3174 int indent UNUSED)
3175{
3176 listitem_T **p = (listitem_T **)cookie;
3177 listitem_T *item = *p;
3178 char_u buf[NUMBUFLEN];
3179 char_u *s;
3180
3181 if (item == NULL)
3182 return NULL;
3183 s = get_tv_string_buf_chk(&item->li_tv, buf);
3184 *p = item->li_next;
3185 return s == NULL ? NULL : vim_strsave(s);
3186}
3187
3188/*
3189 * "execute()" function
3190 */
3191 static void
3192f_execute(typval_T *argvars, typval_T *rettv)
3193{
3194 char_u *cmd = NULL;
3195 list_T *list = NULL;
3196 int save_msg_silent = msg_silent;
3197 int save_emsg_silent = emsg_silent;
3198 int save_emsg_noredir = emsg_noredir;
3199 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003200 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003201 garray_T save_ga;
3202
3203 rettv->vval.v_string = NULL;
3204 rettv->v_type = VAR_STRING;
3205
3206 if (argvars[0].v_type == VAR_LIST)
3207 {
3208 list = argvars[0].vval.v_list;
3209 if (list == NULL || list->lv_first == NULL)
3210 /* empty list, no commands, empty output */
3211 return;
3212 ++list->lv_refcount;
3213 }
3214 else
3215 {
3216 cmd = get_tv_string_chk(&argvars[0]);
3217 if (cmd == NULL)
3218 return;
3219 }
3220
3221 if (argvars[1].v_type != VAR_UNKNOWN)
3222 {
3223 char_u buf[NUMBUFLEN];
3224 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
3225
3226 if (s == NULL)
3227 return;
3228 if (STRNCMP(s, "silent", 6) == 0)
3229 ++msg_silent;
3230 if (STRCMP(s, "silent!") == 0)
3231 {
3232 emsg_silent = TRUE;
3233 emsg_noredir = TRUE;
3234 }
3235 }
3236 else
3237 ++msg_silent;
3238
3239 if (redir_execute)
3240 save_ga = redir_execute_ga;
3241 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3242 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003243 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003244
3245 if (cmd != NULL)
3246 do_cmdline_cmd(cmd);
3247 else
3248 {
3249 listitem_T *item = list->lv_first;
3250
3251 do_cmdline(NULL, get_list_line, (void *)&item,
3252 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3253 --list->lv_refcount;
3254 }
3255
Bram Moolenaard297f352017-01-29 20:31:21 +01003256 /* Need to append a NUL to the result. */
3257 if (ga_grow(&redir_execute_ga, 1) == OK)
3258 {
3259 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3260 rettv->vval.v_string = redir_execute_ga.ga_data;
3261 }
3262 else
3263 {
3264 ga_clear(&redir_execute_ga);
3265 rettv->vval.v_string = NULL;
3266 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267 msg_silent = save_msg_silent;
3268 emsg_silent = save_emsg_silent;
3269 emsg_noredir = save_emsg_noredir;
3270
3271 redir_execute = save_redir_execute;
3272 if (redir_execute)
3273 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003274 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003275
3276 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3277 * line. Put it back in the first column. */
3278 msg_col = 0;
3279}
3280
3281/*
3282 * "exepath()" function
3283 */
3284 static void
3285f_exepath(typval_T *argvars, typval_T *rettv)
3286{
3287 char_u *p = NULL;
3288
3289 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3290 rettv->v_type = VAR_STRING;
3291 rettv->vval.v_string = p;
3292}
3293
3294/*
3295 * "exists()" function
3296 */
3297 static void
3298f_exists(typval_T *argvars, typval_T *rettv)
3299{
3300 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003302
3303 p = get_tv_string(&argvars[0]);
3304 if (*p == '$') /* environment variable */
3305 {
3306 /* first try "normal" environment variables (fast) */
3307 if (mch_getenv(p + 1) != NULL)
3308 n = TRUE;
3309 else
3310 {
3311 /* try expanding things like $VIM and ${HOME} */
3312 p = expand_env_save(p);
3313 if (p != NULL && *p != '$')
3314 n = TRUE;
3315 vim_free(p);
3316 }
3317 }
3318 else if (*p == '&' || *p == '+') /* option */
3319 {
3320 n = (get_option_tv(&p, NULL, TRUE) == OK);
3321 if (*skipwhite(p) != NUL)
3322 n = FALSE; /* trailing garbage */
3323 }
3324 else if (*p == '*') /* internal or user defined function */
3325 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003326 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003327 }
3328 else if (*p == ':')
3329 {
3330 n = cmd_exists(p + 1);
3331 }
3332 else if (*p == '#')
3333 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003334 if (p[1] == '#')
3335 n = autocmd_supported(p + 2);
3336 else
3337 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003338 }
3339 else /* internal variable */
3340 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003341 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342 }
3343
3344 rettv->vval.v_number = n;
3345}
3346
3347#ifdef FEAT_FLOAT
3348/*
3349 * "exp()" function
3350 */
3351 static void
3352f_exp(typval_T *argvars, typval_T *rettv)
3353{
3354 float_T f = 0.0;
3355
3356 rettv->v_type = VAR_FLOAT;
3357 if (get_float_arg(argvars, &f) == OK)
3358 rettv->vval.v_float = exp(f);
3359 else
3360 rettv->vval.v_float = 0.0;
3361}
3362#endif
3363
3364/*
3365 * "expand()" function
3366 */
3367 static void
3368f_expand(typval_T *argvars, typval_T *rettv)
3369{
3370 char_u *s;
3371 int len;
3372 char_u *errormsg;
3373 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3374 expand_T xpc;
3375 int error = FALSE;
3376 char_u *result;
3377
3378 rettv->v_type = VAR_STRING;
3379 if (argvars[1].v_type != VAR_UNKNOWN
3380 && argvars[2].v_type != VAR_UNKNOWN
3381 && get_tv_number_chk(&argvars[2], &error)
3382 && !error)
3383 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003384 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003385 }
3386
3387 s = get_tv_string(&argvars[0]);
3388 if (*s == '%' || *s == '#' || *s == '<')
3389 {
3390 ++emsg_off;
3391 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3392 --emsg_off;
3393 if (rettv->v_type == VAR_LIST)
3394 {
3395 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3396 list_append_string(rettv->vval.v_list, result, -1);
3397 else
3398 vim_free(result);
3399 }
3400 else
3401 rettv->vval.v_string = result;
3402 }
3403 else
3404 {
3405 /* When the optional second argument is non-zero, don't remove matches
3406 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3407 if (argvars[1].v_type != VAR_UNKNOWN
3408 && get_tv_number_chk(&argvars[1], &error))
3409 options |= WILD_KEEP_ALL;
3410 if (!error)
3411 {
3412 ExpandInit(&xpc);
3413 xpc.xp_context = EXPAND_FILES;
3414 if (p_wic)
3415 options += WILD_ICASE;
3416 if (rettv->v_type == VAR_STRING)
3417 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3418 options, WILD_ALL);
3419 else if (rettv_list_alloc(rettv) != FAIL)
3420 {
3421 int i;
3422
3423 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3424 for (i = 0; i < xpc.xp_numfiles; i++)
3425 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3426 ExpandCleanup(&xpc);
3427 }
3428 }
3429 else
3430 rettv->vval.v_string = NULL;
3431 }
3432}
3433
3434/*
3435 * "extend(list, list [, idx])" function
3436 * "extend(dict, dict [, action])" function
3437 */
3438 static void
3439f_extend(typval_T *argvars, typval_T *rettv)
3440{
3441 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3442
3443 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3444 {
3445 list_T *l1, *l2;
3446 listitem_T *item;
3447 long before;
3448 int error = FALSE;
3449
3450 l1 = argvars[0].vval.v_list;
3451 l2 = argvars[1].vval.v_list;
3452 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3453 && l2 != NULL)
3454 {
3455 if (argvars[2].v_type != VAR_UNKNOWN)
3456 {
3457 before = (long)get_tv_number_chk(&argvars[2], &error);
3458 if (error)
3459 return; /* type error; errmsg already given */
3460
3461 if (before == l1->lv_len)
3462 item = NULL;
3463 else
3464 {
3465 item = list_find(l1, before);
3466 if (item == NULL)
3467 {
3468 EMSGN(_(e_listidx), before);
3469 return;
3470 }
3471 }
3472 }
3473 else
3474 item = NULL;
3475 list_extend(l1, l2, item);
3476
3477 copy_tv(&argvars[0], rettv);
3478 }
3479 }
3480 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3481 {
3482 dict_T *d1, *d2;
3483 char_u *action;
3484 int i;
3485
3486 d1 = argvars[0].vval.v_dict;
3487 d2 = argvars[1].vval.v_dict;
3488 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3489 && d2 != NULL)
3490 {
3491 /* Check the third argument. */
3492 if (argvars[2].v_type != VAR_UNKNOWN)
3493 {
3494 static char *(av[]) = {"keep", "force", "error"};
3495
3496 action = get_tv_string_chk(&argvars[2]);
3497 if (action == NULL)
3498 return; /* type error; errmsg already given */
3499 for (i = 0; i < 3; ++i)
3500 if (STRCMP(action, av[i]) == 0)
3501 break;
3502 if (i == 3)
3503 {
3504 EMSG2(_(e_invarg2), action);
3505 return;
3506 }
3507 }
3508 else
3509 action = (char_u *)"force";
3510
3511 dict_extend(d1, d2, action);
3512
3513 copy_tv(&argvars[0], rettv);
3514 }
3515 }
3516 else
3517 EMSG2(_(e_listdictarg), "extend()");
3518}
3519
3520/*
3521 * "feedkeys()" function
3522 */
3523 static void
3524f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3525{
3526 int remap = TRUE;
3527 int insert = FALSE;
3528 char_u *keys, *flags;
3529 char_u nbuf[NUMBUFLEN];
3530 int typed = FALSE;
3531 int execute = FALSE;
3532 int dangerous = FALSE;
3533 char_u *keys_esc;
3534
3535 /* This is not allowed in the sandbox. If the commands would still be
3536 * executed in the sandbox it would be OK, but it probably happens later,
3537 * when "sandbox" is no longer set. */
3538 if (check_secure())
3539 return;
3540
3541 keys = get_tv_string(&argvars[0]);
3542
3543 if (argvars[1].v_type != VAR_UNKNOWN)
3544 {
3545 flags = get_tv_string_buf(&argvars[1], nbuf);
3546 for ( ; *flags != NUL; ++flags)
3547 {
3548 switch (*flags)
3549 {
3550 case 'n': remap = FALSE; break;
3551 case 'm': remap = TRUE; break;
3552 case 't': typed = TRUE; break;
3553 case 'i': insert = TRUE; break;
3554 case 'x': execute = TRUE; break;
3555 case '!': dangerous = TRUE; break;
3556 }
3557 }
3558 }
3559
3560 if (*keys != NUL || execute)
3561 {
3562 /* Need to escape K_SPECIAL and CSI before putting the string in the
3563 * typeahead buffer. */
3564 keys_esc = vim_strsave_escape_csi(keys);
3565 if (keys_esc != NULL)
3566 {
3567 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3568 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3569 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003570 if (vgetc_busy
3571#ifdef FEAT_TIMERS
3572 || timer_busy
3573#endif
3574 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003575 typebuf_was_filled = TRUE;
3576 if (execute)
3577 {
3578 int save_msg_scroll = msg_scroll;
3579
3580 /* Avoid a 1 second delay when the keys start Insert mode. */
3581 msg_scroll = FALSE;
3582
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003583 if (!dangerous)
3584 ++ex_normal_busy;
Bram Moolenaar655a82a2018-05-08 22:01:07 +02003585 exec_normal(TRUE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003586 if (!dangerous)
3587 --ex_normal_busy;
3588
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589 msg_scroll |= save_msg_scroll;
3590 }
3591 }
3592 }
3593}
3594
3595/*
3596 * "filereadable()" function
3597 */
3598 static void
3599f_filereadable(typval_T *argvars, typval_T *rettv)
3600{
3601 int fd;
3602 char_u *p;
3603 int n;
3604
3605#ifndef O_NONBLOCK
3606# define O_NONBLOCK 0
3607#endif
3608 p = get_tv_string(&argvars[0]);
3609 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3610 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3611 {
3612 n = TRUE;
3613 close(fd);
3614 }
3615 else
3616 n = FALSE;
3617
3618 rettv->vval.v_number = n;
3619}
3620
3621/*
3622 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3623 * rights to write into.
3624 */
3625 static void
3626f_filewritable(typval_T *argvars, typval_T *rettv)
3627{
3628 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3629}
3630
3631 static void
3632findfilendir(
3633 typval_T *argvars UNUSED,
3634 typval_T *rettv,
3635 int find_what UNUSED)
3636{
3637#ifdef FEAT_SEARCHPATH
3638 char_u *fname;
3639 char_u *fresult = NULL;
3640 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3641 char_u *p;
3642 char_u pathbuf[NUMBUFLEN];
3643 int count = 1;
3644 int first = TRUE;
3645 int error = FALSE;
3646#endif
3647
3648 rettv->vval.v_string = NULL;
3649 rettv->v_type = VAR_STRING;
3650
3651#ifdef FEAT_SEARCHPATH
3652 fname = get_tv_string(&argvars[0]);
3653
3654 if (argvars[1].v_type != VAR_UNKNOWN)
3655 {
3656 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3657 if (p == NULL)
3658 error = TRUE;
3659 else
3660 {
3661 if (*p != NUL)
3662 path = p;
3663
3664 if (argvars[2].v_type != VAR_UNKNOWN)
3665 count = (int)get_tv_number_chk(&argvars[2], &error);
3666 }
3667 }
3668
3669 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3670 error = TRUE;
3671
3672 if (*fname != NUL && !error)
3673 {
3674 do
3675 {
3676 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3677 vim_free(fresult);
3678 fresult = find_file_in_path_option(first ? fname : NULL,
3679 first ? (int)STRLEN(fname) : 0,
3680 0, first, path,
3681 find_what,
3682 curbuf->b_ffname,
3683 find_what == FINDFILE_DIR
3684 ? (char_u *)"" : curbuf->b_p_sua);
3685 first = FALSE;
3686
3687 if (fresult != NULL && rettv->v_type == VAR_LIST)
3688 list_append_string(rettv->vval.v_list, fresult, -1);
3689
3690 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3691 }
3692
3693 if (rettv->v_type == VAR_STRING)
3694 rettv->vval.v_string = fresult;
3695#endif
3696}
3697
3698/*
3699 * "filter()" function
3700 */
3701 static void
3702f_filter(typval_T *argvars, typval_T *rettv)
3703{
3704 filter_map(argvars, rettv, FALSE);
3705}
3706
3707/*
3708 * "finddir({fname}[, {path}[, {count}]])" function
3709 */
3710 static void
3711f_finddir(typval_T *argvars, typval_T *rettv)
3712{
3713 findfilendir(argvars, rettv, FINDFILE_DIR);
3714}
3715
3716/*
3717 * "findfile({fname}[, {path}[, {count}]])" function
3718 */
3719 static void
3720f_findfile(typval_T *argvars, typval_T *rettv)
3721{
3722 findfilendir(argvars, rettv, FINDFILE_FILE);
3723}
3724
3725#ifdef FEAT_FLOAT
3726/*
3727 * "float2nr({float})" function
3728 */
3729 static void
3730f_float2nr(typval_T *argvars, typval_T *rettv)
3731{
3732 float_T f = 0.0;
3733
3734 if (get_float_arg(argvars, &f) == OK)
3735 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003736 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003737 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003738 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003739 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740 else
3741 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742 }
3743}
3744
3745/*
3746 * "floor({float})" function
3747 */
3748 static void
3749f_floor(typval_T *argvars, typval_T *rettv)
3750{
3751 float_T f = 0.0;
3752
3753 rettv->v_type = VAR_FLOAT;
3754 if (get_float_arg(argvars, &f) == OK)
3755 rettv->vval.v_float = floor(f);
3756 else
3757 rettv->vval.v_float = 0.0;
3758}
3759
3760/*
3761 * "fmod()" function
3762 */
3763 static void
3764f_fmod(typval_T *argvars, typval_T *rettv)
3765{
3766 float_T fx = 0.0, fy = 0.0;
3767
3768 rettv->v_type = VAR_FLOAT;
3769 if (get_float_arg(argvars, &fx) == OK
3770 && get_float_arg(&argvars[1], &fy) == OK)
3771 rettv->vval.v_float = fmod(fx, fy);
3772 else
3773 rettv->vval.v_float = 0.0;
3774}
3775#endif
3776
3777/*
3778 * "fnameescape({string})" function
3779 */
3780 static void
3781f_fnameescape(typval_T *argvars, typval_T *rettv)
3782{
3783 rettv->vval.v_string = vim_strsave_fnameescape(
3784 get_tv_string(&argvars[0]), FALSE);
3785 rettv->v_type = VAR_STRING;
3786}
3787
3788/*
3789 * "fnamemodify({fname}, {mods})" function
3790 */
3791 static void
3792f_fnamemodify(typval_T *argvars, typval_T *rettv)
3793{
3794 char_u *fname;
3795 char_u *mods;
3796 int usedlen = 0;
3797 int len;
3798 char_u *fbuf = NULL;
3799 char_u buf[NUMBUFLEN];
3800
3801 fname = get_tv_string_chk(&argvars[0]);
3802 mods = get_tv_string_buf_chk(&argvars[1], buf);
3803 if (fname == NULL || mods == NULL)
3804 fname = NULL;
3805 else
3806 {
3807 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003808 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003809 }
3810
3811 rettv->v_type = VAR_STRING;
3812 if (fname == NULL)
3813 rettv->vval.v_string = NULL;
3814 else
3815 rettv->vval.v_string = vim_strnsave(fname, len);
3816 vim_free(fbuf);
3817}
3818
3819static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3820
3821/*
3822 * "foldclosed()" function
3823 */
3824 static void
3825foldclosed_both(
3826 typval_T *argvars UNUSED,
3827 typval_T *rettv,
3828 int end UNUSED)
3829{
3830#ifdef FEAT_FOLDING
3831 linenr_T lnum;
3832 linenr_T first, last;
3833
3834 lnum = get_tv_lnum(argvars);
3835 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3836 {
3837 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3838 {
3839 if (end)
3840 rettv->vval.v_number = (varnumber_T)last;
3841 else
3842 rettv->vval.v_number = (varnumber_T)first;
3843 return;
3844 }
3845 }
3846#endif
3847 rettv->vval.v_number = -1;
3848}
3849
3850/*
3851 * "foldclosed()" function
3852 */
3853 static void
3854f_foldclosed(typval_T *argvars, typval_T *rettv)
3855{
3856 foldclosed_both(argvars, rettv, FALSE);
3857}
3858
3859/*
3860 * "foldclosedend()" function
3861 */
3862 static void
3863f_foldclosedend(typval_T *argvars, typval_T *rettv)
3864{
3865 foldclosed_both(argvars, rettv, TRUE);
3866}
3867
3868/*
3869 * "foldlevel()" function
3870 */
3871 static void
3872f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3873{
3874#ifdef FEAT_FOLDING
3875 linenr_T lnum;
3876
3877 lnum = get_tv_lnum(argvars);
3878 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3879 rettv->vval.v_number = foldLevel(lnum);
3880#endif
3881}
3882
3883/*
3884 * "foldtext()" function
3885 */
3886 static void
3887f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3888{
3889#ifdef FEAT_FOLDING
3890 linenr_T foldstart;
3891 linenr_T foldend;
3892 char_u *dashes;
3893 linenr_T lnum;
3894 char_u *s;
3895 char_u *r;
3896 int len;
3897 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003898 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003899#endif
3900
3901 rettv->v_type = VAR_STRING;
3902 rettv->vval.v_string = NULL;
3903#ifdef FEAT_FOLDING
3904 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3905 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3906 dashes = get_vim_var_str(VV_FOLDDASHES);
3907 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3908 && dashes != NULL)
3909 {
3910 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003911 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912 if (!linewhite(lnum))
3913 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003914
3915 /* Find interesting text in this line. */
3916 s = skipwhite(ml_get(lnum));
3917 /* skip C comment-start */
3918 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3919 {
3920 s = skipwhite(s + 2);
3921 if (*skipwhite(s) == NUL
3922 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3923 {
3924 s = skipwhite(ml_get(lnum + 1));
3925 if (*s == '*')
3926 s = skipwhite(s + 1);
3927 }
3928 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003929 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003930 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931 r = alloc((unsigned)(STRLEN(txt)
3932 + STRLEN(dashes) /* for %s */
3933 + 20 /* for %3ld */
3934 + STRLEN(s))); /* concatenated */
3935 if (r != NULL)
3936 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003937 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003938 len = (int)STRLEN(r);
3939 STRCAT(r, s);
3940 /* remove 'foldmarker' and 'commentstring' */
3941 foldtext_cleanup(r + len);
3942 rettv->vval.v_string = r;
3943 }
3944 }
3945#endif
3946}
3947
3948/*
3949 * "foldtextresult(lnum)" function
3950 */
3951 static void
3952f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3953{
3954#ifdef FEAT_FOLDING
3955 linenr_T lnum;
3956 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003957 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003958 foldinfo_T foldinfo;
3959 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003960 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003961#endif
3962
3963 rettv->v_type = VAR_STRING;
3964 rettv->vval.v_string = NULL;
3965#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003966 if (entered)
3967 return; /* reject recursive use */
3968 entered = TRUE;
3969
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003970 lnum = get_tv_lnum(argvars);
3971 /* treat illegal types and illegal string values for {lnum} the same */
3972 if (lnum < 0)
3973 lnum = 0;
3974 fold_count = foldedCount(curwin, lnum, &foldinfo);
3975 if (fold_count > 0)
3976 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003977 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3978 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003979 if (text == buf)
3980 text = vim_strsave(text);
3981 rettv->vval.v_string = text;
3982 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003983
3984 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003985#endif
3986}
3987
3988/*
3989 * "foreground()" function
3990 */
3991 static void
3992f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3993{
3994#ifdef FEAT_GUI
3995 if (gui.in_use)
3996 gui_mch_set_foreground();
3997#else
3998# ifdef WIN32
3999 win32_set_foreground();
4000# endif
4001#endif
4002}
4003
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004004 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004005common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004006{
4007 char_u *s;
4008 char_u *name;
4009 int use_string = FALSE;
4010 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004011 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012
4013 if (argvars[0].v_type == VAR_FUNC)
4014 {
4015 /* function(MyFunc, [arg], dict) */
4016 s = argvars[0].vval.v_string;
4017 }
4018 else if (argvars[0].v_type == VAR_PARTIAL
4019 && argvars[0].vval.v_partial != NULL)
4020 {
4021 /* function(dict.MyFunc, [arg]) */
4022 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004023 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004024 }
4025 else
4026 {
4027 /* function('MyFunc', [arg], dict) */
4028 s = get_tv_string(&argvars[0]);
4029 use_string = TRUE;
4030 }
4031
Bram Moolenaar843b8842016-08-21 14:36:15 +02004032 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004033 {
4034 name = s;
4035 trans_name = trans_function_name(&name, FALSE,
4036 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4037 if (*name != NUL)
4038 s = NULL;
4039 }
4040
Bram Moolenaar843b8842016-08-21 14:36:15 +02004041 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4042 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02004043 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004045 else if (trans_name != NULL && (is_funcref
4046 ? find_func(trans_name) == NULL
4047 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004048 EMSG2(_("E700: Unknown function: %s"), s);
4049 else
4050 {
4051 int dict_idx = 0;
4052 int arg_idx = 0;
4053 list_T *list = NULL;
4054
4055 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4056 {
4057 char sid_buf[25];
4058 int off = *s == 's' ? 2 : 5;
4059
4060 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4061 * also be called from another script. Using trans_function_name()
4062 * would also work, but some plugins depend on the name being
4063 * printable text. */
4064 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
4065 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4066 if (name != NULL)
4067 {
4068 STRCPY(name, sid_buf);
4069 STRCAT(name, s + off);
4070 }
4071 }
4072 else
4073 name = vim_strsave(s);
4074
4075 if (argvars[1].v_type != VAR_UNKNOWN)
4076 {
4077 if (argvars[2].v_type != VAR_UNKNOWN)
4078 {
4079 /* function(name, [args], dict) */
4080 arg_idx = 1;
4081 dict_idx = 2;
4082 }
4083 else if (argvars[1].v_type == VAR_DICT)
4084 /* function(name, dict) */
4085 dict_idx = 1;
4086 else
4087 /* function(name, [args]) */
4088 arg_idx = 1;
4089 if (dict_idx > 0)
4090 {
4091 if (argvars[dict_idx].v_type != VAR_DICT)
4092 {
4093 EMSG(_("E922: expected a dict"));
4094 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004095 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004096 }
4097 if (argvars[dict_idx].vval.v_dict == NULL)
4098 dict_idx = 0;
4099 }
4100 if (arg_idx > 0)
4101 {
4102 if (argvars[arg_idx].v_type != VAR_LIST)
4103 {
4104 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4105 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004106 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107 }
4108 list = argvars[arg_idx].vval.v_list;
4109 if (list == NULL || list->lv_len == 0)
4110 arg_idx = 0;
4111 }
4112 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004113 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004114 {
4115 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4116
4117 /* result is a VAR_PARTIAL */
4118 if (pt == NULL)
4119 vim_free(name);
4120 else
4121 {
4122 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4123 {
4124 listitem_T *li;
4125 int i = 0;
4126 int arg_len = 0;
4127 int lv_len = 0;
4128
4129 if (arg_pt != NULL)
4130 arg_len = arg_pt->pt_argc;
4131 if (list != NULL)
4132 lv_len = list->lv_len;
4133 pt->pt_argc = arg_len + lv_len;
4134 pt->pt_argv = (typval_T *)alloc(
4135 sizeof(typval_T) * pt->pt_argc);
4136 if (pt->pt_argv == NULL)
4137 {
4138 vim_free(pt);
4139 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004140 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004142 for (i = 0; i < arg_len; i++)
4143 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4144 if (lv_len > 0)
4145 for (li = list->lv_first; li != NULL;
4146 li = li->li_next)
4147 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 }
4149
4150 /* For "function(dict.func, [], dict)" and "func" is a partial
4151 * use "dict". That is backwards compatible. */
4152 if (dict_idx > 0)
4153 {
4154 /* The dict is bound explicitly, pt_auto is FALSE. */
4155 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4156 ++pt->pt_dict->dv_refcount;
4157 }
4158 else if (arg_pt != NULL)
4159 {
4160 /* If the dict was bound automatically the result is also
4161 * bound automatically. */
4162 pt->pt_dict = arg_pt->pt_dict;
4163 pt->pt_auto = arg_pt->pt_auto;
4164 if (pt->pt_dict != NULL)
4165 ++pt->pt_dict->dv_refcount;
4166 }
4167
4168 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004169 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4170 {
4171 pt->pt_func = arg_pt->pt_func;
4172 func_ptr_ref(pt->pt_func);
4173 vim_free(name);
4174 }
4175 else if (is_funcref)
4176 {
4177 pt->pt_func = find_func(trans_name);
4178 func_ptr_ref(pt->pt_func);
4179 vim_free(name);
4180 }
4181 else
4182 {
4183 pt->pt_name = name;
4184 func_ref(name);
4185 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004186 }
4187 rettv->v_type = VAR_PARTIAL;
4188 rettv->vval.v_partial = pt;
4189 }
4190 else
4191 {
4192 /* result is a VAR_FUNC */
4193 rettv->v_type = VAR_FUNC;
4194 rettv->vval.v_string = name;
4195 func_ref(name);
4196 }
4197 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004198theend:
4199 vim_free(trans_name);
4200}
4201
4202/*
4203 * "funcref()" function
4204 */
4205 static void
4206f_funcref(typval_T *argvars, typval_T *rettv)
4207{
4208 common_function(argvars, rettv, TRUE);
4209}
4210
4211/*
4212 * "function()" function
4213 */
4214 static void
4215f_function(typval_T *argvars, typval_T *rettv)
4216{
4217 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004218}
4219
4220/*
4221 * "garbagecollect()" function
4222 */
4223 static void
4224f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4225{
4226 /* This is postponed until we are back at the toplevel, because we may be
4227 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4228 want_garbage_collect = TRUE;
4229
4230 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
4231 garbage_collect_at_exit = TRUE;
4232}
4233
4234/*
4235 * "get()" function
4236 */
4237 static void
4238f_get(typval_T *argvars, typval_T *rettv)
4239{
4240 listitem_T *li;
4241 list_T *l;
4242 dictitem_T *di;
4243 dict_T *d;
4244 typval_T *tv = NULL;
4245
4246 if (argvars[0].v_type == VAR_LIST)
4247 {
4248 if ((l = argvars[0].vval.v_list) != NULL)
4249 {
4250 int error = FALSE;
4251
4252 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
4253 if (!error && li != NULL)
4254 tv = &li->li_tv;
4255 }
4256 }
4257 else if (argvars[0].v_type == VAR_DICT)
4258 {
4259 if ((d = argvars[0].vval.v_dict) != NULL)
4260 {
4261 di = dict_find(d, get_tv_string(&argvars[1]), -1);
4262 if (di != NULL)
4263 tv = &di->di_tv;
4264 }
4265 }
4266 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4267 {
4268 partial_T *pt;
4269 partial_T fref_pt;
4270
4271 if (argvars[0].v_type == VAR_PARTIAL)
4272 pt = argvars[0].vval.v_partial;
4273 else
4274 {
4275 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4276 fref_pt.pt_name = argvars[0].vval.v_string;
4277 pt = &fref_pt;
4278 }
4279
4280 if (pt != NULL)
4281 {
4282 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004283 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004284
4285 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4286 {
4287 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004288 n = partial_name(pt);
4289 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004290 rettv->vval.v_string = NULL;
4291 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004292 {
4293 rettv->vval.v_string = vim_strsave(n);
4294 if (rettv->v_type == VAR_FUNC)
4295 func_ref(rettv->vval.v_string);
4296 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004297 }
4298 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004299 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004300 else if (STRCMP(what, "args") == 0)
4301 {
4302 rettv->v_type = VAR_LIST;
4303 if (rettv_list_alloc(rettv) == OK)
4304 {
4305 int i;
4306
4307 for (i = 0; i < pt->pt_argc; ++i)
4308 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4309 }
4310 }
4311 else
4312 EMSG2(_(e_invarg2), what);
4313 return;
4314 }
4315 }
4316 else
4317 EMSG2(_(e_listdictarg), "get()");
4318
4319 if (tv == NULL)
4320 {
4321 if (argvars[2].v_type != VAR_UNKNOWN)
4322 copy_tv(&argvars[2], rettv);
4323 }
4324 else
4325 copy_tv(tv, rettv);
4326}
4327
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004328#ifdef FEAT_SIGNS
4329/*
4330 * Returns information about signs placed in a buffer as list of dicts.
4331 */
4332 static void
4333get_buffer_signs(buf_T *buf, list_T *l)
4334{
4335 signlist_T *sign;
4336
4337 for (sign = buf->b_signlist; sign; sign = sign->next)
4338 {
4339 dict_T *d = dict_alloc();
4340
4341 if (d != NULL)
4342 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02004343 dict_add_number(d, "id", sign->id);
4344 dict_add_number(d, "lnum", sign->lnum);
4345 dict_add_string(d, "name", sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004346
4347 list_append_dict(l, d);
4348 }
4349 }
4350}
4351#endif
4352
4353/*
4354 * Returns buffer options, variables and other attributes in a dictionary.
4355 */
4356 static dict_T *
4357get_buffer_info(buf_T *buf)
4358{
4359 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004360 tabpage_T *tp;
4361 win_T *wp;
4362 list_T *windows;
4363
4364 dict = dict_alloc();
4365 if (dict == NULL)
4366 return NULL;
4367
Bram Moolenaare0be1672018-07-08 16:50:37 +02004368 dict_add_number(dict, "bufnr", buf->b_fnum);
4369 dict_add_string(dict, "name", buf->b_ffname);
4370 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4371 : buflist_findlnum(buf));
4372 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4373 dict_add_number(dict, "listed", buf->b_p_bl);
4374 dict_add_number(dict, "changed", bufIsChanged(buf));
4375 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4376 dict_add_number(dict, "hidden",
4377 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004378
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004379 /* Get a reference to buffer variables */
4380 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004381
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004382 /* List of windows displaying this buffer */
4383 windows = list_alloc();
4384 if (windows != NULL)
4385 {
4386 FOR_ALL_TAB_WINDOWS(tp, wp)
4387 if (wp->w_buffer == buf)
4388 list_append_number(windows, (varnumber_T)wp->w_id);
4389 dict_add_list(dict, "windows", windows);
4390 }
4391
4392#ifdef FEAT_SIGNS
4393 if (buf->b_signlist != NULL)
4394 {
4395 /* List of signs placed in this buffer */
4396 list_T *signs = list_alloc();
4397 if (signs != NULL)
4398 {
4399 get_buffer_signs(buf, signs);
4400 dict_add_list(dict, "signs", signs);
4401 }
4402 }
4403#endif
4404
4405 return dict;
4406}
4407
4408/*
4409 * "getbufinfo()" function
4410 */
4411 static void
4412f_getbufinfo(typval_T *argvars, typval_T *rettv)
4413{
4414 buf_T *buf = NULL;
4415 buf_T *argbuf = NULL;
4416 dict_T *d;
4417 int filtered = FALSE;
4418 int sel_buflisted = FALSE;
4419 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004420 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004421
4422 if (rettv_list_alloc(rettv) != OK)
4423 return;
4424
4425 /* List of all the buffers or selected buffers */
4426 if (argvars[0].v_type == VAR_DICT)
4427 {
4428 dict_T *sel_d = argvars[0].vval.v_dict;
4429
4430 if (sel_d != NULL)
4431 {
4432 dictitem_T *di;
4433
4434 filtered = TRUE;
4435
4436 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4437 if (di != NULL && get_tv_number(&di->di_tv))
4438 sel_buflisted = TRUE;
4439
4440 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4441 if (di != NULL && get_tv_number(&di->di_tv))
4442 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004443
4444 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4445 if (di != NULL && get_tv_number(&di->di_tv))
4446 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004447 }
4448 }
4449 else if (argvars[0].v_type != VAR_UNKNOWN)
4450 {
4451 /* Information about one buffer. Argument specifies the buffer */
4452 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4453 ++emsg_off;
4454 argbuf = get_buf_tv(&argvars[0], FALSE);
4455 --emsg_off;
4456 if (argbuf == NULL)
4457 return;
4458 }
4459
4460 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004461 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004462 {
4463 if (argbuf != NULL && argbuf != buf)
4464 continue;
4465 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004466 || (sel_buflisted && !buf->b_p_bl)
4467 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004468 continue;
4469
4470 d = get_buffer_info(buf);
4471 if (d != NULL)
4472 list_append_dict(rettv->vval.v_list, d);
4473 if (argbuf != NULL)
4474 return;
4475 }
4476}
4477
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004478static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4479
4480/*
4481 * Get line or list of lines from buffer "buf" into "rettv".
4482 * Return a range (from start to end) of lines in rettv from the specified
4483 * buffer.
4484 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4485 */
4486 static void
4487get_buffer_lines(
4488 buf_T *buf,
4489 linenr_T start,
4490 linenr_T end,
4491 int retlist,
4492 typval_T *rettv)
4493{
4494 char_u *p;
4495
4496 rettv->v_type = VAR_STRING;
4497 rettv->vval.v_string = NULL;
4498 if (retlist && rettv_list_alloc(rettv) == FAIL)
4499 return;
4500
4501 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4502 return;
4503
4504 if (!retlist)
4505 {
4506 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4507 p = ml_get_buf(buf, start, FALSE);
4508 else
4509 p = (char_u *)"";
4510 rettv->vval.v_string = vim_strsave(p);
4511 }
4512 else
4513 {
4514 if (end < start)
4515 return;
4516
4517 if (start < 1)
4518 start = 1;
4519 if (end > buf->b_ml.ml_line_count)
4520 end = buf->b_ml.ml_line_count;
4521 while (start <= end)
4522 if (list_append_string(rettv->vval.v_list,
4523 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4524 break;
4525 }
4526}
4527
4528/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004529 * "getbufline()" function
4530 */
4531 static void
4532f_getbufline(typval_T *argvars, typval_T *rettv)
4533{
4534 linenr_T lnum;
4535 linenr_T end;
4536 buf_T *buf;
4537
4538 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4539 ++emsg_off;
4540 buf = get_buf_tv(&argvars[0], FALSE);
4541 --emsg_off;
4542
4543 lnum = get_tv_lnum_buf(&argvars[1], buf);
4544 if (argvars[2].v_type == VAR_UNKNOWN)
4545 end = lnum;
4546 else
4547 end = get_tv_lnum_buf(&argvars[2], buf);
4548
4549 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4550}
4551
4552/*
4553 * "getbufvar()" function
4554 */
4555 static void
4556f_getbufvar(typval_T *argvars, typval_T *rettv)
4557{
4558 buf_T *buf;
4559 buf_T *save_curbuf;
4560 char_u *varname;
4561 dictitem_T *v;
4562 int done = FALSE;
4563
4564 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4565 varname = get_tv_string_chk(&argvars[1]);
4566 ++emsg_off;
4567 buf = get_buf_tv(&argvars[0], FALSE);
4568
4569 rettv->v_type = VAR_STRING;
4570 rettv->vval.v_string = NULL;
4571
4572 if (buf != NULL && varname != NULL)
4573 {
4574 /* set curbuf to be our buf, temporarily */
4575 save_curbuf = curbuf;
4576 curbuf = buf;
4577
Bram Moolenaar30567352016-08-27 21:25:44 +02004578 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004579 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004580 if (varname[1] == NUL)
4581 {
4582 /* get all buffer-local options in a dict */
4583 dict_T *opts = get_winbuf_options(TRUE);
4584
4585 if (opts != NULL)
4586 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004587 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004588 done = TRUE;
4589 }
4590 }
4591 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4592 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004593 done = TRUE;
4594 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004595 else
4596 {
4597 /* Look up the variable. */
4598 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4599 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4600 'b', varname, FALSE);
4601 if (v != NULL)
4602 {
4603 copy_tv(&v->di_tv, rettv);
4604 done = TRUE;
4605 }
4606 }
4607
4608 /* restore previous notion of curbuf */
4609 curbuf = save_curbuf;
4610 }
4611
4612 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4613 /* use the default value */
4614 copy_tv(&argvars[2], rettv);
4615
4616 --emsg_off;
4617}
4618
4619/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004620 * "getchangelist()" function
4621 */
4622 static void
4623f_getchangelist(typval_T *argvars, typval_T *rettv)
4624{
4625#ifdef FEAT_JUMPLIST
4626 buf_T *buf;
4627 int i;
4628 list_T *l;
4629 dict_T *d;
4630#endif
4631
4632 if (rettv_list_alloc(rettv) != OK)
4633 return;
4634
4635#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004636 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4637 ++emsg_off;
4638 buf = get_buf_tv(&argvars[0], FALSE);
4639 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004640 if (buf == NULL)
4641 return;
4642
4643 l = list_alloc();
4644 if (l == NULL)
4645 return;
4646
4647 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4648 return;
4649 /*
4650 * The current window change list index tracks only the position in the
4651 * current buffer change list. For other buffers, use the change list
4652 * length as the current index.
4653 */
4654 list_append_number(rettv->vval.v_list,
4655 (varnumber_T)((buf == curwin->w_buffer)
4656 ? curwin->w_changelistidx : buf->b_changelistlen));
4657
4658 for (i = 0; i < buf->b_changelistlen; ++i)
4659 {
4660 if (buf->b_changelist[i].lnum == 0)
4661 continue;
4662 if ((d = dict_alloc()) == NULL)
4663 return;
4664 if (list_append_dict(l, d) == FAIL)
4665 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004666 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4667 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004668# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004669 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004670# endif
4671 }
4672#endif
4673}
4674/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675 * "getchar()" function
4676 */
4677 static void
4678f_getchar(typval_T *argvars, typval_T *rettv)
4679{
4680 varnumber_T n;
4681 int error = FALSE;
4682
4683 /* Position the cursor. Needed after a message that ends in a space. */
4684 windgoto(msg_row, msg_col);
4685
4686 ++no_mapping;
4687 ++allow_keys;
4688 for (;;)
4689 {
4690 if (argvars[0].v_type == VAR_UNKNOWN)
4691 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004692 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4694 /* getchar(1): only check if char avail */
4695 n = vpeekc_any();
4696 else if (error || vpeekc_any() == NUL)
4697 /* illegal argument or getchar(0) and no char avail: return zero */
4698 n = 0;
4699 else
4700 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004701 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702
4703 if (n == K_IGNORE)
4704 continue;
4705 break;
4706 }
4707 --no_mapping;
4708 --allow_keys;
4709
4710 set_vim_var_nr(VV_MOUSE_WIN, 0);
4711 set_vim_var_nr(VV_MOUSE_WINID, 0);
4712 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4713 set_vim_var_nr(VV_MOUSE_COL, 0);
4714
4715 rettv->vval.v_number = n;
4716 if (IS_SPECIAL(n) || mod_mask != 0)
4717 {
4718 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4719 int i = 0;
4720
4721 /* Turn a special key into three bytes, plus modifier. */
4722 if (mod_mask != 0)
4723 {
4724 temp[i++] = K_SPECIAL;
4725 temp[i++] = KS_MODIFIER;
4726 temp[i++] = mod_mask;
4727 }
4728 if (IS_SPECIAL(n))
4729 {
4730 temp[i++] = K_SPECIAL;
4731 temp[i++] = K_SECOND(n);
4732 temp[i++] = K_THIRD(n);
4733 }
4734#ifdef FEAT_MBYTE
4735 else if (has_mbyte)
4736 i += (*mb_char2bytes)(n, temp + i);
4737#endif
4738 else
4739 temp[i++] = n;
4740 temp[i++] = NUL;
4741 rettv->v_type = VAR_STRING;
4742 rettv->vval.v_string = vim_strsave(temp);
4743
4744#ifdef FEAT_MOUSE
4745 if (is_mouse_key(n))
4746 {
4747 int row = mouse_row;
4748 int col = mouse_col;
4749 win_T *win;
4750 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004751 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004752 int winnr = 1;
4753
4754 if (row >= 0 && col >= 0)
4755 {
4756 /* Find the window at the mouse coordinates and compute the
4757 * text position. */
4758 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004759 if (win == NULL)
4760 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004761 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004762 for (wp = firstwin; wp != win; wp = wp->w_next)
4763 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004764 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4765 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4766 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4767 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4768 }
4769 }
4770#endif
4771 }
4772}
4773
4774/*
4775 * "getcharmod()" function
4776 */
4777 static void
4778f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4779{
4780 rettv->vval.v_number = mod_mask;
4781}
4782
4783/*
4784 * "getcharsearch()" function
4785 */
4786 static void
4787f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4788{
4789 if (rettv_dict_alloc(rettv) != FAIL)
4790 {
4791 dict_T *dict = rettv->vval.v_dict;
4792
Bram Moolenaare0be1672018-07-08 16:50:37 +02004793 dict_add_string(dict, "char", last_csearch());
4794 dict_add_number(dict, "forward", last_csearch_forward());
4795 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796 }
4797}
4798
4799/*
4800 * "getcmdline()" function
4801 */
4802 static void
4803f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4804{
4805 rettv->v_type = VAR_STRING;
4806 rettv->vval.v_string = get_cmdline_str();
4807}
4808
4809/*
4810 * "getcmdpos()" function
4811 */
4812 static void
4813f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4814{
4815 rettv->vval.v_number = get_cmdline_pos() + 1;
4816}
4817
4818/*
4819 * "getcmdtype()" function
4820 */
4821 static void
4822f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4823{
4824 rettv->v_type = VAR_STRING;
4825 rettv->vval.v_string = alloc(2);
4826 if (rettv->vval.v_string != NULL)
4827 {
4828 rettv->vval.v_string[0] = get_cmdline_type();
4829 rettv->vval.v_string[1] = NUL;
4830 }
4831}
4832
4833/*
4834 * "getcmdwintype()" function
4835 */
4836 static void
4837f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4838{
4839 rettv->v_type = VAR_STRING;
4840 rettv->vval.v_string = NULL;
4841#ifdef FEAT_CMDWIN
4842 rettv->vval.v_string = alloc(2);
4843 if (rettv->vval.v_string != NULL)
4844 {
4845 rettv->vval.v_string[0] = cmdwin_type;
4846 rettv->vval.v_string[1] = NUL;
4847 }
4848#endif
4849}
4850
4851#if defined(FEAT_CMDL_COMPL)
4852/*
4853 * "getcompletion()" function
4854 */
4855 static void
4856f_getcompletion(typval_T *argvars, typval_T *rettv)
4857{
4858 char_u *pat;
4859 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004860 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004861 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4862 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004863
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004864 if (argvars[2].v_type != VAR_UNKNOWN)
4865 filtered = get_tv_number_chk(&argvars[2], NULL);
4866
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004867 if (p_wic)
4868 options |= WILD_ICASE;
4869
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004870 /* For filtered results, 'wildignore' is used */
4871 if (!filtered)
4872 options |= WILD_KEEP_ALL;
4873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004874 ExpandInit(&xpc);
4875 xpc.xp_pattern = get_tv_string(&argvars[0]);
4876 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4877 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4878 if (xpc.xp_context == EXPAND_NOTHING)
4879 {
4880 if (argvars[1].v_type == VAR_STRING)
4881 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4882 else
4883 EMSG(_(e_invarg));
4884 return;
4885 }
4886
4887# if defined(FEAT_MENU)
4888 if (xpc.xp_context == EXPAND_MENUS)
4889 {
4890 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4891 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4892 }
4893# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004894#ifdef FEAT_CSCOPE
4895 if (xpc.xp_context == EXPAND_CSCOPE)
4896 {
4897 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4898 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4899 }
4900#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004901#ifdef FEAT_SIGNS
4902 if (xpc.xp_context == EXPAND_SIGN)
4903 {
4904 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4905 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4906 }
4907#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908
4909 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4910 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4911 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004912 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004913
4914 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4915
4916 for (i = 0; i < xpc.xp_numfiles; i++)
4917 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4918 }
4919 vim_free(pat);
4920 ExpandCleanup(&xpc);
4921}
4922#endif
4923
4924/*
4925 * "getcwd()" function
4926 */
4927 static void
4928f_getcwd(typval_T *argvars, typval_T *rettv)
4929{
4930 win_T *wp = NULL;
4931 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004932 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933
4934 rettv->v_type = VAR_STRING;
4935 rettv->vval.v_string = NULL;
4936
Bram Moolenaar54591292018-02-09 20:53:59 +01004937 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4938 global = TRUE;
4939 else
4940 wp = find_tabwin(&argvars[0], &argvars[1]);
4941
4942 if (wp != NULL && wp->w_localdir != NULL)
4943 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4944 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004946 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 rettv->vval.v_string = vim_strsave(globaldir);
4948 else
4949 {
4950 cwd = alloc(MAXPATHL);
4951 if (cwd != NULL)
4952 {
4953 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4954 rettv->vval.v_string = vim_strsave(cwd);
4955 vim_free(cwd);
4956 }
4957 }
4958#ifdef BACKSLASH_IN_FILENAME
4959 if (rettv->vval.v_string != NULL)
4960 slash_adjust(rettv->vval.v_string);
4961#endif
4962 }
4963}
4964
4965/*
4966 * "getfontname()" function
4967 */
4968 static void
4969f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4970{
4971 rettv->v_type = VAR_STRING;
4972 rettv->vval.v_string = NULL;
4973#ifdef FEAT_GUI
4974 if (gui.in_use)
4975 {
4976 GuiFont font;
4977 char_u *name = NULL;
4978
4979 if (argvars[0].v_type == VAR_UNKNOWN)
4980 {
4981 /* Get the "Normal" font. Either the name saved by
4982 * hl_set_font_name() or from the font ID. */
4983 font = gui.norm_font;
4984 name = hl_get_font_name();
4985 }
4986 else
4987 {
4988 name = get_tv_string(&argvars[0]);
4989 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4990 return;
4991 font = gui_mch_get_font(name, FALSE);
4992 if (font == NOFONT)
4993 return; /* Invalid font name, return empty string. */
4994 }
4995 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4996 if (argvars[0].v_type != VAR_UNKNOWN)
4997 gui_mch_free_font(font);
4998 }
4999#endif
5000}
5001
5002/*
5003 * "getfperm({fname})" function
5004 */
5005 static void
5006f_getfperm(typval_T *argvars, typval_T *rettv)
5007{
5008 char_u *fname;
5009 stat_T st;
5010 char_u *perm = NULL;
5011 char_u flags[] = "rwx";
5012 int i;
5013
5014 fname = get_tv_string(&argvars[0]);
5015
5016 rettv->v_type = VAR_STRING;
5017 if (mch_stat((char *)fname, &st) >= 0)
5018 {
5019 perm = vim_strsave((char_u *)"---------");
5020 if (perm != NULL)
5021 {
5022 for (i = 0; i < 9; i++)
5023 {
5024 if (st.st_mode & (1 << (8 - i)))
5025 perm[i] = flags[i % 3];
5026 }
5027 }
5028 }
5029 rettv->vval.v_string = perm;
5030}
5031
5032/*
5033 * "getfsize({fname})" function
5034 */
5035 static void
5036f_getfsize(typval_T *argvars, typval_T *rettv)
5037{
5038 char_u *fname;
5039 stat_T st;
5040
5041 fname = get_tv_string(&argvars[0]);
5042
5043 rettv->v_type = VAR_NUMBER;
5044
5045 if (mch_stat((char *)fname, &st) >= 0)
5046 {
5047 if (mch_isdir(fname))
5048 rettv->vval.v_number = 0;
5049 else
5050 {
5051 rettv->vval.v_number = (varnumber_T)st.st_size;
5052
5053 /* non-perfect check for overflow */
5054 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5055 rettv->vval.v_number = -2;
5056 }
5057 }
5058 else
5059 rettv->vval.v_number = -1;
5060}
5061
5062/*
5063 * "getftime({fname})" function
5064 */
5065 static void
5066f_getftime(typval_T *argvars, typval_T *rettv)
5067{
5068 char_u *fname;
5069 stat_T st;
5070
5071 fname = get_tv_string(&argvars[0]);
5072
5073 if (mch_stat((char *)fname, &st) >= 0)
5074 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5075 else
5076 rettv->vval.v_number = -1;
5077}
5078
5079/*
5080 * "getftype({fname})" function
5081 */
5082 static void
5083f_getftype(typval_T *argvars, typval_T *rettv)
5084{
5085 char_u *fname;
5086 stat_T st;
5087 char_u *type = NULL;
5088 char *t;
5089
5090 fname = get_tv_string(&argvars[0]);
5091
5092 rettv->v_type = VAR_STRING;
5093 if (mch_lstat((char *)fname, &st) >= 0)
5094 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005095 if (S_ISREG(st.st_mode))
5096 t = "file";
5097 else if (S_ISDIR(st.st_mode))
5098 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 else if (S_ISLNK(st.st_mode))
5100 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005101 else if (S_ISBLK(st.st_mode))
5102 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103 else if (S_ISCHR(st.st_mode))
5104 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 else if (S_ISFIFO(st.st_mode))
5106 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005108 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 else
5110 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005111 type = vim_strsave((char_u *)t);
5112 }
5113 rettv->vval.v_string = type;
5114}
5115
5116/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005117 * "getjumplist()" function
5118 */
5119 static void
5120f_getjumplist(typval_T *argvars, typval_T *rettv)
5121{
5122#ifdef FEAT_JUMPLIST
5123 win_T *wp;
5124 int i;
5125 list_T *l;
5126 dict_T *d;
5127#endif
5128
5129 if (rettv_list_alloc(rettv) != OK)
5130 return;
5131
5132#ifdef FEAT_JUMPLIST
5133 wp = find_tabwin(&argvars[0], &argvars[1]);
5134 if (wp == NULL)
5135 return;
5136
5137 l = list_alloc();
5138 if (l == NULL)
5139 return;
5140
5141 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5142 return;
5143 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5144
Bram Moolenaar48679742018-02-13 13:33:29 +01005145 cleanup_jumplist(wp, TRUE);
5146
Bram Moolenaar4f505882018-02-10 21:06:32 +01005147 for (i = 0; i < wp->w_jumplistlen; ++i)
5148 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005149 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5150 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005151 if ((d = dict_alloc()) == NULL)
5152 return;
5153 if (list_append_dict(l, d) == FAIL)
5154 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005155 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5156 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005157# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005158 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005159# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005160 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005161 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005162 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005163 }
5164#endif
5165}
5166
5167/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005168 * "getline(lnum, [end])" function
5169 */
5170 static void
5171f_getline(typval_T *argvars, typval_T *rettv)
5172{
5173 linenr_T lnum;
5174 linenr_T end;
5175 int retlist;
5176
5177 lnum = get_tv_lnum(argvars);
5178 if (argvars[1].v_type == VAR_UNKNOWN)
5179 {
5180 end = 0;
5181 retlist = FALSE;
5182 }
5183 else
5184 {
5185 end = get_tv_lnum(&argvars[1]);
5186 retlist = TRUE;
5187 }
5188
5189 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5190}
5191
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005192#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005193 static void
5194get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5195{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005196 if (what_arg->v_type == VAR_UNKNOWN)
5197 {
5198 if (rettv_list_alloc(rettv) == OK)
5199 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005200 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005201 }
5202 else
5203 {
5204 if (rettv_dict_alloc(rettv) == OK)
5205 if (is_qf || (wp != NULL))
5206 {
5207 if (what_arg->v_type == VAR_DICT)
5208 {
5209 dict_T *d = what_arg->vval.v_dict;
5210
5211 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005212 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005213 }
5214 else
5215 EMSG(_(e_dictreq));
5216 }
5217 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005218}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005219#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005220
5221/*
5222 * "getloclist()" function
5223 */
5224 static void
5225f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5226{
5227#ifdef FEAT_QUICKFIX
5228 win_T *wp;
5229
5230 wp = find_win_by_nr(&argvars[0], NULL);
5231 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5232#endif
5233}
5234
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005235/*
5236 * "getmatches()" function
5237 */
5238 static void
5239f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5240{
5241#ifdef FEAT_SEARCH_EXTRA
5242 dict_T *dict;
5243 matchitem_T *cur = curwin->w_match_head;
5244 int i;
5245
5246 if (rettv_list_alloc(rettv) == OK)
5247 {
5248 while (cur != NULL)
5249 {
5250 dict = dict_alloc();
5251 if (dict == NULL)
5252 return;
5253 if (cur->match.regprog == NULL)
5254 {
5255 /* match added with matchaddpos() */
5256 for (i = 0; i < MAXPOSMATCH; ++i)
5257 {
5258 llpos_T *llpos;
5259 char buf[6];
5260 list_T *l;
5261
5262 llpos = &cur->pos.pos[i];
5263 if (llpos->lnum == 0)
5264 break;
5265 l = list_alloc();
5266 if (l == NULL)
5267 break;
5268 list_append_number(l, (varnumber_T)llpos->lnum);
5269 if (llpos->col > 0)
5270 {
5271 list_append_number(l, (varnumber_T)llpos->col);
5272 list_append_number(l, (varnumber_T)llpos->len);
5273 }
5274 sprintf(buf, "pos%d", i + 1);
5275 dict_add_list(dict, buf, l);
5276 }
5277 }
5278 else
5279 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005280 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005281 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005282 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5283 dict_add_number(dict, "priority", (long)cur->priority);
5284 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005285# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5286 if (cur->conceal_char)
5287 {
5288 char_u buf[MB_MAXBYTES + 1];
5289
5290 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005291 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 }
5293# endif
5294 list_append_dict(rettv->vval.v_list, dict);
5295 cur = cur->next;
5296 }
5297 }
5298#endif
5299}
5300
5301/*
5302 * "getpid()" function
5303 */
5304 static void
5305f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5306{
5307 rettv->vval.v_number = mch_get_pid();
5308}
5309
5310 static void
5311getpos_both(
5312 typval_T *argvars,
5313 typval_T *rettv,
5314 int getcurpos)
5315{
5316 pos_T *fp;
5317 list_T *l;
5318 int fnum = -1;
5319
5320 if (rettv_list_alloc(rettv) == OK)
5321 {
5322 l = rettv->vval.v_list;
5323 if (getcurpos)
5324 fp = &curwin->w_cursor;
5325 else
5326 fp = var2fpos(&argvars[0], TRUE, &fnum);
5327 if (fnum != -1)
5328 list_append_number(l, (varnumber_T)fnum);
5329 else
5330 list_append_number(l, (varnumber_T)0);
5331 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5332 : (varnumber_T)0);
5333 list_append_number(l, (fp != NULL)
5334 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5335 : (varnumber_T)0);
5336 list_append_number(l,
5337#ifdef FEAT_VIRTUALEDIT
5338 (fp != NULL) ? (varnumber_T)fp->coladd :
5339#endif
5340 (varnumber_T)0);
5341 if (getcurpos)
5342 {
5343 update_curswant();
5344 list_append_number(l, curwin->w_curswant == MAXCOL ?
5345 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5346 }
5347 }
5348 else
5349 rettv->vval.v_number = FALSE;
5350}
5351
5352
5353/*
5354 * "getcurpos()" function
5355 */
5356 static void
5357f_getcurpos(typval_T *argvars, typval_T *rettv)
5358{
5359 getpos_both(argvars, rettv, TRUE);
5360}
5361
5362/*
5363 * "getpos(string)" function
5364 */
5365 static void
5366f_getpos(typval_T *argvars, typval_T *rettv)
5367{
5368 getpos_both(argvars, rettv, FALSE);
5369}
5370
5371/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005372 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005373 */
5374 static void
5375f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5376{
5377#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005378 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379#endif
5380}
5381
5382/*
5383 * "getreg()" function
5384 */
5385 static void
5386f_getreg(typval_T *argvars, typval_T *rettv)
5387{
5388 char_u *strregname;
5389 int regname;
5390 int arg2 = FALSE;
5391 int return_list = FALSE;
5392 int error = FALSE;
5393
5394 if (argvars[0].v_type != VAR_UNKNOWN)
5395 {
5396 strregname = get_tv_string_chk(&argvars[0]);
5397 error = strregname == NULL;
5398 if (argvars[1].v_type != VAR_UNKNOWN)
5399 {
5400 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5401 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5402 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5403 }
5404 }
5405 else
5406 strregname = get_vim_var_str(VV_REG);
5407
5408 if (error)
5409 return;
5410
5411 regname = (strregname == NULL ? '"' : *strregname);
5412 if (regname == 0)
5413 regname = '"';
5414
5415 if (return_list)
5416 {
5417 rettv->v_type = VAR_LIST;
5418 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5419 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5420 if (rettv->vval.v_list == NULL)
5421 (void)rettv_list_alloc(rettv);
5422 else
5423 ++rettv->vval.v_list->lv_refcount;
5424 }
5425 else
5426 {
5427 rettv->v_type = VAR_STRING;
5428 rettv->vval.v_string = get_reg_contents(regname,
5429 arg2 ? GREG_EXPR_SRC : 0);
5430 }
5431}
5432
5433/*
5434 * "getregtype()" function
5435 */
5436 static void
5437f_getregtype(typval_T *argvars, typval_T *rettv)
5438{
5439 char_u *strregname;
5440 int regname;
5441 char_u buf[NUMBUFLEN + 2];
5442 long reglen = 0;
5443
5444 if (argvars[0].v_type != VAR_UNKNOWN)
5445 {
5446 strregname = get_tv_string_chk(&argvars[0]);
5447 if (strregname == NULL) /* type error; errmsg already given */
5448 {
5449 rettv->v_type = VAR_STRING;
5450 rettv->vval.v_string = NULL;
5451 return;
5452 }
5453 }
5454 else
5455 /* Default to v:register */
5456 strregname = get_vim_var_str(VV_REG);
5457
5458 regname = (strregname == NULL ? '"' : *strregname);
5459 if (regname == 0)
5460 regname = '"';
5461
5462 buf[0] = NUL;
5463 buf[1] = NUL;
5464 switch (get_reg_type(regname, &reglen))
5465 {
5466 case MLINE: buf[0] = 'V'; break;
5467 case MCHAR: buf[0] = 'v'; break;
5468 case MBLOCK:
5469 buf[0] = Ctrl_V;
5470 sprintf((char *)buf + 1, "%ld", reglen + 1);
5471 break;
5472 }
5473 rettv->v_type = VAR_STRING;
5474 rettv->vval.v_string = vim_strsave(buf);
5475}
5476
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005477/*
5478 * Returns information (variables, options, etc.) about a tab page
5479 * as a dictionary.
5480 */
5481 static dict_T *
5482get_tabpage_info(tabpage_T *tp, int tp_idx)
5483{
5484 win_T *wp;
5485 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005486 list_T *l;
5487
5488 dict = dict_alloc();
5489 if (dict == NULL)
5490 return NULL;
5491
Bram Moolenaare0be1672018-07-08 16:50:37 +02005492 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005493
5494 l = list_alloc();
5495 if (l != NULL)
5496 {
5497 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5498 wp; wp = wp->w_next)
5499 list_append_number(l, (varnumber_T)wp->w_id);
5500 dict_add_list(dict, "windows", l);
5501 }
5502
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005503 /* Make a reference to tabpage variables */
5504 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005505
5506 return dict;
5507}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005508
5509/*
5510 * "gettabinfo()" function
5511 */
5512 static void
5513f_gettabinfo(typval_T *argvars, typval_T *rettv)
5514{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005515 tabpage_T *tp, *tparg = NULL;
5516 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005517 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005518
5519 if (rettv_list_alloc(rettv) != OK)
5520 return;
5521
5522 if (argvars[0].v_type != VAR_UNKNOWN)
5523 {
5524 /* Information about one tab page */
5525 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5526 if (tparg == NULL)
5527 return;
5528 }
5529
5530 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005531 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005532 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005533 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005534 if (tparg != NULL && tp != tparg)
5535 continue;
5536 d = get_tabpage_info(tp, tpnr);
5537 if (d != NULL)
5538 list_append_dict(rettv->vval.v_list, d);
5539 if (tparg != NULL)
5540 return;
5541 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005542}
5543
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544/*
5545 * "gettabvar()" function
5546 */
5547 static void
5548f_gettabvar(typval_T *argvars, typval_T *rettv)
5549{
5550 win_T *oldcurwin;
5551 tabpage_T *tp, *oldtabpage;
5552 dictitem_T *v;
5553 char_u *varname;
5554 int done = FALSE;
5555
5556 rettv->v_type = VAR_STRING;
5557 rettv->vval.v_string = NULL;
5558
5559 varname = get_tv_string_chk(&argvars[1]);
5560 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5561 if (tp != NULL && varname != NULL)
5562 {
5563 /* Set tp to be our tabpage, temporarily. Also set the window to the
5564 * first window in the tabpage, otherwise the window is not valid. */
5565 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005566 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5567 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005568 {
5569 /* look up the variable */
5570 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5571 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5572 if (v != NULL)
5573 {
5574 copy_tv(&v->di_tv, rettv);
5575 done = TRUE;
5576 }
5577 }
5578
5579 /* restore previous notion of curwin */
5580 restore_win(oldcurwin, oldtabpage, TRUE);
5581 }
5582
5583 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5584 copy_tv(&argvars[2], rettv);
5585}
5586
5587/*
5588 * "gettabwinvar()" function
5589 */
5590 static void
5591f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5592{
5593 getwinvar(argvars, rettv, 1);
5594}
5595
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005596/*
5597 * Returns information about a window as a dictionary.
5598 */
5599 static dict_T *
5600get_win_info(win_T *wp, short tpnr, short winnr)
5601{
5602 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005603
5604 dict = dict_alloc();
5605 if (dict == NULL)
5606 return NULL;
5607
Bram Moolenaare0be1672018-07-08 16:50:37 +02005608 dict_add_number(dict, "tabnr", tpnr);
5609 dict_add_number(dict, "winnr", winnr);
5610 dict_add_number(dict, "winid", wp->w_id);
5611 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005612 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005613#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005614 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005615#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005616 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005617 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005618 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005619
Bram Moolenaar69905d12017-08-13 18:14:47 +02005620#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005621 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005622#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005623#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005624 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5625 dict_add_number(dict, "loclist",
5626 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005627#endif
5628
Bram Moolenaar30567352016-08-27 21:25:44 +02005629 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005630 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005631
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632 return dict;
5633}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005634
5635/*
5636 * "getwininfo()" function
5637 */
5638 static void
5639f_getwininfo(typval_T *argvars, typval_T *rettv)
5640{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005641 tabpage_T *tp;
5642 win_T *wp = NULL, *wparg = NULL;
5643 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005644 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005645
5646 if (rettv_list_alloc(rettv) != OK)
5647 return;
5648
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005649 if (argvars[0].v_type != VAR_UNKNOWN)
5650 {
5651 wparg = win_id2wp(argvars);
5652 if (wparg == NULL)
5653 return;
5654 }
5655
5656 /* Collect information about either all the windows across all the tab
5657 * pages or one particular window.
5658 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005659 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005660 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005661 tabnr++;
5662 winnr = 0;
5663 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005664 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005665 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005666 if (wparg != NULL && wp != wparg)
5667 continue;
5668 d = get_win_info(wp, tabnr, winnr);
5669 if (d != NULL)
5670 list_append_dict(rettv->vval.v_list, d);
5671 if (wparg != NULL)
5672 /* found information about a specific window */
5673 return;
5674 }
5675 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005676}
5677
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005678/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005679 * "win_findbuf()" function
5680 */
5681 static void
5682f_win_findbuf(typval_T *argvars, typval_T *rettv)
5683{
5684 if (rettv_list_alloc(rettv) != FAIL)
5685 win_findbuf(argvars, rettv->vval.v_list);
5686}
5687
5688/*
5689 * "win_getid()" function
5690 */
5691 static void
5692f_win_getid(typval_T *argvars, typval_T *rettv)
5693{
5694 rettv->vval.v_number = win_getid(argvars);
5695}
5696
5697/*
5698 * "win_gotoid()" function
5699 */
5700 static void
5701f_win_gotoid(typval_T *argvars, typval_T *rettv)
5702{
5703 rettv->vval.v_number = win_gotoid(argvars);
5704}
5705
5706/*
5707 * "win_id2tabwin()" function
5708 */
5709 static void
5710f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5711{
5712 if (rettv_list_alloc(rettv) != FAIL)
5713 win_id2tabwin(argvars, rettv->vval.v_list);
5714}
5715
5716/*
5717 * "win_id2win()" function
5718 */
5719 static void
5720f_win_id2win(typval_T *argvars, typval_T *rettv)
5721{
5722 rettv->vval.v_number = win_id2win(argvars);
5723}
5724
5725/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005726 * "win_screenpos()" function
5727 */
5728 static void
5729f_win_screenpos(typval_T *argvars, typval_T *rettv)
5730{
5731 win_T *wp;
5732
5733 if (rettv_list_alloc(rettv) == FAIL)
5734 return;
5735
5736 wp = find_win_by_nr(&argvars[0], NULL);
5737 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5738 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5739}
5740
5741/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005742 * "getwinpos({timeout})" function
5743 */
5744 static void
5745f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5746{
5747 int x = -1;
5748 int y = -1;
5749
5750 if (rettv_list_alloc(rettv) == FAIL)
5751 return;
5752#ifdef FEAT_GUI
5753 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005754 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005755# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5756 else
5757# endif
5758#endif
5759#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5760 {
5761 varnumber_T timeout = 100;
5762
5763 if (argvars[0].v_type != VAR_UNKNOWN)
5764 timeout = get_tv_number(&argvars[0]);
5765 term_get_winpos(&x, &y, timeout);
5766 }
5767#endif
5768 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5769 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5770}
5771
5772
5773/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005774 * "getwinposx()" function
5775 */
5776 static void
5777f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5778{
5779 rettv->vval.v_number = -1;
5780#ifdef FEAT_GUI
5781 if (gui.in_use)
5782 {
5783 int x, y;
5784
5785 if (gui_mch_get_winpos(&x, &y) == OK)
5786 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005787 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005788 }
5789#endif
5790#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5791 {
5792 int x, y;
5793
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005794 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005795 rettv->vval.v_number = x;
5796 }
5797#endif
5798}
5799
5800/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 * "getwinposy()" function
5802 */
5803 static void
5804f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5805{
5806 rettv->vval.v_number = -1;
5807#ifdef FEAT_GUI
5808 if (gui.in_use)
5809 {
5810 int x, y;
5811
5812 if (gui_mch_get_winpos(&x, &y) == OK)
5813 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005814 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005815 }
5816#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005817#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5818 {
5819 int x, y;
5820
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005821 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005822 rettv->vval.v_number = y;
5823 }
5824#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005825}
5826
5827/*
5828 * "getwinvar()" function
5829 */
5830 static void
5831f_getwinvar(typval_T *argvars, typval_T *rettv)
5832{
5833 getwinvar(argvars, rettv, 0);
5834}
5835
5836/*
5837 * "glob()" function
5838 */
5839 static void
5840f_glob(typval_T *argvars, typval_T *rettv)
5841{
5842 int options = WILD_SILENT|WILD_USE_NL;
5843 expand_T xpc;
5844 int error = FALSE;
5845
5846 /* When the optional second argument is non-zero, don't remove matches
5847 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5848 rettv->v_type = VAR_STRING;
5849 if (argvars[1].v_type != VAR_UNKNOWN)
5850 {
5851 if (get_tv_number_chk(&argvars[1], &error))
5852 options |= WILD_KEEP_ALL;
5853 if (argvars[2].v_type != VAR_UNKNOWN)
5854 {
5855 if (get_tv_number_chk(&argvars[2], &error))
5856 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005857 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005858 }
5859 if (argvars[3].v_type != VAR_UNKNOWN
5860 && get_tv_number_chk(&argvars[3], &error))
5861 options |= WILD_ALLLINKS;
5862 }
5863 }
5864 if (!error)
5865 {
5866 ExpandInit(&xpc);
5867 xpc.xp_context = EXPAND_FILES;
5868 if (p_wic)
5869 options += WILD_ICASE;
5870 if (rettv->v_type == VAR_STRING)
5871 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5872 NULL, options, WILD_ALL);
5873 else if (rettv_list_alloc(rettv) != FAIL)
5874 {
5875 int i;
5876
5877 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5878 NULL, options, WILD_ALL_KEEP);
5879 for (i = 0; i < xpc.xp_numfiles; i++)
5880 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5881
5882 ExpandCleanup(&xpc);
5883 }
5884 }
5885 else
5886 rettv->vval.v_string = NULL;
5887}
5888
5889/*
5890 * "globpath()" function
5891 */
5892 static void
5893f_globpath(typval_T *argvars, typval_T *rettv)
5894{
5895 int flags = 0;
5896 char_u buf1[NUMBUFLEN];
5897 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5898 int error = FALSE;
5899 garray_T ga;
5900 int i;
5901
5902 /* When the optional second argument is non-zero, don't remove matches
5903 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5904 rettv->v_type = VAR_STRING;
5905 if (argvars[2].v_type != VAR_UNKNOWN)
5906 {
5907 if (get_tv_number_chk(&argvars[2], &error))
5908 flags |= WILD_KEEP_ALL;
5909 if (argvars[3].v_type != VAR_UNKNOWN)
5910 {
5911 if (get_tv_number_chk(&argvars[3], &error))
5912 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005913 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914 }
5915 if (argvars[4].v_type != VAR_UNKNOWN
5916 && get_tv_number_chk(&argvars[4], &error))
5917 flags |= WILD_ALLLINKS;
5918 }
5919 }
5920 if (file != NULL && !error)
5921 {
5922 ga_init2(&ga, (int)sizeof(char_u *), 10);
5923 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5924 if (rettv->v_type == VAR_STRING)
5925 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5926 else if (rettv_list_alloc(rettv) != FAIL)
5927 for (i = 0; i < ga.ga_len; ++i)
5928 list_append_string(rettv->vval.v_list,
5929 ((char_u **)(ga.ga_data))[i], -1);
5930 ga_clear_strings(&ga);
5931 }
5932 else
5933 rettv->vval.v_string = NULL;
5934}
5935
5936/*
5937 * "glob2regpat()" function
5938 */
5939 static void
5940f_glob2regpat(typval_T *argvars, typval_T *rettv)
5941{
5942 char_u *pat = get_tv_string_chk(&argvars[0]);
5943
5944 rettv->v_type = VAR_STRING;
5945 rettv->vval.v_string = (pat == NULL)
5946 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5947}
5948
5949/* for VIM_VERSION_ defines */
5950#include "version.h"
5951
5952/*
5953 * "has()" function
5954 */
5955 static void
5956f_has(typval_T *argvars, typval_T *rettv)
5957{
5958 int i;
5959 char_u *name;
5960 int n = FALSE;
5961 static char *(has_list[]) =
5962 {
5963#ifdef AMIGA
5964 "amiga",
5965# ifdef FEAT_ARP
5966 "arp",
5967# endif
5968#endif
5969#ifdef __BEOS__
5970 "beos",
5971#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005972#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005973 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5974 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005975# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005976 "macunix", /* Mac OS X, with the darwin feature */
5977 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005978# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005979#endif
5980#ifdef __QNX__
5981 "qnx",
5982#endif
5983#ifdef UNIX
5984 "unix",
5985#endif
5986#ifdef VMS
5987 "vms",
5988#endif
5989#ifdef WIN32
5990 "win32",
5991#endif
5992#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5993 "win32unix",
5994#endif
5995#if defined(WIN64) || defined(_WIN64)
5996 "win64",
5997#endif
5998#ifdef EBCDIC
5999 "ebcdic",
6000#endif
6001#ifndef CASE_INSENSITIVE_FILENAME
6002 "fname_case",
6003#endif
6004#ifdef HAVE_ACL
6005 "acl",
6006#endif
6007#ifdef FEAT_ARABIC
6008 "arabic",
6009#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006010 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006011#ifdef FEAT_AUTOCHDIR
6012 "autochdir",
6013#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006014#ifdef FEAT_AUTOSERVERNAME
6015 "autoservername",
6016#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006017#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 "balloon_eval",
6019# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6020 "balloon_multiline",
6021# endif
6022#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006023#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006024 "balloon_eval_term",
6025#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006026#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6027 "builtin_terms",
6028# ifdef ALL_BUILTIN_TCAPS
6029 "all_builtin_terms",
6030# endif
6031#endif
6032#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6033 || defined(FEAT_GUI_W32) \
6034 || defined(FEAT_GUI_MOTIF))
6035 "browsefilter",
6036#endif
6037#ifdef FEAT_BYTEOFF
6038 "byte_offset",
6039#endif
6040#ifdef FEAT_JOB_CHANNEL
6041 "channel",
6042#endif
6043#ifdef FEAT_CINDENT
6044 "cindent",
6045#endif
6046#ifdef FEAT_CLIENTSERVER
6047 "clientserver",
6048#endif
6049#ifdef FEAT_CLIPBOARD
6050 "clipboard",
6051#endif
6052#ifdef FEAT_CMDL_COMPL
6053 "cmdline_compl",
6054#endif
6055#ifdef FEAT_CMDHIST
6056 "cmdline_hist",
6057#endif
6058#ifdef FEAT_COMMENTS
6059 "comments",
6060#endif
6061#ifdef FEAT_CONCEAL
6062 "conceal",
6063#endif
6064#ifdef FEAT_CRYPT
6065 "cryptv",
6066 "crypt-blowfish",
6067 "crypt-blowfish2",
6068#endif
6069#ifdef FEAT_CSCOPE
6070 "cscope",
6071#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006072 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006073#ifdef CURSOR_SHAPE
6074 "cursorshape",
6075#endif
6076#ifdef DEBUG
6077 "debug",
6078#endif
6079#ifdef FEAT_CON_DIALOG
6080 "dialog_con",
6081#endif
6082#ifdef FEAT_GUI_DIALOG
6083 "dialog_gui",
6084#endif
6085#ifdef FEAT_DIFF
6086 "diff",
6087#endif
6088#ifdef FEAT_DIGRAPHS
6089 "digraphs",
6090#endif
6091#ifdef FEAT_DIRECTX
6092 "directx",
6093#endif
6094#ifdef FEAT_DND
6095 "dnd",
6096#endif
6097#ifdef FEAT_EMACS_TAGS
6098 "emacs_tags",
6099#endif
6100 "eval", /* always present, of course! */
6101 "ex_extra", /* graduated feature */
6102#ifdef FEAT_SEARCH_EXTRA
6103 "extra_search",
6104#endif
6105#ifdef FEAT_FKMAP
6106 "farsi",
6107#endif
6108#ifdef FEAT_SEARCHPATH
6109 "file_in_path",
6110#endif
6111#ifdef FEAT_FILTERPIPE
6112 "filterpipe",
6113#endif
6114#ifdef FEAT_FIND_ID
6115 "find_in_path",
6116#endif
6117#ifdef FEAT_FLOAT
6118 "float",
6119#endif
6120#ifdef FEAT_FOLDING
6121 "folding",
6122#endif
6123#ifdef FEAT_FOOTER
6124 "footer",
6125#endif
6126#if !defined(USE_SYSTEM) && defined(UNIX)
6127 "fork",
6128#endif
6129#ifdef FEAT_GETTEXT
6130 "gettext",
6131#endif
6132#ifdef FEAT_GUI
6133 "gui",
6134#endif
6135#ifdef FEAT_GUI_ATHENA
6136# ifdef FEAT_GUI_NEXTAW
6137 "gui_neXtaw",
6138# else
6139 "gui_athena",
6140# endif
6141#endif
6142#ifdef FEAT_GUI_GTK
6143 "gui_gtk",
6144# ifdef USE_GTK3
6145 "gui_gtk3",
6146# else
6147 "gui_gtk2",
6148# endif
6149#endif
6150#ifdef FEAT_GUI_GNOME
6151 "gui_gnome",
6152#endif
6153#ifdef FEAT_GUI_MAC
6154 "gui_mac",
6155#endif
6156#ifdef FEAT_GUI_MOTIF
6157 "gui_motif",
6158#endif
6159#ifdef FEAT_GUI_PHOTON
6160 "gui_photon",
6161#endif
6162#ifdef FEAT_GUI_W32
6163 "gui_win32",
6164#endif
6165#ifdef FEAT_HANGULIN
6166 "hangul_input",
6167#endif
6168#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6169 "iconv",
6170#endif
6171#ifdef FEAT_INS_EXPAND
6172 "insert_expand",
6173#endif
6174#ifdef FEAT_JOB_CHANNEL
6175 "job",
6176#endif
6177#ifdef FEAT_JUMPLIST
6178 "jumplist",
6179#endif
6180#ifdef FEAT_KEYMAP
6181 "keymap",
6182#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006183 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006184#ifdef FEAT_LANGMAP
6185 "langmap",
6186#endif
6187#ifdef FEAT_LIBCALL
6188 "libcall",
6189#endif
6190#ifdef FEAT_LINEBREAK
6191 "linebreak",
6192#endif
6193#ifdef FEAT_LISP
6194 "lispindent",
6195#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197#ifdef FEAT_LOCALMAP
6198 "localmap",
6199#endif
6200#ifdef FEAT_LUA
6201# ifndef DYNAMIC_LUA
6202 "lua",
6203# endif
6204#endif
6205#ifdef FEAT_MENU
6206 "menu",
6207#endif
6208#ifdef FEAT_SESSION
6209 "mksession",
6210#endif
6211#ifdef FEAT_MODIFY_FNAME
6212 "modify_fname",
6213#endif
6214#ifdef FEAT_MOUSE
6215 "mouse",
6216#endif
6217#ifdef FEAT_MOUSESHAPE
6218 "mouseshape",
6219#endif
6220#if defined(UNIX) || defined(VMS)
6221# ifdef FEAT_MOUSE_DEC
6222 "mouse_dec",
6223# endif
6224# ifdef FEAT_MOUSE_GPM
6225 "mouse_gpm",
6226# endif
6227# ifdef FEAT_MOUSE_JSB
6228 "mouse_jsbterm",
6229# endif
6230# ifdef FEAT_MOUSE_NET
6231 "mouse_netterm",
6232# endif
6233# ifdef FEAT_MOUSE_PTERM
6234 "mouse_pterm",
6235# endif
6236# ifdef FEAT_MOUSE_SGR
6237 "mouse_sgr",
6238# endif
6239# ifdef FEAT_SYSMOUSE
6240 "mouse_sysmouse",
6241# endif
6242# ifdef FEAT_MOUSE_URXVT
6243 "mouse_urxvt",
6244# endif
6245# ifdef FEAT_MOUSE_XTERM
6246 "mouse_xterm",
6247# endif
6248#endif
6249#ifdef FEAT_MBYTE
6250 "multi_byte",
6251#endif
6252#ifdef FEAT_MBYTE_IME
6253 "multi_byte_ime",
6254#endif
6255#ifdef FEAT_MULTI_LANG
6256 "multi_lang",
6257#endif
6258#ifdef FEAT_MZSCHEME
6259#ifndef DYNAMIC_MZSCHEME
6260 "mzscheme",
6261#endif
6262#endif
6263#ifdef FEAT_NUM64
6264 "num64",
6265#endif
6266#ifdef FEAT_OLE
6267 "ole",
6268#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006269#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006271#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272#ifdef FEAT_PATH_EXTRA
6273 "path_extra",
6274#endif
6275#ifdef FEAT_PERL
6276#ifndef DYNAMIC_PERL
6277 "perl",
6278#endif
6279#endif
6280#ifdef FEAT_PERSISTENT_UNDO
6281 "persistent_undo",
6282#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006283#if defined(FEAT_PYTHON)
6284 "python_compiled",
6285# if defined(DYNAMIC_PYTHON)
6286 "python_dynamic",
6287# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006288 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006289 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006290# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006292#if defined(FEAT_PYTHON3)
6293 "python3_compiled",
6294# if defined(DYNAMIC_PYTHON3)
6295 "python3_dynamic",
6296# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006298 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006299# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300#endif
6301#ifdef FEAT_POSTSCRIPT
6302 "postscript",
6303#endif
6304#ifdef FEAT_PRINTER
6305 "printer",
6306#endif
6307#ifdef FEAT_PROFILE
6308 "profile",
6309#endif
6310#ifdef FEAT_RELTIME
6311 "reltime",
6312#endif
6313#ifdef FEAT_QUICKFIX
6314 "quickfix",
6315#endif
6316#ifdef FEAT_RIGHTLEFT
6317 "rightleft",
6318#endif
6319#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6320 "ruby",
6321#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323#ifdef FEAT_CMDL_INFO
6324 "showcmd",
6325 "cmdline_info",
6326#endif
6327#ifdef FEAT_SIGNS
6328 "signs",
6329#endif
6330#ifdef FEAT_SMARTINDENT
6331 "smartindent",
6332#endif
6333#ifdef STARTUPTIME
6334 "startuptime",
6335#endif
6336#ifdef FEAT_STL_OPT
6337 "statusline",
6338#endif
6339#ifdef FEAT_SUN_WORKSHOP
6340 "sun_workshop",
6341#endif
6342#ifdef FEAT_NETBEANS_INTG
6343 "netbeans_intg",
6344#endif
6345#ifdef FEAT_SPELL
6346 "spell",
6347#endif
6348#ifdef FEAT_SYN_HL
6349 "syntax",
6350#endif
6351#if defined(USE_SYSTEM) || !defined(UNIX)
6352 "system",
6353#endif
6354#ifdef FEAT_TAG_BINS
6355 "tag_binary",
6356#endif
6357#ifdef FEAT_TAG_OLDSTATIC
6358 "tag_old_static",
6359#endif
6360#ifdef FEAT_TAG_ANYWHITE
6361 "tag_any_white",
6362#endif
6363#ifdef FEAT_TCL
6364# ifndef DYNAMIC_TCL
6365 "tcl",
6366# endif
6367#endif
6368#ifdef FEAT_TERMGUICOLORS
6369 "termguicolors",
6370#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006371#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006372 "terminal",
6373#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006374#ifdef TERMINFO
6375 "terminfo",
6376#endif
6377#ifdef FEAT_TERMRESPONSE
6378 "termresponse",
6379#endif
6380#ifdef FEAT_TEXTOBJ
6381 "textobjects",
6382#endif
6383#ifdef HAVE_TGETENT
6384 "tgetent",
6385#endif
6386#ifdef FEAT_TIMERS
6387 "timers",
6388#endif
6389#ifdef FEAT_TITLE
6390 "title",
6391#endif
6392#ifdef FEAT_TOOLBAR
6393 "toolbar",
6394#endif
6395#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6396 "unnamedplus",
6397#endif
6398#ifdef FEAT_USR_CMDS
6399 "user-commands", /* was accidentally included in 5.4 */
6400 "user_commands",
6401#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006402#ifdef FEAT_VARTABS
6403 "vartabs",
6404#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006405#ifdef FEAT_VIMINFO
6406 "viminfo",
6407#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006408 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006409#ifdef FEAT_VIRTUALEDIT
6410 "virtualedit",
6411#endif
6412 "visual",
6413#ifdef FEAT_VISUALEXTRA
6414 "visualextra",
6415#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006417#ifdef FEAT_VTP
6418 "vtp",
6419#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420#ifdef FEAT_WILDIGN
6421 "wildignore",
6422#endif
6423#ifdef FEAT_WILDMENU
6424 "wildmenu",
6425#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427#ifdef FEAT_WAK
6428 "winaltkeys",
6429#endif
6430#ifdef FEAT_WRITEBACKUP
6431 "writebackup",
6432#endif
6433#ifdef FEAT_XIM
6434 "xim",
6435#endif
6436#ifdef FEAT_XFONTSET
6437 "xfontset",
6438#endif
6439#ifdef FEAT_XPM_W32
6440 "xpm",
6441 "xpm_w32", /* for backward compatibility */
6442#else
6443# if defined(HAVE_XPM)
6444 "xpm",
6445# endif
6446#endif
6447#ifdef USE_XSMP
6448 "xsmp",
6449#endif
6450#ifdef USE_XSMP_INTERACT
6451 "xsmp_interact",
6452#endif
6453#ifdef FEAT_XCLIPBOARD
6454 "xterm_clipboard",
6455#endif
6456#ifdef FEAT_XTERM_SAVE
6457 "xterm_save",
6458#endif
6459#if defined(UNIX) && defined(FEAT_X11)
6460 "X11",
6461#endif
6462 NULL
6463 };
6464
6465 name = get_tv_string(&argvars[0]);
6466 for (i = 0; has_list[i] != NULL; ++i)
6467 if (STRICMP(name, has_list[i]) == 0)
6468 {
6469 n = TRUE;
6470 break;
6471 }
6472
6473 if (n == FALSE)
6474 {
6475 if (STRNICMP(name, "patch", 5) == 0)
6476 {
6477 if (name[5] == '-'
6478 && STRLEN(name) >= 11
6479 && vim_isdigit(name[6])
6480 && vim_isdigit(name[8])
6481 && vim_isdigit(name[10]))
6482 {
6483 int major = atoi((char *)name + 6);
6484 int minor = atoi((char *)name + 8);
6485
6486 /* Expect "patch-9.9.01234". */
6487 n = (major < VIM_VERSION_MAJOR
6488 || (major == VIM_VERSION_MAJOR
6489 && (minor < VIM_VERSION_MINOR
6490 || (minor == VIM_VERSION_MINOR
6491 && has_patch(atoi((char *)name + 10))))));
6492 }
6493 else
6494 n = has_patch(atoi((char *)name + 5));
6495 }
6496 else if (STRICMP(name, "vim_starting") == 0)
6497 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006498 else if (STRICMP(name, "ttyin") == 0)
6499 n = mch_input_isatty();
6500 else if (STRICMP(name, "ttyout") == 0)
6501 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502#ifdef FEAT_MBYTE
6503 else if (STRICMP(name, "multi_byte_encoding") == 0)
6504 n = has_mbyte;
6505#endif
6506#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6507 else if (STRICMP(name, "balloon_multiline") == 0)
6508 n = multiline_balloon_available();
6509#endif
6510#ifdef DYNAMIC_TCL
6511 else if (STRICMP(name, "tcl") == 0)
6512 n = tcl_enabled(FALSE);
6513#endif
6514#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6515 else if (STRICMP(name, "iconv") == 0)
6516 n = iconv_enabled(FALSE);
6517#endif
6518#ifdef DYNAMIC_LUA
6519 else if (STRICMP(name, "lua") == 0)
6520 n = lua_enabled(FALSE);
6521#endif
6522#ifdef DYNAMIC_MZSCHEME
6523 else if (STRICMP(name, "mzscheme") == 0)
6524 n = mzscheme_enabled(FALSE);
6525#endif
6526#ifdef DYNAMIC_RUBY
6527 else if (STRICMP(name, "ruby") == 0)
6528 n = ruby_enabled(FALSE);
6529#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006530#ifdef DYNAMIC_PYTHON
6531 else if (STRICMP(name, "python") == 0)
6532 n = python_enabled(FALSE);
6533#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006534#ifdef DYNAMIC_PYTHON3
6535 else if (STRICMP(name, "python3") == 0)
6536 n = python3_enabled(FALSE);
6537#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006538#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6539 else if (STRICMP(name, "pythonx") == 0)
6540 {
6541# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6542 if (p_pyx == 0)
6543 n = python3_enabled(FALSE) || python_enabled(FALSE);
6544 else if (p_pyx == 3)
6545 n = python3_enabled(FALSE);
6546 else if (p_pyx == 2)
6547 n = python_enabled(FALSE);
6548# elif defined(DYNAMIC_PYTHON)
6549 n = python_enabled(FALSE);
6550# elif defined(DYNAMIC_PYTHON3)
6551 n = python3_enabled(FALSE);
6552# endif
6553 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554#endif
6555#ifdef DYNAMIC_PERL
6556 else if (STRICMP(name, "perl") == 0)
6557 n = perl_enabled(FALSE);
6558#endif
6559#ifdef FEAT_GUI
6560 else if (STRICMP(name, "gui_running") == 0)
6561 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562# ifdef FEAT_BROWSE
6563 else if (STRICMP(name, "browse") == 0)
6564 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6565# endif
6566#endif
6567#ifdef FEAT_SYN_HL
6568 else if (STRICMP(name, "syntax_items") == 0)
6569 n = syntax_present(curwin);
6570#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006571#ifdef FEAT_VTP
6572 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006573 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574#endif
6575#ifdef FEAT_NETBEANS_INTG
6576 else if (STRICMP(name, "netbeans_enabled") == 0)
6577 n = netbeans_active();
6578#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006579#if defined(FEAT_TERMINAL) && defined(WIN3264)
6580 else if (STRICMP(name, "terminal") == 0)
6581 n = terminal_enabled();
6582#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583 }
6584
6585 rettv->vval.v_number = n;
6586}
6587
6588/*
6589 * "has_key()" function
6590 */
6591 static void
6592f_has_key(typval_T *argvars, typval_T *rettv)
6593{
6594 if (argvars[0].v_type != VAR_DICT)
6595 {
6596 EMSG(_(e_dictreq));
6597 return;
6598 }
6599 if (argvars[0].vval.v_dict == NULL)
6600 return;
6601
6602 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6603 get_tv_string(&argvars[1]), -1) != NULL;
6604}
6605
6606/*
6607 * "haslocaldir()" function
6608 */
6609 static void
6610f_haslocaldir(typval_T *argvars, typval_T *rettv)
6611{
6612 win_T *wp = NULL;
6613
6614 wp = find_tabwin(&argvars[0], &argvars[1]);
6615 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6616}
6617
6618/*
6619 * "hasmapto()" function
6620 */
6621 static void
6622f_hasmapto(typval_T *argvars, typval_T *rettv)
6623{
6624 char_u *name;
6625 char_u *mode;
6626 char_u buf[NUMBUFLEN];
6627 int abbr = FALSE;
6628
6629 name = get_tv_string(&argvars[0]);
6630 if (argvars[1].v_type == VAR_UNKNOWN)
6631 mode = (char_u *)"nvo";
6632 else
6633 {
6634 mode = get_tv_string_buf(&argvars[1], buf);
6635 if (argvars[2].v_type != VAR_UNKNOWN)
6636 abbr = (int)get_tv_number(&argvars[2]);
6637 }
6638
6639 if (map_to_exists(name, mode, abbr))
6640 rettv->vval.v_number = TRUE;
6641 else
6642 rettv->vval.v_number = FALSE;
6643}
6644
6645/*
6646 * "histadd()" function
6647 */
6648 static void
6649f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6650{
6651#ifdef FEAT_CMDHIST
6652 int histype;
6653 char_u *str;
6654 char_u buf[NUMBUFLEN];
6655#endif
6656
6657 rettv->vval.v_number = FALSE;
6658 if (check_restricted() || check_secure())
6659 return;
6660#ifdef FEAT_CMDHIST
6661 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6662 histype = str != NULL ? get_histtype(str) : -1;
6663 if (histype >= 0)
6664 {
6665 str = get_tv_string_buf(&argvars[1], buf);
6666 if (*str != NUL)
6667 {
6668 init_history();
6669 add_to_history(histype, str, FALSE, NUL);
6670 rettv->vval.v_number = TRUE;
6671 return;
6672 }
6673 }
6674#endif
6675}
6676
6677/*
6678 * "histdel()" function
6679 */
6680 static void
6681f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6682{
6683#ifdef FEAT_CMDHIST
6684 int n;
6685 char_u buf[NUMBUFLEN];
6686 char_u *str;
6687
6688 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6689 if (str == NULL)
6690 n = 0;
6691 else if (argvars[1].v_type == VAR_UNKNOWN)
6692 /* only one argument: clear entire history */
6693 n = clr_history(get_histtype(str));
6694 else if (argvars[1].v_type == VAR_NUMBER)
6695 /* index given: remove that entry */
6696 n = del_history_idx(get_histtype(str),
6697 (int)get_tv_number(&argvars[1]));
6698 else
6699 /* string given: remove all matching entries */
6700 n = del_history_entry(get_histtype(str),
6701 get_tv_string_buf(&argvars[1], buf));
6702 rettv->vval.v_number = n;
6703#endif
6704}
6705
6706/*
6707 * "histget()" function
6708 */
6709 static void
6710f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6711{
6712#ifdef FEAT_CMDHIST
6713 int type;
6714 int idx;
6715 char_u *str;
6716
6717 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6718 if (str == NULL)
6719 rettv->vval.v_string = NULL;
6720 else
6721 {
6722 type = get_histtype(str);
6723 if (argvars[1].v_type == VAR_UNKNOWN)
6724 idx = get_history_idx(type);
6725 else
6726 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6727 /* -1 on type error */
6728 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6729 }
6730#else
6731 rettv->vval.v_string = NULL;
6732#endif
6733 rettv->v_type = VAR_STRING;
6734}
6735
6736/*
6737 * "histnr()" function
6738 */
6739 static void
6740f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6741{
6742 int i;
6743
6744#ifdef FEAT_CMDHIST
6745 char_u *history = get_tv_string_chk(&argvars[0]);
6746
6747 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6748 if (i >= HIST_CMD && i < HIST_COUNT)
6749 i = get_history_idx(i);
6750 else
6751#endif
6752 i = -1;
6753 rettv->vval.v_number = i;
6754}
6755
6756/*
6757 * "highlightID(name)" function
6758 */
6759 static void
6760f_hlID(typval_T *argvars, typval_T *rettv)
6761{
6762 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6763}
6764
6765/*
6766 * "highlight_exists()" function
6767 */
6768 static void
6769f_hlexists(typval_T *argvars, typval_T *rettv)
6770{
6771 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6772}
6773
6774/*
6775 * "hostname()" function
6776 */
6777 static void
6778f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6779{
6780 char_u hostname[256];
6781
6782 mch_get_host_name(hostname, 256);
6783 rettv->v_type = VAR_STRING;
6784 rettv->vval.v_string = vim_strsave(hostname);
6785}
6786
6787/*
6788 * iconv() function
6789 */
6790 static void
6791f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6792{
6793#ifdef FEAT_MBYTE
6794 char_u buf1[NUMBUFLEN];
6795 char_u buf2[NUMBUFLEN];
6796 char_u *from, *to, *str;
6797 vimconv_T vimconv;
6798#endif
6799
6800 rettv->v_type = VAR_STRING;
6801 rettv->vval.v_string = NULL;
6802
6803#ifdef FEAT_MBYTE
6804 str = get_tv_string(&argvars[0]);
6805 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6806 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6807 vimconv.vc_type = CONV_NONE;
6808 convert_setup(&vimconv, from, to);
6809
6810 /* If the encodings are equal, no conversion needed. */
6811 if (vimconv.vc_type == CONV_NONE)
6812 rettv->vval.v_string = vim_strsave(str);
6813 else
6814 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6815
6816 convert_setup(&vimconv, NULL, NULL);
6817 vim_free(from);
6818 vim_free(to);
6819#endif
6820}
6821
6822/*
6823 * "indent()" function
6824 */
6825 static void
6826f_indent(typval_T *argvars, typval_T *rettv)
6827{
6828 linenr_T lnum;
6829
6830 lnum = get_tv_lnum(argvars);
6831 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6832 rettv->vval.v_number = get_indent_lnum(lnum);
6833 else
6834 rettv->vval.v_number = -1;
6835}
6836
6837/*
6838 * "index()" function
6839 */
6840 static void
6841f_index(typval_T *argvars, typval_T *rettv)
6842{
6843 list_T *l;
6844 listitem_T *item;
6845 long idx = 0;
6846 int ic = FALSE;
6847
6848 rettv->vval.v_number = -1;
6849 if (argvars[0].v_type != VAR_LIST)
6850 {
6851 EMSG(_(e_listreq));
6852 return;
6853 }
6854 l = argvars[0].vval.v_list;
6855 if (l != NULL)
6856 {
6857 item = l->lv_first;
6858 if (argvars[2].v_type != VAR_UNKNOWN)
6859 {
6860 int error = FALSE;
6861
6862 /* Start at specified item. Use the cached index that list_find()
6863 * sets, so that a negative number also works. */
6864 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6865 idx = l->lv_idx;
6866 if (argvars[3].v_type != VAR_UNKNOWN)
6867 ic = (int)get_tv_number_chk(&argvars[3], &error);
6868 if (error)
6869 item = NULL;
6870 }
6871
6872 for ( ; item != NULL; item = item->li_next, ++idx)
6873 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6874 {
6875 rettv->vval.v_number = idx;
6876 break;
6877 }
6878 }
6879}
6880
6881static int inputsecret_flag = 0;
6882
6883/*
6884 * "input()" function
6885 * Also handles inputsecret() when inputsecret is set.
6886 */
6887 static void
6888f_input(typval_T *argvars, typval_T *rettv)
6889{
6890 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6891}
6892
6893/*
6894 * "inputdialog()" function
6895 */
6896 static void
6897f_inputdialog(typval_T *argvars, typval_T *rettv)
6898{
6899#if defined(FEAT_GUI_TEXTDIALOG)
6900 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6901 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6902 {
6903 char_u *message;
6904 char_u buf[NUMBUFLEN];
6905 char_u *defstr = (char_u *)"";
6906
6907 message = get_tv_string_chk(&argvars[0]);
6908 if (argvars[1].v_type != VAR_UNKNOWN
6909 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6910 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6911 else
6912 IObuff[0] = NUL;
6913 if (message != NULL && defstr != NULL
6914 && do_dialog(VIM_QUESTION, NULL, message,
6915 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6916 rettv->vval.v_string = vim_strsave(IObuff);
6917 else
6918 {
6919 if (message != NULL && defstr != NULL
6920 && argvars[1].v_type != VAR_UNKNOWN
6921 && argvars[2].v_type != VAR_UNKNOWN)
6922 rettv->vval.v_string = vim_strsave(
6923 get_tv_string_buf(&argvars[2], buf));
6924 else
6925 rettv->vval.v_string = NULL;
6926 }
6927 rettv->v_type = VAR_STRING;
6928 }
6929 else
6930#endif
6931 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6932}
6933
6934/*
6935 * "inputlist()" function
6936 */
6937 static void
6938f_inputlist(typval_T *argvars, typval_T *rettv)
6939{
6940 listitem_T *li;
6941 int selected;
6942 int mouse_used;
6943
6944#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006945 /* While starting up, there is no place to enter text. When running tests
6946 * with --not-a-term we assume feedkeys() will be used. */
6947 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 return;
6949#endif
6950 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6951 {
6952 EMSG2(_(e_listarg), "inputlist()");
6953 return;
6954 }
6955
6956 msg_start();
6957 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6958 lines_left = Rows; /* avoid more prompt */
6959 msg_scroll = TRUE;
6960 msg_clr_eos();
6961
6962 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6963 {
6964 msg_puts(get_tv_string(&li->li_tv));
6965 msg_putchar('\n');
6966 }
6967
6968 /* Ask for choice. */
6969 selected = prompt_for_number(&mouse_used);
6970 if (mouse_used)
6971 selected -= lines_left;
6972
6973 rettv->vval.v_number = selected;
6974}
6975
6976
6977static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6978
6979/*
6980 * "inputrestore()" function
6981 */
6982 static void
6983f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6984{
6985 if (ga_userinput.ga_len > 0)
6986 {
6987 --ga_userinput.ga_len;
6988 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6989 + ga_userinput.ga_len);
6990 /* default return is zero == OK */
6991 }
6992 else if (p_verbose > 1)
6993 {
6994 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6995 rettv->vval.v_number = 1; /* Failed */
6996 }
6997}
6998
6999/*
7000 * "inputsave()" function
7001 */
7002 static void
7003f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7004{
7005 /* Add an entry to the stack of typeahead storage. */
7006 if (ga_grow(&ga_userinput, 1) == OK)
7007 {
7008 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7009 + ga_userinput.ga_len);
7010 ++ga_userinput.ga_len;
7011 /* default return is zero == OK */
7012 }
7013 else
7014 rettv->vval.v_number = 1; /* Failed */
7015}
7016
7017/*
7018 * "inputsecret()" function
7019 */
7020 static void
7021f_inputsecret(typval_T *argvars, typval_T *rettv)
7022{
7023 ++cmdline_star;
7024 ++inputsecret_flag;
7025 f_input(argvars, rettv);
7026 --cmdline_star;
7027 --inputsecret_flag;
7028}
7029
7030/*
7031 * "insert()" function
7032 */
7033 static void
7034f_insert(typval_T *argvars, typval_T *rettv)
7035{
7036 long before = 0;
7037 listitem_T *item;
7038 list_T *l;
7039 int error = FALSE;
7040
7041 if (argvars[0].v_type != VAR_LIST)
7042 EMSG2(_(e_listarg), "insert()");
7043 else if ((l = argvars[0].vval.v_list) != NULL
7044 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7045 {
7046 if (argvars[2].v_type != VAR_UNKNOWN)
7047 before = (long)get_tv_number_chk(&argvars[2], &error);
7048 if (error)
7049 return; /* type error; errmsg already given */
7050
7051 if (before == l->lv_len)
7052 item = NULL;
7053 else
7054 {
7055 item = list_find(l, before);
7056 if (item == NULL)
7057 {
7058 EMSGN(_(e_listidx), before);
7059 l = NULL;
7060 }
7061 }
7062 if (l != NULL)
7063 {
7064 list_insert_tv(l, &argvars[1], item);
7065 copy_tv(&argvars[0], rettv);
7066 }
7067 }
7068}
7069
7070/*
7071 * "invert(expr)" function
7072 */
7073 static void
7074f_invert(typval_T *argvars, typval_T *rettv)
7075{
7076 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
7077}
7078
7079/*
7080 * "isdirectory()" function
7081 */
7082 static void
7083f_isdirectory(typval_T *argvars, typval_T *rettv)
7084{
7085 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
7086}
7087
7088/*
7089 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7090 * or it refers to a List or Dictionary that is locked.
7091 */
7092 static int
7093tv_islocked(typval_T *tv)
7094{
7095 return (tv->v_lock & VAR_LOCKED)
7096 || (tv->v_type == VAR_LIST
7097 && tv->vval.v_list != NULL
7098 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7099 || (tv->v_type == VAR_DICT
7100 && tv->vval.v_dict != NULL
7101 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7102}
7103
7104/*
7105 * "islocked()" function
7106 */
7107 static void
7108f_islocked(typval_T *argvars, typval_T *rettv)
7109{
7110 lval_T lv;
7111 char_u *end;
7112 dictitem_T *di;
7113
7114 rettv->vval.v_number = -1;
7115 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007116 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007117 if (end != NULL && lv.ll_name != NULL)
7118 {
7119 if (*end != NUL)
7120 EMSG(_(e_trailing));
7121 else
7122 {
7123 if (lv.ll_tv == NULL)
7124 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007125 di = find_var(lv.ll_name, NULL, TRUE);
7126 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007127 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007128 /* Consider a variable locked when:
7129 * 1. the variable itself is locked
7130 * 2. the value of the variable is locked.
7131 * 3. the List or Dict value is locked.
7132 */
7133 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7134 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 }
7136 }
7137 else if (lv.ll_range)
7138 EMSG(_("E786: Range not allowed"));
7139 else if (lv.ll_newkey != NULL)
7140 EMSG2(_(e_dictkey), lv.ll_newkey);
7141 else if (lv.ll_list != NULL)
7142 /* List item. */
7143 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7144 else
7145 /* Dictionary item. */
7146 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7147 }
7148 }
7149
7150 clear_lval(&lv);
7151}
7152
7153#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7154/*
7155 * "isnan()" function
7156 */
7157 static void
7158f_isnan(typval_T *argvars, typval_T *rettv)
7159{
7160 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7161 && isnan(argvars[0].vval.v_float);
7162}
7163#endif
7164
7165/*
7166 * "items(dict)" function
7167 */
7168 static void
7169f_items(typval_T *argvars, typval_T *rettv)
7170{
7171 dict_list(argvars, rettv, 2);
7172}
7173
7174#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7175/*
7176 * Get the job from the argument.
7177 * Returns NULL if the job is invalid.
7178 */
7179 static job_T *
7180get_job_arg(typval_T *tv)
7181{
7182 job_T *job;
7183
7184 if (tv->v_type != VAR_JOB)
7185 {
7186 EMSG2(_(e_invarg2), get_tv_string(tv));
7187 return NULL;
7188 }
7189 job = tv->vval.v_job;
7190
7191 if (job == NULL)
7192 EMSG(_("E916: not a valid job"));
7193 return job;
7194}
7195
7196/*
7197 * "job_getchannel()" function
7198 */
7199 static void
7200f_job_getchannel(typval_T *argvars, typval_T *rettv)
7201{
7202 job_T *job = get_job_arg(&argvars[0]);
7203
7204 if (job != NULL)
7205 {
7206 rettv->v_type = VAR_CHANNEL;
7207 rettv->vval.v_channel = job->jv_channel;
7208 if (job->jv_channel != NULL)
7209 ++job->jv_channel->ch_refcount;
7210 }
7211}
7212
7213/*
7214 * "job_info()" function
7215 */
7216 static void
7217f_job_info(typval_T *argvars, typval_T *rettv)
7218{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007219 if (argvars[0].v_type != VAR_UNKNOWN)
7220 {
7221 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007222
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007223 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7224 job_info(job, rettv->vval.v_dict);
7225 }
7226 else if (rettv_list_alloc(rettv) == OK)
7227 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228}
7229
7230/*
7231 * "job_setoptions()" function
7232 */
7233 static void
7234f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7235{
7236 job_T *job = get_job_arg(&argvars[0]);
7237 jobopt_T opt;
7238
7239 if (job == NULL)
7240 return;
7241 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007242 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007243 job_set_options(job, &opt);
7244 free_job_options(&opt);
7245}
7246
7247/*
7248 * "job_start()" function
7249 */
7250 static void
7251f_job_start(typval_T *argvars, typval_T *rettv)
7252{
7253 rettv->v_type = VAR_JOB;
7254 if (check_restricted() || check_secure())
7255 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007256 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007257}
7258
7259/*
7260 * "job_status()" function
7261 */
7262 static void
7263f_job_status(typval_T *argvars, typval_T *rettv)
7264{
7265 job_T *job = get_job_arg(&argvars[0]);
7266
7267 if (job != NULL)
7268 {
7269 rettv->v_type = VAR_STRING;
7270 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7271 }
7272}
7273
7274/*
7275 * "job_stop()" function
7276 */
7277 static void
7278f_job_stop(typval_T *argvars, typval_T *rettv)
7279{
7280 job_T *job = get_job_arg(&argvars[0]);
7281
7282 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007283 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007284}
7285#endif
7286
7287/*
7288 * "join()" function
7289 */
7290 static void
7291f_join(typval_T *argvars, typval_T *rettv)
7292{
7293 garray_T ga;
7294 char_u *sep;
7295
7296 if (argvars[0].v_type != VAR_LIST)
7297 {
7298 EMSG(_(e_listreq));
7299 return;
7300 }
7301 if (argvars[0].vval.v_list == NULL)
7302 return;
7303 if (argvars[1].v_type == VAR_UNKNOWN)
7304 sep = (char_u *)" ";
7305 else
7306 sep = get_tv_string_chk(&argvars[1]);
7307
7308 rettv->v_type = VAR_STRING;
7309
7310 if (sep != NULL)
7311 {
7312 ga_init2(&ga, (int)sizeof(char), 80);
7313 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7314 ga_append(&ga, NUL);
7315 rettv->vval.v_string = (char_u *)ga.ga_data;
7316 }
7317 else
7318 rettv->vval.v_string = NULL;
7319}
7320
7321/*
7322 * "js_decode()" function
7323 */
7324 static void
7325f_js_decode(typval_T *argvars, typval_T *rettv)
7326{
7327 js_read_T reader;
7328
7329 reader.js_buf = get_tv_string(&argvars[0]);
7330 reader.js_fill = NULL;
7331 reader.js_used = 0;
7332 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7333 EMSG(_(e_invarg));
7334}
7335
7336/*
7337 * "js_encode()" function
7338 */
7339 static void
7340f_js_encode(typval_T *argvars, typval_T *rettv)
7341{
7342 rettv->v_type = VAR_STRING;
7343 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7344}
7345
7346/*
7347 * "json_decode()" function
7348 */
7349 static void
7350f_json_decode(typval_T *argvars, typval_T *rettv)
7351{
7352 js_read_T reader;
7353
7354 reader.js_buf = get_tv_string(&argvars[0]);
7355 reader.js_fill = NULL;
7356 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007357 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358}
7359
7360/*
7361 * "json_encode()" function
7362 */
7363 static void
7364f_json_encode(typval_T *argvars, typval_T *rettv)
7365{
7366 rettv->v_type = VAR_STRING;
7367 rettv->vval.v_string = json_encode(&argvars[0], 0);
7368}
7369
7370/*
7371 * "keys()" function
7372 */
7373 static void
7374f_keys(typval_T *argvars, typval_T *rettv)
7375{
7376 dict_list(argvars, rettv, 0);
7377}
7378
7379/*
7380 * "last_buffer_nr()" function.
7381 */
7382 static void
7383f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7384{
7385 int n = 0;
7386 buf_T *buf;
7387
Bram Moolenaar29323592016-07-24 22:04:11 +02007388 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389 if (n < buf->b_fnum)
7390 n = buf->b_fnum;
7391
7392 rettv->vval.v_number = n;
7393}
7394
7395/*
7396 * "len()" function
7397 */
7398 static void
7399f_len(typval_T *argvars, typval_T *rettv)
7400{
7401 switch (argvars[0].v_type)
7402 {
7403 case VAR_STRING:
7404 case VAR_NUMBER:
7405 rettv->vval.v_number = (varnumber_T)STRLEN(
7406 get_tv_string(&argvars[0]));
7407 break;
7408 case VAR_LIST:
7409 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7410 break;
7411 case VAR_DICT:
7412 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7413 break;
7414 case VAR_UNKNOWN:
7415 case VAR_SPECIAL:
7416 case VAR_FLOAT:
7417 case VAR_FUNC:
7418 case VAR_PARTIAL:
7419 case VAR_JOB:
7420 case VAR_CHANNEL:
7421 EMSG(_("E701: Invalid type for len()"));
7422 break;
7423 }
7424}
7425
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007427libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428{
7429#ifdef FEAT_LIBCALL
7430 char_u *string_in;
7431 char_u **string_result;
7432 int nr_result;
7433#endif
7434
7435 rettv->v_type = type;
7436 if (type != VAR_NUMBER)
7437 rettv->vval.v_string = NULL;
7438
7439 if (check_restricted() || check_secure())
7440 return;
7441
7442#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007443 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007444 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7445 {
7446 string_in = NULL;
7447 if (argvars[2].v_type == VAR_STRING)
7448 string_in = argvars[2].vval.v_string;
7449 if (type == VAR_NUMBER)
7450 string_result = NULL;
7451 else
7452 string_result = &rettv->vval.v_string;
7453 if (mch_libcall(argvars[0].vval.v_string,
7454 argvars[1].vval.v_string,
7455 string_in,
7456 argvars[2].vval.v_number,
7457 string_result,
7458 &nr_result) == OK
7459 && type == VAR_NUMBER)
7460 rettv->vval.v_number = nr_result;
7461 }
7462#endif
7463}
7464
7465/*
7466 * "libcall()" function
7467 */
7468 static void
7469f_libcall(typval_T *argvars, typval_T *rettv)
7470{
7471 libcall_common(argvars, rettv, VAR_STRING);
7472}
7473
7474/*
7475 * "libcallnr()" function
7476 */
7477 static void
7478f_libcallnr(typval_T *argvars, typval_T *rettv)
7479{
7480 libcall_common(argvars, rettv, VAR_NUMBER);
7481}
7482
7483/*
7484 * "line(string)" function
7485 */
7486 static void
7487f_line(typval_T *argvars, typval_T *rettv)
7488{
7489 linenr_T lnum = 0;
7490 pos_T *fp;
7491 int fnum;
7492
7493 fp = var2fpos(&argvars[0], TRUE, &fnum);
7494 if (fp != NULL)
7495 lnum = fp->lnum;
7496 rettv->vval.v_number = lnum;
7497}
7498
7499/*
7500 * "line2byte(lnum)" function
7501 */
7502 static void
7503f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7504{
7505#ifndef FEAT_BYTEOFF
7506 rettv->vval.v_number = -1;
7507#else
7508 linenr_T lnum;
7509
7510 lnum = get_tv_lnum(argvars);
7511 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7512 rettv->vval.v_number = -1;
7513 else
7514 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7515 if (rettv->vval.v_number >= 0)
7516 ++rettv->vval.v_number;
7517#endif
7518}
7519
7520/*
7521 * "lispindent(lnum)" function
7522 */
7523 static void
7524f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7525{
7526#ifdef FEAT_LISP
7527 pos_T pos;
7528 linenr_T lnum;
7529
7530 pos = curwin->w_cursor;
7531 lnum = get_tv_lnum(argvars);
7532 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7533 {
7534 curwin->w_cursor.lnum = lnum;
7535 rettv->vval.v_number = get_lisp_indent();
7536 curwin->w_cursor = pos;
7537 }
7538 else
7539#endif
7540 rettv->vval.v_number = -1;
7541}
7542
7543/*
7544 * "localtime()" function
7545 */
7546 static void
7547f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7548{
7549 rettv->vval.v_number = (varnumber_T)time(NULL);
7550}
7551
7552static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7553
7554 static void
7555get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7556{
7557 char_u *keys;
7558 char_u *which;
7559 char_u buf[NUMBUFLEN];
7560 char_u *keys_buf = NULL;
7561 char_u *rhs;
7562 int mode;
7563 int abbr = FALSE;
7564 int get_dict = FALSE;
7565 mapblock_T *mp;
7566 int buffer_local;
7567
7568 /* return empty string for failure */
7569 rettv->v_type = VAR_STRING;
7570 rettv->vval.v_string = NULL;
7571
7572 keys = get_tv_string(&argvars[0]);
7573 if (*keys == NUL)
7574 return;
7575
7576 if (argvars[1].v_type != VAR_UNKNOWN)
7577 {
7578 which = get_tv_string_buf_chk(&argvars[1], buf);
7579 if (argvars[2].v_type != VAR_UNKNOWN)
7580 {
7581 abbr = (int)get_tv_number(&argvars[2]);
7582 if (argvars[3].v_type != VAR_UNKNOWN)
7583 get_dict = (int)get_tv_number(&argvars[3]);
7584 }
7585 }
7586 else
7587 which = (char_u *)"";
7588 if (which == NULL)
7589 return;
7590
7591 mode = get_map_mode(&which, 0);
7592
7593 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7594 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7595 vim_free(keys_buf);
7596
7597 if (!get_dict)
7598 {
7599 /* Return a string. */
7600 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007601 {
7602 if (*rhs == NUL)
7603 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7604 else
7605 rettv->vval.v_string = str2special_save(rhs, FALSE);
7606 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007607
7608 }
7609 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7610 {
7611 /* Return a dictionary. */
7612 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7613 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7614 dict_T *dict = rettv->vval.v_dict;
7615
Bram Moolenaare0be1672018-07-08 16:50:37 +02007616 dict_add_string(dict, "lhs", lhs);
7617 dict_add_string(dict, "rhs", mp->m_orig_str);
7618 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7619 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7620 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
7621 dict_add_number(dict, "sid", (long)mp->m_script_ID);
7622 dict_add_number(dict, "buffer", (long)buffer_local);
7623 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7624 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007625
7626 vim_free(lhs);
7627 vim_free(mapmode);
7628 }
7629}
7630
7631#ifdef FEAT_FLOAT
7632/*
7633 * "log()" function
7634 */
7635 static void
7636f_log(typval_T *argvars, typval_T *rettv)
7637{
7638 float_T f = 0.0;
7639
7640 rettv->v_type = VAR_FLOAT;
7641 if (get_float_arg(argvars, &f) == OK)
7642 rettv->vval.v_float = log(f);
7643 else
7644 rettv->vval.v_float = 0.0;
7645}
7646
7647/*
7648 * "log10()" function
7649 */
7650 static void
7651f_log10(typval_T *argvars, typval_T *rettv)
7652{
7653 float_T f = 0.0;
7654
7655 rettv->v_type = VAR_FLOAT;
7656 if (get_float_arg(argvars, &f) == OK)
7657 rettv->vval.v_float = log10(f);
7658 else
7659 rettv->vval.v_float = 0.0;
7660}
7661#endif
7662
7663#ifdef FEAT_LUA
7664/*
7665 * "luaeval()" function
7666 */
7667 static void
7668f_luaeval(typval_T *argvars, typval_T *rettv)
7669{
7670 char_u *str;
7671 char_u buf[NUMBUFLEN];
7672
7673 str = get_tv_string_buf(&argvars[0], buf);
7674 do_luaeval(str, argvars + 1, rettv);
7675}
7676#endif
7677
7678/*
7679 * "map()" function
7680 */
7681 static void
7682f_map(typval_T *argvars, typval_T *rettv)
7683{
7684 filter_map(argvars, rettv, TRUE);
7685}
7686
7687/*
7688 * "maparg()" function
7689 */
7690 static void
7691f_maparg(typval_T *argvars, typval_T *rettv)
7692{
7693 get_maparg(argvars, rettv, TRUE);
7694}
7695
7696/*
7697 * "mapcheck()" function
7698 */
7699 static void
7700f_mapcheck(typval_T *argvars, typval_T *rettv)
7701{
7702 get_maparg(argvars, rettv, FALSE);
7703}
7704
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007705typedef enum
7706{
7707 MATCH_END, /* matchend() */
7708 MATCH_MATCH, /* match() */
7709 MATCH_STR, /* matchstr() */
7710 MATCH_LIST, /* matchlist() */
7711 MATCH_POS /* matchstrpos() */
7712} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007713
7714 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007715find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716{
7717 char_u *str = NULL;
7718 long len = 0;
7719 char_u *expr = NULL;
7720 char_u *pat;
7721 regmatch_T regmatch;
7722 char_u patbuf[NUMBUFLEN];
7723 char_u strbuf[NUMBUFLEN];
7724 char_u *save_cpo;
7725 long start = 0;
7726 long nth = 1;
7727 colnr_T startcol = 0;
7728 int match = 0;
7729 list_T *l = NULL;
7730 listitem_T *li = NULL;
7731 long idx = 0;
7732 char_u *tofree = NULL;
7733
7734 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7735 save_cpo = p_cpo;
7736 p_cpo = (char_u *)"";
7737
7738 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007739 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007740 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007741 /* type MATCH_LIST: return empty list when there are no matches.
7742 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007743 if (rettv_list_alloc(rettv) == FAIL)
7744 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007745 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746 && (list_append_string(rettv->vval.v_list,
7747 (char_u *)"", 0) == FAIL
7748 || list_append_number(rettv->vval.v_list,
7749 (varnumber_T)-1) == FAIL
7750 || list_append_number(rettv->vval.v_list,
7751 (varnumber_T)-1) == FAIL
7752 || list_append_number(rettv->vval.v_list,
7753 (varnumber_T)-1) == FAIL))
7754 {
7755 list_free(rettv->vval.v_list);
7756 rettv->vval.v_list = NULL;
7757 goto theend;
7758 }
7759 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007760 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007761 {
7762 rettv->v_type = VAR_STRING;
7763 rettv->vval.v_string = NULL;
7764 }
7765
7766 if (argvars[0].v_type == VAR_LIST)
7767 {
7768 if ((l = argvars[0].vval.v_list) == NULL)
7769 goto theend;
7770 li = l->lv_first;
7771 }
7772 else
7773 {
7774 expr = str = get_tv_string(&argvars[0]);
7775 len = (long)STRLEN(str);
7776 }
7777
7778 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7779 if (pat == NULL)
7780 goto theend;
7781
7782 if (argvars[2].v_type != VAR_UNKNOWN)
7783 {
7784 int error = FALSE;
7785
7786 start = (long)get_tv_number_chk(&argvars[2], &error);
7787 if (error)
7788 goto theend;
7789 if (l != NULL)
7790 {
7791 li = list_find(l, start);
7792 if (li == NULL)
7793 goto theend;
7794 idx = l->lv_idx; /* use the cached index */
7795 }
7796 else
7797 {
7798 if (start < 0)
7799 start = 0;
7800 if (start > len)
7801 goto theend;
7802 /* When "count" argument is there ignore matches before "start",
7803 * otherwise skip part of the string. Differs when pattern is "^"
7804 * or "\<". */
7805 if (argvars[3].v_type != VAR_UNKNOWN)
7806 startcol = start;
7807 else
7808 {
7809 str += start;
7810 len -= start;
7811 }
7812 }
7813
7814 if (argvars[3].v_type != VAR_UNKNOWN)
7815 nth = (long)get_tv_number_chk(&argvars[3], &error);
7816 if (error)
7817 goto theend;
7818 }
7819
7820 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7821 if (regmatch.regprog != NULL)
7822 {
7823 regmatch.rm_ic = p_ic;
7824
7825 for (;;)
7826 {
7827 if (l != NULL)
7828 {
7829 if (li == NULL)
7830 {
7831 match = FALSE;
7832 break;
7833 }
7834 vim_free(tofree);
7835 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7836 if (str == NULL)
7837 break;
7838 }
7839
7840 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7841
7842 if (match && --nth <= 0)
7843 break;
7844 if (l == NULL && !match)
7845 break;
7846
7847 /* Advance to just after the match. */
7848 if (l != NULL)
7849 {
7850 li = li->li_next;
7851 ++idx;
7852 }
7853 else
7854 {
7855#ifdef FEAT_MBYTE
7856 startcol = (colnr_T)(regmatch.startp[0]
7857 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7858#else
7859 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7860#endif
7861 if (startcol > (colnr_T)len
7862 || str + startcol <= regmatch.startp[0])
7863 {
7864 match = FALSE;
7865 break;
7866 }
7867 }
7868 }
7869
7870 if (match)
7871 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007872 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007873 {
7874 listitem_T *li1 = rettv->vval.v_list->lv_first;
7875 listitem_T *li2 = li1->li_next;
7876 listitem_T *li3 = li2->li_next;
7877 listitem_T *li4 = li3->li_next;
7878
7879 vim_free(li1->li_tv.vval.v_string);
7880 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7881 (int)(regmatch.endp[0] - regmatch.startp[0]));
7882 li3->li_tv.vval.v_number =
7883 (varnumber_T)(regmatch.startp[0] - expr);
7884 li4->li_tv.vval.v_number =
7885 (varnumber_T)(regmatch.endp[0] - expr);
7886 if (l != NULL)
7887 li2->li_tv.vval.v_number = (varnumber_T)idx;
7888 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007889 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 {
7891 int i;
7892
7893 /* return list with matched string and submatches */
7894 for (i = 0; i < NSUBEXP; ++i)
7895 {
7896 if (regmatch.endp[i] == NULL)
7897 {
7898 if (list_append_string(rettv->vval.v_list,
7899 (char_u *)"", 0) == FAIL)
7900 break;
7901 }
7902 else if (list_append_string(rettv->vval.v_list,
7903 regmatch.startp[i],
7904 (int)(regmatch.endp[i] - regmatch.startp[i]))
7905 == FAIL)
7906 break;
7907 }
7908 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007909 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910 {
7911 /* return matched string */
7912 if (l != NULL)
7913 copy_tv(&li->li_tv, rettv);
7914 else
7915 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7916 (int)(regmatch.endp[0] - regmatch.startp[0]));
7917 }
7918 else if (l != NULL)
7919 rettv->vval.v_number = idx;
7920 else
7921 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007922 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007923 rettv->vval.v_number =
7924 (varnumber_T)(regmatch.startp[0] - str);
7925 else
7926 rettv->vval.v_number =
7927 (varnumber_T)(regmatch.endp[0] - str);
7928 rettv->vval.v_number += (varnumber_T)(str - expr);
7929 }
7930 }
7931 vim_regfree(regmatch.regprog);
7932 }
7933
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007934theend:
7935 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 /* matchstrpos() without a list: drop the second item. */
7937 listitem_remove(rettv->vval.v_list,
7938 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007939 vim_free(tofree);
7940 p_cpo = save_cpo;
7941}
7942
7943/*
7944 * "match()" function
7945 */
7946 static void
7947f_match(typval_T *argvars, typval_T *rettv)
7948{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007949 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950}
7951
Bram Moolenaar95e51472018-07-28 16:55:56 +02007952#ifdef FEAT_SEARCH_EXTRA
7953 static int
7954matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
7955{
7956 dictitem_T *di;
7957
7958 if (tv->v_type != VAR_DICT)
7959 {
7960 EMSG(_(e_dictreq));
7961 return FAIL;
7962 }
7963
7964 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
7965 *conceal_char = get_dict_string(tv->vval.v_dict,
7966 (char_u *)"conceal", FALSE);
7967
7968 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
7969 {
7970 *win = find_win_by_nr(&di->di_tv, NULL);
7971 if (*win == NULL)
7972 {
7973 EMSG(_("E957: Invalid window number"));
7974 return FAIL;
7975 }
7976 }
7977
7978 return OK;
7979}
7980#endif
7981
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007982/*
7983 * "matchadd()" function
7984 */
7985 static void
7986f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7987{
7988#ifdef FEAT_SEARCH_EXTRA
7989 char_u buf[NUMBUFLEN];
7990 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7991 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7992 int prio = 10; /* default priority */
7993 int id = -1;
7994 int error = FALSE;
7995 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02007996 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997
7998 rettv->vval.v_number = -1;
7999
8000 if (grp == NULL || pat == NULL)
8001 return;
8002 if (argvars[2].v_type != VAR_UNKNOWN)
8003 {
8004 prio = (int)get_tv_number_chk(&argvars[2], &error);
8005 if (argvars[3].v_type != VAR_UNKNOWN)
8006 {
8007 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008008 if (argvars[4].v_type != VAR_UNKNOWN
8009 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8010 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011 }
8012 }
8013 if (error == TRUE)
8014 return;
8015 if (id >= 1 && id <= 3)
8016 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008017 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008018 return;
8019 }
8020
Bram Moolenaar95e51472018-07-28 16:55:56 +02008021 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008022 conceal_char);
8023#endif
8024}
8025
8026/*
8027 * "matchaddpos()" function
8028 */
8029 static void
8030f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8031{
8032#ifdef FEAT_SEARCH_EXTRA
8033 char_u buf[NUMBUFLEN];
8034 char_u *group;
8035 int prio = 10;
8036 int id = -1;
8037 int error = FALSE;
8038 list_T *l;
8039 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008040 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008041
8042 rettv->vval.v_number = -1;
8043
8044 group = get_tv_string_buf_chk(&argvars[0], buf);
8045 if (group == NULL)
8046 return;
8047
8048 if (argvars[1].v_type != VAR_LIST)
8049 {
8050 EMSG2(_(e_listarg), "matchaddpos()");
8051 return;
8052 }
8053 l = argvars[1].vval.v_list;
8054 if (l == NULL)
8055 return;
8056
8057 if (argvars[2].v_type != VAR_UNKNOWN)
8058 {
8059 prio = (int)get_tv_number_chk(&argvars[2], &error);
8060 if (argvars[3].v_type != VAR_UNKNOWN)
8061 {
8062 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008063
8064 if (argvars[4].v_type != VAR_UNKNOWN
8065 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8066 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008067 }
8068 }
8069 if (error == TRUE)
8070 return;
8071
8072 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8073 if (id == 1 || id == 2)
8074 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008075 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008076 return;
8077 }
8078
Bram Moolenaar95e51472018-07-28 16:55:56 +02008079 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008080 conceal_char);
8081#endif
8082}
8083
8084/*
8085 * "matcharg()" function
8086 */
8087 static void
8088f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8089{
8090 if (rettv_list_alloc(rettv) == OK)
8091 {
8092#ifdef FEAT_SEARCH_EXTRA
8093 int id = (int)get_tv_number(&argvars[0]);
8094 matchitem_T *m;
8095
8096 if (id >= 1 && id <= 3)
8097 {
8098 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8099 {
8100 list_append_string(rettv->vval.v_list,
8101 syn_id2name(m->hlg_id), -1);
8102 list_append_string(rettv->vval.v_list, m->pattern, -1);
8103 }
8104 else
8105 {
8106 list_append_string(rettv->vval.v_list, NULL, -1);
8107 list_append_string(rettv->vval.v_list, NULL, -1);
8108 }
8109 }
8110#endif
8111 }
8112}
8113
8114/*
8115 * "matchdelete()" function
8116 */
8117 static void
8118f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8119{
8120#ifdef FEAT_SEARCH_EXTRA
8121 rettv->vval.v_number = match_delete(curwin,
8122 (int)get_tv_number(&argvars[0]), TRUE);
8123#endif
8124}
8125
8126/*
8127 * "matchend()" function
8128 */
8129 static void
8130f_matchend(typval_T *argvars, typval_T *rettv)
8131{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008132 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133}
8134
8135/*
8136 * "matchlist()" function
8137 */
8138 static void
8139f_matchlist(typval_T *argvars, typval_T *rettv)
8140{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008141 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142}
8143
8144/*
8145 * "matchstr()" function
8146 */
8147 static void
8148f_matchstr(typval_T *argvars, typval_T *rettv)
8149{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008150 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008151}
8152
8153/*
8154 * "matchstrpos()" function
8155 */
8156 static void
8157f_matchstrpos(typval_T *argvars, typval_T *rettv)
8158{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008159 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160}
8161
8162static void max_min(typval_T *argvars, typval_T *rettv, int domax);
8163
8164 static void
8165max_min(typval_T *argvars, typval_T *rettv, int domax)
8166{
8167 varnumber_T n = 0;
8168 varnumber_T i;
8169 int error = FALSE;
8170
8171 if (argvars[0].v_type == VAR_LIST)
8172 {
8173 list_T *l;
8174 listitem_T *li;
8175
8176 l = argvars[0].vval.v_list;
8177 if (l != NULL)
8178 {
8179 li = l->lv_first;
8180 if (li != NULL)
8181 {
8182 n = get_tv_number_chk(&li->li_tv, &error);
8183 for (;;)
8184 {
8185 li = li->li_next;
8186 if (li == NULL)
8187 break;
8188 i = get_tv_number_chk(&li->li_tv, &error);
8189 if (domax ? i > n : i < n)
8190 n = i;
8191 }
8192 }
8193 }
8194 }
8195 else if (argvars[0].v_type == VAR_DICT)
8196 {
8197 dict_T *d;
8198 int first = TRUE;
8199 hashitem_T *hi;
8200 int todo;
8201
8202 d = argvars[0].vval.v_dict;
8203 if (d != NULL)
8204 {
8205 todo = (int)d->dv_hashtab.ht_used;
8206 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8207 {
8208 if (!HASHITEM_EMPTY(hi))
8209 {
8210 --todo;
8211 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8212 if (first)
8213 {
8214 n = i;
8215 first = FALSE;
8216 }
8217 else if (domax ? i > n : i < n)
8218 n = i;
8219 }
8220 }
8221 }
8222 }
8223 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008224 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225 rettv->vval.v_number = error ? 0 : n;
8226}
8227
8228/*
8229 * "max()" function
8230 */
8231 static void
8232f_max(typval_T *argvars, typval_T *rettv)
8233{
8234 max_min(argvars, rettv, TRUE);
8235}
8236
8237/*
8238 * "min()" function
8239 */
8240 static void
8241f_min(typval_T *argvars, typval_T *rettv)
8242{
8243 max_min(argvars, rettv, FALSE);
8244}
8245
8246static int mkdir_recurse(char_u *dir, int prot);
8247
8248/*
8249 * Create the directory in which "dir" is located, and higher levels when
8250 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008251 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008252 */
8253 static int
8254mkdir_recurse(char_u *dir, int prot)
8255{
8256 char_u *p;
8257 char_u *updir;
8258 int r = FAIL;
8259
8260 /* Get end of directory name in "dir".
8261 * We're done when it's "/" or "c:/". */
8262 p = gettail_sep(dir);
8263 if (p <= get_past_head(dir))
8264 return OK;
8265
8266 /* If the directory exists we're done. Otherwise: create it.*/
8267 updir = vim_strnsave(dir, (int)(p - dir));
8268 if (updir == NULL)
8269 return FAIL;
8270 if (mch_isdir(updir))
8271 r = OK;
8272 else if (mkdir_recurse(updir, prot) == OK)
8273 r = vim_mkdir_emsg(updir, prot);
8274 vim_free(updir);
8275 return r;
8276}
8277
8278#ifdef vim_mkdir
8279/*
8280 * "mkdir()" function
8281 */
8282 static void
8283f_mkdir(typval_T *argvars, typval_T *rettv)
8284{
8285 char_u *dir;
8286 char_u buf[NUMBUFLEN];
8287 int prot = 0755;
8288
8289 rettv->vval.v_number = FAIL;
8290 if (check_restricted() || check_secure())
8291 return;
8292
8293 dir = get_tv_string_buf(&argvars[0], buf);
8294 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008295 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008296
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008297 if (*gettail(dir) == NUL)
8298 /* remove trailing slashes */
8299 *gettail_sep(dir) = NUL;
8300
8301 if (argvars[1].v_type != VAR_UNKNOWN)
8302 {
8303 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008305 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8306 if (prot == -1)
8307 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008309 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8310 {
8311 if (mch_isdir(dir))
8312 {
8313 /* With the "p" flag it's OK if the dir already exists. */
8314 rettv->vval.v_number = OK;
8315 return;
8316 }
8317 mkdir_recurse(dir, prot);
8318 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008320 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008321}
8322#endif
8323
8324/*
8325 * "mode()" function
8326 */
8327 static void
8328f_mode(typval_T *argvars, typval_T *rettv)
8329{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008330 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008331
Bram Moolenaar612cc382018-07-29 15:34:26 +02008332 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008333
8334 if (time_for_testing == 93784)
8335 {
8336 /* Testing the two-character code. */
8337 buf[0] = 'x';
8338 buf[1] = '!';
8339 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008340#ifdef FEAT_TERMINAL
8341 else if (term_use_loop())
8342 buf[0] = 't';
8343#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008344 else if (VIsual_active)
8345 {
8346 if (VIsual_select)
8347 buf[0] = VIsual_mode + 's' - 'v';
8348 else
8349 buf[0] = VIsual_mode;
8350 }
8351 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8352 || State == CONFIRM)
8353 {
8354 buf[0] = 'r';
8355 if (State == ASKMORE)
8356 buf[1] = 'm';
8357 else if (State == CONFIRM)
8358 buf[1] = '?';
8359 }
8360 else if (State == EXTERNCMD)
8361 buf[0] = '!';
8362 else if (State & INSERT)
8363 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008364 if (State & VREPLACE_FLAG)
8365 {
8366 buf[0] = 'R';
8367 buf[1] = 'v';
8368 }
8369 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008370 {
8371 if (State & REPLACE_FLAG)
8372 buf[0] = 'R';
8373 else
8374 buf[0] = 'i';
8375#ifdef FEAT_INS_EXPAND
8376 if (ins_compl_active())
8377 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008378 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008379 buf[1] = 'x';
8380#endif
8381 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008382 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008383 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384 {
8385 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008386 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008387 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008388 else if (exmode_active == EXMODE_NORMAL)
8389 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390 }
8391 else
8392 {
8393 buf[0] = 'n';
8394 if (finish_op)
8395 buf[1] = 'o';
Bram Moolenaar612cc382018-07-29 15:34:26 +02008396 else if (restart_edit == 'I' || restart_edit == 'R'
8397 || restart_edit == 'V')
8398 {
8399 buf[1] = 'i';
8400 buf[2] = restart_edit;
8401 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 }
8403
8404 /* Clear out the minor mode when the argument is not a non-zero number or
8405 * non-empty string. */
8406 if (!non_zero_arg(&argvars[0]))
8407 buf[1] = NUL;
8408
8409 rettv->vval.v_string = vim_strsave(buf);
8410 rettv->v_type = VAR_STRING;
8411}
8412
8413#if defined(FEAT_MZSCHEME) || defined(PROTO)
8414/*
8415 * "mzeval()" function
8416 */
8417 static void
8418f_mzeval(typval_T *argvars, typval_T *rettv)
8419{
8420 char_u *str;
8421 char_u buf[NUMBUFLEN];
8422
8423 str = get_tv_string_buf(&argvars[0], buf);
8424 do_mzeval(str, rettv);
8425}
8426
8427 void
8428mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8429{
8430 typval_T argvars[3];
8431
8432 argvars[0].v_type = VAR_STRING;
8433 argvars[0].vval.v_string = name;
8434 copy_tv(args, &argvars[1]);
8435 argvars[2].v_type = VAR_UNKNOWN;
8436 f_call(argvars, rettv);
8437 clear_tv(&argvars[1]);
8438}
8439#endif
8440
8441/*
8442 * "nextnonblank()" function
8443 */
8444 static void
8445f_nextnonblank(typval_T *argvars, typval_T *rettv)
8446{
8447 linenr_T lnum;
8448
8449 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8450 {
8451 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8452 {
8453 lnum = 0;
8454 break;
8455 }
8456 if (*skipwhite(ml_get(lnum)) != NUL)
8457 break;
8458 }
8459 rettv->vval.v_number = lnum;
8460}
8461
8462/*
8463 * "nr2char()" function
8464 */
8465 static void
8466f_nr2char(typval_T *argvars, typval_T *rettv)
8467{
8468 char_u buf[NUMBUFLEN];
8469
8470#ifdef FEAT_MBYTE
8471 if (has_mbyte)
8472 {
8473 int utf8 = 0;
8474
8475 if (argvars[1].v_type != VAR_UNKNOWN)
8476 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8477 if (utf8)
8478 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8479 else
8480 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8481 }
8482 else
8483#endif
8484 {
8485 buf[0] = (char_u)get_tv_number(&argvars[0]);
8486 buf[1] = NUL;
8487 }
8488 rettv->v_type = VAR_STRING;
8489 rettv->vval.v_string = vim_strsave(buf);
8490}
8491
8492/*
8493 * "or(expr, expr)" function
8494 */
8495 static void
8496f_or(typval_T *argvars, typval_T *rettv)
8497{
8498 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8499 | get_tv_number_chk(&argvars[1], NULL);
8500}
8501
8502/*
8503 * "pathshorten()" function
8504 */
8505 static void
8506f_pathshorten(typval_T *argvars, typval_T *rettv)
8507{
8508 char_u *p;
8509
8510 rettv->v_type = VAR_STRING;
8511 p = get_tv_string_chk(&argvars[0]);
8512 if (p == NULL)
8513 rettv->vval.v_string = NULL;
8514 else
8515 {
8516 p = vim_strsave(p);
8517 rettv->vval.v_string = p;
8518 if (p != NULL)
8519 shorten_dir(p);
8520 }
8521}
8522
8523#ifdef FEAT_PERL
8524/*
8525 * "perleval()" function
8526 */
8527 static void
8528f_perleval(typval_T *argvars, typval_T *rettv)
8529{
8530 char_u *str;
8531 char_u buf[NUMBUFLEN];
8532
8533 str = get_tv_string_buf(&argvars[0], buf);
8534 do_perleval(str, rettv);
8535}
8536#endif
8537
8538#ifdef FEAT_FLOAT
8539/*
8540 * "pow()" function
8541 */
8542 static void
8543f_pow(typval_T *argvars, typval_T *rettv)
8544{
8545 float_T fx = 0.0, fy = 0.0;
8546
8547 rettv->v_type = VAR_FLOAT;
8548 if (get_float_arg(argvars, &fx) == OK
8549 && get_float_arg(&argvars[1], &fy) == OK)
8550 rettv->vval.v_float = pow(fx, fy);
8551 else
8552 rettv->vval.v_float = 0.0;
8553}
8554#endif
8555
8556/*
8557 * "prevnonblank()" function
8558 */
8559 static void
8560f_prevnonblank(typval_T *argvars, typval_T *rettv)
8561{
8562 linenr_T lnum;
8563
8564 lnum = get_tv_lnum(argvars);
8565 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8566 lnum = 0;
8567 else
8568 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8569 --lnum;
8570 rettv->vval.v_number = lnum;
8571}
8572
8573/* This dummy va_list is here because:
8574 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8575 * - locally in the function results in a "used before set" warning
8576 * - using va_start() to initialize it gives "function with fixed args" error */
8577static va_list ap;
8578
8579/*
8580 * "printf()" function
8581 */
8582 static void
8583f_printf(typval_T *argvars, typval_T *rettv)
8584{
8585 char_u buf[NUMBUFLEN];
8586 int len;
8587 char_u *s;
8588 int saved_did_emsg = did_emsg;
8589 char *fmt;
8590
8591 rettv->v_type = VAR_STRING;
8592 rettv->vval.v_string = NULL;
8593
8594 /* Get the required length, allocate the buffer and do it for real. */
8595 did_emsg = FALSE;
8596 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008597 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008598 if (!did_emsg)
8599 {
8600 s = alloc(len + 1);
8601 if (s != NULL)
8602 {
8603 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008604 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8605 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008606 }
8607 }
8608 did_emsg |= saved_did_emsg;
8609}
8610
Bram Moolenaarf2732452018-06-03 14:47:35 +02008611#ifdef FEAT_JOB_CHANNEL
8612/*
8613 * "prompt_setcallback({buffer}, {callback})" function
8614 */
8615 static void
8616f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8617{
8618 buf_T *buf;
8619 char_u *callback;
8620 partial_T *partial;
8621
8622 if (check_secure())
8623 return;
8624 buf = get_buf_tv(&argvars[0], FALSE);
8625 if (buf == NULL)
8626 return;
8627
8628 callback = get_callback(&argvars[1], &partial);
8629 if (callback == NULL)
8630 return;
8631
8632 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8633 if (partial == NULL)
8634 buf->b_prompt_callback = vim_strsave(callback);
8635 else
8636 /* pointer into the partial */
8637 buf->b_prompt_callback = callback;
8638 buf->b_prompt_partial = partial;
8639}
8640
8641/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008642 * "prompt_setinterrupt({buffer}, {callback})" function
8643 */
8644 static void
8645f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8646{
8647 buf_T *buf;
8648 char_u *callback;
8649 partial_T *partial;
8650
8651 if (check_secure())
8652 return;
8653 buf = get_buf_tv(&argvars[0], FALSE);
8654 if (buf == NULL)
8655 return;
8656
8657 callback = get_callback(&argvars[1], &partial);
8658 if (callback == NULL)
8659 return;
8660
8661 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8662 if (partial == NULL)
8663 buf->b_prompt_interrupt = vim_strsave(callback);
8664 else
8665 /* pointer into the partial */
8666 buf->b_prompt_interrupt = callback;
8667 buf->b_prompt_int_partial = partial;
8668}
8669
8670/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008671 * "prompt_setprompt({buffer}, {text})" function
8672 */
8673 static void
8674f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8675{
8676 buf_T *buf;
8677 char_u *text;
8678
8679 if (check_secure())
8680 return;
8681 buf = get_buf_tv(&argvars[0], FALSE);
8682 if (buf == NULL)
8683 return;
8684
8685 text = get_tv_string(&argvars[1]);
8686 vim_free(buf->b_prompt_text);
8687 buf->b_prompt_text = vim_strsave(text);
8688}
8689#endif
8690
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008691/*
8692 * "pumvisible()" function
8693 */
8694 static void
8695f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8696{
8697#ifdef FEAT_INS_EXPAND
8698 if (pum_visible())
8699 rettv->vval.v_number = 1;
8700#endif
8701}
8702
8703#ifdef FEAT_PYTHON3
8704/*
8705 * "py3eval()" function
8706 */
8707 static void
8708f_py3eval(typval_T *argvars, typval_T *rettv)
8709{
8710 char_u *str;
8711 char_u buf[NUMBUFLEN];
8712
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008713 if (p_pyx == 0)
8714 p_pyx = 3;
8715
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008716 str = get_tv_string_buf(&argvars[0], buf);
8717 do_py3eval(str, rettv);
8718}
8719#endif
8720
8721#ifdef FEAT_PYTHON
8722/*
8723 * "pyeval()" function
8724 */
8725 static void
8726f_pyeval(typval_T *argvars, typval_T *rettv)
8727{
8728 char_u *str;
8729 char_u buf[NUMBUFLEN];
8730
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008731 if (p_pyx == 0)
8732 p_pyx = 2;
8733
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008734 str = get_tv_string_buf(&argvars[0], buf);
8735 do_pyeval(str, rettv);
8736}
8737#endif
8738
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008739#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8740/*
8741 * "pyxeval()" function
8742 */
8743 static void
8744f_pyxeval(typval_T *argvars, typval_T *rettv)
8745{
8746# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8747 init_pyxversion();
8748 if (p_pyx == 2)
8749 f_pyeval(argvars, rettv);
8750 else
8751 f_py3eval(argvars, rettv);
8752# elif defined(FEAT_PYTHON)
8753 f_pyeval(argvars, rettv);
8754# elif defined(FEAT_PYTHON3)
8755 f_py3eval(argvars, rettv);
8756# endif
8757}
8758#endif
8759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008760/*
8761 * "range()" function
8762 */
8763 static void
8764f_range(typval_T *argvars, typval_T *rettv)
8765{
8766 varnumber_T start;
8767 varnumber_T end;
8768 varnumber_T stride = 1;
8769 varnumber_T i;
8770 int error = FALSE;
8771
8772 start = get_tv_number_chk(&argvars[0], &error);
8773 if (argvars[1].v_type == VAR_UNKNOWN)
8774 {
8775 end = start - 1;
8776 start = 0;
8777 }
8778 else
8779 {
8780 end = get_tv_number_chk(&argvars[1], &error);
8781 if (argvars[2].v_type != VAR_UNKNOWN)
8782 stride = get_tv_number_chk(&argvars[2], &error);
8783 }
8784
8785 if (error)
8786 return; /* type error; errmsg already given */
8787 if (stride == 0)
8788 EMSG(_("E726: Stride is zero"));
8789 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8790 EMSG(_("E727: Start past end"));
8791 else
8792 {
8793 if (rettv_list_alloc(rettv) == OK)
8794 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8795 if (list_append_number(rettv->vval.v_list,
8796 (varnumber_T)i) == FAIL)
8797 break;
8798 }
8799}
8800
8801/*
8802 * "readfile()" function
8803 */
8804 static void
8805f_readfile(typval_T *argvars, typval_T *rettv)
8806{
8807 int binary = FALSE;
8808 int failed = FALSE;
8809 char_u *fname;
8810 FILE *fd;
8811 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8812 int io_size = sizeof(buf);
8813 int readlen; /* size of last fread() */
8814 char_u *prev = NULL; /* previously read bytes, if any */
8815 long prevlen = 0; /* length of data in prev */
8816 long prevsize = 0; /* size of prev buffer */
8817 long maxline = MAXLNUM;
8818 long cnt = 0;
8819 char_u *p; /* position in buf */
8820 char_u *start; /* start of current line */
8821
8822 if (argvars[1].v_type != VAR_UNKNOWN)
8823 {
8824 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8825 binary = TRUE;
8826 if (argvars[2].v_type != VAR_UNKNOWN)
8827 maxline = (long)get_tv_number(&argvars[2]);
8828 }
8829
8830 if (rettv_list_alloc(rettv) == FAIL)
8831 return;
8832
8833 /* Always open the file in binary mode, library functions have a mind of
8834 * their own about CR-LF conversion. */
8835 fname = get_tv_string(&argvars[0]);
8836 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8837 {
8838 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8839 return;
8840 }
8841
8842 while (cnt < maxline || maxline < 0)
8843 {
8844 readlen = (int)fread(buf, 1, io_size, fd);
8845
8846 /* This for loop processes what was read, but is also entered at end
8847 * of file so that either:
8848 * - an incomplete line gets written
8849 * - a "binary" file gets an empty line at the end if it ends in a
8850 * newline. */
8851 for (p = buf, start = buf;
8852 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8853 ++p)
8854 {
8855 if (*p == '\n' || readlen <= 0)
8856 {
8857 listitem_T *li;
8858 char_u *s = NULL;
8859 long_u len = p - start;
8860
8861 /* Finished a line. Remove CRs before NL. */
8862 if (readlen > 0 && !binary)
8863 {
8864 while (len > 0 && start[len - 1] == '\r')
8865 --len;
8866 /* removal may cross back to the "prev" string */
8867 if (len == 0)
8868 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8869 --prevlen;
8870 }
8871 if (prevlen == 0)
8872 s = vim_strnsave(start, (int)len);
8873 else
8874 {
8875 /* Change "prev" buffer to be the right size. This way
8876 * the bytes are only copied once, and very long lines are
8877 * allocated only once. */
8878 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8879 {
8880 mch_memmove(s + prevlen, start, len);
8881 s[prevlen + len] = NUL;
8882 prev = NULL; /* the list will own the string */
8883 prevlen = prevsize = 0;
8884 }
8885 }
8886 if (s == NULL)
8887 {
8888 do_outofmem_msg((long_u) prevlen + len + 1);
8889 failed = TRUE;
8890 break;
8891 }
8892
8893 if ((li = listitem_alloc()) == NULL)
8894 {
8895 vim_free(s);
8896 failed = TRUE;
8897 break;
8898 }
8899 li->li_tv.v_type = VAR_STRING;
8900 li->li_tv.v_lock = 0;
8901 li->li_tv.vval.v_string = s;
8902 list_append(rettv->vval.v_list, li);
8903
8904 start = p + 1; /* step over newline */
8905 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8906 break;
8907 }
8908 else if (*p == NUL)
8909 *p = '\n';
8910#ifdef FEAT_MBYTE
8911 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8912 * when finding the BF and check the previous two bytes. */
8913 else if (*p == 0xbf && enc_utf8 && !binary)
8914 {
8915 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8916 * + 1, these may be in the "prev" string. */
8917 char_u back1 = p >= buf + 1 ? p[-1]
8918 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8919 char_u back2 = p >= buf + 2 ? p[-2]
8920 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8921 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8922
8923 if (back2 == 0xef && back1 == 0xbb)
8924 {
8925 char_u *dest = p - 2;
8926
8927 /* Usually a BOM is at the beginning of a file, and so at
8928 * the beginning of a line; then we can just step over it.
8929 */
8930 if (start == dest)
8931 start = p + 1;
8932 else
8933 {
8934 /* have to shuffle buf to close gap */
8935 int adjust_prevlen = 0;
8936
8937 if (dest < buf)
8938 {
8939 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8940 dest = buf;
8941 }
8942 if (readlen > p - buf + 1)
8943 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8944 readlen -= 3 - adjust_prevlen;
8945 prevlen -= adjust_prevlen;
8946 p = dest - 1;
8947 }
8948 }
8949 }
8950#endif
8951 } /* for */
8952
8953 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8954 break;
8955 if (start < p)
8956 {
8957 /* There's part of a line in buf, store it in "prev". */
8958 if (p - start + prevlen >= prevsize)
8959 {
8960 /* need bigger "prev" buffer */
8961 char_u *newprev;
8962
8963 /* A common use case is ordinary text files and "prev" gets a
8964 * fragment of a line, so the first allocation is made
8965 * small, to avoid repeatedly 'allocing' large and
8966 * 'reallocing' small. */
8967 if (prevsize == 0)
8968 prevsize = (long)(p - start);
8969 else
8970 {
8971 long grow50pc = (prevsize * 3) / 2;
8972 long growmin = (long)((p - start) * 2 + prevlen);
8973 prevsize = grow50pc > growmin ? grow50pc : growmin;
8974 }
8975 newprev = prev == NULL ? alloc(prevsize)
8976 : vim_realloc(prev, prevsize);
8977 if (newprev == NULL)
8978 {
8979 do_outofmem_msg((long_u)prevsize);
8980 failed = TRUE;
8981 break;
8982 }
8983 prev = newprev;
8984 }
8985 /* Add the line part to end of "prev". */
8986 mch_memmove(prev + prevlen, start, p - start);
8987 prevlen += (long)(p - start);
8988 }
8989 } /* while */
8990
8991 /*
8992 * For a negative line count use only the lines at the end of the file,
8993 * free the rest.
8994 */
8995 if (!failed && maxline < 0)
8996 while (cnt > -maxline)
8997 {
8998 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8999 --cnt;
9000 }
9001
9002 if (failed)
9003 {
9004 list_free(rettv->vval.v_list);
9005 /* readfile doc says an empty list is returned on error */
9006 rettv->vval.v_list = list_alloc();
9007 }
9008
9009 vim_free(prev);
9010 fclose(fd);
9011}
9012
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009013 static void
9014return_register(int regname, typval_T *rettv)
9015{
9016 char_u buf[2] = {0, 0};
9017
9018 buf[0] = (char_u)regname;
9019 rettv->v_type = VAR_STRING;
9020 rettv->vval.v_string = vim_strsave(buf);
9021}
9022
9023/*
9024 * "reg_executing()" function
9025 */
9026 static void
9027f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9028{
9029 return_register(reg_executing, rettv);
9030}
9031
9032/*
9033 * "reg_recording()" function
9034 */
9035 static void
9036f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9037{
9038 return_register(reg_recording, rettv);
9039}
9040
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009041#if defined(FEAT_RELTIME)
9042static int list2proftime(typval_T *arg, proftime_T *tm);
9043
9044/*
9045 * Convert a List to proftime_T.
9046 * Return FAIL when there is something wrong.
9047 */
9048 static int
9049list2proftime(typval_T *arg, proftime_T *tm)
9050{
9051 long n1, n2;
9052 int error = FALSE;
9053
9054 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9055 || arg->vval.v_list->lv_len != 2)
9056 return FAIL;
9057 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9058 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9059# ifdef WIN3264
9060 tm->HighPart = n1;
9061 tm->LowPart = n2;
9062# else
9063 tm->tv_sec = n1;
9064 tm->tv_usec = n2;
9065# endif
9066 return error ? FAIL : OK;
9067}
9068#endif /* FEAT_RELTIME */
9069
9070/*
9071 * "reltime()" function
9072 */
9073 static void
9074f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9075{
9076#ifdef FEAT_RELTIME
9077 proftime_T res;
9078 proftime_T start;
9079
9080 if (argvars[0].v_type == VAR_UNKNOWN)
9081 {
9082 /* No arguments: get current time. */
9083 profile_start(&res);
9084 }
9085 else if (argvars[1].v_type == VAR_UNKNOWN)
9086 {
9087 if (list2proftime(&argvars[0], &res) == FAIL)
9088 return;
9089 profile_end(&res);
9090 }
9091 else
9092 {
9093 /* Two arguments: compute the difference. */
9094 if (list2proftime(&argvars[0], &start) == FAIL
9095 || list2proftime(&argvars[1], &res) == FAIL)
9096 return;
9097 profile_sub(&res, &start);
9098 }
9099
9100 if (rettv_list_alloc(rettv) == OK)
9101 {
9102 long n1, n2;
9103
9104# ifdef WIN3264
9105 n1 = res.HighPart;
9106 n2 = res.LowPart;
9107# else
9108 n1 = res.tv_sec;
9109 n2 = res.tv_usec;
9110# endif
9111 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9112 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9113 }
9114#endif
9115}
9116
9117#ifdef FEAT_FLOAT
9118/*
9119 * "reltimefloat()" function
9120 */
9121 static void
9122f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9123{
9124# ifdef FEAT_RELTIME
9125 proftime_T tm;
9126# endif
9127
9128 rettv->v_type = VAR_FLOAT;
9129 rettv->vval.v_float = 0;
9130# ifdef FEAT_RELTIME
9131 if (list2proftime(&argvars[0], &tm) == OK)
9132 rettv->vval.v_float = profile_float(&tm);
9133# endif
9134}
9135#endif
9136
9137/*
9138 * "reltimestr()" function
9139 */
9140 static void
9141f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9142{
9143#ifdef FEAT_RELTIME
9144 proftime_T tm;
9145#endif
9146
9147 rettv->v_type = VAR_STRING;
9148 rettv->vval.v_string = NULL;
9149#ifdef FEAT_RELTIME
9150 if (list2proftime(&argvars[0], &tm) == OK)
9151 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9152#endif
9153}
9154
9155#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9156static void make_connection(void);
9157static int check_connection(void);
9158
9159 static void
9160make_connection(void)
9161{
9162 if (X_DISPLAY == NULL
9163# ifdef FEAT_GUI
9164 && !gui.in_use
9165# endif
9166 )
9167 {
9168 x_force_connect = TRUE;
9169 setup_term_clip();
9170 x_force_connect = FALSE;
9171 }
9172}
9173
9174 static int
9175check_connection(void)
9176{
9177 make_connection();
9178 if (X_DISPLAY == NULL)
9179 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009180 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009181 return FAIL;
9182 }
9183 return OK;
9184}
9185#endif
9186
9187#ifdef FEAT_CLIENTSERVER
9188 static void
9189remote_common(typval_T *argvars, typval_T *rettv, int expr)
9190{
9191 char_u *server_name;
9192 char_u *keys;
9193 char_u *r = NULL;
9194 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009195 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009196# ifdef WIN32
9197 HWND w;
9198# else
9199 Window w;
9200# endif
9201
9202 if (check_restricted() || check_secure())
9203 return;
9204
9205# ifdef FEAT_X11
9206 if (check_connection() == FAIL)
9207 return;
9208# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009209 if (argvars[2].v_type != VAR_UNKNOWN
9210 && argvars[3].v_type != VAR_UNKNOWN)
9211 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009212
9213 server_name = get_tv_string_chk(&argvars[0]);
9214 if (server_name == NULL)
9215 return; /* type error; errmsg already given */
9216 keys = get_tv_string_buf(&argvars[1], buf);
9217# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009218 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009219# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009220 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9221 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009222# endif
9223 {
9224 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009225 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009226 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009227 vim_free(r);
9228 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009229 else
9230 EMSG2(_("E241: Unable to send to %s"), server_name);
9231 return;
9232 }
9233
9234 rettv->vval.v_string = r;
9235
9236 if (argvars[2].v_type != VAR_UNKNOWN)
9237 {
9238 dictitem_T v;
9239 char_u str[30];
9240 char_u *idvar;
9241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009242 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009243 if (idvar != NULL && *idvar != NUL)
9244 {
9245 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9246 v.di_tv.v_type = VAR_STRING;
9247 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009248 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009249 vim_free(v.di_tv.vval.v_string);
9250 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009251 }
9252}
9253#endif
9254
9255/*
9256 * "remote_expr()" function
9257 */
9258 static void
9259f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9260{
9261 rettv->v_type = VAR_STRING;
9262 rettv->vval.v_string = NULL;
9263#ifdef FEAT_CLIENTSERVER
9264 remote_common(argvars, rettv, TRUE);
9265#endif
9266}
9267
9268/*
9269 * "remote_foreground()" function
9270 */
9271 static void
9272f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9273{
9274#ifdef FEAT_CLIENTSERVER
9275# ifdef WIN32
9276 /* On Win32 it's done in this application. */
9277 {
9278 char_u *server_name = get_tv_string_chk(&argvars[0]);
9279
9280 if (server_name != NULL)
9281 serverForeground(server_name);
9282 }
9283# else
9284 /* Send a foreground() expression to the server. */
9285 argvars[1].v_type = VAR_STRING;
9286 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9287 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009288 rettv->v_type = VAR_STRING;
9289 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009290 remote_common(argvars, rettv, TRUE);
9291 vim_free(argvars[1].vval.v_string);
9292# endif
9293#endif
9294}
9295
9296 static void
9297f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9298{
9299#ifdef FEAT_CLIENTSERVER
9300 dictitem_T v;
9301 char_u *s = NULL;
9302# ifdef WIN32
9303 long_u n = 0;
9304# endif
9305 char_u *serverid;
9306
9307 if (check_restricted() || check_secure())
9308 {
9309 rettv->vval.v_number = -1;
9310 return;
9311 }
9312 serverid = get_tv_string_chk(&argvars[0]);
9313 if (serverid == NULL)
9314 {
9315 rettv->vval.v_number = -1;
9316 return; /* type error; errmsg already given */
9317 }
9318# ifdef WIN32
9319 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9320 if (n == 0)
9321 rettv->vval.v_number = -1;
9322 else
9323 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009324 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009325 rettv->vval.v_number = (s != NULL);
9326 }
9327# else
9328 if (check_connection() == FAIL)
9329 return;
9330
9331 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9332 serverStrToWin(serverid), &s);
9333# endif
9334
9335 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9336 {
9337 char_u *retvar;
9338
9339 v.di_tv.v_type = VAR_STRING;
9340 v.di_tv.vval.v_string = vim_strsave(s);
9341 retvar = get_tv_string_chk(&argvars[1]);
9342 if (retvar != NULL)
9343 set_var(retvar, &v.di_tv, FALSE);
9344 vim_free(v.di_tv.vval.v_string);
9345 }
9346#else
9347 rettv->vval.v_number = -1;
9348#endif
9349}
9350
9351 static void
9352f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9353{
9354 char_u *r = NULL;
9355
9356#ifdef FEAT_CLIENTSERVER
9357 char_u *serverid = get_tv_string_chk(&argvars[0]);
9358
9359 if (serverid != NULL && !check_restricted() && !check_secure())
9360 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009361 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009362# ifdef WIN32
9363 /* The server's HWND is encoded in the 'id' parameter */
9364 long_u n = 0;
9365# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009366
9367 if (argvars[1].v_type != VAR_UNKNOWN)
9368 timeout = get_tv_number(&argvars[1]);
9369
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009370# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009371 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9372 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009373 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009374 if (r == NULL)
9375# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009376 if (check_connection() == FAIL
9377 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9378 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009379# endif
9380 EMSG(_("E277: Unable to read a server reply"));
9381 }
9382#endif
9383 rettv->v_type = VAR_STRING;
9384 rettv->vval.v_string = r;
9385}
9386
9387/*
9388 * "remote_send()" function
9389 */
9390 static void
9391f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9392{
9393 rettv->v_type = VAR_STRING;
9394 rettv->vval.v_string = NULL;
9395#ifdef FEAT_CLIENTSERVER
9396 remote_common(argvars, rettv, FALSE);
9397#endif
9398}
9399
9400/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009401 * "remote_startserver()" function
9402 */
9403 static void
9404f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9405{
9406#ifdef FEAT_CLIENTSERVER
9407 char_u *server = get_tv_string_chk(&argvars[0]);
9408
9409 if (server == NULL)
9410 return; /* type error; errmsg already given */
9411 if (serverName != NULL)
9412 EMSG(_("E941: already started a server"));
9413 else
9414 {
9415# ifdef FEAT_X11
9416 if (check_connection() == OK)
9417 serverRegisterName(X_DISPLAY, server);
9418# else
9419 serverSetName(server);
9420# endif
9421 }
9422#else
9423 EMSG(_("E942: +clientserver feature not available"));
9424#endif
9425}
9426
9427/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009428 * "remove()" function
9429 */
9430 static void
9431f_remove(typval_T *argvars, typval_T *rettv)
9432{
9433 list_T *l;
9434 listitem_T *item, *item2;
9435 listitem_T *li;
9436 long idx;
9437 long end;
9438 char_u *key;
9439 dict_T *d;
9440 dictitem_T *di;
9441 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9442
9443 if (argvars[0].v_type == VAR_DICT)
9444 {
9445 if (argvars[2].v_type != VAR_UNKNOWN)
9446 EMSG2(_(e_toomanyarg), "remove()");
9447 else if ((d = argvars[0].vval.v_dict) != NULL
9448 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9449 {
9450 key = get_tv_string_chk(&argvars[1]);
9451 if (key != NULL)
9452 {
9453 di = dict_find(d, key, -1);
9454 if (di == NULL)
9455 EMSG2(_(e_dictkey), key);
9456 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9457 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9458 {
9459 *rettv = di->di_tv;
9460 init_tv(&di->di_tv);
9461 dictitem_remove(d, di);
9462 }
9463 }
9464 }
9465 }
9466 else if (argvars[0].v_type != VAR_LIST)
9467 EMSG2(_(e_listdictarg), "remove()");
9468 else if ((l = argvars[0].vval.v_list) != NULL
9469 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9470 {
9471 int error = FALSE;
9472
9473 idx = (long)get_tv_number_chk(&argvars[1], &error);
9474 if (error)
9475 ; /* type error: do nothing, errmsg already given */
9476 else if ((item = list_find(l, idx)) == NULL)
9477 EMSGN(_(e_listidx), idx);
9478 else
9479 {
9480 if (argvars[2].v_type == VAR_UNKNOWN)
9481 {
9482 /* Remove one item, return its value. */
9483 vimlist_remove(l, item, item);
9484 *rettv = item->li_tv;
9485 vim_free(item);
9486 }
9487 else
9488 {
9489 /* Remove range of items, return list with values. */
9490 end = (long)get_tv_number_chk(&argvars[2], &error);
9491 if (error)
9492 ; /* type error: do nothing */
9493 else if ((item2 = list_find(l, end)) == NULL)
9494 EMSGN(_(e_listidx), end);
9495 else
9496 {
9497 int cnt = 0;
9498
9499 for (li = item; li != NULL; li = li->li_next)
9500 {
9501 ++cnt;
9502 if (li == item2)
9503 break;
9504 }
9505 if (li == NULL) /* didn't find "item2" after "item" */
9506 EMSG(_(e_invrange));
9507 else
9508 {
9509 vimlist_remove(l, item, item2);
9510 if (rettv_list_alloc(rettv) == OK)
9511 {
9512 l = rettv->vval.v_list;
9513 l->lv_first = item;
9514 l->lv_last = item2;
9515 item->li_prev = NULL;
9516 item2->li_next = NULL;
9517 l->lv_len = cnt;
9518 }
9519 }
9520 }
9521 }
9522 }
9523 }
9524}
9525
9526/*
9527 * "rename({from}, {to})" function
9528 */
9529 static void
9530f_rename(typval_T *argvars, typval_T *rettv)
9531{
9532 char_u buf[NUMBUFLEN];
9533
9534 if (check_restricted() || check_secure())
9535 rettv->vval.v_number = -1;
9536 else
9537 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9538 get_tv_string_buf(&argvars[1], buf));
9539}
9540
9541/*
9542 * "repeat()" function
9543 */
9544 static void
9545f_repeat(typval_T *argvars, typval_T *rettv)
9546{
9547 char_u *p;
9548 int n;
9549 int slen;
9550 int len;
9551 char_u *r;
9552 int i;
9553
9554 n = (int)get_tv_number(&argvars[1]);
9555 if (argvars[0].v_type == VAR_LIST)
9556 {
9557 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9558 while (n-- > 0)
9559 if (list_extend(rettv->vval.v_list,
9560 argvars[0].vval.v_list, NULL) == FAIL)
9561 break;
9562 }
9563 else
9564 {
9565 p = get_tv_string(&argvars[0]);
9566 rettv->v_type = VAR_STRING;
9567 rettv->vval.v_string = NULL;
9568
9569 slen = (int)STRLEN(p);
9570 len = slen * n;
9571 if (len <= 0)
9572 return;
9573
9574 r = alloc(len + 1);
9575 if (r != NULL)
9576 {
9577 for (i = 0; i < n; i++)
9578 mch_memmove(r + i * slen, p, (size_t)slen);
9579 r[len] = NUL;
9580 }
9581
9582 rettv->vval.v_string = r;
9583 }
9584}
9585
9586/*
9587 * "resolve()" function
9588 */
9589 static void
9590f_resolve(typval_T *argvars, typval_T *rettv)
9591{
9592 char_u *p;
9593#ifdef HAVE_READLINK
9594 char_u *buf = NULL;
9595#endif
9596
9597 p = get_tv_string(&argvars[0]);
9598#ifdef FEAT_SHORTCUT
9599 {
9600 char_u *v = NULL;
9601
9602 v = mch_resolve_shortcut(p);
9603 if (v != NULL)
9604 rettv->vval.v_string = v;
9605 else
9606 rettv->vval.v_string = vim_strsave(p);
9607 }
9608#else
9609# ifdef HAVE_READLINK
9610 {
9611 char_u *cpy;
9612 int len;
9613 char_u *remain = NULL;
9614 char_u *q;
9615 int is_relative_to_current = FALSE;
9616 int has_trailing_pathsep = FALSE;
9617 int limit = 100;
9618
9619 p = vim_strsave(p);
9620
9621 if (p[0] == '.' && (vim_ispathsep(p[1])
9622 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9623 is_relative_to_current = TRUE;
9624
9625 len = STRLEN(p);
9626 if (len > 0 && after_pathsep(p, p + len))
9627 {
9628 has_trailing_pathsep = TRUE;
9629 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9630 }
9631
9632 q = getnextcomp(p);
9633 if (*q != NUL)
9634 {
9635 /* Separate the first path component in "p", and keep the
9636 * remainder (beginning with the path separator). */
9637 remain = vim_strsave(q - 1);
9638 q[-1] = NUL;
9639 }
9640
9641 buf = alloc(MAXPATHL + 1);
9642 if (buf == NULL)
9643 goto fail;
9644
9645 for (;;)
9646 {
9647 for (;;)
9648 {
9649 len = readlink((char *)p, (char *)buf, MAXPATHL);
9650 if (len <= 0)
9651 break;
9652 buf[len] = NUL;
9653
9654 if (limit-- == 0)
9655 {
9656 vim_free(p);
9657 vim_free(remain);
9658 EMSG(_("E655: Too many symbolic links (cycle?)"));
9659 rettv->vval.v_string = NULL;
9660 goto fail;
9661 }
9662
9663 /* Ensure that the result will have a trailing path separator
9664 * if the argument has one. */
9665 if (remain == NULL && has_trailing_pathsep)
9666 add_pathsep(buf);
9667
9668 /* Separate the first path component in the link value and
9669 * concatenate the remainders. */
9670 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9671 if (*q != NUL)
9672 {
9673 if (remain == NULL)
9674 remain = vim_strsave(q - 1);
9675 else
9676 {
9677 cpy = concat_str(q - 1, remain);
9678 if (cpy != NULL)
9679 {
9680 vim_free(remain);
9681 remain = cpy;
9682 }
9683 }
9684 q[-1] = NUL;
9685 }
9686
9687 q = gettail(p);
9688 if (q > p && *q == NUL)
9689 {
9690 /* Ignore trailing path separator. */
9691 q[-1] = NUL;
9692 q = gettail(p);
9693 }
9694 if (q > p && !mch_isFullName(buf))
9695 {
9696 /* symlink is relative to directory of argument */
9697 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9698 if (cpy != NULL)
9699 {
9700 STRCPY(cpy, p);
9701 STRCPY(gettail(cpy), buf);
9702 vim_free(p);
9703 p = cpy;
9704 }
9705 }
9706 else
9707 {
9708 vim_free(p);
9709 p = vim_strsave(buf);
9710 }
9711 }
9712
9713 if (remain == NULL)
9714 break;
9715
9716 /* Append the first path component of "remain" to "p". */
9717 q = getnextcomp(remain + 1);
9718 len = q - remain - (*q != NUL);
9719 cpy = vim_strnsave(p, STRLEN(p) + len);
9720 if (cpy != NULL)
9721 {
9722 STRNCAT(cpy, remain, len);
9723 vim_free(p);
9724 p = cpy;
9725 }
9726 /* Shorten "remain". */
9727 if (*q != NUL)
9728 STRMOVE(remain, q - 1);
9729 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009730 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009731 }
9732
9733 /* If the result is a relative path name, make it explicitly relative to
9734 * the current directory if and only if the argument had this form. */
9735 if (!vim_ispathsep(*p))
9736 {
9737 if (is_relative_to_current
9738 && *p != NUL
9739 && !(p[0] == '.'
9740 && (p[1] == NUL
9741 || vim_ispathsep(p[1])
9742 || (p[1] == '.'
9743 && (p[2] == NUL
9744 || vim_ispathsep(p[2]))))))
9745 {
9746 /* Prepend "./". */
9747 cpy = concat_str((char_u *)"./", p);
9748 if (cpy != NULL)
9749 {
9750 vim_free(p);
9751 p = cpy;
9752 }
9753 }
9754 else if (!is_relative_to_current)
9755 {
9756 /* Strip leading "./". */
9757 q = p;
9758 while (q[0] == '.' && vim_ispathsep(q[1]))
9759 q += 2;
9760 if (q > p)
9761 STRMOVE(p, p + 2);
9762 }
9763 }
9764
9765 /* Ensure that the result will have no trailing path separator
9766 * if the argument had none. But keep "/" or "//". */
9767 if (!has_trailing_pathsep)
9768 {
9769 q = p + STRLEN(p);
9770 if (after_pathsep(p, q))
9771 *gettail_sep(p) = NUL;
9772 }
9773
9774 rettv->vval.v_string = p;
9775 }
9776# else
9777 rettv->vval.v_string = vim_strsave(p);
9778# endif
9779#endif
9780
9781 simplify_filename(rettv->vval.v_string);
9782
9783#ifdef HAVE_READLINK
9784fail:
9785 vim_free(buf);
9786#endif
9787 rettv->v_type = VAR_STRING;
9788}
9789
9790/*
9791 * "reverse({list})" function
9792 */
9793 static void
9794f_reverse(typval_T *argvars, typval_T *rettv)
9795{
9796 list_T *l;
9797 listitem_T *li, *ni;
9798
9799 if (argvars[0].v_type != VAR_LIST)
9800 EMSG2(_(e_listarg), "reverse()");
9801 else if ((l = argvars[0].vval.v_list) != NULL
9802 && !tv_check_lock(l->lv_lock,
9803 (char_u *)N_("reverse() argument"), TRUE))
9804 {
9805 li = l->lv_last;
9806 l->lv_first = l->lv_last = NULL;
9807 l->lv_len = 0;
9808 while (li != NULL)
9809 {
9810 ni = li->li_prev;
9811 list_append(l, li);
9812 li = ni;
9813 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009814 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009815 l->lv_idx = l->lv_len - l->lv_idx - 1;
9816 }
9817}
9818
9819#define SP_NOMOVE 0x01 /* don't move cursor */
9820#define SP_REPEAT 0x02 /* repeat to find outer pair */
9821#define SP_RETCOUNT 0x04 /* return matchcount */
9822#define SP_SETPCMARK 0x08 /* set previous context mark */
9823#define SP_START 0x10 /* accept match at start position */
9824#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9825#define SP_END 0x40 /* leave cursor at end of match */
9826#define SP_COLUMN 0x80 /* start at cursor column */
9827
9828static int get_search_arg(typval_T *varp, int *flagsp);
9829
9830/*
9831 * Get flags for a search function.
9832 * Possibly sets "p_ws".
9833 * Returns BACKWARD, FORWARD or zero (for an error).
9834 */
9835 static int
9836get_search_arg(typval_T *varp, int *flagsp)
9837{
9838 int dir = FORWARD;
9839 char_u *flags;
9840 char_u nbuf[NUMBUFLEN];
9841 int mask;
9842
9843 if (varp->v_type != VAR_UNKNOWN)
9844 {
9845 flags = get_tv_string_buf_chk(varp, nbuf);
9846 if (flags == NULL)
9847 return 0; /* type error; errmsg already given */
9848 while (*flags != NUL)
9849 {
9850 switch (*flags)
9851 {
9852 case 'b': dir = BACKWARD; break;
9853 case 'w': p_ws = TRUE; break;
9854 case 'W': p_ws = FALSE; break;
9855 default: mask = 0;
9856 if (flagsp != NULL)
9857 switch (*flags)
9858 {
9859 case 'c': mask = SP_START; break;
9860 case 'e': mask = SP_END; break;
9861 case 'm': mask = SP_RETCOUNT; break;
9862 case 'n': mask = SP_NOMOVE; break;
9863 case 'p': mask = SP_SUBPAT; break;
9864 case 'r': mask = SP_REPEAT; break;
9865 case 's': mask = SP_SETPCMARK; break;
9866 case 'z': mask = SP_COLUMN; break;
9867 }
9868 if (mask == 0)
9869 {
9870 EMSG2(_(e_invarg2), flags);
9871 dir = 0;
9872 }
9873 else
9874 *flagsp |= mask;
9875 }
9876 if (dir == 0)
9877 break;
9878 ++flags;
9879 }
9880 }
9881 return dir;
9882}
9883
9884/*
9885 * Shared by search() and searchpos() functions.
9886 */
9887 static int
9888search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9889{
9890 int flags;
9891 char_u *pat;
9892 pos_T pos;
9893 pos_T save_cursor;
9894 int save_p_ws = p_ws;
9895 int dir;
9896 int retval = 0; /* default: FAIL */
9897 long lnum_stop = 0;
9898 proftime_T tm;
9899#ifdef FEAT_RELTIME
9900 long time_limit = 0;
9901#endif
9902 int options = SEARCH_KEEP;
9903 int subpatnum;
9904
9905 pat = get_tv_string(&argvars[0]);
9906 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9907 if (dir == 0)
9908 goto theend;
9909 flags = *flagsp;
9910 if (flags & SP_START)
9911 options |= SEARCH_START;
9912 if (flags & SP_END)
9913 options |= SEARCH_END;
9914 if (flags & SP_COLUMN)
9915 options |= SEARCH_COL;
9916
9917 /* Optional arguments: line number to stop searching and timeout. */
9918 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9919 {
9920 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9921 if (lnum_stop < 0)
9922 goto theend;
9923#ifdef FEAT_RELTIME
9924 if (argvars[3].v_type != VAR_UNKNOWN)
9925 {
9926 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9927 if (time_limit < 0)
9928 goto theend;
9929 }
9930#endif
9931 }
9932
9933#ifdef FEAT_RELTIME
9934 /* Set the time limit, if there is one. */
9935 profile_setlimit(time_limit, &tm);
9936#endif
9937
9938 /*
9939 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9940 * Check to make sure only those flags are set.
9941 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9942 * flags cannot be set. Check for that condition also.
9943 */
9944 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9945 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9946 {
9947 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9948 goto theend;
9949 }
9950
9951 pos = save_cursor = curwin->w_cursor;
9952 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009953 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009954 if (subpatnum != FAIL)
9955 {
9956 if (flags & SP_SUBPAT)
9957 retval = subpatnum;
9958 else
9959 retval = pos.lnum;
9960 if (flags & SP_SETPCMARK)
9961 setpcmark();
9962 curwin->w_cursor = pos;
9963 if (match_pos != NULL)
9964 {
9965 /* Store the match cursor position */
9966 match_pos->lnum = pos.lnum;
9967 match_pos->col = pos.col + 1;
9968 }
9969 /* "/$" will put the cursor after the end of the line, may need to
9970 * correct that here */
9971 check_cursor();
9972 }
9973
9974 /* If 'n' flag is used: restore cursor position. */
9975 if (flags & SP_NOMOVE)
9976 curwin->w_cursor = save_cursor;
9977 else
9978 curwin->w_set_curswant = TRUE;
9979theend:
9980 p_ws = save_p_ws;
9981
9982 return retval;
9983}
9984
9985#ifdef FEAT_FLOAT
9986
9987/*
9988 * round() is not in C90, use ceil() or floor() instead.
9989 */
9990 float_T
9991vim_round(float_T f)
9992{
9993 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9994}
9995
9996/*
9997 * "round({float})" function
9998 */
9999 static void
10000f_round(typval_T *argvars, typval_T *rettv)
10001{
10002 float_T f = 0.0;
10003
10004 rettv->v_type = VAR_FLOAT;
10005 if (get_float_arg(argvars, &f) == OK)
10006 rettv->vval.v_float = vim_round(f);
10007 else
10008 rettv->vval.v_float = 0.0;
10009}
10010#endif
10011
10012/*
10013 * "screenattr()" function
10014 */
10015 static void
10016f_screenattr(typval_T *argvars, typval_T *rettv)
10017{
10018 int row;
10019 int col;
10020 int c;
10021
10022 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10023 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10024 if (row < 0 || row >= screen_Rows
10025 || col < 0 || col >= screen_Columns)
10026 c = -1;
10027 else
10028 c = ScreenAttrs[LineOffset[row] + col];
10029 rettv->vval.v_number = c;
10030}
10031
10032/*
10033 * "screenchar()" function
10034 */
10035 static void
10036f_screenchar(typval_T *argvars, typval_T *rettv)
10037{
10038 int row;
10039 int col;
10040 int off;
10041 int c;
10042
10043 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10044 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10045 if (row < 0 || row >= screen_Rows
10046 || col < 0 || col >= screen_Columns)
10047 c = -1;
10048 else
10049 {
10050 off = LineOffset[row] + col;
10051#ifdef FEAT_MBYTE
10052 if (enc_utf8 && ScreenLinesUC[off] != 0)
10053 c = ScreenLinesUC[off];
10054 else
10055#endif
10056 c = ScreenLines[off];
10057 }
10058 rettv->vval.v_number = c;
10059}
10060
10061/*
10062 * "screencol()" function
10063 *
10064 * First column is 1 to be consistent with virtcol().
10065 */
10066 static void
10067f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10068{
10069 rettv->vval.v_number = screen_screencol() + 1;
10070}
10071
10072/*
10073 * "screenrow()" function
10074 */
10075 static void
10076f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10077{
10078 rettv->vval.v_number = screen_screenrow() + 1;
10079}
10080
10081/*
10082 * "search()" function
10083 */
10084 static void
10085f_search(typval_T *argvars, typval_T *rettv)
10086{
10087 int flags = 0;
10088
10089 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10090}
10091
10092/*
10093 * "searchdecl()" function
10094 */
10095 static void
10096f_searchdecl(typval_T *argvars, typval_T *rettv)
10097{
10098 int locally = 1;
10099 int thisblock = 0;
10100 int error = FALSE;
10101 char_u *name;
10102
10103 rettv->vval.v_number = 1; /* default: FAIL */
10104
10105 name = get_tv_string_chk(&argvars[0]);
10106 if (argvars[1].v_type != VAR_UNKNOWN)
10107 {
10108 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
10109 if (!error && argvars[2].v_type != VAR_UNKNOWN)
10110 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
10111 }
10112 if (!error && name != NULL)
10113 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10114 locally, thisblock, SEARCH_KEEP) == FAIL;
10115}
10116
10117/*
10118 * Used by searchpair() and searchpairpos()
10119 */
10120 static int
10121searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10122{
10123 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010124 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010125 int save_p_ws = p_ws;
10126 int dir;
10127 int flags = 0;
10128 char_u nbuf1[NUMBUFLEN];
10129 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010130 int retval = 0; /* default: FAIL */
10131 long lnum_stop = 0;
10132 long time_limit = 0;
10133
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010134 /* Get the three pattern arguments: start, middle, end. Will result in an
10135 * error if not a valid argument. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010136 spat = get_tv_string_chk(&argvars[0]);
10137 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
10138 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
10139 if (spat == NULL || mpat == NULL || epat == NULL)
10140 goto theend; /* type error */
10141
10142 /* Handle the optional fourth argument: flags */
10143 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10144 if (dir == 0)
10145 goto theend;
10146
10147 /* Don't accept SP_END or SP_SUBPAT.
10148 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10149 */
10150 if ((flags & (SP_END | SP_SUBPAT)) != 0
10151 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10152 {
10153 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10154 goto theend;
10155 }
10156
10157 /* Using 'r' implies 'W', otherwise it doesn't work. */
10158 if (flags & SP_REPEAT)
10159 p_ws = FALSE;
10160
10161 /* Optional fifth argument: skip expression */
10162 if (argvars[3].v_type == VAR_UNKNOWN
10163 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010164 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010165 else
10166 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010167 skip = &argvars[4];
10168 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10169 && skip->v_type != VAR_STRING)
10170 {
10171 /* Type error */
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010172 EMSG2(_(e_invarg2), get_tv_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010173 goto theend;
10174 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010175 if (argvars[5].v_type != VAR_UNKNOWN)
10176 {
10177 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10178 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010179 {
10180 EMSG2(_(e_invarg2), get_tv_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010181 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010182 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010183#ifdef FEAT_RELTIME
10184 if (argvars[6].v_type != VAR_UNKNOWN)
10185 {
10186 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10187 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010188 {
10189 EMSG2(_(e_invarg2), get_tv_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010190 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010191 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010192 }
10193#endif
10194 }
10195 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010196
10197 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10198 match_pos, lnum_stop, time_limit);
10199
10200theend:
10201 p_ws = save_p_ws;
10202
10203 return retval;
10204}
10205
10206/*
10207 * "searchpair()" function
10208 */
10209 static void
10210f_searchpair(typval_T *argvars, typval_T *rettv)
10211{
10212 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10213}
10214
10215/*
10216 * "searchpairpos()" function
10217 */
10218 static void
10219f_searchpairpos(typval_T *argvars, typval_T *rettv)
10220{
10221 pos_T match_pos;
10222 int lnum = 0;
10223 int col = 0;
10224
10225 if (rettv_list_alloc(rettv) == FAIL)
10226 return;
10227
10228 if (searchpair_cmn(argvars, &match_pos) > 0)
10229 {
10230 lnum = match_pos.lnum;
10231 col = match_pos.col;
10232 }
10233
10234 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10235 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10236}
10237
10238/*
10239 * Search for a start/middle/end thing.
10240 * Used by searchpair(), see its documentation for the details.
10241 * Returns 0 or -1 for no match,
10242 */
10243 long
10244do_searchpair(
10245 char_u *spat, /* start pattern */
10246 char_u *mpat, /* middle pattern */
10247 char_u *epat, /* end pattern */
10248 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010249 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010250 int flags, /* SP_SETPCMARK and other SP_ values */
10251 pos_T *match_pos,
10252 linenr_T lnum_stop, /* stop at this line if not zero */
10253 long time_limit UNUSED) /* stop after this many msec */
10254{
10255 char_u *save_cpo;
10256 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10257 long retval = 0;
10258 pos_T pos;
10259 pos_T firstpos;
10260 pos_T foundpos;
10261 pos_T save_cursor;
10262 pos_T save_pos;
10263 int n;
10264 int r;
10265 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010266 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010267 int err;
10268 int options = SEARCH_KEEP;
10269 proftime_T tm;
10270
10271 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10272 save_cpo = p_cpo;
10273 p_cpo = empty_option;
10274
10275#ifdef FEAT_RELTIME
10276 /* Set the time limit, if there is one. */
10277 profile_setlimit(time_limit, &tm);
10278#endif
10279
10280 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10281 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010282 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10283 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010284 if (pat2 == NULL || pat3 == NULL)
10285 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010286 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010287 if (*mpat == NUL)
10288 STRCPY(pat3, pat2);
10289 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010290 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010291 spat, epat, mpat);
10292 if (flags & SP_START)
10293 options |= SEARCH_START;
10294
Bram Moolenaar48570482017-10-30 21:48:41 +010010295 if (skip != NULL)
10296 {
10297 /* Empty string means to not use the skip expression. */
10298 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10299 use_skip = skip->vval.v_string != NULL
10300 && *skip->vval.v_string != NUL;
10301 }
10302
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010303 save_cursor = curwin->w_cursor;
10304 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010305 CLEAR_POS(&firstpos);
10306 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010307 pat = pat3;
10308 for (;;)
10309 {
10310 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010311 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010312 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010313 /* didn't find it or found the first match again: FAIL */
10314 break;
10315
10316 if (firstpos.lnum == 0)
10317 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010318 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010319 {
10320 /* Found the same position again. Can happen with a pattern that
10321 * has "\zs" at the end and searching backwards. Advance one
10322 * character and try again. */
10323 if (dir == BACKWARD)
10324 decl(&pos);
10325 else
10326 incl(&pos);
10327 }
10328 foundpos = pos;
10329
10330 /* clear the start flag to avoid getting stuck here */
10331 options &= ~SEARCH_START;
10332
10333 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010334 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010335 {
10336 save_pos = curwin->w_cursor;
10337 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010338 err = FALSE;
10339 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010340 curwin->w_cursor = save_pos;
10341 if (err)
10342 {
10343 /* Evaluating {skip} caused an error, break here. */
10344 curwin->w_cursor = save_cursor;
10345 retval = -1;
10346 break;
10347 }
10348 if (r)
10349 continue;
10350 }
10351
10352 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10353 {
10354 /* Found end when searching backwards or start when searching
10355 * forward: nested pair. */
10356 ++nest;
10357 pat = pat2; /* nested, don't search for middle */
10358 }
10359 else
10360 {
10361 /* Found end when searching forward or start when searching
10362 * backward: end of (nested) pair; or found middle in outer pair. */
10363 if (--nest == 1)
10364 pat = pat3; /* outer level, search for middle */
10365 }
10366
10367 if (nest == 0)
10368 {
10369 /* Found the match: return matchcount or line number. */
10370 if (flags & SP_RETCOUNT)
10371 ++retval;
10372 else
10373 retval = pos.lnum;
10374 if (flags & SP_SETPCMARK)
10375 setpcmark();
10376 curwin->w_cursor = pos;
10377 if (!(flags & SP_REPEAT))
10378 break;
10379 nest = 1; /* search for next unmatched */
10380 }
10381 }
10382
10383 if (match_pos != NULL)
10384 {
10385 /* Store the match cursor position */
10386 match_pos->lnum = curwin->w_cursor.lnum;
10387 match_pos->col = curwin->w_cursor.col + 1;
10388 }
10389
10390 /* If 'n' flag is used or search failed: restore cursor position. */
10391 if ((flags & SP_NOMOVE) || retval == 0)
10392 curwin->w_cursor = save_cursor;
10393
10394theend:
10395 vim_free(pat2);
10396 vim_free(pat3);
10397 if (p_cpo == empty_option)
10398 p_cpo = save_cpo;
10399 else
10400 /* Darn, evaluating the {skip} expression changed the value. */
10401 free_string_option(save_cpo);
10402
10403 return retval;
10404}
10405
10406/*
10407 * "searchpos()" function
10408 */
10409 static void
10410f_searchpos(typval_T *argvars, typval_T *rettv)
10411{
10412 pos_T match_pos;
10413 int lnum = 0;
10414 int col = 0;
10415 int n;
10416 int flags = 0;
10417
10418 if (rettv_list_alloc(rettv) == FAIL)
10419 return;
10420
10421 n = search_cmn(argvars, &match_pos, &flags);
10422 if (n > 0)
10423 {
10424 lnum = match_pos.lnum;
10425 col = match_pos.col;
10426 }
10427
10428 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10429 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10430 if (flags & SP_SUBPAT)
10431 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10432}
10433
10434 static void
10435f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10436{
10437#ifdef FEAT_CLIENTSERVER
10438 char_u buf[NUMBUFLEN];
10439 char_u *server = get_tv_string_chk(&argvars[0]);
10440 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10441
10442 rettv->vval.v_number = -1;
10443 if (server == NULL || reply == NULL)
10444 return;
10445 if (check_restricted() || check_secure())
10446 return;
10447# ifdef FEAT_X11
10448 if (check_connection() == FAIL)
10449 return;
10450# endif
10451
10452 if (serverSendReply(server, reply) < 0)
10453 {
10454 EMSG(_("E258: Unable to send to client"));
10455 return;
10456 }
10457 rettv->vval.v_number = 0;
10458#else
10459 rettv->vval.v_number = -1;
10460#endif
10461}
10462
10463 static void
10464f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10465{
10466 char_u *r = NULL;
10467
10468#ifdef FEAT_CLIENTSERVER
10469# ifdef WIN32
10470 r = serverGetVimNames();
10471# else
10472 make_connection();
10473 if (X_DISPLAY != NULL)
10474 r = serverGetVimNames(X_DISPLAY);
10475# endif
10476#endif
10477 rettv->v_type = VAR_STRING;
10478 rettv->vval.v_string = r;
10479}
10480
10481/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010482 * "setbufline()" function
10483 */
10484 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010485f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010486{
10487 linenr_T lnum;
10488 buf_T *buf;
10489
10490 buf = get_buf_tv(&argvars[0], FALSE);
10491 if (buf == NULL)
10492 rettv->vval.v_number = 1; /* FAIL */
10493 else
10494 {
10495 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010496 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010497 }
10498}
10499
10500/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010501 * "setbufvar()" function
10502 */
10503 static void
10504f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10505{
10506 buf_T *buf;
10507 char_u *varname, *bufvarname;
10508 typval_T *varp;
10509 char_u nbuf[NUMBUFLEN];
10510
10511 if (check_restricted() || check_secure())
10512 return;
10513 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10514 varname = get_tv_string_chk(&argvars[1]);
10515 buf = get_buf_tv(&argvars[0], FALSE);
10516 varp = &argvars[2];
10517
10518 if (buf != NULL && varname != NULL && varp != NULL)
10519 {
10520 if (*varname == '&')
10521 {
10522 long numval;
10523 char_u *strval;
10524 int error = FALSE;
10525 aco_save_T aco;
10526
10527 /* set curbuf to be our buf, temporarily */
10528 aucmd_prepbuf(&aco, buf);
10529
10530 ++varname;
10531 numval = (long)get_tv_number_chk(varp, &error);
10532 strval = get_tv_string_buf_chk(varp, nbuf);
10533 if (!error && strval != NULL)
10534 set_option_value(varname, numval, strval, OPT_LOCAL);
10535
10536 /* reset notion of buffer */
10537 aucmd_restbuf(&aco);
10538 }
10539 else
10540 {
10541 buf_T *save_curbuf = curbuf;
10542
10543 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10544 if (bufvarname != NULL)
10545 {
10546 curbuf = buf;
10547 STRCPY(bufvarname, "b:");
10548 STRCPY(bufvarname + 2, varname);
10549 set_var(bufvarname, varp, TRUE);
10550 vim_free(bufvarname);
10551 curbuf = save_curbuf;
10552 }
10553 }
10554 }
10555}
10556
10557 static void
10558f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10559{
10560 dict_T *d;
10561 dictitem_T *di;
10562 char_u *csearch;
10563
10564 if (argvars[0].v_type != VAR_DICT)
10565 {
10566 EMSG(_(e_dictreq));
10567 return;
10568 }
10569
10570 if ((d = argvars[0].vval.v_dict) != NULL)
10571 {
10572 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10573 if (csearch != NULL)
10574 {
10575#ifdef FEAT_MBYTE
10576 if (enc_utf8)
10577 {
10578 int pcc[MAX_MCO];
10579 int c = utfc_ptr2char(csearch, pcc);
10580
10581 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10582 }
10583 else
10584#endif
10585 set_last_csearch(PTR2CHAR(csearch),
10586 csearch, MB_PTR2LEN(csearch));
10587 }
10588
10589 di = dict_find(d, (char_u *)"forward", -1);
10590 if (di != NULL)
10591 set_csearch_direction((int)get_tv_number(&di->di_tv)
10592 ? FORWARD : BACKWARD);
10593
10594 di = dict_find(d, (char_u *)"until", -1);
10595 if (di != NULL)
10596 set_csearch_until(!!get_tv_number(&di->di_tv));
10597 }
10598}
10599
10600/*
10601 * "setcmdpos()" function
10602 */
10603 static void
10604f_setcmdpos(typval_T *argvars, typval_T *rettv)
10605{
10606 int pos = (int)get_tv_number(&argvars[0]) - 1;
10607
10608 if (pos >= 0)
10609 rettv->vval.v_number = set_cmdline_pos(pos);
10610}
10611
10612/*
10613 * "setfperm({fname}, {mode})" function
10614 */
10615 static void
10616f_setfperm(typval_T *argvars, typval_T *rettv)
10617{
10618 char_u *fname;
10619 char_u modebuf[NUMBUFLEN];
10620 char_u *mode_str;
10621 int i;
10622 int mask;
10623 int mode = 0;
10624
10625 rettv->vval.v_number = 0;
10626 fname = get_tv_string_chk(&argvars[0]);
10627 if (fname == NULL)
10628 return;
10629 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10630 if (mode_str == NULL)
10631 return;
10632 if (STRLEN(mode_str) != 9)
10633 {
10634 EMSG2(_(e_invarg2), mode_str);
10635 return;
10636 }
10637
10638 mask = 1;
10639 for (i = 8; i >= 0; --i)
10640 {
10641 if (mode_str[i] != '-')
10642 mode |= mask;
10643 mask = mask << 1;
10644 }
10645 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10646}
10647
10648/*
10649 * "setline()" function
10650 */
10651 static void
10652f_setline(typval_T *argvars, typval_T *rettv)
10653{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010654 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010655
Bram Moolenaarca851592018-06-06 21:04:07 +020010656 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010657}
10658
Bram Moolenaard823fa92016-08-12 16:29:27 +020010659static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *what_arg, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010660
10661/*
10662 * Used by "setqflist()" and "setloclist()" functions
10663 */
10664 static void
10665set_qf_ll_list(
10666 win_T *wp UNUSED,
10667 typval_T *list_arg UNUSED,
10668 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010669 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010670 typval_T *rettv)
10671{
10672#ifdef FEAT_QUICKFIX
10673 static char *e_invact = N_("E927: Invalid action: '%s'");
10674 char_u *act;
10675 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010676 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010677#endif
10678
10679 rettv->vval.v_number = -1;
10680
10681#ifdef FEAT_QUICKFIX
10682 if (list_arg->v_type != VAR_LIST)
10683 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010684 else if (recursive != 0)
10685 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010686 else
10687 {
10688 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010689 dict_T *d = NULL;
10690 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010691
10692 if (action_arg->v_type == VAR_STRING)
10693 {
10694 act = get_tv_string_chk(action_arg);
10695 if (act == NULL)
10696 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010697 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10698 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010699 action = *act;
10700 else
10701 EMSG2(_(e_invact), act);
10702 }
10703 else if (action_arg->v_type == VAR_UNKNOWN)
10704 action = ' ';
10705 else
10706 EMSG(_(e_stringreq));
10707
Bram Moolenaard823fa92016-08-12 16:29:27 +020010708 if (action_arg->v_type != VAR_UNKNOWN
10709 && what_arg->v_type != VAR_UNKNOWN)
10710 {
10711 if (what_arg->v_type == VAR_DICT)
10712 d = what_arg->vval.v_dict;
10713 else
10714 {
10715 EMSG(_(e_dictreq));
10716 valid_dict = FALSE;
10717 }
10718 }
10719
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010720 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010721 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010722 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10723 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010724 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010725 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010726 }
10727#endif
10728}
10729
10730/*
10731 * "setloclist()" function
10732 */
10733 static void
10734f_setloclist(typval_T *argvars, typval_T *rettv)
10735{
10736 win_T *win;
10737
10738 rettv->vval.v_number = -1;
10739
10740 win = find_win_by_nr(&argvars[0], NULL);
10741 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010742 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010743}
10744
10745/*
10746 * "setmatches()" function
10747 */
10748 static void
10749f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10750{
10751#ifdef FEAT_SEARCH_EXTRA
10752 list_T *l;
10753 listitem_T *li;
10754 dict_T *d;
10755 list_T *s = NULL;
10756
10757 rettv->vval.v_number = -1;
10758 if (argvars[0].v_type != VAR_LIST)
10759 {
10760 EMSG(_(e_listreq));
10761 return;
10762 }
10763 if ((l = argvars[0].vval.v_list) != NULL)
10764 {
10765
10766 /* To some extent make sure that we are dealing with a list from
10767 * "getmatches()". */
10768 li = l->lv_first;
10769 while (li != NULL)
10770 {
10771 if (li->li_tv.v_type != VAR_DICT
10772 || (d = li->li_tv.vval.v_dict) == NULL)
10773 {
10774 EMSG(_(e_invarg));
10775 return;
10776 }
10777 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10778 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10779 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10780 && dict_find(d, (char_u *)"priority", -1) != NULL
10781 && dict_find(d, (char_u *)"id", -1) != NULL))
10782 {
10783 EMSG(_(e_invarg));
10784 return;
10785 }
10786 li = li->li_next;
10787 }
10788
10789 clear_matches(curwin);
10790 li = l->lv_first;
10791 while (li != NULL)
10792 {
10793 int i = 0;
10794 char_u buf[5];
10795 dictitem_T *di;
10796 char_u *group;
10797 int priority;
10798 int id;
10799 char_u *conceal;
10800
10801 d = li->li_tv.vval.v_dict;
10802 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10803 {
10804 if (s == NULL)
10805 {
10806 s = list_alloc();
10807 if (s == NULL)
10808 return;
10809 }
10810
10811 /* match from matchaddpos() */
10812 for (i = 1; i < 9; i++)
10813 {
10814 sprintf((char *)buf, (char *)"pos%d", i);
10815 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10816 {
10817 if (di->di_tv.v_type != VAR_LIST)
10818 return;
10819
10820 list_append_tv(s, &di->di_tv);
10821 s->lv_refcount++;
10822 }
10823 else
10824 break;
10825 }
10826 }
10827
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010828 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010829 priority = (int)get_dict_number(d, (char_u *)"priority");
10830 id = (int)get_dict_number(d, (char_u *)"id");
10831 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010832 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010833 : NULL;
10834 if (i == 0)
10835 {
10836 match_add(curwin, group,
10837 get_dict_string(d, (char_u *)"pattern", FALSE),
10838 priority, id, NULL, conceal);
10839 }
10840 else
10841 {
10842 match_add(curwin, group, NULL, priority, id, s, conceal);
10843 list_unref(s);
10844 s = NULL;
10845 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010846 vim_free(group);
10847 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010848
10849 li = li->li_next;
10850 }
10851 rettv->vval.v_number = 0;
10852 }
10853#endif
10854}
10855
10856/*
10857 * "setpos()" function
10858 */
10859 static void
10860f_setpos(typval_T *argvars, typval_T *rettv)
10861{
10862 pos_T pos;
10863 int fnum;
10864 char_u *name;
10865 colnr_T curswant = -1;
10866
10867 rettv->vval.v_number = -1;
10868 name = get_tv_string_chk(argvars);
10869 if (name != NULL)
10870 {
10871 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10872 {
10873 if (--pos.col < 0)
10874 pos.col = 0;
10875 if (name[0] == '.' && name[1] == NUL)
10876 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010877 /* set cursor; "fnum" is ignored */
10878 curwin->w_cursor = pos;
10879 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010880 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010881 curwin->w_curswant = curswant - 1;
10882 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010883 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010884 check_cursor();
10885 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010886 }
10887 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10888 {
10889 /* set mark */
10890 if (setmark_pos(name[1], &pos, fnum) == OK)
10891 rettv->vval.v_number = 0;
10892 }
10893 else
10894 EMSG(_(e_invarg));
10895 }
10896 }
10897}
10898
10899/*
10900 * "setqflist()" function
10901 */
10902 static void
10903f_setqflist(typval_T *argvars, typval_T *rettv)
10904{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010905 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010906}
10907
10908/*
10909 * "setreg()" function
10910 */
10911 static void
10912f_setreg(typval_T *argvars, typval_T *rettv)
10913{
10914 int regname;
10915 char_u *strregname;
10916 char_u *stropt;
10917 char_u *strval;
10918 int append;
10919 char_u yank_type;
10920 long block_len;
10921
10922 block_len = -1;
10923 yank_type = MAUTO;
10924 append = FALSE;
10925
10926 strregname = get_tv_string_chk(argvars);
10927 rettv->vval.v_number = 1; /* FAIL is default */
10928
10929 if (strregname == NULL)
10930 return; /* type error; errmsg already given */
10931 regname = *strregname;
10932 if (regname == 0 || regname == '@')
10933 regname = '"';
10934
10935 if (argvars[2].v_type != VAR_UNKNOWN)
10936 {
10937 stropt = get_tv_string_chk(&argvars[2]);
10938 if (stropt == NULL)
10939 return; /* type error */
10940 for (; *stropt != NUL; ++stropt)
10941 switch (*stropt)
10942 {
10943 case 'a': case 'A': /* append */
10944 append = TRUE;
10945 break;
10946 case 'v': case 'c': /* character-wise selection */
10947 yank_type = MCHAR;
10948 break;
10949 case 'V': case 'l': /* line-wise selection */
10950 yank_type = MLINE;
10951 break;
10952 case 'b': case Ctrl_V: /* block-wise selection */
10953 yank_type = MBLOCK;
10954 if (VIM_ISDIGIT(stropt[1]))
10955 {
10956 ++stropt;
10957 block_len = getdigits(&stropt) - 1;
10958 --stropt;
10959 }
10960 break;
10961 }
10962 }
10963
10964 if (argvars[1].v_type == VAR_LIST)
10965 {
10966 char_u **lstval;
10967 char_u **allocval;
10968 char_u buf[NUMBUFLEN];
10969 char_u **curval;
10970 char_u **curallocval;
10971 list_T *ll = argvars[1].vval.v_list;
10972 listitem_T *li;
10973 int len;
10974
10975 /* If the list is NULL handle like an empty list. */
10976 len = ll == NULL ? 0 : ll->lv_len;
10977
10978 /* First half: use for pointers to result lines; second half: use for
10979 * pointers to allocated copies. */
10980 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10981 if (lstval == NULL)
10982 return;
10983 curval = lstval;
10984 allocval = lstval + len + 2;
10985 curallocval = allocval;
10986
10987 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10988 li = li->li_next)
10989 {
10990 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10991 if (strval == NULL)
10992 goto free_lstval;
10993 if (strval == buf)
10994 {
10995 /* Need to make a copy, next get_tv_string_buf_chk() will
10996 * overwrite the string. */
10997 strval = vim_strsave(buf);
10998 if (strval == NULL)
10999 goto free_lstval;
11000 *curallocval++ = strval;
11001 }
11002 *curval++ = strval;
11003 }
11004 *curval++ = NULL;
11005
11006 write_reg_contents_lst(regname, lstval, -1,
11007 append, yank_type, block_len);
11008free_lstval:
11009 while (curallocval > allocval)
11010 vim_free(*--curallocval);
11011 vim_free(lstval);
11012 }
11013 else
11014 {
11015 strval = get_tv_string_chk(&argvars[1]);
11016 if (strval == NULL)
11017 return;
11018 write_reg_contents_ex(regname, strval, -1,
11019 append, yank_type, block_len);
11020 }
11021 rettv->vval.v_number = 0;
11022}
11023
11024/*
11025 * "settabvar()" function
11026 */
11027 static void
11028f_settabvar(typval_T *argvars, typval_T *rettv)
11029{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011030 tabpage_T *save_curtab;
11031 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011032 char_u *varname, *tabvarname;
11033 typval_T *varp;
11034
11035 rettv->vval.v_number = 0;
11036
11037 if (check_restricted() || check_secure())
11038 return;
11039
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011040 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011041 varname = get_tv_string_chk(&argvars[1]);
11042 varp = &argvars[2];
11043
Bram Moolenaar4033c552017-09-16 20:54:51 +020011044 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011045 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011046 save_curtab = curtab;
11047 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011048
11049 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11050 if (tabvarname != NULL)
11051 {
11052 STRCPY(tabvarname, "t:");
11053 STRCPY(tabvarname + 2, varname);
11054 set_var(tabvarname, varp, TRUE);
11055 vim_free(tabvarname);
11056 }
11057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011058 /* Restore current tabpage */
11059 if (valid_tabpage(save_curtab))
11060 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011061 }
11062}
11063
11064/*
11065 * "settabwinvar()" function
11066 */
11067 static void
11068f_settabwinvar(typval_T *argvars, typval_T *rettv)
11069{
11070 setwinvar(argvars, rettv, 1);
11071}
11072
11073/*
11074 * "setwinvar()" function
11075 */
11076 static void
11077f_setwinvar(typval_T *argvars, typval_T *rettv)
11078{
11079 setwinvar(argvars, rettv, 0);
11080}
11081
11082#ifdef FEAT_CRYPT
11083/*
11084 * "sha256({string})" function
11085 */
11086 static void
11087f_sha256(typval_T *argvars, typval_T *rettv)
11088{
11089 char_u *p;
11090
11091 p = get_tv_string(&argvars[0]);
11092 rettv->vval.v_string = vim_strsave(
11093 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11094 rettv->v_type = VAR_STRING;
11095}
11096#endif /* FEAT_CRYPT */
11097
11098/*
11099 * "shellescape({string})" function
11100 */
11101 static void
11102f_shellescape(typval_T *argvars, typval_T *rettv)
11103{
Bram Moolenaar20615522017-06-05 18:46:26 +020011104 int do_special = non_zero_arg(&argvars[1]);
11105
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011106 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020011107 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011108 rettv->v_type = VAR_STRING;
11109}
11110
11111/*
11112 * shiftwidth() function
11113 */
11114 static void
11115f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11116{
11117 rettv->vval.v_number = get_sw_value(curbuf);
11118}
11119
11120/*
11121 * "simplify()" function
11122 */
11123 static void
11124f_simplify(typval_T *argvars, typval_T *rettv)
11125{
11126 char_u *p;
11127
11128 p = get_tv_string(&argvars[0]);
11129 rettv->vval.v_string = vim_strsave(p);
11130 simplify_filename(rettv->vval.v_string); /* simplify in place */
11131 rettv->v_type = VAR_STRING;
11132}
11133
11134#ifdef FEAT_FLOAT
11135/*
11136 * "sin()" function
11137 */
11138 static void
11139f_sin(typval_T *argvars, typval_T *rettv)
11140{
11141 float_T f = 0.0;
11142
11143 rettv->v_type = VAR_FLOAT;
11144 if (get_float_arg(argvars, &f) == OK)
11145 rettv->vval.v_float = sin(f);
11146 else
11147 rettv->vval.v_float = 0.0;
11148}
11149
11150/*
11151 * "sinh()" function
11152 */
11153 static void
11154f_sinh(typval_T *argvars, typval_T *rettv)
11155{
11156 float_T f = 0.0;
11157
11158 rettv->v_type = VAR_FLOAT;
11159 if (get_float_arg(argvars, &f) == OK)
11160 rettv->vval.v_float = sinh(f);
11161 else
11162 rettv->vval.v_float = 0.0;
11163}
11164#endif
11165
11166static int
11167#ifdef __BORLANDC__
11168 _RTLENTRYF
11169#endif
11170 item_compare(const void *s1, const void *s2);
11171static int
11172#ifdef __BORLANDC__
11173 _RTLENTRYF
11174#endif
11175 item_compare2(const void *s1, const void *s2);
11176
11177/* struct used in the array that's given to qsort() */
11178typedef struct
11179{
11180 listitem_T *item;
11181 int idx;
11182} sortItem_T;
11183
11184/* struct storing information about current sort */
11185typedef struct
11186{
11187 int item_compare_ic;
11188 int item_compare_numeric;
11189 int item_compare_numbers;
11190#ifdef FEAT_FLOAT
11191 int item_compare_float;
11192#endif
11193 char_u *item_compare_func;
11194 partial_T *item_compare_partial;
11195 dict_T *item_compare_selfdict;
11196 int item_compare_func_err;
11197 int item_compare_keep_zero;
11198} sortinfo_T;
11199static sortinfo_T *sortinfo = NULL;
11200static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
11201#define ITEM_COMPARE_FAIL 999
11202
11203/*
11204 * Compare functions for f_sort() and f_uniq() below.
11205 */
11206 static int
11207#ifdef __BORLANDC__
11208_RTLENTRYF
11209#endif
11210item_compare(const void *s1, const void *s2)
11211{
11212 sortItem_T *si1, *si2;
11213 typval_T *tv1, *tv2;
11214 char_u *p1, *p2;
11215 char_u *tofree1 = NULL, *tofree2 = NULL;
11216 int res;
11217 char_u numbuf1[NUMBUFLEN];
11218 char_u numbuf2[NUMBUFLEN];
11219
11220 si1 = (sortItem_T *)s1;
11221 si2 = (sortItem_T *)s2;
11222 tv1 = &si1->item->li_tv;
11223 tv2 = &si2->item->li_tv;
11224
11225 if (sortinfo->item_compare_numbers)
11226 {
11227 varnumber_T v1 = get_tv_number(tv1);
11228 varnumber_T v2 = get_tv_number(tv2);
11229
11230 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11231 }
11232
11233#ifdef FEAT_FLOAT
11234 if (sortinfo->item_compare_float)
11235 {
11236 float_T v1 = get_tv_float(tv1);
11237 float_T v2 = get_tv_float(tv2);
11238
11239 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11240 }
11241#endif
11242
11243 /* tv2string() puts quotes around a string and allocates memory. Don't do
11244 * that for string variables. Use a single quote when comparing with a
11245 * non-string to do what the docs promise. */
11246 if (tv1->v_type == VAR_STRING)
11247 {
11248 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11249 p1 = (char_u *)"'";
11250 else
11251 p1 = tv1->vval.v_string;
11252 }
11253 else
11254 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11255 if (tv2->v_type == VAR_STRING)
11256 {
11257 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11258 p2 = (char_u *)"'";
11259 else
11260 p2 = tv2->vval.v_string;
11261 }
11262 else
11263 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11264 if (p1 == NULL)
11265 p1 = (char_u *)"";
11266 if (p2 == NULL)
11267 p2 = (char_u *)"";
11268 if (!sortinfo->item_compare_numeric)
11269 {
11270 if (sortinfo->item_compare_ic)
11271 res = STRICMP(p1, p2);
11272 else
11273 res = STRCMP(p1, p2);
11274 }
11275 else
11276 {
11277 double n1, n2;
11278 n1 = strtod((char *)p1, (char **)&p1);
11279 n2 = strtod((char *)p2, (char **)&p2);
11280 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11281 }
11282
11283 /* When the result would be zero, compare the item indexes. Makes the
11284 * sort stable. */
11285 if (res == 0 && !sortinfo->item_compare_keep_zero)
11286 res = si1->idx > si2->idx ? 1 : -1;
11287
11288 vim_free(tofree1);
11289 vim_free(tofree2);
11290 return res;
11291}
11292
11293 static int
11294#ifdef __BORLANDC__
11295_RTLENTRYF
11296#endif
11297item_compare2(const void *s1, const void *s2)
11298{
11299 sortItem_T *si1, *si2;
11300 int res;
11301 typval_T rettv;
11302 typval_T argv[3];
11303 int dummy;
11304 char_u *func_name;
11305 partial_T *partial = sortinfo->item_compare_partial;
11306
11307 /* shortcut after failure in previous call; compare all items equal */
11308 if (sortinfo->item_compare_func_err)
11309 return 0;
11310
11311 si1 = (sortItem_T *)s1;
11312 si2 = (sortItem_T *)s2;
11313
11314 if (partial == NULL)
11315 func_name = sortinfo->item_compare_func;
11316 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011317 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011318
11319 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11320 * in the copy without changing the original list items. */
11321 copy_tv(&si1->item->li_tv, &argv[0]);
11322 copy_tv(&si2->item->li_tv, &argv[1]);
11323
11324 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11325 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011326 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011327 partial, sortinfo->item_compare_selfdict);
11328 clear_tv(&argv[0]);
11329 clear_tv(&argv[1]);
11330
11331 if (res == FAIL)
11332 res = ITEM_COMPARE_FAIL;
11333 else
11334 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11335 if (sortinfo->item_compare_func_err)
11336 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11337 clear_tv(&rettv);
11338
11339 /* When the result would be zero, compare the pointers themselves. Makes
11340 * the sort stable. */
11341 if (res == 0 && !sortinfo->item_compare_keep_zero)
11342 res = si1->idx > si2->idx ? 1 : -1;
11343
11344 return res;
11345}
11346
11347/*
11348 * "sort({list})" function
11349 */
11350 static void
11351do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11352{
11353 list_T *l;
11354 listitem_T *li;
11355 sortItem_T *ptrs;
11356 sortinfo_T *old_sortinfo;
11357 sortinfo_T info;
11358 long len;
11359 long i;
11360
11361 /* Pointer to current info struct used in compare function. Save and
11362 * restore the current one for nested calls. */
11363 old_sortinfo = sortinfo;
11364 sortinfo = &info;
11365
11366 if (argvars[0].v_type != VAR_LIST)
11367 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11368 else
11369 {
11370 l = argvars[0].vval.v_list;
11371 if (l == NULL || tv_check_lock(l->lv_lock,
11372 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11373 TRUE))
11374 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011375 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011376
11377 len = list_len(l);
11378 if (len <= 1)
11379 goto theend; /* short list sorts pretty quickly */
11380
11381 info.item_compare_ic = FALSE;
11382 info.item_compare_numeric = FALSE;
11383 info.item_compare_numbers = FALSE;
11384#ifdef FEAT_FLOAT
11385 info.item_compare_float = FALSE;
11386#endif
11387 info.item_compare_func = NULL;
11388 info.item_compare_partial = NULL;
11389 info.item_compare_selfdict = NULL;
11390 if (argvars[1].v_type != VAR_UNKNOWN)
11391 {
11392 /* optional second argument: {func} */
11393 if (argvars[1].v_type == VAR_FUNC)
11394 info.item_compare_func = argvars[1].vval.v_string;
11395 else if (argvars[1].v_type == VAR_PARTIAL)
11396 info.item_compare_partial = argvars[1].vval.v_partial;
11397 else
11398 {
11399 int error = FALSE;
11400
11401 i = (long)get_tv_number_chk(&argvars[1], &error);
11402 if (error)
11403 goto theend; /* type error; errmsg already given */
11404 if (i == 1)
11405 info.item_compare_ic = TRUE;
11406 else if (argvars[1].v_type != VAR_NUMBER)
11407 info.item_compare_func = get_tv_string(&argvars[1]);
11408 else if (i != 0)
11409 {
11410 EMSG(_(e_invarg));
11411 goto theend;
11412 }
11413 if (info.item_compare_func != NULL)
11414 {
11415 if (*info.item_compare_func == NUL)
11416 {
11417 /* empty string means default sort */
11418 info.item_compare_func = NULL;
11419 }
11420 else if (STRCMP(info.item_compare_func, "n") == 0)
11421 {
11422 info.item_compare_func = NULL;
11423 info.item_compare_numeric = TRUE;
11424 }
11425 else if (STRCMP(info.item_compare_func, "N") == 0)
11426 {
11427 info.item_compare_func = NULL;
11428 info.item_compare_numbers = TRUE;
11429 }
11430#ifdef FEAT_FLOAT
11431 else if (STRCMP(info.item_compare_func, "f") == 0)
11432 {
11433 info.item_compare_func = NULL;
11434 info.item_compare_float = TRUE;
11435 }
11436#endif
11437 else if (STRCMP(info.item_compare_func, "i") == 0)
11438 {
11439 info.item_compare_func = NULL;
11440 info.item_compare_ic = TRUE;
11441 }
11442 }
11443 }
11444
11445 if (argvars[2].v_type != VAR_UNKNOWN)
11446 {
11447 /* optional third argument: {dict} */
11448 if (argvars[2].v_type != VAR_DICT)
11449 {
11450 EMSG(_(e_dictreq));
11451 goto theend;
11452 }
11453 info.item_compare_selfdict = argvars[2].vval.v_dict;
11454 }
11455 }
11456
11457 /* Make an array with each entry pointing to an item in the List. */
11458 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11459 if (ptrs == NULL)
11460 goto theend;
11461
11462 i = 0;
11463 if (sort)
11464 {
11465 /* sort(): ptrs will be the list to sort */
11466 for (li = l->lv_first; li != NULL; li = li->li_next)
11467 {
11468 ptrs[i].item = li;
11469 ptrs[i].idx = i;
11470 ++i;
11471 }
11472
11473 info.item_compare_func_err = FALSE;
11474 info.item_compare_keep_zero = FALSE;
11475 /* test the compare function */
11476 if ((info.item_compare_func != NULL
11477 || info.item_compare_partial != NULL)
11478 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11479 == ITEM_COMPARE_FAIL)
11480 EMSG(_("E702: Sort compare function failed"));
11481 else
11482 {
11483 /* Sort the array with item pointers. */
11484 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11485 info.item_compare_func == NULL
11486 && info.item_compare_partial == NULL
11487 ? item_compare : item_compare2);
11488
11489 if (!info.item_compare_func_err)
11490 {
11491 /* Clear the List and append the items in sorted order. */
11492 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11493 l->lv_len = 0;
11494 for (i = 0; i < len; ++i)
11495 list_append(l, ptrs[i].item);
11496 }
11497 }
11498 }
11499 else
11500 {
11501 int (*item_compare_func_ptr)(const void *, const void *);
11502
11503 /* f_uniq(): ptrs will be a stack of items to remove */
11504 info.item_compare_func_err = FALSE;
11505 info.item_compare_keep_zero = TRUE;
11506 item_compare_func_ptr = info.item_compare_func != NULL
11507 || info.item_compare_partial != NULL
11508 ? item_compare2 : item_compare;
11509
11510 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11511 li = li->li_next)
11512 {
11513 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11514 == 0)
11515 ptrs[i++].item = li;
11516 if (info.item_compare_func_err)
11517 {
11518 EMSG(_("E882: Uniq compare function failed"));
11519 break;
11520 }
11521 }
11522
11523 if (!info.item_compare_func_err)
11524 {
11525 while (--i >= 0)
11526 {
11527 li = ptrs[i].item->li_next;
11528 ptrs[i].item->li_next = li->li_next;
11529 if (li->li_next != NULL)
11530 li->li_next->li_prev = ptrs[i].item;
11531 else
11532 l->lv_last = ptrs[i].item;
11533 list_fix_watch(l, li);
11534 listitem_free(li);
11535 l->lv_len--;
11536 }
11537 }
11538 }
11539
11540 vim_free(ptrs);
11541 }
11542theend:
11543 sortinfo = old_sortinfo;
11544}
11545
11546/*
11547 * "sort({list})" function
11548 */
11549 static void
11550f_sort(typval_T *argvars, typval_T *rettv)
11551{
11552 do_sort_uniq(argvars, rettv, TRUE);
11553}
11554
11555/*
11556 * "uniq({list})" function
11557 */
11558 static void
11559f_uniq(typval_T *argvars, typval_T *rettv)
11560{
11561 do_sort_uniq(argvars, rettv, FALSE);
11562}
11563
11564/*
11565 * "soundfold({word})" function
11566 */
11567 static void
11568f_soundfold(typval_T *argvars, typval_T *rettv)
11569{
11570 char_u *s;
11571
11572 rettv->v_type = VAR_STRING;
11573 s = get_tv_string(&argvars[0]);
11574#ifdef FEAT_SPELL
11575 rettv->vval.v_string = eval_soundfold(s);
11576#else
11577 rettv->vval.v_string = vim_strsave(s);
11578#endif
11579}
11580
11581/*
11582 * "spellbadword()" function
11583 */
11584 static void
11585f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11586{
11587 char_u *word = (char_u *)"";
11588 hlf_T attr = HLF_COUNT;
11589 int len = 0;
11590
11591 if (rettv_list_alloc(rettv) == FAIL)
11592 return;
11593
11594#ifdef FEAT_SPELL
11595 if (argvars[0].v_type == VAR_UNKNOWN)
11596 {
11597 /* Find the start and length of the badly spelled word. */
11598 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11599 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011600 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011601 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011602 curwin->w_set_curswant = TRUE;
11603 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011604 }
11605 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11606 {
11607 char_u *str = get_tv_string_chk(&argvars[0]);
11608 int capcol = -1;
11609
11610 if (str != NULL)
11611 {
11612 /* Check the argument for spelling. */
11613 while (*str != NUL)
11614 {
11615 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11616 if (attr != HLF_COUNT)
11617 {
11618 word = str;
11619 break;
11620 }
11621 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020011622 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011623 }
11624 }
11625 }
11626#endif
11627
11628 list_append_string(rettv->vval.v_list, word, len);
11629 list_append_string(rettv->vval.v_list, (char_u *)(
11630 attr == HLF_SPB ? "bad" :
11631 attr == HLF_SPR ? "rare" :
11632 attr == HLF_SPL ? "local" :
11633 attr == HLF_SPC ? "caps" :
11634 ""), -1);
11635}
11636
11637/*
11638 * "spellsuggest()" function
11639 */
11640 static void
11641f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11642{
11643#ifdef FEAT_SPELL
11644 char_u *str;
11645 int typeerr = FALSE;
11646 int maxcount;
11647 garray_T ga;
11648 int i;
11649 listitem_T *li;
11650 int need_capital = FALSE;
11651#endif
11652
11653 if (rettv_list_alloc(rettv) == FAIL)
11654 return;
11655
11656#ifdef FEAT_SPELL
11657 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11658 {
11659 str = get_tv_string(&argvars[0]);
11660 if (argvars[1].v_type != VAR_UNKNOWN)
11661 {
11662 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11663 if (maxcount <= 0)
11664 return;
11665 if (argvars[2].v_type != VAR_UNKNOWN)
11666 {
11667 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11668 if (typeerr)
11669 return;
11670 }
11671 }
11672 else
11673 maxcount = 25;
11674
11675 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11676
11677 for (i = 0; i < ga.ga_len; ++i)
11678 {
11679 str = ((char_u **)ga.ga_data)[i];
11680
11681 li = listitem_alloc();
11682 if (li == NULL)
11683 vim_free(str);
11684 else
11685 {
11686 li->li_tv.v_type = VAR_STRING;
11687 li->li_tv.v_lock = 0;
11688 li->li_tv.vval.v_string = str;
11689 list_append(rettv->vval.v_list, li);
11690 }
11691 }
11692 ga_clear(&ga);
11693 }
11694#endif
11695}
11696
11697 static void
11698f_split(typval_T *argvars, typval_T *rettv)
11699{
11700 char_u *str;
11701 char_u *end;
11702 char_u *pat = NULL;
11703 regmatch_T regmatch;
11704 char_u patbuf[NUMBUFLEN];
11705 char_u *save_cpo;
11706 int match;
11707 colnr_T col = 0;
11708 int keepempty = FALSE;
11709 int typeerr = FALSE;
11710
11711 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11712 save_cpo = p_cpo;
11713 p_cpo = (char_u *)"";
11714
11715 str = get_tv_string(&argvars[0]);
11716 if (argvars[1].v_type != VAR_UNKNOWN)
11717 {
11718 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11719 if (pat == NULL)
11720 typeerr = TRUE;
11721 if (argvars[2].v_type != VAR_UNKNOWN)
11722 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11723 }
11724 if (pat == NULL || *pat == NUL)
11725 pat = (char_u *)"[\\x01- ]\\+";
11726
11727 if (rettv_list_alloc(rettv) == FAIL)
11728 return;
11729 if (typeerr)
11730 return;
11731
11732 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11733 if (regmatch.regprog != NULL)
11734 {
11735 regmatch.rm_ic = FALSE;
11736 while (*str != NUL || keepempty)
11737 {
11738 if (*str == NUL)
11739 match = FALSE; /* empty item at the end */
11740 else
11741 match = vim_regexec_nl(&regmatch, str, col);
11742 if (match)
11743 end = regmatch.startp[0];
11744 else
11745 end = str + STRLEN(str);
11746 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11747 && *str != NUL && match && end < regmatch.endp[0]))
11748 {
11749 if (list_append_string(rettv->vval.v_list, str,
11750 (int)(end - str)) == FAIL)
11751 break;
11752 }
11753 if (!match)
11754 break;
11755 /* Advance to just after the match. */
11756 if (regmatch.endp[0] > str)
11757 col = 0;
11758 else
11759 {
11760 /* Don't get stuck at the same match. */
11761#ifdef FEAT_MBYTE
11762 col = (*mb_ptr2len)(regmatch.endp[0]);
11763#else
11764 col = 1;
11765#endif
11766 }
11767 str = regmatch.endp[0];
11768 }
11769
11770 vim_regfree(regmatch.regprog);
11771 }
11772
11773 p_cpo = save_cpo;
11774}
11775
11776#ifdef FEAT_FLOAT
11777/*
11778 * "sqrt()" function
11779 */
11780 static void
11781f_sqrt(typval_T *argvars, typval_T *rettv)
11782{
11783 float_T f = 0.0;
11784
11785 rettv->v_type = VAR_FLOAT;
11786 if (get_float_arg(argvars, &f) == OK)
11787 rettv->vval.v_float = sqrt(f);
11788 else
11789 rettv->vval.v_float = 0.0;
11790}
11791
11792/*
11793 * "str2float()" function
11794 */
11795 static void
11796f_str2float(typval_T *argvars, typval_T *rettv)
11797{
11798 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011799 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011800
Bram Moolenaar08243d22017-01-10 16:12:29 +010011801 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011802 p = skipwhite(p + 1);
11803 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011804 if (isneg)
11805 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011806 rettv->v_type = VAR_FLOAT;
11807}
11808#endif
11809
11810/*
11811 * "str2nr()" function
11812 */
11813 static void
11814f_str2nr(typval_T *argvars, typval_T *rettv)
11815{
11816 int base = 10;
11817 char_u *p;
11818 varnumber_T n;
11819 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011820 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011821
11822 if (argvars[1].v_type != VAR_UNKNOWN)
11823 {
11824 base = (int)get_tv_number(&argvars[1]);
11825 if (base != 2 && base != 8 && base != 10 && base != 16)
11826 {
11827 EMSG(_(e_invarg));
11828 return;
11829 }
11830 }
11831
11832 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011833 isneg = (*p == '-');
11834 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011835 p = skipwhite(p + 1);
11836 switch (base)
11837 {
11838 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11839 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11840 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11841 default: what = 0;
11842 }
11843 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011844 if (isneg)
11845 rettv->vval.v_number = -n;
11846 else
11847 rettv->vval.v_number = n;
11848
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011849}
11850
11851#ifdef HAVE_STRFTIME
11852/*
11853 * "strftime({format}[, {time}])" function
11854 */
11855 static void
11856f_strftime(typval_T *argvars, typval_T *rettv)
11857{
11858 char_u result_buf[256];
11859 struct tm *curtime;
11860 time_t seconds;
11861 char_u *p;
11862
11863 rettv->v_type = VAR_STRING;
11864
11865 p = get_tv_string(&argvars[0]);
11866 if (argvars[1].v_type == VAR_UNKNOWN)
11867 seconds = time(NULL);
11868 else
11869 seconds = (time_t)get_tv_number(&argvars[1]);
11870 curtime = localtime(&seconds);
11871 /* MSVC returns NULL for an invalid value of seconds. */
11872 if (curtime == NULL)
11873 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11874 else
11875 {
11876# ifdef FEAT_MBYTE
11877 vimconv_T conv;
11878 char_u *enc;
11879
11880 conv.vc_type = CONV_NONE;
11881 enc = enc_locale();
11882 convert_setup(&conv, p_enc, enc);
11883 if (conv.vc_type != CONV_NONE)
11884 p = string_convert(&conv, p, NULL);
11885# endif
11886 if (p != NULL)
11887 (void)strftime((char *)result_buf, sizeof(result_buf),
11888 (char *)p, curtime);
11889 else
11890 result_buf[0] = NUL;
11891
11892# ifdef FEAT_MBYTE
11893 if (conv.vc_type != CONV_NONE)
11894 vim_free(p);
11895 convert_setup(&conv, enc, p_enc);
11896 if (conv.vc_type != CONV_NONE)
11897 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11898 else
11899# endif
11900 rettv->vval.v_string = vim_strsave(result_buf);
11901
11902# ifdef FEAT_MBYTE
11903 /* Release conversion descriptors */
11904 convert_setup(&conv, NULL, NULL);
11905 vim_free(enc);
11906# endif
11907 }
11908}
11909#endif
11910
11911/*
11912 * "strgetchar()" function
11913 */
11914 static void
11915f_strgetchar(typval_T *argvars, typval_T *rettv)
11916{
11917 char_u *str;
11918 int len;
11919 int error = FALSE;
11920 int charidx;
11921
11922 rettv->vval.v_number = -1;
11923 str = get_tv_string_chk(&argvars[0]);
11924 if (str == NULL)
11925 return;
11926 len = (int)STRLEN(str);
11927 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11928 if (error)
11929 return;
11930#ifdef FEAT_MBYTE
11931 {
11932 int byteidx = 0;
11933
11934 while (charidx >= 0 && byteidx < len)
11935 {
11936 if (charidx == 0)
11937 {
11938 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11939 break;
11940 }
11941 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011942 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011943 }
11944 }
11945#else
11946 if (charidx < len)
11947 rettv->vval.v_number = str[charidx];
11948#endif
11949}
11950
11951/*
11952 * "stridx()" function
11953 */
11954 static void
11955f_stridx(typval_T *argvars, typval_T *rettv)
11956{
11957 char_u buf[NUMBUFLEN];
11958 char_u *needle;
11959 char_u *haystack;
11960 char_u *save_haystack;
11961 char_u *pos;
11962 int start_idx;
11963
11964 needle = get_tv_string_chk(&argvars[1]);
11965 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11966 rettv->vval.v_number = -1;
11967 if (needle == NULL || haystack == NULL)
11968 return; /* type error; errmsg already given */
11969
11970 if (argvars[2].v_type != VAR_UNKNOWN)
11971 {
11972 int error = FALSE;
11973
11974 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11975 if (error || start_idx >= (int)STRLEN(haystack))
11976 return;
11977 if (start_idx >= 0)
11978 haystack += start_idx;
11979 }
11980
11981 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11982 if (pos != NULL)
11983 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11984}
11985
11986/*
11987 * "string()" function
11988 */
11989 static void
11990f_string(typval_T *argvars, typval_T *rettv)
11991{
11992 char_u *tofree;
11993 char_u numbuf[NUMBUFLEN];
11994
11995 rettv->v_type = VAR_STRING;
11996 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11997 get_copyID());
11998 /* Make a copy if we have a value but it's not in allocated memory. */
11999 if (rettv->vval.v_string != NULL && tofree == NULL)
12000 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12001}
12002
12003/*
12004 * "strlen()" function
12005 */
12006 static void
12007f_strlen(typval_T *argvars, typval_T *rettv)
12008{
12009 rettv->vval.v_number = (varnumber_T)(STRLEN(
12010 get_tv_string(&argvars[0])));
12011}
12012
12013/*
12014 * "strchars()" function
12015 */
12016 static void
12017f_strchars(typval_T *argvars, typval_T *rettv)
12018{
12019 char_u *s = get_tv_string(&argvars[0]);
12020 int skipcc = 0;
12021#ifdef FEAT_MBYTE
12022 varnumber_T len = 0;
12023 int (*func_mb_ptr2char_adv)(char_u **pp);
12024#endif
12025
12026 if (argvars[1].v_type != VAR_UNKNOWN)
12027 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
12028 if (skipcc < 0 || skipcc > 1)
12029 EMSG(_(e_invarg));
12030 else
12031 {
12032#ifdef FEAT_MBYTE
12033 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12034 while (*s != NUL)
12035 {
12036 func_mb_ptr2char_adv(&s);
12037 ++len;
12038 }
12039 rettv->vval.v_number = len;
12040#else
12041 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12042#endif
12043 }
12044}
12045
12046/*
12047 * "strdisplaywidth()" function
12048 */
12049 static void
12050f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12051{
12052 char_u *s = get_tv_string(&argvars[0]);
12053 int col = 0;
12054
12055 if (argvars[1].v_type != VAR_UNKNOWN)
12056 col = (int)get_tv_number(&argvars[1]);
12057
12058 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12059}
12060
12061/*
12062 * "strwidth()" function
12063 */
12064 static void
12065f_strwidth(typval_T *argvars, typval_T *rettv)
12066{
12067 char_u *s = get_tv_string(&argvars[0]);
12068
12069 rettv->vval.v_number = (varnumber_T)(
12070#ifdef FEAT_MBYTE
12071 mb_string2cells(s, -1)
12072#else
12073 STRLEN(s)
12074#endif
12075 );
12076}
12077
12078/*
12079 * "strcharpart()" function
12080 */
12081 static void
12082f_strcharpart(typval_T *argvars, typval_T *rettv)
12083{
12084#ifdef FEAT_MBYTE
12085 char_u *p;
12086 int nchar;
12087 int nbyte = 0;
12088 int charlen;
12089 int len = 0;
12090 int slen;
12091 int error = FALSE;
12092
12093 p = get_tv_string(&argvars[0]);
12094 slen = (int)STRLEN(p);
12095
12096 nchar = (int)get_tv_number_chk(&argvars[1], &error);
12097 if (!error)
12098 {
12099 if (nchar > 0)
12100 while (nchar > 0 && nbyte < slen)
12101 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012102 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012103 --nchar;
12104 }
12105 else
12106 nbyte = nchar;
12107 if (argvars[2].v_type != VAR_UNKNOWN)
12108 {
12109 charlen = (int)get_tv_number(&argvars[2]);
12110 while (charlen > 0 && nbyte + len < slen)
12111 {
12112 int off = nbyte + len;
12113
12114 if (off < 0)
12115 len += 1;
12116 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012117 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012118 --charlen;
12119 }
12120 }
12121 else
12122 len = slen - nbyte; /* default: all bytes that are available. */
12123 }
12124
12125 /*
12126 * Only return the overlap between the specified part and the actual
12127 * string.
12128 */
12129 if (nbyte < 0)
12130 {
12131 len += nbyte;
12132 nbyte = 0;
12133 }
12134 else if (nbyte > slen)
12135 nbyte = slen;
12136 if (len < 0)
12137 len = 0;
12138 else if (nbyte + len > slen)
12139 len = slen - nbyte;
12140
12141 rettv->v_type = VAR_STRING;
12142 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12143#else
12144 f_strpart(argvars, rettv);
12145#endif
12146}
12147
12148/*
12149 * "strpart()" function
12150 */
12151 static void
12152f_strpart(typval_T *argvars, typval_T *rettv)
12153{
12154 char_u *p;
12155 int n;
12156 int len;
12157 int slen;
12158 int error = FALSE;
12159
12160 p = get_tv_string(&argvars[0]);
12161 slen = (int)STRLEN(p);
12162
12163 n = (int)get_tv_number_chk(&argvars[1], &error);
12164 if (error)
12165 len = 0;
12166 else if (argvars[2].v_type != VAR_UNKNOWN)
12167 len = (int)get_tv_number(&argvars[2]);
12168 else
12169 len = slen - n; /* default len: all bytes that are available. */
12170
12171 /*
12172 * Only return the overlap between the specified part and the actual
12173 * string.
12174 */
12175 if (n < 0)
12176 {
12177 len += n;
12178 n = 0;
12179 }
12180 else if (n > slen)
12181 n = slen;
12182 if (len < 0)
12183 len = 0;
12184 else if (n + len > slen)
12185 len = slen - n;
12186
12187 rettv->v_type = VAR_STRING;
12188 rettv->vval.v_string = vim_strnsave(p + n, len);
12189}
12190
12191/*
12192 * "strridx()" function
12193 */
12194 static void
12195f_strridx(typval_T *argvars, typval_T *rettv)
12196{
12197 char_u buf[NUMBUFLEN];
12198 char_u *needle;
12199 char_u *haystack;
12200 char_u *rest;
12201 char_u *lastmatch = NULL;
12202 int haystack_len, end_idx;
12203
12204 needle = get_tv_string_chk(&argvars[1]);
12205 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12206
12207 rettv->vval.v_number = -1;
12208 if (needle == NULL || haystack == NULL)
12209 return; /* type error; errmsg already given */
12210
12211 haystack_len = (int)STRLEN(haystack);
12212 if (argvars[2].v_type != VAR_UNKNOWN)
12213 {
12214 /* Third argument: upper limit for index */
12215 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12216 if (end_idx < 0)
12217 return; /* can never find a match */
12218 }
12219 else
12220 end_idx = haystack_len;
12221
12222 if (*needle == NUL)
12223 {
12224 /* Empty string matches past the end. */
12225 lastmatch = haystack + end_idx;
12226 }
12227 else
12228 {
12229 for (rest = haystack; *rest != '\0'; ++rest)
12230 {
12231 rest = (char_u *)strstr((char *)rest, (char *)needle);
12232 if (rest == NULL || rest > haystack + end_idx)
12233 break;
12234 lastmatch = rest;
12235 }
12236 }
12237
12238 if (lastmatch == NULL)
12239 rettv->vval.v_number = -1;
12240 else
12241 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12242}
12243
12244/*
12245 * "strtrans()" function
12246 */
12247 static void
12248f_strtrans(typval_T *argvars, typval_T *rettv)
12249{
12250 rettv->v_type = VAR_STRING;
12251 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12252}
12253
12254/*
12255 * "submatch()" function
12256 */
12257 static void
12258f_submatch(typval_T *argvars, typval_T *rettv)
12259{
12260 int error = FALSE;
12261 int no;
12262 int retList = 0;
12263
12264 no = (int)get_tv_number_chk(&argvars[0], &error);
12265 if (error)
12266 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012267 if (no < 0 || no >= NSUBEXP)
12268 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012269 EMSGN(_("E935: invalid submatch number: %d"), no);
12270 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012271 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012272 if (argvars[1].v_type != VAR_UNKNOWN)
12273 retList = (int)get_tv_number_chk(&argvars[1], &error);
12274 if (error)
12275 return;
12276
12277 if (retList == 0)
12278 {
12279 rettv->v_type = VAR_STRING;
12280 rettv->vval.v_string = reg_submatch(no);
12281 }
12282 else
12283 {
12284 rettv->v_type = VAR_LIST;
12285 rettv->vval.v_list = reg_submatch_list(no);
12286 }
12287}
12288
12289/*
12290 * "substitute()" function
12291 */
12292 static void
12293f_substitute(typval_T *argvars, typval_T *rettv)
12294{
12295 char_u patbuf[NUMBUFLEN];
12296 char_u subbuf[NUMBUFLEN];
12297 char_u flagsbuf[NUMBUFLEN];
12298
12299 char_u *str = get_tv_string_chk(&argvars[0]);
12300 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012301 char_u *sub = NULL;
12302 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012303 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12304
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012305 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12306 expr = &argvars[2];
12307 else
12308 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12309
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012310 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012311 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12312 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012313 rettv->vval.v_string = NULL;
12314 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012315 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012316}
12317
12318/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012319 * "swapinfo(swap_filename)" function
12320 */
12321 static void
12322f_swapinfo(typval_T *argvars, typval_T *rettv)
12323{
12324 if (rettv_dict_alloc(rettv) == OK)
12325 get_b0_dict(get_tv_string(argvars), rettv->vval.v_dict);
12326}
12327
12328/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012329 * "synID(lnum, col, trans)" function
12330 */
12331 static void
12332f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12333{
12334 int id = 0;
12335#ifdef FEAT_SYN_HL
12336 linenr_T lnum;
12337 colnr_T col;
12338 int trans;
12339 int transerr = FALSE;
12340
12341 lnum = get_tv_lnum(argvars); /* -1 on type error */
12342 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12343 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12344
12345 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12346 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12347 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12348#endif
12349
12350 rettv->vval.v_number = id;
12351}
12352
12353/*
12354 * "synIDattr(id, what [, mode])" function
12355 */
12356 static void
12357f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12358{
12359 char_u *p = NULL;
12360#ifdef FEAT_SYN_HL
12361 int id;
12362 char_u *what;
12363 char_u *mode;
12364 char_u modebuf[NUMBUFLEN];
12365 int modec;
12366
12367 id = (int)get_tv_number(&argvars[0]);
12368 what = get_tv_string(&argvars[1]);
12369 if (argvars[2].v_type != VAR_UNKNOWN)
12370 {
12371 mode = get_tv_string_buf(&argvars[2], modebuf);
12372 modec = TOLOWER_ASC(mode[0]);
12373 if (modec != 't' && modec != 'c' && modec != 'g')
12374 modec = 0; /* replace invalid with current */
12375 }
12376 else
12377 {
12378#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12379 if (USE_24BIT)
12380 modec = 'g';
12381 else
12382#endif
12383 if (t_colors > 1)
12384 modec = 'c';
12385 else
12386 modec = 't';
12387 }
12388
12389
12390 switch (TOLOWER_ASC(what[0]))
12391 {
12392 case 'b':
12393 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12394 p = highlight_color(id, what, modec);
12395 else /* bold */
12396 p = highlight_has_attr(id, HL_BOLD, modec);
12397 break;
12398
12399 case 'f': /* fg[#] or font */
12400 p = highlight_color(id, what, modec);
12401 break;
12402
12403 case 'i':
12404 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12405 p = highlight_has_attr(id, HL_INVERSE, modec);
12406 else /* italic */
12407 p = highlight_has_attr(id, HL_ITALIC, modec);
12408 break;
12409
12410 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012411 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012412 break;
12413
12414 case 'r': /* reverse */
12415 p = highlight_has_attr(id, HL_INVERSE, modec);
12416 break;
12417
12418 case 's':
12419 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12420 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012421 /* strikeout */
12422 else if (TOLOWER_ASC(what[1]) == 't' &&
12423 TOLOWER_ASC(what[2]) == 'r')
12424 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012425 else /* standout */
12426 p = highlight_has_attr(id, HL_STANDOUT, modec);
12427 break;
12428
12429 case 'u':
12430 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12431 /* underline */
12432 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12433 else
12434 /* undercurl */
12435 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12436 break;
12437 }
12438
12439 if (p != NULL)
12440 p = vim_strsave(p);
12441#endif
12442 rettv->v_type = VAR_STRING;
12443 rettv->vval.v_string = p;
12444}
12445
12446/*
12447 * "synIDtrans(id)" function
12448 */
12449 static void
12450f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12451{
12452 int id;
12453
12454#ifdef FEAT_SYN_HL
12455 id = (int)get_tv_number(&argvars[0]);
12456
12457 if (id > 0)
12458 id = syn_get_final_id(id);
12459 else
12460#endif
12461 id = 0;
12462
12463 rettv->vval.v_number = id;
12464}
12465
12466/*
12467 * "synconcealed(lnum, col)" function
12468 */
12469 static void
12470f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12471{
12472#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12473 linenr_T lnum;
12474 colnr_T col;
12475 int syntax_flags = 0;
12476 int cchar;
12477 int matchid = 0;
12478 char_u str[NUMBUFLEN];
12479#endif
12480
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012481 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012482
12483#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12484 lnum = get_tv_lnum(argvars); /* -1 on type error */
12485 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12486
12487 vim_memset(str, NUL, sizeof(str));
12488
12489 if (rettv_list_alloc(rettv) != FAIL)
12490 {
12491 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12492 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12493 && curwin->w_p_cole > 0)
12494 {
12495 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12496 syntax_flags = get_syntax_info(&matchid);
12497
12498 /* get the conceal character */
12499 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12500 {
12501 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012502 if (cchar == NUL && curwin->w_p_cole == 1)
12503 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012504 if (cchar != NUL)
12505 {
12506# ifdef FEAT_MBYTE
12507 if (has_mbyte)
12508 (*mb_char2bytes)(cchar, str);
12509 else
12510# endif
12511 str[0] = cchar;
12512 }
12513 }
12514 }
12515
12516 list_append_number(rettv->vval.v_list,
12517 (syntax_flags & HL_CONCEAL) != 0);
12518 /* -1 to auto-determine strlen */
12519 list_append_string(rettv->vval.v_list, str, -1);
12520 list_append_number(rettv->vval.v_list, matchid);
12521 }
12522#endif
12523}
12524
12525/*
12526 * "synstack(lnum, col)" function
12527 */
12528 static void
12529f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12530{
12531#ifdef FEAT_SYN_HL
12532 linenr_T lnum;
12533 colnr_T col;
12534 int i;
12535 int id;
12536#endif
12537
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012538 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012539
12540#ifdef FEAT_SYN_HL
12541 lnum = get_tv_lnum(argvars); /* -1 on type error */
12542 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12543
12544 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12545 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12546 && rettv_list_alloc(rettv) != FAIL)
12547 {
12548 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12549 for (i = 0; ; ++i)
12550 {
12551 id = syn_get_stack_item(i);
12552 if (id < 0)
12553 break;
12554 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12555 break;
12556 }
12557 }
12558#endif
12559}
12560
12561 static void
12562get_cmd_output_as_rettv(
12563 typval_T *argvars,
12564 typval_T *rettv,
12565 int retlist)
12566{
12567 char_u *res = NULL;
12568 char_u *p;
12569 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012570 int err = FALSE;
12571 FILE *fd;
12572 list_T *list = NULL;
12573 int flags = SHELL_SILENT;
12574
12575 rettv->v_type = VAR_STRING;
12576 rettv->vval.v_string = NULL;
12577 if (check_restricted() || check_secure())
12578 goto errret;
12579
12580 if (argvars[1].v_type != VAR_UNKNOWN)
12581 {
12582 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012583 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012584 * command.
12585 */
12586 if ((infile = vim_tempname('i', TRUE)) == NULL)
12587 {
12588 EMSG(_(e_notmp));
12589 goto errret;
12590 }
12591
12592 fd = mch_fopen((char *)infile, WRITEBIN);
12593 if (fd == NULL)
12594 {
12595 EMSG2(_(e_notopen), infile);
12596 goto errret;
12597 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012598 if (argvars[1].v_type == VAR_NUMBER)
12599 {
12600 linenr_T lnum;
12601 buf_T *buf;
12602
12603 buf = buflist_findnr(argvars[1].vval.v_number);
12604 if (buf == NULL)
12605 {
12606 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012607 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012608 goto errret;
12609 }
12610
12611 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12612 {
12613 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12614 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12615 {
12616 err = TRUE;
12617 break;
12618 }
12619 if (putc(NL, fd) == EOF)
12620 {
12621 err = TRUE;
12622 break;
12623 }
12624 }
12625 }
12626 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012627 {
12628 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12629 err = TRUE;
12630 }
12631 else
12632 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012633 size_t len;
12634 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012635
12636 p = get_tv_string_buf_chk(&argvars[1], buf);
12637 if (p == NULL)
12638 {
12639 fclose(fd);
12640 goto errret; /* type error; errmsg already given */
12641 }
12642 len = STRLEN(p);
12643 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12644 err = TRUE;
12645 }
12646 if (fclose(fd) != 0)
12647 err = TRUE;
12648 if (err)
12649 {
12650 EMSG(_("E677: Error writing temp file"));
12651 goto errret;
12652 }
12653 }
12654
12655 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12656 * echoes typeahead, that messes up the display. */
12657 if (!msg_silent)
12658 flags += SHELL_COOKED;
12659
12660 if (retlist)
12661 {
12662 int len;
12663 listitem_T *li;
12664 char_u *s = NULL;
12665 char_u *start;
12666 char_u *end;
12667 int i;
12668
12669 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12670 if (res == NULL)
12671 goto errret;
12672
12673 list = list_alloc();
12674 if (list == NULL)
12675 goto errret;
12676
12677 for (i = 0; i < len; ++i)
12678 {
12679 start = res + i;
12680 while (i < len && res[i] != NL)
12681 ++i;
12682 end = res + i;
12683
12684 s = alloc((unsigned)(end - start + 1));
12685 if (s == NULL)
12686 goto errret;
12687
12688 for (p = s; start < end; ++p, ++start)
12689 *p = *start == NUL ? NL : *start;
12690 *p = NUL;
12691
12692 li = listitem_alloc();
12693 if (li == NULL)
12694 {
12695 vim_free(s);
12696 goto errret;
12697 }
12698 li->li_tv.v_type = VAR_STRING;
12699 li->li_tv.v_lock = 0;
12700 li->li_tv.vval.v_string = s;
12701 list_append(list, li);
12702 }
12703
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012704 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012705 list = NULL;
12706 }
12707 else
12708 {
12709 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12710#ifdef USE_CR
12711 /* translate <CR> into <NL> */
12712 if (res != NULL)
12713 {
12714 char_u *s;
12715
12716 for (s = res; *s; ++s)
12717 {
12718 if (*s == CAR)
12719 *s = NL;
12720 }
12721 }
12722#else
12723# ifdef USE_CRNL
12724 /* translate <CR><NL> into <NL> */
12725 if (res != NULL)
12726 {
12727 char_u *s, *d;
12728
12729 d = res;
12730 for (s = res; *s; ++s)
12731 {
12732 if (s[0] == CAR && s[1] == NL)
12733 ++s;
12734 *d++ = *s;
12735 }
12736 *d = NUL;
12737 }
12738# endif
12739#endif
12740 rettv->vval.v_string = res;
12741 res = NULL;
12742 }
12743
12744errret:
12745 if (infile != NULL)
12746 {
12747 mch_remove(infile);
12748 vim_free(infile);
12749 }
12750 if (res != NULL)
12751 vim_free(res);
12752 if (list != NULL)
12753 list_free(list);
12754}
12755
12756/*
12757 * "system()" function
12758 */
12759 static void
12760f_system(typval_T *argvars, typval_T *rettv)
12761{
12762 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12763}
12764
12765/*
12766 * "systemlist()" function
12767 */
12768 static void
12769f_systemlist(typval_T *argvars, typval_T *rettv)
12770{
12771 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12772}
12773
12774/*
12775 * "tabpagebuflist()" function
12776 */
12777 static void
12778f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12779{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012780 tabpage_T *tp;
12781 win_T *wp = NULL;
12782
12783 if (argvars[0].v_type == VAR_UNKNOWN)
12784 wp = firstwin;
12785 else
12786 {
12787 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12788 if (tp != NULL)
12789 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12790 }
12791 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12792 {
12793 for (; wp != NULL; wp = wp->w_next)
12794 if (list_append_number(rettv->vval.v_list,
12795 wp->w_buffer->b_fnum) == FAIL)
12796 break;
12797 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012798}
12799
12800
12801/*
12802 * "tabpagenr()" function
12803 */
12804 static void
12805f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12806{
12807 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012808 char_u *arg;
12809
12810 if (argvars[0].v_type != VAR_UNKNOWN)
12811 {
12812 arg = get_tv_string_chk(&argvars[0]);
12813 nr = 0;
12814 if (arg != NULL)
12815 {
12816 if (STRCMP(arg, "$") == 0)
12817 nr = tabpage_index(NULL) - 1;
12818 else
12819 EMSG2(_(e_invexpr2), arg);
12820 }
12821 }
12822 else
12823 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012824 rettv->vval.v_number = nr;
12825}
12826
12827
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012828static int get_winnr(tabpage_T *tp, typval_T *argvar);
12829
12830/*
12831 * Common code for tabpagewinnr() and winnr().
12832 */
12833 static int
12834get_winnr(tabpage_T *tp, typval_T *argvar)
12835{
12836 win_T *twin;
12837 int nr = 1;
12838 win_T *wp;
12839 char_u *arg;
12840
12841 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12842 if (argvar->v_type != VAR_UNKNOWN)
12843 {
12844 arg = get_tv_string_chk(argvar);
12845 if (arg == NULL)
12846 nr = 0; /* type error; errmsg already given */
12847 else if (STRCMP(arg, "$") == 0)
12848 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12849 else if (STRCMP(arg, "#") == 0)
12850 {
12851 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12852 if (twin == NULL)
12853 nr = 0;
12854 }
12855 else
12856 {
12857 EMSG2(_(e_invexpr2), arg);
12858 nr = 0;
12859 }
12860 }
12861
12862 if (nr > 0)
12863 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12864 wp != twin; wp = wp->w_next)
12865 {
12866 if (wp == NULL)
12867 {
12868 /* didn't find it in this tabpage */
12869 nr = 0;
12870 break;
12871 }
12872 ++nr;
12873 }
12874 return nr;
12875}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012876
12877/*
12878 * "tabpagewinnr()" function
12879 */
12880 static void
12881f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12882{
12883 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012884 tabpage_T *tp;
12885
12886 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12887 if (tp == NULL)
12888 nr = 0;
12889 else
12890 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012891 rettv->vval.v_number = nr;
12892}
12893
12894
12895/*
12896 * "tagfiles()" function
12897 */
12898 static void
12899f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12900{
12901 char_u *fname;
12902 tagname_T tn;
12903 int first;
12904
12905 if (rettv_list_alloc(rettv) == FAIL)
12906 return;
12907 fname = alloc(MAXPATHL);
12908 if (fname == NULL)
12909 return;
12910
12911 for (first = TRUE; ; first = FALSE)
12912 if (get_tagfname(&tn, first, fname) == FAIL
12913 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12914 break;
12915 tagname_free(&tn);
12916 vim_free(fname);
12917}
12918
12919/*
12920 * "taglist()" function
12921 */
12922 static void
12923f_taglist(typval_T *argvars, typval_T *rettv)
12924{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012925 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012926 char_u *tag_pattern;
12927
12928 tag_pattern = get_tv_string(&argvars[0]);
12929
12930 rettv->vval.v_number = FALSE;
12931 if (*tag_pattern == NUL)
12932 return;
12933
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012934 if (argvars[1].v_type != VAR_UNKNOWN)
12935 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012936 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012937 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012938}
12939
12940/*
12941 * "tempname()" function
12942 */
12943 static void
12944f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12945{
12946 static int x = 'A';
12947
12948 rettv->v_type = VAR_STRING;
12949 rettv->vval.v_string = vim_tempname(x, FALSE);
12950
12951 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12952 * names. Skip 'I' and 'O', they are used for shell redirection. */
12953 do
12954 {
12955 if (x == 'Z')
12956 x = '0';
12957 else if (x == '9')
12958 x = 'A';
12959 else
12960 {
12961#ifdef EBCDIC
12962 if (x == 'I')
12963 x = 'J';
12964 else if (x == 'R')
12965 x = 'S';
12966 else
12967#endif
12968 ++x;
12969 }
12970 } while (x == 'I' || x == 'O');
12971}
12972
12973#ifdef FEAT_FLOAT
12974/*
12975 * "tan()" function
12976 */
12977 static void
12978f_tan(typval_T *argvars, typval_T *rettv)
12979{
12980 float_T f = 0.0;
12981
12982 rettv->v_type = VAR_FLOAT;
12983 if (get_float_arg(argvars, &f) == OK)
12984 rettv->vval.v_float = tan(f);
12985 else
12986 rettv->vval.v_float = 0.0;
12987}
12988
12989/*
12990 * "tanh()" function
12991 */
12992 static void
12993f_tanh(typval_T *argvars, typval_T *rettv)
12994{
12995 float_T f = 0.0;
12996
12997 rettv->v_type = VAR_FLOAT;
12998 if (get_float_arg(argvars, &f) == OK)
12999 rettv->vval.v_float = tanh(f);
13000 else
13001 rettv->vval.v_float = 0.0;
13002}
13003#endif
13004
13005/*
13006 * "test_alloc_fail(id, countdown, repeat)" function
13007 */
13008 static void
13009f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13010{
13011 if (argvars[0].v_type != VAR_NUMBER
13012 || argvars[0].vval.v_number <= 0
13013 || argvars[1].v_type != VAR_NUMBER
13014 || argvars[1].vval.v_number < 0
13015 || argvars[2].v_type != VAR_NUMBER)
13016 EMSG(_(e_invarg));
13017 else
13018 {
13019 alloc_fail_id = argvars[0].vval.v_number;
13020 if (alloc_fail_id >= aid_last)
13021 EMSG(_(e_invarg));
13022 alloc_fail_countdown = argvars[1].vval.v_number;
13023 alloc_fail_repeat = argvars[2].vval.v_number;
13024 did_outofmem_msg = FALSE;
13025 }
13026}
13027
13028/*
13029 * "test_autochdir()"
13030 */
13031 static void
13032f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13033{
13034#if defined(FEAT_AUTOCHDIR)
13035 test_autochdir = TRUE;
13036#endif
13037}
13038
13039/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013040 * "test_feedinput()"
13041 */
13042 static void
13043f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13044{
13045#ifdef USE_INPUT_BUF
13046 char_u *val = get_tv_string_chk(&argvars[0]);
13047
13048 if (val != NULL)
13049 {
13050 trash_input_buf();
13051 add_to_input_buf_csi(val, (int)STRLEN(val));
13052 }
13053#endif
13054}
13055
13056/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013057 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013058 */
13059 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013060f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013061{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013062 char_u *name = (char_u *)"";
13063 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013064 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013065
13066 if (argvars[0].v_type != VAR_STRING
13067 || (argvars[1].v_type) != VAR_NUMBER)
13068 EMSG(_(e_invarg));
13069 else
13070 {
13071 name = get_tv_string_chk(&argvars[0]);
13072 val = (int)get_tv_number(&argvars[1]);
13073
13074 if (STRCMP(name, (char_u *)"redraw") == 0)
13075 disable_redraw_for_testing = val;
13076 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13077 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013078 else if (STRCMP(name, (char_u *)"starting") == 0)
13079 {
13080 if (val)
13081 {
13082 if (save_starting < 0)
13083 save_starting = starting;
13084 starting = 0;
13085 }
13086 else
13087 {
13088 starting = save_starting;
13089 save_starting = -1;
13090 }
13091 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013092 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13093 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013094 else if (STRCMP(name, (char_u *)"ALL") == 0)
13095 {
13096 disable_char_avail_for_testing = FALSE;
13097 disable_redraw_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013098 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013099 if (save_starting >= 0)
13100 {
13101 starting = save_starting;
13102 save_starting = -1;
13103 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013104 }
13105 else
13106 EMSG2(_(e_invarg2), name);
13107 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013108}
13109
13110/*
13111 * "test_garbagecollect_now()" function
13112 */
13113 static void
13114f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13115{
13116 /* This is dangerous, any Lists and Dicts used internally may be freed
13117 * while still in use. */
13118 garbage_collect(TRUE);
13119}
13120
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013121/*
13122 * "test_ignore_error()" function
13123 */
13124 static void
13125f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13126{
13127 ignore_error_for_testing(get_tv_string(&argvars[0]));
13128}
13129
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013130#ifdef FEAT_JOB_CHANNEL
13131 static void
13132f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13133{
13134 rettv->v_type = VAR_CHANNEL;
13135 rettv->vval.v_channel = NULL;
13136}
13137#endif
13138
13139 static void
13140f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13141{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013142 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013143}
13144
13145#ifdef FEAT_JOB_CHANNEL
13146 static void
13147f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13148{
13149 rettv->v_type = VAR_JOB;
13150 rettv->vval.v_job = NULL;
13151}
13152#endif
13153
13154 static void
13155f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13156{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013157 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013158}
13159
13160 static void
13161f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13162{
13163 rettv->v_type = VAR_PARTIAL;
13164 rettv->vval.v_partial = NULL;
13165}
13166
13167 static void
13168f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13169{
13170 rettv->v_type = VAR_STRING;
13171 rettv->vval.v_string = NULL;
13172}
13173
13174 static void
13175f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13176{
13177 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13178}
13179
13180#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13181/*
13182 * Get a callback from "arg". It can be a Funcref or a function name.
13183 * When "arg" is zero return an empty string.
13184 * Return NULL for an invalid argument.
13185 */
13186 char_u *
13187get_callback(typval_T *arg, partial_T **pp)
13188{
13189 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13190 {
13191 *pp = arg->vval.v_partial;
13192 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013193 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013194 }
13195 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013196 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013197 {
13198 func_ref(arg->vval.v_string);
13199 return arg->vval.v_string;
13200 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013201 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13202 return (char_u *)"";
13203 EMSG(_("E921: Invalid callback argument"));
13204 return NULL;
13205}
13206
13207/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013208 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013209 */
13210 void
13211free_callback(char_u *callback, partial_T *partial)
13212{
13213 if (partial != NULL)
13214 partial_unref(partial);
13215 else if (callback != NULL)
13216 {
13217 func_unref(callback);
13218 vim_free(callback);
13219 }
13220}
13221#endif
13222
13223#ifdef FEAT_TIMERS
13224/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013225 * "timer_info([timer])" function
13226 */
13227 static void
13228f_timer_info(typval_T *argvars, typval_T *rettv)
13229{
13230 timer_T *timer = NULL;
13231
13232 if (rettv_list_alloc(rettv) != OK)
13233 return;
13234 if (argvars[0].v_type != VAR_UNKNOWN)
13235 {
13236 if (argvars[0].v_type != VAR_NUMBER)
13237 EMSG(_(e_number_exp));
13238 else
13239 {
13240 timer = find_timer((int)get_tv_number(&argvars[0]));
13241 if (timer != NULL)
13242 add_timer_info(rettv, timer);
13243 }
13244 }
13245 else
13246 add_timer_info_all(rettv);
13247}
13248
13249/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013250 * "timer_pause(timer, paused)" function
13251 */
13252 static void
13253f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13254{
13255 timer_T *timer = NULL;
13256 int paused = (int)get_tv_number(&argvars[1]);
13257
13258 if (argvars[0].v_type != VAR_NUMBER)
13259 EMSG(_(e_number_exp));
13260 else
13261 {
13262 timer = find_timer((int)get_tv_number(&argvars[0]));
13263 if (timer != NULL)
13264 timer->tr_paused = paused;
13265 }
13266}
13267
13268/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013269 * "timer_start(time, callback [, options])" function
13270 */
13271 static void
13272f_timer_start(typval_T *argvars, typval_T *rettv)
13273{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013274 long msec = (long)get_tv_number(&argvars[0]);
13275 timer_T *timer;
13276 int repeat = 0;
13277 char_u *callback;
13278 dict_T *dict;
13279 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013280
Bram Moolenaar75537a92016-09-05 22:45:28 +020013281 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013282 if (check_secure())
13283 return;
13284 if (argvars[2].v_type != VAR_UNKNOWN)
13285 {
13286 if (argvars[2].v_type != VAR_DICT
13287 || (dict = argvars[2].vval.v_dict) == NULL)
13288 {
13289 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13290 return;
13291 }
13292 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13293 repeat = get_dict_number(dict, (char_u *)"repeat");
13294 }
13295
Bram Moolenaar75537a92016-09-05 22:45:28 +020013296 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013297 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013298 return;
13299
13300 timer = create_timer(msec, repeat);
13301 if (timer == NULL)
13302 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013303 else
13304 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013305 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013306 timer->tr_callback = vim_strsave(callback);
13307 else
13308 /* pointer into the partial */
13309 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013310 timer->tr_partial = partial;
13311 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013312 }
13313}
13314
13315/*
13316 * "timer_stop(timer)" function
13317 */
13318 static void
13319f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13320{
13321 timer_T *timer;
13322
13323 if (argvars[0].v_type != VAR_NUMBER)
13324 {
13325 EMSG(_(e_number_exp));
13326 return;
13327 }
13328 timer = find_timer((int)get_tv_number(&argvars[0]));
13329 if (timer != NULL)
13330 stop_timer(timer);
13331}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013332
13333/*
13334 * "timer_stopall()" function
13335 */
13336 static void
13337f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13338{
13339 stop_all_timers();
13340}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013341#endif
13342
13343/*
13344 * "tolower(string)" function
13345 */
13346 static void
13347f_tolower(typval_T *argvars, typval_T *rettv)
13348{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013349 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013350 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013351}
13352
13353/*
13354 * "toupper(string)" function
13355 */
13356 static void
13357f_toupper(typval_T *argvars, typval_T *rettv)
13358{
13359 rettv->v_type = VAR_STRING;
13360 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13361}
13362
13363/*
13364 * "tr(string, fromstr, tostr)" function
13365 */
13366 static void
13367f_tr(typval_T *argvars, typval_T *rettv)
13368{
13369 char_u *in_str;
13370 char_u *fromstr;
13371 char_u *tostr;
13372 char_u *p;
13373#ifdef FEAT_MBYTE
13374 int inlen;
13375 int fromlen;
13376 int tolen;
13377 int idx;
13378 char_u *cpstr;
13379 int cplen;
13380 int first = TRUE;
13381#endif
13382 char_u buf[NUMBUFLEN];
13383 char_u buf2[NUMBUFLEN];
13384 garray_T ga;
13385
13386 in_str = get_tv_string(&argvars[0]);
13387 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13388 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13389
13390 /* Default return value: empty string. */
13391 rettv->v_type = VAR_STRING;
13392 rettv->vval.v_string = NULL;
13393 if (fromstr == NULL || tostr == NULL)
13394 return; /* type error; errmsg already given */
13395 ga_init2(&ga, (int)sizeof(char), 80);
13396
13397#ifdef FEAT_MBYTE
13398 if (!has_mbyte)
13399#endif
13400 /* not multi-byte: fromstr and tostr must be the same length */
13401 if (STRLEN(fromstr) != STRLEN(tostr))
13402 {
13403#ifdef FEAT_MBYTE
13404error:
13405#endif
13406 EMSG2(_(e_invarg2), fromstr);
13407 ga_clear(&ga);
13408 return;
13409 }
13410
13411 /* fromstr and tostr have to contain the same number of chars */
13412 while (*in_str != NUL)
13413 {
13414#ifdef FEAT_MBYTE
13415 if (has_mbyte)
13416 {
13417 inlen = (*mb_ptr2len)(in_str);
13418 cpstr = in_str;
13419 cplen = inlen;
13420 idx = 0;
13421 for (p = fromstr; *p != NUL; p += fromlen)
13422 {
13423 fromlen = (*mb_ptr2len)(p);
13424 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13425 {
13426 for (p = tostr; *p != NUL; p += tolen)
13427 {
13428 tolen = (*mb_ptr2len)(p);
13429 if (idx-- == 0)
13430 {
13431 cplen = tolen;
13432 cpstr = p;
13433 break;
13434 }
13435 }
13436 if (*p == NUL) /* tostr is shorter than fromstr */
13437 goto error;
13438 break;
13439 }
13440 ++idx;
13441 }
13442
13443 if (first && cpstr == in_str)
13444 {
13445 /* Check that fromstr and tostr have the same number of
13446 * (multi-byte) characters. Done only once when a character
13447 * of in_str doesn't appear in fromstr. */
13448 first = FALSE;
13449 for (p = tostr; *p != NUL; p += tolen)
13450 {
13451 tolen = (*mb_ptr2len)(p);
13452 --idx;
13453 }
13454 if (idx != 0)
13455 goto error;
13456 }
13457
13458 (void)ga_grow(&ga, cplen);
13459 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13460 ga.ga_len += cplen;
13461
13462 in_str += inlen;
13463 }
13464 else
13465#endif
13466 {
13467 /* When not using multi-byte chars we can do it faster. */
13468 p = vim_strchr(fromstr, *in_str);
13469 if (p != NULL)
13470 ga_append(&ga, tostr[p - fromstr]);
13471 else
13472 ga_append(&ga, *in_str);
13473 ++in_str;
13474 }
13475 }
13476
13477 /* add a terminating NUL */
13478 (void)ga_grow(&ga, 1);
13479 ga_append(&ga, NUL);
13480
13481 rettv->vval.v_string = ga.ga_data;
13482}
13483
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013484/*
13485 * "trim({expr})" function
13486 */
13487 static void
13488f_trim(typval_T *argvars, typval_T *rettv)
13489{
13490 char_u buf1[NUMBUFLEN];
13491 char_u buf2[NUMBUFLEN];
13492 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13493 char_u *mask = NULL;
13494 char_u *tail;
13495 char_u *prev;
13496 char_u *p;
13497 int c1;
13498
13499 rettv->v_type = VAR_STRING;
13500 if (head == NULL)
13501 {
13502 rettv->vval.v_string = NULL;
13503 return;
13504 }
13505
13506 if (argvars[1].v_type == VAR_STRING)
13507 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13508
13509 while (*head != NUL)
13510 {
13511 c1 = PTR2CHAR(head);
13512 if (mask == NULL)
13513 {
13514 if (c1 > ' ' && c1 != 0xa0)
13515 break;
13516 }
13517 else
13518 {
13519 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13520 if (c1 == PTR2CHAR(p))
13521 break;
13522 if (*p == NUL)
13523 break;
13524 }
13525 MB_PTR_ADV(head);
13526 }
13527
13528 for (tail = head + STRLEN(head); tail > head; tail = prev)
13529 {
13530 prev = tail;
13531 MB_PTR_BACK(head, prev);
13532 c1 = PTR2CHAR(prev);
13533 if (mask == NULL)
13534 {
13535 if (c1 > ' ' && c1 != 0xa0)
13536 break;
13537 }
13538 else
13539 {
13540 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13541 if (c1 == PTR2CHAR(p))
13542 break;
13543 if (*p == NUL)
13544 break;
13545 }
13546 }
13547 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13548}
13549
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013550#ifdef FEAT_FLOAT
13551/*
13552 * "trunc({float})" function
13553 */
13554 static void
13555f_trunc(typval_T *argvars, typval_T *rettv)
13556{
13557 float_T f = 0.0;
13558
13559 rettv->v_type = VAR_FLOAT;
13560 if (get_float_arg(argvars, &f) == OK)
13561 /* trunc() is not in C90, use floor() or ceil() instead. */
13562 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13563 else
13564 rettv->vval.v_float = 0.0;
13565}
13566#endif
13567
13568/*
13569 * "type(expr)" function
13570 */
13571 static void
13572f_type(typval_T *argvars, typval_T *rettv)
13573{
13574 int n = -1;
13575
13576 switch (argvars[0].v_type)
13577 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013578 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13579 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013580 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013581 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13582 case VAR_LIST: n = VAR_TYPE_LIST; break;
13583 case VAR_DICT: n = VAR_TYPE_DICT; break;
13584 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013585 case VAR_SPECIAL:
13586 if (argvars[0].vval.v_number == VVAL_FALSE
13587 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013588 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013589 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013590 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013591 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013592 case VAR_JOB: n = VAR_TYPE_JOB; break;
13593 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013594 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013595 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013596 n = -1;
13597 break;
13598 }
13599 rettv->vval.v_number = n;
13600}
13601
13602/*
13603 * "undofile(name)" function
13604 */
13605 static void
13606f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13607{
13608 rettv->v_type = VAR_STRING;
13609#ifdef FEAT_PERSISTENT_UNDO
13610 {
13611 char_u *fname = get_tv_string(&argvars[0]);
13612
13613 if (*fname == NUL)
13614 {
13615 /* If there is no file name there will be no undo file. */
13616 rettv->vval.v_string = NULL;
13617 }
13618 else
13619 {
13620 char_u *ffname = FullName_save(fname, FALSE);
13621
13622 if (ffname != NULL)
13623 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13624 vim_free(ffname);
13625 }
13626 }
13627#else
13628 rettv->vval.v_string = NULL;
13629#endif
13630}
13631
13632/*
13633 * "undotree()" function
13634 */
13635 static void
13636f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13637{
13638 if (rettv_dict_alloc(rettv) == OK)
13639 {
13640 dict_T *dict = rettv->vval.v_dict;
13641 list_T *list;
13642
Bram Moolenaare0be1672018-07-08 16:50:37 +020013643 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
13644 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
13645 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
13646 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
13647 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
13648 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013649
13650 list = list_alloc();
13651 if (list != NULL)
13652 {
13653 u_eval_tree(curbuf->b_u_oldhead, list);
13654 dict_add_list(dict, "entries", list);
13655 }
13656 }
13657}
13658
13659/*
13660 * "values(dict)" function
13661 */
13662 static void
13663f_values(typval_T *argvars, typval_T *rettv)
13664{
13665 dict_list(argvars, rettv, 1);
13666}
13667
13668/*
13669 * "virtcol(string)" function
13670 */
13671 static void
13672f_virtcol(typval_T *argvars, typval_T *rettv)
13673{
13674 colnr_T vcol = 0;
13675 pos_T *fp;
13676 int fnum = curbuf->b_fnum;
13677
13678 fp = var2fpos(&argvars[0], FALSE, &fnum);
13679 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13680 && fnum == curbuf->b_fnum)
13681 {
13682 getvvcol(curwin, fp, NULL, NULL, &vcol);
13683 ++vcol;
13684 }
13685
13686 rettv->vval.v_number = vcol;
13687}
13688
13689/*
13690 * "visualmode()" function
13691 */
13692 static void
13693f_visualmode(typval_T *argvars, typval_T *rettv)
13694{
13695 char_u str[2];
13696
13697 rettv->v_type = VAR_STRING;
13698 str[0] = curbuf->b_visual_mode_eval;
13699 str[1] = NUL;
13700 rettv->vval.v_string = vim_strsave(str);
13701
13702 /* A non-zero number or non-empty string argument: reset mode. */
13703 if (non_zero_arg(&argvars[0]))
13704 curbuf->b_visual_mode_eval = NUL;
13705}
13706
13707/*
13708 * "wildmenumode()" function
13709 */
13710 static void
13711f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13712{
13713#ifdef FEAT_WILDMENU
13714 if (wild_menu_showing)
13715 rettv->vval.v_number = 1;
13716#endif
13717}
13718
13719/*
13720 * "winbufnr(nr)" function
13721 */
13722 static void
13723f_winbufnr(typval_T *argvars, typval_T *rettv)
13724{
13725 win_T *wp;
13726
13727 wp = find_win_by_nr(&argvars[0], NULL);
13728 if (wp == NULL)
13729 rettv->vval.v_number = -1;
13730 else
13731 rettv->vval.v_number = wp->w_buffer->b_fnum;
13732}
13733
13734/*
13735 * "wincol()" function
13736 */
13737 static void
13738f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13739{
13740 validate_cursor();
13741 rettv->vval.v_number = curwin->w_wcol + 1;
13742}
13743
13744/*
13745 * "winheight(nr)" function
13746 */
13747 static void
13748f_winheight(typval_T *argvars, typval_T *rettv)
13749{
13750 win_T *wp;
13751
13752 wp = find_win_by_nr(&argvars[0], NULL);
13753 if (wp == NULL)
13754 rettv->vval.v_number = -1;
13755 else
13756 rettv->vval.v_number = wp->w_height;
13757}
13758
13759/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020013760 * "winlayout()" function
13761 */
13762 static void
13763f_winlayout(typval_T *argvars, typval_T *rettv)
13764{
13765 tabpage_T *tp;
13766
13767 if (rettv_list_alloc(rettv) != OK)
13768 return;
13769
13770 if (argvars[0].v_type == VAR_UNKNOWN)
13771 tp = curtab;
13772 else
13773 {
13774 tp = find_tabpage((int)get_tv_number(&argvars[0]));
13775 if (tp == NULL)
13776 return;
13777 }
13778
13779 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
13780}
13781
13782/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013783 * "winline()" function
13784 */
13785 static void
13786f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13787{
13788 validate_cursor();
13789 rettv->vval.v_number = curwin->w_wrow + 1;
13790}
13791
13792/*
13793 * "winnr()" function
13794 */
13795 static void
13796f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13797{
13798 int nr = 1;
13799
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013800 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013801 rettv->vval.v_number = nr;
13802}
13803
13804/*
13805 * "winrestcmd()" function
13806 */
13807 static void
13808f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13809{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013810 win_T *wp;
13811 int winnr = 1;
13812 garray_T ga;
13813 char_u buf[50];
13814
13815 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013816 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013817 {
13818 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13819 ga_concat(&ga, buf);
13820 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13821 ga_concat(&ga, buf);
13822 ++winnr;
13823 }
13824 ga_append(&ga, NUL);
13825
13826 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013827 rettv->v_type = VAR_STRING;
13828}
13829
13830/*
13831 * "winrestview()" function
13832 */
13833 static void
13834f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13835{
13836 dict_T *dict;
13837
13838 if (argvars[0].v_type != VAR_DICT
13839 || (dict = argvars[0].vval.v_dict) == NULL)
13840 EMSG(_(e_invarg));
13841 else
13842 {
13843 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13844 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13845 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13846 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13847#ifdef FEAT_VIRTUALEDIT
13848 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13849 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13850#endif
13851 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13852 {
13853 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13854 curwin->w_set_curswant = FALSE;
13855 }
13856
13857 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13858 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13859#ifdef FEAT_DIFF
13860 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13861 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13862#endif
13863 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13864 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13865 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13866 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13867
13868 check_cursor();
13869 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013870 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013871 changed_window_setting();
13872
13873 if (curwin->w_topline <= 0)
13874 curwin->w_topline = 1;
13875 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13876 curwin->w_topline = curbuf->b_ml.ml_line_count;
13877#ifdef FEAT_DIFF
13878 check_topfill(curwin, TRUE);
13879#endif
13880 }
13881}
13882
13883/*
13884 * "winsaveview()" function
13885 */
13886 static void
13887f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13888{
13889 dict_T *dict;
13890
13891 if (rettv_dict_alloc(rettv) == FAIL)
13892 return;
13893 dict = rettv->vval.v_dict;
13894
Bram Moolenaare0be1672018-07-08 16:50:37 +020013895 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13896 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013897#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020013898 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013899#endif
13900 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013901 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013902
Bram Moolenaare0be1672018-07-08 16:50:37 +020013903 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013904#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013905 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013906#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013907 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13908 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013909}
13910
13911/*
13912 * "winwidth(nr)" function
13913 */
13914 static void
13915f_winwidth(typval_T *argvars, typval_T *rettv)
13916{
13917 win_T *wp;
13918
13919 wp = find_win_by_nr(&argvars[0], NULL);
13920 if (wp == NULL)
13921 rettv->vval.v_number = -1;
13922 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013923 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013924}
13925
13926/*
13927 * "wordcount()" function
13928 */
13929 static void
13930f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13931{
13932 if (rettv_dict_alloc(rettv) == FAIL)
13933 return;
13934 cursor_pos_info(rettv->vval.v_dict);
13935}
13936
13937/*
13938 * "writefile()" function
13939 */
13940 static void
13941f_writefile(typval_T *argvars, typval_T *rettv)
13942{
13943 int binary = FALSE;
13944 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013945#ifdef HAVE_FSYNC
13946 int do_fsync = p_fs;
13947#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013948 char_u *fname;
13949 FILE *fd;
13950 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013951 listitem_T *li;
13952 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013953
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013954 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013955 if (check_restricted() || check_secure())
13956 return;
13957
13958 if (argvars[0].v_type != VAR_LIST)
13959 {
13960 EMSG2(_(e_listarg), "writefile()");
13961 return;
13962 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013963 list = argvars[0].vval.v_list;
13964 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013965 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013966 for (li = list->lv_first; li != NULL; li = li->li_next)
13967 if (get_tv_string_chk(&li->li_tv) == NULL)
13968 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013969
13970 if (argvars[2].v_type != VAR_UNKNOWN)
13971 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013972 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13973
13974 if (arg2 == NULL)
13975 return;
13976 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013977 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013978 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013979 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013980#ifdef HAVE_FSYNC
13981 if (vim_strchr(arg2, 's') != NULL)
13982 do_fsync = TRUE;
13983 else if (vim_strchr(arg2, 'S') != NULL)
13984 do_fsync = FALSE;
13985#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013986 }
13987
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013988 fname = get_tv_string_chk(&argvars[1]);
13989 if (fname == NULL)
13990 return;
13991
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013992 /* Always open the file in binary mode, library functions have a mind of
13993 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013994 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13995 append ? APPENDBIN : WRITEBIN)) == NULL)
13996 {
13997 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13998 ret = -1;
13999 }
14000 else
14001 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014002 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014003 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014004#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014005 else if (do_fsync)
14006 /* Ignore the error, the user wouldn't know what to do about it.
14007 * May happen for a device. */
14008 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014009#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014010 fclose(fd);
14011 }
14012
14013 rettv->vval.v_number = ret;
14014}
14015
14016/*
14017 * "xor(expr, expr)" function
14018 */
14019 static void
14020f_xor(typval_T *argvars, typval_T *rettv)
14021{
14022 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
14023 ^ get_tv_number_chk(&argvars[1], NULL);
14024}
14025
14026
14027#endif /* FEAT_EVAL */