blob: eb379a5cc1d49737bb93551f984609f9dbdc700b [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);
126static void f_deepcopy(typval_T *argvars, typval_T *rettv);
127static void f_delete(typval_T *argvars, typval_T *rettv);
128static void f_did_filetype(typval_T *argvars, typval_T *rettv);
129static void f_diff_filler(typval_T *argvars, typval_T *rettv);
130static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
131static void f_empty(typval_T *argvars, typval_T *rettv);
132static void f_escape(typval_T *argvars, typval_T *rettv);
133static void f_eval(typval_T *argvars, typval_T *rettv);
134static void f_eventhandler(typval_T *argvars, typval_T *rettv);
135static void f_executable(typval_T *argvars, typval_T *rettv);
136static void f_execute(typval_T *argvars, typval_T *rettv);
137static void f_exepath(typval_T *argvars, typval_T *rettv);
138static void f_exists(typval_T *argvars, typval_T *rettv);
139#ifdef FEAT_FLOAT
140static void f_exp(typval_T *argvars, typval_T *rettv);
141#endif
142static void f_expand(typval_T *argvars, typval_T *rettv);
143static void f_extend(typval_T *argvars, typval_T *rettv);
144static void f_feedkeys(typval_T *argvars, typval_T *rettv);
145static void f_filereadable(typval_T *argvars, typval_T *rettv);
146static void f_filewritable(typval_T *argvars, typval_T *rettv);
147static void f_filter(typval_T *argvars, typval_T *rettv);
148static void f_finddir(typval_T *argvars, typval_T *rettv);
149static void f_findfile(typval_T *argvars, typval_T *rettv);
150#ifdef FEAT_FLOAT
151static void f_float2nr(typval_T *argvars, typval_T *rettv);
152static void f_floor(typval_T *argvars, typval_T *rettv);
153static void f_fmod(typval_T *argvars, typval_T *rettv);
154#endif
155static void f_fnameescape(typval_T *argvars, typval_T *rettv);
156static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
157static void f_foldclosed(typval_T *argvars, typval_T *rettv);
158static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
159static void f_foldlevel(typval_T *argvars, typval_T *rettv);
160static void f_foldtext(typval_T *argvars, typval_T *rettv);
161static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
162static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200163static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200164static void f_function(typval_T *argvars, typval_T *rettv);
165static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
166static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200167static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_getbufline(typval_T *argvars, typval_T *rettv);
169static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100170static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_getchar(typval_T *argvars, typval_T *rettv);
172static void f_getcharmod(typval_T *argvars, typval_T *rettv);
173static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
174static void f_getcmdline(typval_T *argvars, typval_T *rettv);
175#if defined(FEAT_CMDL_COMPL)
176static void f_getcompletion(typval_T *argvars, typval_T *rettv);
177#endif
178static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
179static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
180static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
181static void f_getcwd(typval_T *argvars, typval_T *rettv);
182static void f_getfontname(typval_T *argvars, typval_T *rettv);
183static void f_getfperm(typval_T *argvars, typval_T *rettv);
184static void f_getfsize(typval_T *argvars, typval_T *rettv);
185static void f_getftime(typval_T *argvars, typval_T *rettv);
186static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100187static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200189static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200190static void f_getmatches(typval_T *argvars, typval_T *rettv);
191static void f_getpid(typval_T *argvars, typval_T *rettv);
192static void f_getcurpos(typval_T *argvars, typval_T *rettv);
193static void f_getpos(typval_T *argvars, typval_T *rettv);
194static void f_getqflist(typval_T *argvars, typval_T *rettv);
195static void f_getreg(typval_T *argvars, typval_T *rettv);
196static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200197static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_gettabvar(typval_T *argvars, typval_T *rettv);
199static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200200static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100201static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_getwinposx(typval_T *argvars, typval_T *rettv);
203static void f_getwinposy(typval_T *argvars, typval_T *rettv);
204static void f_getwinvar(typval_T *argvars, typval_T *rettv);
205static void f_glob(typval_T *argvars, typval_T *rettv);
206static void f_globpath(typval_T *argvars, typval_T *rettv);
207static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
208static void f_has(typval_T *argvars, typval_T *rettv);
209static void f_has_key(typval_T *argvars, typval_T *rettv);
210static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
211static void f_hasmapto(typval_T *argvars, typval_T *rettv);
212static void f_histadd(typval_T *argvars, typval_T *rettv);
213static void f_histdel(typval_T *argvars, typval_T *rettv);
214static void f_histget(typval_T *argvars, typval_T *rettv);
215static void f_histnr(typval_T *argvars, typval_T *rettv);
216static void f_hlID(typval_T *argvars, typval_T *rettv);
217static void f_hlexists(typval_T *argvars, typval_T *rettv);
218static void f_hostname(typval_T *argvars, typval_T *rettv);
219static void f_iconv(typval_T *argvars, typval_T *rettv);
220static void f_indent(typval_T *argvars, typval_T *rettv);
221static void f_index(typval_T *argvars, typval_T *rettv);
222static void f_input(typval_T *argvars, typval_T *rettv);
223static void f_inputdialog(typval_T *argvars, typval_T *rettv);
224static void f_inputlist(typval_T *argvars, typval_T *rettv);
225static void f_inputrestore(typval_T *argvars, typval_T *rettv);
226static void f_inputsave(typval_T *argvars, typval_T *rettv);
227static void f_inputsecret(typval_T *argvars, typval_T *rettv);
228static void f_insert(typval_T *argvars, typval_T *rettv);
229static void f_invert(typval_T *argvars, typval_T *rettv);
230static void f_isdirectory(typval_T *argvars, typval_T *rettv);
231static void f_islocked(typval_T *argvars, typval_T *rettv);
232#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
233static void f_isnan(typval_T *argvars, typval_T *rettv);
234#endif
235static void f_items(typval_T *argvars, typval_T *rettv);
236#ifdef FEAT_JOB_CHANNEL
237static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
238static void f_job_info(typval_T *argvars, typval_T *rettv);
239static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
240static void f_job_start(typval_T *argvars, typval_T *rettv);
241static void f_job_stop(typval_T *argvars, typval_T *rettv);
242static void f_job_status(typval_T *argvars, typval_T *rettv);
243#endif
244static void f_join(typval_T *argvars, typval_T *rettv);
245static void f_js_decode(typval_T *argvars, typval_T *rettv);
246static void f_js_encode(typval_T *argvars, typval_T *rettv);
247static void f_json_decode(typval_T *argvars, typval_T *rettv);
248static void f_json_encode(typval_T *argvars, typval_T *rettv);
249static void f_keys(typval_T *argvars, typval_T *rettv);
250static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
251static void f_len(typval_T *argvars, typval_T *rettv);
252static void f_libcall(typval_T *argvars, typval_T *rettv);
253static void f_libcallnr(typval_T *argvars, typval_T *rettv);
254static void f_line(typval_T *argvars, typval_T *rettv);
255static void f_line2byte(typval_T *argvars, typval_T *rettv);
256static void f_lispindent(typval_T *argvars, typval_T *rettv);
257static void f_localtime(typval_T *argvars, typval_T *rettv);
258#ifdef FEAT_FLOAT
259static void f_log(typval_T *argvars, typval_T *rettv);
260static void f_log10(typval_T *argvars, typval_T *rettv);
261#endif
262#ifdef FEAT_LUA
263static void f_luaeval(typval_T *argvars, typval_T *rettv);
264#endif
265static void f_map(typval_T *argvars, typval_T *rettv);
266static void f_maparg(typval_T *argvars, typval_T *rettv);
267static void f_mapcheck(typval_T *argvars, typval_T *rettv);
268static void f_match(typval_T *argvars, typval_T *rettv);
269static void f_matchadd(typval_T *argvars, typval_T *rettv);
270static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
271static void f_matcharg(typval_T *argvars, typval_T *rettv);
272static void f_matchdelete(typval_T *argvars, typval_T *rettv);
273static void f_matchend(typval_T *argvars, typval_T *rettv);
274static void f_matchlist(typval_T *argvars, typval_T *rettv);
275static void f_matchstr(typval_T *argvars, typval_T *rettv);
276static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
277static void f_max(typval_T *argvars, typval_T *rettv);
278static void f_min(typval_T *argvars, typval_T *rettv);
279#ifdef vim_mkdir
280static void f_mkdir(typval_T *argvars, typval_T *rettv);
281#endif
282static void f_mode(typval_T *argvars, typval_T *rettv);
283#ifdef FEAT_MZSCHEME
284static void f_mzeval(typval_T *argvars, typval_T *rettv);
285#endif
286static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
287static void f_nr2char(typval_T *argvars, typval_T *rettv);
288static void f_or(typval_T *argvars, typval_T *rettv);
289static void f_pathshorten(typval_T *argvars, typval_T *rettv);
290#ifdef FEAT_PERL
291static void f_perleval(typval_T *argvars, typval_T *rettv);
292#endif
293#ifdef FEAT_FLOAT
294static void f_pow(typval_T *argvars, typval_T *rettv);
295#endif
296static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
297static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200298#ifdef FEAT_JOB_CHANNEL
299static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
300static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
301#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_pumvisible(typval_T *argvars, typval_T *rettv);
303#ifdef FEAT_PYTHON3
304static void f_py3eval(typval_T *argvars, typval_T *rettv);
305#endif
306#ifdef FEAT_PYTHON
307static void f_pyeval(typval_T *argvars, typval_T *rettv);
308#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100309#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
310static void f_pyxeval(typval_T *argvars, typval_T *rettv);
311#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200312static void f_range(typval_T *argvars, typval_T *rettv);
313static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200314static void f_reg_executing(typval_T *argvars, typval_T *rettv);
315static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200316static void f_reltime(typval_T *argvars, typval_T *rettv);
317#ifdef FEAT_FLOAT
318static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
319#endif
320static void f_reltimestr(typval_T *argvars, typval_T *rettv);
321static void f_remote_expr(typval_T *argvars, typval_T *rettv);
322static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
323static void f_remote_peek(typval_T *argvars, typval_T *rettv);
324static void f_remote_read(typval_T *argvars, typval_T *rettv);
325static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100326static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200327static void f_remove(typval_T *argvars, typval_T *rettv);
328static void f_rename(typval_T *argvars, typval_T *rettv);
329static void f_repeat(typval_T *argvars, typval_T *rettv);
330static void f_resolve(typval_T *argvars, typval_T *rettv);
331static void f_reverse(typval_T *argvars, typval_T *rettv);
332#ifdef FEAT_FLOAT
333static void f_round(typval_T *argvars, typval_T *rettv);
334#endif
335static void f_screenattr(typval_T *argvars, typval_T *rettv);
336static void f_screenchar(typval_T *argvars, typval_T *rettv);
337static void f_screencol(typval_T *argvars, typval_T *rettv);
338static void f_screenrow(typval_T *argvars, typval_T *rettv);
339static void f_search(typval_T *argvars, typval_T *rettv);
340static void f_searchdecl(typval_T *argvars, typval_T *rettv);
341static void f_searchpair(typval_T *argvars, typval_T *rettv);
342static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
343static void f_searchpos(typval_T *argvars, typval_T *rettv);
344static void f_server2client(typval_T *argvars, typval_T *rettv);
345static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200346static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200347static void f_setbufvar(typval_T *argvars, typval_T *rettv);
348static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
349static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
350static void f_setfperm(typval_T *argvars, typval_T *rettv);
351static void f_setline(typval_T *argvars, typval_T *rettv);
352static void f_setloclist(typval_T *argvars, typval_T *rettv);
353static void f_setmatches(typval_T *argvars, typval_T *rettv);
354static void f_setpos(typval_T *argvars, typval_T *rettv);
355static void f_setqflist(typval_T *argvars, typval_T *rettv);
356static void f_setreg(typval_T *argvars, typval_T *rettv);
357static void f_settabvar(typval_T *argvars, typval_T *rettv);
358static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
359static void f_setwinvar(typval_T *argvars, typval_T *rettv);
360#ifdef FEAT_CRYPT
361static void f_sha256(typval_T *argvars, typval_T *rettv);
362#endif /* FEAT_CRYPT */
363static void f_shellescape(typval_T *argvars, typval_T *rettv);
364static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
365static void f_simplify(typval_T *argvars, typval_T *rettv);
366#ifdef FEAT_FLOAT
367static void f_sin(typval_T *argvars, typval_T *rettv);
368static void f_sinh(typval_T *argvars, typval_T *rettv);
369#endif
370static void f_sort(typval_T *argvars, typval_T *rettv);
371static void f_soundfold(typval_T *argvars, typval_T *rettv);
372static void f_spellbadword(typval_T *argvars, typval_T *rettv);
373static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
374static void f_split(typval_T *argvars, typval_T *rettv);
375#ifdef FEAT_FLOAT
376static void f_sqrt(typval_T *argvars, typval_T *rettv);
377static void f_str2float(typval_T *argvars, typval_T *rettv);
378#endif
379static void f_str2nr(typval_T *argvars, typval_T *rettv);
380static void f_strchars(typval_T *argvars, typval_T *rettv);
381#ifdef HAVE_STRFTIME
382static void f_strftime(typval_T *argvars, typval_T *rettv);
383#endif
384static void f_strgetchar(typval_T *argvars, typval_T *rettv);
385static void f_stridx(typval_T *argvars, typval_T *rettv);
386static void f_string(typval_T *argvars, typval_T *rettv);
387static void f_strlen(typval_T *argvars, typval_T *rettv);
388static void f_strcharpart(typval_T *argvars, typval_T *rettv);
389static void f_strpart(typval_T *argvars, typval_T *rettv);
390static void f_strridx(typval_T *argvars, typval_T *rettv);
391static void f_strtrans(typval_T *argvars, typval_T *rettv);
392static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
393static void f_strwidth(typval_T *argvars, typval_T *rettv);
394static void f_submatch(typval_T *argvars, typval_T *rettv);
395static void f_substitute(typval_T *argvars, typval_T *rettv);
396static void f_synID(typval_T *argvars, typval_T *rettv);
397static void f_synIDattr(typval_T *argvars, typval_T *rettv);
398static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
399static void f_synstack(typval_T *argvars, typval_T *rettv);
400static void f_synconcealed(typval_T *argvars, typval_T *rettv);
401static void f_system(typval_T *argvars, typval_T *rettv);
402static void f_systemlist(typval_T *argvars, typval_T *rettv);
403static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
404static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
405static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
406static void f_taglist(typval_T *argvars, typval_T *rettv);
407static void f_tagfiles(typval_T *argvars, typval_T *rettv);
408static void f_tempname(typval_T *argvars, typval_T *rettv);
409static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
410static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200411static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100412static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200413static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100414static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200415#ifdef FEAT_JOB_CHANNEL
416static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
417#endif
418static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
419#ifdef FEAT_JOB_CHANNEL
420static void f_test_null_job(typval_T *argvars, typval_T *rettv);
421#endif
422static void f_test_null_list(typval_T *argvars, typval_T *rettv);
423static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
424static void f_test_null_string(typval_T *argvars, typval_T *rettv);
425static void f_test_settime(typval_T *argvars, typval_T *rettv);
426#ifdef FEAT_FLOAT
427static void f_tan(typval_T *argvars, typval_T *rettv);
428static void f_tanh(typval_T *argvars, typval_T *rettv);
429#endif
430#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200431static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200432static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200433static void f_timer_start(typval_T *argvars, typval_T *rettv);
434static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200435static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#endif
437static void f_tolower(typval_T *argvars, typval_T *rettv);
438static void f_toupper(typval_T *argvars, typval_T *rettv);
439static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100440static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200441#ifdef FEAT_FLOAT
442static void f_trunc(typval_T *argvars, typval_T *rettv);
443#endif
444static void f_type(typval_T *argvars, typval_T *rettv);
445static void f_undofile(typval_T *argvars, typval_T *rettv);
446static void f_undotree(typval_T *argvars, typval_T *rettv);
447static void f_uniq(typval_T *argvars, typval_T *rettv);
448static void f_values(typval_T *argvars, typval_T *rettv);
449static void f_virtcol(typval_T *argvars, typval_T *rettv);
450static void f_visualmode(typval_T *argvars, typval_T *rettv);
451static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
452static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
453static void f_win_getid(typval_T *argvars, typval_T *rettv);
454static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
455static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
456static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100457static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200458static void f_winbufnr(typval_T *argvars, typval_T *rettv);
459static void f_wincol(typval_T *argvars, typval_T *rettv);
460static void f_winheight(typval_T *argvars, typval_T *rettv);
461static void f_winline(typval_T *argvars, typval_T *rettv);
462static void f_winnr(typval_T *argvars, typval_T *rettv);
463static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
464static void f_winrestview(typval_T *argvars, typval_T *rettv);
465static void f_winsaveview(typval_T *argvars, typval_T *rettv);
466static void f_winwidth(typval_T *argvars, typval_T *rettv);
467static void f_writefile(typval_T *argvars, typval_T *rettv);
468static void f_wordcount(typval_T *argvars, typval_T *rettv);
469static void f_xor(typval_T *argvars, typval_T *rettv);
470
471/*
472 * Array with names and number of arguments of all internal functions
473 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
474 */
475static struct fst
476{
477 char *f_name; /* function name */
478 char f_min_argc; /* minimal number of arguments */
479 char f_max_argc; /* maximal number of arguments */
480 void (*f_func)(typval_T *args, typval_T *rvar);
481 /* implementation of function */
482} functions[] =
483{
484#ifdef FEAT_FLOAT
485 {"abs", 1, 1, f_abs},
486 {"acos", 1, 1, f_acos}, /* WJMc */
487#endif
488 {"add", 2, 2, f_add},
489 {"and", 2, 2, f_and},
490 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200491 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200492 {"argc", 0, 0, f_argc},
493 {"argidx", 0, 0, f_argidx},
494 {"arglistid", 0, 2, f_arglistid},
495 {"argv", 0, 1, f_argv},
496#ifdef FEAT_FLOAT
497 {"asin", 1, 1, f_asin}, /* WJMc */
498#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100499 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200500 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100501 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200502 {"assert_exception", 1, 2, f_assert_exception},
503 {"assert_fails", 1, 2, f_assert_fails},
504 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100505 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200506 {"assert_match", 2, 3, f_assert_match},
507 {"assert_notequal", 2, 3, f_assert_notequal},
508 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100509 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200510 {"assert_true", 1, 2, f_assert_true},
511#ifdef FEAT_FLOAT
512 {"atan", 1, 1, f_atan},
513 {"atan2", 2, 2, f_atan2},
514#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100515#ifdef FEAT_BEVAL
516 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100517# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100518 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100519# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100520#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200521 {"browse", 4, 4, f_browse},
522 {"browsedir", 2, 2, f_browsedir},
523 {"bufexists", 1, 1, f_bufexists},
524 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
525 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
526 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
527 {"buflisted", 1, 1, f_buflisted},
528 {"bufloaded", 1, 1, f_bufloaded},
529 {"bufname", 1, 1, f_bufname},
530 {"bufnr", 1, 2, f_bufnr},
531 {"bufwinid", 1, 1, f_bufwinid},
532 {"bufwinnr", 1, 1, f_bufwinnr},
533 {"byte2line", 1, 1, f_byte2line},
534 {"byteidx", 2, 2, f_byteidx},
535 {"byteidxcomp", 2, 2, f_byteidxcomp},
536 {"call", 2, 3, f_call},
537#ifdef FEAT_FLOAT
538 {"ceil", 1, 1, f_ceil},
539#endif
540#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100541 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200542 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200543 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200544 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
545 {"ch_evalraw", 2, 3, f_ch_evalraw},
546 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
547 {"ch_getjob", 1, 1, f_ch_getjob},
548 {"ch_info", 1, 1, f_ch_info},
549 {"ch_log", 1, 2, f_ch_log},
550 {"ch_logfile", 1, 2, f_ch_logfile},
551 {"ch_open", 1, 2, f_ch_open},
552 {"ch_read", 1, 2, f_ch_read},
553 {"ch_readraw", 1, 2, f_ch_readraw},
554 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
555 {"ch_sendraw", 2, 3, f_ch_sendraw},
556 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200557 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200558#endif
559 {"changenr", 0, 0, f_changenr},
560 {"char2nr", 1, 2, f_char2nr},
561 {"cindent", 1, 1, f_cindent},
562 {"clearmatches", 0, 0, f_clearmatches},
563 {"col", 1, 1, f_col},
564#if defined(FEAT_INS_EXPAND)
565 {"complete", 2, 2, f_complete},
566 {"complete_add", 1, 1, f_complete_add},
567 {"complete_check", 0, 0, f_complete_check},
568#endif
569 {"confirm", 1, 4, f_confirm},
570 {"copy", 1, 1, f_copy},
571#ifdef FEAT_FLOAT
572 {"cos", 1, 1, f_cos},
573 {"cosh", 1, 1, f_cosh},
574#endif
575 {"count", 2, 4, f_count},
576 {"cscope_connection",0,3, f_cscope_connection},
577 {"cursor", 1, 3, f_cursor},
578 {"deepcopy", 1, 2, f_deepcopy},
579 {"delete", 1, 2, f_delete},
580 {"did_filetype", 0, 0, f_did_filetype},
581 {"diff_filler", 1, 1, f_diff_filler},
582 {"diff_hlID", 2, 2, f_diff_hlID},
583 {"empty", 1, 1, f_empty},
584 {"escape", 2, 2, f_escape},
585 {"eval", 1, 1, f_eval},
586 {"eventhandler", 0, 0, f_eventhandler},
587 {"executable", 1, 1, f_executable},
588 {"execute", 1, 2, f_execute},
589 {"exepath", 1, 1, f_exepath},
590 {"exists", 1, 1, f_exists},
591#ifdef FEAT_FLOAT
592 {"exp", 1, 1, f_exp},
593#endif
594 {"expand", 1, 3, f_expand},
595 {"extend", 2, 3, f_extend},
596 {"feedkeys", 1, 2, f_feedkeys},
597 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
598 {"filereadable", 1, 1, f_filereadable},
599 {"filewritable", 1, 1, f_filewritable},
600 {"filter", 2, 2, f_filter},
601 {"finddir", 1, 3, f_finddir},
602 {"findfile", 1, 3, f_findfile},
603#ifdef FEAT_FLOAT
604 {"float2nr", 1, 1, f_float2nr},
605 {"floor", 1, 1, f_floor},
606 {"fmod", 2, 2, f_fmod},
607#endif
608 {"fnameescape", 1, 1, f_fnameescape},
609 {"fnamemodify", 2, 2, f_fnamemodify},
610 {"foldclosed", 1, 1, f_foldclosed},
611 {"foldclosedend", 1, 1, f_foldclosedend},
612 {"foldlevel", 1, 1, f_foldlevel},
613 {"foldtext", 0, 0, f_foldtext},
614 {"foldtextresult", 1, 1, f_foldtextresult},
615 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200616 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200617 {"function", 1, 3, f_function},
618 {"garbagecollect", 0, 1, f_garbagecollect},
619 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200620 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200621 {"getbufline", 2, 3, f_getbufline},
622 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100623 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200624 {"getchar", 0, 1, f_getchar},
625 {"getcharmod", 0, 0, f_getcharmod},
626 {"getcharsearch", 0, 0, f_getcharsearch},
627 {"getcmdline", 0, 0, f_getcmdline},
628 {"getcmdpos", 0, 0, f_getcmdpos},
629 {"getcmdtype", 0, 0, f_getcmdtype},
630 {"getcmdwintype", 0, 0, f_getcmdwintype},
631#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200632 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633#endif
634 {"getcurpos", 0, 0, f_getcurpos},
635 {"getcwd", 0, 2, f_getcwd},
636 {"getfontname", 0, 1, f_getfontname},
637 {"getfperm", 1, 1, f_getfperm},
638 {"getfsize", 1, 1, f_getfsize},
639 {"getftime", 1, 1, f_getftime},
640 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100641 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200642 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200643 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644 {"getmatches", 0, 0, f_getmatches},
645 {"getpid", 0, 0, f_getpid},
646 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200647 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200648 {"getreg", 0, 3, f_getreg},
649 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200650 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651 {"gettabvar", 2, 3, f_gettabvar},
652 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200653 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100654 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655 {"getwinposx", 0, 0, f_getwinposx},
656 {"getwinposy", 0, 0, f_getwinposy},
657 {"getwinvar", 2, 3, f_getwinvar},
658 {"glob", 1, 4, f_glob},
659 {"glob2regpat", 1, 1, f_glob2regpat},
660 {"globpath", 2, 5, f_globpath},
661 {"has", 1, 1, f_has},
662 {"has_key", 2, 2, f_has_key},
663 {"haslocaldir", 0, 2, f_haslocaldir},
664 {"hasmapto", 1, 3, f_hasmapto},
665 {"highlightID", 1, 1, f_hlID}, /* obsolete */
666 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
667 {"histadd", 2, 2, f_histadd},
668 {"histdel", 1, 2, f_histdel},
669 {"histget", 1, 2, f_histget},
670 {"histnr", 1, 1, f_histnr},
671 {"hlID", 1, 1, f_hlID},
672 {"hlexists", 1, 1, f_hlexists},
673 {"hostname", 0, 0, f_hostname},
674 {"iconv", 3, 3, f_iconv},
675 {"indent", 1, 1, f_indent},
676 {"index", 2, 4, f_index},
677 {"input", 1, 3, f_input},
678 {"inputdialog", 1, 3, f_inputdialog},
679 {"inputlist", 1, 1, f_inputlist},
680 {"inputrestore", 0, 0, f_inputrestore},
681 {"inputsave", 0, 0, f_inputsave},
682 {"inputsecret", 1, 2, f_inputsecret},
683 {"insert", 2, 3, f_insert},
684 {"invert", 1, 1, f_invert},
685 {"isdirectory", 1, 1, f_isdirectory},
686 {"islocked", 1, 1, f_islocked},
687#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
688 {"isnan", 1, 1, f_isnan},
689#endif
690 {"items", 1, 1, f_items},
691#ifdef FEAT_JOB_CHANNEL
692 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200693 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200694 {"job_setoptions", 2, 2, f_job_setoptions},
695 {"job_start", 1, 2, f_job_start},
696 {"job_status", 1, 1, f_job_status},
697 {"job_stop", 1, 2, f_job_stop},
698#endif
699 {"join", 1, 2, f_join},
700 {"js_decode", 1, 1, f_js_decode},
701 {"js_encode", 1, 1, f_js_encode},
702 {"json_decode", 1, 1, f_json_decode},
703 {"json_encode", 1, 1, f_json_encode},
704 {"keys", 1, 1, f_keys},
705 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
706 {"len", 1, 1, f_len},
707 {"libcall", 3, 3, f_libcall},
708 {"libcallnr", 3, 3, f_libcallnr},
709 {"line", 1, 1, f_line},
710 {"line2byte", 1, 1, f_line2byte},
711 {"lispindent", 1, 1, f_lispindent},
712 {"localtime", 0, 0, f_localtime},
713#ifdef FEAT_FLOAT
714 {"log", 1, 1, f_log},
715 {"log10", 1, 1, f_log10},
716#endif
717#ifdef FEAT_LUA
718 {"luaeval", 1, 2, f_luaeval},
719#endif
720 {"map", 2, 2, f_map},
721 {"maparg", 1, 4, f_maparg},
722 {"mapcheck", 1, 3, f_mapcheck},
723 {"match", 2, 4, f_match},
724 {"matchadd", 2, 5, f_matchadd},
725 {"matchaddpos", 2, 5, f_matchaddpos},
726 {"matcharg", 1, 1, f_matcharg},
727 {"matchdelete", 1, 1, f_matchdelete},
728 {"matchend", 2, 4, f_matchend},
729 {"matchlist", 2, 4, f_matchlist},
730 {"matchstr", 2, 4, f_matchstr},
731 {"matchstrpos", 2, 4, f_matchstrpos},
732 {"max", 1, 1, f_max},
733 {"min", 1, 1, f_min},
734#ifdef vim_mkdir
735 {"mkdir", 1, 3, f_mkdir},
736#endif
737 {"mode", 0, 1, f_mode},
738#ifdef FEAT_MZSCHEME
739 {"mzeval", 1, 1, f_mzeval},
740#endif
741 {"nextnonblank", 1, 1, f_nextnonblank},
742 {"nr2char", 1, 2, f_nr2char},
743 {"or", 2, 2, f_or},
744 {"pathshorten", 1, 1, f_pathshorten},
745#ifdef FEAT_PERL
746 {"perleval", 1, 1, f_perleval},
747#endif
748#ifdef FEAT_FLOAT
749 {"pow", 2, 2, f_pow},
750#endif
751 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100752 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200753#ifdef FEAT_JOB_CHANNEL
754 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
755 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
756#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757 {"pumvisible", 0, 0, f_pumvisible},
758#ifdef FEAT_PYTHON3
759 {"py3eval", 1, 1, f_py3eval},
760#endif
761#ifdef FEAT_PYTHON
762 {"pyeval", 1, 1, f_pyeval},
763#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100764#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
765 {"pyxeval", 1, 1, f_pyxeval},
766#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200767 {"range", 1, 3, f_range},
768 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200769 {"reg_executing", 0, 0, f_reg_executing},
770 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200771 {"reltime", 0, 2, f_reltime},
772#ifdef FEAT_FLOAT
773 {"reltimefloat", 1, 1, f_reltimefloat},
774#endif
775 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100776 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777 {"remote_foreground", 1, 1, f_remote_foreground},
778 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100779 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200780 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100781 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200782 {"remove", 2, 3, f_remove},
783 {"rename", 2, 2, f_rename},
784 {"repeat", 2, 2, f_repeat},
785 {"resolve", 1, 1, f_resolve},
786 {"reverse", 1, 1, f_reverse},
787#ifdef FEAT_FLOAT
788 {"round", 1, 1, f_round},
789#endif
790 {"screenattr", 2, 2, f_screenattr},
791 {"screenchar", 2, 2, f_screenchar},
792 {"screencol", 0, 0, f_screencol},
793 {"screenrow", 0, 0, f_screenrow},
794 {"search", 1, 4, f_search},
795 {"searchdecl", 1, 3, f_searchdecl},
796 {"searchpair", 3, 7, f_searchpair},
797 {"searchpairpos", 3, 7, f_searchpairpos},
798 {"searchpos", 1, 4, f_searchpos},
799 {"server2client", 2, 2, f_server2client},
800 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200801 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200802 {"setbufvar", 3, 3, f_setbufvar},
803 {"setcharsearch", 1, 1, f_setcharsearch},
804 {"setcmdpos", 1, 1, f_setcmdpos},
805 {"setfperm", 2, 2, f_setfperm},
806 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200807 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808 {"setmatches", 1, 1, f_setmatches},
809 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200810 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200811 {"setreg", 2, 3, f_setreg},
812 {"settabvar", 3, 3, f_settabvar},
813 {"settabwinvar", 4, 4, f_settabwinvar},
814 {"setwinvar", 3, 3, f_setwinvar},
815#ifdef FEAT_CRYPT
816 {"sha256", 1, 1, f_sha256},
817#endif
818 {"shellescape", 1, 2, f_shellescape},
819 {"shiftwidth", 0, 0, f_shiftwidth},
820 {"simplify", 1, 1, f_simplify},
821#ifdef FEAT_FLOAT
822 {"sin", 1, 1, f_sin},
823 {"sinh", 1, 1, f_sinh},
824#endif
825 {"sort", 1, 3, f_sort},
826 {"soundfold", 1, 1, f_soundfold},
827 {"spellbadword", 0, 1, f_spellbadword},
828 {"spellsuggest", 1, 3, f_spellsuggest},
829 {"split", 1, 3, f_split},
830#ifdef FEAT_FLOAT
831 {"sqrt", 1, 1, f_sqrt},
832 {"str2float", 1, 1, f_str2float},
833#endif
834 {"str2nr", 1, 2, f_str2nr},
835 {"strcharpart", 2, 3, f_strcharpart},
836 {"strchars", 1, 2, f_strchars},
837 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
838#ifdef HAVE_STRFTIME
839 {"strftime", 1, 2, f_strftime},
840#endif
841 {"strgetchar", 2, 2, f_strgetchar},
842 {"stridx", 2, 3, f_stridx},
843 {"string", 1, 1, f_string},
844 {"strlen", 1, 1, f_strlen},
845 {"strpart", 2, 3, f_strpart},
846 {"strridx", 2, 3, f_strridx},
847 {"strtrans", 1, 1, f_strtrans},
848 {"strwidth", 1, 1, f_strwidth},
849 {"submatch", 1, 2, f_submatch},
850 {"substitute", 4, 4, f_substitute},
851 {"synID", 3, 3, f_synID},
852 {"synIDattr", 2, 3, f_synIDattr},
853 {"synIDtrans", 1, 1, f_synIDtrans},
854 {"synconcealed", 2, 2, f_synconcealed},
855 {"synstack", 2, 2, f_synstack},
856 {"system", 1, 2, f_system},
857 {"systemlist", 1, 2, f_systemlist},
858 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
859 {"tabpagenr", 0, 1, f_tabpagenr},
860 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
861 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100862 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200863#ifdef FEAT_FLOAT
864 {"tan", 1, 1, f_tan},
865 {"tanh", 1, 1, f_tanh},
866#endif
867 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200868#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100869 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
870 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100871 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200872 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200873# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
874 {"term_getansicolors", 1, 1, f_term_getansicolors},
875# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200876 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200877 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200878 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200879 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200880 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200881 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200882 {"term_getstatus", 1, 1, f_term_getstatus},
883 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200884 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200885 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200886 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200887 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200888# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
889 {"term_setansicolors", 2, 2, f_term_setansicolors},
890# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100891 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100892 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200893 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200894 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200895 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200896#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200897 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
898 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200899 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200900 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100901 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200902#ifdef FEAT_JOB_CHANNEL
903 {"test_null_channel", 0, 0, f_test_null_channel},
904#endif
905 {"test_null_dict", 0, 0, f_test_null_dict},
906#ifdef FEAT_JOB_CHANNEL
907 {"test_null_job", 0, 0, f_test_null_job},
908#endif
909 {"test_null_list", 0, 0, f_test_null_list},
910 {"test_null_partial", 0, 0, f_test_null_partial},
911 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100912 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200913 {"test_settime", 1, 1, f_test_settime},
914#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200915 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200916 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917 {"timer_start", 2, 3, f_timer_start},
918 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200919 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920#endif
921 {"tolower", 1, 1, f_tolower},
922 {"toupper", 1, 1, f_toupper},
923 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100924 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925#ifdef FEAT_FLOAT
926 {"trunc", 1, 1, f_trunc},
927#endif
928 {"type", 1, 1, f_type},
929 {"undofile", 1, 1, f_undofile},
930 {"undotree", 0, 0, f_undotree},
931 {"uniq", 1, 3, f_uniq},
932 {"values", 1, 1, f_values},
933 {"virtcol", 1, 1, f_virtcol},
934 {"visualmode", 0, 1, f_visualmode},
935 {"wildmenumode", 0, 0, f_wildmenumode},
936 {"win_findbuf", 1, 1, f_win_findbuf},
937 {"win_getid", 0, 2, f_win_getid},
938 {"win_gotoid", 1, 1, f_win_gotoid},
939 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
940 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100941 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200942 {"winbufnr", 1, 1, f_winbufnr},
943 {"wincol", 0, 0, f_wincol},
944 {"winheight", 1, 1, f_winheight},
945 {"winline", 0, 0, f_winline},
946 {"winnr", 0, 1, f_winnr},
947 {"winrestcmd", 0, 0, f_winrestcmd},
948 {"winrestview", 1, 1, f_winrestview},
949 {"winsaveview", 0, 0, f_winsaveview},
950 {"winwidth", 1, 1, f_winwidth},
951 {"wordcount", 0, 0, f_wordcount},
952 {"writefile", 2, 3, f_writefile},
953 {"xor", 2, 2, f_xor},
954};
955
956#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
957
958/*
959 * Function given to ExpandGeneric() to obtain the list of internal
960 * or user defined function names.
961 */
962 char_u *
963get_function_name(expand_T *xp, int idx)
964{
965 static int intidx = -1;
966 char_u *name;
967
968 if (idx == 0)
969 intidx = -1;
970 if (intidx < 0)
971 {
972 name = get_user_func_name(xp, idx);
973 if (name != NULL)
974 return name;
975 }
976 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
977 {
978 STRCPY(IObuff, functions[intidx].f_name);
979 STRCAT(IObuff, "(");
980 if (functions[intidx].f_max_argc == 0)
981 STRCAT(IObuff, ")");
982 return IObuff;
983 }
984
985 return NULL;
986}
987
988/*
989 * Function given to ExpandGeneric() to obtain the list of internal or
990 * user defined variable or function names.
991 */
992 char_u *
993get_expr_name(expand_T *xp, int idx)
994{
995 static int intidx = -1;
996 char_u *name;
997
998 if (idx == 0)
999 intidx = -1;
1000 if (intidx < 0)
1001 {
1002 name = get_function_name(xp, idx);
1003 if (name != NULL)
1004 return name;
1005 }
1006 return get_user_var_name(xp, ++intidx);
1007}
1008
1009#endif /* FEAT_CMDL_COMPL */
1010
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001011/*
1012 * Find internal function in table above.
1013 * Return index, or -1 if not found
1014 */
1015 int
1016find_internal_func(
1017 char_u *name) /* name of the function */
1018{
1019 int first = 0;
1020 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1021 int cmp;
1022 int x;
1023
1024 /*
1025 * Find the function name in the table. Binary search.
1026 */
1027 while (first <= last)
1028 {
1029 x = first + ((unsigned)(last - first) >> 1);
1030 cmp = STRCMP(name, functions[x].f_name);
1031 if (cmp < 0)
1032 last = x - 1;
1033 else if (cmp > 0)
1034 first = x + 1;
1035 else
1036 return x;
1037 }
1038 return -1;
1039}
1040
1041 int
1042call_internal_func(
1043 char_u *name,
1044 int argcount,
1045 typval_T *argvars,
1046 typval_T *rettv)
1047{
1048 int i;
1049
1050 i = find_internal_func(name);
1051 if (i < 0)
1052 return ERROR_UNKNOWN;
1053 if (argcount < functions[i].f_min_argc)
1054 return ERROR_TOOFEW;
1055 if (argcount > functions[i].f_max_argc)
1056 return ERROR_TOOMANY;
1057 argvars[argcount].v_type = VAR_UNKNOWN;
1058 functions[i].f_func(argvars, rettv);
1059 return ERROR_NONE;
1060}
1061
1062/*
1063 * Return TRUE for a non-zero Number and a non-empty String.
1064 */
1065 static int
1066non_zero_arg(typval_T *argvars)
1067{
1068 return ((argvars[0].v_type == VAR_NUMBER
1069 && argvars[0].vval.v_number != 0)
1070 || (argvars[0].v_type == VAR_SPECIAL
1071 && argvars[0].vval.v_number == VVAL_TRUE)
1072 || (argvars[0].v_type == VAR_STRING
1073 && argvars[0].vval.v_string != NULL
1074 && *argvars[0].vval.v_string != NUL));
1075}
1076
1077/*
1078 * Get the lnum from the first argument.
1079 * Also accepts ".", "$", etc., but that only works for the current buffer.
1080 * Returns -1 on error.
1081 */
1082 static linenr_T
1083get_tv_lnum(typval_T *argvars)
1084{
1085 typval_T rettv;
1086 linenr_T lnum;
1087
1088 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1089 if (lnum == 0) /* no valid number, try using line() */
1090 {
1091 rettv.v_type = VAR_NUMBER;
1092 f_line(argvars, &rettv);
1093 lnum = (linenr_T)rettv.vval.v_number;
1094 clear_tv(&rettv);
1095 }
1096 return lnum;
1097}
1098
1099#ifdef FEAT_FLOAT
1100static int get_float_arg(typval_T *argvars, float_T *f);
1101
1102/*
1103 * Get the float value of "argvars[0]" into "f".
1104 * Returns FAIL when the argument is not a Number or Float.
1105 */
1106 static int
1107get_float_arg(typval_T *argvars, float_T *f)
1108{
1109 if (argvars[0].v_type == VAR_FLOAT)
1110 {
1111 *f = argvars[0].vval.v_float;
1112 return OK;
1113 }
1114 if (argvars[0].v_type == VAR_NUMBER)
1115 {
1116 *f = (float_T)argvars[0].vval.v_number;
1117 return OK;
1118 }
1119 EMSG(_("E808: Number or Float required"));
1120 return FAIL;
1121}
1122
1123/*
1124 * "abs(expr)" function
1125 */
1126 static void
1127f_abs(typval_T *argvars, typval_T *rettv)
1128{
1129 if (argvars[0].v_type == VAR_FLOAT)
1130 {
1131 rettv->v_type = VAR_FLOAT;
1132 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1133 }
1134 else
1135 {
1136 varnumber_T n;
1137 int error = FALSE;
1138
1139 n = get_tv_number_chk(&argvars[0], &error);
1140 if (error)
1141 rettv->vval.v_number = -1;
1142 else if (n > 0)
1143 rettv->vval.v_number = n;
1144 else
1145 rettv->vval.v_number = -n;
1146 }
1147}
1148
1149/*
1150 * "acos()" function
1151 */
1152 static void
1153f_acos(typval_T *argvars, typval_T *rettv)
1154{
1155 float_T f = 0.0;
1156
1157 rettv->v_type = VAR_FLOAT;
1158 if (get_float_arg(argvars, &f) == OK)
1159 rettv->vval.v_float = acos(f);
1160 else
1161 rettv->vval.v_float = 0.0;
1162}
1163#endif
1164
1165/*
1166 * "add(list, item)" function
1167 */
1168 static void
1169f_add(typval_T *argvars, typval_T *rettv)
1170{
1171 list_T *l;
1172
1173 rettv->vval.v_number = 1; /* Default: Failed */
1174 if (argvars[0].v_type == VAR_LIST)
1175 {
1176 if ((l = argvars[0].vval.v_list) != NULL
1177 && !tv_check_lock(l->lv_lock,
1178 (char_u *)N_("add() argument"), TRUE)
1179 && list_append_tv(l, &argvars[1]) == OK)
1180 copy_tv(&argvars[0], rettv);
1181 }
1182 else
1183 EMSG(_(e_listreq));
1184}
1185
1186/*
1187 * "and(expr, expr)" function
1188 */
1189 static void
1190f_and(typval_T *argvars, typval_T *rettv)
1191{
1192 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1193 & get_tv_number_chk(&argvars[1], NULL);
1194}
1195
1196/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001197 * Get the lnum from the first argument.
1198 * Also accepts "$", then "buf" is used.
1199 * Returns 0 on error.
1200 */
1201 static linenr_T
1202get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
1203{
1204 if (argvars[0].v_type == VAR_STRING
1205 && argvars[0].vval.v_string != NULL
1206 && argvars[0].vval.v_string[0] == '$'
1207 && buf != NULL)
1208 return buf->b_ml.ml_line_count;
1209 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1210}
1211
1212/*
1213 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001214 */
1215 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001216set_buffer_lines(
1217 buf_T *buf,
1218 linenr_T lnum_arg,
1219 int append,
1220 typval_T *lines,
1221 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001222{
Bram Moolenaarca851592018-06-06 21:04:07 +02001223 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1224 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001225 list_T *l = NULL;
1226 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001227 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001228 linenr_T append_lnum;
1229 buf_T *curbuf_save = NULL;
1230 win_T *curwin_save = NULL;
1231 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001232
Bram Moolenaarca851592018-06-06 21:04:07 +02001233 /* When using the current buffer ml_mfp will be set if needed. Useful when
1234 * setline() is used on startup. For other buffers the buffer must be
1235 * loaded. */
1236 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001237 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001238 rettv->vval.v_number = 1; /* FAIL */
1239 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001240 }
1241
Bram Moolenaarca851592018-06-06 21:04:07 +02001242 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001243 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001244 wininfo_T *wip;
1245
1246 curbuf_save = curbuf;
1247 curwin_save = curwin;
1248 curbuf = buf;
1249 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001250 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001251 if (wip->wi_win != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001253 curwin = wip->wi_win;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254 break;
1255 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001256 }
1257 }
1258
1259 if (append)
1260 // appendbufline() uses the line number below which we insert
1261 append_lnum = lnum - 1;
1262 else
1263 // setbufline() uses the line number above which we insert, we only
1264 // append if it's below the last line
1265 append_lnum = curbuf->b_ml.ml_line_count;
1266
1267 if (lines->v_type == VAR_LIST)
1268 {
1269 l = lines->vval.v_list;
1270 li = l->lv_first;
1271 }
1272 else
1273 line = get_tv_string_chk(lines);
1274
1275 /* default result is zero == OK */
1276 for (;;)
1277 {
1278 if (l != NULL)
1279 {
1280 /* list argument, get next string */
1281 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001282 break;
Bram Moolenaarca851592018-06-06 21:04:07 +02001283 line = get_tv_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001284 li = li->li_next;
1285 }
1286
Bram Moolenaarca851592018-06-06 21:04:07 +02001287 rettv->vval.v_number = 1; /* FAIL */
1288 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1289 break;
1290
1291 /* When coming here from Insert mode, sync undo, so that this can be
1292 * undone separately from what was previously inserted. */
1293 if (u_sync_once == 2)
1294 {
1295 u_sync_once = 1; /* notify that u_sync() was called */
1296 u_sync(TRUE);
1297 }
1298
1299 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1300 {
1301 /* existing line, replace it */
1302 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1303 {
1304 changed_bytes(lnum, 0);
1305 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1306 check_cursor_col();
1307 rettv->vval.v_number = 0; /* OK */
1308 }
1309 }
1310 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1311 {
1312 /* append the line */
1313 ++added;
1314 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1315 rettv->vval.v_number = 0; /* OK */
1316 }
1317
1318 if (l == NULL) /* only one string argument */
1319 break;
1320 ++lnum;
1321 }
1322
1323 if (added > 0)
1324 {
1325 win_T *wp;
1326 tabpage_T *tp;
1327
1328 appended_lines_mark(append_lnum, added);
1329 FOR_ALL_TAB_WINDOWS(tp, wp)
1330 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1331 wp->w_cursor.lnum += added;
1332 check_cursor_col();
1333
Bram Moolenaarf2732452018-06-03 14:47:35 +02001334#ifdef FEAT_JOB_CHANNEL
1335 if (bt_prompt(curbuf) && (State & INSERT))
1336 // show the line with the prompt
1337 update_topline();
1338#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001339 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001340
1341 if (!is_curbuf)
1342 {
1343 curbuf = curbuf_save;
1344 curwin = curwin_save;
1345 }
1346}
1347
1348/*
1349 * "append(lnum, string/list)" function
1350 */
1351 static void
1352f_append(typval_T *argvars, typval_T *rettv)
1353{
1354 linenr_T lnum = get_tv_lnum(&argvars[0]);
1355
1356 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1357}
1358
1359/*
1360 * "appendbufline(buf, lnum, string/list)" function
1361 */
1362 static void
1363f_appendbufline(typval_T *argvars, typval_T *rettv)
1364{
1365 linenr_T lnum;
1366 buf_T *buf;
1367
1368 buf = get_buf_tv(&argvars[0], FALSE);
1369 if (buf == NULL)
1370 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001371 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001372 {
1373 lnum = get_tv_lnum_buf(&argvars[1], buf);
1374 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1375 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376}
1377
1378/*
1379 * "argc()" function
1380 */
1381 static void
1382f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1383{
1384 rettv->vval.v_number = ARGCOUNT;
1385}
1386
1387/*
1388 * "argidx()" function
1389 */
1390 static void
1391f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1392{
1393 rettv->vval.v_number = curwin->w_arg_idx;
1394}
1395
1396/*
1397 * "arglistid()" function
1398 */
1399 static void
1400f_arglistid(typval_T *argvars, typval_T *rettv)
1401{
1402 win_T *wp;
1403
1404 rettv->vval.v_number = -1;
1405 wp = find_tabwin(&argvars[0], &argvars[1]);
1406 if (wp != NULL)
1407 rettv->vval.v_number = wp->w_alist->id;
1408}
1409
1410/*
1411 * "argv(nr)" function
1412 */
1413 static void
1414f_argv(typval_T *argvars, typval_T *rettv)
1415{
1416 int idx;
1417
1418 if (argvars[0].v_type != VAR_UNKNOWN)
1419 {
1420 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1421 if (idx >= 0 && idx < ARGCOUNT)
1422 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1423 else
1424 rettv->vval.v_string = NULL;
1425 rettv->v_type = VAR_STRING;
1426 }
1427 else if (rettv_list_alloc(rettv) == OK)
1428 for (idx = 0; idx < ARGCOUNT; ++idx)
1429 list_append_string(rettv->vval.v_list,
1430 alist_name(&ARGLIST[idx]), -1);
1431}
1432
1433/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001434 * "assert_beeps(cmd [, error])" function
1435 */
1436 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001437f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001438{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001439 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001440}
1441
1442/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001443 * "assert_equal(expected, actual[, msg])" function
1444 */
1445 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001446f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001447{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001448 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001449}
1450
1451/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001452 * "assert_equalfile(fname-one, fname-two)" function
1453 */
1454 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001455f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001456{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001457 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001458}
1459
1460/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001461 * "assert_notequal(expected, actual[, msg])" function
1462 */
1463 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001464f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001465{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001466 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001467}
1468
1469/*
1470 * "assert_exception(string[, msg])" function
1471 */
1472 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001473f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001474{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001475 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001476}
1477
1478/*
1479 * "assert_fails(cmd [, error])" function
1480 */
1481 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001482f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001484 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001485}
1486
1487/*
1488 * "assert_false(actual[, msg])" function
1489 */
1490 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001491f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001492{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001493 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001494}
1495
1496/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001497 * "assert_inrange(lower, upper[, msg])" function
1498 */
1499 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001500f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001501{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001502 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001503}
1504
1505/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506 * "assert_match(pattern, actual[, msg])" function
1507 */
1508 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001509f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001510{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001511 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512}
1513
1514/*
1515 * "assert_notmatch(pattern, actual[, msg])" function
1516 */
1517 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001518f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001519{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001520 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001521}
1522
1523/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001524 * "assert_report(msg)" function
1525 */
1526 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001527f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001528{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001529 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001530}
1531
1532/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533 * "assert_true(actual[, msg])" function
1534 */
1535 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001536f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001537{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001538 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001539}
1540
1541#ifdef FEAT_FLOAT
1542/*
1543 * "asin()" function
1544 */
1545 static void
1546f_asin(typval_T *argvars, typval_T *rettv)
1547{
1548 float_T f = 0.0;
1549
1550 rettv->v_type = VAR_FLOAT;
1551 if (get_float_arg(argvars, &f) == OK)
1552 rettv->vval.v_float = asin(f);
1553 else
1554 rettv->vval.v_float = 0.0;
1555}
1556
1557/*
1558 * "atan()" function
1559 */
1560 static void
1561f_atan(typval_T *argvars, typval_T *rettv)
1562{
1563 float_T f = 0.0;
1564
1565 rettv->v_type = VAR_FLOAT;
1566 if (get_float_arg(argvars, &f) == OK)
1567 rettv->vval.v_float = atan(f);
1568 else
1569 rettv->vval.v_float = 0.0;
1570}
1571
1572/*
1573 * "atan2()" function
1574 */
1575 static void
1576f_atan2(typval_T *argvars, typval_T *rettv)
1577{
1578 float_T fx = 0.0, fy = 0.0;
1579
1580 rettv->v_type = VAR_FLOAT;
1581 if (get_float_arg(argvars, &fx) == OK
1582 && get_float_arg(&argvars[1], &fy) == OK)
1583 rettv->vval.v_float = atan2(fx, fy);
1584 else
1585 rettv->vval.v_float = 0.0;
1586}
1587#endif
1588
1589/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001590 * "balloon_show()" function
1591 */
1592#ifdef FEAT_BEVAL
1593 static void
1594f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1595{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001596 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001597 {
1598 if (argvars[0].v_type == VAR_LIST
1599# ifdef FEAT_GUI
1600 && !gui.in_use
1601# endif
1602 )
1603 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1604 else
1605 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1606 }
1607}
1608
Bram Moolenaar669a8282017-11-19 20:13:05 +01001609# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001610 static void
1611f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1612{
1613 if (rettv_list_alloc(rettv) == OK)
1614 {
1615 char_u *msg = get_tv_string_chk(&argvars[0]);
1616
1617 if (msg != NULL)
1618 {
1619 pumitem_T *array;
1620 int size = split_message(msg, &array);
1621 int i;
1622
1623 /* Skip the first and last item, they are always empty. */
1624 for (i = 1; i < size - 1; ++i)
1625 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001626 while (size > 0)
1627 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001628 vim_free(array);
1629 }
1630 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001631}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001632# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001633#endif
1634
1635/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001636 * "browse(save, title, initdir, default)" function
1637 */
1638 static void
1639f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1640{
1641#ifdef FEAT_BROWSE
1642 int save;
1643 char_u *title;
1644 char_u *initdir;
1645 char_u *defname;
1646 char_u buf[NUMBUFLEN];
1647 char_u buf2[NUMBUFLEN];
1648 int error = FALSE;
1649
1650 save = (int)get_tv_number_chk(&argvars[0], &error);
1651 title = get_tv_string_chk(&argvars[1]);
1652 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1653 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1654
1655 if (error || title == NULL || initdir == NULL || defname == NULL)
1656 rettv->vval.v_string = NULL;
1657 else
1658 rettv->vval.v_string =
1659 do_browse(save ? BROWSE_SAVE : 0,
1660 title, defname, NULL, initdir, NULL, curbuf);
1661#else
1662 rettv->vval.v_string = NULL;
1663#endif
1664 rettv->v_type = VAR_STRING;
1665}
1666
1667/*
1668 * "browsedir(title, initdir)" function
1669 */
1670 static void
1671f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1672{
1673#ifdef FEAT_BROWSE
1674 char_u *title;
1675 char_u *initdir;
1676 char_u buf[NUMBUFLEN];
1677
1678 title = get_tv_string_chk(&argvars[0]);
1679 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1680
1681 if (title == NULL || initdir == NULL)
1682 rettv->vval.v_string = NULL;
1683 else
1684 rettv->vval.v_string = do_browse(BROWSE_DIR,
1685 title, NULL, NULL, initdir, NULL, curbuf);
1686#else
1687 rettv->vval.v_string = NULL;
1688#endif
1689 rettv->v_type = VAR_STRING;
1690}
1691
1692static buf_T *find_buffer(typval_T *avar);
1693
1694/*
1695 * Find a buffer by number or exact name.
1696 */
1697 static buf_T *
1698find_buffer(typval_T *avar)
1699{
1700 buf_T *buf = NULL;
1701
1702 if (avar->v_type == VAR_NUMBER)
1703 buf = buflist_findnr((int)avar->vval.v_number);
1704 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1705 {
1706 buf = buflist_findname_exp(avar->vval.v_string);
1707 if (buf == NULL)
1708 {
1709 /* No full path name match, try a match with a URL or a "nofile"
1710 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001711 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 if (buf->b_fname != NULL
1713 && (path_with_url(buf->b_fname)
1714#ifdef FEAT_QUICKFIX
1715 || bt_nofile(buf)
1716#endif
1717 )
1718 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1719 break;
1720 }
1721 }
1722 return buf;
1723}
1724
1725/*
1726 * "bufexists(expr)" function
1727 */
1728 static void
1729f_bufexists(typval_T *argvars, typval_T *rettv)
1730{
1731 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1732}
1733
1734/*
1735 * "buflisted(expr)" function
1736 */
1737 static void
1738f_buflisted(typval_T *argvars, typval_T *rettv)
1739{
1740 buf_T *buf;
1741
1742 buf = find_buffer(&argvars[0]);
1743 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1744}
1745
1746/*
1747 * "bufloaded(expr)" function
1748 */
1749 static void
1750f_bufloaded(typval_T *argvars, typval_T *rettv)
1751{
1752 buf_T *buf;
1753
1754 buf = find_buffer(&argvars[0]);
1755 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1756}
1757
1758 buf_T *
1759buflist_find_by_name(char_u *name, int curtab_only)
1760{
1761 int save_magic;
1762 char_u *save_cpo;
1763 buf_T *buf;
1764
1765 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1766 save_magic = p_magic;
1767 p_magic = TRUE;
1768 save_cpo = p_cpo;
1769 p_cpo = (char_u *)"";
1770
1771 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1772 TRUE, FALSE, curtab_only));
1773
1774 p_magic = save_magic;
1775 p_cpo = save_cpo;
1776 return buf;
1777}
1778
1779/*
1780 * Get buffer by number or pattern.
1781 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001782 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001783get_buf_tv(typval_T *tv, int curtab_only)
1784{
1785 char_u *name = tv->vval.v_string;
1786 buf_T *buf;
1787
1788 if (tv->v_type == VAR_NUMBER)
1789 return buflist_findnr((int)tv->vval.v_number);
1790 if (tv->v_type != VAR_STRING)
1791 return NULL;
1792 if (name == NULL || *name == NUL)
1793 return curbuf;
1794 if (name[0] == '$' && name[1] == NUL)
1795 return lastbuf;
1796
1797 buf = buflist_find_by_name(name, curtab_only);
1798
1799 /* If not found, try expanding the name, like done for bufexists(). */
1800 if (buf == NULL)
1801 buf = find_buffer(tv);
1802
1803 return buf;
1804}
1805
1806/*
1807 * "bufname(expr)" function
1808 */
1809 static void
1810f_bufname(typval_T *argvars, typval_T *rettv)
1811{
1812 buf_T *buf;
1813
1814 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1815 ++emsg_off;
1816 buf = get_buf_tv(&argvars[0], FALSE);
1817 rettv->v_type = VAR_STRING;
1818 if (buf != NULL && buf->b_fname != NULL)
1819 rettv->vval.v_string = vim_strsave(buf->b_fname);
1820 else
1821 rettv->vval.v_string = NULL;
1822 --emsg_off;
1823}
1824
1825/*
1826 * "bufnr(expr)" function
1827 */
1828 static void
1829f_bufnr(typval_T *argvars, typval_T *rettv)
1830{
1831 buf_T *buf;
1832 int error = FALSE;
1833 char_u *name;
1834
1835 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1836 ++emsg_off;
1837 buf = get_buf_tv(&argvars[0], FALSE);
1838 --emsg_off;
1839
1840 /* If the buffer isn't found and the second argument is not zero create a
1841 * new buffer. */
1842 if (buf == NULL
1843 && argvars[1].v_type != VAR_UNKNOWN
1844 && get_tv_number_chk(&argvars[1], &error) != 0
1845 && !error
1846 && (name = get_tv_string_chk(&argvars[0])) != NULL
1847 && !error)
1848 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1849
1850 if (buf != NULL)
1851 rettv->vval.v_number = buf->b_fnum;
1852 else
1853 rettv->vval.v_number = -1;
1854}
1855
1856 static void
1857buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1858{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001859 win_T *wp;
1860 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001861 buf_T *buf;
1862
1863 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1864 ++emsg_off;
1865 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001866 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001867 {
1868 ++winnr;
1869 if (wp->w_buffer == buf)
1870 break;
1871 }
1872 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001873 --emsg_off;
1874}
1875
1876/*
1877 * "bufwinid(nr)" function
1878 */
1879 static void
1880f_bufwinid(typval_T *argvars, typval_T *rettv)
1881{
1882 buf_win_common(argvars, rettv, FALSE);
1883}
1884
1885/*
1886 * "bufwinnr(nr)" function
1887 */
1888 static void
1889f_bufwinnr(typval_T *argvars, typval_T *rettv)
1890{
1891 buf_win_common(argvars, rettv, TRUE);
1892}
1893
1894/*
1895 * "byte2line(byte)" function
1896 */
1897 static void
1898f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1899{
1900#ifndef FEAT_BYTEOFF
1901 rettv->vval.v_number = -1;
1902#else
1903 long boff = 0;
1904
1905 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1906 if (boff < 0)
1907 rettv->vval.v_number = -1;
1908 else
1909 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1910 (linenr_T)0, &boff);
1911#endif
1912}
1913
1914 static void
1915byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1916{
1917#ifdef FEAT_MBYTE
1918 char_u *t;
1919#endif
1920 char_u *str;
1921 varnumber_T idx;
1922
1923 str = get_tv_string_chk(&argvars[0]);
1924 idx = get_tv_number_chk(&argvars[1], NULL);
1925 rettv->vval.v_number = -1;
1926 if (str == NULL || idx < 0)
1927 return;
1928
1929#ifdef FEAT_MBYTE
1930 t = str;
1931 for ( ; idx > 0; idx--)
1932 {
1933 if (*t == NUL) /* EOL reached */
1934 return;
1935 if (enc_utf8 && comp)
1936 t += utf_ptr2len(t);
1937 else
1938 t += (*mb_ptr2len)(t);
1939 }
1940 rettv->vval.v_number = (varnumber_T)(t - str);
1941#else
1942 if ((size_t)idx <= STRLEN(str))
1943 rettv->vval.v_number = idx;
1944#endif
1945}
1946
1947/*
1948 * "byteidx()" function
1949 */
1950 static void
1951f_byteidx(typval_T *argvars, typval_T *rettv)
1952{
1953 byteidx(argvars, rettv, FALSE);
1954}
1955
1956/*
1957 * "byteidxcomp()" function
1958 */
1959 static void
1960f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1961{
1962 byteidx(argvars, rettv, TRUE);
1963}
1964
1965/*
1966 * "call(func, arglist [, dict])" function
1967 */
1968 static void
1969f_call(typval_T *argvars, typval_T *rettv)
1970{
1971 char_u *func;
1972 partial_T *partial = NULL;
1973 dict_T *selfdict = NULL;
1974
1975 if (argvars[1].v_type != VAR_LIST)
1976 {
1977 EMSG(_(e_listreq));
1978 return;
1979 }
1980 if (argvars[1].vval.v_list == NULL)
1981 return;
1982
1983 if (argvars[0].v_type == VAR_FUNC)
1984 func = argvars[0].vval.v_string;
1985 else if (argvars[0].v_type == VAR_PARTIAL)
1986 {
1987 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001988 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989 }
1990 else
1991 func = get_tv_string(&argvars[0]);
1992 if (*func == NUL)
1993 return; /* type error or empty name */
1994
1995 if (argvars[2].v_type != VAR_UNKNOWN)
1996 {
1997 if (argvars[2].v_type != VAR_DICT)
1998 {
1999 EMSG(_(e_dictreq));
2000 return;
2001 }
2002 selfdict = argvars[2].vval.v_dict;
2003 }
2004
2005 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2006}
2007
2008#ifdef FEAT_FLOAT
2009/*
2010 * "ceil({float})" function
2011 */
2012 static void
2013f_ceil(typval_T *argvars, typval_T *rettv)
2014{
2015 float_T f = 0.0;
2016
2017 rettv->v_type = VAR_FLOAT;
2018 if (get_float_arg(argvars, &f) == OK)
2019 rettv->vval.v_float = ceil(f);
2020 else
2021 rettv->vval.v_float = 0.0;
2022}
2023#endif
2024
2025#ifdef FEAT_JOB_CHANNEL
2026/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002027 * "ch_canread()" function
2028 */
2029 static void
2030f_ch_canread(typval_T *argvars, typval_T *rettv)
2031{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002032 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002033
2034 rettv->vval.v_number = 0;
2035 if (channel != NULL)
2036 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2037 || channel_has_readahead(channel, PART_OUT)
2038 || channel_has_readahead(channel, PART_ERR);
2039}
2040
2041/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002042 * "ch_close()" function
2043 */
2044 static void
2045f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2046{
2047 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2048
2049 if (channel != NULL)
2050 {
2051 channel_close(channel, FALSE);
2052 channel_clear(channel);
2053 }
2054}
2055
2056/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002057 * "ch_close()" function
2058 */
2059 static void
2060f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2061{
2062 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2063
2064 if (channel != NULL)
2065 channel_close_in(channel);
2066}
2067
2068/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002069 * "ch_getbufnr()" function
2070 */
2071 static void
2072f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2073{
2074 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2075
2076 rettv->vval.v_number = -1;
2077 if (channel != NULL)
2078 {
2079 char_u *what = get_tv_string(&argvars[1]);
2080 int part;
2081
2082 if (STRCMP(what, "err") == 0)
2083 part = PART_ERR;
2084 else if (STRCMP(what, "out") == 0)
2085 part = PART_OUT;
2086 else if (STRCMP(what, "in") == 0)
2087 part = PART_IN;
2088 else
2089 part = PART_SOCK;
2090 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2091 rettv->vval.v_number =
2092 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2093 }
2094}
2095
2096/*
2097 * "ch_getjob()" function
2098 */
2099 static void
2100f_ch_getjob(typval_T *argvars, typval_T *rettv)
2101{
2102 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2103
2104 if (channel != NULL)
2105 {
2106 rettv->v_type = VAR_JOB;
2107 rettv->vval.v_job = channel->ch_job;
2108 if (channel->ch_job != NULL)
2109 ++channel->ch_job->jv_refcount;
2110 }
2111}
2112
2113/*
2114 * "ch_info()" function
2115 */
2116 static void
2117f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2118{
2119 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2120
2121 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2122 channel_info(channel, rettv->vval.v_dict);
2123}
2124
2125/*
2126 * "ch_log()" function
2127 */
2128 static void
2129f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2130{
2131 char_u *msg = get_tv_string(&argvars[0]);
2132 channel_T *channel = NULL;
2133
2134 if (argvars[1].v_type != VAR_UNKNOWN)
2135 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2136
Bram Moolenaard5359b22018-04-05 22:44:39 +02002137 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138}
2139
2140/*
2141 * "ch_logfile()" function
2142 */
2143 static void
2144f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2145{
2146 char_u *fname;
2147 char_u *opt = (char_u *)"";
2148 char_u buf[NUMBUFLEN];
2149
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002150 /* Don't open a file in restricted mode. */
2151 if (check_restricted() || check_secure())
2152 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 fname = get_tv_string(&argvars[0]);
2154 if (argvars[1].v_type == VAR_STRING)
2155 opt = get_tv_string_buf(&argvars[1], buf);
2156 ch_logfile(fname, opt);
2157}
2158
2159/*
2160 * "ch_open()" function
2161 */
2162 static void
2163f_ch_open(typval_T *argvars, typval_T *rettv)
2164{
2165 rettv->v_type = VAR_CHANNEL;
2166 if (check_restricted() || check_secure())
2167 return;
2168 rettv->vval.v_channel = channel_open_func(argvars);
2169}
2170
2171/*
2172 * "ch_read()" function
2173 */
2174 static void
2175f_ch_read(typval_T *argvars, typval_T *rettv)
2176{
2177 common_channel_read(argvars, rettv, FALSE);
2178}
2179
2180/*
2181 * "ch_readraw()" function
2182 */
2183 static void
2184f_ch_readraw(typval_T *argvars, typval_T *rettv)
2185{
2186 common_channel_read(argvars, rettv, TRUE);
2187}
2188
2189/*
2190 * "ch_evalexpr()" function
2191 */
2192 static void
2193f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2194{
2195 ch_expr_common(argvars, rettv, TRUE);
2196}
2197
2198/*
2199 * "ch_sendexpr()" function
2200 */
2201 static void
2202f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2203{
2204 ch_expr_common(argvars, rettv, FALSE);
2205}
2206
2207/*
2208 * "ch_evalraw()" function
2209 */
2210 static void
2211f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2212{
2213 ch_raw_common(argvars, rettv, TRUE);
2214}
2215
2216/*
2217 * "ch_sendraw()" function
2218 */
2219 static void
2220f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2221{
2222 ch_raw_common(argvars, rettv, FALSE);
2223}
2224
2225/*
2226 * "ch_setoptions()" function
2227 */
2228 static void
2229f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2230{
2231 channel_T *channel;
2232 jobopt_T opt;
2233
2234 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2235 if (channel == NULL)
2236 return;
2237 clear_job_options(&opt);
2238 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002239 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002240 channel_set_options(channel, &opt);
2241 free_job_options(&opt);
2242}
2243
2244/*
2245 * "ch_status()" function
2246 */
2247 static void
2248f_ch_status(typval_T *argvars, typval_T *rettv)
2249{
2250 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002251 jobopt_T opt;
2252 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002253
2254 /* return an empty string by default */
2255 rettv->v_type = VAR_STRING;
2256 rettv->vval.v_string = NULL;
2257
2258 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002259
2260 if (argvars[1].v_type != VAR_UNKNOWN)
2261 {
2262 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002263 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002264 && (opt.jo_set & JO_PART))
2265 part = opt.jo_part;
2266 }
2267
2268 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269}
2270#endif
2271
2272/*
2273 * "changenr()" function
2274 */
2275 static void
2276f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2277{
2278 rettv->vval.v_number = curbuf->b_u_seq_cur;
2279}
2280
2281/*
2282 * "char2nr(string)" function
2283 */
2284 static void
2285f_char2nr(typval_T *argvars, typval_T *rettv)
2286{
2287#ifdef FEAT_MBYTE
2288 if (has_mbyte)
2289 {
2290 int utf8 = 0;
2291
2292 if (argvars[1].v_type != VAR_UNKNOWN)
2293 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2294
2295 if (utf8)
2296 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2297 else
2298 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2299 }
2300 else
2301#endif
2302 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2303}
2304
2305/*
2306 * "cindent(lnum)" function
2307 */
2308 static void
2309f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2310{
2311#ifdef FEAT_CINDENT
2312 pos_T pos;
2313 linenr_T lnum;
2314
2315 pos = curwin->w_cursor;
2316 lnum = get_tv_lnum(argvars);
2317 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2318 {
2319 curwin->w_cursor.lnum = lnum;
2320 rettv->vval.v_number = get_c_indent();
2321 curwin->w_cursor = pos;
2322 }
2323 else
2324#endif
2325 rettv->vval.v_number = -1;
2326}
2327
2328/*
2329 * "clearmatches()" function
2330 */
2331 static void
2332f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2333{
2334#ifdef FEAT_SEARCH_EXTRA
2335 clear_matches(curwin);
2336#endif
2337}
2338
2339/*
2340 * "col(string)" function
2341 */
2342 static void
2343f_col(typval_T *argvars, typval_T *rettv)
2344{
2345 colnr_T col = 0;
2346 pos_T *fp;
2347 int fnum = curbuf->b_fnum;
2348
2349 fp = var2fpos(&argvars[0], FALSE, &fnum);
2350 if (fp != NULL && fnum == curbuf->b_fnum)
2351 {
2352 if (fp->col == MAXCOL)
2353 {
2354 /* '> can be MAXCOL, get the length of the line then */
2355 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2356 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2357 else
2358 col = MAXCOL;
2359 }
2360 else
2361 {
2362 col = fp->col + 1;
2363#ifdef FEAT_VIRTUALEDIT
2364 /* col(".") when the cursor is on the NUL at the end of the line
2365 * because of "coladd" can be seen as an extra column. */
2366 if (virtual_active() && fp == &curwin->w_cursor)
2367 {
2368 char_u *p = ml_get_cursor();
2369
2370 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2371 curwin->w_virtcol - curwin->w_cursor.coladd))
2372 {
2373# ifdef FEAT_MBYTE
2374 int l;
2375
2376 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2377 col += l;
2378# else
2379 if (*p != NUL && p[1] == NUL)
2380 ++col;
2381# endif
2382 }
2383 }
2384#endif
2385 }
2386 }
2387 rettv->vval.v_number = col;
2388}
2389
2390#if defined(FEAT_INS_EXPAND)
2391/*
2392 * "complete()" function
2393 */
2394 static void
2395f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2396{
2397 int startcol;
2398
2399 if ((State & INSERT) == 0)
2400 {
2401 EMSG(_("E785: complete() can only be used in Insert mode"));
2402 return;
2403 }
2404
2405 /* Check for undo allowed here, because if something was already inserted
2406 * the line was already saved for undo and this check isn't done. */
2407 if (!undo_allowed())
2408 return;
2409
2410 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2411 {
2412 EMSG(_(e_invarg));
2413 return;
2414 }
2415
2416 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2417 if (startcol <= 0)
2418 return;
2419
2420 set_completion(startcol - 1, argvars[1].vval.v_list);
2421}
2422
2423/*
2424 * "complete_add()" function
2425 */
2426 static void
2427f_complete_add(typval_T *argvars, typval_T *rettv)
2428{
2429 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2430}
2431
2432/*
2433 * "complete_check()" function
2434 */
2435 static void
2436f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2437{
2438 int saved = RedrawingDisabled;
2439
2440 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002441 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 rettv->vval.v_number = compl_interrupted;
2443 RedrawingDisabled = saved;
2444}
2445#endif
2446
2447/*
2448 * "confirm(message, buttons[, default [, type]])" function
2449 */
2450 static void
2451f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2452{
2453#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2454 char_u *message;
2455 char_u *buttons = NULL;
2456 char_u buf[NUMBUFLEN];
2457 char_u buf2[NUMBUFLEN];
2458 int def = 1;
2459 int type = VIM_GENERIC;
2460 char_u *typestr;
2461 int error = FALSE;
2462
2463 message = get_tv_string_chk(&argvars[0]);
2464 if (message == NULL)
2465 error = TRUE;
2466 if (argvars[1].v_type != VAR_UNKNOWN)
2467 {
2468 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2469 if (buttons == NULL)
2470 error = TRUE;
2471 if (argvars[2].v_type != VAR_UNKNOWN)
2472 {
2473 def = (int)get_tv_number_chk(&argvars[2], &error);
2474 if (argvars[3].v_type != VAR_UNKNOWN)
2475 {
2476 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2477 if (typestr == NULL)
2478 error = TRUE;
2479 else
2480 {
2481 switch (TOUPPER_ASC(*typestr))
2482 {
2483 case 'E': type = VIM_ERROR; break;
2484 case 'Q': type = VIM_QUESTION; break;
2485 case 'I': type = VIM_INFO; break;
2486 case 'W': type = VIM_WARNING; break;
2487 case 'G': type = VIM_GENERIC; break;
2488 }
2489 }
2490 }
2491 }
2492 }
2493
2494 if (buttons == NULL || *buttons == NUL)
2495 buttons = (char_u *)_("&Ok");
2496
2497 if (!error)
2498 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2499 def, NULL, FALSE);
2500#endif
2501}
2502
2503/*
2504 * "copy()" function
2505 */
2506 static void
2507f_copy(typval_T *argvars, typval_T *rettv)
2508{
2509 item_copy(&argvars[0], rettv, FALSE, 0);
2510}
2511
2512#ifdef FEAT_FLOAT
2513/*
2514 * "cos()" function
2515 */
2516 static void
2517f_cos(typval_T *argvars, typval_T *rettv)
2518{
2519 float_T f = 0.0;
2520
2521 rettv->v_type = VAR_FLOAT;
2522 if (get_float_arg(argvars, &f) == OK)
2523 rettv->vval.v_float = cos(f);
2524 else
2525 rettv->vval.v_float = 0.0;
2526}
2527
2528/*
2529 * "cosh()" function
2530 */
2531 static void
2532f_cosh(typval_T *argvars, typval_T *rettv)
2533{
2534 float_T f = 0.0;
2535
2536 rettv->v_type = VAR_FLOAT;
2537 if (get_float_arg(argvars, &f) == OK)
2538 rettv->vval.v_float = cosh(f);
2539 else
2540 rettv->vval.v_float = 0.0;
2541}
2542#endif
2543
2544/*
2545 * "count()" function
2546 */
2547 static void
2548f_count(typval_T *argvars, typval_T *rettv)
2549{
2550 long n = 0;
2551 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002552 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002553
Bram Moolenaar9966b212017-07-28 16:46:57 +02002554 if (argvars[2].v_type != VAR_UNKNOWN)
2555 ic = (int)get_tv_number_chk(&argvars[2], &error);
2556
2557 if (argvars[0].v_type == VAR_STRING)
2558 {
2559 char_u *expr = get_tv_string_chk(&argvars[1]);
2560 char_u *p = argvars[0].vval.v_string;
2561 char_u *next;
2562
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002563 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002564 {
2565 if (ic)
2566 {
2567 size_t len = STRLEN(expr);
2568
2569 while (*p != NUL)
2570 {
2571 if (MB_STRNICMP(p, expr, len) == 0)
2572 {
2573 ++n;
2574 p += len;
2575 }
2576 else
2577 MB_PTR_ADV(p);
2578 }
2579 }
2580 else
2581 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2582 != NULL)
2583 {
2584 ++n;
2585 p = next + STRLEN(expr);
2586 }
2587 }
2588
2589 }
2590 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591 {
2592 listitem_T *li;
2593 list_T *l;
2594 long idx;
2595
2596 if ((l = argvars[0].vval.v_list) != NULL)
2597 {
2598 li = l->lv_first;
2599 if (argvars[2].v_type != VAR_UNKNOWN)
2600 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601 if (argvars[3].v_type != VAR_UNKNOWN)
2602 {
2603 idx = (long)get_tv_number_chk(&argvars[3], &error);
2604 if (!error)
2605 {
2606 li = list_find(l, idx);
2607 if (li == NULL)
2608 EMSGN(_(e_listidx), idx);
2609 }
2610 }
2611 if (error)
2612 li = NULL;
2613 }
2614
2615 for ( ; li != NULL; li = li->li_next)
2616 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2617 ++n;
2618 }
2619 }
2620 else if (argvars[0].v_type == VAR_DICT)
2621 {
2622 int todo;
2623 dict_T *d;
2624 hashitem_T *hi;
2625
2626 if ((d = argvars[0].vval.v_dict) != NULL)
2627 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002628 if (argvars[2].v_type != VAR_UNKNOWN)
2629 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002630 if (argvars[3].v_type != VAR_UNKNOWN)
2631 EMSG(_(e_invarg));
2632 }
2633
2634 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2635 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2636 {
2637 if (!HASHITEM_EMPTY(hi))
2638 {
2639 --todo;
2640 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2641 ++n;
2642 }
2643 }
2644 }
2645 }
2646 else
2647 EMSG2(_(e_listdictarg), "count()");
2648 rettv->vval.v_number = n;
2649}
2650
2651/*
2652 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2653 *
2654 * Checks the existence of a cscope connection.
2655 */
2656 static void
2657f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2658{
2659#ifdef FEAT_CSCOPE
2660 int num = 0;
2661 char_u *dbpath = NULL;
2662 char_u *prepend = NULL;
2663 char_u buf[NUMBUFLEN];
2664
2665 if (argvars[0].v_type != VAR_UNKNOWN
2666 && argvars[1].v_type != VAR_UNKNOWN)
2667 {
2668 num = (int)get_tv_number(&argvars[0]);
2669 dbpath = get_tv_string(&argvars[1]);
2670 if (argvars[2].v_type != VAR_UNKNOWN)
2671 prepend = get_tv_string_buf(&argvars[2], buf);
2672 }
2673
2674 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2675#endif
2676}
2677
2678/*
2679 * "cursor(lnum, col)" function, or
2680 * "cursor(list)"
2681 *
2682 * Moves the cursor to the specified line and column.
2683 * Returns 0 when the position could be set, -1 otherwise.
2684 */
2685 static void
2686f_cursor(typval_T *argvars, typval_T *rettv)
2687{
2688 long line, col;
2689#ifdef FEAT_VIRTUALEDIT
2690 long coladd = 0;
2691#endif
2692 int set_curswant = TRUE;
2693
2694 rettv->vval.v_number = -1;
2695 if (argvars[1].v_type == VAR_UNKNOWN)
2696 {
2697 pos_T pos;
2698 colnr_T curswant = -1;
2699
2700 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2701 {
2702 EMSG(_(e_invarg));
2703 return;
2704 }
2705 line = pos.lnum;
2706 col = pos.col;
2707#ifdef FEAT_VIRTUALEDIT
2708 coladd = pos.coladd;
2709#endif
2710 if (curswant >= 0)
2711 {
2712 curwin->w_curswant = curswant - 1;
2713 set_curswant = FALSE;
2714 }
2715 }
2716 else
2717 {
2718 line = get_tv_lnum(argvars);
2719 col = (long)get_tv_number_chk(&argvars[1], NULL);
2720#ifdef FEAT_VIRTUALEDIT
2721 if (argvars[2].v_type != VAR_UNKNOWN)
2722 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2723#endif
2724 }
2725 if (line < 0 || col < 0
2726#ifdef FEAT_VIRTUALEDIT
2727 || coladd < 0
2728#endif
2729 )
2730 return; /* type error; errmsg already given */
2731 if (line > 0)
2732 curwin->w_cursor.lnum = line;
2733 if (col > 0)
2734 curwin->w_cursor.col = col - 1;
2735#ifdef FEAT_VIRTUALEDIT
2736 curwin->w_cursor.coladd = coladd;
2737#endif
2738
2739 /* Make sure the cursor is in a valid position. */
2740 check_cursor();
2741#ifdef FEAT_MBYTE
2742 /* Correct cursor for multi-byte character. */
2743 if (has_mbyte)
2744 mb_adjust_cursor();
2745#endif
2746
2747 curwin->w_set_curswant = set_curswant;
2748 rettv->vval.v_number = 0;
2749}
2750
2751/*
2752 * "deepcopy()" function
2753 */
2754 static void
2755f_deepcopy(typval_T *argvars, typval_T *rettv)
2756{
2757 int noref = 0;
2758 int copyID;
2759
2760 if (argvars[1].v_type != VAR_UNKNOWN)
2761 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2762 if (noref < 0 || noref > 1)
2763 EMSG(_(e_invarg));
2764 else
2765 {
2766 copyID = get_copyID();
2767 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2768 }
2769}
2770
2771/*
2772 * "delete()" function
2773 */
2774 static void
2775f_delete(typval_T *argvars, typval_T *rettv)
2776{
2777 char_u nbuf[NUMBUFLEN];
2778 char_u *name;
2779 char_u *flags;
2780
2781 rettv->vval.v_number = -1;
2782 if (check_restricted() || check_secure())
2783 return;
2784
2785 name = get_tv_string(&argvars[0]);
2786 if (name == NULL || *name == NUL)
2787 {
2788 EMSG(_(e_invarg));
2789 return;
2790 }
2791
2792 if (argvars[1].v_type != VAR_UNKNOWN)
2793 flags = get_tv_string_buf(&argvars[1], nbuf);
2794 else
2795 flags = (char_u *)"";
2796
2797 if (*flags == NUL)
2798 /* delete a file */
2799 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2800 else if (STRCMP(flags, "d") == 0)
2801 /* delete an empty directory */
2802 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2803 else if (STRCMP(flags, "rf") == 0)
2804 /* delete a directory recursively */
2805 rettv->vval.v_number = delete_recursive(name);
2806 else
2807 EMSG2(_(e_invexpr2), flags);
2808}
2809
2810/*
2811 * "did_filetype()" function
2812 */
2813 static void
2814f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2815{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002816 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817}
2818
2819/*
2820 * "diff_filler()" function
2821 */
2822 static void
2823f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2824{
2825#ifdef FEAT_DIFF
2826 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2827#endif
2828}
2829
2830/*
2831 * "diff_hlID()" function
2832 */
2833 static void
2834f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2835{
2836#ifdef FEAT_DIFF
2837 linenr_T lnum = get_tv_lnum(argvars);
2838 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002839 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 static int fnum = 0;
2841 static int change_start = 0;
2842 static int change_end = 0;
2843 static hlf_T hlID = (hlf_T)0;
2844 int filler_lines;
2845 int col;
2846
2847 if (lnum < 0) /* ignore type error in {lnum} arg */
2848 lnum = 0;
2849 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002850 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851 || fnum != curbuf->b_fnum)
2852 {
2853 /* New line, buffer, change: need to get the values. */
2854 filler_lines = diff_check(curwin, lnum);
2855 if (filler_lines < 0)
2856 {
2857 if (filler_lines == -1)
2858 {
2859 change_start = MAXCOL;
2860 change_end = -1;
2861 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2862 hlID = HLF_ADD; /* added line */
2863 else
2864 hlID = HLF_CHD; /* changed line */
2865 }
2866 else
2867 hlID = HLF_ADD; /* added line */
2868 }
2869 else
2870 hlID = (hlf_T)0;
2871 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002872 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002873 fnum = curbuf->b_fnum;
2874 }
2875
2876 if (hlID == HLF_CHD || hlID == HLF_TXD)
2877 {
2878 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2879 if (col >= change_start && col <= change_end)
2880 hlID = HLF_TXD; /* changed text */
2881 else
2882 hlID = HLF_CHD; /* changed line */
2883 }
2884 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2885#endif
2886}
2887
2888/*
2889 * "empty({expr})" function
2890 */
2891 static void
2892f_empty(typval_T *argvars, typval_T *rettv)
2893{
2894 int n = FALSE;
2895
2896 switch (argvars[0].v_type)
2897 {
2898 case VAR_STRING:
2899 case VAR_FUNC:
2900 n = argvars[0].vval.v_string == NULL
2901 || *argvars[0].vval.v_string == NUL;
2902 break;
2903 case VAR_PARTIAL:
2904 n = FALSE;
2905 break;
2906 case VAR_NUMBER:
2907 n = argvars[0].vval.v_number == 0;
2908 break;
2909 case VAR_FLOAT:
2910#ifdef FEAT_FLOAT
2911 n = argvars[0].vval.v_float == 0.0;
2912 break;
2913#endif
2914 case VAR_LIST:
2915 n = argvars[0].vval.v_list == NULL
2916 || argvars[0].vval.v_list->lv_first == NULL;
2917 break;
2918 case VAR_DICT:
2919 n = argvars[0].vval.v_dict == NULL
2920 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2921 break;
2922 case VAR_SPECIAL:
2923 n = argvars[0].vval.v_number != VVAL_TRUE;
2924 break;
2925
2926 case VAR_JOB:
2927#ifdef FEAT_JOB_CHANNEL
2928 n = argvars[0].vval.v_job == NULL
2929 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2930 break;
2931#endif
2932 case VAR_CHANNEL:
2933#ifdef FEAT_JOB_CHANNEL
2934 n = argvars[0].vval.v_channel == NULL
2935 || !channel_is_open(argvars[0].vval.v_channel);
2936 break;
2937#endif
2938 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002939 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940 n = TRUE;
2941 break;
2942 }
2943
2944 rettv->vval.v_number = n;
2945}
2946
2947/*
2948 * "escape({string}, {chars})" function
2949 */
2950 static void
2951f_escape(typval_T *argvars, typval_T *rettv)
2952{
2953 char_u buf[NUMBUFLEN];
2954
2955 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2956 get_tv_string_buf(&argvars[1], buf));
2957 rettv->v_type = VAR_STRING;
2958}
2959
2960/*
2961 * "eval()" function
2962 */
2963 static void
2964f_eval(typval_T *argvars, typval_T *rettv)
2965{
2966 char_u *s, *p;
2967
2968 s = get_tv_string_chk(&argvars[0]);
2969 if (s != NULL)
2970 s = skipwhite(s);
2971
2972 p = s;
2973 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2974 {
2975 if (p != NULL && !aborting())
2976 EMSG2(_(e_invexpr2), p);
2977 need_clr_eos = FALSE;
2978 rettv->v_type = VAR_NUMBER;
2979 rettv->vval.v_number = 0;
2980 }
2981 else if (*s != NUL)
2982 EMSG(_(e_trailing));
2983}
2984
2985/*
2986 * "eventhandler()" function
2987 */
2988 static void
2989f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2990{
2991 rettv->vval.v_number = vgetc_busy;
2992}
2993
2994/*
2995 * "executable()" function
2996 */
2997 static void
2998f_executable(typval_T *argvars, typval_T *rettv)
2999{
3000 char_u *name = get_tv_string(&argvars[0]);
3001
3002 /* Check in $PATH and also check directly if there is a directory name. */
3003 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3004 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3005}
3006
3007static garray_T redir_execute_ga;
3008
3009/*
3010 * Append "value[value_len]" to the execute() output.
3011 */
3012 void
3013execute_redir_str(char_u *value, int value_len)
3014{
3015 int len;
3016
3017 if (value_len == -1)
3018 len = (int)STRLEN(value); /* Append the entire string */
3019 else
3020 len = value_len; /* Append only "value_len" characters */
3021 if (ga_grow(&redir_execute_ga, len) == OK)
3022 {
3023 mch_memmove((char *)redir_execute_ga.ga_data
3024 + redir_execute_ga.ga_len, value, len);
3025 redir_execute_ga.ga_len += len;
3026 }
3027}
3028
3029/*
3030 * Get next line from a list.
3031 * Called by do_cmdline() to get the next line.
3032 * Returns allocated string, or NULL for end of function.
3033 */
3034
3035 static char_u *
3036get_list_line(
3037 int c UNUSED,
3038 void *cookie,
3039 int indent UNUSED)
3040{
3041 listitem_T **p = (listitem_T **)cookie;
3042 listitem_T *item = *p;
3043 char_u buf[NUMBUFLEN];
3044 char_u *s;
3045
3046 if (item == NULL)
3047 return NULL;
3048 s = get_tv_string_buf_chk(&item->li_tv, buf);
3049 *p = item->li_next;
3050 return s == NULL ? NULL : vim_strsave(s);
3051}
3052
3053/*
3054 * "execute()" function
3055 */
3056 static void
3057f_execute(typval_T *argvars, typval_T *rettv)
3058{
3059 char_u *cmd = NULL;
3060 list_T *list = NULL;
3061 int save_msg_silent = msg_silent;
3062 int save_emsg_silent = emsg_silent;
3063 int save_emsg_noredir = emsg_noredir;
3064 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003065 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003066 garray_T save_ga;
3067
3068 rettv->vval.v_string = NULL;
3069 rettv->v_type = VAR_STRING;
3070
3071 if (argvars[0].v_type == VAR_LIST)
3072 {
3073 list = argvars[0].vval.v_list;
3074 if (list == NULL || list->lv_first == NULL)
3075 /* empty list, no commands, empty output */
3076 return;
3077 ++list->lv_refcount;
3078 }
3079 else
3080 {
3081 cmd = get_tv_string_chk(&argvars[0]);
3082 if (cmd == NULL)
3083 return;
3084 }
3085
3086 if (argvars[1].v_type != VAR_UNKNOWN)
3087 {
3088 char_u buf[NUMBUFLEN];
3089 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
3090
3091 if (s == NULL)
3092 return;
3093 if (STRNCMP(s, "silent", 6) == 0)
3094 ++msg_silent;
3095 if (STRCMP(s, "silent!") == 0)
3096 {
3097 emsg_silent = TRUE;
3098 emsg_noredir = TRUE;
3099 }
3100 }
3101 else
3102 ++msg_silent;
3103
3104 if (redir_execute)
3105 save_ga = redir_execute_ga;
3106 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3107 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003108 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003109
3110 if (cmd != NULL)
3111 do_cmdline_cmd(cmd);
3112 else
3113 {
3114 listitem_T *item = list->lv_first;
3115
3116 do_cmdline(NULL, get_list_line, (void *)&item,
3117 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3118 --list->lv_refcount;
3119 }
3120
Bram Moolenaard297f352017-01-29 20:31:21 +01003121 /* Need to append a NUL to the result. */
3122 if (ga_grow(&redir_execute_ga, 1) == OK)
3123 {
3124 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3125 rettv->vval.v_string = redir_execute_ga.ga_data;
3126 }
3127 else
3128 {
3129 ga_clear(&redir_execute_ga);
3130 rettv->vval.v_string = NULL;
3131 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003132 msg_silent = save_msg_silent;
3133 emsg_silent = save_emsg_silent;
3134 emsg_noredir = save_emsg_noredir;
3135
3136 redir_execute = save_redir_execute;
3137 if (redir_execute)
3138 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003139 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003140
3141 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3142 * line. Put it back in the first column. */
3143 msg_col = 0;
3144}
3145
3146/*
3147 * "exepath()" function
3148 */
3149 static void
3150f_exepath(typval_T *argvars, typval_T *rettv)
3151{
3152 char_u *p = NULL;
3153
3154 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3155 rettv->v_type = VAR_STRING;
3156 rettv->vval.v_string = p;
3157}
3158
3159/*
3160 * "exists()" function
3161 */
3162 static void
3163f_exists(typval_T *argvars, typval_T *rettv)
3164{
3165 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003166 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003167
3168 p = get_tv_string(&argvars[0]);
3169 if (*p == '$') /* environment variable */
3170 {
3171 /* first try "normal" environment variables (fast) */
3172 if (mch_getenv(p + 1) != NULL)
3173 n = TRUE;
3174 else
3175 {
3176 /* try expanding things like $VIM and ${HOME} */
3177 p = expand_env_save(p);
3178 if (p != NULL && *p != '$')
3179 n = TRUE;
3180 vim_free(p);
3181 }
3182 }
3183 else if (*p == '&' || *p == '+') /* option */
3184 {
3185 n = (get_option_tv(&p, NULL, TRUE) == OK);
3186 if (*skipwhite(p) != NUL)
3187 n = FALSE; /* trailing garbage */
3188 }
3189 else if (*p == '*') /* internal or user defined function */
3190 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003191 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003192 }
3193 else if (*p == ':')
3194 {
3195 n = cmd_exists(p + 1);
3196 }
3197 else if (*p == '#')
3198 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003199 if (p[1] == '#')
3200 n = autocmd_supported(p + 2);
3201 else
3202 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003203 }
3204 else /* internal variable */
3205 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003206 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003207 }
3208
3209 rettv->vval.v_number = n;
3210}
3211
3212#ifdef FEAT_FLOAT
3213/*
3214 * "exp()" function
3215 */
3216 static void
3217f_exp(typval_T *argvars, typval_T *rettv)
3218{
3219 float_T f = 0.0;
3220
3221 rettv->v_type = VAR_FLOAT;
3222 if (get_float_arg(argvars, &f) == OK)
3223 rettv->vval.v_float = exp(f);
3224 else
3225 rettv->vval.v_float = 0.0;
3226}
3227#endif
3228
3229/*
3230 * "expand()" function
3231 */
3232 static void
3233f_expand(typval_T *argvars, typval_T *rettv)
3234{
3235 char_u *s;
3236 int len;
3237 char_u *errormsg;
3238 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3239 expand_T xpc;
3240 int error = FALSE;
3241 char_u *result;
3242
3243 rettv->v_type = VAR_STRING;
3244 if (argvars[1].v_type != VAR_UNKNOWN
3245 && argvars[2].v_type != VAR_UNKNOWN
3246 && get_tv_number_chk(&argvars[2], &error)
3247 && !error)
3248 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003249 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003250 }
3251
3252 s = get_tv_string(&argvars[0]);
3253 if (*s == '%' || *s == '#' || *s == '<')
3254 {
3255 ++emsg_off;
3256 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3257 --emsg_off;
3258 if (rettv->v_type == VAR_LIST)
3259 {
3260 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3261 list_append_string(rettv->vval.v_list, result, -1);
3262 else
3263 vim_free(result);
3264 }
3265 else
3266 rettv->vval.v_string = result;
3267 }
3268 else
3269 {
3270 /* When the optional second argument is non-zero, don't remove matches
3271 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3272 if (argvars[1].v_type != VAR_UNKNOWN
3273 && get_tv_number_chk(&argvars[1], &error))
3274 options |= WILD_KEEP_ALL;
3275 if (!error)
3276 {
3277 ExpandInit(&xpc);
3278 xpc.xp_context = EXPAND_FILES;
3279 if (p_wic)
3280 options += WILD_ICASE;
3281 if (rettv->v_type == VAR_STRING)
3282 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3283 options, WILD_ALL);
3284 else if (rettv_list_alloc(rettv) != FAIL)
3285 {
3286 int i;
3287
3288 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3289 for (i = 0; i < xpc.xp_numfiles; i++)
3290 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3291 ExpandCleanup(&xpc);
3292 }
3293 }
3294 else
3295 rettv->vval.v_string = NULL;
3296 }
3297}
3298
3299/*
3300 * "extend(list, list [, idx])" function
3301 * "extend(dict, dict [, action])" function
3302 */
3303 static void
3304f_extend(typval_T *argvars, typval_T *rettv)
3305{
3306 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3307
3308 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3309 {
3310 list_T *l1, *l2;
3311 listitem_T *item;
3312 long before;
3313 int error = FALSE;
3314
3315 l1 = argvars[0].vval.v_list;
3316 l2 = argvars[1].vval.v_list;
3317 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3318 && l2 != NULL)
3319 {
3320 if (argvars[2].v_type != VAR_UNKNOWN)
3321 {
3322 before = (long)get_tv_number_chk(&argvars[2], &error);
3323 if (error)
3324 return; /* type error; errmsg already given */
3325
3326 if (before == l1->lv_len)
3327 item = NULL;
3328 else
3329 {
3330 item = list_find(l1, before);
3331 if (item == NULL)
3332 {
3333 EMSGN(_(e_listidx), before);
3334 return;
3335 }
3336 }
3337 }
3338 else
3339 item = NULL;
3340 list_extend(l1, l2, item);
3341
3342 copy_tv(&argvars[0], rettv);
3343 }
3344 }
3345 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3346 {
3347 dict_T *d1, *d2;
3348 char_u *action;
3349 int i;
3350
3351 d1 = argvars[0].vval.v_dict;
3352 d2 = argvars[1].vval.v_dict;
3353 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3354 && d2 != NULL)
3355 {
3356 /* Check the third argument. */
3357 if (argvars[2].v_type != VAR_UNKNOWN)
3358 {
3359 static char *(av[]) = {"keep", "force", "error"};
3360
3361 action = get_tv_string_chk(&argvars[2]);
3362 if (action == NULL)
3363 return; /* type error; errmsg already given */
3364 for (i = 0; i < 3; ++i)
3365 if (STRCMP(action, av[i]) == 0)
3366 break;
3367 if (i == 3)
3368 {
3369 EMSG2(_(e_invarg2), action);
3370 return;
3371 }
3372 }
3373 else
3374 action = (char_u *)"force";
3375
3376 dict_extend(d1, d2, action);
3377
3378 copy_tv(&argvars[0], rettv);
3379 }
3380 }
3381 else
3382 EMSG2(_(e_listdictarg), "extend()");
3383}
3384
3385/*
3386 * "feedkeys()" function
3387 */
3388 static void
3389f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3390{
3391 int remap = TRUE;
3392 int insert = FALSE;
3393 char_u *keys, *flags;
3394 char_u nbuf[NUMBUFLEN];
3395 int typed = FALSE;
3396 int execute = FALSE;
3397 int dangerous = FALSE;
3398 char_u *keys_esc;
3399
3400 /* This is not allowed in the sandbox. If the commands would still be
3401 * executed in the sandbox it would be OK, but it probably happens later,
3402 * when "sandbox" is no longer set. */
3403 if (check_secure())
3404 return;
3405
3406 keys = get_tv_string(&argvars[0]);
3407
3408 if (argvars[1].v_type != VAR_UNKNOWN)
3409 {
3410 flags = get_tv_string_buf(&argvars[1], nbuf);
3411 for ( ; *flags != NUL; ++flags)
3412 {
3413 switch (*flags)
3414 {
3415 case 'n': remap = FALSE; break;
3416 case 'm': remap = TRUE; break;
3417 case 't': typed = TRUE; break;
3418 case 'i': insert = TRUE; break;
3419 case 'x': execute = TRUE; break;
3420 case '!': dangerous = TRUE; break;
3421 }
3422 }
3423 }
3424
3425 if (*keys != NUL || execute)
3426 {
3427 /* Need to escape K_SPECIAL and CSI before putting the string in the
3428 * typeahead buffer. */
3429 keys_esc = vim_strsave_escape_csi(keys);
3430 if (keys_esc != NULL)
3431 {
3432 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3433 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3434 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003435 if (vgetc_busy
3436#ifdef FEAT_TIMERS
3437 || timer_busy
3438#endif
3439 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003440 typebuf_was_filled = TRUE;
3441 if (execute)
3442 {
3443 int save_msg_scroll = msg_scroll;
3444
3445 /* Avoid a 1 second delay when the keys start Insert mode. */
3446 msg_scroll = FALSE;
3447
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003448 if (!dangerous)
3449 ++ex_normal_busy;
Bram Moolenaar655a82a2018-05-08 22:01:07 +02003450 exec_normal(TRUE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003451 if (!dangerous)
3452 --ex_normal_busy;
3453
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003454 msg_scroll |= save_msg_scroll;
3455 }
3456 }
3457 }
3458}
3459
3460/*
3461 * "filereadable()" function
3462 */
3463 static void
3464f_filereadable(typval_T *argvars, typval_T *rettv)
3465{
3466 int fd;
3467 char_u *p;
3468 int n;
3469
3470#ifndef O_NONBLOCK
3471# define O_NONBLOCK 0
3472#endif
3473 p = get_tv_string(&argvars[0]);
3474 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3475 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3476 {
3477 n = TRUE;
3478 close(fd);
3479 }
3480 else
3481 n = FALSE;
3482
3483 rettv->vval.v_number = n;
3484}
3485
3486/*
3487 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3488 * rights to write into.
3489 */
3490 static void
3491f_filewritable(typval_T *argvars, typval_T *rettv)
3492{
3493 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3494}
3495
3496 static void
3497findfilendir(
3498 typval_T *argvars UNUSED,
3499 typval_T *rettv,
3500 int find_what UNUSED)
3501{
3502#ifdef FEAT_SEARCHPATH
3503 char_u *fname;
3504 char_u *fresult = NULL;
3505 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3506 char_u *p;
3507 char_u pathbuf[NUMBUFLEN];
3508 int count = 1;
3509 int first = TRUE;
3510 int error = FALSE;
3511#endif
3512
3513 rettv->vval.v_string = NULL;
3514 rettv->v_type = VAR_STRING;
3515
3516#ifdef FEAT_SEARCHPATH
3517 fname = get_tv_string(&argvars[0]);
3518
3519 if (argvars[1].v_type != VAR_UNKNOWN)
3520 {
3521 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3522 if (p == NULL)
3523 error = TRUE;
3524 else
3525 {
3526 if (*p != NUL)
3527 path = p;
3528
3529 if (argvars[2].v_type != VAR_UNKNOWN)
3530 count = (int)get_tv_number_chk(&argvars[2], &error);
3531 }
3532 }
3533
3534 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3535 error = TRUE;
3536
3537 if (*fname != NUL && !error)
3538 {
3539 do
3540 {
3541 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3542 vim_free(fresult);
3543 fresult = find_file_in_path_option(first ? fname : NULL,
3544 first ? (int)STRLEN(fname) : 0,
3545 0, first, path,
3546 find_what,
3547 curbuf->b_ffname,
3548 find_what == FINDFILE_DIR
3549 ? (char_u *)"" : curbuf->b_p_sua);
3550 first = FALSE;
3551
3552 if (fresult != NULL && rettv->v_type == VAR_LIST)
3553 list_append_string(rettv->vval.v_list, fresult, -1);
3554
3555 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3556 }
3557
3558 if (rettv->v_type == VAR_STRING)
3559 rettv->vval.v_string = fresult;
3560#endif
3561}
3562
3563/*
3564 * "filter()" function
3565 */
3566 static void
3567f_filter(typval_T *argvars, typval_T *rettv)
3568{
3569 filter_map(argvars, rettv, FALSE);
3570}
3571
3572/*
3573 * "finddir({fname}[, {path}[, {count}]])" function
3574 */
3575 static void
3576f_finddir(typval_T *argvars, typval_T *rettv)
3577{
3578 findfilendir(argvars, rettv, FINDFILE_DIR);
3579}
3580
3581/*
3582 * "findfile({fname}[, {path}[, {count}]])" function
3583 */
3584 static void
3585f_findfile(typval_T *argvars, typval_T *rettv)
3586{
3587 findfilendir(argvars, rettv, FINDFILE_FILE);
3588}
3589
3590#ifdef FEAT_FLOAT
3591/*
3592 * "float2nr({float})" function
3593 */
3594 static void
3595f_float2nr(typval_T *argvars, typval_T *rettv)
3596{
3597 float_T f = 0.0;
3598
3599 if (get_float_arg(argvars, &f) == OK)
3600 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003601 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003602 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003603 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003604 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605 else
3606 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607 }
3608}
3609
3610/*
3611 * "floor({float})" function
3612 */
3613 static void
3614f_floor(typval_T *argvars, typval_T *rettv)
3615{
3616 float_T f = 0.0;
3617
3618 rettv->v_type = VAR_FLOAT;
3619 if (get_float_arg(argvars, &f) == OK)
3620 rettv->vval.v_float = floor(f);
3621 else
3622 rettv->vval.v_float = 0.0;
3623}
3624
3625/*
3626 * "fmod()" function
3627 */
3628 static void
3629f_fmod(typval_T *argvars, typval_T *rettv)
3630{
3631 float_T fx = 0.0, fy = 0.0;
3632
3633 rettv->v_type = VAR_FLOAT;
3634 if (get_float_arg(argvars, &fx) == OK
3635 && get_float_arg(&argvars[1], &fy) == OK)
3636 rettv->vval.v_float = fmod(fx, fy);
3637 else
3638 rettv->vval.v_float = 0.0;
3639}
3640#endif
3641
3642/*
3643 * "fnameescape({string})" function
3644 */
3645 static void
3646f_fnameescape(typval_T *argvars, typval_T *rettv)
3647{
3648 rettv->vval.v_string = vim_strsave_fnameescape(
3649 get_tv_string(&argvars[0]), FALSE);
3650 rettv->v_type = VAR_STRING;
3651}
3652
3653/*
3654 * "fnamemodify({fname}, {mods})" function
3655 */
3656 static void
3657f_fnamemodify(typval_T *argvars, typval_T *rettv)
3658{
3659 char_u *fname;
3660 char_u *mods;
3661 int usedlen = 0;
3662 int len;
3663 char_u *fbuf = NULL;
3664 char_u buf[NUMBUFLEN];
3665
3666 fname = get_tv_string_chk(&argvars[0]);
3667 mods = get_tv_string_buf_chk(&argvars[1], buf);
3668 if (fname == NULL || mods == NULL)
3669 fname = NULL;
3670 else
3671 {
3672 len = (int)STRLEN(fname);
3673 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3674 }
3675
3676 rettv->v_type = VAR_STRING;
3677 if (fname == NULL)
3678 rettv->vval.v_string = NULL;
3679 else
3680 rettv->vval.v_string = vim_strnsave(fname, len);
3681 vim_free(fbuf);
3682}
3683
3684static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3685
3686/*
3687 * "foldclosed()" function
3688 */
3689 static void
3690foldclosed_both(
3691 typval_T *argvars UNUSED,
3692 typval_T *rettv,
3693 int end UNUSED)
3694{
3695#ifdef FEAT_FOLDING
3696 linenr_T lnum;
3697 linenr_T first, last;
3698
3699 lnum = get_tv_lnum(argvars);
3700 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3701 {
3702 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3703 {
3704 if (end)
3705 rettv->vval.v_number = (varnumber_T)last;
3706 else
3707 rettv->vval.v_number = (varnumber_T)first;
3708 return;
3709 }
3710 }
3711#endif
3712 rettv->vval.v_number = -1;
3713}
3714
3715/*
3716 * "foldclosed()" function
3717 */
3718 static void
3719f_foldclosed(typval_T *argvars, typval_T *rettv)
3720{
3721 foldclosed_both(argvars, rettv, FALSE);
3722}
3723
3724/*
3725 * "foldclosedend()" function
3726 */
3727 static void
3728f_foldclosedend(typval_T *argvars, typval_T *rettv)
3729{
3730 foldclosed_both(argvars, rettv, TRUE);
3731}
3732
3733/*
3734 * "foldlevel()" function
3735 */
3736 static void
3737f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3738{
3739#ifdef FEAT_FOLDING
3740 linenr_T lnum;
3741
3742 lnum = get_tv_lnum(argvars);
3743 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3744 rettv->vval.v_number = foldLevel(lnum);
3745#endif
3746}
3747
3748/*
3749 * "foldtext()" function
3750 */
3751 static void
3752f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3753{
3754#ifdef FEAT_FOLDING
3755 linenr_T foldstart;
3756 linenr_T foldend;
3757 char_u *dashes;
3758 linenr_T lnum;
3759 char_u *s;
3760 char_u *r;
3761 int len;
3762 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003763 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003764#endif
3765
3766 rettv->v_type = VAR_STRING;
3767 rettv->vval.v_string = NULL;
3768#ifdef FEAT_FOLDING
3769 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3770 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3771 dashes = get_vim_var_str(VV_FOLDDASHES);
3772 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3773 && dashes != NULL)
3774 {
3775 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003776 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777 if (!linewhite(lnum))
3778 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003779
3780 /* Find interesting text in this line. */
3781 s = skipwhite(ml_get(lnum));
3782 /* skip C comment-start */
3783 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3784 {
3785 s = skipwhite(s + 2);
3786 if (*skipwhite(s) == NUL
3787 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3788 {
3789 s = skipwhite(ml_get(lnum + 1));
3790 if (*s == '*')
3791 s = skipwhite(s + 1);
3792 }
3793 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003794 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003795 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003796 r = alloc((unsigned)(STRLEN(txt)
3797 + STRLEN(dashes) /* for %s */
3798 + 20 /* for %3ld */
3799 + STRLEN(s))); /* concatenated */
3800 if (r != NULL)
3801 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003802 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003803 len = (int)STRLEN(r);
3804 STRCAT(r, s);
3805 /* remove 'foldmarker' and 'commentstring' */
3806 foldtext_cleanup(r + len);
3807 rettv->vval.v_string = r;
3808 }
3809 }
3810#endif
3811}
3812
3813/*
3814 * "foldtextresult(lnum)" function
3815 */
3816 static void
3817f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3818{
3819#ifdef FEAT_FOLDING
3820 linenr_T lnum;
3821 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003822 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003823 foldinfo_T foldinfo;
3824 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003825 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826#endif
3827
3828 rettv->v_type = VAR_STRING;
3829 rettv->vval.v_string = NULL;
3830#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003831 if (entered)
3832 return; /* reject recursive use */
3833 entered = TRUE;
3834
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003835 lnum = get_tv_lnum(argvars);
3836 /* treat illegal types and illegal string values for {lnum} the same */
3837 if (lnum < 0)
3838 lnum = 0;
3839 fold_count = foldedCount(curwin, lnum, &foldinfo);
3840 if (fold_count > 0)
3841 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003842 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3843 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003844 if (text == buf)
3845 text = vim_strsave(text);
3846 rettv->vval.v_string = text;
3847 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003848
3849 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003850#endif
3851}
3852
3853/*
3854 * "foreground()" function
3855 */
3856 static void
3857f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3858{
3859#ifdef FEAT_GUI
3860 if (gui.in_use)
3861 gui_mch_set_foreground();
3862#else
3863# ifdef WIN32
3864 win32_set_foreground();
3865# endif
3866#endif
3867}
3868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003869 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003870common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871{
3872 char_u *s;
3873 char_u *name;
3874 int use_string = FALSE;
3875 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003876 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003877
3878 if (argvars[0].v_type == VAR_FUNC)
3879 {
3880 /* function(MyFunc, [arg], dict) */
3881 s = argvars[0].vval.v_string;
3882 }
3883 else if (argvars[0].v_type == VAR_PARTIAL
3884 && argvars[0].vval.v_partial != NULL)
3885 {
3886 /* function(dict.MyFunc, [arg]) */
3887 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003888 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003889 }
3890 else
3891 {
3892 /* function('MyFunc', [arg], dict) */
3893 s = get_tv_string(&argvars[0]);
3894 use_string = TRUE;
3895 }
3896
Bram Moolenaar843b8842016-08-21 14:36:15 +02003897 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003898 {
3899 name = s;
3900 trans_name = trans_function_name(&name, FALSE,
3901 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3902 if (*name != NUL)
3903 s = NULL;
3904 }
3905
Bram Moolenaar843b8842016-08-21 14:36:15 +02003906 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3907 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003908 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003910 else if (trans_name != NULL && (is_funcref
3911 ? find_func(trans_name) == NULL
3912 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003913 EMSG2(_("E700: Unknown function: %s"), s);
3914 else
3915 {
3916 int dict_idx = 0;
3917 int arg_idx = 0;
3918 list_T *list = NULL;
3919
3920 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3921 {
3922 char sid_buf[25];
3923 int off = *s == 's' ? 2 : 5;
3924
3925 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3926 * also be called from another script. Using trans_function_name()
3927 * would also work, but some plugins depend on the name being
3928 * printable text. */
3929 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3930 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3931 if (name != NULL)
3932 {
3933 STRCPY(name, sid_buf);
3934 STRCAT(name, s + off);
3935 }
3936 }
3937 else
3938 name = vim_strsave(s);
3939
3940 if (argvars[1].v_type != VAR_UNKNOWN)
3941 {
3942 if (argvars[2].v_type != VAR_UNKNOWN)
3943 {
3944 /* function(name, [args], dict) */
3945 arg_idx = 1;
3946 dict_idx = 2;
3947 }
3948 else if (argvars[1].v_type == VAR_DICT)
3949 /* function(name, dict) */
3950 dict_idx = 1;
3951 else
3952 /* function(name, [args]) */
3953 arg_idx = 1;
3954 if (dict_idx > 0)
3955 {
3956 if (argvars[dict_idx].v_type != VAR_DICT)
3957 {
3958 EMSG(_("E922: expected a dict"));
3959 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003960 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003961 }
3962 if (argvars[dict_idx].vval.v_dict == NULL)
3963 dict_idx = 0;
3964 }
3965 if (arg_idx > 0)
3966 {
3967 if (argvars[arg_idx].v_type != VAR_LIST)
3968 {
3969 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3970 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003971 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003972 }
3973 list = argvars[arg_idx].vval.v_list;
3974 if (list == NULL || list->lv_len == 0)
3975 arg_idx = 0;
3976 }
3977 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003978 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003979 {
3980 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3981
3982 /* result is a VAR_PARTIAL */
3983 if (pt == NULL)
3984 vim_free(name);
3985 else
3986 {
3987 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3988 {
3989 listitem_T *li;
3990 int i = 0;
3991 int arg_len = 0;
3992 int lv_len = 0;
3993
3994 if (arg_pt != NULL)
3995 arg_len = arg_pt->pt_argc;
3996 if (list != NULL)
3997 lv_len = list->lv_len;
3998 pt->pt_argc = arg_len + lv_len;
3999 pt->pt_argv = (typval_T *)alloc(
4000 sizeof(typval_T) * pt->pt_argc);
4001 if (pt->pt_argv == NULL)
4002 {
4003 vim_free(pt);
4004 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004005 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004006 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004007 for (i = 0; i < arg_len; i++)
4008 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4009 if (lv_len > 0)
4010 for (li = list->lv_first; li != NULL;
4011 li = li->li_next)
4012 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 }
4014
4015 /* For "function(dict.func, [], dict)" and "func" is a partial
4016 * use "dict". That is backwards compatible. */
4017 if (dict_idx > 0)
4018 {
4019 /* The dict is bound explicitly, pt_auto is FALSE. */
4020 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4021 ++pt->pt_dict->dv_refcount;
4022 }
4023 else if (arg_pt != NULL)
4024 {
4025 /* If the dict was bound automatically the result is also
4026 * bound automatically. */
4027 pt->pt_dict = arg_pt->pt_dict;
4028 pt->pt_auto = arg_pt->pt_auto;
4029 if (pt->pt_dict != NULL)
4030 ++pt->pt_dict->dv_refcount;
4031 }
4032
4033 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004034 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4035 {
4036 pt->pt_func = arg_pt->pt_func;
4037 func_ptr_ref(pt->pt_func);
4038 vim_free(name);
4039 }
4040 else if (is_funcref)
4041 {
4042 pt->pt_func = find_func(trans_name);
4043 func_ptr_ref(pt->pt_func);
4044 vim_free(name);
4045 }
4046 else
4047 {
4048 pt->pt_name = name;
4049 func_ref(name);
4050 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004051 }
4052 rettv->v_type = VAR_PARTIAL;
4053 rettv->vval.v_partial = pt;
4054 }
4055 else
4056 {
4057 /* result is a VAR_FUNC */
4058 rettv->v_type = VAR_FUNC;
4059 rettv->vval.v_string = name;
4060 func_ref(name);
4061 }
4062 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004063theend:
4064 vim_free(trans_name);
4065}
4066
4067/*
4068 * "funcref()" function
4069 */
4070 static void
4071f_funcref(typval_T *argvars, typval_T *rettv)
4072{
4073 common_function(argvars, rettv, TRUE);
4074}
4075
4076/*
4077 * "function()" function
4078 */
4079 static void
4080f_function(typval_T *argvars, typval_T *rettv)
4081{
4082 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004083}
4084
4085/*
4086 * "garbagecollect()" function
4087 */
4088 static void
4089f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4090{
4091 /* This is postponed until we are back at the toplevel, because we may be
4092 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4093 want_garbage_collect = TRUE;
4094
4095 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
4096 garbage_collect_at_exit = TRUE;
4097}
4098
4099/*
4100 * "get()" function
4101 */
4102 static void
4103f_get(typval_T *argvars, typval_T *rettv)
4104{
4105 listitem_T *li;
4106 list_T *l;
4107 dictitem_T *di;
4108 dict_T *d;
4109 typval_T *tv = NULL;
4110
4111 if (argvars[0].v_type == VAR_LIST)
4112 {
4113 if ((l = argvars[0].vval.v_list) != NULL)
4114 {
4115 int error = FALSE;
4116
4117 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
4118 if (!error && li != NULL)
4119 tv = &li->li_tv;
4120 }
4121 }
4122 else if (argvars[0].v_type == VAR_DICT)
4123 {
4124 if ((d = argvars[0].vval.v_dict) != NULL)
4125 {
4126 di = dict_find(d, get_tv_string(&argvars[1]), -1);
4127 if (di != NULL)
4128 tv = &di->di_tv;
4129 }
4130 }
4131 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4132 {
4133 partial_T *pt;
4134 partial_T fref_pt;
4135
4136 if (argvars[0].v_type == VAR_PARTIAL)
4137 pt = argvars[0].vval.v_partial;
4138 else
4139 {
4140 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4141 fref_pt.pt_name = argvars[0].vval.v_string;
4142 pt = &fref_pt;
4143 }
4144
4145 if (pt != NULL)
4146 {
4147 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004148 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004149
4150 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4151 {
4152 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004153 n = partial_name(pt);
4154 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004155 rettv->vval.v_string = NULL;
4156 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004157 {
4158 rettv->vval.v_string = vim_strsave(n);
4159 if (rettv->v_type == VAR_FUNC)
4160 func_ref(rettv->vval.v_string);
4161 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004162 }
4163 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004164 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004165 else if (STRCMP(what, "args") == 0)
4166 {
4167 rettv->v_type = VAR_LIST;
4168 if (rettv_list_alloc(rettv) == OK)
4169 {
4170 int i;
4171
4172 for (i = 0; i < pt->pt_argc; ++i)
4173 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4174 }
4175 }
4176 else
4177 EMSG2(_(e_invarg2), what);
4178 return;
4179 }
4180 }
4181 else
4182 EMSG2(_(e_listdictarg), "get()");
4183
4184 if (tv == NULL)
4185 {
4186 if (argvars[2].v_type != VAR_UNKNOWN)
4187 copy_tv(&argvars[2], rettv);
4188 }
4189 else
4190 copy_tv(tv, rettv);
4191}
4192
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004193#ifdef FEAT_SIGNS
4194/*
4195 * Returns information about signs placed in a buffer as list of dicts.
4196 */
4197 static void
4198get_buffer_signs(buf_T *buf, list_T *l)
4199{
4200 signlist_T *sign;
4201
4202 for (sign = buf->b_signlist; sign; sign = sign->next)
4203 {
4204 dict_T *d = dict_alloc();
4205
4206 if (d != NULL)
4207 {
4208 dict_add_nr_str(d, "id", sign->id, NULL);
4209 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004210 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004211
4212 list_append_dict(l, d);
4213 }
4214 }
4215}
4216#endif
4217
4218/*
4219 * Returns buffer options, variables and other attributes in a dictionary.
4220 */
4221 static dict_T *
4222get_buffer_info(buf_T *buf)
4223{
4224 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004225 tabpage_T *tp;
4226 win_T *wp;
4227 list_T *windows;
4228
4229 dict = dict_alloc();
4230 if (dict == NULL)
4231 return NULL;
4232
Bram Moolenaar33928832016-08-18 21:22:04 +02004233 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004234 dict_add_nr_str(dict, "name", 0L,
4235 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004236 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4237 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004238 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4239 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4240 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004241 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004242 dict_add_nr_str(dict, "hidden",
4243 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4244 NULL);
4245
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004246 /* Get a reference to buffer variables */
4247 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004248
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004249 /* List of windows displaying this buffer */
4250 windows = list_alloc();
4251 if (windows != NULL)
4252 {
4253 FOR_ALL_TAB_WINDOWS(tp, wp)
4254 if (wp->w_buffer == buf)
4255 list_append_number(windows, (varnumber_T)wp->w_id);
4256 dict_add_list(dict, "windows", windows);
4257 }
4258
4259#ifdef FEAT_SIGNS
4260 if (buf->b_signlist != NULL)
4261 {
4262 /* List of signs placed in this buffer */
4263 list_T *signs = list_alloc();
4264 if (signs != NULL)
4265 {
4266 get_buffer_signs(buf, signs);
4267 dict_add_list(dict, "signs", signs);
4268 }
4269 }
4270#endif
4271
4272 return dict;
4273}
4274
4275/*
4276 * "getbufinfo()" function
4277 */
4278 static void
4279f_getbufinfo(typval_T *argvars, typval_T *rettv)
4280{
4281 buf_T *buf = NULL;
4282 buf_T *argbuf = NULL;
4283 dict_T *d;
4284 int filtered = FALSE;
4285 int sel_buflisted = FALSE;
4286 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004287 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004288
4289 if (rettv_list_alloc(rettv) != OK)
4290 return;
4291
4292 /* List of all the buffers or selected buffers */
4293 if (argvars[0].v_type == VAR_DICT)
4294 {
4295 dict_T *sel_d = argvars[0].vval.v_dict;
4296
4297 if (sel_d != NULL)
4298 {
4299 dictitem_T *di;
4300
4301 filtered = TRUE;
4302
4303 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4304 if (di != NULL && get_tv_number(&di->di_tv))
4305 sel_buflisted = TRUE;
4306
4307 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4308 if (di != NULL && get_tv_number(&di->di_tv))
4309 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004310
4311 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4312 if (di != NULL && get_tv_number(&di->di_tv))
4313 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004314 }
4315 }
4316 else if (argvars[0].v_type != VAR_UNKNOWN)
4317 {
4318 /* Information about one buffer. Argument specifies the buffer */
4319 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4320 ++emsg_off;
4321 argbuf = get_buf_tv(&argvars[0], FALSE);
4322 --emsg_off;
4323 if (argbuf == NULL)
4324 return;
4325 }
4326
4327 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004328 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004329 {
4330 if (argbuf != NULL && argbuf != buf)
4331 continue;
4332 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004333 || (sel_buflisted && !buf->b_p_bl)
4334 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004335 continue;
4336
4337 d = get_buffer_info(buf);
4338 if (d != NULL)
4339 list_append_dict(rettv->vval.v_list, d);
4340 if (argbuf != NULL)
4341 return;
4342 }
4343}
4344
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004345static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4346
4347/*
4348 * Get line or list of lines from buffer "buf" into "rettv".
4349 * Return a range (from start to end) of lines in rettv from the specified
4350 * buffer.
4351 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4352 */
4353 static void
4354get_buffer_lines(
4355 buf_T *buf,
4356 linenr_T start,
4357 linenr_T end,
4358 int retlist,
4359 typval_T *rettv)
4360{
4361 char_u *p;
4362
4363 rettv->v_type = VAR_STRING;
4364 rettv->vval.v_string = NULL;
4365 if (retlist && rettv_list_alloc(rettv) == FAIL)
4366 return;
4367
4368 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4369 return;
4370
4371 if (!retlist)
4372 {
4373 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4374 p = ml_get_buf(buf, start, FALSE);
4375 else
4376 p = (char_u *)"";
4377 rettv->vval.v_string = vim_strsave(p);
4378 }
4379 else
4380 {
4381 if (end < start)
4382 return;
4383
4384 if (start < 1)
4385 start = 1;
4386 if (end > buf->b_ml.ml_line_count)
4387 end = buf->b_ml.ml_line_count;
4388 while (start <= end)
4389 if (list_append_string(rettv->vval.v_list,
4390 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4391 break;
4392 }
4393}
4394
4395/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004396 * "getbufline()" function
4397 */
4398 static void
4399f_getbufline(typval_T *argvars, typval_T *rettv)
4400{
4401 linenr_T lnum;
4402 linenr_T end;
4403 buf_T *buf;
4404
4405 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4406 ++emsg_off;
4407 buf = get_buf_tv(&argvars[0], FALSE);
4408 --emsg_off;
4409
4410 lnum = get_tv_lnum_buf(&argvars[1], buf);
4411 if (argvars[2].v_type == VAR_UNKNOWN)
4412 end = lnum;
4413 else
4414 end = get_tv_lnum_buf(&argvars[2], buf);
4415
4416 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4417}
4418
4419/*
4420 * "getbufvar()" function
4421 */
4422 static void
4423f_getbufvar(typval_T *argvars, typval_T *rettv)
4424{
4425 buf_T *buf;
4426 buf_T *save_curbuf;
4427 char_u *varname;
4428 dictitem_T *v;
4429 int done = FALSE;
4430
4431 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4432 varname = get_tv_string_chk(&argvars[1]);
4433 ++emsg_off;
4434 buf = get_buf_tv(&argvars[0], FALSE);
4435
4436 rettv->v_type = VAR_STRING;
4437 rettv->vval.v_string = NULL;
4438
4439 if (buf != NULL && varname != NULL)
4440 {
4441 /* set curbuf to be our buf, temporarily */
4442 save_curbuf = curbuf;
4443 curbuf = buf;
4444
Bram Moolenaar30567352016-08-27 21:25:44 +02004445 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004446 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004447 if (varname[1] == NUL)
4448 {
4449 /* get all buffer-local options in a dict */
4450 dict_T *opts = get_winbuf_options(TRUE);
4451
4452 if (opts != NULL)
4453 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004454 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004455 done = TRUE;
4456 }
4457 }
4458 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4459 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004460 done = TRUE;
4461 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004462 else
4463 {
4464 /* Look up the variable. */
4465 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4466 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4467 'b', varname, FALSE);
4468 if (v != NULL)
4469 {
4470 copy_tv(&v->di_tv, rettv);
4471 done = TRUE;
4472 }
4473 }
4474
4475 /* restore previous notion of curbuf */
4476 curbuf = save_curbuf;
4477 }
4478
4479 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4480 /* use the default value */
4481 copy_tv(&argvars[2], rettv);
4482
4483 --emsg_off;
4484}
4485
4486/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004487 * "getchangelist()" function
4488 */
4489 static void
4490f_getchangelist(typval_T *argvars, typval_T *rettv)
4491{
4492#ifdef FEAT_JUMPLIST
4493 buf_T *buf;
4494 int i;
4495 list_T *l;
4496 dict_T *d;
4497#endif
4498
4499 if (rettv_list_alloc(rettv) != OK)
4500 return;
4501
4502#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004503 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4504 ++emsg_off;
4505 buf = get_buf_tv(&argvars[0], FALSE);
4506 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004507 if (buf == NULL)
4508 return;
4509
4510 l = list_alloc();
4511 if (l == NULL)
4512 return;
4513
4514 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4515 return;
4516 /*
4517 * The current window change list index tracks only the position in the
4518 * current buffer change list. For other buffers, use the change list
4519 * length as the current index.
4520 */
4521 list_append_number(rettv->vval.v_list,
4522 (varnumber_T)((buf == curwin->w_buffer)
4523 ? curwin->w_changelistidx : buf->b_changelistlen));
4524
4525 for (i = 0; i < buf->b_changelistlen; ++i)
4526 {
4527 if (buf->b_changelist[i].lnum == 0)
4528 continue;
4529 if ((d = dict_alloc()) == NULL)
4530 return;
4531 if (list_append_dict(l, d) == FAIL)
4532 return;
4533 dict_add_nr_str(d, "lnum", (long)buf->b_changelist[i].lnum, NULL);
4534 dict_add_nr_str(d, "col", (long)buf->b_changelist[i].col, NULL);
4535# ifdef FEAT_VIRTUALEDIT
4536 dict_add_nr_str(d, "coladd", (long)buf->b_changelist[i].coladd, NULL);
4537# endif
4538 }
4539#endif
4540}
4541/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004542 * "getchar()" function
4543 */
4544 static void
4545f_getchar(typval_T *argvars, typval_T *rettv)
4546{
4547 varnumber_T n;
4548 int error = FALSE;
4549
4550 /* Position the cursor. Needed after a message that ends in a space. */
4551 windgoto(msg_row, msg_col);
4552
4553 ++no_mapping;
4554 ++allow_keys;
4555 for (;;)
4556 {
4557 if (argvars[0].v_type == VAR_UNKNOWN)
4558 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004559 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4561 /* getchar(1): only check if char avail */
4562 n = vpeekc_any();
4563 else if (error || vpeekc_any() == NUL)
4564 /* illegal argument or getchar(0) and no char avail: return zero */
4565 n = 0;
4566 else
4567 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004568 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004569
4570 if (n == K_IGNORE)
4571 continue;
4572 break;
4573 }
4574 --no_mapping;
4575 --allow_keys;
4576
4577 set_vim_var_nr(VV_MOUSE_WIN, 0);
4578 set_vim_var_nr(VV_MOUSE_WINID, 0);
4579 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4580 set_vim_var_nr(VV_MOUSE_COL, 0);
4581
4582 rettv->vval.v_number = n;
4583 if (IS_SPECIAL(n) || mod_mask != 0)
4584 {
4585 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4586 int i = 0;
4587
4588 /* Turn a special key into three bytes, plus modifier. */
4589 if (mod_mask != 0)
4590 {
4591 temp[i++] = K_SPECIAL;
4592 temp[i++] = KS_MODIFIER;
4593 temp[i++] = mod_mask;
4594 }
4595 if (IS_SPECIAL(n))
4596 {
4597 temp[i++] = K_SPECIAL;
4598 temp[i++] = K_SECOND(n);
4599 temp[i++] = K_THIRD(n);
4600 }
4601#ifdef FEAT_MBYTE
4602 else if (has_mbyte)
4603 i += (*mb_char2bytes)(n, temp + i);
4604#endif
4605 else
4606 temp[i++] = n;
4607 temp[i++] = NUL;
4608 rettv->v_type = VAR_STRING;
4609 rettv->vval.v_string = vim_strsave(temp);
4610
4611#ifdef FEAT_MOUSE
4612 if (is_mouse_key(n))
4613 {
4614 int row = mouse_row;
4615 int col = mouse_col;
4616 win_T *win;
4617 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004618 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004619 int winnr = 1;
4620
4621 if (row >= 0 && col >= 0)
4622 {
4623 /* Find the window at the mouse coordinates and compute the
4624 * text position. */
4625 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004626 if (win == NULL)
4627 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004628 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004629 for (wp = firstwin; wp != win; wp = wp->w_next)
4630 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004631 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4632 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4633 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4634 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4635 }
4636 }
4637#endif
4638 }
4639}
4640
4641/*
4642 * "getcharmod()" function
4643 */
4644 static void
4645f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4646{
4647 rettv->vval.v_number = mod_mask;
4648}
4649
4650/*
4651 * "getcharsearch()" function
4652 */
4653 static void
4654f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4655{
4656 if (rettv_dict_alloc(rettv) != FAIL)
4657 {
4658 dict_T *dict = rettv->vval.v_dict;
4659
4660 dict_add_nr_str(dict, "char", 0L, last_csearch());
4661 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4662 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4663 }
4664}
4665
4666/*
4667 * "getcmdline()" function
4668 */
4669 static void
4670f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4671{
4672 rettv->v_type = VAR_STRING;
4673 rettv->vval.v_string = get_cmdline_str();
4674}
4675
4676/*
4677 * "getcmdpos()" function
4678 */
4679 static void
4680f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4681{
4682 rettv->vval.v_number = get_cmdline_pos() + 1;
4683}
4684
4685/*
4686 * "getcmdtype()" function
4687 */
4688 static void
4689f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4690{
4691 rettv->v_type = VAR_STRING;
4692 rettv->vval.v_string = alloc(2);
4693 if (rettv->vval.v_string != NULL)
4694 {
4695 rettv->vval.v_string[0] = get_cmdline_type();
4696 rettv->vval.v_string[1] = NUL;
4697 }
4698}
4699
4700/*
4701 * "getcmdwintype()" function
4702 */
4703 static void
4704f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4705{
4706 rettv->v_type = VAR_STRING;
4707 rettv->vval.v_string = NULL;
4708#ifdef FEAT_CMDWIN
4709 rettv->vval.v_string = alloc(2);
4710 if (rettv->vval.v_string != NULL)
4711 {
4712 rettv->vval.v_string[0] = cmdwin_type;
4713 rettv->vval.v_string[1] = NUL;
4714 }
4715#endif
4716}
4717
4718#if defined(FEAT_CMDL_COMPL)
4719/*
4720 * "getcompletion()" function
4721 */
4722 static void
4723f_getcompletion(typval_T *argvars, typval_T *rettv)
4724{
4725 char_u *pat;
4726 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004727 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004728 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4729 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004730
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004731 if (argvars[2].v_type != VAR_UNKNOWN)
4732 filtered = get_tv_number_chk(&argvars[2], NULL);
4733
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 if (p_wic)
4735 options |= WILD_ICASE;
4736
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004737 /* For filtered results, 'wildignore' is used */
4738 if (!filtered)
4739 options |= WILD_KEEP_ALL;
4740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004741 ExpandInit(&xpc);
4742 xpc.xp_pattern = get_tv_string(&argvars[0]);
4743 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4744 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4745 if (xpc.xp_context == EXPAND_NOTHING)
4746 {
4747 if (argvars[1].v_type == VAR_STRING)
4748 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4749 else
4750 EMSG(_(e_invarg));
4751 return;
4752 }
4753
4754# if defined(FEAT_MENU)
4755 if (xpc.xp_context == EXPAND_MENUS)
4756 {
4757 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4758 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4759 }
4760# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004761#ifdef FEAT_CSCOPE
4762 if (xpc.xp_context == EXPAND_CSCOPE)
4763 {
4764 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4765 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4766 }
4767#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004768#ifdef FEAT_SIGNS
4769 if (xpc.xp_context == EXPAND_SIGN)
4770 {
4771 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4772 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4773 }
4774#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004775
4776 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4777 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4778 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004779 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004780
4781 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4782
4783 for (i = 0; i < xpc.xp_numfiles; i++)
4784 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4785 }
4786 vim_free(pat);
4787 ExpandCleanup(&xpc);
4788}
4789#endif
4790
4791/*
4792 * "getcwd()" function
4793 */
4794 static void
4795f_getcwd(typval_T *argvars, typval_T *rettv)
4796{
4797 win_T *wp = NULL;
4798 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004799 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004800
4801 rettv->v_type = VAR_STRING;
4802 rettv->vval.v_string = NULL;
4803
Bram Moolenaar54591292018-02-09 20:53:59 +01004804 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4805 global = TRUE;
4806 else
4807 wp = find_tabwin(&argvars[0], &argvars[1]);
4808
4809 if (wp != NULL && wp->w_localdir != NULL)
4810 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4811 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004812 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004813 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004814 rettv->vval.v_string = vim_strsave(globaldir);
4815 else
4816 {
4817 cwd = alloc(MAXPATHL);
4818 if (cwd != NULL)
4819 {
4820 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4821 rettv->vval.v_string = vim_strsave(cwd);
4822 vim_free(cwd);
4823 }
4824 }
4825#ifdef BACKSLASH_IN_FILENAME
4826 if (rettv->vval.v_string != NULL)
4827 slash_adjust(rettv->vval.v_string);
4828#endif
4829 }
4830}
4831
4832/*
4833 * "getfontname()" function
4834 */
4835 static void
4836f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4837{
4838 rettv->v_type = VAR_STRING;
4839 rettv->vval.v_string = NULL;
4840#ifdef FEAT_GUI
4841 if (gui.in_use)
4842 {
4843 GuiFont font;
4844 char_u *name = NULL;
4845
4846 if (argvars[0].v_type == VAR_UNKNOWN)
4847 {
4848 /* Get the "Normal" font. Either the name saved by
4849 * hl_set_font_name() or from the font ID. */
4850 font = gui.norm_font;
4851 name = hl_get_font_name();
4852 }
4853 else
4854 {
4855 name = get_tv_string(&argvars[0]);
4856 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4857 return;
4858 font = gui_mch_get_font(name, FALSE);
4859 if (font == NOFONT)
4860 return; /* Invalid font name, return empty string. */
4861 }
4862 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4863 if (argvars[0].v_type != VAR_UNKNOWN)
4864 gui_mch_free_font(font);
4865 }
4866#endif
4867}
4868
4869/*
4870 * "getfperm({fname})" function
4871 */
4872 static void
4873f_getfperm(typval_T *argvars, typval_T *rettv)
4874{
4875 char_u *fname;
4876 stat_T st;
4877 char_u *perm = NULL;
4878 char_u flags[] = "rwx";
4879 int i;
4880
4881 fname = get_tv_string(&argvars[0]);
4882
4883 rettv->v_type = VAR_STRING;
4884 if (mch_stat((char *)fname, &st) >= 0)
4885 {
4886 perm = vim_strsave((char_u *)"---------");
4887 if (perm != NULL)
4888 {
4889 for (i = 0; i < 9; i++)
4890 {
4891 if (st.st_mode & (1 << (8 - i)))
4892 perm[i] = flags[i % 3];
4893 }
4894 }
4895 }
4896 rettv->vval.v_string = perm;
4897}
4898
4899/*
4900 * "getfsize({fname})" function
4901 */
4902 static void
4903f_getfsize(typval_T *argvars, typval_T *rettv)
4904{
4905 char_u *fname;
4906 stat_T st;
4907
4908 fname = get_tv_string(&argvars[0]);
4909
4910 rettv->v_type = VAR_NUMBER;
4911
4912 if (mch_stat((char *)fname, &st) >= 0)
4913 {
4914 if (mch_isdir(fname))
4915 rettv->vval.v_number = 0;
4916 else
4917 {
4918 rettv->vval.v_number = (varnumber_T)st.st_size;
4919
4920 /* non-perfect check for overflow */
4921 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4922 rettv->vval.v_number = -2;
4923 }
4924 }
4925 else
4926 rettv->vval.v_number = -1;
4927}
4928
4929/*
4930 * "getftime({fname})" function
4931 */
4932 static void
4933f_getftime(typval_T *argvars, typval_T *rettv)
4934{
4935 char_u *fname;
4936 stat_T st;
4937
4938 fname = get_tv_string(&argvars[0]);
4939
4940 if (mch_stat((char *)fname, &st) >= 0)
4941 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4942 else
4943 rettv->vval.v_number = -1;
4944}
4945
4946/*
4947 * "getftype({fname})" function
4948 */
4949 static void
4950f_getftype(typval_T *argvars, typval_T *rettv)
4951{
4952 char_u *fname;
4953 stat_T st;
4954 char_u *type = NULL;
4955 char *t;
4956
4957 fname = get_tv_string(&argvars[0]);
4958
4959 rettv->v_type = VAR_STRING;
4960 if (mch_lstat((char *)fname, &st) >= 0)
4961 {
4962#ifdef S_ISREG
4963 if (S_ISREG(st.st_mode))
4964 t = "file";
4965 else if (S_ISDIR(st.st_mode))
4966 t = "dir";
4967# ifdef S_ISLNK
4968 else if (S_ISLNK(st.st_mode))
4969 t = "link";
4970# endif
4971# ifdef S_ISBLK
4972 else if (S_ISBLK(st.st_mode))
4973 t = "bdev";
4974# endif
4975# ifdef S_ISCHR
4976 else if (S_ISCHR(st.st_mode))
4977 t = "cdev";
4978# endif
4979# ifdef S_ISFIFO
4980 else if (S_ISFIFO(st.st_mode))
4981 t = "fifo";
4982# endif
4983# ifdef S_ISSOCK
4984 else if (S_ISSOCK(st.st_mode))
4985 t = "fifo";
4986# endif
4987 else
4988 t = "other";
4989#else
4990# ifdef S_IFMT
4991 switch (st.st_mode & S_IFMT)
4992 {
4993 case S_IFREG: t = "file"; break;
4994 case S_IFDIR: t = "dir"; break;
4995# ifdef S_IFLNK
4996 case S_IFLNK: t = "link"; break;
4997# endif
4998# ifdef S_IFBLK
4999 case S_IFBLK: t = "bdev"; break;
5000# endif
5001# ifdef S_IFCHR
5002 case S_IFCHR: t = "cdev"; break;
5003# endif
5004# ifdef S_IFIFO
5005 case S_IFIFO: t = "fifo"; break;
5006# endif
5007# ifdef S_IFSOCK
5008 case S_IFSOCK: t = "socket"; break;
5009# endif
5010 default: t = "other";
5011 }
5012# else
5013 if (mch_isdir(fname))
5014 t = "dir";
5015 else
5016 t = "file";
5017# endif
5018#endif
5019 type = vim_strsave((char_u *)t);
5020 }
5021 rettv->vval.v_string = type;
5022}
5023
5024/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005025 * "getjumplist()" function
5026 */
5027 static void
5028f_getjumplist(typval_T *argvars, typval_T *rettv)
5029{
5030#ifdef FEAT_JUMPLIST
5031 win_T *wp;
5032 int i;
5033 list_T *l;
5034 dict_T *d;
5035#endif
5036
5037 if (rettv_list_alloc(rettv) != OK)
5038 return;
5039
5040#ifdef FEAT_JUMPLIST
5041 wp = find_tabwin(&argvars[0], &argvars[1]);
5042 if (wp == NULL)
5043 return;
5044
5045 l = list_alloc();
5046 if (l == NULL)
5047 return;
5048
5049 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5050 return;
5051 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5052
Bram Moolenaar48679742018-02-13 13:33:29 +01005053 cleanup_jumplist(wp, TRUE);
5054
Bram Moolenaar4f505882018-02-10 21:06:32 +01005055 for (i = 0; i < wp->w_jumplistlen; ++i)
5056 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005057 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5058 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005059 if ((d = dict_alloc()) == NULL)
5060 return;
5061 if (list_append_dict(l, d) == FAIL)
5062 return;
5063 dict_add_nr_str(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum,
5064 NULL);
5065 dict_add_nr_str(d, "col", (long)wp->w_jumplist[i].fmark.mark.col,
5066 NULL);
5067# ifdef FEAT_VIRTUALEDIT
5068 dict_add_nr_str(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd,
5069 NULL);
5070# endif
5071 dict_add_nr_str(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum, NULL);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005072 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaar4f505882018-02-10 21:06:32 +01005073 dict_add_nr_str(d, "filename", 0L, wp->w_jumplist[i].fname);
5074 }
5075#endif
5076}
5077
5078/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005079 * "getline(lnum, [end])" function
5080 */
5081 static void
5082f_getline(typval_T *argvars, typval_T *rettv)
5083{
5084 linenr_T lnum;
5085 linenr_T end;
5086 int retlist;
5087
5088 lnum = get_tv_lnum(argvars);
5089 if (argvars[1].v_type == VAR_UNKNOWN)
5090 {
5091 end = 0;
5092 retlist = FALSE;
5093 }
5094 else
5095 {
5096 end = get_tv_lnum(&argvars[1]);
5097 retlist = TRUE;
5098 }
5099
5100 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5101}
5102
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005103#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005104 static void
5105get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5106{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005107 if (what_arg->v_type == VAR_UNKNOWN)
5108 {
5109 if (rettv_list_alloc(rettv) == OK)
5110 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005111 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005112 }
5113 else
5114 {
5115 if (rettv_dict_alloc(rettv) == OK)
5116 if (is_qf || (wp != NULL))
5117 {
5118 if (what_arg->v_type == VAR_DICT)
5119 {
5120 dict_T *d = what_arg->vval.v_dict;
5121
5122 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005123 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005124 }
5125 else
5126 EMSG(_(e_dictreq));
5127 }
5128 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005129}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005130#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005131
5132/*
5133 * "getloclist()" function
5134 */
5135 static void
5136f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5137{
5138#ifdef FEAT_QUICKFIX
5139 win_T *wp;
5140
5141 wp = find_win_by_nr(&argvars[0], NULL);
5142 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5143#endif
5144}
5145
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005146/*
5147 * "getmatches()" function
5148 */
5149 static void
5150f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5151{
5152#ifdef FEAT_SEARCH_EXTRA
5153 dict_T *dict;
5154 matchitem_T *cur = curwin->w_match_head;
5155 int i;
5156
5157 if (rettv_list_alloc(rettv) == OK)
5158 {
5159 while (cur != NULL)
5160 {
5161 dict = dict_alloc();
5162 if (dict == NULL)
5163 return;
5164 if (cur->match.regprog == NULL)
5165 {
5166 /* match added with matchaddpos() */
5167 for (i = 0; i < MAXPOSMATCH; ++i)
5168 {
5169 llpos_T *llpos;
5170 char buf[6];
5171 list_T *l;
5172
5173 llpos = &cur->pos.pos[i];
5174 if (llpos->lnum == 0)
5175 break;
5176 l = list_alloc();
5177 if (l == NULL)
5178 break;
5179 list_append_number(l, (varnumber_T)llpos->lnum);
5180 if (llpos->col > 0)
5181 {
5182 list_append_number(l, (varnumber_T)llpos->col);
5183 list_append_number(l, (varnumber_T)llpos->len);
5184 }
5185 sprintf(buf, "pos%d", i + 1);
5186 dict_add_list(dict, buf, l);
5187 }
5188 }
5189 else
5190 {
5191 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
5192 }
5193 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
5194 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
5195 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
5196# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5197 if (cur->conceal_char)
5198 {
5199 char_u buf[MB_MAXBYTES + 1];
5200
5201 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5202 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
5203 }
5204# endif
5205 list_append_dict(rettv->vval.v_list, dict);
5206 cur = cur->next;
5207 }
5208 }
5209#endif
5210}
5211
5212/*
5213 * "getpid()" function
5214 */
5215 static void
5216f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5217{
5218 rettv->vval.v_number = mch_get_pid();
5219}
5220
5221 static void
5222getpos_both(
5223 typval_T *argvars,
5224 typval_T *rettv,
5225 int getcurpos)
5226{
5227 pos_T *fp;
5228 list_T *l;
5229 int fnum = -1;
5230
5231 if (rettv_list_alloc(rettv) == OK)
5232 {
5233 l = rettv->vval.v_list;
5234 if (getcurpos)
5235 fp = &curwin->w_cursor;
5236 else
5237 fp = var2fpos(&argvars[0], TRUE, &fnum);
5238 if (fnum != -1)
5239 list_append_number(l, (varnumber_T)fnum);
5240 else
5241 list_append_number(l, (varnumber_T)0);
5242 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5243 : (varnumber_T)0);
5244 list_append_number(l, (fp != NULL)
5245 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5246 : (varnumber_T)0);
5247 list_append_number(l,
5248#ifdef FEAT_VIRTUALEDIT
5249 (fp != NULL) ? (varnumber_T)fp->coladd :
5250#endif
5251 (varnumber_T)0);
5252 if (getcurpos)
5253 {
5254 update_curswant();
5255 list_append_number(l, curwin->w_curswant == MAXCOL ?
5256 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5257 }
5258 }
5259 else
5260 rettv->vval.v_number = FALSE;
5261}
5262
5263
5264/*
5265 * "getcurpos()" function
5266 */
5267 static void
5268f_getcurpos(typval_T *argvars, typval_T *rettv)
5269{
5270 getpos_both(argvars, rettv, TRUE);
5271}
5272
5273/*
5274 * "getpos(string)" function
5275 */
5276 static void
5277f_getpos(typval_T *argvars, typval_T *rettv)
5278{
5279 getpos_both(argvars, rettv, FALSE);
5280}
5281
5282/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005283 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005284 */
5285 static void
5286f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5287{
5288#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005289 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005290#endif
5291}
5292
5293/*
5294 * "getreg()" function
5295 */
5296 static void
5297f_getreg(typval_T *argvars, typval_T *rettv)
5298{
5299 char_u *strregname;
5300 int regname;
5301 int arg2 = FALSE;
5302 int return_list = FALSE;
5303 int error = FALSE;
5304
5305 if (argvars[0].v_type != VAR_UNKNOWN)
5306 {
5307 strregname = get_tv_string_chk(&argvars[0]);
5308 error = strregname == NULL;
5309 if (argvars[1].v_type != VAR_UNKNOWN)
5310 {
5311 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5312 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5313 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5314 }
5315 }
5316 else
5317 strregname = get_vim_var_str(VV_REG);
5318
5319 if (error)
5320 return;
5321
5322 regname = (strregname == NULL ? '"' : *strregname);
5323 if (regname == 0)
5324 regname = '"';
5325
5326 if (return_list)
5327 {
5328 rettv->v_type = VAR_LIST;
5329 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5330 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5331 if (rettv->vval.v_list == NULL)
5332 (void)rettv_list_alloc(rettv);
5333 else
5334 ++rettv->vval.v_list->lv_refcount;
5335 }
5336 else
5337 {
5338 rettv->v_type = VAR_STRING;
5339 rettv->vval.v_string = get_reg_contents(regname,
5340 arg2 ? GREG_EXPR_SRC : 0);
5341 }
5342}
5343
5344/*
5345 * "getregtype()" function
5346 */
5347 static void
5348f_getregtype(typval_T *argvars, typval_T *rettv)
5349{
5350 char_u *strregname;
5351 int regname;
5352 char_u buf[NUMBUFLEN + 2];
5353 long reglen = 0;
5354
5355 if (argvars[0].v_type != VAR_UNKNOWN)
5356 {
5357 strregname = get_tv_string_chk(&argvars[0]);
5358 if (strregname == NULL) /* type error; errmsg already given */
5359 {
5360 rettv->v_type = VAR_STRING;
5361 rettv->vval.v_string = NULL;
5362 return;
5363 }
5364 }
5365 else
5366 /* Default to v:register */
5367 strregname = get_vim_var_str(VV_REG);
5368
5369 regname = (strregname == NULL ? '"' : *strregname);
5370 if (regname == 0)
5371 regname = '"';
5372
5373 buf[0] = NUL;
5374 buf[1] = NUL;
5375 switch (get_reg_type(regname, &reglen))
5376 {
5377 case MLINE: buf[0] = 'V'; break;
5378 case MCHAR: buf[0] = 'v'; break;
5379 case MBLOCK:
5380 buf[0] = Ctrl_V;
5381 sprintf((char *)buf + 1, "%ld", reglen + 1);
5382 break;
5383 }
5384 rettv->v_type = VAR_STRING;
5385 rettv->vval.v_string = vim_strsave(buf);
5386}
5387
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005388/*
5389 * Returns information (variables, options, etc.) about a tab page
5390 * as a dictionary.
5391 */
5392 static dict_T *
5393get_tabpage_info(tabpage_T *tp, int tp_idx)
5394{
5395 win_T *wp;
5396 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005397 list_T *l;
5398
5399 dict = dict_alloc();
5400 if (dict == NULL)
5401 return NULL;
5402
Bram Moolenaar33928832016-08-18 21:22:04 +02005403 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005404
5405 l = list_alloc();
5406 if (l != NULL)
5407 {
5408 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5409 wp; wp = wp->w_next)
5410 list_append_number(l, (varnumber_T)wp->w_id);
5411 dict_add_list(dict, "windows", l);
5412 }
5413
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005414 /* Make a reference to tabpage variables */
5415 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005416
5417 return dict;
5418}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005419
5420/*
5421 * "gettabinfo()" function
5422 */
5423 static void
5424f_gettabinfo(typval_T *argvars, typval_T *rettv)
5425{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005426 tabpage_T *tp, *tparg = NULL;
5427 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005428 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005429
5430 if (rettv_list_alloc(rettv) != OK)
5431 return;
5432
5433 if (argvars[0].v_type != VAR_UNKNOWN)
5434 {
5435 /* Information about one tab page */
5436 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5437 if (tparg == NULL)
5438 return;
5439 }
5440
5441 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005442 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005443 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005444 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005445 if (tparg != NULL && tp != tparg)
5446 continue;
5447 d = get_tabpage_info(tp, tpnr);
5448 if (d != NULL)
5449 list_append_dict(rettv->vval.v_list, d);
5450 if (tparg != NULL)
5451 return;
5452 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005453}
5454
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005455/*
5456 * "gettabvar()" function
5457 */
5458 static void
5459f_gettabvar(typval_T *argvars, typval_T *rettv)
5460{
5461 win_T *oldcurwin;
5462 tabpage_T *tp, *oldtabpage;
5463 dictitem_T *v;
5464 char_u *varname;
5465 int done = FALSE;
5466
5467 rettv->v_type = VAR_STRING;
5468 rettv->vval.v_string = NULL;
5469
5470 varname = get_tv_string_chk(&argvars[1]);
5471 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5472 if (tp != NULL && varname != NULL)
5473 {
5474 /* Set tp to be our tabpage, temporarily. Also set the window to the
5475 * first window in the tabpage, otherwise the window is not valid. */
5476 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005477 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5478 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 {
5480 /* look up the variable */
5481 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5482 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5483 if (v != NULL)
5484 {
5485 copy_tv(&v->di_tv, rettv);
5486 done = TRUE;
5487 }
5488 }
5489
5490 /* restore previous notion of curwin */
5491 restore_win(oldcurwin, oldtabpage, TRUE);
5492 }
5493
5494 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5495 copy_tv(&argvars[2], rettv);
5496}
5497
5498/*
5499 * "gettabwinvar()" function
5500 */
5501 static void
5502f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5503{
5504 getwinvar(argvars, rettv, 1);
5505}
5506
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005507/*
5508 * Returns information about a window as a dictionary.
5509 */
5510 static dict_T *
5511get_win_info(win_T *wp, short tpnr, short winnr)
5512{
5513 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005514
5515 dict = dict_alloc();
5516 if (dict == NULL)
5517 return NULL;
5518
Bram Moolenaar33928832016-08-18 21:22:04 +02005519 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5520 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005521 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5522 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005523#ifdef FEAT_MENU
5524 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5525#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005526 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005527 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005528
Bram Moolenaar69905d12017-08-13 18:14:47 +02005529#ifdef FEAT_TERMINAL
5530 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5531#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005532#ifdef FEAT_QUICKFIX
5533 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5534 dict_add_nr_str(dict, "loclist",
5535 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5536#endif
5537
Bram Moolenaar30567352016-08-27 21:25:44 +02005538 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005539 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005540
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005541 return dict;
5542}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005543
5544/*
5545 * "getwininfo()" function
5546 */
5547 static void
5548f_getwininfo(typval_T *argvars, typval_T *rettv)
5549{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005550 tabpage_T *tp;
5551 win_T *wp = NULL, *wparg = NULL;
5552 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005553 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005554
5555 if (rettv_list_alloc(rettv) != OK)
5556 return;
5557
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005558 if (argvars[0].v_type != VAR_UNKNOWN)
5559 {
5560 wparg = win_id2wp(argvars);
5561 if (wparg == NULL)
5562 return;
5563 }
5564
5565 /* Collect information about either all the windows across all the tab
5566 * pages or one particular window.
5567 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005568 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005569 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005570 tabnr++;
5571 winnr = 0;
5572 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005573 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005574 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005575 if (wparg != NULL && wp != wparg)
5576 continue;
5577 d = get_win_info(wp, tabnr, winnr);
5578 if (d != NULL)
5579 list_append_dict(rettv->vval.v_list, d);
5580 if (wparg != NULL)
5581 /* found information about a specific window */
5582 return;
5583 }
5584 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005585}
5586
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005587/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005588 * "win_findbuf()" function
5589 */
5590 static void
5591f_win_findbuf(typval_T *argvars, typval_T *rettv)
5592{
5593 if (rettv_list_alloc(rettv) != FAIL)
5594 win_findbuf(argvars, rettv->vval.v_list);
5595}
5596
5597/*
5598 * "win_getid()" function
5599 */
5600 static void
5601f_win_getid(typval_T *argvars, typval_T *rettv)
5602{
5603 rettv->vval.v_number = win_getid(argvars);
5604}
5605
5606/*
5607 * "win_gotoid()" function
5608 */
5609 static void
5610f_win_gotoid(typval_T *argvars, typval_T *rettv)
5611{
5612 rettv->vval.v_number = win_gotoid(argvars);
5613}
5614
5615/*
5616 * "win_id2tabwin()" function
5617 */
5618 static void
5619f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5620{
5621 if (rettv_list_alloc(rettv) != FAIL)
5622 win_id2tabwin(argvars, rettv->vval.v_list);
5623}
5624
5625/*
5626 * "win_id2win()" function
5627 */
5628 static void
5629f_win_id2win(typval_T *argvars, typval_T *rettv)
5630{
5631 rettv->vval.v_number = win_id2win(argvars);
5632}
5633
5634/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005635 * "win_screenpos()" function
5636 */
5637 static void
5638f_win_screenpos(typval_T *argvars, typval_T *rettv)
5639{
5640 win_T *wp;
5641
5642 if (rettv_list_alloc(rettv) == FAIL)
5643 return;
5644
5645 wp = find_win_by_nr(&argvars[0], NULL);
5646 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5647 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5648}
5649
5650/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005651 * "getwinpos({timeout})" function
5652 */
5653 static void
5654f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5655{
5656 int x = -1;
5657 int y = -1;
5658
5659 if (rettv_list_alloc(rettv) == FAIL)
5660 return;
5661#ifdef FEAT_GUI
5662 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005663 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005664# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5665 else
5666# endif
5667#endif
5668#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5669 {
5670 varnumber_T timeout = 100;
5671
5672 if (argvars[0].v_type != VAR_UNKNOWN)
5673 timeout = get_tv_number(&argvars[0]);
5674 term_get_winpos(&x, &y, timeout);
5675 }
5676#endif
5677 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5678 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5679}
5680
5681
5682/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005683 * "getwinposx()" function
5684 */
5685 static void
5686f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5687{
5688 rettv->vval.v_number = -1;
5689#ifdef FEAT_GUI
5690 if (gui.in_use)
5691 {
5692 int x, y;
5693
5694 if (gui_mch_get_winpos(&x, &y) == OK)
5695 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005696 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005697 }
5698#endif
5699#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5700 {
5701 int x, y;
5702
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005703 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005704 rettv->vval.v_number = x;
5705 }
5706#endif
5707}
5708
5709/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005710 * "getwinposy()" function
5711 */
5712 static void
5713f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5714{
5715 rettv->vval.v_number = -1;
5716#ifdef FEAT_GUI
5717 if (gui.in_use)
5718 {
5719 int x, y;
5720
5721 if (gui_mch_get_winpos(&x, &y) == OK)
5722 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005723 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005724 }
5725#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005726#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5727 {
5728 int x, y;
5729
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005730 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005731 rettv->vval.v_number = y;
5732 }
5733#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734}
5735
5736/*
5737 * "getwinvar()" function
5738 */
5739 static void
5740f_getwinvar(typval_T *argvars, typval_T *rettv)
5741{
5742 getwinvar(argvars, rettv, 0);
5743}
5744
5745/*
5746 * "glob()" function
5747 */
5748 static void
5749f_glob(typval_T *argvars, typval_T *rettv)
5750{
5751 int options = WILD_SILENT|WILD_USE_NL;
5752 expand_T xpc;
5753 int error = FALSE;
5754
5755 /* When the optional second argument is non-zero, don't remove matches
5756 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5757 rettv->v_type = VAR_STRING;
5758 if (argvars[1].v_type != VAR_UNKNOWN)
5759 {
5760 if (get_tv_number_chk(&argvars[1], &error))
5761 options |= WILD_KEEP_ALL;
5762 if (argvars[2].v_type != VAR_UNKNOWN)
5763 {
5764 if (get_tv_number_chk(&argvars[2], &error))
5765 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005766 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005767 }
5768 if (argvars[3].v_type != VAR_UNKNOWN
5769 && get_tv_number_chk(&argvars[3], &error))
5770 options |= WILD_ALLLINKS;
5771 }
5772 }
5773 if (!error)
5774 {
5775 ExpandInit(&xpc);
5776 xpc.xp_context = EXPAND_FILES;
5777 if (p_wic)
5778 options += WILD_ICASE;
5779 if (rettv->v_type == VAR_STRING)
5780 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5781 NULL, options, WILD_ALL);
5782 else if (rettv_list_alloc(rettv) != FAIL)
5783 {
5784 int i;
5785
5786 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5787 NULL, options, WILD_ALL_KEEP);
5788 for (i = 0; i < xpc.xp_numfiles; i++)
5789 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5790
5791 ExpandCleanup(&xpc);
5792 }
5793 }
5794 else
5795 rettv->vval.v_string = NULL;
5796}
5797
5798/*
5799 * "globpath()" function
5800 */
5801 static void
5802f_globpath(typval_T *argvars, typval_T *rettv)
5803{
5804 int flags = 0;
5805 char_u buf1[NUMBUFLEN];
5806 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5807 int error = FALSE;
5808 garray_T ga;
5809 int i;
5810
5811 /* When the optional second argument is non-zero, don't remove matches
5812 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5813 rettv->v_type = VAR_STRING;
5814 if (argvars[2].v_type != VAR_UNKNOWN)
5815 {
5816 if (get_tv_number_chk(&argvars[2], &error))
5817 flags |= WILD_KEEP_ALL;
5818 if (argvars[3].v_type != VAR_UNKNOWN)
5819 {
5820 if (get_tv_number_chk(&argvars[3], &error))
5821 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005822 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005823 }
5824 if (argvars[4].v_type != VAR_UNKNOWN
5825 && get_tv_number_chk(&argvars[4], &error))
5826 flags |= WILD_ALLLINKS;
5827 }
5828 }
5829 if (file != NULL && !error)
5830 {
5831 ga_init2(&ga, (int)sizeof(char_u *), 10);
5832 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5833 if (rettv->v_type == VAR_STRING)
5834 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5835 else if (rettv_list_alloc(rettv) != FAIL)
5836 for (i = 0; i < ga.ga_len; ++i)
5837 list_append_string(rettv->vval.v_list,
5838 ((char_u **)(ga.ga_data))[i], -1);
5839 ga_clear_strings(&ga);
5840 }
5841 else
5842 rettv->vval.v_string = NULL;
5843}
5844
5845/*
5846 * "glob2regpat()" function
5847 */
5848 static void
5849f_glob2regpat(typval_T *argvars, typval_T *rettv)
5850{
5851 char_u *pat = get_tv_string_chk(&argvars[0]);
5852
5853 rettv->v_type = VAR_STRING;
5854 rettv->vval.v_string = (pat == NULL)
5855 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5856}
5857
5858/* for VIM_VERSION_ defines */
5859#include "version.h"
5860
5861/*
5862 * "has()" function
5863 */
5864 static void
5865f_has(typval_T *argvars, typval_T *rettv)
5866{
5867 int i;
5868 char_u *name;
5869 int n = FALSE;
5870 static char *(has_list[]) =
5871 {
5872#ifdef AMIGA
5873 "amiga",
5874# ifdef FEAT_ARP
5875 "arp",
5876# endif
5877#endif
5878#ifdef __BEOS__
5879 "beos",
5880#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005881#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005882 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5883 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005884# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005885 "macunix", /* Mac OS X, with the darwin feature */
5886 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005887# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005888#endif
5889#ifdef __QNX__
5890 "qnx",
5891#endif
5892#ifdef UNIX
5893 "unix",
5894#endif
5895#ifdef VMS
5896 "vms",
5897#endif
5898#ifdef WIN32
5899 "win32",
5900#endif
5901#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5902 "win32unix",
5903#endif
5904#if defined(WIN64) || defined(_WIN64)
5905 "win64",
5906#endif
5907#ifdef EBCDIC
5908 "ebcdic",
5909#endif
5910#ifndef CASE_INSENSITIVE_FILENAME
5911 "fname_case",
5912#endif
5913#ifdef HAVE_ACL
5914 "acl",
5915#endif
5916#ifdef FEAT_ARABIC
5917 "arabic",
5918#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005919 "autocmd",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005920#ifdef FEAT_AUTOSERVERNAME
5921 "autoservername",
5922#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005923#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005924 "balloon_eval",
5925# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5926 "balloon_multiline",
5927# endif
5928#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005929#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005930 "balloon_eval_term",
5931#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005932#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5933 "builtin_terms",
5934# ifdef ALL_BUILTIN_TCAPS
5935 "all_builtin_terms",
5936# endif
5937#endif
5938#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5939 || defined(FEAT_GUI_W32) \
5940 || defined(FEAT_GUI_MOTIF))
5941 "browsefilter",
5942#endif
5943#ifdef FEAT_BYTEOFF
5944 "byte_offset",
5945#endif
5946#ifdef FEAT_JOB_CHANNEL
5947 "channel",
5948#endif
5949#ifdef FEAT_CINDENT
5950 "cindent",
5951#endif
5952#ifdef FEAT_CLIENTSERVER
5953 "clientserver",
5954#endif
5955#ifdef FEAT_CLIPBOARD
5956 "clipboard",
5957#endif
5958#ifdef FEAT_CMDL_COMPL
5959 "cmdline_compl",
5960#endif
5961#ifdef FEAT_CMDHIST
5962 "cmdline_hist",
5963#endif
5964#ifdef FEAT_COMMENTS
5965 "comments",
5966#endif
5967#ifdef FEAT_CONCEAL
5968 "conceal",
5969#endif
5970#ifdef FEAT_CRYPT
5971 "cryptv",
5972 "crypt-blowfish",
5973 "crypt-blowfish2",
5974#endif
5975#ifdef FEAT_CSCOPE
5976 "cscope",
5977#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005979#ifdef CURSOR_SHAPE
5980 "cursorshape",
5981#endif
5982#ifdef DEBUG
5983 "debug",
5984#endif
5985#ifdef FEAT_CON_DIALOG
5986 "dialog_con",
5987#endif
5988#ifdef FEAT_GUI_DIALOG
5989 "dialog_gui",
5990#endif
5991#ifdef FEAT_DIFF
5992 "diff",
5993#endif
5994#ifdef FEAT_DIGRAPHS
5995 "digraphs",
5996#endif
5997#ifdef FEAT_DIRECTX
5998 "directx",
5999#endif
6000#ifdef FEAT_DND
6001 "dnd",
6002#endif
6003#ifdef FEAT_EMACS_TAGS
6004 "emacs_tags",
6005#endif
6006 "eval", /* always present, of course! */
6007 "ex_extra", /* graduated feature */
6008#ifdef FEAT_SEARCH_EXTRA
6009 "extra_search",
6010#endif
6011#ifdef FEAT_FKMAP
6012 "farsi",
6013#endif
6014#ifdef FEAT_SEARCHPATH
6015 "file_in_path",
6016#endif
6017#ifdef FEAT_FILTERPIPE
6018 "filterpipe",
6019#endif
6020#ifdef FEAT_FIND_ID
6021 "find_in_path",
6022#endif
6023#ifdef FEAT_FLOAT
6024 "float",
6025#endif
6026#ifdef FEAT_FOLDING
6027 "folding",
6028#endif
6029#ifdef FEAT_FOOTER
6030 "footer",
6031#endif
6032#if !defined(USE_SYSTEM) && defined(UNIX)
6033 "fork",
6034#endif
6035#ifdef FEAT_GETTEXT
6036 "gettext",
6037#endif
6038#ifdef FEAT_GUI
6039 "gui",
6040#endif
6041#ifdef FEAT_GUI_ATHENA
6042# ifdef FEAT_GUI_NEXTAW
6043 "gui_neXtaw",
6044# else
6045 "gui_athena",
6046# endif
6047#endif
6048#ifdef FEAT_GUI_GTK
6049 "gui_gtk",
6050# ifdef USE_GTK3
6051 "gui_gtk3",
6052# else
6053 "gui_gtk2",
6054# endif
6055#endif
6056#ifdef FEAT_GUI_GNOME
6057 "gui_gnome",
6058#endif
6059#ifdef FEAT_GUI_MAC
6060 "gui_mac",
6061#endif
6062#ifdef FEAT_GUI_MOTIF
6063 "gui_motif",
6064#endif
6065#ifdef FEAT_GUI_PHOTON
6066 "gui_photon",
6067#endif
6068#ifdef FEAT_GUI_W32
6069 "gui_win32",
6070#endif
6071#ifdef FEAT_HANGULIN
6072 "hangul_input",
6073#endif
6074#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6075 "iconv",
6076#endif
6077#ifdef FEAT_INS_EXPAND
6078 "insert_expand",
6079#endif
6080#ifdef FEAT_JOB_CHANNEL
6081 "job",
6082#endif
6083#ifdef FEAT_JUMPLIST
6084 "jumplist",
6085#endif
6086#ifdef FEAT_KEYMAP
6087 "keymap",
6088#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006089 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090#ifdef FEAT_LANGMAP
6091 "langmap",
6092#endif
6093#ifdef FEAT_LIBCALL
6094 "libcall",
6095#endif
6096#ifdef FEAT_LINEBREAK
6097 "linebreak",
6098#endif
6099#ifdef FEAT_LISP
6100 "lispindent",
6101#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006102 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006103#ifdef FEAT_LOCALMAP
6104 "localmap",
6105#endif
6106#ifdef FEAT_LUA
6107# ifndef DYNAMIC_LUA
6108 "lua",
6109# endif
6110#endif
6111#ifdef FEAT_MENU
6112 "menu",
6113#endif
6114#ifdef FEAT_SESSION
6115 "mksession",
6116#endif
6117#ifdef FEAT_MODIFY_FNAME
6118 "modify_fname",
6119#endif
6120#ifdef FEAT_MOUSE
6121 "mouse",
6122#endif
6123#ifdef FEAT_MOUSESHAPE
6124 "mouseshape",
6125#endif
6126#if defined(UNIX) || defined(VMS)
6127# ifdef FEAT_MOUSE_DEC
6128 "mouse_dec",
6129# endif
6130# ifdef FEAT_MOUSE_GPM
6131 "mouse_gpm",
6132# endif
6133# ifdef FEAT_MOUSE_JSB
6134 "mouse_jsbterm",
6135# endif
6136# ifdef FEAT_MOUSE_NET
6137 "mouse_netterm",
6138# endif
6139# ifdef FEAT_MOUSE_PTERM
6140 "mouse_pterm",
6141# endif
6142# ifdef FEAT_MOUSE_SGR
6143 "mouse_sgr",
6144# endif
6145# ifdef FEAT_SYSMOUSE
6146 "mouse_sysmouse",
6147# endif
6148# ifdef FEAT_MOUSE_URXVT
6149 "mouse_urxvt",
6150# endif
6151# ifdef FEAT_MOUSE_XTERM
6152 "mouse_xterm",
6153# endif
6154#endif
6155#ifdef FEAT_MBYTE
6156 "multi_byte",
6157#endif
6158#ifdef FEAT_MBYTE_IME
6159 "multi_byte_ime",
6160#endif
6161#ifdef FEAT_MULTI_LANG
6162 "multi_lang",
6163#endif
6164#ifdef FEAT_MZSCHEME
6165#ifndef DYNAMIC_MZSCHEME
6166 "mzscheme",
6167#endif
6168#endif
6169#ifdef FEAT_NUM64
6170 "num64",
6171#endif
6172#ifdef FEAT_OLE
6173 "ole",
6174#endif
6175 "packages",
6176#ifdef FEAT_PATH_EXTRA
6177 "path_extra",
6178#endif
6179#ifdef FEAT_PERL
6180#ifndef DYNAMIC_PERL
6181 "perl",
6182#endif
6183#endif
6184#ifdef FEAT_PERSISTENT_UNDO
6185 "persistent_undo",
6186#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006187#if defined(FEAT_PYTHON)
6188 "python_compiled",
6189# if defined(DYNAMIC_PYTHON)
6190 "python_dynamic",
6191# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006192 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006193 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006194# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006196#if defined(FEAT_PYTHON3)
6197 "python3_compiled",
6198# if defined(DYNAMIC_PYTHON3)
6199 "python3_dynamic",
6200# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006201 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006202 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006203# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006204#endif
6205#ifdef FEAT_POSTSCRIPT
6206 "postscript",
6207#endif
6208#ifdef FEAT_PRINTER
6209 "printer",
6210#endif
6211#ifdef FEAT_PROFILE
6212 "profile",
6213#endif
6214#ifdef FEAT_RELTIME
6215 "reltime",
6216#endif
6217#ifdef FEAT_QUICKFIX
6218 "quickfix",
6219#endif
6220#ifdef FEAT_RIGHTLEFT
6221 "rightleft",
6222#endif
6223#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6224 "ruby",
6225#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006226 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006227#ifdef FEAT_CMDL_INFO
6228 "showcmd",
6229 "cmdline_info",
6230#endif
6231#ifdef FEAT_SIGNS
6232 "signs",
6233#endif
6234#ifdef FEAT_SMARTINDENT
6235 "smartindent",
6236#endif
6237#ifdef STARTUPTIME
6238 "startuptime",
6239#endif
6240#ifdef FEAT_STL_OPT
6241 "statusline",
6242#endif
6243#ifdef FEAT_SUN_WORKSHOP
6244 "sun_workshop",
6245#endif
6246#ifdef FEAT_NETBEANS_INTG
6247 "netbeans_intg",
6248#endif
6249#ifdef FEAT_SPELL
6250 "spell",
6251#endif
6252#ifdef FEAT_SYN_HL
6253 "syntax",
6254#endif
6255#if defined(USE_SYSTEM) || !defined(UNIX)
6256 "system",
6257#endif
6258#ifdef FEAT_TAG_BINS
6259 "tag_binary",
6260#endif
6261#ifdef FEAT_TAG_OLDSTATIC
6262 "tag_old_static",
6263#endif
6264#ifdef FEAT_TAG_ANYWHITE
6265 "tag_any_white",
6266#endif
6267#ifdef FEAT_TCL
6268# ifndef DYNAMIC_TCL
6269 "tcl",
6270# endif
6271#endif
6272#ifdef FEAT_TERMGUICOLORS
6273 "termguicolors",
6274#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006275#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006276 "terminal",
6277#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006278#ifdef TERMINFO
6279 "terminfo",
6280#endif
6281#ifdef FEAT_TERMRESPONSE
6282 "termresponse",
6283#endif
6284#ifdef FEAT_TEXTOBJ
6285 "textobjects",
6286#endif
6287#ifdef HAVE_TGETENT
6288 "tgetent",
6289#endif
6290#ifdef FEAT_TIMERS
6291 "timers",
6292#endif
6293#ifdef FEAT_TITLE
6294 "title",
6295#endif
6296#ifdef FEAT_TOOLBAR
6297 "toolbar",
6298#endif
6299#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6300 "unnamedplus",
6301#endif
6302#ifdef FEAT_USR_CMDS
6303 "user-commands", /* was accidentally included in 5.4 */
6304 "user_commands",
6305#endif
6306#ifdef FEAT_VIMINFO
6307 "viminfo",
6308#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006309 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006310#ifdef FEAT_VIRTUALEDIT
6311 "virtualedit",
6312#endif
6313 "visual",
6314#ifdef FEAT_VISUALEXTRA
6315 "visualextra",
6316#endif
6317#ifdef FEAT_VREPLACE
6318 "vreplace",
6319#endif
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006320#ifdef FEAT_VTP
6321 "vtp",
6322#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323#ifdef FEAT_WILDIGN
6324 "wildignore",
6325#endif
6326#ifdef FEAT_WILDMENU
6327 "wildmenu",
6328#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006329 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006330#ifdef FEAT_WAK
6331 "winaltkeys",
6332#endif
6333#ifdef FEAT_WRITEBACKUP
6334 "writebackup",
6335#endif
6336#ifdef FEAT_XIM
6337 "xim",
6338#endif
6339#ifdef FEAT_XFONTSET
6340 "xfontset",
6341#endif
6342#ifdef FEAT_XPM_W32
6343 "xpm",
6344 "xpm_w32", /* for backward compatibility */
6345#else
6346# if defined(HAVE_XPM)
6347 "xpm",
6348# endif
6349#endif
6350#ifdef USE_XSMP
6351 "xsmp",
6352#endif
6353#ifdef USE_XSMP_INTERACT
6354 "xsmp_interact",
6355#endif
6356#ifdef FEAT_XCLIPBOARD
6357 "xterm_clipboard",
6358#endif
6359#ifdef FEAT_XTERM_SAVE
6360 "xterm_save",
6361#endif
6362#if defined(UNIX) && defined(FEAT_X11)
6363 "X11",
6364#endif
6365 NULL
6366 };
6367
6368 name = get_tv_string(&argvars[0]);
6369 for (i = 0; has_list[i] != NULL; ++i)
6370 if (STRICMP(name, has_list[i]) == 0)
6371 {
6372 n = TRUE;
6373 break;
6374 }
6375
6376 if (n == FALSE)
6377 {
6378 if (STRNICMP(name, "patch", 5) == 0)
6379 {
6380 if (name[5] == '-'
6381 && STRLEN(name) >= 11
6382 && vim_isdigit(name[6])
6383 && vim_isdigit(name[8])
6384 && vim_isdigit(name[10]))
6385 {
6386 int major = atoi((char *)name + 6);
6387 int minor = atoi((char *)name + 8);
6388
6389 /* Expect "patch-9.9.01234". */
6390 n = (major < VIM_VERSION_MAJOR
6391 || (major == VIM_VERSION_MAJOR
6392 && (minor < VIM_VERSION_MINOR
6393 || (minor == VIM_VERSION_MINOR
6394 && has_patch(atoi((char *)name + 10))))));
6395 }
6396 else
6397 n = has_patch(atoi((char *)name + 5));
6398 }
6399 else if (STRICMP(name, "vim_starting") == 0)
6400 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006401 else if (STRICMP(name, "ttyin") == 0)
6402 n = mch_input_isatty();
6403 else if (STRICMP(name, "ttyout") == 0)
6404 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006405#ifdef FEAT_MBYTE
6406 else if (STRICMP(name, "multi_byte_encoding") == 0)
6407 n = has_mbyte;
6408#endif
6409#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6410 else if (STRICMP(name, "balloon_multiline") == 0)
6411 n = multiline_balloon_available();
6412#endif
6413#ifdef DYNAMIC_TCL
6414 else if (STRICMP(name, "tcl") == 0)
6415 n = tcl_enabled(FALSE);
6416#endif
6417#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6418 else if (STRICMP(name, "iconv") == 0)
6419 n = iconv_enabled(FALSE);
6420#endif
6421#ifdef DYNAMIC_LUA
6422 else if (STRICMP(name, "lua") == 0)
6423 n = lua_enabled(FALSE);
6424#endif
6425#ifdef DYNAMIC_MZSCHEME
6426 else if (STRICMP(name, "mzscheme") == 0)
6427 n = mzscheme_enabled(FALSE);
6428#endif
6429#ifdef DYNAMIC_RUBY
6430 else if (STRICMP(name, "ruby") == 0)
6431 n = ruby_enabled(FALSE);
6432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006433#ifdef DYNAMIC_PYTHON
6434 else if (STRICMP(name, "python") == 0)
6435 n = python_enabled(FALSE);
6436#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006437#ifdef DYNAMIC_PYTHON3
6438 else if (STRICMP(name, "python3") == 0)
6439 n = python3_enabled(FALSE);
6440#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006441#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6442 else if (STRICMP(name, "pythonx") == 0)
6443 {
6444# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6445 if (p_pyx == 0)
6446 n = python3_enabled(FALSE) || python_enabled(FALSE);
6447 else if (p_pyx == 3)
6448 n = python3_enabled(FALSE);
6449 else if (p_pyx == 2)
6450 n = python_enabled(FALSE);
6451# elif defined(DYNAMIC_PYTHON)
6452 n = python_enabled(FALSE);
6453# elif defined(DYNAMIC_PYTHON3)
6454 n = python3_enabled(FALSE);
6455# endif
6456 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006457#endif
6458#ifdef DYNAMIC_PERL
6459 else if (STRICMP(name, "perl") == 0)
6460 n = perl_enabled(FALSE);
6461#endif
6462#ifdef FEAT_GUI
6463 else if (STRICMP(name, "gui_running") == 0)
6464 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465# ifdef FEAT_BROWSE
6466 else if (STRICMP(name, "browse") == 0)
6467 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6468# endif
6469#endif
6470#ifdef FEAT_SYN_HL
6471 else if (STRICMP(name, "syntax_items") == 0)
6472 n = syntax_present(curwin);
6473#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006474#ifdef FEAT_VTP
6475 else if (STRICMP(name, "vcon") == 0)
6476 n = has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006477#endif
6478#ifdef FEAT_NETBEANS_INTG
6479 else if (STRICMP(name, "netbeans_enabled") == 0)
6480 n = netbeans_active();
6481#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006482#if defined(FEAT_TERMINAL) && defined(WIN3264)
6483 else if (STRICMP(name, "terminal") == 0)
6484 n = terminal_enabled();
6485#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486 }
6487
6488 rettv->vval.v_number = n;
6489}
6490
6491/*
6492 * "has_key()" function
6493 */
6494 static void
6495f_has_key(typval_T *argvars, typval_T *rettv)
6496{
6497 if (argvars[0].v_type != VAR_DICT)
6498 {
6499 EMSG(_(e_dictreq));
6500 return;
6501 }
6502 if (argvars[0].vval.v_dict == NULL)
6503 return;
6504
6505 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6506 get_tv_string(&argvars[1]), -1) != NULL;
6507}
6508
6509/*
6510 * "haslocaldir()" function
6511 */
6512 static void
6513f_haslocaldir(typval_T *argvars, typval_T *rettv)
6514{
6515 win_T *wp = NULL;
6516
6517 wp = find_tabwin(&argvars[0], &argvars[1]);
6518 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6519}
6520
6521/*
6522 * "hasmapto()" function
6523 */
6524 static void
6525f_hasmapto(typval_T *argvars, typval_T *rettv)
6526{
6527 char_u *name;
6528 char_u *mode;
6529 char_u buf[NUMBUFLEN];
6530 int abbr = FALSE;
6531
6532 name = get_tv_string(&argvars[0]);
6533 if (argvars[1].v_type == VAR_UNKNOWN)
6534 mode = (char_u *)"nvo";
6535 else
6536 {
6537 mode = get_tv_string_buf(&argvars[1], buf);
6538 if (argvars[2].v_type != VAR_UNKNOWN)
6539 abbr = (int)get_tv_number(&argvars[2]);
6540 }
6541
6542 if (map_to_exists(name, mode, abbr))
6543 rettv->vval.v_number = TRUE;
6544 else
6545 rettv->vval.v_number = FALSE;
6546}
6547
6548/*
6549 * "histadd()" function
6550 */
6551 static void
6552f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6553{
6554#ifdef FEAT_CMDHIST
6555 int histype;
6556 char_u *str;
6557 char_u buf[NUMBUFLEN];
6558#endif
6559
6560 rettv->vval.v_number = FALSE;
6561 if (check_restricted() || check_secure())
6562 return;
6563#ifdef FEAT_CMDHIST
6564 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6565 histype = str != NULL ? get_histtype(str) : -1;
6566 if (histype >= 0)
6567 {
6568 str = get_tv_string_buf(&argvars[1], buf);
6569 if (*str != NUL)
6570 {
6571 init_history();
6572 add_to_history(histype, str, FALSE, NUL);
6573 rettv->vval.v_number = TRUE;
6574 return;
6575 }
6576 }
6577#endif
6578}
6579
6580/*
6581 * "histdel()" function
6582 */
6583 static void
6584f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6585{
6586#ifdef FEAT_CMDHIST
6587 int n;
6588 char_u buf[NUMBUFLEN];
6589 char_u *str;
6590
6591 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6592 if (str == NULL)
6593 n = 0;
6594 else if (argvars[1].v_type == VAR_UNKNOWN)
6595 /* only one argument: clear entire history */
6596 n = clr_history(get_histtype(str));
6597 else if (argvars[1].v_type == VAR_NUMBER)
6598 /* index given: remove that entry */
6599 n = del_history_idx(get_histtype(str),
6600 (int)get_tv_number(&argvars[1]));
6601 else
6602 /* string given: remove all matching entries */
6603 n = del_history_entry(get_histtype(str),
6604 get_tv_string_buf(&argvars[1], buf));
6605 rettv->vval.v_number = n;
6606#endif
6607}
6608
6609/*
6610 * "histget()" function
6611 */
6612 static void
6613f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6614{
6615#ifdef FEAT_CMDHIST
6616 int type;
6617 int idx;
6618 char_u *str;
6619
6620 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6621 if (str == NULL)
6622 rettv->vval.v_string = NULL;
6623 else
6624 {
6625 type = get_histtype(str);
6626 if (argvars[1].v_type == VAR_UNKNOWN)
6627 idx = get_history_idx(type);
6628 else
6629 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6630 /* -1 on type error */
6631 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6632 }
6633#else
6634 rettv->vval.v_string = NULL;
6635#endif
6636 rettv->v_type = VAR_STRING;
6637}
6638
6639/*
6640 * "histnr()" function
6641 */
6642 static void
6643f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6644{
6645 int i;
6646
6647#ifdef FEAT_CMDHIST
6648 char_u *history = get_tv_string_chk(&argvars[0]);
6649
6650 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6651 if (i >= HIST_CMD && i < HIST_COUNT)
6652 i = get_history_idx(i);
6653 else
6654#endif
6655 i = -1;
6656 rettv->vval.v_number = i;
6657}
6658
6659/*
6660 * "highlightID(name)" function
6661 */
6662 static void
6663f_hlID(typval_T *argvars, typval_T *rettv)
6664{
6665 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6666}
6667
6668/*
6669 * "highlight_exists()" function
6670 */
6671 static void
6672f_hlexists(typval_T *argvars, typval_T *rettv)
6673{
6674 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6675}
6676
6677/*
6678 * "hostname()" function
6679 */
6680 static void
6681f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6682{
6683 char_u hostname[256];
6684
6685 mch_get_host_name(hostname, 256);
6686 rettv->v_type = VAR_STRING;
6687 rettv->vval.v_string = vim_strsave(hostname);
6688}
6689
6690/*
6691 * iconv() function
6692 */
6693 static void
6694f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6695{
6696#ifdef FEAT_MBYTE
6697 char_u buf1[NUMBUFLEN];
6698 char_u buf2[NUMBUFLEN];
6699 char_u *from, *to, *str;
6700 vimconv_T vimconv;
6701#endif
6702
6703 rettv->v_type = VAR_STRING;
6704 rettv->vval.v_string = NULL;
6705
6706#ifdef FEAT_MBYTE
6707 str = get_tv_string(&argvars[0]);
6708 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6709 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6710 vimconv.vc_type = CONV_NONE;
6711 convert_setup(&vimconv, from, to);
6712
6713 /* If the encodings are equal, no conversion needed. */
6714 if (vimconv.vc_type == CONV_NONE)
6715 rettv->vval.v_string = vim_strsave(str);
6716 else
6717 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6718
6719 convert_setup(&vimconv, NULL, NULL);
6720 vim_free(from);
6721 vim_free(to);
6722#endif
6723}
6724
6725/*
6726 * "indent()" function
6727 */
6728 static void
6729f_indent(typval_T *argvars, typval_T *rettv)
6730{
6731 linenr_T lnum;
6732
6733 lnum = get_tv_lnum(argvars);
6734 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6735 rettv->vval.v_number = get_indent_lnum(lnum);
6736 else
6737 rettv->vval.v_number = -1;
6738}
6739
6740/*
6741 * "index()" function
6742 */
6743 static void
6744f_index(typval_T *argvars, typval_T *rettv)
6745{
6746 list_T *l;
6747 listitem_T *item;
6748 long idx = 0;
6749 int ic = FALSE;
6750
6751 rettv->vval.v_number = -1;
6752 if (argvars[0].v_type != VAR_LIST)
6753 {
6754 EMSG(_(e_listreq));
6755 return;
6756 }
6757 l = argvars[0].vval.v_list;
6758 if (l != NULL)
6759 {
6760 item = l->lv_first;
6761 if (argvars[2].v_type != VAR_UNKNOWN)
6762 {
6763 int error = FALSE;
6764
6765 /* Start at specified item. Use the cached index that list_find()
6766 * sets, so that a negative number also works. */
6767 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6768 idx = l->lv_idx;
6769 if (argvars[3].v_type != VAR_UNKNOWN)
6770 ic = (int)get_tv_number_chk(&argvars[3], &error);
6771 if (error)
6772 item = NULL;
6773 }
6774
6775 for ( ; item != NULL; item = item->li_next, ++idx)
6776 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6777 {
6778 rettv->vval.v_number = idx;
6779 break;
6780 }
6781 }
6782}
6783
6784static int inputsecret_flag = 0;
6785
6786/*
6787 * "input()" function
6788 * Also handles inputsecret() when inputsecret is set.
6789 */
6790 static void
6791f_input(typval_T *argvars, typval_T *rettv)
6792{
6793 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6794}
6795
6796/*
6797 * "inputdialog()" function
6798 */
6799 static void
6800f_inputdialog(typval_T *argvars, typval_T *rettv)
6801{
6802#if defined(FEAT_GUI_TEXTDIALOG)
6803 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6804 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6805 {
6806 char_u *message;
6807 char_u buf[NUMBUFLEN];
6808 char_u *defstr = (char_u *)"";
6809
6810 message = get_tv_string_chk(&argvars[0]);
6811 if (argvars[1].v_type != VAR_UNKNOWN
6812 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6813 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6814 else
6815 IObuff[0] = NUL;
6816 if (message != NULL && defstr != NULL
6817 && do_dialog(VIM_QUESTION, NULL, message,
6818 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6819 rettv->vval.v_string = vim_strsave(IObuff);
6820 else
6821 {
6822 if (message != NULL && defstr != NULL
6823 && argvars[1].v_type != VAR_UNKNOWN
6824 && argvars[2].v_type != VAR_UNKNOWN)
6825 rettv->vval.v_string = vim_strsave(
6826 get_tv_string_buf(&argvars[2], buf));
6827 else
6828 rettv->vval.v_string = NULL;
6829 }
6830 rettv->v_type = VAR_STRING;
6831 }
6832 else
6833#endif
6834 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6835}
6836
6837/*
6838 * "inputlist()" function
6839 */
6840 static void
6841f_inputlist(typval_T *argvars, typval_T *rettv)
6842{
6843 listitem_T *li;
6844 int selected;
6845 int mouse_used;
6846
6847#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006848 /* While starting up, there is no place to enter text. When running tests
6849 * with --not-a-term we assume feedkeys() will be used. */
6850 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 return;
6852#endif
6853 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6854 {
6855 EMSG2(_(e_listarg), "inputlist()");
6856 return;
6857 }
6858
6859 msg_start();
6860 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6861 lines_left = Rows; /* avoid more prompt */
6862 msg_scroll = TRUE;
6863 msg_clr_eos();
6864
6865 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6866 {
6867 msg_puts(get_tv_string(&li->li_tv));
6868 msg_putchar('\n');
6869 }
6870
6871 /* Ask for choice. */
6872 selected = prompt_for_number(&mouse_used);
6873 if (mouse_used)
6874 selected -= lines_left;
6875
6876 rettv->vval.v_number = selected;
6877}
6878
6879
6880static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6881
6882/*
6883 * "inputrestore()" function
6884 */
6885 static void
6886f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6887{
6888 if (ga_userinput.ga_len > 0)
6889 {
6890 --ga_userinput.ga_len;
6891 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6892 + ga_userinput.ga_len);
6893 /* default return is zero == OK */
6894 }
6895 else if (p_verbose > 1)
6896 {
6897 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6898 rettv->vval.v_number = 1; /* Failed */
6899 }
6900}
6901
6902/*
6903 * "inputsave()" function
6904 */
6905 static void
6906f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6907{
6908 /* Add an entry to the stack of typeahead storage. */
6909 if (ga_grow(&ga_userinput, 1) == OK)
6910 {
6911 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6912 + ga_userinput.ga_len);
6913 ++ga_userinput.ga_len;
6914 /* default return is zero == OK */
6915 }
6916 else
6917 rettv->vval.v_number = 1; /* Failed */
6918}
6919
6920/*
6921 * "inputsecret()" function
6922 */
6923 static void
6924f_inputsecret(typval_T *argvars, typval_T *rettv)
6925{
6926 ++cmdline_star;
6927 ++inputsecret_flag;
6928 f_input(argvars, rettv);
6929 --cmdline_star;
6930 --inputsecret_flag;
6931}
6932
6933/*
6934 * "insert()" function
6935 */
6936 static void
6937f_insert(typval_T *argvars, typval_T *rettv)
6938{
6939 long before = 0;
6940 listitem_T *item;
6941 list_T *l;
6942 int error = FALSE;
6943
6944 if (argvars[0].v_type != VAR_LIST)
6945 EMSG2(_(e_listarg), "insert()");
6946 else if ((l = argvars[0].vval.v_list) != NULL
6947 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6948 {
6949 if (argvars[2].v_type != VAR_UNKNOWN)
6950 before = (long)get_tv_number_chk(&argvars[2], &error);
6951 if (error)
6952 return; /* type error; errmsg already given */
6953
6954 if (before == l->lv_len)
6955 item = NULL;
6956 else
6957 {
6958 item = list_find(l, before);
6959 if (item == NULL)
6960 {
6961 EMSGN(_(e_listidx), before);
6962 l = NULL;
6963 }
6964 }
6965 if (l != NULL)
6966 {
6967 list_insert_tv(l, &argvars[1], item);
6968 copy_tv(&argvars[0], rettv);
6969 }
6970 }
6971}
6972
6973/*
6974 * "invert(expr)" function
6975 */
6976 static void
6977f_invert(typval_T *argvars, typval_T *rettv)
6978{
6979 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6980}
6981
6982/*
6983 * "isdirectory()" function
6984 */
6985 static void
6986f_isdirectory(typval_T *argvars, typval_T *rettv)
6987{
6988 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6989}
6990
6991/*
6992 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6993 * or it refers to a List or Dictionary that is locked.
6994 */
6995 static int
6996tv_islocked(typval_T *tv)
6997{
6998 return (tv->v_lock & VAR_LOCKED)
6999 || (tv->v_type == VAR_LIST
7000 && tv->vval.v_list != NULL
7001 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7002 || (tv->v_type == VAR_DICT
7003 && tv->vval.v_dict != NULL
7004 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7005}
7006
7007/*
7008 * "islocked()" function
7009 */
7010 static void
7011f_islocked(typval_T *argvars, typval_T *rettv)
7012{
7013 lval_T lv;
7014 char_u *end;
7015 dictitem_T *di;
7016
7017 rettv->vval.v_number = -1;
7018 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007019 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007020 if (end != NULL && lv.ll_name != NULL)
7021 {
7022 if (*end != NUL)
7023 EMSG(_(e_trailing));
7024 else
7025 {
7026 if (lv.ll_tv == NULL)
7027 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007028 di = find_var(lv.ll_name, NULL, TRUE);
7029 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007030 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007031 /* Consider a variable locked when:
7032 * 1. the variable itself is locked
7033 * 2. the value of the variable is locked.
7034 * 3. the List or Dict value is locked.
7035 */
7036 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7037 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038 }
7039 }
7040 else if (lv.ll_range)
7041 EMSG(_("E786: Range not allowed"));
7042 else if (lv.ll_newkey != NULL)
7043 EMSG2(_(e_dictkey), lv.ll_newkey);
7044 else if (lv.ll_list != NULL)
7045 /* List item. */
7046 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7047 else
7048 /* Dictionary item. */
7049 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7050 }
7051 }
7052
7053 clear_lval(&lv);
7054}
7055
7056#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7057/*
7058 * "isnan()" function
7059 */
7060 static void
7061f_isnan(typval_T *argvars, typval_T *rettv)
7062{
7063 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7064 && isnan(argvars[0].vval.v_float);
7065}
7066#endif
7067
7068/*
7069 * "items(dict)" function
7070 */
7071 static void
7072f_items(typval_T *argvars, typval_T *rettv)
7073{
7074 dict_list(argvars, rettv, 2);
7075}
7076
7077#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7078/*
7079 * Get the job from the argument.
7080 * Returns NULL if the job is invalid.
7081 */
7082 static job_T *
7083get_job_arg(typval_T *tv)
7084{
7085 job_T *job;
7086
7087 if (tv->v_type != VAR_JOB)
7088 {
7089 EMSG2(_(e_invarg2), get_tv_string(tv));
7090 return NULL;
7091 }
7092 job = tv->vval.v_job;
7093
7094 if (job == NULL)
7095 EMSG(_("E916: not a valid job"));
7096 return job;
7097}
7098
7099/*
7100 * "job_getchannel()" function
7101 */
7102 static void
7103f_job_getchannel(typval_T *argvars, typval_T *rettv)
7104{
7105 job_T *job = get_job_arg(&argvars[0]);
7106
7107 if (job != NULL)
7108 {
7109 rettv->v_type = VAR_CHANNEL;
7110 rettv->vval.v_channel = job->jv_channel;
7111 if (job->jv_channel != NULL)
7112 ++job->jv_channel->ch_refcount;
7113 }
7114}
7115
7116/*
7117 * "job_info()" function
7118 */
7119 static void
7120f_job_info(typval_T *argvars, typval_T *rettv)
7121{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007122 if (argvars[0].v_type != VAR_UNKNOWN)
7123 {
7124 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007125
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007126 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7127 job_info(job, rettv->vval.v_dict);
7128 }
7129 else if (rettv_list_alloc(rettv) == OK)
7130 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131}
7132
7133/*
7134 * "job_setoptions()" function
7135 */
7136 static void
7137f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7138{
7139 job_T *job = get_job_arg(&argvars[0]);
7140 jobopt_T opt;
7141
7142 if (job == NULL)
7143 return;
7144 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007145 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007146 job_set_options(job, &opt);
7147 free_job_options(&opt);
7148}
7149
7150/*
7151 * "job_start()" function
7152 */
7153 static void
7154f_job_start(typval_T *argvars, typval_T *rettv)
7155{
7156 rettv->v_type = VAR_JOB;
7157 if (check_restricted() || check_secure())
7158 return;
Bram Moolenaar13568252018-03-16 20:46:58 +01007159 rettv->vval.v_job = job_start(argvars, NULL, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160}
7161
7162/*
7163 * "job_status()" function
7164 */
7165 static void
7166f_job_status(typval_T *argvars, typval_T *rettv)
7167{
7168 job_T *job = get_job_arg(&argvars[0]);
7169
7170 if (job != NULL)
7171 {
7172 rettv->v_type = VAR_STRING;
7173 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7174 }
7175}
7176
7177/*
7178 * "job_stop()" function
7179 */
7180 static void
7181f_job_stop(typval_T *argvars, typval_T *rettv)
7182{
7183 job_T *job = get_job_arg(&argvars[0]);
7184
7185 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007186 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187}
7188#endif
7189
7190/*
7191 * "join()" function
7192 */
7193 static void
7194f_join(typval_T *argvars, typval_T *rettv)
7195{
7196 garray_T ga;
7197 char_u *sep;
7198
7199 if (argvars[0].v_type != VAR_LIST)
7200 {
7201 EMSG(_(e_listreq));
7202 return;
7203 }
7204 if (argvars[0].vval.v_list == NULL)
7205 return;
7206 if (argvars[1].v_type == VAR_UNKNOWN)
7207 sep = (char_u *)" ";
7208 else
7209 sep = get_tv_string_chk(&argvars[1]);
7210
7211 rettv->v_type = VAR_STRING;
7212
7213 if (sep != NULL)
7214 {
7215 ga_init2(&ga, (int)sizeof(char), 80);
7216 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7217 ga_append(&ga, NUL);
7218 rettv->vval.v_string = (char_u *)ga.ga_data;
7219 }
7220 else
7221 rettv->vval.v_string = NULL;
7222}
7223
7224/*
7225 * "js_decode()" function
7226 */
7227 static void
7228f_js_decode(typval_T *argvars, typval_T *rettv)
7229{
7230 js_read_T reader;
7231
7232 reader.js_buf = get_tv_string(&argvars[0]);
7233 reader.js_fill = NULL;
7234 reader.js_used = 0;
7235 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7236 EMSG(_(e_invarg));
7237}
7238
7239/*
7240 * "js_encode()" function
7241 */
7242 static void
7243f_js_encode(typval_T *argvars, typval_T *rettv)
7244{
7245 rettv->v_type = VAR_STRING;
7246 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7247}
7248
7249/*
7250 * "json_decode()" function
7251 */
7252 static void
7253f_json_decode(typval_T *argvars, typval_T *rettv)
7254{
7255 js_read_T reader;
7256
7257 reader.js_buf = get_tv_string(&argvars[0]);
7258 reader.js_fill = NULL;
7259 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007260 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007261}
7262
7263/*
7264 * "json_encode()" function
7265 */
7266 static void
7267f_json_encode(typval_T *argvars, typval_T *rettv)
7268{
7269 rettv->v_type = VAR_STRING;
7270 rettv->vval.v_string = json_encode(&argvars[0], 0);
7271}
7272
7273/*
7274 * "keys()" function
7275 */
7276 static void
7277f_keys(typval_T *argvars, typval_T *rettv)
7278{
7279 dict_list(argvars, rettv, 0);
7280}
7281
7282/*
7283 * "last_buffer_nr()" function.
7284 */
7285 static void
7286f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7287{
7288 int n = 0;
7289 buf_T *buf;
7290
Bram Moolenaar29323592016-07-24 22:04:11 +02007291 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007292 if (n < buf->b_fnum)
7293 n = buf->b_fnum;
7294
7295 rettv->vval.v_number = n;
7296}
7297
7298/*
7299 * "len()" function
7300 */
7301 static void
7302f_len(typval_T *argvars, typval_T *rettv)
7303{
7304 switch (argvars[0].v_type)
7305 {
7306 case VAR_STRING:
7307 case VAR_NUMBER:
7308 rettv->vval.v_number = (varnumber_T)STRLEN(
7309 get_tv_string(&argvars[0]));
7310 break;
7311 case VAR_LIST:
7312 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7313 break;
7314 case VAR_DICT:
7315 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7316 break;
7317 case VAR_UNKNOWN:
7318 case VAR_SPECIAL:
7319 case VAR_FLOAT:
7320 case VAR_FUNC:
7321 case VAR_PARTIAL:
7322 case VAR_JOB:
7323 case VAR_CHANNEL:
7324 EMSG(_("E701: Invalid type for len()"));
7325 break;
7326 }
7327}
7328
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007329 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007330libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007331{
7332#ifdef FEAT_LIBCALL
7333 char_u *string_in;
7334 char_u **string_result;
7335 int nr_result;
7336#endif
7337
7338 rettv->v_type = type;
7339 if (type != VAR_NUMBER)
7340 rettv->vval.v_string = NULL;
7341
7342 if (check_restricted() || check_secure())
7343 return;
7344
7345#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007346 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7348 {
7349 string_in = NULL;
7350 if (argvars[2].v_type == VAR_STRING)
7351 string_in = argvars[2].vval.v_string;
7352 if (type == VAR_NUMBER)
7353 string_result = NULL;
7354 else
7355 string_result = &rettv->vval.v_string;
7356 if (mch_libcall(argvars[0].vval.v_string,
7357 argvars[1].vval.v_string,
7358 string_in,
7359 argvars[2].vval.v_number,
7360 string_result,
7361 &nr_result) == OK
7362 && type == VAR_NUMBER)
7363 rettv->vval.v_number = nr_result;
7364 }
7365#endif
7366}
7367
7368/*
7369 * "libcall()" function
7370 */
7371 static void
7372f_libcall(typval_T *argvars, typval_T *rettv)
7373{
7374 libcall_common(argvars, rettv, VAR_STRING);
7375}
7376
7377/*
7378 * "libcallnr()" function
7379 */
7380 static void
7381f_libcallnr(typval_T *argvars, typval_T *rettv)
7382{
7383 libcall_common(argvars, rettv, VAR_NUMBER);
7384}
7385
7386/*
7387 * "line(string)" function
7388 */
7389 static void
7390f_line(typval_T *argvars, typval_T *rettv)
7391{
7392 linenr_T lnum = 0;
7393 pos_T *fp;
7394 int fnum;
7395
7396 fp = var2fpos(&argvars[0], TRUE, &fnum);
7397 if (fp != NULL)
7398 lnum = fp->lnum;
7399 rettv->vval.v_number = lnum;
7400}
7401
7402/*
7403 * "line2byte(lnum)" function
7404 */
7405 static void
7406f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7407{
7408#ifndef FEAT_BYTEOFF
7409 rettv->vval.v_number = -1;
7410#else
7411 linenr_T lnum;
7412
7413 lnum = get_tv_lnum(argvars);
7414 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7415 rettv->vval.v_number = -1;
7416 else
7417 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7418 if (rettv->vval.v_number >= 0)
7419 ++rettv->vval.v_number;
7420#endif
7421}
7422
7423/*
7424 * "lispindent(lnum)" function
7425 */
7426 static void
7427f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7428{
7429#ifdef FEAT_LISP
7430 pos_T pos;
7431 linenr_T lnum;
7432
7433 pos = curwin->w_cursor;
7434 lnum = get_tv_lnum(argvars);
7435 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7436 {
7437 curwin->w_cursor.lnum = lnum;
7438 rettv->vval.v_number = get_lisp_indent();
7439 curwin->w_cursor = pos;
7440 }
7441 else
7442#endif
7443 rettv->vval.v_number = -1;
7444}
7445
7446/*
7447 * "localtime()" function
7448 */
7449 static void
7450f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7451{
7452 rettv->vval.v_number = (varnumber_T)time(NULL);
7453}
7454
7455static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7456
7457 static void
7458get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7459{
7460 char_u *keys;
7461 char_u *which;
7462 char_u buf[NUMBUFLEN];
7463 char_u *keys_buf = NULL;
7464 char_u *rhs;
7465 int mode;
7466 int abbr = FALSE;
7467 int get_dict = FALSE;
7468 mapblock_T *mp;
7469 int buffer_local;
7470
7471 /* return empty string for failure */
7472 rettv->v_type = VAR_STRING;
7473 rettv->vval.v_string = NULL;
7474
7475 keys = get_tv_string(&argvars[0]);
7476 if (*keys == NUL)
7477 return;
7478
7479 if (argvars[1].v_type != VAR_UNKNOWN)
7480 {
7481 which = get_tv_string_buf_chk(&argvars[1], buf);
7482 if (argvars[2].v_type != VAR_UNKNOWN)
7483 {
7484 abbr = (int)get_tv_number(&argvars[2]);
7485 if (argvars[3].v_type != VAR_UNKNOWN)
7486 get_dict = (int)get_tv_number(&argvars[3]);
7487 }
7488 }
7489 else
7490 which = (char_u *)"";
7491 if (which == NULL)
7492 return;
7493
7494 mode = get_map_mode(&which, 0);
7495
7496 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7497 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7498 vim_free(keys_buf);
7499
7500 if (!get_dict)
7501 {
7502 /* Return a string. */
7503 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007504 {
7505 if (*rhs == NUL)
7506 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7507 else
7508 rettv->vval.v_string = str2special_save(rhs, FALSE);
7509 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007510
7511 }
7512 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7513 {
7514 /* Return a dictionary. */
7515 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7516 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7517 dict_T *dict = rettv->vval.v_dict;
7518
7519 dict_add_nr_str(dict, "lhs", 0L, lhs);
7520 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7521 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7522 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7523 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7524 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7525 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7526 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7527 dict_add_nr_str(dict, "mode", 0L, mapmode);
7528
7529 vim_free(lhs);
7530 vim_free(mapmode);
7531 }
7532}
7533
7534#ifdef FEAT_FLOAT
7535/*
7536 * "log()" function
7537 */
7538 static void
7539f_log(typval_T *argvars, typval_T *rettv)
7540{
7541 float_T f = 0.0;
7542
7543 rettv->v_type = VAR_FLOAT;
7544 if (get_float_arg(argvars, &f) == OK)
7545 rettv->vval.v_float = log(f);
7546 else
7547 rettv->vval.v_float = 0.0;
7548}
7549
7550/*
7551 * "log10()" function
7552 */
7553 static void
7554f_log10(typval_T *argvars, typval_T *rettv)
7555{
7556 float_T f = 0.0;
7557
7558 rettv->v_type = VAR_FLOAT;
7559 if (get_float_arg(argvars, &f) == OK)
7560 rettv->vval.v_float = log10(f);
7561 else
7562 rettv->vval.v_float = 0.0;
7563}
7564#endif
7565
7566#ifdef FEAT_LUA
7567/*
7568 * "luaeval()" function
7569 */
7570 static void
7571f_luaeval(typval_T *argvars, typval_T *rettv)
7572{
7573 char_u *str;
7574 char_u buf[NUMBUFLEN];
7575
7576 str = get_tv_string_buf(&argvars[0], buf);
7577 do_luaeval(str, argvars + 1, rettv);
7578}
7579#endif
7580
7581/*
7582 * "map()" function
7583 */
7584 static void
7585f_map(typval_T *argvars, typval_T *rettv)
7586{
7587 filter_map(argvars, rettv, TRUE);
7588}
7589
7590/*
7591 * "maparg()" function
7592 */
7593 static void
7594f_maparg(typval_T *argvars, typval_T *rettv)
7595{
7596 get_maparg(argvars, rettv, TRUE);
7597}
7598
7599/*
7600 * "mapcheck()" function
7601 */
7602 static void
7603f_mapcheck(typval_T *argvars, typval_T *rettv)
7604{
7605 get_maparg(argvars, rettv, FALSE);
7606}
7607
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007608typedef enum
7609{
7610 MATCH_END, /* matchend() */
7611 MATCH_MATCH, /* match() */
7612 MATCH_STR, /* matchstr() */
7613 MATCH_LIST, /* matchlist() */
7614 MATCH_POS /* matchstrpos() */
7615} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007616
7617 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007618find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619{
7620 char_u *str = NULL;
7621 long len = 0;
7622 char_u *expr = NULL;
7623 char_u *pat;
7624 regmatch_T regmatch;
7625 char_u patbuf[NUMBUFLEN];
7626 char_u strbuf[NUMBUFLEN];
7627 char_u *save_cpo;
7628 long start = 0;
7629 long nth = 1;
7630 colnr_T startcol = 0;
7631 int match = 0;
7632 list_T *l = NULL;
7633 listitem_T *li = NULL;
7634 long idx = 0;
7635 char_u *tofree = NULL;
7636
7637 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7638 save_cpo = p_cpo;
7639 p_cpo = (char_u *)"";
7640
7641 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007642 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007643 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007644 /* type MATCH_LIST: return empty list when there are no matches.
7645 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007646 if (rettv_list_alloc(rettv) == FAIL)
7647 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007648 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649 && (list_append_string(rettv->vval.v_list,
7650 (char_u *)"", 0) == FAIL
7651 || list_append_number(rettv->vval.v_list,
7652 (varnumber_T)-1) == FAIL
7653 || list_append_number(rettv->vval.v_list,
7654 (varnumber_T)-1) == FAIL
7655 || list_append_number(rettv->vval.v_list,
7656 (varnumber_T)-1) == FAIL))
7657 {
7658 list_free(rettv->vval.v_list);
7659 rettv->vval.v_list = NULL;
7660 goto theend;
7661 }
7662 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007663 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007664 {
7665 rettv->v_type = VAR_STRING;
7666 rettv->vval.v_string = NULL;
7667 }
7668
7669 if (argvars[0].v_type == VAR_LIST)
7670 {
7671 if ((l = argvars[0].vval.v_list) == NULL)
7672 goto theend;
7673 li = l->lv_first;
7674 }
7675 else
7676 {
7677 expr = str = get_tv_string(&argvars[0]);
7678 len = (long)STRLEN(str);
7679 }
7680
7681 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7682 if (pat == NULL)
7683 goto theend;
7684
7685 if (argvars[2].v_type != VAR_UNKNOWN)
7686 {
7687 int error = FALSE;
7688
7689 start = (long)get_tv_number_chk(&argvars[2], &error);
7690 if (error)
7691 goto theend;
7692 if (l != NULL)
7693 {
7694 li = list_find(l, start);
7695 if (li == NULL)
7696 goto theend;
7697 idx = l->lv_idx; /* use the cached index */
7698 }
7699 else
7700 {
7701 if (start < 0)
7702 start = 0;
7703 if (start > len)
7704 goto theend;
7705 /* When "count" argument is there ignore matches before "start",
7706 * otherwise skip part of the string. Differs when pattern is "^"
7707 * or "\<". */
7708 if (argvars[3].v_type != VAR_UNKNOWN)
7709 startcol = start;
7710 else
7711 {
7712 str += start;
7713 len -= start;
7714 }
7715 }
7716
7717 if (argvars[3].v_type != VAR_UNKNOWN)
7718 nth = (long)get_tv_number_chk(&argvars[3], &error);
7719 if (error)
7720 goto theend;
7721 }
7722
7723 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7724 if (regmatch.regprog != NULL)
7725 {
7726 regmatch.rm_ic = p_ic;
7727
7728 for (;;)
7729 {
7730 if (l != NULL)
7731 {
7732 if (li == NULL)
7733 {
7734 match = FALSE;
7735 break;
7736 }
7737 vim_free(tofree);
7738 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7739 if (str == NULL)
7740 break;
7741 }
7742
7743 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7744
7745 if (match && --nth <= 0)
7746 break;
7747 if (l == NULL && !match)
7748 break;
7749
7750 /* Advance to just after the match. */
7751 if (l != NULL)
7752 {
7753 li = li->li_next;
7754 ++idx;
7755 }
7756 else
7757 {
7758#ifdef FEAT_MBYTE
7759 startcol = (colnr_T)(regmatch.startp[0]
7760 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7761#else
7762 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7763#endif
7764 if (startcol > (colnr_T)len
7765 || str + startcol <= regmatch.startp[0])
7766 {
7767 match = FALSE;
7768 break;
7769 }
7770 }
7771 }
7772
7773 if (match)
7774 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007775 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 {
7777 listitem_T *li1 = rettv->vval.v_list->lv_first;
7778 listitem_T *li2 = li1->li_next;
7779 listitem_T *li3 = li2->li_next;
7780 listitem_T *li4 = li3->li_next;
7781
7782 vim_free(li1->li_tv.vval.v_string);
7783 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7784 (int)(regmatch.endp[0] - regmatch.startp[0]));
7785 li3->li_tv.vval.v_number =
7786 (varnumber_T)(regmatch.startp[0] - expr);
7787 li4->li_tv.vval.v_number =
7788 (varnumber_T)(regmatch.endp[0] - expr);
7789 if (l != NULL)
7790 li2->li_tv.vval.v_number = (varnumber_T)idx;
7791 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007792 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007793 {
7794 int i;
7795
7796 /* return list with matched string and submatches */
7797 for (i = 0; i < NSUBEXP; ++i)
7798 {
7799 if (regmatch.endp[i] == NULL)
7800 {
7801 if (list_append_string(rettv->vval.v_list,
7802 (char_u *)"", 0) == FAIL)
7803 break;
7804 }
7805 else if (list_append_string(rettv->vval.v_list,
7806 regmatch.startp[i],
7807 (int)(regmatch.endp[i] - regmatch.startp[i]))
7808 == FAIL)
7809 break;
7810 }
7811 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007812 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007813 {
7814 /* return matched string */
7815 if (l != NULL)
7816 copy_tv(&li->li_tv, rettv);
7817 else
7818 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7819 (int)(regmatch.endp[0] - regmatch.startp[0]));
7820 }
7821 else if (l != NULL)
7822 rettv->vval.v_number = idx;
7823 else
7824 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007825 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 rettv->vval.v_number =
7827 (varnumber_T)(regmatch.startp[0] - str);
7828 else
7829 rettv->vval.v_number =
7830 (varnumber_T)(regmatch.endp[0] - str);
7831 rettv->vval.v_number += (varnumber_T)(str - expr);
7832 }
7833 }
7834 vim_regfree(regmatch.regprog);
7835 }
7836
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007837theend:
7838 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007839 /* matchstrpos() without a list: drop the second item. */
7840 listitem_remove(rettv->vval.v_list,
7841 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007842 vim_free(tofree);
7843 p_cpo = save_cpo;
7844}
7845
7846/*
7847 * "match()" function
7848 */
7849 static void
7850f_match(typval_T *argvars, typval_T *rettv)
7851{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007852 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853}
7854
7855/*
7856 * "matchadd()" function
7857 */
7858 static void
7859f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7860{
7861#ifdef FEAT_SEARCH_EXTRA
7862 char_u buf[NUMBUFLEN];
7863 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7864 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7865 int prio = 10; /* default priority */
7866 int id = -1;
7867 int error = FALSE;
7868 char_u *conceal_char = NULL;
7869
7870 rettv->vval.v_number = -1;
7871
7872 if (grp == NULL || pat == NULL)
7873 return;
7874 if (argvars[2].v_type != VAR_UNKNOWN)
7875 {
7876 prio = (int)get_tv_number_chk(&argvars[2], &error);
7877 if (argvars[3].v_type != VAR_UNKNOWN)
7878 {
7879 id = (int)get_tv_number_chk(&argvars[3], &error);
7880 if (argvars[4].v_type != VAR_UNKNOWN)
7881 {
7882 if (argvars[4].v_type != VAR_DICT)
7883 {
7884 EMSG(_(e_dictreq));
7885 return;
7886 }
7887 if (dict_find(argvars[4].vval.v_dict,
7888 (char_u *)"conceal", -1) != NULL)
7889 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7890 (char_u *)"conceal", FALSE);
7891 }
7892 }
7893 }
7894 if (error == TRUE)
7895 return;
7896 if (id >= 1 && id <= 3)
7897 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007898 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007899 return;
7900 }
7901
7902 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7903 conceal_char);
7904#endif
7905}
7906
7907/*
7908 * "matchaddpos()" function
7909 */
7910 static void
7911f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7912{
7913#ifdef FEAT_SEARCH_EXTRA
7914 char_u buf[NUMBUFLEN];
7915 char_u *group;
7916 int prio = 10;
7917 int id = -1;
7918 int error = FALSE;
7919 list_T *l;
7920 char_u *conceal_char = NULL;
7921
7922 rettv->vval.v_number = -1;
7923
7924 group = get_tv_string_buf_chk(&argvars[0], buf);
7925 if (group == NULL)
7926 return;
7927
7928 if (argvars[1].v_type != VAR_LIST)
7929 {
7930 EMSG2(_(e_listarg), "matchaddpos()");
7931 return;
7932 }
7933 l = argvars[1].vval.v_list;
7934 if (l == NULL)
7935 return;
7936
7937 if (argvars[2].v_type != VAR_UNKNOWN)
7938 {
7939 prio = (int)get_tv_number_chk(&argvars[2], &error);
7940 if (argvars[3].v_type != VAR_UNKNOWN)
7941 {
7942 id = (int)get_tv_number_chk(&argvars[3], &error);
7943 if (argvars[4].v_type != VAR_UNKNOWN)
7944 {
7945 if (argvars[4].v_type != VAR_DICT)
7946 {
7947 EMSG(_(e_dictreq));
7948 return;
7949 }
7950 if (dict_find(argvars[4].vval.v_dict,
7951 (char_u *)"conceal", -1) != NULL)
7952 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7953 (char_u *)"conceal", FALSE);
7954 }
7955 }
7956 }
7957 if (error == TRUE)
7958 return;
7959
7960 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7961 if (id == 1 || id == 2)
7962 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007963 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007964 return;
7965 }
7966
7967 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7968 conceal_char);
7969#endif
7970}
7971
7972/*
7973 * "matcharg()" function
7974 */
7975 static void
7976f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7977{
7978 if (rettv_list_alloc(rettv) == OK)
7979 {
7980#ifdef FEAT_SEARCH_EXTRA
7981 int id = (int)get_tv_number(&argvars[0]);
7982 matchitem_T *m;
7983
7984 if (id >= 1 && id <= 3)
7985 {
7986 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7987 {
7988 list_append_string(rettv->vval.v_list,
7989 syn_id2name(m->hlg_id), -1);
7990 list_append_string(rettv->vval.v_list, m->pattern, -1);
7991 }
7992 else
7993 {
7994 list_append_string(rettv->vval.v_list, NULL, -1);
7995 list_append_string(rettv->vval.v_list, NULL, -1);
7996 }
7997 }
7998#endif
7999 }
8000}
8001
8002/*
8003 * "matchdelete()" function
8004 */
8005 static void
8006f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8007{
8008#ifdef FEAT_SEARCH_EXTRA
8009 rettv->vval.v_number = match_delete(curwin,
8010 (int)get_tv_number(&argvars[0]), TRUE);
8011#endif
8012}
8013
8014/*
8015 * "matchend()" function
8016 */
8017 static void
8018f_matchend(typval_T *argvars, typval_T *rettv)
8019{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008020 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008021}
8022
8023/*
8024 * "matchlist()" function
8025 */
8026 static void
8027f_matchlist(typval_T *argvars, typval_T *rettv)
8028{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008029 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030}
8031
8032/*
8033 * "matchstr()" function
8034 */
8035 static void
8036f_matchstr(typval_T *argvars, typval_T *rettv)
8037{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008038 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039}
8040
8041/*
8042 * "matchstrpos()" function
8043 */
8044 static void
8045f_matchstrpos(typval_T *argvars, typval_T *rettv)
8046{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008047 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008048}
8049
8050static void max_min(typval_T *argvars, typval_T *rettv, int domax);
8051
8052 static void
8053max_min(typval_T *argvars, typval_T *rettv, int domax)
8054{
8055 varnumber_T n = 0;
8056 varnumber_T i;
8057 int error = FALSE;
8058
8059 if (argvars[0].v_type == VAR_LIST)
8060 {
8061 list_T *l;
8062 listitem_T *li;
8063
8064 l = argvars[0].vval.v_list;
8065 if (l != NULL)
8066 {
8067 li = l->lv_first;
8068 if (li != NULL)
8069 {
8070 n = get_tv_number_chk(&li->li_tv, &error);
8071 for (;;)
8072 {
8073 li = li->li_next;
8074 if (li == NULL)
8075 break;
8076 i = get_tv_number_chk(&li->li_tv, &error);
8077 if (domax ? i > n : i < n)
8078 n = i;
8079 }
8080 }
8081 }
8082 }
8083 else if (argvars[0].v_type == VAR_DICT)
8084 {
8085 dict_T *d;
8086 int first = TRUE;
8087 hashitem_T *hi;
8088 int todo;
8089
8090 d = argvars[0].vval.v_dict;
8091 if (d != NULL)
8092 {
8093 todo = (int)d->dv_hashtab.ht_used;
8094 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8095 {
8096 if (!HASHITEM_EMPTY(hi))
8097 {
8098 --todo;
8099 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8100 if (first)
8101 {
8102 n = i;
8103 first = FALSE;
8104 }
8105 else if (domax ? i > n : i < n)
8106 n = i;
8107 }
8108 }
8109 }
8110 }
8111 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008112 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008113 rettv->vval.v_number = error ? 0 : n;
8114}
8115
8116/*
8117 * "max()" function
8118 */
8119 static void
8120f_max(typval_T *argvars, typval_T *rettv)
8121{
8122 max_min(argvars, rettv, TRUE);
8123}
8124
8125/*
8126 * "min()" function
8127 */
8128 static void
8129f_min(typval_T *argvars, typval_T *rettv)
8130{
8131 max_min(argvars, rettv, FALSE);
8132}
8133
8134static int mkdir_recurse(char_u *dir, int prot);
8135
8136/*
8137 * Create the directory in which "dir" is located, and higher levels when
8138 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008139 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140 */
8141 static int
8142mkdir_recurse(char_u *dir, int prot)
8143{
8144 char_u *p;
8145 char_u *updir;
8146 int r = FAIL;
8147
8148 /* Get end of directory name in "dir".
8149 * We're done when it's "/" or "c:/". */
8150 p = gettail_sep(dir);
8151 if (p <= get_past_head(dir))
8152 return OK;
8153
8154 /* If the directory exists we're done. Otherwise: create it.*/
8155 updir = vim_strnsave(dir, (int)(p - dir));
8156 if (updir == NULL)
8157 return FAIL;
8158 if (mch_isdir(updir))
8159 r = OK;
8160 else if (mkdir_recurse(updir, prot) == OK)
8161 r = vim_mkdir_emsg(updir, prot);
8162 vim_free(updir);
8163 return r;
8164}
8165
8166#ifdef vim_mkdir
8167/*
8168 * "mkdir()" function
8169 */
8170 static void
8171f_mkdir(typval_T *argvars, typval_T *rettv)
8172{
8173 char_u *dir;
8174 char_u buf[NUMBUFLEN];
8175 int prot = 0755;
8176
8177 rettv->vval.v_number = FAIL;
8178 if (check_restricted() || check_secure())
8179 return;
8180
8181 dir = get_tv_string_buf(&argvars[0], buf);
8182 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008183 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008185 if (*gettail(dir) == NUL)
8186 /* remove trailing slashes */
8187 *gettail_sep(dir) = NUL;
8188
8189 if (argvars[1].v_type != VAR_UNKNOWN)
8190 {
8191 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008193 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8194 if (prot == -1)
8195 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008196 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008197 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8198 {
8199 if (mch_isdir(dir))
8200 {
8201 /* With the "p" flag it's OK if the dir already exists. */
8202 rettv->vval.v_number = OK;
8203 return;
8204 }
8205 mkdir_recurse(dir, prot);
8206 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008207 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008208 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209}
8210#endif
8211
8212/*
8213 * "mode()" function
8214 */
8215 static void
8216f_mode(typval_T *argvars, typval_T *rettv)
8217{
8218 char_u buf[3];
8219
8220 buf[1] = NUL;
8221 buf[2] = NUL;
8222
8223 if (time_for_testing == 93784)
8224 {
8225 /* Testing the two-character code. */
8226 buf[0] = 'x';
8227 buf[1] = '!';
8228 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008229#ifdef FEAT_TERMINAL
8230 else if (term_use_loop())
8231 buf[0] = 't';
8232#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008233 else if (VIsual_active)
8234 {
8235 if (VIsual_select)
8236 buf[0] = VIsual_mode + 's' - 'v';
8237 else
8238 buf[0] = VIsual_mode;
8239 }
8240 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8241 || State == CONFIRM)
8242 {
8243 buf[0] = 'r';
8244 if (State == ASKMORE)
8245 buf[1] = 'm';
8246 else if (State == CONFIRM)
8247 buf[1] = '?';
8248 }
8249 else if (State == EXTERNCMD)
8250 buf[0] = '!';
8251 else if (State & INSERT)
8252 {
8253#ifdef FEAT_VREPLACE
8254 if (State & VREPLACE_FLAG)
8255 {
8256 buf[0] = 'R';
8257 buf[1] = 'v';
8258 }
8259 else
8260#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01008261 {
8262 if (State & REPLACE_FLAG)
8263 buf[0] = 'R';
8264 else
8265 buf[0] = 'i';
8266#ifdef FEAT_INS_EXPAND
8267 if (ins_compl_active())
8268 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008269 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008270 buf[1] = 'x';
8271#endif
8272 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008273 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008274 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008275 {
8276 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008277 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008278 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008279 else if (exmode_active == EXMODE_NORMAL)
8280 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281 }
8282 else
8283 {
8284 buf[0] = 'n';
8285 if (finish_op)
8286 buf[1] = 'o';
8287 }
8288
8289 /* Clear out the minor mode when the argument is not a non-zero number or
8290 * non-empty string. */
8291 if (!non_zero_arg(&argvars[0]))
8292 buf[1] = NUL;
8293
8294 rettv->vval.v_string = vim_strsave(buf);
8295 rettv->v_type = VAR_STRING;
8296}
8297
8298#if defined(FEAT_MZSCHEME) || defined(PROTO)
8299/*
8300 * "mzeval()" function
8301 */
8302 static void
8303f_mzeval(typval_T *argvars, typval_T *rettv)
8304{
8305 char_u *str;
8306 char_u buf[NUMBUFLEN];
8307
8308 str = get_tv_string_buf(&argvars[0], buf);
8309 do_mzeval(str, rettv);
8310}
8311
8312 void
8313mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8314{
8315 typval_T argvars[3];
8316
8317 argvars[0].v_type = VAR_STRING;
8318 argvars[0].vval.v_string = name;
8319 copy_tv(args, &argvars[1]);
8320 argvars[2].v_type = VAR_UNKNOWN;
8321 f_call(argvars, rettv);
8322 clear_tv(&argvars[1]);
8323}
8324#endif
8325
8326/*
8327 * "nextnonblank()" function
8328 */
8329 static void
8330f_nextnonblank(typval_T *argvars, typval_T *rettv)
8331{
8332 linenr_T lnum;
8333
8334 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8335 {
8336 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8337 {
8338 lnum = 0;
8339 break;
8340 }
8341 if (*skipwhite(ml_get(lnum)) != NUL)
8342 break;
8343 }
8344 rettv->vval.v_number = lnum;
8345}
8346
8347/*
8348 * "nr2char()" function
8349 */
8350 static void
8351f_nr2char(typval_T *argvars, typval_T *rettv)
8352{
8353 char_u buf[NUMBUFLEN];
8354
8355#ifdef FEAT_MBYTE
8356 if (has_mbyte)
8357 {
8358 int utf8 = 0;
8359
8360 if (argvars[1].v_type != VAR_UNKNOWN)
8361 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8362 if (utf8)
8363 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8364 else
8365 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8366 }
8367 else
8368#endif
8369 {
8370 buf[0] = (char_u)get_tv_number(&argvars[0]);
8371 buf[1] = NUL;
8372 }
8373 rettv->v_type = VAR_STRING;
8374 rettv->vval.v_string = vim_strsave(buf);
8375}
8376
8377/*
8378 * "or(expr, expr)" function
8379 */
8380 static void
8381f_or(typval_T *argvars, typval_T *rettv)
8382{
8383 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8384 | get_tv_number_chk(&argvars[1], NULL);
8385}
8386
8387/*
8388 * "pathshorten()" function
8389 */
8390 static void
8391f_pathshorten(typval_T *argvars, typval_T *rettv)
8392{
8393 char_u *p;
8394
8395 rettv->v_type = VAR_STRING;
8396 p = get_tv_string_chk(&argvars[0]);
8397 if (p == NULL)
8398 rettv->vval.v_string = NULL;
8399 else
8400 {
8401 p = vim_strsave(p);
8402 rettv->vval.v_string = p;
8403 if (p != NULL)
8404 shorten_dir(p);
8405 }
8406}
8407
8408#ifdef FEAT_PERL
8409/*
8410 * "perleval()" function
8411 */
8412 static void
8413f_perleval(typval_T *argvars, typval_T *rettv)
8414{
8415 char_u *str;
8416 char_u buf[NUMBUFLEN];
8417
8418 str = get_tv_string_buf(&argvars[0], buf);
8419 do_perleval(str, rettv);
8420}
8421#endif
8422
8423#ifdef FEAT_FLOAT
8424/*
8425 * "pow()" function
8426 */
8427 static void
8428f_pow(typval_T *argvars, typval_T *rettv)
8429{
8430 float_T fx = 0.0, fy = 0.0;
8431
8432 rettv->v_type = VAR_FLOAT;
8433 if (get_float_arg(argvars, &fx) == OK
8434 && get_float_arg(&argvars[1], &fy) == OK)
8435 rettv->vval.v_float = pow(fx, fy);
8436 else
8437 rettv->vval.v_float = 0.0;
8438}
8439#endif
8440
8441/*
8442 * "prevnonblank()" function
8443 */
8444 static void
8445f_prevnonblank(typval_T *argvars, typval_T *rettv)
8446{
8447 linenr_T lnum;
8448
8449 lnum = get_tv_lnum(argvars);
8450 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8451 lnum = 0;
8452 else
8453 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8454 --lnum;
8455 rettv->vval.v_number = lnum;
8456}
8457
8458/* This dummy va_list is here because:
8459 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8460 * - locally in the function results in a "used before set" warning
8461 * - using va_start() to initialize it gives "function with fixed args" error */
8462static va_list ap;
8463
8464/*
8465 * "printf()" function
8466 */
8467 static void
8468f_printf(typval_T *argvars, typval_T *rettv)
8469{
8470 char_u buf[NUMBUFLEN];
8471 int len;
8472 char_u *s;
8473 int saved_did_emsg = did_emsg;
8474 char *fmt;
8475
8476 rettv->v_type = VAR_STRING;
8477 rettv->vval.v_string = NULL;
8478
8479 /* Get the required length, allocate the buffer and do it for real. */
8480 did_emsg = FALSE;
8481 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008482 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008483 if (!did_emsg)
8484 {
8485 s = alloc(len + 1);
8486 if (s != NULL)
8487 {
8488 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008489 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8490 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008491 }
8492 }
8493 did_emsg |= saved_did_emsg;
8494}
8495
Bram Moolenaarf2732452018-06-03 14:47:35 +02008496#ifdef FEAT_JOB_CHANNEL
8497/*
8498 * "prompt_setcallback({buffer}, {callback})" function
8499 */
8500 static void
8501f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8502{
8503 buf_T *buf;
8504 char_u *callback;
8505 partial_T *partial;
8506
8507 if (check_secure())
8508 return;
8509 buf = get_buf_tv(&argvars[0], FALSE);
8510 if (buf == NULL)
8511 return;
8512
8513 callback = get_callback(&argvars[1], &partial);
8514 if (callback == NULL)
8515 return;
8516
8517 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8518 if (partial == NULL)
8519 buf->b_prompt_callback = vim_strsave(callback);
8520 else
8521 /* pointer into the partial */
8522 buf->b_prompt_callback = callback;
8523 buf->b_prompt_partial = partial;
8524}
8525
8526/*
8527 * "prompt_setprompt({buffer}, {text})" function
8528 */
8529 static void
8530f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8531{
8532 buf_T *buf;
8533 char_u *text;
8534
8535 if (check_secure())
8536 return;
8537 buf = get_buf_tv(&argvars[0], FALSE);
8538 if (buf == NULL)
8539 return;
8540
8541 text = get_tv_string(&argvars[1]);
8542 vim_free(buf->b_prompt_text);
8543 buf->b_prompt_text = vim_strsave(text);
8544}
8545#endif
8546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547/*
8548 * "pumvisible()" function
8549 */
8550 static void
8551f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8552{
8553#ifdef FEAT_INS_EXPAND
8554 if (pum_visible())
8555 rettv->vval.v_number = 1;
8556#endif
8557}
8558
8559#ifdef FEAT_PYTHON3
8560/*
8561 * "py3eval()" function
8562 */
8563 static void
8564f_py3eval(typval_T *argvars, typval_T *rettv)
8565{
8566 char_u *str;
8567 char_u buf[NUMBUFLEN];
8568
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008569 if (p_pyx == 0)
8570 p_pyx = 3;
8571
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008572 str = get_tv_string_buf(&argvars[0], buf);
8573 do_py3eval(str, rettv);
8574}
8575#endif
8576
8577#ifdef FEAT_PYTHON
8578/*
8579 * "pyeval()" function
8580 */
8581 static void
8582f_pyeval(typval_T *argvars, typval_T *rettv)
8583{
8584 char_u *str;
8585 char_u buf[NUMBUFLEN];
8586
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008587 if (p_pyx == 0)
8588 p_pyx = 2;
8589
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008590 str = get_tv_string_buf(&argvars[0], buf);
8591 do_pyeval(str, rettv);
8592}
8593#endif
8594
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008595#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8596/*
8597 * "pyxeval()" function
8598 */
8599 static void
8600f_pyxeval(typval_T *argvars, typval_T *rettv)
8601{
8602# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8603 init_pyxversion();
8604 if (p_pyx == 2)
8605 f_pyeval(argvars, rettv);
8606 else
8607 f_py3eval(argvars, rettv);
8608# elif defined(FEAT_PYTHON)
8609 f_pyeval(argvars, rettv);
8610# elif defined(FEAT_PYTHON3)
8611 f_py3eval(argvars, rettv);
8612# endif
8613}
8614#endif
8615
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008616/*
8617 * "range()" function
8618 */
8619 static void
8620f_range(typval_T *argvars, typval_T *rettv)
8621{
8622 varnumber_T start;
8623 varnumber_T end;
8624 varnumber_T stride = 1;
8625 varnumber_T i;
8626 int error = FALSE;
8627
8628 start = get_tv_number_chk(&argvars[0], &error);
8629 if (argvars[1].v_type == VAR_UNKNOWN)
8630 {
8631 end = start - 1;
8632 start = 0;
8633 }
8634 else
8635 {
8636 end = get_tv_number_chk(&argvars[1], &error);
8637 if (argvars[2].v_type != VAR_UNKNOWN)
8638 stride = get_tv_number_chk(&argvars[2], &error);
8639 }
8640
8641 if (error)
8642 return; /* type error; errmsg already given */
8643 if (stride == 0)
8644 EMSG(_("E726: Stride is zero"));
8645 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8646 EMSG(_("E727: Start past end"));
8647 else
8648 {
8649 if (rettv_list_alloc(rettv) == OK)
8650 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8651 if (list_append_number(rettv->vval.v_list,
8652 (varnumber_T)i) == FAIL)
8653 break;
8654 }
8655}
8656
8657/*
8658 * "readfile()" function
8659 */
8660 static void
8661f_readfile(typval_T *argvars, typval_T *rettv)
8662{
8663 int binary = FALSE;
8664 int failed = FALSE;
8665 char_u *fname;
8666 FILE *fd;
8667 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8668 int io_size = sizeof(buf);
8669 int readlen; /* size of last fread() */
8670 char_u *prev = NULL; /* previously read bytes, if any */
8671 long prevlen = 0; /* length of data in prev */
8672 long prevsize = 0; /* size of prev buffer */
8673 long maxline = MAXLNUM;
8674 long cnt = 0;
8675 char_u *p; /* position in buf */
8676 char_u *start; /* start of current line */
8677
8678 if (argvars[1].v_type != VAR_UNKNOWN)
8679 {
8680 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8681 binary = TRUE;
8682 if (argvars[2].v_type != VAR_UNKNOWN)
8683 maxline = (long)get_tv_number(&argvars[2]);
8684 }
8685
8686 if (rettv_list_alloc(rettv) == FAIL)
8687 return;
8688
8689 /* Always open the file in binary mode, library functions have a mind of
8690 * their own about CR-LF conversion. */
8691 fname = get_tv_string(&argvars[0]);
8692 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8693 {
8694 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8695 return;
8696 }
8697
8698 while (cnt < maxline || maxline < 0)
8699 {
8700 readlen = (int)fread(buf, 1, io_size, fd);
8701
8702 /* This for loop processes what was read, but is also entered at end
8703 * of file so that either:
8704 * - an incomplete line gets written
8705 * - a "binary" file gets an empty line at the end if it ends in a
8706 * newline. */
8707 for (p = buf, start = buf;
8708 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8709 ++p)
8710 {
8711 if (*p == '\n' || readlen <= 0)
8712 {
8713 listitem_T *li;
8714 char_u *s = NULL;
8715 long_u len = p - start;
8716
8717 /* Finished a line. Remove CRs before NL. */
8718 if (readlen > 0 && !binary)
8719 {
8720 while (len > 0 && start[len - 1] == '\r')
8721 --len;
8722 /* removal may cross back to the "prev" string */
8723 if (len == 0)
8724 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8725 --prevlen;
8726 }
8727 if (prevlen == 0)
8728 s = vim_strnsave(start, (int)len);
8729 else
8730 {
8731 /* Change "prev" buffer to be the right size. This way
8732 * the bytes are only copied once, and very long lines are
8733 * allocated only once. */
8734 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8735 {
8736 mch_memmove(s + prevlen, start, len);
8737 s[prevlen + len] = NUL;
8738 prev = NULL; /* the list will own the string */
8739 prevlen = prevsize = 0;
8740 }
8741 }
8742 if (s == NULL)
8743 {
8744 do_outofmem_msg((long_u) prevlen + len + 1);
8745 failed = TRUE;
8746 break;
8747 }
8748
8749 if ((li = listitem_alloc()) == NULL)
8750 {
8751 vim_free(s);
8752 failed = TRUE;
8753 break;
8754 }
8755 li->li_tv.v_type = VAR_STRING;
8756 li->li_tv.v_lock = 0;
8757 li->li_tv.vval.v_string = s;
8758 list_append(rettv->vval.v_list, li);
8759
8760 start = p + 1; /* step over newline */
8761 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8762 break;
8763 }
8764 else if (*p == NUL)
8765 *p = '\n';
8766#ifdef FEAT_MBYTE
8767 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8768 * when finding the BF and check the previous two bytes. */
8769 else if (*p == 0xbf && enc_utf8 && !binary)
8770 {
8771 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8772 * + 1, these may be in the "prev" string. */
8773 char_u back1 = p >= buf + 1 ? p[-1]
8774 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8775 char_u back2 = p >= buf + 2 ? p[-2]
8776 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8777 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8778
8779 if (back2 == 0xef && back1 == 0xbb)
8780 {
8781 char_u *dest = p - 2;
8782
8783 /* Usually a BOM is at the beginning of a file, and so at
8784 * the beginning of a line; then we can just step over it.
8785 */
8786 if (start == dest)
8787 start = p + 1;
8788 else
8789 {
8790 /* have to shuffle buf to close gap */
8791 int adjust_prevlen = 0;
8792
8793 if (dest < buf)
8794 {
8795 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8796 dest = buf;
8797 }
8798 if (readlen > p - buf + 1)
8799 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8800 readlen -= 3 - adjust_prevlen;
8801 prevlen -= adjust_prevlen;
8802 p = dest - 1;
8803 }
8804 }
8805 }
8806#endif
8807 } /* for */
8808
8809 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8810 break;
8811 if (start < p)
8812 {
8813 /* There's part of a line in buf, store it in "prev". */
8814 if (p - start + prevlen >= prevsize)
8815 {
8816 /* need bigger "prev" buffer */
8817 char_u *newprev;
8818
8819 /* A common use case is ordinary text files and "prev" gets a
8820 * fragment of a line, so the first allocation is made
8821 * small, to avoid repeatedly 'allocing' large and
8822 * 'reallocing' small. */
8823 if (prevsize == 0)
8824 prevsize = (long)(p - start);
8825 else
8826 {
8827 long grow50pc = (prevsize * 3) / 2;
8828 long growmin = (long)((p - start) * 2 + prevlen);
8829 prevsize = grow50pc > growmin ? grow50pc : growmin;
8830 }
8831 newprev = prev == NULL ? alloc(prevsize)
8832 : vim_realloc(prev, prevsize);
8833 if (newprev == NULL)
8834 {
8835 do_outofmem_msg((long_u)prevsize);
8836 failed = TRUE;
8837 break;
8838 }
8839 prev = newprev;
8840 }
8841 /* Add the line part to end of "prev". */
8842 mch_memmove(prev + prevlen, start, p - start);
8843 prevlen += (long)(p - start);
8844 }
8845 } /* while */
8846
8847 /*
8848 * For a negative line count use only the lines at the end of the file,
8849 * free the rest.
8850 */
8851 if (!failed && maxline < 0)
8852 while (cnt > -maxline)
8853 {
8854 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8855 --cnt;
8856 }
8857
8858 if (failed)
8859 {
8860 list_free(rettv->vval.v_list);
8861 /* readfile doc says an empty list is returned on error */
8862 rettv->vval.v_list = list_alloc();
8863 }
8864
8865 vim_free(prev);
8866 fclose(fd);
8867}
8868
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008869 static void
8870return_register(int regname, typval_T *rettv)
8871{
8872 char_u buf[2] = {0, 0};
8873
8874 buf[0] = (char_u)regname;
8875 rettv->v_type = VAR_STRING;
8876 rettv->vval.v_string = vim_strsave(buf);
8877}
8878
8879/*
8880 * "reg_executing()" function
8881 */
8882 static void
8883f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8884{
8885 return_register(reg_executing, rettv);
8886}
8887
8888/*
8889 * "reg_recording()" function
8890 */
8891 static void
8892f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8893{
8894 return_register(reg_recording, rettv);
8895}
8896
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008897#if defined(FEAT_RELTIME)
8898static int list2proftime(typval_T *arg, proftime_T *tm);
8899
8900/*
8901 * Convert a List to proftime_T.
8902 * Return FAIL when there is something wrong.
8903 */
8904 static int
8905list2proftime(typval_T *arg, proftime_T *tm)
8906{
8907 long n1, n2;
8908 int error = FALSE;
8909
8910 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8911 || arg->vval.v_list->lv_len != 2)
8912 return FAIL;
8913 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8914 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8915# ifdef WIN3264
8916 tm->HighPart = n1;
8917 tm->LowPart = n2;
8918# else
8919 tm->tv_sec = n1;
8920 tm->tv_usec = n2;
8921# endif
8922 return error ? FAIL : OK;
8923}
8924#endif /* FEAT_RELTIME */
8925
8926/*
8927 * "reltime()" function
8928 */
8929 static void
8930f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8931{
8932#ifdef FEAT_RELTIME
8933 proftime_T res;
8934 proftime_T start;
8935
8936 if (argvars[0].v_type == VAR_UNKNOWN)
8937 {
8938 /* No arguments: get current time. */
8939 profile_start(&res);
8940 }
8941 else if (argvars[1].v_type == VAR_UNKNOWN)
8942 {
8943 if (list2proftime(&argvars[0], &res) == FAIL)
8944 return;
8945 profile_end(&res);
8946 }
8947 else
8948 {
8949 /* Two arguments: compute the difference. */
8950 if (list2proftime(&argvars[0], &start) == FAIL
8951 || list2proftime(&argvars[1], &res) == FAIL)
8952 return;
8953 profile_sub(&res, &start);
8954 }
8955
8956 if (rettv_list_alloc(rettv) == OK)
8957 {
8958 long n1, n2;
8959
8960# ifdef WIN3264
8961 n1 = res.HighPart;
8962 n2 = res.LowPart;
8963# else
8964 n1 = res.tv_sec;
8965 n2 = res.tv_usec;
8966# endif
8967 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8968 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8969 }
8970#endif
8971}
8972
8973#ifdef FEAT_FLOAT
8974/*
8975 * "reltimefloat()" function
8976 */
8977 static void
8978f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8979{
8980# ifdef FEAT_RELTIME
8981 proftime_T tm;
8982# endif
8983
8984 rettv->v_type = VAR_FLOAT;
8985 rettv->vval.v_float = 0;
8986# ifdef FEAT_RELTIME
8987 if (list2proftime(&argvars[0], &tm) == OK)
8988 rettv->vval.v_float = profile_float(&tm);
8989# endif
8990}
8991#endif
8992
8993/*
8994 * "reltimestr()" function
8995 */
8996 static void
8997f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8998{
8999#ifdef FEAT_RELTIME
9000 proftime_T tm;
9001#endif
9002
9003 rettv->v_type = VAR_STRING;
9004 rettv->vval.v_string = NULL;
9005#ifdef FEAT_RELTIME
9006 if (list2proftime(&argvars[0], &tm) == OK)
9007 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9008#endif
9009}
9010
9011#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9012static void make_connection(void);
9013static int check_connection(void);
9014
9015 static void
9016make_connection(void)
9017{
9018 if (X_DISPLAY == NULL
9019# ifdef FEAT_GUI
9020 && !gui.in_use
9021# endif
9022 )
9023 {
9024 x_force_connect = TRUE;
9025 setup_term_clip();
9026 x_force_connect = FALSE;
9027 }
9028}
9029
9030 static int
9031check_connection(void)
9032{
9033 make_connection();
9034 if (X_DISPLAY == NULL)
9035 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009036 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009037 return FAIL;
9038 }
9039 return OK;
9040}
9041#endif
9042
9043#ifdef FEAT_CLIENTSERVER
9044 static void
9045remote_common(typval_T *argvars, typval_T *rettv, int expr)
9046{
9047 char_u *server_name;
9048 char_u *keys;
9049 char_u *r = NULL;
9050 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009051 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009052# ifdef WIN32
9053 HWND w;
9054# else
9055 Window w;
9056# endif
9057
9058 if (check_restricted() || check_secure())
9059 return;
9060
9061# ifdef FEAT_X11
9062 if (check_connection() == FAIL)
9063 return;
9064# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009065 if (argvars[2].v_type != VAR_UNKNOWN
9066 && argvars[3].v_type != VAR_UNKNOWN)
9067 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009068
9069 server_name = get_tv_string_chk(&argvars[0]);
9070 if (server_name == NULL)
9071 return; /* type error; errmsg already given */
9072 keys = get_tv_string_buf(&argvars[1], buf);
9073# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009074 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009075# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009076 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9077 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009078# endif
9079 {
9080 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009081 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009082 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009083 vim_free(r);
9084 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009085 else
9086 EMSG2(_("E241: Unable to send to %s"), server_name);
9087 return;
9088 }
9089
9090 rettv->vval.v_string = r;
9091
9092 if (argvars[2].v_type != VAR_UNKNOWN)
9093 {
9094 dictitem_T v;
9095 char_u str[30];
9096 char_u *idvar;
9097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009098 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009099 if (idvar != NULL && *idvar != NUL)
9100 {
9101 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9102 v.di_tv.v_type = VAR_STRING;
9103 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009104 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009105 vim_free(v.di_tv.vval.v_string);
9106 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009107 }
9108}
9109#endif
9110
9111/*
9112 * "remote_expr()" function
9113 */
9114 static void
9115f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9116{
9117 rettv->v_type = VAR_STRING;
9118 rettv->vval.v_string = NULL;
9119#ifdef FEAT_CLIENTSERVER
9120 remote_common(argvars, rettv, TRUE);
9121#endif
9122}
9123
9124/*
9125 * "remote_foreground()" function
9126 */
9127 static void
9128f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9129{
9130#ifdef FEAT_CLIENTSERVER
9131# ifdef WIN32
9132 /* On Win32 it's done in this application. */
9133 {
9134 char_u *server_name = get_tv_string_chk(&argvars[0]);
9135
9136 if (server_name != NULL)
9137 serverForeground(server_name);
9138 }
9139# else
9140 /* Send a foreground() expression to the server. */
9141 argvars[1].v_type = VAR_STRING;
9142 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9143 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009144 rettv->v_type = VAR_STRING;
9145 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009146 remote_common(argvars, rettv, TRUE);
9147 vim_free(argvars[1].vval.v_string);
9148# endif
9149#endif
9150}
9151
9152 static void
9153f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9154{
9155#ifdef FEAT_CLIENTSERVER
9156 dictitem_T v;
9157 char_u *s = NULL;
9158# ifdef WIN32
9159 long_u n = 0;
9160# endif
9161 char_u *serverid;
9162
9163 if (check_restricted() || check_secure())
9164 {
9165 rettv->vval.v_number = -1;
9166 return;
9167 }
9168 serverid = get_tv_string_chk(&argvars[0]);
9169 if (serverid == NULL)
9170 {
9171 rettv->vval.v_number = -1;
9172 return; /* type error; errmsg already given */
9173 }
9174# ifdef WIN32
9175 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9176 if (n == 0)
9177 rettv->vval.v_number = -1;
9178 else
9179 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009180 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009181 rettv->vval.v_number = (s != NULL);
9182 }
9183# else
9184 if (check_connection() == FAIL)
9185 return;
9186
9187 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9188 serverStrToWin(serverid), &s);
9189# endif
9190
9191 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9192 {
9193 char_u *retvar;
9194
9195 v.di_tv.v_type = VAR_STRING;
9196 v.di_tv.vval.v_string = vim_strsave(s);
9197 retvar = get_tv_string_chk(&argvars[1]);
9198 if (retvar != NULL)
9199 set_var(retvar, &v.di_tv, FALSE);
9200 vim_free(v.di_tv.vval.v_string);
9201 }
9202#else
9203 rettv->vval.v_number = -1;
9204#endif
9205}
9206
9207 static void
9208f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9209{
9210 char_u *r = NULL;
9211
9212#ifdef FEAT_CLIENTSERVER
9213 char_u *serverid = get_tv_string_chk(&argvars[0]);
9214
9215 if (serverid != NULL && !check_restricted() && !check_secure())
9216 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009217 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009218# ifdef WIN32
9219 /* The server's HWND is encoded in the 'id' parameter */
9220 long_u n = 0;
9221# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009222
9223 if (argvars[1].v_type != VAR_UNKNOWN)
9224 timeout = get_tv_number(&argvars[1]);
9225
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009226# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009227 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9228 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009229 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009230 if (r == NULL)
9231# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009232 if (check_connection() == FAIL
9233 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9234 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009235# endif
9236 EMSG(_("E277: Unable to read a server reply"));
9237 }
9238#endif
9239 rettv->v_type = VAR_STRING;
9240 rettv->vval.v_string = r;
9241}
9242
9243/*
9244 * "remote_send()" function
9245 */
9246 static void
9247f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9248{
9249 rettv->v_type = VAR_STRING;
9250 rettv->vval.v_string = NULL;
9251#ifdef FEAT_CLIENTSERVER
9252 remote_common(argvars, rettv, FALSE);
9253#endif
9254}
9255
9256/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009257 * "remote_startserver()" function
9258 */
9259 static void
9260f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9261{
9262#ifdef FEAT_CLIENTSERVER
9263 char_u *server = get_tv_string_chk(&argvars[0]);
9264
9265 if (server == NULL)
9266 return; /* type error; errmsg already given */
9267 if (serverName != NULL)
9268 EMSG(_("E941: already started a server"));
9269 else
9270 {
9271# ifdef FEAT_X11
9272 if (check_connection() == OK)
9273 serverRegisterName(X_DISPLAY, server);
9274# else
9275 serverSetName(server);
9276# endif
9277 }
9278#else
9279 EMSG(_("E942: +clientserver feature not available"));
9280#endif
9281}
9282
9283/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009284 * "remove()" function
9285 */
9286 static void
9287f_remove(typval_T *argvars, typval_T *rettv)
9288{
9289 list_T *l;
9290 listitem_T *item, *item2;
9291 listitem_T *li;
9292 long idx;
9293 long end;
9294 char_u *key;
9295 dict_T *d;
9296 dictitem_T *di;
9297 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9298
9299 if (argvars[0].v_type == VAR_DICT)
9300 {
9301 if (argvars[2].v_type != VAR_UNKNOWN)
9302 EMSG2(_(e_toomanyarg), "remove()");
9303 else if ((d = argvars[0].vval.v_dict) != NULL
9304 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9305 {
9306 key = get_tv_string_chk(&argvars[1]);
9307 if (key != NULL)
9308 {
9309 di = dict_find(d, key, -1);
9310 if (di == NULL)
9311 EMSG2(_(e_dictkey), key);
9312 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9313 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9314 {
9315 *rettv = di->di_tv;
9316 init_tv(&di->di_tv);
9317 dictitem_remove(d, di);
9318 }
9319 }
9320 }
9321 }
9322 else if (argvars[0].v_type != VAR_LIST)
9323 EMSG2(_(e_listdictarg), "remove()");
9324 else if ((l = argvars[0].vval.v_list) != NULL
9325 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9326 {
9327 int error = FALSE;
9328
9329 idx = (long)get_tv_number_chk(&argvars[1], &error);
9330 if (error)
9331 ; /* type error: do nothing, errmsg already given */
9332 else if ((item = list_find(l, idx)) == NULL)
9333 EMSGN(_(e_listidx), idx);
9334 else
9335 {
9336 if (argvars[2].v_type == VAR_UNKNOWN)
9337 {
9338 /* Remove one item, return its value. */
9339 vimlist_remove(l, item, item);
9340 *rettv = item->li_tv;
9341 vim_free(item);
9342 }
9343 else
9344 {
9345 /* Remove range of items, return list with values. */
9346 end = (long)get_tv_number_chk(&argvars[2], &error);
9347 if (error)
9348 ; /* type error: do nothing */
9349 else if ((item2 = list_find(l, end)) == NULL)
9350 EMSGN(_(e_listidx), end);
9351 else
9352 {
9353 int cnt = 0;
9354
9355 for (li = item; li != NULL; li = li->li_next)
9356 {
9357 ++cnt;
9358 if (li == item2)
9359 break;
9360 }
9361 if (li == NULL) /* didn't find "item2" after "item" */
9362 EMSG(_(e_invrange));
9363 else
9364 {
9365 vimlist_remove(l, item, item2);
9366 if (rettv_list_alloc(rettv) == OK)
9367 {
9368 l = rettv->vval.v_list;
9369 l->lv_first = item;
9370 l->lv_last = item2;
9371 item->li_prev = NULL;
9372 item2->li_next = NULL;
9373 l->lv_len = cnt;
9374 }
9375 }
9376 }
9377 }
9378 }
9379 }
9380}
9381
9382/*
9383 * "rename({from}, {to})" function
9384 */
9385 static void
9386f_rename(typval_T *argvars, typval_T *rettv)
9387{
9388 char_u buf[NUMBUFLEN];
9389
9390 if (check_restricted() || check_secure())
9391 rettv->vval.v_number = -1;
9392 else
9393 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9394 get_tv_string_buf(&argvars[1], buf));
9395}
9396
9397/*
9398 * "repeat()" function
9399 */
9400 static void
9401f_repeat(typval_T *argvars, typval_T *rettv)
9402{
9403 char_u *p;
9404 int n;
9405 int slen;
9406 int len;
9407 char_u *r;
9408 int i;
9409
9410 n = (int)get_tv_number(&argvars[1]);
9411 if (argvars[0].v_type == VAR_LIST)
9412 {
9413 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9414 while (n-- > 0)
9415 if (list_extend(rettv->vval.v_list,
9416 argvars[0].vval.v_list, NULL) == FAIL)
9417 break;
9418 }
9419 else
9420 {
9421 p = get_tv_string(&argvars[0]);
9422 rettv->v_type = VAR_STRING;
9423 rettv->vval.v_string = NULL;
9424
9425 slen = (int)STRLEN(p);
9426 len = slen * n;
9427 if (len <= 0)
9428 return;
9429
9430 r = alloc(len + 1);
9431 if (r != NULL)
9432 {
9433 for (i = 0; i < n; i++)
9434 mch_memmove(r + i * slen, p, (size_t)slen);
9435 r[len] = NUL;
9436 }
9437
9438 rettv->vval.v_string = r;
9439 }
9440}
9441
9442/*
9443 * "resolve()" function
9444 */
9445 static void
9446f_resolve(typval_T *argvars, typval_T *rettv)
9447{
9448 char_u *p;
9449#ifdef HAVE_READLINK
9450 char_u *buf = NULL;
9451#endif
9452
9453 p = get_tv_string(&argvars[0]);
9454#ifdef FEAT_SHORTCUT
9455 {
9456 char_u *v = NULL;
9457
9458 v = mch_resolve_shortcut(p);
9459 if (v != NULL)
9460 rettv->vval.v_string = v;
9461 else
9462 rettv->vval.v_string = vim_strsave(p);
9463 }
9464#else
9465# ifdef HAVE_READLINK
9466 {
9467 char_u *cpy;
9468 int len;
9469 char_u *remain = NULL;
9470 char_u *q;
9471 int is_relative_to_current = FALSE;
9472 int has_trailing_pathsep = FALSE;
9473 int limit = 100;
9474
9475 p = vim_strsave(p);
9476
9477 if (p[0] == '.' && (vim_ispathsep(p[1])
9478 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9479 is_relative_to_current = TRUE;
9480
9481 len = STRLEN(p);
9482 if (len > 0 && after_pathsep(p, p + len))
9483 {
9484 has_trailing_pathsep = TRUE;
9485 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9486 }
9487
9488 q = getnextcomp(p);
9489 if (*q != NUL)
9490 {
9491 /* Separate the first path component in "p", and keep the
9492 * remainder (beginning with the path separator). */
9493 remain = vim_strsave(q - 1);
9494 q[-1] = NUL;
9495 }
9496
9497 buf = alloc(MAXPATHL + 1);
9498 if (buf == NULL)
9499 goto fail;
9500
9501 for (;;)
9502 {
9503 for (;;)
9504 {
9505 len = readlink((char *)p, (char *)buf, MAXPATHL);
9506 if (len <= 0)
9507 break;
9508 buf[len] = NUL;
9509
9510 if (limit-- == 0)
9511 {
9512 vim_free(p);
9513 vim_free(remain);
9514 EMSG(_("E655: Too many symbolic links (cycle?)"));
9515 rettv->vval.v_string = NULL;
9516 goto fail;
9517 }
9518
9519 /* Ensure that the result will have a trailing path separator
9520 * if the argument has one. */
9521 if (remain == NULL && has_trailing_pathsep)
9522 add_pathsep(buf);
9523
9524 /* Separate the first path component in the link value and
9525 * concatenate the remainders. */
9526 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9527 if (*q != NUL)
9528 {
9529 if (remain == NULL)
9530 remain = vim_strsave(q - 1);
9531 else
9532 {
9533 cpy = concat_str(q - 1, remain);
9534 if (cpy != NULL)
9535 {
9536 vim_free(remain);
9537 remain = cpy;
9538 }
9539 }
9540 q[-1] = NUL;
9541 }
9542
9543 q = gettail(p);
9544 if (q > p && *q == NUL)
9545 {
9546 /* Ignore trailing path separator. */
9547 q[-1] = NUL;
9548 q = gettail(p);
9549 }
9550 if (q > p && !mch_isFullName(buf))
9551 {
9552 /* symlink is relative to directory of argument */
9553 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9554 if (cpy != NULL)
9555 {
9556 STRCPY(cpy, p);
9557 STRCPY(gettail(cpy), buf);
9558 vim_free(p);
9559 p = cpy;
9560 }
9561 }
9562 else
9563 {
9564 vim_free(p);
9565 p = vim_strsave(buf);
9566 }
9567 }
9568
9569 if (remain == NULL)
9570 break;
9571
9572 /* Append the first path component of "remain" to "p". */
9573 q = getnextcomp(remain + 1);
9574 len = q - remain - (*q != NUL);
9575 cpy = vim_strnsave(p, STRLEN(p) + len);
9576 if (cpy != NULL)
9577 {
9578 STRNCAT(cpy, remain, len);
9579 vim_free(p);
9580 p = cpy;
9581 }
9582 /* Shorten "remain". */
9583 if (*q != NUL)
9584 STRMOVE(remain, q - 1);
9585 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009586 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009587 }
9588
9589 /* If the result is a relative path name, make it explicitly relative to
9590 * the current directory if and only if the argument had this form. */
9591 if (!vim_ispathsep(*p))
9592 {
9593 if (is_relative_to_current
9594 && *p != NUL
9595 && !(p[0] == '.'
9596 && (p[1] == NUL
9597 || vim_ispathsep(p[1])
9598 || (p[1] == '.'
9599 && (p[2] == NUL
9600 || vim_ispathsep(p[2]))))))
9601 {
9602 /* Prepend "./". */
9603 cpy = concat_str((char_u *)"./", p);
9604 if (cpy != NULL)
9605 {
9606 vim_free(p);
9607 p = cpy;
9608 }
9609 }
9610 else if (!is_relative_to_current)
9611 {
9612 /* Strip leading "./". */
9613 q = p;
9614 while (q[0] == '.' && vim_ispathsep(q[1]))
9615 q += 2;
9616 if (q > p)
9617 STRMOVE(p, p + 2);
9618 }
9619 }
9620
9621 /* Ensure that the result will have no trailing path separator
9622 * if the argument had none. But keep "/" or "//". */
9623 if (!has_trailing_pathsep)
9624 {
9625 q = p + STRLEN(p);
9626 if (after_pathsep(p, q))
9627 *gettail_sep(p) = NUL;
9628 }
9629
9630 rettv->vval.v_string = p;
9631 }
9632# else
9633 rettv->vval.v_string = vim_strsave(p);
9634# endif
9635#endif
9636
9637 simplify_filename(rettv->vval.v_string);
9638
9639#ifdef HAVE_READLINK
9640fail:
9641 vim_free(buf);
9642#endif
9643 rettv->v_type = VAR_STRING;
9644}
9645
9646/*
9647 * "reverse({list})" function
9648 */
9649 static void
9650f_reverse(typval_T *argvars, typval_T *rettv)
9651{
9652 list_T *l;
9653 listitem_T *li, *ni;
9654
9655 if (argvars[0].v_type != VAR_LIST)
9656 EMSG2(_(e_listarg), "reverse()");
9657 else if ((l = argvars[0].vval.v_list) != NULL
9658 && !tv_check_lock(l->lv_lock,
9659 (char_u *)N_("reverse() argument"), TRUE))
9660 {
9661 li = l->lv_last;
9662 l->lv_first = l->lv_last = NULL;
9663 l->lv_len = 0;
9664 while (li != NULL)
9665 {
9666 ni = li->li_prev;
9667 list_append(l, li);
9668 li = ni;
9669 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009670 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671 l->lv_idx = l->lv_len - l->lv_idx - 1;
9672 }
9673}
9674
9675#define SP_NOMOVE 0x01 /* don't move cursor */
9676#define SP_REPEAT 0x02 /* repeat to find outer pair */
9677#define SP_RETCOUNT 0x04 /* return matchcount */
9678#define SP_SETPCMARK 0x08 /* set previous context mark */
9679#define SP_START 0x10 /* accept match at start position */
9680#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9681#define SP_END 0x40 /* leave cursor at end of match */
9682#define SP_COLUMN 0x80 /* start at cursor column */
9683
9684static int get_search_arg(typval_T *varp, int *flagsp);
9685
9686/*
9687 * Get flags for a search function.
9688 * Possibly sets "p_ws".
9689 * Returns BACKWARD, FORWARD or zero (for an error).
9690 */
9691 static int
9692get_search_arg(typval_T *varp, int *flagsp)
9693{
9694 int dir = FORWARD;
9695 char_u *flags;
9696 char_u nbuf[NUMBUFLEN];
9697 int mask;
9698
9699 if (varp->v_type != VAR_UNKNOWN)
9700 {
9701 flags = get_tv_string_buf_chk(varp, nbuf);
9702 if (flags == NULL)
9703 return 0; /* type error; errmsg already given */
9704 while (*flags != NUL)
9705 {
9706 switch (*flags)
9707 {
9708 case 'b': dir = BACKWARD; break;
9709 case 'w': p_ws = TRUE; break;
9710 case 'W': p_ws = FALSE; break;
9711 default: mask = 0;
9712 if (flagsp != NULL)
9713 switch (*flags)
9714 {
9715 case 'c': mask = SP_START; break;
9716 case 'e': mask = SP_END; break;
9717 case 'm': mask = SP_RETCOUNT; break;
9718 case 'n': mask = SP_NOMOVE; break;
9719 case 'p': mask = SP_SUBPAT; break;
9720 case 'r': mask = SP_REPEAT; break;
9721 case 's': mask = SP_SETPCMARK; break;
9722 case 'z': mask = SP_COLUMN; break;
9723 }
9724 if (mask == 0)
9725 {
9726 EMSG2(_(e_invarg2), flags);
9727 dir = 0;
9728 }
9729 else
9730 *flagsp |= mask;
9731 }
9732 if (dir == 0)
9733 break;
9734 ++flags;
9735 }
9736 }
9737 return dir;
9738}
9739
9740/*
9741 * Shared by search() and searchpos() functions.
9742 */
9743 static int
9744search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9745{
9746 int flags;
9747 char_u *pat;
9748 pos_T pos;
9749 pos_T save_cursor;
9750 int save_p_ws = p_ws;
9751 int dir;
9752 int retval = 0; /* default: FAIL */
9753 long lnum_stop = 0;
9754 proftime_T tm;
9755#ifdef FEAT_RELTIME
9756 long time_limit = 0;
9757#endif
9758 int options = SEARCH_KEEP;
9759 int subpatnum;
9760
9761 pat = get_tv_string(&argvars[0]);
9762 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9763 if (dir == 0)
9764 goto theend;
9765 flags = *flagsp;
9766 if (flags & SP_START)
9767 options |= SEARCH_START;
9768 if (flags & SP_END)
9769 options |= SEARCH_END;
9770 if (flags & SP_COLUMN)
9771 options |= SEARCH_COL;
9772
9773 /* Optional arguments: line number to stop searching and timeout. */
9774 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9775 {
9776 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9777 if (lnum_stop < 0)
9778 goto theend;
9779#ifdef FEAT_RELTIME
9780 if (argvars[3].v_type != VAR_UNKNOWN)
9781 {
9782 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9783 if (time_limit < 0)
9784 goto theend;
9785 }
9786#endif
9787 }
9788
9789#ifdef FEAT_RELTIME
9790 /* Set the time limit, if there is one. */
9791 profile_setlimit(time_limit, &tm);
9792#endif
9793
9794 /*
9795 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9796 * Check to make sure only those flags are set.
9797 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9798 * flags cannot be set. Check for that condition also.
9799 */
9800 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9801 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9802 {
9803 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9804 goto theend;
9805 }
9806
9807 pos = save_cursor = curwin->w_cursor;
9808 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009809 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009810 if (subpatnum != FAIL)
9811 {
9812 if (flags & SP_SUBPAT)
9813 retval = subpatnum;
9814 else
9815 retval = pos.lnum;
9816 if (flags & SP_SETPCMARK)
9817 setpcmark();
9818 curwin->w_cursor = pos;
9819 if (match_pos != NULL)
9820 {
9821 /* Store the match cursor position */
9822 match_pos->lnum = pos.lnum;
9823 match_pos->col = pos.col + 1;
9824 }
9825 /* "/$" will put the cursor after the end of the line, may need to
9826 * correct that here */
9827 check_cursor();
9828 }
9829
9830 /* If 'n' flag is used: restore cursor position. */
9831 if (flags & SP_NOMOVE)
9832 curwin->w_cursor = save_cursor;
9833 else
9834 curwin->w_set_curswant = TRUE;
9835theend:
9836 p_ws = save_p_ws;
9837
9838 return retval;
9839}
9840
9841#ifdef FEAT_FLOAT
9842
9843/*
9844 * round() is not in C90, use ceil() or floor() instead.
9845 */
9846 float_T
9847vim_round(float_T f)
9848{
9849 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9850}
9851
9852/*
9853 * "round({float})" function
9854 */
9855 static void
9856f_round(typval_T *argvars, typval_T *rettv)
9857{
9858 float_T f = 0.0;
9859
9860 rettv->v_type = VAR_FLOAT;
9861 if (get_float_arg(argvars, &f) == OK)
9862 rettv->vval.v_float = vim_round(f);
9863 else
9864 rettv->vval.v_float = 0.0;
9865}
9866#endif
9867
9868/*
9869 * "screenattr()" function
9870 */
9871 static void
9872f_screenattr(typval_T *argvars, typval_T *rettv)
9873{
9874 int row;
9875 int col;
9876 int c;
9877
9878 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9879 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9880 if (row < 0 || row >= screen_Rows
9881 || col < 0 || col >= screen_Columns)
9882 c = -1;
9883 else
9884 c = ScreenAttrs[LineOffset[row] + col];
9885 rettv->vval.v_number = c;
9886}
9887
9888/*
9889 * "screenchar()" function
9890 */
9891 static void
9892f_screenchar(typval_T *argvars, typval_T *rettv)
9893{
9894 int row;
9895 int col;
9896 int off;
9897 int c;
9898
9899 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9900 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9901 if (row < 0 || row >= screen_Rows
9902 || col < 0 || col >= screen_Columns)
9903 c = -1;
9904 else
9905 {
9906 off = LineOffset[row] + col;
9907#ifdef FEAT_MBYTE
9908 if (enc_utf8 && ScreenLinesUC[off] != 0)
9909 c = ScreenLinesUC[off];
9910 else
9911#endif
9912 c = ScreenLines[off];
9913 }
9914 rettv->vval.v_number = c;
9915}
9916
9917/*
9918 * "screencol()" function
9919 *
9920 * First column is 1 to be consistent with virtcol().
9921 */
9922 static void
9923f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9924{
9925 rettv->vval.v_number = screen_screencol() + 1;
9926}
9927
9928/*
9929 * "screenrow()" function
9930 */
9931 static void
9932f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9933{
9934 rettv->vval.v_number = screen_screenrow() + 1;
9935}
9936
9937/*
9938 * "search()" function
9939 */
9940 static void
9941f_search(typval_T *argvars, typval_T *rettv)
9942{
9943 int flags = 0;
9944
9945 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9946}
9947
9948/*
9949 * "searchdecl()" function
9950 */
9951 static void
9952f_searchdecl(typval_T *argvars, typval_T *rettv)
9953{
9954 int locally = 1;
9955 int thisblock = 0;
9956 int error = FALSE;
9957 char_u *name;
9958
9959 rettv->vval.v_number = 1; /* default: FAIL */
9960
9961 name = get_tv_string_chk(&argvars[0]);
9962 if (argvars[1].v_type != VAR_UNKNOWN)
9963 {
9964 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9965 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9966 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9967 }
9968 if (!error && name != NULL)
9969 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9970 locally, thisblock, SEARCH_KEEP) == FAIL;
9971}
9972
9973/*
9974 * Used by searchpair() and searchpairpos()
9975 */
9976 static int
9977searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9978{
9979 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009980 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009981 int save_p_ws = p_ws;
9982 int dir;
9983 int flags = 0;
9984 char_u nbuf1[NUMBUFLEN];
9985 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009986 int retval = 0; /* default: FAIL */
9987 long lnum_stop = 0;
9988 long time_limit = 0;
9989
9990 /* Get the three pattern arguments: start, middle, end. */
9991 spat = get_tv_string_chk(&argvars[0]);
9992 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9993 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9994 if (spat == NULL || mpat == NULL || epat == NULL)
9995 goto theend; /* type error */
9996
9997 /* Handle the optional fourth argument: flags */
9998 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9999 if (dir == 0)
10000 goto theend;
10001
10002 /* Don't accept SP_END or SP_SUBPAT.
10003 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10004 */
10005 if ((flags & (SP_END | SP_SUBPAT)) != 0
10006 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10007 {
10008 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10009 goto theend;
10010 }
10011
10012 /* Using 'r' implies 'W', otherwise it doesn't work. */
10013 if (flags & SP_REPEAT)
10014 p_ws = FALSE;
10015
10016 /* Optional fifth argument: skip expression */
10017 if (argvars[3].v_type == VAR_UNKNOWN
10018 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010019 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010020 else
10021 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010022 skip = &argvars[4];
10023 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10024 && skip->v_type != VAR_STRING)
10025 {
10026 /* Type error */
10027 goto theend;
10028 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010029 if (argvars[5].v_type != VAR_UNKNOWN)
10030 {
10031 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10032 if (lnum_stop < 0)
10033 goto theend;
10034#ifdef FEAT_RELTIME
10035 if (argvars[6].v_type != VAR_UNKNOWN)
10036 {
10037 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10038 if (time_limit < 0)
10039 goto theend;
10040 }
10041#endif
10042 }
10043 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010044
10045 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10046 match_pos, lnum_stop, time_limit);
10047
10048theend:
10049 p_ws = save_p_ws;
10050
10051 return retval;
10052}
10053
10054/*
10055 * "searchpair()" function
10056 */
10057 static void
10058f_searchpair(typval_T *argvars, typval_T *rettv)
10059{
10060 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10061}
10062
10063/*
10064 * "searchpairpos()" function
10065 */
10066 static void
10067f_searchpairpos(typval_T *argvars, typval_T *rettv)
10068{
10069 pos_T match_pos;
10070 int lnum = 0;
10071 int col = 0;
10072
10073 if (rettv_list_alloc(rettv) == FAIL)
10074 return;
10075
10076 if (searchpair_cmn(argvars, &match_pos) > 0)
10077 {
10078 lnum = match_pos.lnum;
10079 col = match_pos.col;
10080 }
10081
10082 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10083 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10084}
10085
10086/*
10087 * Search for a start/middle/end thing.
10088 * Used by searchpair(), see its documentation for the details.
10089 * Returns 0 or -1 for no match,
10090 */
10091 long
10092do_searchpair(
10093 char_u *spat, /* start pattern */
10094 char_u *mpat, /* middle pattern */
10095 char_u *epat, /* end pattern */
10096 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010097 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010098 int flags, /* SP_SETPCMARK and other SP_ values */
10099 pos_T *match_pos,
10100 linenr_T lnum_stop, /* stop at this line if not zero */
10101 long time_limit UNUSED) /* stop after this many msec */
10102{
10103 char_u *save_cpo;
10104 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10105 long retval = 0;
10106 pos_T pos;
10107 pos_T firstpos;
10108 pos_T foundpos;
10109 pos_T save_cursor;
10110 pos_T save_pos;
10111 int n;
10112 int r;
10113 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010114 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010115 int err;
10116 int options = SEARCH_KEEP;
10117 proftime_T tm;
10118
10119 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10120 save_cpo = p_cpo;
10121 p_cpo = empty_option;
10122
10123#ifdef FEAT_RELTIME
10124 /* Set the time limit, if there is one. */
10125 profile_setlimit(time_limit, &tm);
10126#endif
10127
10128 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10129 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010130 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10131 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010132 if (pat2 == NULL || pat3 == NULL)
10133 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010134 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010135 if (*mpat == NUL)
10136 STRCPY(pat3, pat2);
10137 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010138 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010139 spat, epat, mpat);
10140 if (flags & SP_START)
10141 options |= SEARCH_START;
10142
Bram Moolenaar48570482017-10-30 21:48:41 +010010143 if (skip != NULL)
10144 {
10145 /* Empty string means to not use the skip expression. */
10146 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10147 use_skip = skip->vval.v_string != NULL
10148 && *skip->vval.v_string != NUL;
10149 }
10150
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010151 save_cursor = curwin->w_cursor;
10152 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010153 CLEAR_POS(&firstpos);
10154 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010155 pat = pat3;
10156 for (;;)
10157 {
10158 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010159 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010160 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010161 /* didn't find it or found the first match again: FAIL */
10162 break;
10163
10164 if (firstpos.lnum == 0)
10165 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010166 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010167 {
10168 /* Found the same position again. Can happen with a pattern that
10169 * has "\zs" at the end and searching backwards. Advance one
10170 * character and try again. */
10171 if (dir == BACKWARD)
10172 decl(&pos);
10173 else
10174 incl(&pos);
10175 }
10176 foundpos = pos;
10177
10178 /* clear the start flag to avoid getting stuck here */
10179 options &= ~SEARCH_START;
10180
10181 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010182 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010183 {
10184 save_pos = curwin->w_cursor;
10185 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010186 err = FALSE;
10187 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010188 curwin->w_cursor = save_pos;
10189 if (err)
10190 {
10191 /* Evaluating {skip} caused an error, break here. */
10192 curwin->w_cursor = save_cursor;
10193 retval = -1;
10194 break;
10195 }
10196 if (r)
10197 continue;
10198 }
10199
10200 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10201 {
10202 /* Found end when searching backwards or start when searching
10203 * forward: nested pair. */
10204 ++nest;
10205 pat = pat2; /* nested, don't search for middle */
10206 }
10207 else
10208 {
10209 /* Found end when searching forward or start when searching
10210 * backward: end of (nested) pair; or found middle in outer pair. */
10211 if (--nest == 1)
10212 pat = pat3; /* outer level, search for middle */
10213 }
10214
10215 if (nest == 0)
10216 {
10217 /* Found the match: return matchcount or line number. */
10218 if (flags & SP_RETCOUNT)
10219 ++retval;
10220 else
10221 retval = pos.lnum;
10222 if (flags & SP_SETPCMARK)
10223 setpcmark();
10224 curwin->w_cursor = pos;
10225 if (!(flags & SP_REPEAT))
10226 break;
10227 nest = 1; /* search for next unmatched */
10228 }
10229 }
10230
10231 if (match_pos != NULL)
10232 {
10233 /* Store the match cursor position */
10234 match_pos->lnum = curwin->w_cursor.lnum;
10235 match_pos->col = curwin->w_cursor.col + 1;
10236 }
10237
10238 /* If 'n' flag is used or search failed: restore cursor position. */
10239 if ((flags & SP_NOMOVE) || retval == 0)
10240 curwin->w_cursor = save_cursor;
10241
10242theend:
10243 vim_free(pat2);
10244 vim_free(pat3);
10245 if (p_cpo == empty_option)
10246 p_cpo = save_cpo;
10247 else
10248 /* Darn, evaluating the {skip} expression changed the value. */
10249 free_string_option(save_cpo);
10250
10251 return retval;
10252}
10253
10254/*
10255 * "searchpos()" function
10256 */
10257 static void
10258f_searchpos(typval_T *argvars, typval_T *rettv)
10259{
10260 pos_T match_pos;
10261 int lnum = 0;
10262 int col = 0;
10263 int n;
10264 int flags = 0;
10265
10266 if (rettv_list_alloc(rettv) == FAIL)
10267 return;
10268
10269 n = search_cmn(argvars, &match_pos, &flags);
10270 if (n > 0)
10271 {
10272 lnum = match_pos.lnum;
10273 col = match_pos.col;
10274 }
10275
10276 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10277 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10278 if (flags & SP_SUBPAT)
10279 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10280}
10281
10282 static void
10283f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10284{
10285#ifdef FEAT_CLIENTSERVER
10286 char_u buf[NUMBUFLEN];
10287 char_u *server = get_tv_string_chk(&argvars[0]);
10288 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10289
10290 rettv->vval.v_number = -1;
10291 if (server == NULL || reply == NULL)
10292 return;
10293 if (check_restricted() || check_secure())
10294 return;
10295# ifdef FEAT_X11
10296 if (check_connection() == FAIL)
10297 return;
10298# endif
10299
10300 if (serverSendReply(server, reply) < 0)
10301 {
10302 EMSG(_("E258: Unable to send to client"));
10303 return;
10304 }
10305 rettv->vval.v_number = 0;
10306#else
10307 rettv->vval.v_number = -1;
10308#endif
10309}
10310
10311 static void
10312f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10313{
10314 char_u *r = NULL;
10315
10316#ifdef FEAT_CLIENTSERVER
10317# ifdef WIN32
10318 r = serverGetVimNames();
10319# else
10320 make_connection();
10321 if (X_DISPLAY != NULL)
10322 r = serverGetVimNames(X_DISPLAY);
10323# endif
10324#endif
10325 rettv->v_type = VAR_STRING;
10326 rettv->vval.v_string = r;
10327}
10328
10329/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010330 * "setbufline()" function
10331 */
10332 static void
10333f_setbufline(argvars, rettv)
10334 typval_T *argvars;
10335 typval_T *rettv;
10336{
10337 linenr_T lnum;
10338 buf_T *buf;
10339
10340 buf = get_buf_tv(&argvars[0], FALSE);
10341 if (buf == NULL)
10342 rettv->vval.v_number = 1; /* FAIL */
10343 else
10344 {
10345 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010346 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010347 }
10348}
10349
10350/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010351 * "setbufvar()" function
10352 */
10353 static void
10354f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10355{
10356 buf_T *buf;
10357 char_u *varname, *bufvarname;
10358 typval_T *varp;
10359 char_u nbuf[NUMBUFLEN];
10360
10361 if (check_restricted() || check_secure())
10362 return;
10363 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10364 varname = get_tv_string_chk(&argvars[1]);
10365 buf = get_buf_tv(&argvars[0], FALSE);
10366 varp = &argvars[2];
10367
10368 if (buf != NULL && varname != NULL && varp != NULL)
10369 {
10370 if (*varname == '&')
10371 {
10372 long numval;
10373 char_u *strval;
10374 int error = FALSE;
10375 aco_save_T aco;
10376
10377 /* set curbuf to be our buf, temporarily */
10378 aucmd_prepbuf(&aco, buf);
10379
10380 ++varname;
10381 numval = (long)get_tv_number_chk(varp, &error);
10382 strval = get_tv_string_buf_chk(varp, nbuf);
10383 if (!error && strval != NULL)
10384 set_option_value(varname, numval, strval, OPT_LOCAL);
10385
10386 /* reset notion of buffer */
10387 aucmd_restbuf(&aco);
10388 }
10389 else
10390 {
10391 buf_T *save_curbuf = curbuf;
10392
10393 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10394 if (bufvarname != NULL)
10395 {
10396 curbuf = buf;
10397 STRCPY(bufvarname, "b:");
10398 STRCPY(bufvarname + 2, varname);
10399 set_var(bufvarname, varp, TRUE);
10400 vim_free(bufvarname);
10401 curbuf = save_curbuf;
10402 }
10403 }
10404 }
10405}
10406
10407 static void
10408f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10409{
10410 dict_T *d;
10411 dictitem_T *di;
10412 char_u *csearch;
10413
10414 if (argvars[0].v_type != VAR_DICT)
10415 {
10416 EMSG(_(e_dictreq));
10417 return;
10418 }
10419
10420 if ((d = argvars[0].vval.v_dict) != NULL)
10421 {
10422 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10423 if (csearch != NULL)
10424 {
10425#ifdef FEAT_MBYTE
10426 if (enc_utf8)
10427 {
10428 int pcc[MAX_MCO];
10429 int c = utfc_ptr2char(csearch, pcc);
10430
10431 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10432 }
10433 else
10434#endif
10435 set_last_csearch(PTR2CHAR(csearch),
10436 csearch, MB_PTR2LEN(csearch));
10437 }
10438
10439 di = dict_find(d, (char_u *)"forward", -1);
10440 if (di != NULL)
10441 set_csearch_direction((int)get_tv_number(&di->di_tv)
10442 ? FORWARD : BACKWARD);
10443
10444 di = dict_find(d, (char_u *)"until", -1);
10445 if (di != NULL)
10446 set_csearch_until(!!get_tv_number(&di->di_tv));
10447 }
10448}
10449
10450/*
10451 * "setcmdpos()" function
10452 */
10453 static void
10454f_setcmdpos(typval_T *argvars, typval_T *rettv)
10455{
10456 int pos = (int)get_tv_number(&argvars[0]) - 1;
10457
10458 if (pos >= 0)
10459 rettv->vval.v_number = set_cmdline_pos(pos);
10460}
10461
10462/*
10463 * "setfperm({fname}, {mode})" function
10464 */
10465 static void
10466f_setfperm(typval_T *argvars, typval_T *rettv)
10467{
10468 char_u *fname;
10469 char_u modebuf[NUMBUFLEN];
10470 char_u *mode_str;
10471 int i;
10472 int mask;
10473 int mode = 0;
10474
10475 rettv->vval.v_number = 0;
10476 fname = get_tv_string_chk(&argvars[0]);
10477 if (fname == NULL)
10478 return;
10479 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10480 if (mode_str == NULL)
10481 return;
10482 if (STRLEN(mode_str) != 9)
10483 {
10484 EMSG2(_(e_invarg2), mode_str);
10485 return;
10486 }
10487
10488 mask = 1;
10489 for (i = 8; i >= 0; --i)
10490 {
10491 if (mode_str[i] != '-')
10492 mode |= mask;
10493 mask = mask << 1;
10494 }
10495 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10496}
10497
10498/*
10499 * "setline()" function
10500 */
10501 static void
10502f_setline(typval_T *argvars, typval_T *rettv)
10503{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010504 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010505
Bram Moolenaarca851592018-06-06 21:04:07 +020010506 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010507}
10508
Bram Moolenaard823fa92016-08-12 16:29:27 +020010509static 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 +020010510
10511/*
10512 * Used by "setqflist()" and "setloclist()" functions
10513 */
10514 static void
10515set_qf_ll_list(
10516 win_T *wp UNUSED,
10517 typval_T *list_arg UNUSED,
10518 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010519 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010520 typval_T *rettv)
10521{
10522#ifdef FEAT_QUICKFIX
10523 static char *e_invact = N_("E927: Invalid action: '%s'");
10524 char_u *act;
10525 int action = 0;
10526#endif
10527
10528 rettv->vval.v_number = -1;
10529
10530#ifdef FEAT_QUICKFIX
10531 if (list_arg->v_type != VAR_LIST)
10532 EMSG(_(e_listreq));
10533 else
10534 {
10535 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010536 dict_T *d = NULL;
10537 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010538
10539 if (action_arg->v_type == VAR_STRING)
10540 {
10541 act = get_tv_string_chk(action_arg);
10542 if (act == NULL)
10543 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010544 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10545 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010546 action = *act;
10547 else
10548 EMSG2(_(e_invact), act);
10549 }
10550 else if (action_arg->v_type == VAR_UNKNOWN)
10551 action = ' ';
10552 else
10553 EMSG(_(e_stringreq));
10554
Bram Moolenaard823fa92016-08-12 16:29:27 +020010555 if (action_arg->v_type != VAR_UNKNOWN
10556 && what_arg->v_type != VAR_UNKNOWN)
10557 {
10558 if (what_arg->v_type == VAR_DICT)
10559 d = what_arg->vval.v_dict;
10560 else
10561 {
10562 EMSG(_(e_dictreq));
10563 valid_dict = FALSE;
10564 }
10565 }
10566
10567 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar8b62e312018-05-13 15:29:04 +020010568 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010569 rettv->vval.v_number = 0;
10570 }
10571#endif
10572}
10573
10574/*
10575 * "setloclist()" function
10576 */
10577 static void
10578f_setloclist(typval_T *argvars, typval_T *rettv)
10579{
10580 win_T *win;
10581
10582 rettv->vval.v_number = -1;
10583
10584 win = find_win_by_nr(&argvars[0], NULL);
10585 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010586 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010587}
10588
10589/*
10590 * "setmatches()" function
10591 */
10592 static void
10593f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10594{
10595#ifdef FEAT_SEARCH_EXTRA
10596 list_T *l;
10597 listitem_T *li;
10598 dict_T *d;
10599 list_T *s = NULL;
10600
10601 rettv->vval.v_number = -1;
10602 if (argvars[0].v_type != VAR_LIST)
10603 {
10604 EMSG(_(e_listreq));
10605 return;
10606 }
10607 if ((l = argvars[0].vval.v_list) != NULL)
10608 {
10609
10610 /* To some extent make sure that we are dealing with a list from
10611 * "getmatches()". */
10612 li = l->lv_first;
10613 while (li != NULL)
10614 {
10615 if (li->li_tv.v_type != VAR_DICT
10616 || (d = li->li_tv.vval.v_dict) == NULL)
10617 {
10618 EMSG(_(e_invarg));
10619 return;
10620 }
10621 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10622 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10623 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10624 && dict_find(d, (char_u *)"priority", -1) != NULL
10625 && dict_find(d, (char_u *)"id", -1) != NULL))
10626 {
10627 EMSG(_(e_invarg));
10628 return;
10629 }
10630 li = li->li_next;
10631 }
10632
10633 clear_matches(curwin);
10634 li = l->lv_first;
10635 while (li != NULL)
10636 {
10637 int i = 0;
10638 char_u buf[5];
10639 dictitem_T *di;
10640 char_u *group;
10641 int priority;
10642 int id;
10643 char_u *conceal;
10644
10645 d = li->li_tv.vval.v_dict;
10646 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10647 {
10648 if (s == NULL)
10649 {
10650 s = list_alloc();
10651 if (s == NULL)
10652 return;
10653 }
10654
10655 /* match from matchaddpos() */
10656 for (i = 1; i < 9; i++)
10657 {
10658 sprintf((char *)buf, (char *)"pos%d", i);
10659 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10660 {
10661 if (di->di_tv.v_type != VAR_LIST)
10662 return;
10663
10664 list_append_tv(s, &di->di_tv);
10665 s->lv_refcount++;
10666 }
10667 else
10668 break;
10669 }
10670 }
10671
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010672 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010673 priority = (int)get_dict_number(d, (char_u *)"priority");
10674 id = (int)get_dict_number(d, (char_u *)"id");
10675 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010676 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010677 : NULL;
10678 if (i == 0)
10679 {
10680 match_add(curwin, group,
10681 get_dict_string(d, (char_u *)"pattern", FALSE),
10682 priority, id, NULL, conceal);
10683 }
10684 else
10685 {
10686 match_add(curwin, group, NULL, priority, id, s, conceal);
10687 list_unref(s);
10688 s = NULL;
10689 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010690 vim_free(group);
10691 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010692
10693 li = li->li_next;
10694 }
10695 rettv->vval.v_number = 0;
10696 }
10697#endif
10698}
10699
10700/*
10701 * "setpos()" function
10702 */
10703 static void
10704f_setpos(typval_T *argvars, typval_T *rettv)
10705{
10706 pos_T pos;
10707 int fnum;
10708 char_u *name;
10709 colnr_T curswant = -1;
10710
10711 rettv->vval.v_number = -1;
10712 name = get_tv_string_chk(argvars);
10713 if (name != NULL)
10714 {
10715 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10716 {
10717 if (--pos.col < 0)
10718 pos.col = 0;
10719 if (name[0] == '.' && name[1] == NUL)
10720 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010721 /* set cursor; "fnum" is ignored */
10722 curwin->w_cursor = pos;
10723 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010724 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010725 curwin->w_curswant = curswant - 1;
10726 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010727 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010728 check_cursor();
10729 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010730 }
10731 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10732 {
10733 /* set mark */
10734 if (setmark_pos(name[1], &pos, fnum) == OK)
10735 rettv->vval.v_number = 0;
10736 }
10737 else
10738 EMSG(_(e_invarg));
10739 }
10740 }
10741}
10742
10743/*
10744 * "setqflist()" function
10745 */
10746 static void
10747f_setqflist(typval_T *argvars, typval_T *rettv)
10748{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010749 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010750}
10751
10752/*
10753 * "setreg()" function
10754 */
10755 static void
10756f_setreg(typval_T *argvars, typval_T *rettv)
10757{
10758 int regname;
10759 char_u *strregname;
10760 char_u *stropt;
10761 char_u *strval;
10762 int append;
10763 char_u yank_type;
10764 long block_len;
10765
10766 block_len = -1;
10767 yank_type = MAUTO;
10768 append = FALSE;
10769
10770 strregname = get_tv_string_chk(argvars);
10771 rettv->vval.v_number = 1; /* FAIL is default */
10772
10773 if (strregname == NULL)
10774 return; /* type error; errmsg already given */
10775 regname = *strregname;
10776 if (regname == 0 || regname == '@')
10777 regname = '"';
10778
10779 if (argvars[2].v_type != VAR_UNKNOWN)
10780 {
10781 stropt = get_tv_string_chk(&argvars[2]);
10782 if (stropt == NULL)
10783 return; /* type error */
10784 for (; *stropt != NUL; ++stropt)
10785 switch (*stropt)
10786 {
10787 case 'a': case 'A': /* append */
10788 append = TRUE;
10789 break;
10790 case 'v': case 'c': /* character-wise selection */
10791 yank_type = MCHAR;
10792 break;
10793 case 'V': case 'l': /* line-wise selection */
10794 yank_type = MLINE;
10795 break;
10796 case 'b': case Ctrl_V: /* block-wise selection */
10797 yank_type = MBLOCK;
10798 if (VIM_ISDIGIT(stropt[1]))
10799 {
10800 ++stropt;
10801 block_len = getdigits(&stropt) - 1;
10802 --stropt;
10803 }
10804 break;
10805 }
10806 }
10807
10808 if (argvars[1].v_type == VAR_LIST)
10809 {
10810 char_u **lstval;
10811 char_u **allocval;
10812 char_u buf[NUMBUFLEN];
10813 char_u **curval;
10814 char_u **curallocval;
10815 list_T *ll = argvars[1].vval.v_list;
10816 listitem_T *li;
10817 int len;
10818
10819 /* If the list is NULL handle like an empty list. */
10820 len = ll == NULL ? 0 : ll->lv_len;
10821
10822 /* First half: use for pointers to result lines; second half: use for
10823 * pointers to allocated copies. */
10824 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10825 if (lstval == NULL)
10826 return;
10827 curval = lstval;
10828 allocval = lstval + len + 2;
10829 curallocval = allocval;
10830
10831 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10832 li = li->li_next)
10833 {
10834 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10835 if (strval == NULL)
10836 goto free_lstval;
10837 if (strval == buf)
10838 {
10839 /* Need to make a copy, next get_tv_string_buf_chk() will
10840 * overwrite the string. */
10841 strval = vim_strsave(buf);
10842 if (strval == NULL)
10843 goto free_lstval;
10844 *curallocval++ = strval;
10845 }
10846 *curval++ = strval;
10847 }
10848 *curval++ = NULL;
10849
10850 write_reg_contents_lst(regname, lstval, -1,
10851 append, yank_type, block_len);
10852free_lstval:
10853 while (curallocval > allocval)
10854 vim_free(*--curallocval);
10855 vim_free(lstval);
10856 }
10857 else
10858 {
10859 strval = get_tv_string_chk(&argvars[1]);
10860 if (strval == NULL)
10861 return;
10862 write_reg_contents_ex(regname, strval, -1,
10863 append, yank_type, block_len);
10864 }
10865 rettv->vval.v_number = 0;
10866}
10867
10868/*
10869 * "settabvar()" function
10870 */
10871 static void
10872f_settabvar(typval_T *argvars, typval_T *rettv)
10873{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010874 tabpage_T *save_curtab;
10875 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010876 char_u *varname, *tabvarname;
10877 typval_T *varp;
10878
10879 rettv->vval.v_number = 0;
10880
10881 if (check_restricted() || check_secure())
10882 return;
10883
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010884 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010885 varname = get_tv_string_chk(&argvars[1]);
10886 varp = &argvars[2];
10887
Bram Moolenaar4033c552017-09-16 20:54:51 +020010888 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010889 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010890 save_curtab = curtab;
10891 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010892
10893 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10894 if (tabvarname != NULL)
10895 {
10896 STRCPY(tabvarname, "t:");
10897 STRCPY(tabvarname + 2, varname);
10898 set_var(tabvarname, varp, TRUE);
10899 vim_free(tabvarname);
10900 }
10901
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010902 /* Restore current tabpage */
10903 if (valid_tabpage(save_curtab))
10904 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010905 }
10906}
10907
10908/*
10909 * "settabwinvar()" function
10910 */
10911 static void
10912f_settabwinvar(typval_T *argvars, typval_T *rettv)
10913{
10914 setwinvar(argvars, rettv, 1);
10915}
10916
10917/*
10918 * "setwinvar()" function
10919 */
10920 static void
10921f_setwinvar(typval_T *argvars, typval_T *rettv)
10922{
10923 setwinvar(argvars, rettv, 0);
10924}
10925
10926#ifdef FEAT_CRYPT
10927/*
10928 * "sha256({string})" function
10929 */
10930 static void
10931f_sha256(typval_T *argvars, typval_T *rettv)
10932{
10933 char_u *p;
10934
10935 p = get_tv_string(&argvars[0]);
10936 rettv->vval.v_string = vim_strsave(
10937 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10938 rettv->v_type = VAR_STRING;
10939}
10940#endif /* FEAT_CRYPT */
10941
10942/*
10943 * "shellescape({string})" function
10944 */
10945 static void
10946f_shellescape(typval_T *argvars, typval_T *rettv)
10947{
Bram Moolenaar20615522017-06-05 18:46:26 +020010948 int do_special = non_zero_arg(&argvars[1]);
10949
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010950 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010951 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010952 rettv->v_type = VAR_STRING;
10953}
10954
10955/*
10956 * shiftwidth() function
10957 */
10958 static void
10959f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10960{
10961 rettv->vval.v_number = get_sw_value(curbuf);
10962}
10963
10964/*
10965 * "simplify()" function
10966 */
10967 static void
10968f_simplify(typval_T *argvars, typval_T *rettv)
10969{
10970 char_u *p;
10971
10972 p = get_tv_string(&argvars[0]);
10973 rettv->vval.v_string = vim_strsave(p);
10974 simplify_filename(rettv->vval.v_string); /* simplify in place */
10975 rettv->v_type = VAR_STRING;
10976}
10977
10978#ifdef FEAT_FLOAT
10979/*
10980 * "sin()" function
10981 */
10982 static void
10983f_sin(typval_T *argvars, typval_T *rettv)
10984{
10985 float_T f = 0.0;
10986
10987 rettv->v_type = VAR_FLOAT;
10988 if (get_float_arg(argvars, &f) == OK)
10989 rettv->vval.v_float = sin(f);
10990 else
10991 rettv->vval.v_float = 0.0;
10992}
10993
10994/*
10995 * "sinh()" function
10996 */
10997 static void
10998f_sinh(typval_T *argvars, typval_T *rettv)
10999{
11000 float_T f = 0.0;
11001
11002 rettv->v_type = VAR_FLOAT;
11003 if (get_float_arg(argvars, &f) == OK)
11004 rettv->vval.v_float = sinh(f);
11005 else
11006 rettv->vval.v_float = 0.0;
11007}
11008#endif
11009
11010static int
11011#ifdef __BORLANDC__
11012 _RTLENTRYF
11013#endif
11014 item_compare(const void *s1, const void *s2);
11015static int
11016#ifdef __BORLANDC__
11017 _RTLENTRYF
11018#endif
11019 item_compare2(const void *s1, const void *s2);
11020
11021/* struct used in the array that's given to qsort() */
11022typedef struct
11023{
11024 listitem_T *item;
11025 int idx;
11026} sortItem_T;
11027
11028/* struct storing information about current sort */
11029typedef struct
11030{
11031 int item_compare_ic;
11032 int item_compare_numeric;
11033 int item_compare_numbers;
11034#ifdef FEAT_FLOAT
11035 int item_compare_float;
11036#endif
11037 char_u *item_compare_func;
11038 partial_T *item_compare_partial;
11039 dict_T *item_compare_selfdict;
11040 int item_compare_func_err;
11041 int item_compare_keep_zero;
11042} sortinfo_T;
11043static sortinfo_T *sortinfo = NULL;
11044static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
11045#define ITEM_COMPARE_FAIL 999
11046
11047/*
11048 * Compare functions for f_sort() and f_uniq() below.
11049 */
11050 static int
11051#ifdef __BORLANDC__
11052_RTLENTRYF
11053#endif
11054item_compare(const void *s1, const void *s2)
11055{
11056 sortItem_T *si1, *si2;
11057 typval_T *tv1, *tv2;
11058 char_u *p1, *p2;
11059 char_u *tofree1 = NULL, *tofree2 = NULL;
11060 int res;
11061 char_u numbuf1[NUMBUFLEN];
11062 char_u numbuf2[NUMBUFLEN];
11063
11064 si1 = (sortItem_T *)s1;
11065 si2 = (sortItem_T *)s2;
11066 tv1 = &si1->item->li_tv;
11067 tv2 = &si2->item->li_tv;
11068
11069 if (sortinfo->item_compare_numbers)
11070 {
11071 varnumber_T v1 = get_tv_number(tv1);
11072 varnumber_T v2 = get_tv_number(tv2);
11073
11074 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11075 }
11076
11077#ifdef FEAT_FLOAT
11078 if (sortinfo->item_compare_float)
11079 {
11080 float_T v1 = get_tv_float(tv1);
11081 float_T v2 = get_tv_float(tv2);
11082
11083 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11084 }
11085#endif
11086
11087 /* tv2string() puts quotes around a string and allocates memory. Don't do
11088 * that for string variables. Use a single quote when comparing with a
11089 * non-string to do what the docs promise. */
11090 if (tv1->v_type == VAR_STRING)
11091 {
11092 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11093 p1 = (char_u *)"'";
11094 else
11095 p1 = tv1->vval.v_string;
11096 }
11097 else
11098 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11099 if (tv2->v_type == VAR_STRING)
11100 {
11101 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11102 p2 = (char_u *)"'";
11103 else
11104 p2 = tv2->vval.v_string;
11105 }
11106 else
11107 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11108 if (p1 == NULL)
11109 p1 = (char_u *)"";
11110 if (p2 == NULL)
11111 p2 = (char_u *)"";
11112 if (!sortinfo->item_compare_numeric)
11113 {
11114 if (sortinfo->item_compare_ic)
11115 res = STRICMP(p1, p2);
11116 else
11117 res = STRCMP(p1, p2);
11118 }
11119 else
11120 {
11121 double n1, n2;
11122 n1 = strtod((char *)p1, (char **)&p1);
11123 n2 = strtod((char *)p2, (char **)&p2);
11124 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11125 }
11126
11127 /* When the result would be zero, compare the item indexes. Makes the
11128 * sort stable. */
11129 if (res == 0 && !sortinfo->item_compare_keep_zero)
11130 res = si1->idx > si2->idx ? 1 : -1;
11131
11132 vim_free(tofree1);
11133 vim_free(tofree2);
11134 return res;
11135}
11136
11137 static int
11138#ifdef __BORLANDC__
11139_RTLENTRYF
11140#endif
11141item_compare2(const void *s1, const void *s2)
11142{
11143 sortItem_T *si1, *si2;
11144 int res;
11145 typval_T rettv;
11146 typval_T argv[3];
11147 int dummy;
11148 char_u *func_name;
11149 partial_T *partial = sortinfo->item_compare_partial;
11150
11151 /* shortcut after failure in previous call; compare all items equal */
11152 if (sortinfo->item_compare_func_err)
11153 return 0;
11154
11155 si1 = (sortItem_T *)s1;
11156 si2 = (sortItem_T *)s2;
11157
11158 if (partial == NULL)
11159 func_name = sortinfo->item_compare_func;
11160 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011161 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011162
11163 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11164 * in the copy without changing the original list items. */
11165 copy_tv(&si1->item->li_tv, &argv[0]);
11166 copy_tv(&si2->item->li_tv, &argv[1]);
11167
11168 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11169 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011170 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011171 partial, sortinfo->item_compare_selfdict);
11172 clear_tv(&argv[0]);
11173 clear_tv(&argv[1]);
11174
11175 if (res == FAIL)
11176 res = ITEM_COMPARE_FAIL;
11177 else
11178 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11179 if (sortinfo->item_compare_func_err)
11180 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11181 clear_tv(&rettv);
11182
11183 /* When the result would be zero, compare the pointers themselves. Makes
11184 * the sort stable. */
11185 if (res == 0 && !sortinfo->item_compare_keep_zero)
11186 res = si1->idx > si2->idx ? 1 : -1;
11187
11188 return res;
11189}
11190
11191/*
11192 * "sort({list})" function
11193 */
11194 static void
11195do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11196{
11197 list_T *l;
11198 listitem_T *li;
11199 sortItem_T *ptrs;
11200 sortinfo_T *old_sortinfo;
11201 sortinfo_T info;
11202 long len;
11203 long i;
11204
11205 /* Pointer to current info struct used in compare function. Save and
11206 * restore the current one for nested calls. */
11207 old_sortinfo = sortinfo;
11208 sortinfo = &info;
11209
11210 if (argvars[0].v_type != VAR_LIST)
11211 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11212 else
11213 {
11214 l = argvars[0].vval.v_list;
11215 if (l == NULL || tv_check_lock(l->lv_lock,
11216 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11217 TRUE))
11218 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011219 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011220
11221 len = list_len(l);
11222 if (len <= 1)
11223 goto theend; /* short list sorts pretty quickly */
11224
11225 info.item_compare_ic = FALSE;
11226 info.item_compare_numeric = FALSE;
11227 info.item_compare_numbers = FALSE;
11228#ifdef FEAT_FLOAT
11229 info.item_compare_float = FALSE;
11230#endif
11231 info.item_compare_func = NULL;
11232 info.item_compare_partial = NULL;
11233 info.item_compare_selfdict = NULL;
11234 if (argvars[1].v_type != VAR_UNKNOWN)
11235 {
11236 /* optional second argument: {func} */
11237 if (argvars[1].v_type == VAR_FUNC)
11238 info.item_compare_func = argvars[1].vval.v_string;
11239 else if (argvars[1].v_type == VAR_PARTIAL)
11240 info.item_compare_partial = argvars[1].vval.v_partial;
11241 else
11242 {
11243 int error = FALSE;
11244
11245 i = (long)get_tv_number_chk(&argvars[1], &error);
11246 if (error)
11247 goto theend; /* type error; errmsg already given */
11248 if (i == 1)
11249 info.item_compare_ic = TRUE;
11250 else if (argvars[1].v_type != VAR_NUMBER)
11251 info.item_compare_func = get_tv_string(&argvars[1]);
11252 else if (i != 0)
11253 {
11254 EMSG(_(e_invarg));
11255 goto theend;
11256 }
11257 if (info.item_compare_func != NULL)
11258 {
11259 if (*info.item_compare_func == NUL)
11260 {
11261 /* empty string means default sort */
11262 info.item_compare_func = NULL;
11263 }
11264 else if (STRCMP(info.item_compare_func, "n") == 0)
11265 {
11266 info.item_compare_func = NULL;
11267 info.item_compare_numeric = TRUE;
11268 }
11269 else if (STRCMP(info.item_compare_func, "N") == 0)
11270 {
11271 info.item_compare_func = NULL;
11272 info.item_compare_numbers = TRUE;
11273 }
11274#ifdef FEAT_FLOAT
11275 else if (STRCMP(info.item_compare_func, "f") == 0)
11276 {
11277 info.item_compare_func = NULL;
11278 info.item_compare_float = TRUE;
11279 }
11280#endif
11281 else if (STRCMP(info.item_compare_func, "i") == 0)
11282 {
11283 info.item_compare_func = NULL;
11284 info.item_compare_ic = TRUE;
11285 }
11286 }
11287 }
11288
11289 if (argvars[2].v_type != VAR_UNKNOWN)
11290 {
11291 /* optional third argument: {dict} */
11292 if (argvars[2].v_type != VAR_DICT)
11293 {
11294 EMSG(_(e_dictreq));
11295 goto theend;
11296 }
11297 info.item_compare_selfdict = argvars[2].vval.v_dict;
11298 }
11299 }
11300
11301 /* Make an array with each entry pointing to an item in the List. */
11302 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11303 if (ptrs == NULL)
11304 goto theend;
11305
11306 i = 0;
11307 if (sort)
11308 {
11309 /* sort(): ptrs will be the list to sort */
11310 for (li = l->lv_first; li != NULL; li = li->li_next)
11311 {
11312 ptrs[i].item = li;
11313 ptrs[i].idx = i;
11314 ++i;
11315 }
11316
11317 info.item_compare_func_err = FALSE;
11318 info.item_compare_keep_zero = FALSE;
11319 /* test the compare function */
11320 if ((info.item_compare_func != NULL
11321 || info.item_compare_partial != NULL)
11322 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11323 == ITEM_COMPARE_FAIL)
11324 EMSG(_("E702: Sort compare function failed"));
11325 else
11326 {
11327 /* Sort the array with item pointers. */
11328 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11329 info.item_compare_func == NULL
11330 && info.item_compare_partial == NULL
11331 ? item_compare : item_compare2);
11332
11333 if (!info.item_compare_func_err)
11334 {
11335 /* Clear the List and append the items in sorted order. */
11336 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11337 l->lv_len = 0;
11338 for (i = 0; i < len; ++i)
11339 list_append(l, ptrs[i].item);
11340 }
11341 }
11342 }
11343 else
11344 {
11345 int (*item_compare_func_ptr)(const void *, const void *);
11346
11347 /* f_uniq(): ptrs will be a stack of items to remove */
11348 info.item_compare_func_err = FALSE;
11349 info.item_compare_keep_zero = TRUE;
11350 item_compare_func_ptr = info.item_compare_func != NULL
11351 || info.item_compare_partial != NULL
11352 ? item_compare2 : item_compare;
11353
11354 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11355 li = li->li_next)
11356 {
11357 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11358 == 0)
11359 ptrs[i++].item = li;
11360 if (info.item_compare_func_err)
11361 {
11362 EMSG(_("E882: Uniq compare function failed"));
11363 break;
11364 }
11365 }
11366
11367 if (!info.item_compare_func_err)
11368 {
11369 while (--i >= 0)
11370 {
11371 li = ptrs[i].item->li_next;
11372 ptrs[i].item->li_next = li->li_next;
11373 if (li->li_next != NULL)
11374 li->li_next->li_prev = ptrs[i].item;
11375 else
11376 l->lv_last = ptrs[i].item;
11377 list_fix_watch(l, li);
11378 listitem_free(li);
11379 l->lv_len--;
11380 }
11381 }
11382 }
11383
11384 vim_free(ptrs);
11385 }
11386theend:
11387 sortinfo = old_sortinfo;
11388}
11389
11390/*
11391 * "sort({list})" function
11392 */
11393 static void
11394f_sort(typval_T *argvars, typval_T *rettv)
11395{
11396 do_sort_uniq(argvars, rettv, TRUE);
11397}
11398
11399/*
11400 * "uniq({list})" function
11401 */
11402 static void
11403f_uniq(typval_T *argvars, typval_T *rettv)
11404{
11405 do_sort_uniq(argvars, rettv, FALSE);
11406}
11407
11408/*
11409 * "soundfold({word})" function
11410 */
11411 static void
11412f_soundfold(typval_T *argvars, typval_T *rettv)
11413{
11414 char_u *s;
11415
11416 rettv->v_type = VAR_STRING;
11417 s = get_tv_string(&argvars[0]);
11418#ifdef FEAT_SPELL
11419 rettv->vval.v_string = eval_soundfold(s);
11420#else
11421 rettv->vval.v_string = vim_strsave(s);
11422#endif
11423}
11424
11425/*
11426 * "spellbadword()" function
11427 */
11428 static void
11429f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11430{
11431 char_u *word = (char_u *)"";
11432 hlf_T attr = HLF_COUNT;
11433 int len = 0;
11434
11435 if (rettv_list_alloc(rettv) == FAIL)
11436 return;
11437
11438#ifdef FEAT_SPELL
11439 if (argvars[0].v_type == VAR_UNKNOWN)
11440 {
11441 /* Find the start and length of the badly spelled word. */
11442 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11443 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011444 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011445 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011446 curwin->w_set_curswant = TRUE;
11447 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011448 }
11449 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11450 {
11451 char_u *str = get_tv_string_chk(&argvars[0]);
11452 int capcol = -1;
11453
11454 if (str != NULL)
11455 {
11456 /* Check the argument for spelling. */
11457 while (*str != NUL)
11458 {
11459 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11460 if (attr != HLF_COUNT)
11461 {
11462 word = str;
11463 break;
11464 }
11465 str += len;
11466 }
11467 }
11468 }
11469#endif
11470
11471 list_append_string(rettv->vval.v_list, word, len);
11472 list_append_string(rettv->vval.v_list, (char_u *)(
11473 attr == HLF_SPB ? "bad" :
11474 attr == HLF_SPR ? "rare" :
11475 attr == HLF_SPL ? "local" :
11476 attr == HLF_SPC ? "caps" :
11477 ""), -1);
11478}
11479
11480/*
11481 * "spellsuggest()" function
11482 */
11483 static void
11484f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11485{
11486#ifdef FEAT_SPELL
11487 char_u *str;
11488 int typeerr = FALSE;
11489 int maxcount;
11490 garray_T ga;
11491 int i;
11492 listitem_T *li;
11493 int need_capital = FALSE;
11494#endif
11495
11496 if (rettv_list_alloc(rettv) == FAIL)
11497 return;
11498
11499#ifdef FEAT_SPELL
11500 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11501 {
11502 str = get_tv_string(&argvars[0]);
11503 if (argvars[1].v_type != VAR_UNKNOWN)
11504 {
11505 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11506 if (maxcount <= 0)
11507 return;
11508 if (argvars[2].v_type != VAR_UNKNOWN)
11509 {
11510 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11511 if (typeerr)
11512 return;
11513 }
11514 }
11515 else
11516 maxcount = 25;
11517
11518 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11519
11520 for (i = 0; i < ga.ga_len; ++i)
11521 {
11522 str = ((char_u **)ga.ga_data)[i];
11523
11524 li = listitem_alloc();
11525 if (li == NULL)
11526 vim_free(str);
11527 else
11528 {
11529 li->li_tv.v_type = VAR_STRING;
11530 li->li_tv.v_lock = 0;
11531 li->li_tv.vval.v_string = str;
11532 list_append(rettv->vval.v_list, li);
11533 }
11534 }
11535 ga_clear(&ga);
11536 }
11537#endif
11538}
11539
11540 static void
11541f_split(typval_T *argvars, typval_T *rettv)
11542{
11543 char_u *str;
11544 char_u *end;
11545 char_u *pat = NULL;
11546 regmatch_T regmatch;
11547 char_u patbuf[NUMBUFLEN];
11548 char_u *save_cpo;
11549 int match;
11550 colnr_T col = 0;
11551 int keepempty = FALSE;
11552 int typeerr = FALSE;
11553
11554 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11555 save_cpo = p_cpo;
11556 p_cpo = (char_u *)"";
11557
11558 str = get_tv_string(&argvars[0]);
11559 if (argvars[1].v_type != VAR_UNKNOWN)
11560 {
11561 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11562 if (pat == NULL)
11563 typeerr = TRUE;
11564 if (argvars[2].v_type != VAR_UNKNOWN)
11565 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11566 }
11567 if (pat == NULL || *pat == NUL)
11568 pat = (char_u *)"[\\x01- ]\\+";
11569
11570 if (rettv_list_alloc(rettv) == FAIL)
11571 return;
11572 if (typeerr)
11573 return;
11574
11575 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11576 if (regmatch.regprog != NULL)
11577 {
11578 regmatch.rm_ic = FALSE;
11579 while (*str != NUL || keepempty)
11580 {
11581 if (*str == NUL)
11582 match = FALSE; /* empty item at the end */
11583 else
11584 match = vim_regexec_nl(&regmatch, str, col);
11585 if (match)
11586 end = regmatch.startp[0];
11587 else
11588 end = str + STRLEN(str);
11589 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11590 && *str != NUL && match && end < regmatch.endp[0]))
11591 {
11592 if (list_append_string(rettv->vval.v_list, str,
11593 (int)(end - str)) == FAIL)
11594 break;
11595 }
11596 if (!match)
11597 break;
11598 /* Advance to just after the match. */
11599 if (regmatch.endp[0] > str)
11600 col = 0;
11601 else
11602 {
11603 /* Don't get stuck at the same match. */
11604#ifdef FEAT_MBYTE
11605 col = (*mb_ptr2len)(regmatch.endp[0]);
11606#else
11607 col = 1;
11608#endif
11609 }
11610 str = regmatch.endp[0];
11611 }
11612
11613 vim_regfree(regmatch.regprog);
11614 }
11615
11616 p_cpo = save_cpo;
11617}
11618
11619#ifdef FEAT_FLOAT
11620/*
11621 * "sqrt()" function
11622 */
11623 static void
11624f_sqrt(typval_T *argvars, typval_T *rettv)
11625{
11626 float_T f = 0.0;
11627
11628 rettv->v_type = VAR_FLOAT;
11629 if (get_float_arg(argvars, &f) == OK)
11630 rettv->vval.v_float = sqrt(f);
11631 else
11632 rettv->vval.v_float = 0.0;
11633}
11634
11635/*
11636 * "str2float()" function
11637 */
11638 static void
11639f_str2float(typval_T *argvars, typval_T *rettv)
11640{
11641 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011642 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011643
Bram Moolenaar08243d22017-01-10 16:12:29 +010011644 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011645 p = skipwhite(p + 1);
11646 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011647 if (isneg)
11648 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011649 rettv->v_type = VAR_FLOAT;
11650}
11651#endif
11652
11653/*
11654 * "str2nr()" function
11655 */
11656 static void
11657f_str2nr(typval_T *argvars, typval_T *rettv)
11658{
11659 int base = 10;
11660 char_u *p;
11661 varnumber_T n;
11662 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011663 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011664
11665 if (argvars[1].v_type != VAR_UNKNOWN)
11666 {
11667 base = (int)get_tv_number(&argvars[1]);
11668 if (base != 2 && base != 8 && base != 10 && base != 16)
11669 {
11670 EMSG(_(e_invarg));
11671 return;
11672 }
11673 }
11674
11675 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011676 isneg = (*p == '-');
11677 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011678 p = skipwhite(p + 1);
11679 switch (base)
11680 {
11681 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11682 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11683 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11684 default: what = 0;
11685 }
11686 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011687 if (isneg)
11688 rettv->vval.v_number = -n;
11689 else
11690 rettv->vval.v_number = n;
11691
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011692}
11693
11694#ifdef HAVE_STRFTIME
11695/*
11696 * "strftime({format}[, {time}])" function
11697 */
11698 static void
11699f_strftime(typval_T *argvars, typval_T *rettv)
11700{
11701 char_u result_buf[256];
11702 struct tm *curtime;
11703 time_t seconds;
11704 char_u *p;
11705
11706 rettv->v_type = VAR_STRING;
11707
11708 p = get_tv_string(&argvars[0]);
11709 if (argvars[1].v_type == VAR_UNKNOWN)
11710 seconds = time(NULL);
11711 else
11712 seconds = (time_t)get_tv_number(&argvars[1]);
11713 curtime = localtime(&seconds);
11714 /* MSVC returns NULL for an invalid value of seconds. */
11715 if (curtime == NULL)
11716 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11717 else
11718 {
11719# ifdef FEAT_MBYTE
11720 vimconv_T conv;
11721 char_u *enc;
11722
11723 conv.vc_type = CONV_NONE;
11724 enc = enc_locale();
11725 convert_setup(&conv, p_enc, enc);
11726 if (conv.vc_type != CONV_NONE)
11727 p = string_convert(&conv, p, NULL);
11728# endif
11729 if (p != NULL)
11730 (void)strftime((char *)result_buf, sizeof(result_buf),
11731 (char *)p, curtime);
11732 else
11733 result_buf[0] = NUL;
11734
11735# ifdef FEAT_MBYTE
11736 if (conv.vc_type != CONV_NONE)
11737 vim_free(p);
11738 convert_setup(&conv, enc, p_enc);
11739 if (conv.vc_type != CONV_NONE)
11740 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11741 else
11742# endif
11743 rettv->vval.v_string = vim_strsave(result_buf);
11744
11745# ifdef FEAT_MBYTE
11746 /* Release conversion descriptors */
11747 convert_setup(&conv, NULL, NULL);
11748 vim_free(enc);
11749# endif
11750 }
11751}
11752#endif
11753
11754/*
11755 * "strgetchar()" function
11756 */
11757 static void
11758f_strgetchar(typval_T *argvars, typval_T *rettv)
11759{
11760 char_u *str;
11761 int len;
11762 int error = FALSE;
11763 int charidx;
11764
11765 rettv->vval.v_number = -1;
11766 str = get_tv_string_chk(&argvars[0]);
11767 if (str == NULL)
11768 return;
11769 len = (int)STRLEN(str);
11770 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11771 if (error)
11772 return;
11773#ifdef FEAT_MBYTE
11774 {
11775 int byteidx = 0;
11776
11777 while (charidx >= 0 && byteidx < len)
11778 {
11779 if (charidx == 0)
11780 {
11781 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11782 break;
11783 }
11784 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011785 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011786 }
11787 }
11788#else
11789 if (charidx < len)
11790 rettv->vval.v_number = str[charidx];
11791#endif
11792}
11793
11794/*
11795 * "stridx()" function
11796 */
11797 static void
11798f_stridx(typval_T *argvars, typval_T *rettv)
11799{
11800 char_u buf[NUMBUFLEN];
11801 char_u *needle;
11802 char_u *haystack;
11803 char_u *save_haystack;
11804 char_u *pos;
11805 int start_idx;
11806
11807 needle = get_tv_string_chk(&argvars[1]);
11808 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11809 rettv->vval.v_number = -1;
11810 if (needle == NULL || haystack == NULL)
11811 return; /* type error; errmsg already given */
11812
11813 if (argvars[2].v_type != VAR_UNKNOWN)
11814 {
11815 int error = FALSE;
11816
11817 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11818 if (error || start_idx >= (int)STRLEN(haystack))
11819 return;
11820 if (start_idx >= 0)
11821 haystack += start_idx;
11822 }
11823
11824 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11825 if (pos != NULL)
11826 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11827}
11828
11829/*
11830 * "string()" function
11831 */
11832 static void
11833f_string(typval_T *argvars, typval_T *rettv)
11834{
11835 char_u *tofree;
11836 char_u numbuf[NUMBUFLEN];
11837
11838 rettv->v_type = VAR_STRING;
11839 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11840 get_copyID());
11841 /* Make a copy if we have a value but it's not in allocated memory. */
11842 if (rettv->vval.v_string != NULL && tofree == NULL)
11843 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11844}
11845
11846/*
11847 * "strlen()" function
11848 */
11849 static void
11850f_strlen(typval_T *argvars, typval_T *rettv)
11851{
11852 rettv->vval.v_number = (varnumber_T)(STRLEN(
11853 get_tv_string(&argvars[0])));
11854}
11855
11856/*
11857 * "strchars()" function
11858 */
11859 static void
11860f_strchars(typval_T *argvars, typval_T *rettv)
11861{
11862 char_u *s = get_tv_string(&argvars[0]);
11863 int skipcc = 0;
11864#ifdef FEAT_MBYTE
11865 varnumber_T len = 0;
11866 int (*func_mb_ptr2char_adv)(char_u **pp);
11867#endif
11868
11869 if (argvars[1].v_type != VAR_UNKNOWN)
11870 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11871 if (skipcc < 0 || skipcc > 1)
11872 EMSG(_(e_invarg));
11873 else
11874 {
11875#ifdef FEAT_MBYTE
11876 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11877 while (*s != NUL)
11878 {
11879 func_mb_ptr2char_adv(&s);
11880 ++len;
11881 }
11882 rettv->vval.v_number = len;
11883#else
11884 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11885#endif
11886 }
11887}
11888
11889/*
11890 * "strdisplaywidth()" function
11891 */
11892 static void
11893f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11894{
11895 char_u *s = get_tv_string(&argvars[0]);
11896 int col = 0;
11897
11898 if (argvars[1].v_type != VAR_UNKNOWN)
11899 col = (int)get_tv_number(&argvars[1]);
11900
11901 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11902}
11903
11904/*
11905 * "strwidth()" function
11906 */
11907 static void
11908f_strwidth(typval_T *argvars, typval_T *rettv)
11909{
11910 char_u *s = get_tv_string(&argvars[0]);
11911
11912 rettv->vval.v_number = (varnumber_T)(
11913#ifdef FEAT_MBYTE
11914 mb_string2cells(s, -1)
11915#else
11916 STRLEN(s)
11917#endif
11918 );
11919}
11920
11921/*
11922 * "strcharpart()" function
11923 */
11924 static void
11925f_strcharpart(typval_T *argvars, typval_T *rettv)
11926{
11927#ifdef FEAT_MBYTE
11928 char_u *p;
11929 int nchar;
11930 int nbyte = 0;
11931 int charlen;
11932 int len = 0;
11933 int slen;
11934 int error = FALSE;
11935
11936 p = get_tv_string(&argvars[0]);
11937 slen = (int)STRLEN(p);
11938
11939 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11940 if (!error)
11941 {
11942 if (nchar > 0)
11943 while (nchar > 0 && nbyte < slen)
11944 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011945 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011946 --nchar;
11947 }
11948 else
11949 nbyte = nchar;
11950 if (argvars[2].v_type != VAR_UNKNOWN)
11951 {
11952 charlen = (int)get_tv_number(&argvars[2]);
11953 while (charlen > 0 && nbyte + len < slen)
11954 {
11955 int off = nbyte + len;
11956
11957 if (off < 0)
11958 len += 1;
11959 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011960 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011961 --charlen;
11962 }
11963 }
11964 else
11965 len = slen - nbyte; /* default: all bytes that are available. */
11966 }
11967
11968 /*
11969 * Only return the overlap between the specified part and the actual
11970 * string.
11971 */
11972 if (nbyte < 0)
11973 {
11974 len += nbyte;
11975 nbyte = 0;
11976 }
11977 else if (nbyte > slen)
11978 nbyte = slen;
11979 if (len < 0)
11980 len = 0;
11981 else if (nbyte + len > slen)
11982 len = slen - nbyte;
11983
11984 rettv->v_type = VAR_STRING;
11985 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11986#else
11987 f_strpart(argvars, rettv);
11988#endif
11989}
11990
11991/*
11992 * "strpart()" function
11993 */
11994 static void
11995f_strpart(typval_T *argvars, typval_T *rettv)
11996{
11997 char_u *p;
11998 int n;
11999 int len;
12000 int slen;
12001 int error = FALSE;
12002
12003 p = get_tv_string(&argvars[0]);
12004 slen = (int)STRLEN(p);
12005
12006 n = (int)get_tv_number_chk(&argvars[1], &error);
12007 if (error)
12008 len = 0;
12009 else if (argvars[2].v_type != VAR_UNKNOWN)
12010 len = (int)get_tv_number(&argvars[2]);
12011 else
12012 len = slen - n; /* default len: all bytes that are available. */
12013
12014 /*
12015 * Only return the overlap between the specified part and the actual
12016 * string.
12017 */
12018 if (n < 0)
12019 {
12020 len += n;
12021 n = 0;
12022 }
12023 else if (n > slen)
12024 n = slen;
12025 if (len < 0)
12026 len = 0;
12027 else if (n + len > slen)
12028 len = slen - n;
12029
12030 rettv->v_type = VAR_STRING;
12031 rettv->vval.v_string = vim_strnsave(p + n, len);
12032}
12033
12034/*
12035 * "strridx()" function
12036 */
12037 static void
12038f_strridx(typval_T *argvars, typval_T *rettv)
12039{
12040 char_u buf[NUMBUFLEN];
12041 char_u *needle;
12042 char_u *haystack;
12043 char_u *rest;
12044 char_u *lastmatch = NULL;
12045 int haystack_len, end_idx;
12046
12047 needle = get_tv_string_chk(&argvars[1]);
12048 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12049
12050 rettv->vval.v_number = -1;
12051 if (needle == NULL || haystack == NULL)
12052 return; /* type error; errmsg already given */
12053
12054 haystack_len = (int)STRLEN(haystack);
12055 if (argvars[2].v_type != VAR_UNKNOWN)
12056 {
12057 /* Third argument: upper limit for index */
12058 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12059 if (end_idx < 0)
12060 return; /* can never find a match */
12061 }
12062 else
12063 end_idx = haystack_len;
12064
12065 if (*needle == NUL)
12066 {
12067 /* Empty string matches past the end. */
12068 lastmatch = haystack + end_idx;
12069 }
12070 else
12071 {
12072 for (rest = haystack; *rest != '\0'; ++rest)
12073 {
12074 rest = (char_u *)strstr((char *)rest, (char *)needle);
12075 if (rest == NULL || rest > haystack + end_idx)
12076 break;
12077 lastmatch = rest;
12078 }
12079 }
12080
12081 if (lastmatch == NULL)
12082 rettv->vval.v_number = -1;
12083 else
12084 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12085}
12086
12087/*
12088 * "strtrans()" function
12089 */
12090 static void
12091f_strtrans(typval_T *argvars, typval_T *rettv)
12092{
12093 rettv->v_type = VAR_STRING;
12094 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12095}
12096
12097/*
12098 * "submatch()" function
12099 */
12100 static void
12101f_submatch(typval_T *argvars, typval_T *rettv)
12102{
12103 int error = FALSE;
12104 int no;
12105 int retList = 0;
12106
12107 no = (int)get_tv_number_chk(&argvars[0], &error);
12108 if (error)
12109 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012110 if (no < 0 || no >= NSUBEXP)
12111 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012112 EMSGN(_("E935: invalid submatch number: %d"), no);
12113 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012114 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012115 if (argvars[1].v_type != VAR_UNKNOWN)
12116 retList = (int)get_tv_number_chk(&argvars[1], &error);
12117 if (error)
12118 return;
12119
12120 if (retList == 0)
12121 {
12122 rettv->v_type = VAR_STRING;
12123 rettv->vval.v_string = reg_submatch(no);
12124 }
12125 else
12126 {
12127 rettv->v_type = VAR_LIST;
12128 rettv->vval.v_list = reg_submatch_list(no);
12129 }
12130}
12131
12132/*
12133 * "substitute()" function
12134 */
12135 static void
12136f_substitute(typval_T *argvars, typval_T *rettv)
12137{
12138 char_u patbuf[NUMBUFLEN];
12139 char_u subbuf[NUMBUFLEN];
12140 char_u flagsbuf[NUMBUFLEN];
12141
12142 char_u *str = get_tv_string_chk(&argvars[0]);
12143 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012144 char_u *sub = NULL;
12145 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012146 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12147
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012148 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12149 expr = &argvars[2];
12150 else
12151 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12152
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012153 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012154 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12155 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012156 rettv->vval.v_string = NULL;
12157 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012158 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012159}
12160
12161/*
12162 * "synID(lnum, col, trans)" function
12163 */
12164 static void
12165f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12166{
12167 int id = 0;
12168#ifdef FEAT_SYN_HL
12169 linenr_T lnum;
12170 colnr_T col;
12171 int trans;
12172 int transerr = FALSE;
12173
12174 lnum = get_tv_lnum(argvars); /* -1 on type error */
12175 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12176 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12177
12178 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12179 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12180 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12181#endif
12182
12183 rettv->vval.v_number = id;
12184}
12185
12186/*
12187 * "synIDattr(id, what [, mode])" function
12188 */
12189 static void
12190f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12191{
12192 char_u *p = NULL;
12193#ifdef FEAT_SYN_HL
12194 int id;
12195 char_u *what;
12196 char_u *mode;
12197 char_u modebuf[NUMBUFLEN];
12198 int modec;
12199
12200 id = (int)get_tv_number(&argvars[0]);
12201 what = get_tv_string(&argvars[1]);
12202 if (argvars[2].v_type != VAR_UNKNOWN)
12203 {
12204 mode = get_tv_string_buf(&argvars[2], modebuf);
12205 modec = TOLOWER_ASC(mode[0]);
12206 if (modec != 't' && modec != 'c' && modec != 'g')
12207 modec = 0; /* replace invalid with current */
12208 }
12209 else
12210 {
12211#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12212 if (USE_24BIT)
12213 modec = 'g';
12214 else
12215#endif
12216 if (t_colors > 1)
12217 modec = 'c';
12218 else
12219 modec = 't';
12220 }
12221
12222
12223 switch (TOLOWER_ASC(what[0]))
12224 {
12225 case 'b':
12226 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12227 p = highlight_color(id, what, modec);
12228 else /* bold */
12229 p = highlight_has_attr(id, HL_BOLD, modec);
12230 break;
12231
12232 case 'f': /* fg[#] or font */
12233 p = highlight_color(id, what, modec);
12234 break;
12235
12236 case 'i':
12237 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12238 p = highlight_has_attr(id, HL_INVERSE, modec);
12239 else /* italic */
12240 p = highlight_has_attr(id, HL_ITALIC, modec);
12241 break;
12242
12243 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012244 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012245 break;
12246
12247 case 'r': /* reverse */
12248 p = highlight_has_attr(id, HL_INVERSE, modec);
12249 break;
12250
12251 case 's':
12252 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12253 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012254 /* strikeout */
12255 else if (TOLOWER_ASC(what[1]) == 't' &&
12256 TOLOWER_ASC(what[2]) == 'r')
12257 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012258 else /* standout */
12259 p = highlight_has_attr(id, HL_STANDOUT, modec);
12260 break;
12261
12262 case 'u':
12263 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12264 /* underline */
12265 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12266 else
12267 /* undercurl */
12268 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12269 break;
12270 }
12271
12272 if (p != NULL)
12273 p = vim_strsave(p);
12274#endif
12275 rettv->v_type = VAR_STRING;
12276 rettv->vval.v_string = p;
12277}
12278
12279/*
12280 * "synIDtrans(id)" function
12281 */
12282 static void
12283f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12284{
12285 int id;
12286
12287#ifdef FEAT_SYN_HL
12288 id = (int)get_tv_number(&argvars[0]);
12289
12290 if (id > 0)
12291 id = syn_get_final_id(id);
12292 else
12293#endif
12294 id = 0;
12295
12296 rettv->vval.v_number = id;
12297}
12298
12299/*
12300 * "synconcealed(lnum, col)" function
12301 */
12302 static void
12303f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12304{
12305#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12306 linenr_T lnum;
12307 colnr_T col;
12308 int syntax_flags = 0;
12309 int cchar;
12310 int matchid = 0;
12311 char_u str[NUMBUFLEN];
12312#endif
12313
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012314 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012315
12316#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12317 lnum = get_tv_lnum(argvars); /* -1 on type error */
12318 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12319
12320 vim_memset(str, NUL, sizeof(str));
12321
12322 if (rettv_list_alloc(rettv) != FAIL)
12323 {
12324 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12325 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12326 && curwin->w_p_cole > 0)
12327 {
12328 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12329 syntax_flags = get_syntax_info(&matchid);
12330
12331 /* get the conceal character */
12332 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12333 {
12334 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012335 if (cchar == NUL && curwin->w_p_cole == 1)
12336 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012337 if (cchar != NUL)
12338 {
12339# ifdef FEAT_MBYTE
12340 if (has_mbyte)
12341 (*mb_char2bytes)(cchar, str);
12342 else
12343# endif
12344 str[0] = cchar;
12345 }
12346 }
12347 }
12348
12349 list_append_number(rettv->vval.v_list,
12350 (syntax_flags & HL_CONCEAL) != 0);
12351 /* -1 to auto-determine strlen */
12352 list_append_string(rettv->vval.v_list, str, -1);
12353 list_append_number(rettv->vval.v_list, matchid);
12354 }
12355#endif
12356}
12357
12358/*
12359 * "synstack(lnum, col)" function
12360 */
12361 static void
12362f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12363{
12364#ifdef FEAT_SYN_HL
12365 linenr_T lnum;
12366 colnr_T col;
12367 int i;
12368 int id;
12369#endif
12370
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012371 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012372
12373#ifdef FEAT_SYN_HL
12374 lnum = get_tv_lnum(argvars); /* -1 on type error */
12375 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12376
12377 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12378 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12379 && rettv_list_alloc(rettv) != FAIL)
12380 {
12381 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12382 for (i = 0; ; ++i)
12383 {
12384 id = syn_get_stack_item(i);
12385 if (id < 0)
12386 break;
12387 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12388 break;
12389 }
12390 }
12391#endif
12392}
12393
12394 static void
12395get_cmd_output_as_rettv(
12396 typval_T *argvars,
12397 typval_T *rettv,
12398 int retlist)
12399{
12400 char_u *res = NULL;
12401 char_u *p;
12402 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012403 int err = FALSE;
12404 FILE *fd;
12405 list_T *list = NULL;
12406 int flags = SHELL_SILENT;
12407
12408 rettv->v_type = VAR_STRING;
12409 rettv->vval.v_string = NULL;
12410 if (check_restricted() || check_secure())
12411 goto errret;
12412
12413 if (argvars[1].v_type != VAR_UNKNOWN)
12414 {
12415 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012416 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012417 * command.
12418 */
12419 if ((infile = vim_tempname('i', TRUE)) == NULL)
12420 {
12421 EMSG(_(e_notmp));
12422 goto errret;
12423 }
12424
12425 fd = mch_fopen((char *)infile, WRITEBIN);
12426 if (fd == NULL)
12427 {
12428 EMSG2(_(e_notopen), infile);
12429 goto errret;
12430 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012431 if (argvars[1].v_type == VAR_NUMBER)
12432 {
12433 linenr_T lnum;
12434 buf_T *buf;
12435
12436 buf = buflist_findnr(argvars[1].vval.v_number);
12437 if (buf == NULL)
12438 {
12439 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012440 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012441 goto errret;
12442 }
12443
12444 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12445 {
12446 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12447 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12448 {
12449 err = TRUE;
12450 break;
12451 }
12452 if (putc(NL, fd) == EOF)
12453 {
12454 err = TRUE;
12455 break;
12456 }
12457 }
12458 }
12459 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012460 {
12461 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12462 err = TRUE;
12463 }
12464 else
12465 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012466 size_t len;
12467 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012468
12469 p = get_tv_string_buf_chk(&argvars[1], buf);
12470 if (p == NULL)
12471 {
12472 fclose(fd);
12473 goto errret; /* type error; errmsg already given */
12474 }
12475 len = STRLEN(p);
12476 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12477 err = TRUE;
12478 }
12479 if (fclose(fd) != 0)
12480 err = TRUE;
12481 if (err)
12482 {
12483 EMSG(_("E677: Error writing temp file"));
12484 goto errret;
12485 }
12486 }
12487
12488 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12489 * echoes typeahead, that messes up the display. */
12490 if (!msg_silent)
12491 flags += SHELL_COOKED;
12492
12493 if (retlist)
12494 {
12495 int len;
12496 listitem_T *li;
12497 char_u *s = NULL;
12498 char_u *start;
12499 char_u *end;
12500 int i;
12501
12502 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12503 if (res == NULL)
12504 goto errret;
12505
12506 list = list_alloc();
12507 if (list == NULL)
12508 goto errret;
12509
12510 for (i = 0; i < len; ++i)
12511 {
12512 start = res + i;
12513 while (i < len && res[i] != NL)
12514 ++i;
12515 end = res + i;
12516
12517 s = alloc((unsigned)(end - start + 1));
12518 if (s == NULL)
12519 goto errret;
12520
12521 for (p = s; start < end; ++p, ++start)
12522 *p = *start == NUL ? NL : *start;
12523 *p = NUL;
12524
12525 li = listitem_alloc();
12526 if (li == NULL)
12527 {
12528 vim_free(s);
12529 goto errret;
12530 }
12531 li->li_tv.v_type = VAR_STRING;
12532 li->li_tv.v_lock = 0;
12533 li->li_tv.vval.v_string = s;
12534 list_append(list, li);
12535 }
12536
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012537 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012538 list = NULL;
12539 }
12540 else
12541 {
12542 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12543#ifdef USE_CR
12544 /* translate <CR> into <NL> */
12545 if (res != NULL)
12546 {
12547 char_u *s;
12548
12549 for (s = res; *s; ++s)
12550 {
12551 if (*s == CAR)
12552 *s = NL;
12553 }
12554 }
12555#else
12556# ifdef USE_CRNL
12557 /* translate <CR><NL> into <NL> */
12558 if (res != NULL)
12559 {
12560 char_u *s, *d;
12561
12562 d = res;
12563 for (s = res; *s; ++s)
12564 {
12565 if (s[0] == CAR && s[1] == NL)
12566 ++s;
12567 *d++ = *s;
12568 }
12569 *d = NUL;
12570 }
12571# endif
12572#endif
12573 rettv->vval.v_string = res;
12574 res = NULL;
12575 }
12576
12577errret:
12578 if (infile != NULL)
12579 {
12580 mch_remove(infile);
12581 vim_free(infile);
12582 }
12583 if (res != NULL)
12584 vim_free(res);
12585 if (list != NULL)
12586 list_free(list);
12587}
12588
12589/*
12590 * "system()" function
12591 */
12592 static void
12593f_system(typval_T *argvars, typval_T *rettv)
12594{
12595 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12596}
12597
12598/*
12599 * "systemlist()" function
12600 */
12601 static void
12602f_systemlist(typval_T *argvars, typval_T *rettv)
12603{
12604 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12605}
12606
12607/*
12608 * "tabpagebuflist()" function
12609 */
12610 static void
12611f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12612{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012613 tabpage_T *tp;
12614 win_T *wp = NULL;
12615
12616 if (argvars[0].v_type == VAR_UNKNOWN)
12617 wp = firstwin;
12618 else
12619 {
12620 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12621 if (tp != NULL)
12622 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12623 }
12624 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12625 {
12626 for (; wp != NULL; wp = wp->w_next)
12627 if (list_append_number(rettv->vval.v_list,
12628 wp->w_buffer->b_fnum) == FAIL)
12629 break;
12630 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012631}
12632
12633
12634/*
12635 * "tabpagenr()" function
12636 */
12637 static void
12638f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12639{
12640 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012641 char_u *arg;
12642
12643 if (argvars[0].v_type != VAR_UNKNOWN)
12644 {
12645 arg = get_tv_string_chk(&argvars[0]);
12646 nr = 0;
12647 if (arg != NULL)
12648 {
12649 if (STRCMP(arg, "$") == 0)
12650 nr = tabpage_index(NULL) - 1;
12651 else
12652 EMSG2(_(e_invexpr2), arg);
12653 }
12654 }
12655 else
12656 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012657 rettv->vval.v_number = nr;
12658}
12659
12660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012661static int get_winnr(tabpage_T *tp, typval_T *argvar);
12662
12663/*
12664 * Common code for tabpagewinnr() and winnr().
12665 */
12666 static int
12667get_winnr(tabpage_T *tp, typval_T *argvar)
12668{
12669 win_T *twin;
12670 int nr = 1;
12671 win_T *wp;
12672 char_u *arg;
12673
12674 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12675 if (argvar->v_type != VAR_UNKNOWN)
12676 {
12677 arg = get_tv_string_chk(argvar);
12678 if (arg == NULL)
12679 nr = 0; /* type error; errmsg already given */
12680 else if (STRCMP(arg, "$") == 0)
12681 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12682 else if (STRCMP(arg, "#") == 0)
12683 {
12684 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12685 if (twin == NULL)
12686 nr = 0;
12687 }
12688 else
12689 {
12690 EMSG2(_(e_invexpr2), arg);
12691 nr = 0;
12692 }
12693 }
12694
12695 if (nr > 0)
12696 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12697 wp != twin; wp = wp->w_next)
12698 {
12699 if (wp == NULL)
12700 {
12701 /* didn't find it in this tabpage */
12702 nr = 0;
12703 break;
12704 }
12705 ++nr;
12706 }
12707 return nr;
12708}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012709
12710/*
12711 * "tabpagewinnr()" function
12712 */
12713 static void
12714f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12715{
12716 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012717 tabpage_T *tp;
12718
12719 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12720 if (tp == NULL)
12721 nr = 0;
12722 else
12723 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012724 rettv->vval.v_number = nr;
12725}
12726
12727
12728/*
12729 * "tagfiles()" function
12730 */
12731 static void
12732f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12733{
12734 char_u *fname;
12735 tagname_T tn;
12736 int first;
12737
12738 if (rettv_list_alloc(rettv) == FAIL)
12739 return;
12740 fname = alloc(MAXPATHL);
12741 if (fname == NULL)
12742 return;
12743
12744 for (first = TRUE; ; first = FALSE)
12745 if (get_tagfname(&tn, first, fname) == FAIL
12746 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12747 break;
12748 tagname_free(&tn);
12749 vim_free(fname);
12750}
12751
12752/*
12753 * "taglist()" function
12754 */
12755 static void
12756f_taglist(typval_T *argvars, typval_T *rettv)
12757{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012758 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012759 char_u *tag_pattern;
12760
12761 tag_pattern = get_tv_string(&argvars[0]);
12762
12763 rettv->vval.v_number = FALSE;
12764 if (*tag_pattern == NUL)
12765 return;
12766
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012767 if (argvars[1].v_type != VAR_UNKNOWN)
12768 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012769 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012770 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771}
12772
12773/*
12774 * "tempname()" function
12775 */
12776 static void
12777f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12778{
12779 static int x = 'A';
12780
12781 rettv->v_type = VAR_STRING;
12782 rettv->vval.v_string = vim_tempname(x, FALSE);
12783
12784 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12785 * names. Skip 'I' and 'O', they are used for shell redirection. */
12786 do
12787 {
12788 if (x == 'Z')
12789 x = '0';
12790 else if (x == '9')
12791 x = 'A';
12792 else
12793 {
12794#ifdef EBCDIC
12795 if (x == 'I')
12796 x = 'J';
12797 else if (x == 'R')
12798 x = 'S';
12799 else
12800#endif
12801 ++x;
12802 }
12803 } while (x == 'I' || x == 'O');
12804}
12805
12806#ifdef FEAT_FLOAT
12807/*
12808 * "tan()" function
12809 */
12810 static void
12811f_tan(typval_T *argvars, typval_T *rettv)
12812{
12813 float_T f = 0.0;
12814
12815 rettv->v_type = VAR_FLOAT;
12816 if (get_float_arg(argvars, &f) == OK)
12817 rettv->vval.v_float = tan(f);
12818 else
12819 rettv->vval.v_float = 0.0;
12820}
12821
12822/*
12823 * "tanh()" function
12824 */
12825 static void
12826f_tanh(typval_T *argvars, typval_T *rettv)
12827{
12828 float_T f = 0.0;
12829
12830 rettv->v_type = VAR_FLOAT;
12831 if (get_float_arg(argvars, &f) == OK)
12832 rettv->vval.v_float = tanh(f);
12833 else
12834 rettv->vval.v_float = 0.0;
12835}
12836#endif
12837
12838/*
12839 * "test_alloc_fail(id, countdown, repeat)" function
12840 */
12841 static void
12842f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12843{
12844 if (argvars[0].v_type != VAR_NUMBER
12845 || argvars[0].vval.v_number <= 0
12846 || argvars[1].v_type != VAR_NUMBER
12847 || argvars[1].vval.v_number < 0
12848 || argvars[2].v_type != VAR_NUMBER)
12849 EMSG(_(e_invarg));
12850 else
12851 {
12852 alloc_fail_id = argvars[0].vval.v_number;
12853 if (alloc_fail_id >= aid_last)
12854 EMSG(_(e_invarg));
12855 alloc_fail_countdown = argvars[1].vval.v_number;
12856 alloc_fail_repeat = argvars[2].vval.v_number;
12857 did_outofmem_msg = FALSE;
12858 }
12859}
12860
12861/*
12862 * "test_autochdir()"
12863 */
12864 static void
12865f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12866{
12867#if defined(FEAT_AUTOCHDIR)
12868 test_autochdir = TRUE;
12869#endif
12870}
12871
12872/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012873 * "test_feedinput()"
12874 */
12875 static void
12876f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12877{
12878#ifdef USE_INPUT_BUF
12879 char_u *val = get_tv_string_chk(&argvars[0]);
12880
12881 if (val != NULL)
12882 {
12883 trash_input_buf();
12884 add_to_input_buf_csi(val, (int)STRLEN(val));
12885 }
12886#endif
12887}
12888
12889/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012890 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012891 */
12892 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012893f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012894{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012895 char_u *name = (char_u *)"";
12896 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012897 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012898
12899 if (argvars[0].v_type != VAR_STRING
12900 || (argvars[1].v_type) != VAR_NUMBER)
12901 EMSG(_(e_invarg));
12902 else
12903 {
12904 name = get_tv_string_chk(&argvars[0]);
12905 val = (int)get_tv_number(&argvars[1]);
12906
12907 if (STRCMP(name, (char_u *)"redraw") == 0)
12908 disable_redraw_for_testing = val;
12909 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12910 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012911 else if (STRCMP(name, (char_u *)"starting") == 0)
12912 {
12913 if (val)
12914 {
12915 if (save_starting < 0)
12916 save_starting = starting;
12917 starting = 0;
12918 }
12919 else
12920 {
12921 starting = save_starting;
12922 save_starting = -1;
12923 }
12924 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012925 else if (STRCMP(name, (char_u *)"ALL") == 0)
12926 {
12927 disable_char_avail_for_testing = FALSE;
12928 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012929 if (save_starting >= 0)
12930 {
12931 starting = save_starting;
12932 save_starting = -1;
12933 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012934 }
12935 else
12936 EMSG2(_(e_invarg2), name);
12937 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012938}
12939
12940/*
12941 * "test_garbagecollect_now()" function
12942 */
12943 static void
12944f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12945{
12946 /* This is dangerous, any Lists and Dicts used internally may be freed
12947 * while still in use. */
12948 garbage_collect(TRUE);
12949}
12950
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012951/*
12952 * "test_ignore_error()" function
12953 */
12954 static void
12955f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12956{
12957 ignore_error_for_testing(get_tv_string(&argvars[0]));
12958}
12959
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012960#ifdef FEAT_JOB_CHANNEL
12961 static void
12962f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12963{
12964 rettv->v_type = VAR_CHANNEL;
12965 rettv->vval.v_channel = NULL;
12966}
12967#endif
12968
12969 static void
12970f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12971{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012972 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012973}
12974
12975#ifdef FEAT_JOB_CHANNEL
12976 static void
12977f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12978{
12979 rettv->v_type = VAR_JOB;
12980 rettv->vval.v_job = NULL;
12981}
12982#endif
12983
12984 static void
12985f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12986{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012987 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012988}
12989
12990 static void
12991f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12992{
12993 rettv->v_type = VAR_PARTIAL;
12994 rettv->vval.v_partial = NULL;
12995}
12996
12997 static void
12998f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12999{
13000 rettv->v_type = VAR_STRING;
13001 rettv->vval.v_string = NULL;
13002}
13003
13004 static void
13005f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13006{
13007 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13008}
13009
13010#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13011/*
13012 * Get a callback from "arg". It can be a Funcref or a function name.
13013 * When "arg" is zero return an empty string.
13014 * Return NULL for an invalid argument.
13015 */
13016 char_u *
13017get_callback(typval_T *arg, partial_T **pp)
13018{
13019 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13020 {
13021 *pp = arg->vval.v_partial;
13022 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013023 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013024 }
13025 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013026 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013027 {
13028 func_ref(arg->vval.v_string);
13029 return arg->vval.v_string;
13030 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013031 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13032 return (char_u *)"";
13033 EMSG(_("E921: Invalid callback argument"));
13034 return NULL;
13035}
13036
13037/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013038 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013039 */
13040 void
13041free_callback(char_u *callback, partial_T *partial)
13042{
13043 if (partial != NULL)
13044 partial_unref(partial);
13045 else if (callback != NULL)
13046 {
13047 func_unref(callback);
13048 vim_free(callback);
13049 }
13050}
13051#endif
13052
13053#ifdef FEAT_TIMERS
13054/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013055 * "timer_info([timer])" function
13056 */
13057 static void
13058f_timer_info(typval_T *argvars, typval_T *rettv)
13059{
13060 timer_T *timer = NULL;
13061
13062 if (rettv_list_alloc(rettv) != OK)
13063 return;
13064 if (argvars[0].v_type != VAR_UNKNOWN)
13065 {
13066 if (argvars[0].v_type != VAR_NUMBER)
13067 EMSG(_(e_number_exp));
13068 else
13069 {
13070 timer = find_timer((int)get_tv_number(&argvars[0]));
13071 if (timer != NULL)
13072 add_timer_info(rettv, timer);
13073 }
13074 }
13075 else
13076 add_timer_info_all(rettv);
13077}
13078
13079/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013080 * "timer_pause(timer, paused)" function
13081 */
13082 static void
13083f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13084{
13085 timer_T *timer = NULL;
13086 int paused = (int)get_tv_number(&argvars[1]);
13087
13088 if (argvars[0].v_type != VAR_NUMBER)
13089 EMSG(_(e_number_exp));
13090 else
13091 {
13092 timer = find_timer((int)get_tv_number(&argvars[0]));
13093 if (timer != NULL)
13094 timer->tr_paused = paused;
13095 }
13096}
13097
13098/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013099 * "timer_start(time, callback [, options])" function
13100 */
13101 static void
13102f_timer_start(typval_T *argvars, typval_T *rettv)
13103{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013104 long msec = (long)get_tv_number(&argvars[0]);
13105 timer_T *timer;
13106 int repeat = 0;
13107 char_u *callback;
13108 dict_T *dict;
13109 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013110
Bram Moolenaar75537a92016-09-05 22:45:28 +020013111 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013112 if (check_secure())
13113 return;
13114 if (argvars[2].v_type != VAR_UNKNOWN)
13115 {
13116 if (argvars[2].v_type != VAR_DICT
13117 || (dict = argvars[2].vval.v_dict) == NULL)
13118 {
13119 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13120 return;
13121 }
13122 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13123 repeat = get_dict_number(dict, (char_u *)"repeat");
13124 }
13125
Bram Moolenaar75537a92016-09-05 22:45:28 +020013126 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013127 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013128 return;
13129
13130 timer = create_timer(msec, repeat);
13131 if (timer == NULL)
13132 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013133 else
13134 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013135 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013136 timer->tr_callback = vim_strsave(callback);
13137 else
13138 /* pointer into the partial */
13139 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013140 timer->tr_partial = partial;
13141 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013142 }
13143}
13144
13145/*
13146 * "timer_stop(timer)" function
13147 */
13148 static void
13149f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13150{
13151 timer_T *timer;
13152
13153 if (argvars[0].v_type != VAR_NUMBER)
13154 {
13155 EMSG(_(e_number_exp));
13156 return;
13157 }
13158 timer = find_timer((int)get_tv_number(&argvars[0]));
13159 if (timer != NULL)
13160 stop_timer(timer);
13161}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013162
13163/*
13164 * "timer_stopall()" function
13165 */
13166 static void
13167f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13168{
13169 stop_all_timers();
13170}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013171#endif
13172
13173/*
13174 * "tolower(string)" function
13175 */
13176 static void
13177f_tolower(typval_T *argvars, typval_T *rettv)
13178{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013179 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013180 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013181}
13182
13183/*
13184 * "toupper(string)" function
13185 */
13186 static void
13187f_toupper(typval_T *argvars, typval_T *rettv)
13188{
13189 rettv->v_type = VAR_STRING;
13190 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13191}
13192
13193/*
13194 * "tr(string, fromstr, tostr)" function
13195 */
13196 static void
13197f_tr(typval_T *argvars, typval_T *rettv)
13198{
13199 char_u *in_str;
13200 char_u *fromstr;
13201 char_u *tostr;
13202 char_u *p;
13203#ifdef FEAT_MBYTE
13204 int inlen;
13205 int fromlen;
13206 int tolen;
13207 int idx;
13208 char_u *cpstr;
13209 int cplen;
13210 int first = TRUE;
13211#endif
13212 char_u buf[NUMBUFLEN];
13213 char_u buf2[NUMBUFLEN];
13214 garray_T ga;
13215
13216 in_str = get_tv_string(&argvars[0]);
13217 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13218 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13219
13220 /* Default return value: empty string. */
13221 rettv->v_type = VAR_STRING;
13222 rettv->vval.v_string = NULL;
13223 if (fromstr == NULL || tostr == NULL)
13224 return; /* type error; errmsg already given */
13225 ga_init2(&ga, (int)sizeof(char), 80);
13226
13227#ifdef FEAT_MBYTE
13228 if (!has_mbyte)
13229#endif
13230 /* not multi-byte: fromstr and tostr must be the same length */
13231 if (STRLEN(fromstr) != STRLEN(tostr))
13232 {
13233#ifdef FEAT_MBYTE
13234error:
13235#endif
13236 EMSG2(_(e_invarg2), fromstr);
13237 ga_clear(&ga);
13238 return;
13239 }
13240
13241 /* fromstr and tostr have to contain the same number of chars */
13242 while (*in_str != NUL)
13243 {
13244#ifdef FEAT_MBYTE
13245 if (has_mbyte)
13246 {
13247 inlen = (*mb_ptr2len)(in_str);
13248 cpstr = in_str;
13249 cplen = inlen;
13250 idx = 0;
13251 for (p = fromstr; *p != NUL; p += fromlen)
13252 {
13253 fromlen = (*mb_ptr2len)(p);
13254 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13255 {
13256 for (p = tostr; *p != NUL; p += tolen)
13257 {
13258 tolen = (*mb_ptr2len)(p);
13259 if (idx-- == 0)
13260 {
13261 cplen = tolen;
13262 cpstr = p;
13263 break;
13264 }
13265 }
13266 if (*p == NUL) /* tostr is shorter than fromstr */
13267 goto error;
13268 break;
13269 }
13270 ++idx;
13271 }
13272
13273 if (first && cpstr == in_str)
13274 {
13275 /* Check that fromstr and tostr have the same number of
13276 * (multi-byte) characters. Done only once when a character
13277 * of in_str doesn't appear in fromstr. */
13278 first = FALSE;
13279 for (p = tostr; *p != NUL; p += tolen)
13280 {
13281 tolen = (*mb_ptr2len)(p);
13282 --idx;
13283 }
13284 if (idx != 0)
13285 goto error;
13286 }
13287
13288 (void)ga_grow(&ga, cplen);
13289 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13290 ga.ga_len += cplen;
13291
13292 in_str += inlen;
13293 }
13294 else
13295#endif
13296 {
13297 /* When not using multi-byte chars we can do it faster. */
13298 p = vim_strchr(fromstr, *in_str);
13299 if (p != NULL)
13300 ga_append(&ga, tostr[p - fromstr]);
13301 else
13302 ga_append(&ga, *in_str);
13303 ++in_str;
13304 }
13305 }
13306
13307 /* add a terminating NUL */
13308 (void)ga_grow(&ga, 1);
13309 ga_append(&ga, NUL);
13310
13311 rettv->vval.v_string = ga.ga_data;
13312}
13313
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013314/*
13315 * "trim({expr})" function
13316 */
13317 static void
13318f_trim(typval_T *argvars, typval_T *rettv)
13319{
13320 char_u buf1[NUMBUFLEN];
13321 char_u buf2[NUMBUFLEN];
13322 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13323 char_u *mask = NULL;
13324 char_u *tail;
13325 char_u *prev;
13326 char_u *p;
13327 int c1;
13328
13329 rettv->v_type = VAR_STRING;
13330 if (head == NULL)
13331 {
13332 rettv->vval.v_string = NULL;
13333 return;
13334 }
13335
13336 if (argvars[1].v_type == VAR_STRING)
13337 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13338
13339 while (*head != NUL)
13340 {
13341 c1 = PTR2CHAR(head);
13342 if (mask == NULL)
13343 {
13344 if (c1 > ' ' && c1 != 0xa0)
13345 break;
13346 }
13347 else
13348 {
13349 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13350 if (c1 == PTR2CHAR(p))
13351 break;
13352 if (*p == NUL)
13353 break;
13354 }
13355 MB_PTR_ADV(head);
13356 }
13357
13358 for (tail = head + STRLEN(head); tail > head; tail = prev)
13359 {
13360 prev = tail;
13361 MB_PTR_BACK(head, prev);
13362 c1 = PTR2CHAR(prev);
13363 if (mask == NULL)
13364 {
13365 if (c1 > ' ' && c1 != 0xa0)
13366 break;
13367 }
13368 else
13369 {
13370 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13371 if (c1 == PTR2CHAR(p))
13372 break;
13373 if (*p == NUL)
13374 break;
13375 }
13376 }
13377 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13378}
13379
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013380#ifdef FEAT_FLOAT
13381/*
13382 * "trunc({float})" function
13383 */
13384 static void
13385f_trunc(typval_T *argvars, typval_T *rettv)
13386{
13387 float_T f = 0.0;
13388
13389 rettv->v_type = VAR_FLOAT;
13390 if (get_float_arg(argvars, &f) == OK)
13391 /* trunc() is not in C90, use floor() or ceil() instead. */
13392 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13393 else
13394 rettv->vval.v_float = 0.0;
13395}
13396#endif
13397
13398/*
13399 * "type(expr)" function
13400 */
13401 static void
13402f_type(typval_T *argvars, typval_T *rettv)
13403{
13404 int n = -1;
13405
13406 switch (argvars[0].v_type)
13407 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013408 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13409 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013410 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013411 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13412 case VAR_LIST: n = VAR_TYPE_LIST; break;
13413 case VAR_DICT: n = VAR_TYPE_DICT; break;
13414 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013415 case VAR_SPECIAL:
13416 if (argvars[0].vval.v_number == VVAL_FALSE
13417 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013418 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013419 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013420 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013421 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013422 case VAR_JOB: n = VAR_TYPE_JOB; break;
13423 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013424 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013425 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013426 n = -1;
13427 break;
13428 }
13429 rettv->vval.v_number = n;
13430}
13431
13432/*
13433 * "undofile(name)" function
13434 */
13435 static void
13436f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13437{
13438 rettv->v_type = VAR_STRING;
13439#ifdef FEAT_PERSISTENT_UNDO
13440 {
13441 char_u *fname = get_tv_string(&argvars[0]);
13442
13443 if (*fname == NUL)
13444 {
13445 /* If there is no file name there will be no undo file. */
13446 rettv->vval.v_string = NULL;
13447 }
13448 else
13449 {
13450 char_u *ffname = FullName_save(fname, FALSE);
13451
13452 if (ffname != NULL)
13453 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13454 vim_free(ffname);
13455 }
13456 }
13457#else
13458 rettv->vval.v_string = NULL;
13459#endif
13460}
13461
13462/*
13463 * "undotree()" function
13464 */
13465 static void
13466f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13467{
13468 if (rettv_dict_alloc(rettv) == OK)
13469 {
13470 dict_T *dict = rettv->vval.v_dict;
13471 list_T *list;
13472
13473 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13474 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13475 dict_add_nr_str(dict, "save_last",
13476 (long)curbuf->b_u_save_nr_last, NULL);
13477 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13478 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13479 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13480
13481 list = list_alloc();
13482 if (list != NULL)
13483 {
13484 u_eval_tree(curbuf->b_u_oldhead, list);
13485 dict_add_list(dict, "entries", list);
13486 }
13487 }
13488}
13489
13490/*
13491 * "values(dict)" function
13492 */
13493 static void
13494f_values(typval_T *argvars, typval_T *rettv)
13495{
13496 dict_list(argvars, rettv, 1);
13497}
13498
13499/*
13500 * "virtcol(string)" function
13501 */
13502 static void
13503f_virtcol(typval_T *argvars, typval_T *rettv)
13504{
13505 colnr_T vcol = 0;
13506 pos_T *fp;
13507 int fnum = curbuf->b_fnum;
13508
13509 fp = var2fpos(&argvars[0], FALSE, &fnum);
13510 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13511 && fnum == curbuf->b_fnum)
13512 {
13513 getvvcol(curwin, fp, NULL, NULL, &vcol);
13514 ++vcol;
13515 }
13516
13517 rettv->vval.v_number = vcol;
13518}
13519
13520/*
13521 * "visualmode()" function
13522 */
13523 static void
13524f_visualmode(typval_T *argvars, typval_T *rettv)
13525{
13526 char_u str[2];
13527
13528 rettv->v_type = VAR_STRING;
13529 str[0] = curbuf->b_visual_mode_eval;
13530 str[1] = NUL;
13531 rettv->vval.v_string = vim_strsave(str);
13532
13533 /* A non-zero number or non-empty string argument: reset mode. */
13534 if (non_zero_arg(&argvars[0]))
13535 curbuf->b_visual_mode_eval = NUL;
13536}
13537
13538/*
13539 * "wildmenumode()" function
13540 */
13541 static void
13542f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13543{
13544#ifdef FEAT_WILDMENU
13545 if (wild_menu_showing)
13546 rettv->vval.v_number = 1;
13547#endif
13548}
13549
13550/*
13551 * "winbufnr(nr)" function
13552 */
13553 static void
13554f_winbufnr(typval_T *argvars, typval_T *rettv)
13555{
13556 win_T *wp;
13557
13558 wp = find_win_by_nr(&argvars[0], NULL);
13559 if (wp == NULL)
13560 rettv->vval.v_number = -1;
13561 else
13562 rettv->vval.v_number = wp->w_buffer->b_fnum;
13563}
13564
13565/*
13566 * "wincol()" function
13567 */
13568 static void
13569f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13570{
13571 validate_cursor();
13572 rettv->vval.v_number = curwin->w_wcol + 1;
13573}
13574
13575/*
13576 * "winheight(nr)" function
13577 */
13578 static void
13579f_winheight(typval_T *argvars, typval_T *rettv)
13580{
13581 win_T *wp;
13582
13583 wp = find_win_by_nr(&argvars[0], NULL);
13584 if (wp == NULL)
13585 rettv->vval.v_number = -1;
13586 else
13587 rettv->vval.v_number = wp->w_height;
13588}
13589
13590/*
13591 * "winline()" function
13592 */
13593 static void
13594f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13595{
13596 validate_cursor();
13597 rettv->vval.v_number = curwin->w_wrow + 1;
13598}
13599
13600/*
13601 * "winnr()" function
13602 */
13603 static void
13604f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13605{
13606 int nr = 1;
13607
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013608 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013609 rettv->vval.v_number = nr;
13610}
13611
13612/*
13613 * "winrestcmd()" function
13614 */
13615 static void
13616f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13617{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013618 win_T *wp;
13619 int winnr = 1;
13620 garray_T ga;
13621 char_u buf[50];
13622
13623 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013624 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013625 {
13626 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13627 ga_concat(&ga, buf);
13628 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13629 ga_concat(&ga, buf);
13630 ++winnr;
13631 }
13632 ga_append(&ga, NUL);
13633
13634 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013635 rettv->v_type = VAR_STRING;
13636}
13637
13638/*
13639 * "winrestview()" function
13640 */
13641 static void
13642f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13643{
13644 dict_T *dict;
13645
13646 if (argvars[0].v_type != VAR_DICT
13647 || (dict = argvars[0].vval.v_dict) == NULL)
13648 EMSG(_(e_invarg));
13649 else
13650 {
13651 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13652 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13653 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13654 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13655#ifdef FEAT_VIRTUALEDIT
13656 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13657 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13658#endif
13659 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13660 {
13661 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13662 curwin->w_set_curswant = FALSE;
13663 }
13664
13665 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13666 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13667#ifdef FEAT_DIFF
13668 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13669 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13670#endif
13671 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13672 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13673 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13674 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13675
13676 check_cursor();
13677 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013678 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013679 changed_window_setting();
13680
13681 if (curwin->w_topline <= 0)
13682 curwin->w_topline = 1;
13683 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13684 curwin->w_topline = curbuf->b_ml.ml_line_count;
13685#ifdef FEAT_DIFF
13686 check_topfill(curwin, TRUE);
13687#endif
13688 }
13689}
13690
13691/*
13692 * "winsaveview()" function
13693 */
13694 static void
13695f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13696{
13697 dict_T *dict;
13698
13699 if (rettv_dict_alloc(rettv) == FAIL)
13700 return;
13701 dict = rettv->vval.v_dict;
13702
13703 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13704 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13705#ifdef FEAT_VIRTUALEDIT
13706 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13707#endif
13708 update_curswant();
13709 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13710
13711 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13712#ifdef FEAT_DIFF
13713 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13714#endif
13715 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13716 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13717}
13718
13719/*
13720 * "winwidth(nr)" function
13721 */
13722 static void
13723f_winwidth(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
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013731 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013732}
13733
13734/*
13735 * "wordcount()" function
13736 */
13737 static void
13738f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13739{
13740 if (rettv_dict_alloc(rettv) == FAIL)
13741 return;
13742 cursor_pos_info(rettv->vval.v_dict);
13743}
13744
13745/*
13746 * "writefile()" function
13747 */
13748 static void
13749f_writefile(typval_T *argvars, typval_T *rettv)
13750{
13751 int binary = FALSE;
13752 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013753#ifdef HAVE_FSYNC
13754 int do_fsync = p_fs;
13755#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013756 char_u *fname;
13757 FILE *fd;
13758 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013759 listitem_T *li;
13760 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013761
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013762 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013763 if (check_restricted() || check_secure())
13764 return;
13765
13766 if (argvars[0].v_type != VAR_LIST)
13767 {
13768 EMSG2(_(e_listarg), "writefile()");
13769 return;
13770 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013771 list = argvars[0].vval.v_list;
13772 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013773 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013774 for (li = list->lv_first; li != NULL; li = li->li_next)
13775 if (get_tv_string_chk(&li->li_tv) == NULL)
13776 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013777
13778 if (argvars[2].v_type != VAR_UNKNOWN)
13779 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013780 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13781
13782 if (arg2 == NULL)
13783 return;
13784 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013785 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013786 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013787 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013788#ifdef HAVE_FSYNC
13789 if (vim_strchr(arg2, 's') != NULL)
13790 do_fsync = TRUE;
13791 else if (vim_strchr(arg2, 'S') != NULL)
13792 do_fsync = FALSE;
13793#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013794 }
13795
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013796 fname = get_tv_string_chk(&argvars[1]);
13797 if (fname == NULL)
13798 return;
13799
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013800 /* Always open the file in binary mode, library functions have a mind of
13801 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013802 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13803 append ? APPENDBIN : WRITEBIN)) == NULL)
13804 {
13805 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13806 ret = -1;
13807 }
13808 else
13809 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013810 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013811 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013812#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013813 else if (do_fsync)
13814 /* Ignore the error, the user wouldn't know what to do about it.
13815 * May happen for a device. */
13816 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013817#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013818 fclose(fd);
13819 }
13820
13821 rettv->vval.v_number = ret;
13822}
13823
13824/*
13825 * "xor(expr, expr)" function
13826 */
13827 static void
13828f_xor(typval_T *argvars, typval_T *rettv)
13829{
13830 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13831 ^ get_tv_number_chk(&argvars[1], NULL);
13832}
13833
13834
13835#endif /* FEAT_EVAL */