blob: 599d61ab81244251bb372f99bc5d6246a4e3ca4f [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);
43static void f_argc(typval_T *argvars, typval_T *rettv);
44static void f_argidx(typval_T *argvars, typval_T *rettv);
45static void f_arglistid(typval_T *argvars, typval_T *rettv);
46static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010047static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010049static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_assert_exception(typval_T *argvars, typval_T *rettv);
51static void f_assert_fails(typval_T *argvars, typval_T *rettv);
52static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020053static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_assert_match(typval_T *argvars, typval_T *rettv);
55static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
56static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010057static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020058static void f_assert_true(typval_T *argvars, typval_T *rettv);
59#ifdef FEAT_FLOAT
60static void f_asin(typval_T *argvars, typval_T *rettv);
61static void f_atan(typval_T *argvars, typval_T *rettv);
62static void f_atan2(typval_T *argvars, typval_T *rettv);
63#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010064#ifdef FEAT_BEVAL
65static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010066# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010067static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010068# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010069#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_browse(typval_T *argvars, typval_T *rettv);
71static void f_browsedir(typval_T *argvars, typval_T *rettv);
72static void f_bufexists(typval_T *argvars, typval_T *rettv);
73static void f_buflisted(typval_T *argvars, typval_T *rettv);
74static void f_bufloaded(typval_T *argvars, typval_T *rettv);
75static void f_bufname(typval_T *argvars, typval_T *rettv);
76static void f_bufnr(typval_T *argvars, typval_T *rettv);
77static void f_bufwinid(typval_T *argvars, typval_T *rettv);
78static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
79static void f_byte2line(typval_T *argvars, typval_T *rettv);
80static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
81static void f_byteidx(typval_T *argvars, typval_T *rettv);
82static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
83static void f_call(typval_T *argvars, typval_T *rettv);
84#ifdef FEAT_FLOAT
85static void f_ceil(typval_T *argvars, typval_T *rettv);
86#endif
87#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010088static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020090static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
92static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
93static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
94static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
95static void f_ch_info(typval_T *argvars, typval_T *rettv);
96static void f_ch_log(typval_T *argvars, typval_T *rettv);
97static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
98static void f_ch_open(typval_T *argvars, typval_T *rettv);
99static void f_ch_read(typval_T *argvars, typval_T *rettv);
100static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
101static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
102static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
103static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
104static void f_ch_status(typval_T *argvars, typval_T *rettv);
105#endif
106static void f_changenr(typval_T *argvars, typval_T *rettv);
107static void f_char2nr(typval_T *argvars, typval_T *rettv);
108static void f_cindent(typval_T *argvars, typval_T *rettv);
109static void f_clearmatches(typval_T *argvars, typval_T *rettv);
110static void f_col(typval_T *argvars, typval_T *rettv);
111#if defined(FEAT_INS_EXPAND)
112static void f_complete(typval_T *argvars, typval_T *rettv);
113static void f_complete_add(typval_T *argvars, typval_T *rettv);
114static void f_complete_check(typval_T *argvars, typval_T *rettv);
115#endif
116static void f_confirm(typval_T *argvars, typval_T *rettv);
117static void f_copy(typval_T *argvars, typval_T *rettv);
118#ifdef FEAT_FLOAT
119static void f_cos(typval_T *argvars, typval_T *rettv);
120static void f_cosh(typval_T *argvars, typval_T *rettv);
121#endif
122static void f_count(typval_T *argvars, typval_T *rettv);
123static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
124static void f_cursor(typval_T *argsvars, typval_T *rettv);
125static void f_deepcopy(typval_T *argvars, typval_T *rettv);
126static void f_delete(typval_T *argvars, typval_T *rettv);
127static void f_did_filetype(typval_T *argvars, typval_T *rettv);
128static void f_diff_filler(typval_T *argvars, typval_T *rettv);
129static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
130static void f_empty(typval_T *argvars, typval_T *rettv);
131static void f_escape(typval_T *argvars, typval_T *rettv);
132static void f_eval(typval_T *argvars, typval_T *rettv);
133static void f_eventhandler(typval_T *argvars, typval_T *rettv);
134static void f_executable(typval_T *argvars, typval_T *rettv);
135static void f_execute(typval_T *argvars, typval_T *rettv);
136static void f_exepath(typval_T *argvars, typval_T *rettv);
137static void f_exists(typval_T *argvars, typval_T *rettv);
138#ifdef FEAT_FLOAT
139static void f_exp(typval_T *argvars, typval_T *rettv);
140#endif
141static void f_expand(typval_T *argvars, typval_T *rettv);
142static void f_extend(typval_T *argvars, typval_T *rettv);
143static void f_feedkeys(typval_T *argvars, typval_T *rettv);
144static void f_filereadable(typval_T *argvars, typval_T *rettv);
145static void f_filewritable(typval_T *argvars, typval_T *rettv);
146static void f_filter(typval_T *argvars, typval_T *rettv);
147static void f_finddir(typval_T *argvars, typval_T *rettv);
148static void f_findfile(typval_T *argvars, typval_T *rettv);
149#ifdef FEAT_FLOAT
150static void f_float2nr(typval_T *argvars, typval_T *rettv);
151static void f_floor(typval_T *argvars, typval_T *rettv);
152static void f_fmod(typval_T *argvars, typval_T *rettv);
153#endif
154static void f_fnameescape(typval_T *argvars, typval_T *rettv);
155static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
156static void f_foldclosed(typval_T *argvars, typval_T *rettv);
157static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
158static void f_foldlevel(typval_T *argvars, typval_T *rettv);
159static void f_foldtext(typval_T *argvars, typval_T *rettv);
160static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
161static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200162static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200163static void f_function(typval_T *argvars, typval_T *rettv);
164static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
165static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200166static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200167static void f_getbufline(typval_T *argvars, typval_T *rettv);
168static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100169static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_getchar(typval_T *argvars, typval_T *rettv);
171static void f_getcharmod(typval_T *argvars, typval_T *rettv);
172static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
173static void f_getcmdline(typval_T *argvars, typval_T *rettv);
174#if defined(FEAT_CMDL_COMPL)
175static void f_getcompletion(typval_T *argvars, typval_T *rettv);
176#endif
177static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
178static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
179static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
180static void f_getcwd(typval_T *argvars, typval_T *rettv);
181static void f_getfontname(typval_T *argvars, typval_T *rettv);
182static void f_getfperm(typval_T *argvars, typval_T *rettv);
183static void f_getfsize(typval_T *argvars, typval_T *rettv);
184static void f_getftime(typval_T *argvars, typval_T *rettv);
185static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100186static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200188static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200189static void f_getmatches(typval_T *argvars, typval_T *rettv);
190static void f_getpid(typval_T *argvars, typval_T *rettv);
191static void f_getcurpos(typval_T *argvars, typval_T *rettv);
192static void f_getpos(typval_T *argvars, typval_T *rettv);
193static void f_getqflist(typval_T *argvars, typval_T *rettv);
194static void f_getreg(typval_T *argvars, typval_T *rettv);
195static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200196static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_gettabvar(typval_T *argvars, typval_T *rettv);
198static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200199static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100200static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_getwinposx(typval_T *argvars, typval_T *rettv);
202static void f_getwinposy(typval_T *argvars, typval_T *rettv);
203static void f_getwinvar(typval_T *argvars, typval_T *rettv);
204static void f_glob(typval_T *argvars, typval_T *rettv);
205static void f_globpath(typval_T *argvars, typval_T *rettv);
206static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
207static void f_has(typval_T *argvars, typval_T *rettv);
208static void f_has_key(typval_T *argvars, typval_T *rettv);
209static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
210static void f_hasmapto(typval_T *argvars, typval_T *rettv);
211static void f_histadd(typval_T *argvars, typval_T *rettv);
212static void f_histdel(typval_T *argvars, typval_T *rettv);
213static void f_histget(typval_T *argvars, typval_T *rettv);
214static void f_histnr(typval_T *argvars, typval_T *rettv);
215static void f_hlID(typval_T *argvars, typval_T *rettv);
216static void f_hlexists(typval_T *argvars, typval_T *rettv);
217static void f_hostname(typval_T *argvars, typval_T *rettv);
218static void f_iconv(typval_T *argvars, typval_T *rettv);
219static void f_indent(typval_T *argvars, typval_T *rettv);
220static void f_index(typval_T *argvars, typval_T *rettv);
221static void f_input(typval_T *argvars, typval_T *rettv);
222static void f_inputdialog(typval_T *argvars, typval_T *rettv);
223static void f_inputlist(typval_T *argvars, typval_T *rettv);
224static void f_inputrestore(typval_T *argvars, typval_T *rettv);
225static void f_inputsave(typval_T *argvars, typval_T *rettv);
226static void f_inputsecret(typval_T *argvars, typval_T *rettv);
227static void f_insert(typval_T *argvars, typval_T *rettv);
228static void f_invert(typval_T *argvars, typval_T *rettv);
229static void f_isdirectory(typval_T *argvars, typval_T *rettv);
230static void f_islocked(typval_T *argvars, typval_T *rettv);
231#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
232static void f_isnan(typval_T *argvars, typval_T *rettv);
233#endif
234static void f_items(typval_T *argvars, typval_T *rettv);
235#ifdef FEAT_JOB_CHANNEL
236static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
237static void f_job_info(typval_T *argvars, typval_T *rettv);
238static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
239static void f_job_start(typval_T *argvars, typval_T *rettv);
240static void f_job_stop(typval_T *argvars, typval_T *rettv);
241static void f_job_status(typval_T *argvars, typval_T *rettv);
242#endif
243static void f_join(typval_T *argvars, typval_T *rettv);
244static void f_js_decode(typval_T *argvars, typval_T *rettv);
245static void f_js_encode(typval_T *argvars, typval_T *rettv);
246static void f_json_decode(typval_T *argvars, typval_T *rettv);
247static void f_json_encode(typval_T *argvars, typval_T *rettv);
248static void f_keys(typval_T *argvars, typval_T *rettv);
249static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
250static void f_len(typval_T *argvars, typval_T *rettv);
251static void f_libcall(typval_T *argvars, typval_T *rettv);
252static void f_libcallnr(typval_T *argvars, typval_T *rettv);
253static void f_line(typval_T *argvars, typval_T *rettv);
254static void f_line2byte(typval_T *argvars, typval_T *rettv);
255static void f_lispindent(typval_T *argvars, typval_T *rettv);
256static void f_localtime(typval_T *argvars, typval_T *rettv);
257#ifdef FEAT_FLOAT
258static void f_log(typval_T *argvars, typval_T *rettv);
259static void f_log10(typval_T *argvars, typval_T *rettv);
260#endif
261#ifdef FEAT_LUA
262static void f_luaeval(typval_T *argvars, typval_T *rettv);
263#endif
264static void f_map(typval_T *argvars, typval_T *rettv);
265static void f_maparg(typval_T *argvars, typval_T *rettv);
266static void f_mapcheck(typval_T *argvars, typval_T *rettv);
267static void f_match(typval_T *argvars, typval_T *rettv);
268static void f_matchadd(typval_T *argvars, typval_T *rettv);
269static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
270static void f_matcharg(typval_T *argvars, typval_T *rettv);
271static void f_matchdelete(typval_T *argvars, typval_T *rettv);
272static void f_matchend(typval_T *argvars, typval_T *rettv);
273static void f_matchlist(typval_T *argvars, typval_T *rettv);
274static void f_matchstr(typval_T *argvars, typval_T *rettv);
275static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
276static void f_max(typval_T *argvars, typval_T *rettv);
277static void f_min(typval_T *argvars, typval_T *rettv);
278#ifdef vim_mkdir
279static void f_mkdir(typval_T *argvars, typval_T *rettv);
280#endif
281static void f_mode(typval_T *argvars, typval_T *rettv);
282#ifdef FEAT_MZSCHEME
283static void f_mzeval(typval_T *argvars, typval_T *rettv);
284#endif
285static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
286static void f_nr2char(typval_T *argvars, typval_T *rettv);
287static void f_or(typval_T *argvars, typval_T *rettv);
288static void f_pathshorten(typval_T *argvars, typval_T *rettv);
289#ifdef FEAT_PERL
290static void f_perleval(typval_T *argvars, typval_T *rettv);
291#endif
292#ifdef FEAT_FLOAT
293static void f_pow(typval_T *argvars, typval_T *rettv);
294#endif
295static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
296static void f_printf(typval_T *argvars, typval_T *rettv);
297static void f_pumvisible(typval_T *argvars, typval_T *rettv);
298#ifdef FEAT_PYTHON3
299static void f_py3eval(typval_T *argvars, typval_T *rettv);
300#endif
301#ifdef FEAT_PYTHON
302static void f_pyeval(typval_T *argvars, typval_T *rettv);
303#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100304#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
305static void f_pyxeval(typval_T *argvars, typval_T *rettv);
306#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200307static void f_range(typval_T *argvars, typval_T *rettv);
308static void f_readfile(typval_T *argvars, typval_T *rettv);
309static void f_reltime(typval_T *argvars, typval_T *rettv);
310#ifdef FEAT_FLOAT
311static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
312#endif
313static void f_reltimestr(typval_T *argvars, typval_T *rettv);
314static void f_remote_expr(typval_T *argvars, typval_T *rettv);
315static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
316static void f_remote_peek(typval_T *argvars, typval_T *rettv);
317static void f_remote_read(typval_T *argvars, typval_T *rettv);
318static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100319static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200320static void f_remove(typval_T *argvars, typval_T *rettv);
321static void f_rename(typval_T *argvars, typval_T *rettv);
322static void f_repeat(typval_T *argvars, typval_T *rettv);
323static void f_resolve(typval_T *argvars, typval_T *rettv);
324static void f_reverse(typval_T *argvars, typval_T *rettv);
325#ifdef FEAT_FLOAT
326static void f_round(typval_T *argvars, typval_T *rettv);
327#endif
328static void f_screenattr(typval_T *argvars, typval_T *rettv);
329static void f_screenchar(typval_T *argvars, typval_T *rettv);
330static void f_screencol(typval_T *argvars, typval_T *rettv);
331static void f_screenrow(typval_T *argvars, typval_T *rettv);
332static void f_search(typval_T *argvars, typval_T *rettv);
333static void f_searchdecl(typval_T *argvars, typval_T *rettv);
334static void f_searchpair(typval_T *argvars, typval_T *rettv);
335static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
336static void f_searchpos(typval_T *argvars, typval_T *rettv);
337static void f_server2client(typval_T *argvars, typval_T *rettv);
338static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200339static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200340static void f_setbufvar(typval_T *argvars, typval_T *rettv);
341static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
342static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
343static void f_setfperm(typval_T *argvars, typval_T *rettv);
344static void f_setline(typval_T *argvars, typval_T *rettv);
345static void f_setloclist(typval_T *argvars, typval_T *rettv);
346static void f_setmatches(typval_T *argvars, typval_T *rettv);
347static void f_setpos(typval_T *argvars, typval_T *rettv);
348static void f_setqflist(typval_T *argvars, typval_T *rettv);
349static void f_setreg(typval_T *argvars, typval_T *rettv);
350static void f_settabvar(typval_T *argvars, typval_T *rettv);
351static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
352static void f_setwinvar(typval_T *argvars, typval_T *rettv);
353#ifdef FEAT_CRYPT
354static void f_sha256(typval_T *argvars, typval_T *rettv);
355#endif /* FEAT_CRYPT */
356static void f_shellescape(typval_T *argvars, typval_T *rettv);
357static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
358static void f_simplify(typval_T *argvars, typval_T *rettv);
359#ifdef FEAT_FLOAT
360static void f_sin(typval_T *argvars, typval_T *rettv);
361static void f_sinh(typval_T *argvars, typval_T *rettv);
362#endif
363static void f_sort(typval_T *argvars, typval_T *rettv);
364static void f_soundfold(typval_T *argvars, typval_T *rettv);
365static void f_spellbadword(typval_T *argvars, typval_T *rettv);
366static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
367static void f_split(typval_T *argvars, typval_T *rettv);
368#ifdef FEAT_FLOAT
369static void f_sqrt(typval_T *argvars, typval_T *rettv);
370static void f_str2float(typval_T *argvars, typval_T *rettv);
371#endif
372static void f_str2nr(typval_T *argvars, typval_T *rettv);
373static void f_strchars(typval_T *argvars, typval_T *rettv);
374#ifdef HAVE_STRFTIME
375static void f_strftime(typval_T *argvars, typval_T *rettv);
376#endif
377static void f_strgetchar(typval_T *argvars, typval_T *rettv);
378static void f_stridx(typval_T *argvars, typval_T *rettv);
379static void f_string(typval_T *argvars, typval_T *rettv);
380static void f_strlen(typval_T *argvars, typval_T *rettv);
381static void f_strcharpart(typval_T *argvars, typval_T *rettv);
382static void f_strpart(typval_T *argvars, typval_T *rettv);
383static void f_strridx(typval_T *argvars, typval_T *rettv);
384static void f_strtrans(typval_T *argvars, typval_T *rettv);
385static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
386static void f_strwidth(typval_T *argvars, typval_T *rettv);
387static void f_submatch(typval_T *argvars, typval_T *rettv);
388static void f_substitute(typval_T *argvars, typval_T *rettv);
389static void f_synID(typval_T *argvars, typval_T *rettv);
390static void f_synIDattr(typval_T *argvars, typval_T *rettv);
391static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
392static void f_synstack(typval_T *argvars, typval_T *rettv);
393static void f_synconcealed(typval_T *argvars, typval_T *rettv);
394static void f_system(typval_T *argvars, typval_T *rettv);
395static void f_systemlist(typval_T *argvars, typval_T *rettv);
396static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
397static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
398static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
399static void f_taglist(typval_T *argvars, typval_T *rettv);
400static void f_tagfiles(typval_T *argvars, typval_T *rettv);
401static void f_tempname(typval_T *argvars, typval_T *rettv);
402static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
403static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200404static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100405static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100407static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200408#ifdef FEAT_JOB_CHANNEL
409static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
410#endif
411static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
412#ifdef FEAT_JOB_CHANNEL
413static void f_test_null_job(typval_T *argvars, typval_T *rettv);
414#endif
415static void f_test_null_list(typval_T *argvars, typval_T *rettv);
416static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
417static void f_test_null_string(typval_T *argvars, typval_T *rettv);
418static void f_test_settime(typval_T *argvars, typval_T *rettv);
419#ifdef FEAT_FLOAT
420static void f_tan(typval_T *argvars, typval_T *rettv);
421static void f_tanh(typval_T *argvars, typval_T *rettv);
422#endif
423#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200424static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200425static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200426static void f_timer_start(typval_T *argvars, typval_T *rettv);
427static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200428static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429#endif
430static void f_tolower(typval_T *argvars, typval_T *rettv);
431static void f_toupper(typval_T *argvars, typval_T *rettv);
432static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100433static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434#ifdef FEAT_FLOAT
435static void f_trunc(typval_T *argvars, typval_T *rettv);
436#endif
437static void f_type(typval_T *argvars, typval_T *rettv);
438static void f_undofile(typval_T *argvars, typval_T *rettv);
439static void f_undotree(typval_T *argvars, typval_T *rettv);
440static void f_uniq(typval_T *argvars, typval_T *rettv);
441static void f_values(typval_T *argvars, typval_T *rettv);
442static void f_virtcol(typval_T *argvars, typval_T *rettv);
443static void f_visualmode(typval_T *argvars, typval_T *rettv);
444static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
445static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
446static void f_win_getid(typval_T *argvars, typval_T *rettv);
447static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
448static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
449static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100450static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200451static void f_winbufnr(typval_T *argvars, typval_T *rettv);
452static void f_wincol(typval_T *argvars, typval_T *rettv);
453static void f_winheight(typval_T *argvars, typval_T *rettv);
454static void f_winline(typval_T *argvars, typval_T *rettv);
455static void f_winnr(typval_T *argvars, typval_T *rettv);
456static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
457static void f_winrestview(typval_T *argvars, typval_T *rettv);
458static void f_winsaveview(typval_T *argvars, typval_T *rettv);
459static void f_winwidth(typval_T *argvars, typval_T *rettv);
460static void f_writefile(typval_T *argvars, typval_T *rettv);
461static void f_wordcount(typval_T *argvars, typval_T *rettv);
462static void f_xor(typval_T *argvars, typval_T *rettv);
463
464/*
465 * Array with names and number of arguments of all internal functions
466 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
467 */
468static struct fst
469{
470 char *f_name; /* function name */
471 char f_min_argc; /* minimal number of arguments */
472 char f_max_argc; /* maximal number of arguments */
473 void (*f_func)(typval_T *args, typval_T *rvar);
474 /* implementation of function */
475} functions[] =
476{
477#ifdef FEAT_FLOAT
478 {"abs", 1, 1, f_abs},
479 {"acos", 1, 1, f_acos}, /* WJMc */
480#endif
481 {"add", 2, 2, f_add},
482 {"and", 2, 2, f_and},
483 {"append", 2, 2, f_append},
484 {"argc", 0, 0, f_argc},
485 {"argidx", 0, 0, f_argidx},
486 {"arglistid", 0, 2, f_arglistid},
487 {"argv", 0, 1, f_argv},
488#ifdef FEAT_FLOAT
489 {"asin", 1, 1, f_asin}, /* WJMc */
490#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100491 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200492 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100493 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200494 {"assert_exception", 1, 2, f_assert_exception},
495 {"assert_fails", 1, 2, f_assert_fails},
496 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100497 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498 {"assert_match", 2, 3, f_assert_match},
499 {"assert_notequal", 2, 3, f_assert_notequal},
500 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100501 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200502 {"assert_true", 1, 2, f_assert_true},
503#ifdef FEAT_FLOAT
504 {"atan", 1, 1, f_atan},
505 {"atan2", 2, 2, f_atan2},
506#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100507#ifdef FEAT_BEVAL
508 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100509# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100510 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100511# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100512#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513 {"browse", 4, 4, f_browse},
514 {"browsedir", 2, 2, f_browsedir},
515 {"bufexists", 1, 1, f_bufexists},
516 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
517 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
518 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
519 {"buflisted", 1, 1, f_buflisted},
520 {"bufloaded", 1, 1, f_bufloaded},
521 {"bufname", 1, 1, f_bufname},
522 {"bufnr", 1, 2, f_bufnr},
523 {"bufwinid", 1, 1, f_bufwinid},
524 {"bufwinnr", 1, 1, f_bufwinnr},
525 {"byte2line", 1, 1, f_byte2line},
526 {"byteidx", 2, 2, f_byteidx},
527 {"byteidxcomp", 2, 2, f_byteidxcomp},
528 {"call", 2, 3, f_call},
529#ifdef FEAT_FLOAT
530 {"ceil", 1, 1, f_ceil},
531#endif
532#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100533 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200534 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200535 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
537 {"ch_evalraw", 2, 3, f_ch_evalraw},
538 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
539 {"ch_getjob", 1, 1, f_ch_getjob},
540 {"ch_info", 1, 1, f_ch_info},
541 {"ch_log", 1, 2, f_ch_log},
542 {"ch_logfile", 1, 2, f_ch_logfile},
543 {"ch_open", 1, 2, f_ch_open},
544 {"ch_read", 1, 2, f_ch_read},
545 {"ch_readraw", 1, 2, f_ch_readraw},
546 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
547 {"ch_sendraw", 2, 3, f_ch_sendraw},
548 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200549 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#endif
551 {"changenr", 0, 0, f_changenr},
552 {"char2nr", 1, 2, f_char2nr},
553 {"cindent", 1, 1, f_cindent},
554 {"clearmatches", 0, 0, f_clearmatches},
555 {"col", 1, 1, f_col},
556#if defined(FEAT_INS_EXPAND)
557 {"complete", 2, 2, f_complete},
558 {"complete_add", 1, 1, f_complete_add},
559 {"complete_check", 0, 0, f_complete_check},
560#endif
561 {"confirm", 1, 4, f_confirm},
562 {"copy", 1, 1, f_copy},
563#ifdef FEAT_FLOAT
564 {"cos", 1, 1, f_cos},
565 {"cosh", 1, 1, f_cosh},
566#endif
567 {"count", 2, 4, f_count},
568 {"cscope_connection",0,3, f_cscope_connection},
569 {"cursor", 1, 3, f_cursor},
570 {"deepcopy", 1, 2, f_deepcopy},
571 {"delete", 1, 2, f_delete},
572 {"did_filetype", 0, 0, f_did_filetype},
573 {"diff_filler", 1, 1, f_diff_filler},
574 {"diff_hlID", 2, 2, f_diff_hlID},
575 {"empty", 1, 1, f_empty},
576 {"escape", 2, 2, f_escape},
577 {"eval", 1, 1, f_eval},
578 {"eventhandler", 0, 0, f_eventhandler},
579 {"executable", 1, 1, f_executable},
580 {"execute", 1, 2, f_execute},
581 {"exepath", 1, 1, f_exepath},
582 {"exists", 1, 1, f_exists},
583#ifdef FEAT_FLOAT
584 {"exp", 1, 1, f_exp},
585#endif
586 {"expand", 1, 3, f_expand},
587 {"extend", 2, 3, f_extend},
588 {"feedkeys", 1, 2, f_feedkeys},
589 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
590 {"filereadable", 1, 1, f_filereadable},
591 {"filewritable", 1, 1, f_filewritable},
592 {"filter", 2, 2, f_filter},
593 {"finddir", 1, 3, f_finddir},
594 {"findfile", 1, 3, f_findfile},
595#ifdef FEAT_FLOAT
596 {"float2nr", 1, 1, f_float2nr},
597 {"floor", 1, 1, f_floor},
598 {"fmod", 2, 2, f_fmod},
599#endif
600 {"fnameescape", 1, 1, f_fnameescape},
601 {"fnamemodify", 2, 2, f_fnamemodify},
602 {"foldclosed", 1, 1, f_foldclosed},
603 {"foldclosedend", 1, 1, f_foldclosedend},
604 {"foldlevel", 1, 1, f_foldlevel},
605 {"foldtext", 0, 0, f_foldtext},
606 {"foldtextresult", 1, 1, f_foldtextresult},
607 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200608 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200609 {"function", 1, 3, f_function},
610 {"garbagecollect", 0, 1, f_garbagecollect},
611 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200612 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200613 {"getbufline", 2, 3, f_getbufline},
614 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100615 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200616 {"getchar", 0, 1, f_getchar},
617 {"getcharmod", 0, 0, f_getcharmod},
618 {"getcharsearch", 0, 0, f_getcharsearch},
619 {"getcmdline", 0, 0, f_getcmdline},
620 {"getcmdpos", 0, 0, f_getcmdpos},
621 {"getcmdtype", 0, 0, f_getcmdtype},
622 {"getcmdwintype", 0, 0, f_getcmdwintype},
623#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200624 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625#endif
626 {"getcurpos", 0, 0, f_getcurpos},
627 {"getcwd", 0, 2, f_getcwd},
628 {"getfontname", 0, 1, f_getfontname},
629 {"getfperm", 1, 1, f_getfperm},
630 {"getfsize", 1, 1, f_getfsize},
631 {"getftime", 1, 1, f_getftime},
632 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100633 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200634 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200635 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636 {"getmatches", 0, 0, f_getmatches},
637 {"getpid", 0, 0, f_getpid},
638 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200639 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640 {"getreg", 0, 3, f_getreg},
641 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200642 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643 {"gettabvar", 2, 3, f_gettabvar},
644 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200645 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100646 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200647 {"getwinposx", 0, 0, f_getwinposx},
648 {"getwinposy", 0, 0, f_getwinposy},
649 {"getwinvar", 2, 3, f_getwinvar},
650 {"glob", 1, 4, f_glob},
651 {"glob2regpat", 1, 1, f_glob2regpat},
652 {"globpath", 2, 5, f_globpath},
653 {"has", 1, 1, f_has},
654 {"has_key", 2, 2, f_has_key},
655 {"haslocaldir", 0, 2, f_haslocaldir},
656 {"hasmapto", 1, 3, f_hasmapto},
657 {"highlightID", 1, 1, f_hlID}, /* obsolete */
658 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
659 {"histadd", 2, 2, f_histadd},
660 {"histdel", 1, 2, f_histdel},
661 {"histget", 1, 2, f_histget},
662 {"histnr", 1, 1, f_histnr},
663 {"hlID", 1, 1, f_hlID},
664 {"hlexists", 1, 1, f_hlexists},
665 {"hostname", 0, 0, f_hostname},
666 {"iconv", 3, 3, f_iconv},
667 {"indent", 1, 1, f_indent},
668 {"index", 2, 4, f_index},
669 {"input", 1, 3, f_input},
670 {"inputdialog", 1, 3, f_inputdialog},
671 {"inputlist", 1, 1, f_inputlist},
672 {"inputrestore", 0, 0, f_inputrestore},
673 {"inputsave", 0, 0, f_inputsave},
674 {"inputsecret", 1, 2, f_inputsecret},
675 {"insert", 2, 3, f_insert},
676 {"invert", 1, 1, f_invert},
677 {"isdirectory", 1, 1, f_isdirectory},
678 {"islocked", 1, 1, f_islocked},
679#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
680 {"isnan", 1, 1, f_isnan},
681#endif
682 {"items", 1, 1, f_items},
683#ifdef FEAT_JOB_CHANNEL
684 {"job_getchannel", 1, 1, f_job_getchannel},
685 {"job_info", 1, 1, f_job_info},
686 {"job_setoptions", 2, 2, f_job_setoptions},
687 {"job_start", 1, 2, f_job_start},
688 {"job_status", 1, 1, f_job_status},
689 {"job_stop", 1, 2, f_job_stop},
690#endif
691 {"join", 1, 2, f_join},
692 {"js_decode", 1, 1, f_js_decode},
693 {"js_encode", 1, 1, f_js_encode},
694 {"json_decode", 1, 1, f_json_decode},
695 {"json_encode", 1, 1, f_json_encode},
696 {"keys", 1, 1, f_keys},
697 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
698 {"len", 1, 1, f_len},
699 {"libcall", 3, 3, f_libcall},
700 {"libcallnr", 3, 3, f_libcallnr},
701 {"line", 1, 1, f_line},
702 {"line2byte", 1, 1, f_line2byte},
703 {"lispindent", 1, 1, f_lispindent},
704 {"localtime", 0, 0, f_localtime},
705#ifdef FEAT_FLOAT
706 {"log", 1, 1, f_log},
707 {"log10", 1, 1, f_log10},
708#endif
709#ifdef FEAT_LUA
710 {"luaeval", 1, 2, f_luaeval},
711#endif
712 {"map", 2, 2, f_map},
713 {"maparg", 1, 4, f_maparg},
714 {"mapcheck", 1, 3, f_mapcheck},
715 {"match", 2, 4, f_match},
716 {"matchadd", 2, 5, f_matchadd},
717 {"matchaddpos", 2, 5, f_matchaddpos},
718 {"matcharg", 1, 1, f_matcharg},
719 {"matchdelete", 1, 1, f_matchdelete},
720 {"matchend", 2, 4, f_matchend},
721 {"matchlist", 2, 4, f_matchlist},
722 {"matchstr", 2, 4, f_matchstr},
723 {"matchstrpos", 2, 4, f_matchstrpos},
724 {"max", 1, 1, f_max},
725 {"min", 1, 1, f_min},
726#ifdef vim_mkdir
727 {"mkdir", 1, 3, f_mkdir},
728#endif
729 {"mode", 0, 1, f_mode},
730#ifdef FEAT_MZSCHEME
731 {"mzeval", 1, 1, f_mzeval},
732#endif
733 {"nextnonblank", 1, 1, f_nextnonblank},
734 {"nr2char", 1, 2, f_nr2char},
735 {"or", 2, 2, f_or},
736 {"pathshorten", 1, 1, f_pathshorten},
737#ifdef FEAT_PERL
738 {"perleval", 1, 1, f_perleval},
739#endif
740#ifdef FEAT_FLOAT
741 {"pow", 2, 2, f_pow},
742#endif
743 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100744 {"printf", 1, 19, f_printf},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200745 {"pumvisible", 0, 0, f_pumvisible},
746#ifdef FEAT_PYTHON3
747 {"py3eval", 1, 1, f_py3eval},
748#endif
749#ifdef FEAT_PYTHON
750 {"pyeval", 1, 1, f_pyeval},
751#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100752#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
753 {"pyxeval", 1, 1, f_pyxeval},
754#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200755 {"range", 1, 3, f_range},
756 {"readfile", 1, 3, f_readfile},
757 {"reltime", 0, 2, f_reltime},
758#ifdef FEAT_FLOAT
759 {"reltimefloat", 1, 1, f_reltimefloat},
760#endif
761 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100762 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763 {"remote_foreground", 1, 1, f_remote_foreground},
764 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100765 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200766 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100767 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200768 {"remove", 2, 3, f_remove},
769 {"rename", 2, 2, f_rename},
770 {"repeat", 2, 2, f_repeat},
771 {"resolve", 1, 1, f_resolve},
772 {"reverse", 1, 1, f_reverse},
773#ifdef FEAT_FLOAT
774 {"round", 1, 1, f_round},
775#endif
776 {"screenattr", 2, 2, f_screenattr},
777 {"screenchar", 2, 2, f_screenchar},
778 {"screencol", 0, 0, f_screencol},
779 {"screenrow", 0, 0, f_screenrow},
780 {"search", 1, 4, f_search},
781 {"searchdecl", 1, 3, f_searchdecl},
782 {"searchpair", 3, 7, f_searchpair},
783 {"searchpairpos", 3, 7, f_searchpairpos},
784 {"searchpos", 1, 4, f_searchpos},
785 {"server2client", 2, 2, f_server2client},
786 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200787 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"setbufvar", 3, 3, f_setbufvar},
789 {"setcharsearch", 1, 1, f_setcharsearch},
790 {"setcmdpos", 1, 1, f_setcmdpos},
791 {"setfperm", 2, 2, f_setfperm},
792 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200793 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794 {"setmatches", 1, 1, f_setmatches},
795 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200796 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200797 {"setreg", 2, 3, f_setreg},
798 {"settabvar", 3, 3, f_settabvar},
799 {"settabwinvar", 4, 4, f_settabwinvar},
800 {"setwinvar", 3, 3, f_setwinvar},
801#ifdef FEAT_CRYPT
802 {"sha256", 1, 1, f_sha256},
803#endif
804 {"shellescape", 1, 2, f_shellescape},
805 {"shiftwidth", 0, 0, f_shiftwidth},
806 {"simplify", 1, 1, f_simplify},
807#ifdef FEAT_FLOAT
808 {"sin", 1, 1, f_sin},
809 {"sinh", 1, 1, f_sinh},
810#endif
811 {"sort", 1, 3, f_sort},
812 {"soundfold", 1, 1, f_soundfold},
813 {"spellbadword", 0, 1, f_spellbadword},
814 {"spellsuggest", 1, 3, f_spellsuggest},
815 {"split", 1, 3, f_split},
816#ifdef FEAT_FLOAT
817 {"sqrt", 1, 1, f_sqrt},
818 {"str2float", 1, 1, f_str2float},
819#endif
820 {"str2nr", 1, 2, f_str2nr},
821 {"strcharpart", 2, 3, f_strcharpart},
822 {"strchars", 1, 2, f_strchars},
823 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
824#ifdef HAVE_STRFTIME
825 {"strftime", 1, 2, f_strftime},
826#endif
827 {"strgetchar", 2, 2, f_strgetchar},
828 {"stridx", 2, 3, f_stridx},
829 {"string", 1, 1, f_string},
830 {"strlen", 1, 1, f_strlen},
831 {"strpart", 2, 3, f_strpart},
832 {"strridx", 2, 3, f_strridx},
833 {"strtrans", 1, 1, f_strtrans},
834 {"strwidth", 1, 1, f_strwidth},
835 {"submatch", 1, 2, f_submatch},
836 {"substitute", 4, 4, f_substitute},
837 {"synID", 3, 3, f_synID},
838 {"synIDattr", 2, 3, f_synIDattr},
839 {"synIDtrans", 1, 1, f_synIDtrans},
840 {"synconcealed", 2, 2, f_synconcealed},
841 {"synstack", 2, 2, f_synstack},
842 {"system", 1, 2, f_system},
843 {"systemlist", 1, 2, f_systemlist},
844 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
845 {"tabpagenr", 0, 1, f_tabpagenr},
846 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
847 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100848 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849#ifdef FEAT_FLOAT
850 {"tan", 1, 1, f_tan},
851 {"tanh", 1, 1, f_tanh},
852#endif
853 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200854#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100855 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
856 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100857 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200858 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200859# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
860 {"term_getansicolors", 1, 1, f_term_getansicolors},
861# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200862 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200863 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200864 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200865 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200866 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200867 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200868 {"term_getstatus", 1, 1, f_term_getstatus},
869 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200870 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200871 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200872 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200873 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200874# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
875 {"term_setansicolors", 2, 2, f_term_setansicolors},
876# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100877 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100878 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200879 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200880 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200881 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200882#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
884 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200885 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100887 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888#ifdef FEAT_JOB_CHANNEL
889 {"test_null_channel", 0, 0, f_test_null_channel},
890#endif
891 {"test_null_dict", 0, 0, f_test_null_dict},
892#ifdef FEAT_JOB_CHANNEL
893 {"test_null_job", 0, 0, f_test_null_job},
894#endif
895 {"test_null_list", 0, 0, f_test_null_list},
896 {"test_null_partial", 0, 0, f_test_null_partial},
897 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100898 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200899 {"test_settime", 1, 1, f_test_settime},
900#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200901 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200902 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200903 {"timer_start", 2, 3, f_timer_start},
904 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200905 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200906#endif
907 {"tolower", 1, 1, f_tolower},
908 {"toupper", 1, 1, f_toupper},
909 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100910 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200911#ifdef FEAT_FLOAT
912 {"trunc", 1, 1, f_trunc},
913#endif
914 {"type", 1, 1, f_type},
915 {"undofile", 1, 1, f_undofile},
916 {"undotree", 0, 0, f_undotree},
917 {"uniq", 1, 3, f_uniq},
918 {"values", 1, 1, f_values},
919 {"virtcol", 1, 1, f_virtcol},
920 {"visualmode", 0, 1, f_visualmode},
921 {"wildmenumode", 0, 0, f_wildmenumode},
922 {"win_findbuf", 1, 1, f_win_findbuf},
923 {"win_getid", 0, 2, f_win_getid},
924 {"win_gotoid", 1, 1, f_win_gotoid},
925 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
926 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100927 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928 {"winbufnr", 1, 1, f_winbufnr},
929 {"wincol", 0, 0, f_wincol},
930 {"winheight", 1, 1, f_winheight},
931 {"winline", 0, 0, f_winline},
932 {"winnr", 0, 1, f_winnr},
933 {"winrestcmd", 0, 0, f_winrestcmd},
934 {"winrestview", 1, 1, f_winrestview},
935 {"winsaveview", 0, 0, f_winsaveview},
936 {"winwidth", 1, 1, f_winwidth},
937 {"wordcount", 0, 0, f_wordcount},
938 {"writefile", 2, 3, f_writefile},
939 {"xor", 2, 2, f_xor},
940};
941
942#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
943
944/*
945 * Function given to ExpandGeneric() to obtain the list of internal
946 * or user defined function names.
947 */
948 char_u *
949get_function_name(expand_T *xp, int idx)
950{
951 static int intidx = -1;
952 char_u *name;
953
954 if (idx == 0)
955 intidx = -1;
956 if (intidx < 0)
957 {
958 name = get_user_func_name(xp, idx);
959 if (name != NULL)
960 return name;
961 }
962 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
963 {
964 STRCPY(IObuff, functions[intidx].f_name);
965 STRCAT(IObuff, "(");
966 if (functions[intidx].f_max_argc == 0)
967 STRCAT(IObuff, ")");
968 return IObuff;
969 }
970
971 return NULL;
972}
973
974/*
975 * Function given to ExpandGeneric() to obtain the list of internal or
976 * user defined variable or function names.
977 */
978 char_u *
979get_expr_name(expand_T *xp, int idx)
980{
981 static int intidx = -1;
982 char_u *name;
983
984 if (idx == 0)
985 intidx = -1;
986 if (intidx < 0)
987 {
988 name = get_function_name(xp, idx);
989 if (name != NULL)
990 return name;
991 }
992 return get_user_var_name(xp, ++intidx);
993}
994
995#endif /* FEAT_CMDL_COMPL */
996
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200997/*
998 * Find internal function in table above.
999 * Return index, or -1 if not found
1000 */
1001 int
1002find_internal_func(
1003 char_u *name) /* name of the function */
1004{
1005 int first = 0;
1006 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1007 int cmp;
1008 int x;
1009
1010 /*
1011 * Find the function name in the table. Binary search.
1012 */
1013 while (first <= last)
1014 {
1015 x = first + ((unsigned)(last - first) >> 1);
1016 cmp = STRCMP(name, functions[x].f_name);
1017 if (cmp < 0)
1018 last = x - 1;
1019 else if (cmp > 0)
1020 first = x + 1;
1021 else
1022 return x;
1023 }
1024 return -1;
1025}
1026
1027 int
1028call_internal_func(
1029 char_u *name,
1030 int argcount,
1031 typval_T *argvars,
1032 typval_T *rettv)
1033{
1034 int i;
1035
1036 i = find_internal_func(name);
1037 if (i < 0)
1038 return ERROR_UNKNOWN;
1039 if (argcount < functions[i].f_min_argc)
1040 return ERROR_TOOFEW;
1041 if (argcount > functions[i].f_max_argc)
1042 return ERROR_TOOMANY;
1043 argvars[argcount].v_type = VAR_UNKNOWN;
1044 functions[i].f_func(argvars, rettv);
1045 return ERROR_NONE;
1046}
1047
1048/*
1049 * Return TRUE for a non-zero Number and a non-empty String.
1050 */
1051 static int
1052non_zero_arg(typval_T *argvars)
1053{
1054 return ((argvars[0].v_type == VAR_NUMBER
1055 && argvars[0].vval.v_number != 0)
1056 || (argvars[0].v_type == VAR_SPECIAL
1057 && argvars[0].vval.v_number == VVAL_TRUE)
1058 || (argvars[0].v_type == VAR_STRING
1059 && argvars[0].vval.v_string != NULL
1060 && *argvars[0].vval.v_string != NUL));
1061}
1062
1063/*
1064 * Get the lnum from the first argument.
1065 * Also accepts ".", "$", etc., but that only works for the current buffer.
1066 * Returns -1 on error.
1067 */
1068 static linenr_T
1069get_tv_lnum(typval_T *argvars)
1070{
1071 typval_T rettv;
1072 linenr_T lnum;
1073
1074 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1075 if (lnum == 0) /* no valid number, try using line() */
1076 {
1077 rettv.v_type = VAR_NUMBER;
1078 f_line(argvars, &rettv);
1079 lnum = (linenr_T)rettv.vval.v_number;
1080 clear_tv(&rettv);
1081 }
1082 return lnum;
1083}
1084
1085#ifdef FEAT_FLOAT
1086static int get_float_arg(typval_T *argvars, float_T *f);
1087
1088/*
1089 * Get the float value of "argvars[0]" into "f".
1090 * Returns FAIL when the argument is not a Number or Float.
1091 */
1092 static int
1093get_float_arg(typval_T *argvars, float_T *f)
1094{
1095 if (argvars[0].v_type == VAR_FLOAT)
1096 {
1097 *f = argvars[0].vval.v_float;
1098 return OK;
1099 }
1100 if (argvars[0].v_type == VAR_NUMBER)
1101 {
1102 *f = (float_T)argvars[0].vval.v_number;
1103 return OK;
1104 }
1105 EMSG(_("E808: Number or Float required"));
1106 return FAIL;
1107}
1108
1109/*
1110 * "abs(expr)" function
1111 */
1112 static void
1113f_abs(typval_T *argvars, typval_T *rettv)
1114{
1115 if (argvars[0].v_type == VAR_FLOAT)
1116 {
1117 rettv->v_type = VAR_FLOAT;
1118 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1119 }
1120 else
1121 {
1122 varnumber_T n;
1123 int error = FALSE;
1124
1125 n = get_tv_number_chk(&argvars[0], &error);
1126 if (error)
1127 rettv->vval.v_number = -1;
1128 else if (n > 0)
1129 rettv->vval.v_number = n;
1130 else
1131 rettv->vval.v_number = -n;
1132 }
1133}
1134
1135/*
1136 * "acos()" function
1137 */
1138 static void
1139f_acos(typval_T *argvars, typval_T *rettv)
1140{
1141 float_T f = 0.0;
1142
1143 rettv->v_type = VAR_FLOAT;
1144 if (get_float_arg(argvars, &f) == OK)
1145 rettv->vval.v_float = acos(f);
1146 else
1147 rettv->vval.v_float = 0.0;
1148}
1149#endif
1150
1151/*
1152 * "add(list, item)" function
1153 */
1154 static void
1155f_add(typval_T *argvars, typval_T *rettv)
1156{
1157 list_T *l;
1158
1159 rettv->vval.v_number = 1; /* Default: Failed */
1160 if (argvars[0].v_type == VAR_LIST)
1161 {
1162 if ((l = argvars[0].vval.v_list) != NULL
1163 && !tv_check_lock(l->lv_lock,
1164 (char_u *)N_("add() argument"), TRUE)
1165 && list_append_tv(l, &argvars[1]) == OK)
1166 copy_tv(&argvars[0], rettv);
1167 }
1168 else
1169 EMSG(_(e_listreq));
1170}
1171
1172/*
1173 * "and(expr, expr)" function
1174 */
1175 static void
1176f_and(typval_T *argvars, typval_T *rettv)
1177{
1178 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1179 & get_tv_number_chk(&argvars[1], NULL);
1180}
1181
1182/*
1183 * "append(lnum, string/list)" function
1184 */
1185 static void
1186f_append(typval_T *argvars, typval_T *rettv)
1187{
1188 long lnum;
1189 char_u *line;
1190 list_T *l = NULL;
1191 listitem_T *li = NULL;
1192 typval_T *tv;
1193 long added = 0;
1194
1195 /* When coming here from Insert mode, sync undo, so that this can be
1196 * undone separately from what was previously inserted. */
1197 if (u_sync_once == 2)
1198 {
1199 u_sync_once = 1; /* notify that u_sync() was called */
1200 u_sync(TRUE);
1201 }
1202
1203 lnum = get_tv_lnum(argvars);
1204 if (lnum >= 0
1205 && lnum <= curbuf->b_ml.ml_line_count
1206 && u_save(lnum, lnum + 1) == OK)
1207 {
1208 if (argvars[1].v_type == VAR_LIST)
1209 {
1210 l = argvars[1].vval.v_list;
1211 if (l == NULL)
1212 return;
1213 li = l->lv_first;
1214 }
1215 for (;;)
1216 {
1217 if (l == NULL)
1218 tv = &argvars[1]; /* append a string */
1219 else if (li == NULL)
1220 break; /* end of list */
1221 else
1222 tv = &li->li_tv; /* append item from list */
1223 line = get_tv_string_chk(tv);
1224 if (line == NULL) /* type error */
1225 {
1226 rettv->vval.v_number = 1; /* Failed */
1227 break;
1228 }
1229 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1230 ++added;
1231 if (l == NULL)
1232 break;
1233 li = li->li_next;
1234 }
1235
1236 appended_lines_mark(lnum, added);
1237 if (curwin->w_cursor.lnum > lnum)
1238 curwin->w_cursor.lnum += added;
1239 }
1240 else
1241 rettv->vval.v_number = 1; /* Failed */
1242}
1243
1244/*
1245 * "argc()" function
1246 */
1247 static void
1248f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1249{
1250 rettv->vval.v_number = ARGCOUNT;
1251}
1252
1253/*
1254 * "argidx()" function
1255 */
1256 static void
1257f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1258{
1259 rettv->vval.v_number = curwin->w_arg_idx;
1260}
1261
1262/*
1263 * "arglistid()" function
1264 */
1265 static void
1266f_arglistid(typval_T *argvars, typval_T *rettv)
1267{
1268 win_T *wp;
1269
1270 rettv->vval.v_number = -1;
1271 wp = find_tabwin(&argvars[0], &argvars[1]);
1272 if (wp != NULL)
1273 rettv->vval.v_number = wp->w_alist->id;
1274}
1275
1276/*
1277 * "argv(nr)" function
1278 */
1279 static void
1280f_argv(typval_T *argvars, typval_T *rettv)
1281{
1282 int idx;
1283
1284 if (argvars[0].v_type != VAR_UNKNOWN)
1285 {
1286 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1287 if (idx >= 0 && idx < ARGCOUNT)
1288 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1289 else
1290 rettv->vval.v_string = NULL;
1291 rettv->v_type = VAR_STRING;
1292 }
1293 else if (rettv_list_alloc(rettv) == OK)
1294 for (idx = 0; idx < ARGCOUNT; ++idx)
1295 list_append_string(rettv->vval.v_list,
1296 alist_name(&ARGLIST[idx]), -1);
1297}
1298
1299/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001300 * "assert_beeps(cmd [, error])" function
1301 */
1302 static void
1303f_assert_beeps(typval_T *argvars, typval_T *rettv UNUSED)
1304{
1305 assert_beeps(argvars);
1306}
1307
1308/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001309 * "assert_equal(expected, actual[, msg])" function
1310 */
1311 static void
1312f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1313{
1314 assert_equal_common(argvars, ASSERT_EQUAL);
1315}
1316
1317/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001318 * "assert_equalfile(fname-one, fname-two)" function
1319 */
1320 static void
1321f_assert_equalfile(typval_T *argvars, typval_T *rettv UNUSED)
1322{
1323 assert_equalfile(argvars);
1324}
1325
1326/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001327 * "assert_notequal(expected, actual[, msg])" function
1328 */
1329 static void
1330f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1331{
1332 assert_equal_common(argvars, ASSERT_NOTEQUAL);
1333}
1334
1335/*
1336 * "assert_exception(string[, msg])" function
1337 */
1338 static void
1339f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1340{
1341 assert_exception(argvars);
1342}
1343
1344/*
1345 * "assert_fails(cmd [, error])" function
1346 */
1347 static void
1348f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1349{
1350 assert_fails(argvars);
1351}
1352
1353/*
1354 * "assert_false(actual[, msg])" function
1355 */
1356 static void
1357f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1358{
1359 assert_bool(argvars, FALSE);
1360}
1361
1362/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001363 * "assert_inrange(lower, upper[, msg])" function
1364 */
1365 static void
1366f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1367{
1368 assert_inrange(argvars);
1369}
1370
1371/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001372 * "assert_match(pattern, actual[, msg])" function
1373 */
1374 static void
1375f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1376{
1377 assert_match_common(argvars, ASSERT_MATCH);
1378}
1379
1380/*
1381 * "assert_notmatch(pattern, actual[, msg])" function
1382 */
1383 static void
1384f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1385{
1386 assert_match_common(argvars, ASSERT_NOTMATCH);
1387}
1388
1389/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001390 * "assert_report(msg)" function
1391 */
1392 static void
1393f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
1394{
1395 assert_report(argvars);
1396}
1397
1398/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001399 * "assert_true(actual[, msg])" function
1400 */
1401 static void
1402f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1403{
1404 assert_bool(argvars, TRUE);
1405}
1406
1407#ifdef FEAT_FLOAT
1408/*
1409 * "asin()" function
1410 */
1411 static void
1412f_asin(typval_T *argvars, typval_T *rettv)
1413{
1414 float_T f = 0.0;
1415
1416 rettv->v_type = VAR_FLOAT;
1417 if (get_float_arg(argvars, &f) == OK)
1418 rettv->vval.v_float = asin(f);
1419 else
1420 rettv->vval.v_float = 0.0;
1421}
1422
1423/*
1424 * "atan()" function
1425 */
1426 static void
1427f_atan(typval_T *argvars, typval_T *rettv)
1428{
1429 float_T f = 0.0;
1430
1431 rettv->v_type = VAR_FLOAT;
1432 if (get_float_arg(argvars, &f) == OK)
1433 rettv->vval.v_float = atan(f);
1434 else
1435 rettv->vval.v_float = 0.0;
1436}
1437
1438/*
1439 * "atan2()" function
1440 */
1441 static void
1442f_atan2(typval_T *argvars, typval_T *rettv)
1443{
1444 float_T fx = 0.0, fy = 0.0;
1445
1446 rettv->v_type = VAR_FLOAT;
1447 if (get_float_arg(argvars, &fx) == OK
1448 && get_float_arg(&argvars[1], &fy) == OK)
1449 rettv->vval.v_float = atan2(fx, fy);
1450 else
1451 rettv->vval.v_float = 0.0;
1452}
1453#endif
1454
1455/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001456 * "balloon_show()" function
1457 */
1458#ifdef FEAT_BEVAL
1459 static void
1460f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1461{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001462 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001463 {
1464 if (argvars[0].v_type == VAR_LIST
1465# ifdef FEAT_GUI
1466 && !gui.in_use
1467# endif
1468 )
1469 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1470 else
1471 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1472 }
1473}
1474
Bram Moolenaar669a8282017-11-19 20:13:05 +01001475# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001476 static void
1477f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1478{
1479 if (rettv_list_alloc(rettv) == OK)
1480 {
1481 char_u *msg = get_tv_string_chk(&argvars[0]);
1482
1483 if (msg != NULL)
1484 {
1485 pumitem_T *array;
1486 int size = split_message(msg, &array);
1487 int i;
1488
1489 /* Skip the first and last item, they are always empty. */
1490 for (i = 1; i < size - 1; ++i)
1491 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001492 while (size > 0)
1493 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001494 vim_free(array);
1495 }
1496 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001497}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001498# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001499#endif
1500
1501/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502 * "browse(save, title, initdir, default)" function
1503 */
1504 static void
1505f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1506{
1507#ifdef FEAT_BROWSE
1508 int save;
1509 char_u *title;
1510 char_u *initdir;
1511 char_u *defname;
1512 char_u buf[NUMBUFLEN];
1513 char_u buf2[NUMBUFLEN];
1514 int error = FALSE;
1515
1516 save = (int)get_tv_number_chk(&argvars[0], &error);
1517 title = get_tv_string_chk(&argvars[1]);
1518 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1519 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1520
1521 if (error || title == NULL || initdir == NULL || defname == NULL)
1522 rettv->vval.v_string = NULL;
1523 else
1524 rettv->vval.v_string =
1525 do_browse(save ? BROWSE_SAVE : 0,
1526 title, defname, NULL, initdir, NULL, curbuf);
1527#else
1528 rettv->vval.v_string = NULL;
1529#endif
1530 rettv->v_type = VAR_STRING;
1531}
1532
1533/*
1534 * "browsedir(title, initdir)" function
1535 */
1536 static void
1537f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1538{
1539#ifdef FEAT_BROWSE
1540 char_u *title;
1541 char_u *initdir;
1542 char_u buf[NUMBUFLEN];
1543
1544 title = get_tv_string_chk(&argvars[0]);
1545 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1546
1547 if (title == NULL || initdir == NULL)
1548 rettv->vval.v_string = NULL;
1549 else
1550 rettv->vval.v_string = do_browse(BROWSE_DIR,
1551 title, NULL, NULL, initdir, NULL, curbuf);
1552#else
1553 rettv->vval.v_string = NULL;
1554#endif
1555 rettv->v_type = VAR_STRING;
1556}
1557
1558static buf_T *find_buffer(typval_T *avar);
1559
1560/*
1561 * Find a buffer by number or exact name.
1562 */
1563 static buf_T *
1564find_buffer(typval_T *avar)
1565{
1566 buf_T *buf = NULL;
1567
1568 if (avar->v_type == VAR_NUMBER)
1569 buf = buflist_findnr((int)avar->vval.v_number);
1570 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1571 {
1572 buf = buflist_findname_exp(avar->vval.v_string);
1573 if (buf == NULL)
1574 {
1575 /* No full path name match, try a match with a URL or a "nofile"
1576 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001577 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578 if (buf->b_fname != NULL
1579 && (path_with_url(buf->b_fname)
1580#ifdef FEAT_QUICKFIX
1581 || bt_nofile(buf)
1582#endif
1583 )
1584 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1585 break;
1586 }
1587 }
1588 return buf;
1589}
1590
1591/*
1592 * "bufexists(expr)" function
1593 */
1594 static void
1595f_bufexists(typval_T *argvars, typval_T *rettv)
1596{
1597 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1598}
1599
1600/*
1601 * "buflisted(expr)" function
1602 */
1603 static void
1604f_buflisted(typval_T *argvars, typval_T *rettv)
1605{
1606 buf_T *buf;
1607
1608 buf = find_buffer(&argvars[0]);
1609 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1610}
1611
1612/*
1613 * "bufloaded(expr)" function
1614 */
1615 static void
1616f_bufloaded(typval_T *argvars, typval_T *rettv)
1617{
1618 buf_T *buf;
1619
1620 buf = find_buffer(&argvars[0]);
1621 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1622}
1623
1624 buf_T *
1625buflist_find_by_name(char_u *name, int curtab_only)
1626{
1627 int save_magic;
1628 char_u *save_cpo;
1629 buf_T *buf;
1630
1631 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1632 save_magic = p_magic;
1633 p_magic = TRUE;
1634 save_cpo = p_cpo;
1635 p_cpo = (char_u *)"";
1636
1637 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1638 TRUE, FALSE, curtab_only));
1639
1640 p_magic = save_magic;
1641 p_cpo = save_cpo;
1642 return buf;
1643}
1644
1645/*
1646 * Get buffer by number or pattern.
1647 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001648 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649get_buf_tv(typval_T *tv, int curtab_only)
1650{
1651 char_u *name = tv->vval.v_string;
1652 buf_T *buf;
1653
1654 if (tv->v_type == VAR_NUMBER)
1655 return buflist_findnr((int)tv->vval.v_number);
1656 if (tv->v_type != VAR_STRING)
1657 return NULL;
1658 if (name == NULL || *name == NUL)
1659 return curbuf;
1660 if (name[0] == '$' && name[1] == NUL)
1661 return lastbuf;
1662
1663 buf = buflist_find_by_name(name, curtab_only);
1664
1665 /* If not found, try expanding the name, like done for bufexists(). */
1666 if (buf == NULL)
1667 buf = find_buffer(tv);
1668
1669 return buf;
1670}
1671
1672/*
1673 * "bufname(expr)" function
1674 */
1675 static void
1676f_bufname(typval_T *argvars, typval_T *rettv)
1677{
1678 buf_T *buf;
1679
1680 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1681 ++emsg_off;
1682 buf = get_buf_tv(&argvars[0], FALSE);
1683 rettv->v_type = VAR_STRING;
1684 if (buf != NULL && buf->b_fname != NULL)
1685 rettv->vval.v_string = vim_strsave(buf->b_fname);
1686 else
1687 rettv->vval.v_string = NULL;
1688 --emsg_off;
1689}
1690
1691/*
1692 * "bufnr(expr)" function
1693 */
1694 static void
1695f_bufnr(typval_T *argvars, typval_T *rettv)
1696{
1697 buf_T *buf;
1698 int error = FALSE;
1699 char_u *name;
1700
1701 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1702 ++emsg_off;
1703 buf = get_buf_tv(&argvars[0], FALSE);
1704 --emsg_off;
1705
1706 /* If the buffer isn't found and the second argument is not zero create a
1707 * new buffer. */
1708 if (buf == NULL
1709 && argvars[1].v_type != VAR_UNKNOWN
1710 && get_tv_number_chk(&argvars[1], &error) != 0
1711 && !error
1712 && (name = get_tv_string_chk(&argvars[0])) != NULL
1713 && !error)
1714 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1715
1716 if (buf != NULL)
1717 rettv->vval.v_number = buf->b_fnum;
1718 else
1719 rettv->vval.v_number = -1;
1720}
1721
1722 static void
1723buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1724{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 win_T *wp;
1726 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727 buf_T *buf;
1728
1729 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1730 ++emsg_off;
1731 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001732 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001733 {
1734 ++winnr;
1735 if (wp->w_buffer == buf)
1736 break;
1737 }
1738 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001739 --emsg_off;
1740}
1741
1742/*
1743 * "bufwinid(nr)" function
1744 */
1745 static void
1746f_bufwinid(typval_T *argvars, typval_T *rettv)
1747{
1748 buf_win_common(argvars, rettv, FALSE);
1749}
1750
1751/*
1752 * "bufwinnr(nr)" function
1753 */
1754 static void
1755f_bufwinnr(typval_T *argvars, typval_T *rettv)
1756{
1757 buf_win_common(argvars, rettv, TRUE);
1758}
1759
1760/*
1761 * "byte2line(byte)" function
1762 */
1763 static void
1764f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1765{
1766#ifndef FEAT_BYTEOFF
1767 rettv->vval.v_number = -1;
1768#else
1769 long boff = 0;
1770
1771 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1772 if (boff < 0)
1773 rettv->vval.v_number = -1;
1774 else
1775 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1776 (linenr_T)0, &boff);
1777#endif
1778}
1779
1780 static void
1781byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1782{
1783#ifdef FEAT_MBYTE
1784 char_u *t;
1785#endif
1786 char_u *str;
1787 varnumber_T idx;
1788
1789 str = get_tv_string_chk(&argvars[0]);
1790 idx = get_tv_number_chk(&argvars[1], NULL);
1791 rettv->vval.v_number = -1;
1792 if (str == NULL || idx < 0)
1793 return;
1794
1795#ifdef FEAT_MBYTE
1796 t = str;
1797 for ( ; idx > 0; idx--)
1798 {
1799 if (*t == NUL) /* EOL reached */
1800 return;
1801 if (enc_utf8 && comp)
1802 t += utf_ptr2len(t);
1803 else
1804 t += (*mb_ptr2len)(t);
1805 }
1806 rettv->vval.v_number = (varnumber_T)(t - str);
1807#else
1808 if ((size_t)idx <= STRLEN(str))
1809 rettv->vval.v_number = idx;
1810#endif
1811}
1812
1813/*
1814 * "byteidx()" function
1815 */
1816 static void
1817f_byteidx(typval_T *argvars, typval_T *rettv)
1818{
1819 byteidx(argvars, rettv, FALSE);
1820}
1821
1822/*
1823 * "byteidxcomp()" function
1824 */
1825 static void
1826f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1827{
1828 byteidx(argvars, rettv, TRUE);
1829}
1830
1831/*
1832 * "call(func, arglist [, dict])" function
1833 */
1834 static void
1835f_call(typval_T *argvars, typval_T *rettv)
1836{
1837 char_u *func;
1838 partial_T *partial = NULL;
1839 dict_T *selfdict = NULL;
1840
1841 if (argvars[1].v_type != VAR_LIST)
1842 {
1843 EMSG(_(e_listreq));
1844 return;
1845 }
1846 if (argvars[1].vval.v_list == NULL)
1847 return;
1848
1849 if (argvars[0].v_type == VAR_FUNC)
1850 func = argvars[0].vval.v_string;
1851 else if (argvars[0].v_type == VAR_PARTIAL)
1852 {
1853 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001854 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001855 }
1856 else
1857 func = get_tv_string(&argvars[0]);
1858 if (*func == NUL)
1859 return; /* type error or empty name */
1860
1861 if (argvars[2].v_type != VAR_UNKNOWN)
1862 {
1863 if (argvars[2].v_type != VAR_DICT)
1864 {
1865 EMSG(_(e_dictreq));
1866 return;
1867 }
1868 selfdict = argvars[2].vval.v_dict;
1869 }
1870
1871 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1872}
1873
1874#ifdef FEAT_FLOAT
1875/*
1876 * "ceil({float})" function
1877 */
1878 static void
1879f_ceil(typval_T *argvars, typval_T *rettv)
1880{
1881 float_T f = 0.0;
1882
1883 rettv->v_type = VAR_FLOAT;
1884 if (get_float_arg(argvars, &f) == OK)
1885 rettv->vval.v_float = ceil(f);
1886 else
1887 rettv->vval.v_float = 0.0;
1888}
1889#endif
1890
1891#ifdef FEAT_JOB_CHANNEL
1892/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001893 * "ch_canread()" function
1894 */
1895 static void
1896f_ch_canread(typval_T *argvars, typval_T *rettv)
1897{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001898 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001899
1900 rettv->vval.v_number = 0;
1901 if (channel != NULL)
1902 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1903 || channel_has_readahead(channel, PART_OUT)
1904 || channel_has_readahead(channel, PART_ERR);
1905}
1906
1907/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908 * "ch_close()" function
1909 */
1910 static void
1911f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1912{
1913 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1914
1915 if (channel != NULL)
1916 {
1917 channel_close(channel, FALSE);
1918 channel_clear(channel);
1919 }
1920}
1921
1922/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001923 * "ch_close()" function
1924 */
1925 static void
1926f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1927{
1928 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1929
1930 if (channel != NULL)
1931 channel_close_in(channel);
1932}
1933
1934/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935 * "ch_getbufnr()" function
1936 */
1937 static void
1938f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1939{
1940 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1941
1942 rettv->vval.v_number = -1;
1943 if (channel != NULL)
1944 {
1945 char_u *what = get_tv_string(&argvars[1]);
1946 int part;
1947
1948 if (STRCMP(what, "err") == 0)
1949 part = PART_ERR;
1950 else if (STRCMP(what, "out") == 0)
1951 part = PART_OUT;
1952 else if (STRCMP(what, "in") == 0)
1953 part = PART_IN;
1954 else
1955 part = PART_SOCK;
1956 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1957 rettv->vval.v_number =
1958 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1959 }
1960}
1961
1962/*
1963 * "ch_getjob()" function
1964 */
1965 static void
1966f_ch_getjob(typval_T *argvars, typval_T *rettv)
1967{
1968 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1969
1970 if (channel != NULL)
1971 {
1972 rettv->v_type = VAR_JOB;
1973 rettv->vval.v_job = channel->ch_job;
1974 if (channel->ch_job != NULL)
1975 ++channel->ch_job->jv_refcount;
1976 }
1977}
1978
1979/*
1980 * "ch_info()" function
1981 */
1982 static void
1983f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1984{
1985 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1986
1987 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1988 channel_info(channel, rettv->vval.v_dict);
1989}
1990
1991/*
1992 * "ch_log()" function
1993 */
1994 static void
1995f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1996{
1997 char_u *msg = get_tv_string(&argvars[0]);
1998 channel_T *channel = NULL;
1999
2000 if (argvars[1].v_type != VAR_UNKNOWN)
2001 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2002
Bram Moolenaard5359b22018-04-05 22:44:39 +02002003 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004}
2005
2006/*
2007 * "ch_logfile()" function
2008 */
2009 static void
2010f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2011{
2012 char_u *fname;
2013 char_u *opt = (char_u *)"";
2014 char_u buf[NUMBUFLEN];
2015
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002016 /* Don't open a file in restricted mode. */
2017 if (check_restricted() || check_secure())
2018 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 fname = get_tv_string(&argvars[0]);
2020 if (argvars[1].v_type == VAR_STRING)
2021 opt = get_tv_string_buf(&argvars[1], buf);
2022 ch_logfile(fname, opt);
2023}
2024
2025/*
2026 * "ch_open()" function
2027 */
2028 static void
2029f_ch_open(typval_T *argvars, typval_T *rettv)
2030{
2031 rettv->v_type = VAR_CHANNEL;
2032 if (check_restricted() || check_secure())
2033 return;
2034 rettv->vval.v_channel = channel_open_func(argvars);
2035}
2036
2037/*
2038 * "ch_read()" function
2039 */
2040 static void
2041f_ch_read(typval_T *argvars, typval_T *rettv)
2042{
2043 common_channel_read(argvars, rettv, FALSE);
2044}
2045
2046/*
2047 * "ch_readraw()" function
2048 */
2049 static void
2050f_ch_readraw(typval_T *argvars, typval_T *rettv)
2051{
2052 common_channel_read(argvars, rettv, TRUE);
2053}
2054
2055/*
2056 * "ch_evalexpr()" function
2057 */
2058 static void
2059f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2060{
2061 ch_expr_common(argvars, rettv, TRUE);
2062}
2063
2064/*
2065 * "ch_sendexpr()" function
2066 */
2067 static void
2068f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2069{
2070 ch_expr_common(argvars, rettv, FALSE);
2071}
2072
2073/*
2074 * "ch_evalraw()" function
2075 */
2076 static void
2077f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2078{
2079 ch_raw_common(argvars, rettv, TRUE);
2080}
2081
2082/*
2083 * "ch_sendraw()" function
2084 */
2085 static void
2086f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2087{
2088 ch_raw_common(argvars, rettv, FALSE);
2089}
2090
2091/*
2092 * "ch_setoptions()" function
2093 */
2094 static void
2095f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2096{
2097 channel_T *channel;
2098 jobopt_T opt;
2099
2100 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2101 if (channel == NULL)
2102 return;
2103 clear_job_options(&opt);
2104 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002105 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002106 channel_set_options(channel, &opt);
2107 free_job_options(&opt);
2108}
2109
2110/*
2111 * "ch_status()" function
2112 */
2113 static void
2114f_ch_status(typval_T *argvars, typval_T *rettv)
2115{
2116 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002117 jobopt_T opt;
2118 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002119
2120 /* return an empty string by default */
2121 rettv->v_type = VAR_STRING;
2122 rettv->vval.v_string = NULL;
2123
2124 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002125
2126 if (argvars[1].v_type != VAR_UNKNOWN)
2127 {
2128 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002129 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002130 && (opt.jo_set & JO_PART))
2131 part = opt.jo_part;
2132 }
2133
2134 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135}
2136#endif
2137
2138/*
2139 * "changenr()" function
2140 */
2141 static void
2142f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2143{
2144 rettv->vval.v_number = curbuf->b_u_seq_cur;
2145}
2146
2147/*
2148 * "char2nr(string)" function
2149 */
2150 static void
2151f_char2nr(typval_T *argvars, typval_T *rettv)
2152{
2153#ifdef FEAT_MBYTE
2154 if (has_mbyte)
2155 {
2156 int utf8 = 0;
2157
2158 if (argvars[1].v_type != VAR_UNKNOWN)
2159 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2160
2161 if (utf8)
2162 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2163 else
2164 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2165 }
2166 else
2167#endif
2168 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2169}
2170
2171/*
2172 * "cindent(lnum)" function
2173 */
2174 static void
2175f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2176{
2177#ifdef FEAT_CINDENT
2178 pos_T pos;
2179 linenr_T lnum;
2180
2181 pos = curwin->w_cursor;
2182 lnum = get_tv_lnum(argvars);
2183 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2184 {
2185 curwin->w_cursor.lnum = lnum;
2186 rettv->vval.v_number = get_c_indent();
2187 curwin->w_cursor = pos;
2188 }
2189 else
2190#endif
2191 rettv->vval.v_number = -1;
2192}
2193
2194/*
2195 * "clearmatches()" function
2196 */
2197 static void
2198f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2199{
2200#ifdef FEAT_SEARCH_EXTRA
2201 clear_matches(curwin);
2202#endif
2203}
2204
2205/*
2206 * "col(string)" function
2207 */
2208 static void
2209f_col(typval_T *argvars, typval_T *rettv)
2210{
2211 colnr_T col = 0;
2212 pos_T *fp;
2213 int fnum = curbuf->b_fnum;
2214
2215 fp = var2fpos(&argvars[0], FALSE, &fnum);
2216 if (fp != NULL && fnum == curbuf->b_fnum)
2217 {
2218 if (fp->col == MAXCOL)
2219 {
2220 /* '> can be MAXCOL, get the length of the line then */
2221 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2222 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2223 else
2224 col = MAXCOL;
2225 }
2226 else
2227 {
2228 col = fp->col + 1;
2229#ifdef FEAT_VIRTUALEDIT
2230 /* col(".") when the cursor is on the NUL at the end of the line
2231 * because of "coladd" can be seen as an extra column. */
2232 if (virtual_active() && fp == &curwin->w_cursor)
2233 {
2234 char_u *p = ml_get_cursor();
2235
2236 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2237 curwin->w_virtcol - curwin->w_cursor.coladd))
2238 {
2239# ifdef FEAT_MBYTE
2240 int l;
2241
2242 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2243 col += l;
2244# else
2245 if (*p != NUL && p[1] == NUL)
2246 ++col;
2247# endif
2248 }
2249 }
2250#endif
2251 }
2252 }
2253 rettv->vval.v_number = col;
2254}
2255
2256#if defined(FEAT_INS_EXPAND)
2257/*
2258 * "complete()" function
2259 */
2260 static void
2261f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2262{
2263 int startcol;
2264
2265 if ((State & INSERT) == 0)
2266 {
2267 EMSG(_("E785: complete() can only be used in Insert mode"));
2268 return;
2269 }
2270
2271 /* Check for undo allowed here, because if something was already inserted
2272 * the line was already saved for undo and this check isn't done. */
2273 if (!undo_allowed())
2274 return;
2275
2276 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2277 {
2278 EMSG(_(e_invarg));
2279 return;
2280 }
2281
2282 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2283 if (startcol <= 0)
2284 return;
2285
2286 set_completion(startcol - 1, argvars[1].vval.v_list);
2287}
2288
2289/*
2290 * "complete_add()" function
2291 */
2292 static void
2293f_complete_add(typval_T *argvars, typval_T *rettv)
2294{
2295 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2296}
2297
2298/*
2299 * "complete_check()" function
2300 */
2301 static void
2302f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2303{
2304 int saved = RedrawingDisabled;
2305
2306 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002307 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 rettv->vval.v_number = compl_interrupted;
2309 RedrawingDisabled = saved;
2310}
2311#endif
2312
2313/*
2314 * "confirm(message, buttons[, default [, type]])" function
2315 */
2316 static void
2317f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2318{
2319#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2320 char_u *message;
2321 char_u *buttons = NULL;
2322 char_u buf[NUMBUFLEN];
2323 char_u buf2[NUMBUFLEN];
2324 int def = 1;
2325 int type = VIM_GENERIC;
2326 char_u *typestr;
2327 int error = FALSE;
2328
2329 message = get_tv_string_chk(&argvars[0]);
2330 if (message == NULL)
2331 error = TRUE;
2332 if (argvars[1].v_type != VAR_UNKNOWN)
2333 {
2334 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2335 if (buttons == NULL)
2336 error = TRUE;
2337 if (argvars[2].v_type != VAR_UNKNOWN)
2338 {
2339 def = (int)get_tv_number_chk(&argvars[2], &error);
2340 if (argvars[3].v_type != VAR_UNKNOWN)
2341 {
2342 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2343 if (typestr == NULL)
2344 error = TRUE;
2345 else
2346 {
2347 switch (TOUPPER_ASC(*typestr))
2348 {
2349 case 'E': type = VIM_ERROR; break;
2350 case 'Q': type = VIM_QUESTION; break;
2351 case 'I': type = VIM_INFO; break;
2352 case 'W': type = VIM_WARNING; break;
2353 case 'G': type = VIM_GENERIC; break;
2354 }
2355 }
2356 }
2357 }
2358 }
2359
2360 if (buttons == NULL || *buttons == NUL)
2361 buttons = (char_u *)_("&Ok");
2362
2363 if (!error)
2364 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2365 def, NULL, FALSE);
2366#endif
2367}
2368
2369/*
2370 * "copy()" function
2371 */
2372 static void
2373f_copy(typval_T *argvars, typval_T *rettv)
2374{
2375 item_copy(&argvars[0], rettv, FALSE, 0);
2376}
2377
2378#ifdef FEAT_FLOAT
2379/*
2380 * "cos()" function
2381 */
2382 static void
2383f_cos(typval_T *argvars, typval_T *rettv)
2384{
2385 float_T f = 0.0;
2386
2387 rettv->v_type = VAR_FLOAT;
2388 if (get_float_arg(argvars, &f) == OK)
2389 rettv->vval.v_float = cos(f);
2390 else
2391 rettv->vval.v_float = 0.0;
2392}
2393
2394/*
2395 * "cosh()" function
2396 */
2397 static void
2398f_cosh(typval_T *argvars, typval_T *rettv)
2399{
2400 float_T f = 0.0;
2401
2402 rettv->v_type = VAR_FLOAT;
2403 if (get_float_arg(argvars, &f) == OK)
2404 rettv->vval.v_float = cosh(f);
2405 else
2406 rettv->vval.v_float = 0.0;
2407}
2408#endif
2409
2410/*
2411 * "count()" function
2412 */
2413 static void
2414f_count(typval_T *argvars, typval_T *rettv)
2415{
2416 long n = 0;
2417 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002418 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419
Bram Moolenaar9966b212017-07-28 16:46:57 +02002420 if (argvars[2].v_type != VAR_UNKNOWN)
2421 ic = (int)get_tv_number_chk(&argvars[2], &error);
2422
2423 if (argvars[0].v_type == VAR_STRING)
2424 {
2425 char_u *expr = get_tv_string_chk(&argvars[1]);
2426 char_u *p = argvars[0].vval.v_string;
2427 char_u *next;
2428
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002429 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002430 {
2431 if (ic)
2432 {
2433 size_t len = STRLEN(expr);
2434
2435 while (*p != NUL)
2436 {
2437 if (MB_STRNICMP(p, expr, len) == 0)
2438 {
2439 ++n;
2440 p += len;
2441 }
2442 else
2443 MB_PTR_ADV(p);
2444 }
2445 }
2446 else
2447 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2448 != NULL)
2449 {
2450 ++n;
2451 p = next + STRLEN(expr);
2452 }
2453 }
2454
2455 }
2456 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457 {
2458 listitem_T *li;
2459 list_T *l;
2460 long idx;
2461
2462 if ((l = argvars[0].vval.v_list) != NULL)
2463 {
2464 li = l->lv_first;
2465 if (argvars[2].v_type != VAR_UNKNOWN)
2466 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467 if (argvars[3].v_type != VAR_UNKNOWN)
2468 {
2469 idx = (long)get_tv_number_chk(&argvars[3], &error);
2470 if (!error)
2471 {
2472 li = list_find(l, idx);
2473 if (li == NULL)
2474 EMSGN(_(e_listidx), idx);
2475 }
2476 }
2477 if (error)
2478 li = NULL;
2479 }
2480
2481 for ( ; li != NULL; li = li->li_next)
2482 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2483 ++n;
2484 }
2485 }
2486 else if (argvars[0].v_type == VAR_DICT)
2487 {
2488 int todo;
2489 dict_T *d;
2490 hashitem_T *hi;
2491
2492 if ((d = argvars[0].vval.v_dict) != NULL)
2493 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002494 if (argvars[2].v_type != VAR_UNKNOWN)
2495 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496 if (argvars[3].v_type != VAR_UNKNOWN)
2497 EMSG(_(e_invarg));
2498 }
2499
2500 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2501 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2502 {
2503 if (!HASHITEM_EMPTY(hi))
2504 {
2505 --todo;
2506 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2507 ++n;
2508 }
2509 }
2510 }
2511 }
2512 else
2513 EMSG2(_(e_listdictarg), "count()");
2514 rettv->vval.v_number = n;
2515}
2516
2517/*
2518 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2519 *
2520 * Checks the existence of a cscope connection.
2521 */
2522 static void
2523f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2524{
2525#ifdef FEAT_CSCOPE
2526 int num = 0;
2527 char_u *dbpath = NULL;
2528 char_u *prepend = NULL;
2529 char_u buf[NUMBUFLEN];
2530
2531 if (argvars[0].v_type != VAR_UNKNOWN
2532 && argvars[1].v_type != VAR_UNKNOWN)
2533 {
2534 num = (int)get_tv_number(&argvars[0]);
2535 dbpath = get_tv_string(&argvars[1]);
2536 if (argvars[2].v_type != VAR_UNKNOWN)
2537 prepend = get_tv_string_buf(&argvars[2], buf);
2538 }
2539
2540 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2541#endif
2542}
2543
2544/*
2545 * "cursor(lnum, col)" function, or
2546 * "cursor(list)"
2547 *
2548 * Moves the cursor to the specified line and column.
2549 * Returns 0 when the position could be set, -1 otherwise.
2550 */
2551 static void
2552f_cursor(typval_T *argvars, typval_T *rettv)
2553{
2554 long line, col;
2555#ifdef FEAT_VIRTUALEDIT
2556 long coladd = 0;
2557#endif
2558 int set_curswant = TRUE;
2559
2560 rettv->vval.v_number = -1;
2561 if (argvars[1].v_type == VAR_UNKNOWN)
2562 {
2563 pos_T pos;
2564 colnr_T curswant = -1;
2565
2566 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2567 {
2568 EMSG(_(e_invarg));
2569 return;
2570 }
2571 line = pos.lnum;
2572 col = pos.col;
2573#ifdef FEAT_VIRTUALEDIT
2574 coladd = pos.coladd;
2575#endif
2576 if (curswant >= 0)
2577 {
2578 curwin->w_curswant = curswant - 1;
2579 set_curswant = FALSE;
2580 }
2581 }
2582 else
2583 {
2584 line = get_tv_lnum(argvars);
2585 col = (long)get_tv_number_chk(&argvars[1], NULL);
2586#ifdef FEAT_VIRTUALEDIT
2587 if (argvars[2].v_type != VAR_UNKNOWN)
2588 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2589#endif
2590 }
2591 if (line < 0 || col < 0
2592#ifdef FEAT_VIRTUALEDIT
2593 || coladd < 0
2594#endif
2595 )
2596 return; /* type error; errmsg already given */
2597 if (line > 0)
2598 curwin->w_cursor.lnum = line;
2599 if (col > 0)
2600 curwin->w_cursor.col = col - 1;
2601#ifdef FEAT_VIRTUALEDIT
2602 curwin->w_cursor.coladd = coladd;
2603#endif
2604
2605 /* Make sure the cursor is in a valid position. */
2606 check_cursor();
2607#ifdef FEAT_MBYTE
2608 /* Correct cursor for multi-byte character. */
2609 if (has_mbyte)
2610 mb_adjust_cursor();
2611#endif
2612
2613 curwin->w_set_curswant = set_curswant;
2614 rettv->vval.v_number = 0;
2615}
2616
2617/*
2618 * "deepcopy()" function
2619 */
2620 static void
2621f_deepcopy(typval_T *argvars, typval_T *rettv)
2622{
2623 int noref = 0;
2624 int copyID;
2625
2626 if (argvars[1].v_type != VAR_UNKNOWN)
2627 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2628 if (noref < 0 || noref > 1)
2629 EMSG(_(e_invarg));
2630 else
2631 {
2632 copyID = get_copyID();
2633 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2634 }
2635}
2636
2637/*
2638 * "delete()" function
2639 */
2640 static void
2641f_delete(typval_T *argvars, typval_T *rettv)
2642{
2643 char_u nbuf[NUMBUFLEN];
2644 char_u *name;
2645 char_u *flags;
2646
2647 rettv->vval.v_number = -1;
2648 if (check_restricted() || check_secure())
2649 return;
2650
2651 name = get_tv_string(&argvars[0]);
2652 if (name == NULL || *name == NUL)
2653 {
2654 EMSG(_(e_invarg));
2655 return;
2656 }
2657
2658 if (argvars[1].v_type != VAR_UNKNOWN)
2659 flags = get_tv_string_buf(&argvars[1], nbuf);
2660 else
2661 flags = (char_u *)"";
2662
2663 if (*flags == NUL)
2664 /* delete a file */
2665 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2666 else if (STRCMP(flags, "d") == 0)
2667 /* delete an empty directory */
2668 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2669 else if (STRCMP(flags, "rf") == 0)
2670 /* delete a directory recursively */
2671 rettv->vval.v_number = delete_recursive(name);
2672 else
2673 EMSG2(_(e_invexpr2), flags);
2674}
2675
2676/*
2677 * "did_filetype()" function
2678 */
2679 static void
2680f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2681{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002683}
2684
2685/*
2686 * "diff_filler()" function
2687 */
2688 static void
2689f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2690{
2691#ifdef FEAT_DIFF
2692 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2693#endif
2694}
2695
2696/*
2697 * "diff_hlID()" function
2698 */
2699 static void
2700f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2701{
2702#ifdef FEAT_DIFF
2703 linenr_T lnum = get_tv_lnum(argvars);
2704 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002705 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706 static int fnum = 0;
2707 static int change_start = 0;
2708 static int change_end = 0;
2709 static hlf_T hlID = (hlf_T)0;
2710 int filler_lines;
2711 int col;
2712
2713 if (lnum < 0) /* ignore type error in {lnum} arg */
2714 lnum = 0;
2715 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002716 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002717 || fnum != curbuf->b_fnum)
2718 {
2719 /* New line, buffer, change: need to get the values. */
2720 filler_lines = diff_check(curwin, lnum);
2721 if (filler_lines < 0)
2722 {
2723 if (filler_lines == -1)
2724 {
2725 change_start = MAXCOL;
2726 change_end = -1;
2727 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2728 hlID = HLF_ADD; /* added line */
2729 else
2730 hlID = HLF_CHD; /* changed line */
2731 }
2732 else
2733 hlID = HLF_ADD; /* added line */
2734 }
2735 else
2736 hlID = (hlf_T)0;
2737 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002738 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002739 fnum = curbuf->b_fnum;
2740 }
2741
2742 if (hlID == HLF_CHD || hlID == HLF_TXD)
2743 {
2744 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2745 if (col >= change_start && col <= change_end)
2746 hlID = HLF_TXD; /* changed text */
2747 else
2748 hlID = HLF_CHD; /* changed line */
2749 }
2750 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2751#endif
2752}
2753
2754/*
2755 * "empty({expr})" function
2756 */
2757 static void
2758f_empty(typval_T *argvars, typval_T *rettv)
2759{
2760 int n = FALSE;
2761
2762 switch (argvars[0].v_type)
2763 {
2764 case VAR_STRING:
2765 case VAR_FUNC:
2766 n = argvars[0].vval.v_string == NULL
2767 || *argvars[0].vval.v_string == NUL;
2768 break;
2769 case VAR_PARTIAL:
2770 n = FALSE;
2771 break;
2772 case VAR_NUMBER:
2773 n = argvars[0].vval.v_number == 0;
2774 break;
2775 case VAR_FLOAT:
2776#ifdef FEAT_FLOAT
2777 n = argvars[0].vval.v_float == 0.0;
2778 break;
2779#endif
2780 case VAR_LIST:
2781 n = argvars[0].vval.v_list == NULL
2782 || argvars[0].vval.v_list->lv_first == NULL;
2783 break;
2784 case VAR_DICT:
2785 n = argvars[0].vval.v_dict == NULL
2786 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2787 break;
2788 case VAR_SPECIAL:
2789 n = argvars[0].vval.v_number != VVAL_TRUE;
2790 break;
2791
2792 case VAR_JOB:
2793#ifdef FEAT_JOB_CHANNEL
2794 n = argvars[0].vval.v_job == NULL
2795 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2796 break;
2797#endif
2798 case VAR_CHANNEL:
2799#ifdef FEAT_JOB_CHANNEL
2800 n = argvars[0].vval.v_channel == NULL
2801 || !channel_is_open(argvars[0].vval.v_channel);
2802 break;
2803#endif
2804 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002805 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002806 n = TRUE;
2807 break;
2808 }
2809
2810 rettv->vval.v_number = n;
2811}
2812
2813/*
2814 * "escape({string}, {chars})" function
2815 */
2816 static void
2817f_escape(typval_T *argvars, typval_T *rettv)
2818{
2819 char_u buf[NUMBUFLEN];
2820
2821 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2822 get_tv_string_buf(&argvars[1], buf));
2823 rettv->v_type = VAR_STRING;
2824}
2825
2826/*
2827 * "eval()" function
2828 */
2829 static void
2830f_eval(typval_T *argvars, typval_T *rettv)
2831{
2832 char_u *s, *p;
2833
2834 s = get_tv_string_chk(&argvars[0]);
2835 if (s != NULL)
2836 s = skipwhite(s);
2837
2838 p = s;
2839 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2840 {
2841 if (p != NULL && !aborting())
2842 EMSG2(_(e_invexpr2), p);
2843 need_clr_eos = FALSE;
2844 rettv->v_type = VAR_NUMBER;
2845 rettv->vval.v_number = 0;
2846 }
2847 else if (*s != NUL)
2848 EMSG(_(e_trailing));
2849}
2850
2851/*
2852 * "eventhandler()" function
2853 */
2854 static void
2855f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2856{
2857 rettv->vval.v_number = vgetc_busy;
2858}
2859
2860/*
2861 * "executable()" function
2862 */
2863 static void
2864f_executable(typval_T *argvars, typval_T *rettv)
2865{
2866 char_u *name = get_tv_string(&argvars[0]);
2867
2868 /* Check in $PATH and also check directly if there is a directory name. */
2869 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2870 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2871}
2872
2873static garray_T redir_execute_ga;
2874
2875/*
2876 * Append "value[value_len]" to the execute() output.
2877 */
2878 void
2879execute_redir_str(char_u *value, int value_len)
2880{
2881 int len;
2882
2883 if (value_len == -1)
2884 len = (int)STRLEN(value); /* Append the entire string */
2885 else
2886 len = value_len; /* Append only "value_len" characters */
2887 if (ga_grow(&redir_execute_ga, len) == OK)
2888 {
2889 mch_memmove((char *)redir_execute_ga.ga_data
2890 + redir_execute_ga.ga_len, value, len);
2891 redir_execute_ga.ga_len += len;
2892 }
2893}
2894
2895/*
2896 * Get next line from a list.
2897 * Called by do_cmdline() to get the next line.
2898 * Returns allocated string, or NULL for end of function.
2899 */
2900
2901 static char_u *
2902get_list_line(
2903 int c UNUSED,
2904 void *cookie,
2905 int indent UNUSED)
2906{
2907 listitem_T **p = (listitem_T **)cookie;
2908 listitem_T *item = *p;
2909 char_u buf[NUMBUFLEN];
2910 char_u *s;
2911
2912 if (item == NULL)
2913 return NULL;
2914 s = get_tv_string_buf_chk(&item->li_tv, buf);
2915 *p = item->li_next;
2916 return s == NULL ? NULL : vim_strsave(s);
2917}
2918
2919/*
2920 * "execute()" function
2921 */
2922 static void
2923f_execute(typval_T *argvars, typval_T *rettv)
2924{
2925 char_u *cmd = NULL;
2926 list_T *list = NULL;
2927 int save_msg_silent = msg_silent;
2928 int save_emsg_silent = emsg_silent;
2929 int save_emsg_noredir = emsg_noredir;
2930 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002931 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002932 garray_T save_ga;
2933
2934 rettv->vval.v_string = NULL;
2935 rettv->v_type = VAR_STRING;
2936
2937 if (argvars[0].v_type == VAR_LIST)
2938 {
2939 list = argvars[0].vval.v_list;
2940 if (list == NULL || list->lv_first == NULL)
2941 /* empty list, no commands, empty output */
2942 return;
2943 ++list->lv_refcount;
2944 }
2945 else
2946 {
2947 cmd = get_tv_string_chk(&argvars[0]);
2948 if (cmd == NULL)
2949 return;
2950 }
2951
2952 if (argvars[1].v_type != VAR_UNKNOWN)
2953 {
2954 char_u buf[NUMBUFLEN];
2955 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2956
2957 if (s == NULL)
2958 return;
2959 if (STRNCMP(s, "silent", 6) == 0)
2960 ++msg_silent;
2961 if (STRCMP(s, "silent!") == 0)
2962 {
2963 emsg_silent = TRUE;
2964 emsg_noredir = TRUE;
2965 }
2966 }
2967 else
2968 ++msg_silent;
2969
2970 if (redir_execute)
2971 save_ga = redir_execute_ga;
2972 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2973 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002974 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975
2976 if (cmd != NULL)
2977 do_cmdline_cmd(cmd);
2978 else
2979 {
2980 listitem_T *item = list->lv_first;
2981
2982 do_cmdline(NULL, get_list_line, (void *)&item,
2983 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2984 --list->lv_refcount;
2985 }
2986
Bram Moolenaard297f352017-01-29 20:31:21 +01002987 /* Need to append a NUL to the result. */
2988 if (ga_grow(&redir_execute_ga, 1) == OK)
2989 {
2990 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2991 rettv->vval.v_string = redir_execute_ga.ga_data;
2992 }
2993 else
2994 {
2995 ga_clear(&redir_execute_ga);
2996 rettv->vval.v_string = NULL;
2997 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002998 msg_silent = save_msg_silent;
2999 emsg_silent = save_emsg_silent;
3000 emsg_noredir = save_emsg_noredir;
3001
3002 redir_execute = save_redir_execute;
3003 if (redir_execute)
3004 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003005 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006
3007 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3008 * line. Put it back in the first column. */
3009 msg_col = 0;
3010}
3011
3012/*
3013 * "exepath()" function
3014 */
3015 static void
3016f_exepath(typval_T *argvars, typval_T *rettv)
3017{
3018 char_u *p = NULL;
3019
3020 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3021 rettv->v_type = VAR_STRING;
3022 rettv->vval.v_string = p;
3023}
3024
3025/*
3026 * "exists()" function
3027 */
3028 static void
3029f_exists(typval_T *argvars, typval_T *rettv)
3030{
3031 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003032 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003033
3034 p = get_tv_string(&argvars[0]);
3035 if (*p == '$') /* environment variable */
3036 {
3037 /* first try "normal" environment variables (fast) */
3038 if (mch_getenv(p + 1) != NULL)
3039 n = TRUE;
3040 else
3041 {
3042 /* try expanding things like $VIM and ${HOME} */
3043 p = expand_env_save(p);
3044 if (p != NULL && *p != '$')
3045 n = TRUE;
3046 vim_free(p);
3047 }
3048 }
3049 else if (*p == '&' || *p == '+') /* option */
3050 {
3051 n = (get_option_tv(&p, NULL, TRUE) == OK);
3052 if (*skipwhite(p) != NUL)
3053 n = FALSE; /* trailing garbage */
3054 }
3055 else if (*p == '*') /* internal or user defined function */
3056 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003057 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 }
3059 else if (*p == ':')
3060 {
3061 n = cmd_exists(p + 1);
3062 }
3063 else if (*p == '#')
3064 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065 if (p[1] == '#')
3066 n = autocmd_supported(p + 2);
3067 else
3068 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003069 }
3070 else /* internal variable */
3071 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003072 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 }
3074
3075 rettv->vval.v_number = n;
3076}
3077
3078#ifdef FEAT_FLOAT
3079/*
3080 * "exp()" function
3081 */
3082 static void
3083f_exp(typval_T *argvars, typval_T *rettv)
3084{
3085 float_T f = 0.0;
3086
3087 rettv->v_type = VAR_FLOAT;
3088 if (get_float_arg(argvars, &f) == OK)
3089 rettv->vval.v_float = exp(f);
3090 else
3091 rettv->vval.v_float = 0.0;
3092}
3093#endif
3094
3095/*
3096 * "expand()" function
3097 */
3098 static void
3099f_expand(typval_T *argvars, typval_T *rettv)
3100{
3101 char_u *s;
3102 int len;
3103 char_u *errormsg;
3104 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3105 expand_T xpc;
3106 int error = FALSE;
3107 char_u *result;
3108
3109 rettv->v_type = VAR_STRING;
3110 if (argvars[1].v_type != VAR_UNKNOWN
3111 && argvars[2].v_type != VAR_UNKNOWN
3112 && get_tv_number_chk(&argvars[2], &error)
3113 && !error)
3114 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003115 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003116 }
3117
3118 s = get_tv_string(&argvars[0]);
3119 if (*s == '%' || *s == '#' || *s == '<')
3120 {
3121 ++emsg_off;
3122 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3123 --emsg_off;
3124 if (rettv->v_type == VAR_LIST)
3125 {
3126 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3127 list_append_string(rettv->vval.v_list, result, -1);
3128 else
3129 vim_free(result);
3130 }
3131 else
3132 rettv->vval.v_string = result;
3133 }
3134 else
3135 {
3136 /* When the optional second argument is non-zero, don't remove matches
3137 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3138 if (argvars[1].v_type != VAR_UNKNOWN
3139 && get_tv_number_chk(&argvars[1], &error))
3140 options |= WILD_KEEP_ALL;
3141 if (!error)
3142 {
3143 ExpandInit(&xpc);
3144 xpc.xp_context = EXPAND_FILES;
3145 if (p_wic)
3146 options += WILD_ICASE;
3147 if (rettv->v_type == VAR_STRING)
3148 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3149 options, WILD_ALL);
3150 else if (rettv_list_alloc(rettv) != FAIL)
3151 {
3152 int i;
3153
3154 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3155 for (i = 0; i < xpc.xp_numfiles; i++)
3156 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3157 ExpandCleanup(&xpc);
3158 }
3159 }
3160 else
3161 rettv->vval.v_string = NULL;
3162 }
3163}
3164
3165/*
3166 * "extend(list, list [, idx])" function
3167 * "extend(dict, dict [, action])" function
3168 */
3169 static void
3170f_extend(typval_T *argvars, typval_T *rettv)
3171{
3172 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3173
3174 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3175 {
3176 list_T *l1, *l2;
3177 listitem_T *item;
3178 long before;
3179 int error = FALSE;
3180
3181 l1 = argvars[0].vval.v_list;
3182 l2 = argvars[1].vval.v_list;
3183 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3184 && l2 != NULL)
3185 {
3186 if (argvars[2].v_type != VAR_UNKNOWN)
3187 {
3188 before = (long)get_tv_number_chk(&argvars[2], &error);
3189 if (error)
3190 return; /* type error; errmsg already given */
3191
3192 if (before == l1->lv_len)
3193 item = NULL;
3194 else
3195 {
3196 item = list_find(l1, before);
3197 if (item == NULL)
3198 {
3199 EMSGN(_(e_listidx), before);
3200 return;
3201 }
3202 }
3203 }
3204 else
3205 item = NULL;
3206 list_extend(l1, l2, item);
3207
3208 copy_tv(&argvars[0], rettv);
3209 }
3210 }
3211 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3212 {
3213 dict_T *d1, *d2;
3214 char_u *action;
3215 int i;
3216
3217 d1 = argvars[0].vval.v_dict;
3218 d2 = argvars[1].vval.v_dict;
3219 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3220 && d2 != NULL)
3221 {
3222 /* Check the third argument. */
3223 if (argvars[2].v_type != VAR_UNKNOWN)
3224 {
3225 static char *(av[]) = {"keep", "force", "error"};
3226
3227 action = get_tv_string_chk(&argvars[2]);
3228 if (action == NULL)
3229 return; /* type error; errmsg already given */
3230 for (i = 0; i < 3; ++i)
3231 if (STRCMP(action, av[i]) == 0)
3232 break;
3233 if (i == 3)
3234 {
3235 EMSG2(_(e_invarg2), action);
3236 return;
3237 }
3238 }
3239 else
3240 action = (char_u *)"force";
3241
3242 dict_extend(d1, d2, action);
3243
3244 copy_tv(&argvars[0], rettv);
3245 }
3246 }
3247 else
3248 EMSG2(_(e_listdictarg), "extend()");
3249}
3250
3251/*
3252 * "feedkeys()" function
3253 */
3254 static void
3255f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3256{
3257 int remap = TRUE;
3258 int insert = FALSE;
3259 char_u *keys, *flags;
3260 char_u nbuf[NUMBUFLEN];
3261 int typed = FALSE;
3262 int execute = FALSE;
3263 int dangerous = FALSE;
3264 char_u *keys_esc;
3265
3266 /* This is not allowed in the sandbox. If the commands would still be
3267 * executed in the sandbox it would be OK, but it probably happens later,
3268 * when "sandbox" is no longer set. */
3269 if (check_secure())
3270 return;
3271
3272 keys = get_tv_string(&argvars[0]);
3273
3274 if (argvars[1].v_type != VAR_UNKNOWN)
3275 {
3276 flags = get_tv_string_buf(&argvars[1], nbuf);
3277 for ( ; *flags != NUL; ++flags)
3278 {
3279 switch (*flags)
3280 {
3281 case 'n': remap = FALSE; break;
3282 case 'm': remap = TRUE; break;
3283 case 't': typed = TRUE; break;
3284 case 'i': insert = TRUE; break;
3285 case 'x': execute = TRUE; break;
3286 case '!': dangerous = TRUE; break;
3287 }
3288 }
3289 }
3290
3291 if (*keys != NUL || execute)
3292 {
3293 /* Need to escape K_SPECIAL and CSI before putting the string in the
3294 * typeahead buffer. */
3295 keys_esc = vim_strsave_escape_csi(keys);
3296 if (keys_esc != NULL)
3297 {
3298 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3299 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3300 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003301 if (vgetc_busy
3302#ifdef FEAT_TIMERS
3303 || timer_busy
3304#endif
3305 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003306 typebuf_was_filled = TRUE;
3307 if (execute)
3308 {
3309 int save_msg_scroll = msg_scroll;
3310
3311 /* Avoid a 1 second delay when the keys start Insert mode. */
3312 msg_scroll = FALSE;
3313
Bram Moolenaar69fbc9e2017-09-14 20:37:57 +02003314#ifdef FEAT_TERMINAL
3315 if (term_use_loop())
3316 terminal_loop(FALSE);
3317 else
3318#endif
3319 {
3320 if (!dangerous)
3321 ++ex_normal_busy;
3322 exec_normal(TRUE);
3323 if (!dangerous)
3324 --ex_normal_busy;
3325 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003326 msg_scroll |= save_msg_scroll;
3327 }
3328 }
3329 }
3330}
3331
3332/*
3333 * "filereadable()" function
3334 */
3335 static void
3336f_filereadable(typval_T *argvars, typval_T *rettv)
3337{
3338 int fd;
3339 char_u *p;
3340 int n;
3341
3342#ifndef O_NONBLOCK
3343# define O_NONBLOCK 0
3344#endif
3345 p = get_tv_string(&argvars[0]);
3346 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3347 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3348 {
3349 n = TRUE;
3350 close(fd);
3351 }
3352 else
3353 n = FALSE;
3354
3355 rettv->vval.v_number = n;
3356}
3357
3358/*
3359 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3360 * rights to write into.
3361 */
3362 static void
3363f_filewritable(typval_T *argvars, typval_T *rettv)
3364{
3365 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3366}
3367
3368 static void
3369findfilendir(
3370 typval_T *argvars UNUSED,
3371 typval_T *rettv,
3372 int find_what UNUSED)
3373{
3374#ifdef FEAT_SEARCHPATH
3375 char_u *fname;
3376 char_u *fresult = NULL;
3377 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3378 char_u *p;
3379 char_u pathbuf[NUMBUFLEN];
3380 int count = 1;
3381 int first = TRUE;
3382 int error = FALSE;
3383#endif
3384
3385 rettv->vval.v_string = NULL;
3386 rettv->v_type = VAR_STRING;
3387
3388#ifdef FEAT_SEARCHPATH
3389 fname = get_tv_string(&argvars[0]);
3390
3391 if (argvars[1].v_type != VAR_UNKNOWN)
3392 {
3393 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3394 if (p == NULL)
3395 error = TRUE;
3396 else
3397 {
3398 if (*p != NUL)
3399 path = p;
3400
3401 if (argvars[2].v_type != VAR_UNKNOWN)
3402 count = (int)get_tv_number_chk(&argvars[2], &error);
3403 }
3404 }
3405
3406 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3407 error = TRUE;
3408
3409 if (*fname != NUL && !error)
3410 {
3411 do
3412 {
3413 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3414 vim_free(fresult);
3415 fresult = find_file_in_path_option(first ? fname : NULL,
3416 first ? (int)STRLEN(fname) : 0,
3417 0, first, path,
3418 find_what,
3419 curbuf->b_ffname,
3420 find_what == FINDFILE_DIR
3421 ? (char_u *)"" : curbuf->b_p_sua);
3422 first = FALSE;
3423
3424 if (fresult != NULL && rettv->v_type == VAR_LIST)
3425 list_append_string(rettv->vval.v_list, fresult, -1);
3426
3427 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3428 }
3429
3430 if (rettv->v_type == VAR_STRING)
3431 rettv->vval.v_string = fresult;
3432#endif
3433}
3434
3435/*
3436 * "filter()" function
3437 */
3438 static void
3439f_filter(typval_T *argvars, typval_T *rettv)
3440{
3441 filter_map(argvars, rettv, FALSE);
3442}
3443
3444/*
3445 * "finddir({fname}[, {path}[, {count}]])" function
3446 */
3447 static void
3448f_finddir(typval_T *argvars, typval_T *rettv)
3449{
3450 findfilendir(argvars, rettv, FINDFILE_DIR);
3451}
3452
3453/*
3454 * "findfile({fname}[, {path}[, {count}]])" function
3455 */
3456 static void
3457f_findfile(typval_T *argvars, typval_T *rettv)
3458{
3459 findfilendir(argvars, rettv, FINDFILE_FILE);
3460}
3461
3462#ifdef FEAT_FLOAT
3463/*
3464 * "float2nr({float})" function
3465 */
3466 static void
3467f_float2nr(typval_T *argvars, typval_T *rettv)
3468{
3469 float_T f = 0.0;
3470
3471 if (get_float_arg(argvars, &f) == OK)
3472 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003473 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003474 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003475 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003476 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003477 else
3478 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003479 }
3480}
3481
3482/*
3483 * "floor({float})" function
3484 */
3485 static void
3486f_floor(typval_T *argvars, typval_T *rettv)
3487{
3488 float_T f = 0.0;
3489
3490 rettv->v_type = VAR_FLOAT;
3491 if (get_float_arg(argvars, &f) == OK)
3492 rettv->vval.v_float = floor(f);
3493 else
3494 rettv->vval.v_float = 0.0;
3495}
3496
3497/*
3498 * "fmod()" function
3499 */
3500 static void
3501f_fmod(typval_T *argvars, typval_T *rettv)
3502{
3503 float_T fx = 0.0, fy = 0.0;
3504
3505 rettv->v_type = VAR_FLOAT;
3506 if (get_float_arg(argvars, &fx) == OK
3507 && get_float_arg(&argvars[1], &fy) == OK)
3508 rettv->vval.v_float = fmod(fx, fy);
3509 else
3510 rettv->vval.v_float = 0.0;
3511}
3512#endif
3513
3514/*
3515 * "fnameescape({string})" function
3516 */
3517 static void
3518f_fnameescape(typval_T *argvars, typval_T *rettv)
3519{
3520 rettv->vval.v_string = vim_strsave_fnameescape(
3521 get_tv_string(&argvars[0]), FALSE);
3522 rettv->v_type = VAR_STRING;
3523}
3524
3525/*
3526 * "fnamemodify({fname}, {mods})" function
3527 */
3528 static void
3529f_fnamemodify(typval_T *argvars, typval_T *rettv)
3530{
3531 char_u *fname;
3532 char_u *mods;
3533 int usedlen = 0;
3534 int len;
3535 char_u *fbuf = NULL;
3536 char_u buf[NUMBUFLEN];
3537
3538 fname = get_tv_string_chk(&argvars[0]);
3539 mods = get_tv_string_buf_chk(&argvars[1], buf);
3540 if (fname == NULL || mods == NULL)
3541 fname = NULL;
3542 else
3543 {
3544 len = (int)STRLEN(fname);
3545 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3546 }
3547
3548 rettv->v_type = VAR_STRING;
3549 if (fname == NULL)
3550 rettv->vval.v_string = NULL;
3551 else
3552 rettv->vval.v_string = vim_strnsave(fname, len);
3553 vim_free(fbuf);
3554}
3555
3556static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3557
3558/*
3559 * "foldclosed()" function
3560 */
3561 static void
3562foldclosed_both(
3563 typval_T *argvars UNUSED,
3564 typval_T *rettv,
3565 int end UNUSED)
3566{
3567#ifdef FEAT_FOLDING
3568 linenr_T lnum;
3569 linenr_T first, last;
3570
3571 lnum = get_tv_lnum(argvars);
3572 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3573 {
3574 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3575 {
3576 if (end)
3577 rettv->vval.v_number = (varnumber_T)last;
3578 else
3579 rettv->vval.v_number = (varnumber_T)first;
3580 return;
3581 }
3582 }
3583#endif
3584 rettv->vval.v_number = -1;
3585}
3586
3587/*
3588 * "foldclosed()" function
3589 */
3590 static void
3591f_foldclosed(typval_T *argvars, typval_T *rettv)
3592{
3593 foldclosed_both(argvars, rettv, FALSE);
3594}
3595
3596/*
3597 * "foldclosedend()" function
3598 */
3599 static void
3600f_foldclosedend(typval_T *argvars, typval_T *rettv)
3601{
3602 foldclosed_both(argvars, rettv, TRUE);
3603}
3604
3605/*
3606 * "foldlevel()" function
3607 */
3608 static void
3609f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3610{
3611#ifdef FEAT_FOLDING
3612 linenr_T lnum;
3613
3614 lnum = get_tv_lnum(argvars);
3615 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3616 rettv->vval.v_number = foldLevel(lnum);
3617#endif
3618}
3619
3620/*
3621 * "foldtext()" function
3622 */
3623 static void
3624f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3625{
3626#ifdef FEAT_FOLDING
3627 linenr_T foldstart;
3628 linenr_T foldend;
3629 char_u *dashes;
3630 linenr_T lnum;
3631 char_u *s;
3632 char_u *r;
3633 int len;
3634 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003635 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636#endif
3637
3638 rettv->v_type = VAR_STRING;
3639 rettv->vval.v_string = NULL;
3640#ifdef FEAT_FOLDING
3641 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3642 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3643 dashes = get_vim_var_str(VV_FOLDDASHES);
3644 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3645 && dashes != NULL)
3646 {
3647 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003648 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649 if (!linewhite(lnum))
3650 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651
3652 /* Find interesting text in this line. */
3653 s = skipwhite(ml_get(lnum));
3654 /* skip C comment-start */
3655 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3656 {
3657 s = skipwhite(s + 2);
3658 if (*skipwhite(s) == NUL
3659 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3660 {
3661 s = skipwhite(ml_get(lnum + 1));
3662 if (*s == '*')
3663 s = skipwhite(s + 1);
3664 }
3665 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003666 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003667 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003668 r = alloc((unsigned)(STRLEN(txt)
3669 + STRLEN(dashes) /* for %s */
3670 + 20 /* for %3ld */
3671 + STRLEN(s))); /* concatenated */
3672 if (r != NULL)
3673 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003674 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003675 len = (int)STRLEN(r);
3676 STRCAT(r, s);
3677 /* remove 'foldmarker' and 'commentstring' */
3678 foldtext_cleanup(r + len);
3679 rettv->vval.v_string = r;
3680 }
3681 }
3682#endif
3683}
3684
3685/*
3686 * "foldtextresult(lnum)" function
3687 */
3688 static void
3689f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3690{
3691#ifdef FEAT_FOLDING
3692 linenr_T lnum;
3693 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003694 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003695 foldinfo_T foldinfo;
3696 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003697 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003698#endif
3699
3700 rettv->v_type = VAR_STRING;
3701 rettv->vval.v_string = NULL;
3702#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003703 if (entered)
3704 return; /* reject recursive use */
3705 entered = TRUE;
3706
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707 lnum = get_tv_lnum(argvars);
3708 /* treat illegal types and illegal string values for {lnum} the same */
3709 if (lnum < 0)
3710 lnum = 0;
3711 fold_count = foldedCount(curwin, lnum, &foldinfo);
3712 if (fold_count > 0)
3713 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003714 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3715 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003716 if (text == buf)
3717 text = vim_strsave(text);
3718 rettv->vval.v_string = text;
3719 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003720
3721 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722#endif
3723}
3724
3725/*
3726 * "foreground()" function
3727 */
3728 static void
3729f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3730{
3731#ifdef FEAT_GUI
3732 if (gui.in_use)
3733 gui_mch_set_foreground();
3734#else
3735# ifdef WIN32
3736 win32_set_foreground();
3737# endif
3738#endif
3739}
3740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003741 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003742common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003743{
3744 char_u *s;
3745 char_u *name;
3746 int use_string = FALSE;
3747 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003748 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003749
3750 if (argvars[0].v_type == VAR_FUNC)
3751 {
3752 /* function(MyFunc, [arg], dict) */
3753 s = argvars[0].vval.v_string;
3754 }
3755 else if (argvars[0].v_type == VAR_PARTIAL
3756 && argvars[0].vval.v_partial != NULL)
3757 {
3758 /* function(dict.MyFunc, [arg]) */
3759 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003760 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003761 }
3762 else
3763 {
3764 /* function('MyFunc', [arg], dict) */
3765 s = get_tv_string(&argvars[0]);
3766 use_string = TRUE;
3767 }
3768
Bram Moolenaar843b8842016-08-21 14:36:15 +02003769 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003770 {
3771 name = s;
3772 trans_name = trans_function_name(&name, FALSE,
3773 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3774 if (*name != NUL)
3775 s = NULL;
3776 }
3777
Bram Moolenaar843b8842016-08-21 14:36:15 +02003778 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3779 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003780 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003782 else if (trans_name != NULL && (is_funcref
3783 ? find_func(trans_name) == NULL
3784 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003785 EMSG2(_("E700: Unknown function: %s"), s);
3786 else
3787 {
3788 int dict_idx = 0;
3789 int arg_idx = 0;
3790 list_T *list = NULL;
3791
3792 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3793 {
3794 char sid_buf[25];
3795 int off = *s == 's' ? 2 : 5;
3796
3797 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3798 * also be called from another script. Using trans_function_name()
3799 * would also work, but some plugins depend on the name being
3800 * printable text. */
3801 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3802 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3803 if (name != NULL)
3804 {
3805 STRCPY(name, sid_buf);
3806 STRCAT(name, s + off);
3807 }
3808 }
3809 else
3810 name = vim_strsave(s);
3811
3812 if (argvars[1].v_type != VAR_UNKNOWN)
3813 {
3814 if (argvars[2].v_type != VAR_UNKNOWN)
3815 {
3816 /* function(name, [args], dict) */
3817 arg_idx = 1;
3818 dict_idx = 2;
3819 }
3820 else if (argvars[1].v_type == VAR_DICT)
3821 /* function(name, dict) */
3822 dict_idx = 1;
3823 else
3824 /* function(name, [args]) */
3825 arg_idx = 1;
3826 if (dict_idx > 0)
3827 {
3828 if (argvars[dict_idx].v_type != VAR_DICT)
3829 {
3830 EMSG(_("E922: expected a dict"));
3831 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003832 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003833 }
3834 if (argvars[dict_idx].vval.v_dict == NULL)
3835 dict_idx = 0;
3836 }
3837 if (arg_idx > 0)
3838 {
3839 if (argvars[arg_idx].v_type != VAR_LIST)
3840 {
3841 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3842 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003843 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003844 }
3845 list = argvars[arg_idx].vval.v_list;
3846 if (list == NULL || list->lv_len == 0)
3847 arg_idx = 0;
3848 }
3849 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003850 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003851 {
3852 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3853
3854 /* result is a VAR_PARTIAL */
3855 if (pt == NULL)
3856 vim_free(name);
3857 else
3858 {
3859 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3860 {
3861 listitem_T *li;
3862 int i = 0;
3863 int arg_len = 0;
3864 int lv_len = 0;
3865
3866 if (arg_pt != NULL)
3867 arg_len = arg_pt->pt_argc;
3868 if (list != NULL)
3869 lv_len = list->lv_len;
3870 pt->pt_argc = arg_len + lv_len;
3871 pt->pt_argv = (typval_T *)alloc(
3872 sizeof(typval_T) * pt->pt_argc);
3873 if (pt->pt_argv == NULL)
3874 {
3875 vim_free(pt);
3876 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003877 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003878 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003879 for (i = 0; i < arg_len; i++)
3880 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3881 if (lv_len > 0)
3882 for (li = list->lv_first; li != NULL;
3883 li = li->li_next)
3884 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003885 }
3886
3887 /* For "function(dict.func, [], dict)" and "func" is a partial
3888 * use "dict". That is backwards compatible. */
3889 if (dict_idx > 0)
3890 {
3891 /* The dict is bound explicitly, pt_auto is FALSE. */
3892 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3893 ++pt->pt_dict->dv_refcount;
3894 }
3895 else if (arg_pt != NULL)
3896 {
3897 /* If the dict was bound automatically the result is also
3898 * bound automatically. */
3899 pt->pt_dict = arg_pt->pt_dict;
3900 pt->pt_auto = arg_pt->pt_auto;
3901 if (pt->pt_dict != NULL)
3902 ++pt->pt_dict->dv_refcount;
3903 }
3904
3905 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003906 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3907 {
3908 pt->pt_func = arg_pt->pt_func;
3909 func_ptr_ref(pt->pt_func);
3910 vim_free(name);
3911 }
3912 else if (is_funcref)
3913 {
3914 pt->pt_func = find_func(trans_name);
3915 func_ptr_ref(pt->pt_func);
3916 vim_free(name);
3917 }
3918 else
3919 {
3920 pt->pt_name = name;
3921 func_ref(name);
3922 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923 }
3924 rettv->v_type = VAR_PARTIAL;
3925 rettv->vval.v_partial = pt;
3926 }
3927 else
3928 {
3929 /* result is a VAR_FUNC */
3930 rettv->v_type = VAR_FUNC;
3931 rettv->vval.v_string = name;
3932 func_ref(name);
3933 }
3934 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003935theend:
3936 vim_free(trans_name);
3937}
3938
3939/*
3940 * "funcref()" function
3941 */
3942 static void
3943f_funcref(typval_T *argvars, typval_T *rettv)
3944{
3945 common_function(argvars, rettv, TRUE);
3946}
3947
3948/*
3949 * "function()" function
3950 */
3951 static void
3952f_function(typval_T *argvars, typval_T *rettv)
3953{
3954 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003955}
3956
3957/*
3958 * "garbagecollect()" function
3959 */
3960 static void
3961f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3962{
3963 /* This is postponed until we are back at the toplevel, because we may be
3964 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3965 want_garbage_collect = TRUE;
3966
3967 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3968 garbage_collect_at_exit = TRUE;
3969}
3970
3971/*
3972 * "get()" function
3973 */
3974 static void
3975f_get(typval_T *argvars, typval_T *rettv)
3976{
3977 listitem_T *li;
3978 list_T *l;
3979 dictitem_T *di;
3980 dict_T *d;
3981 typval_T *tv = NULL;
3982
3983 if (argvars[0].v_type == VAR_LIST)
3984 {
3985 if ((l = argvars[0].vval.v_list) != NULL)
3986 {
3987 int error = FALSE;
3988
3989 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3990 if (!error && li != NULL)
3991 tv = &li->li_tv;
3992 }
3993 }
3994 else if (argvars[0].v_type == VAR_DICT)
3995 {
3996 if ((d = argvars[0].vval.v_dict) != NULL)
3997 {
3998 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3999 if (di != NULL)
4000 tv = &di->di_tv;
4001 }
4002 }
4003 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4004 {
4005 partial_T *pt;
4006 partial_T fref_pt;
4007
4008 if (argvars[0].v_type == VAR_PARTIAL)
4009 pt = argvars[0].vval.v_partial;
4010 else
4011 {
4012 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4013 fref_pt.pt_name = argvars[0].vval.v_string;
4014 pt = &fref_pt;
4015 }
4016
4017 if (pt != NULL)
4018 {
4019 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004020 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021
4022 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4023 {
4024 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004025 n = partial_name(pt);
4026 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004027 rettv->vval.v_string = NULL;
4028 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004029 {
4030 rettv->vval.v_string = vim_strsave(n);
4031 if (rettv->v_type == VAR_FUNC)
4032 func_ref(rettv->vval.v_string);
4033 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034 }
4035 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004036 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004037 else if (STRCMP(what, "args") == 0)
4038 {
4039 rettv->v_type = VAR_LIST;
4040 if (rettv_list_alloc(rettv) == OK)
4041 {
4042 int i;
4043
4044 for (i = 0; i < pt->pt_argc; ++i)
4045 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4046 }
4047 }
4048 else
4049 EMSG2(_(e_invarg2), what);
4050 return;
4051 }
4052 }
4053 else
4054 EMSG2(_(e_listdictarg), "get()");
4055
4056 if (tv == NULL)
4057 {
4058 if (argvars[2].v_type != VAR_UNKNOWN)
4059 copy_tv(&argvars[2], rettv);
4060 }
4061 else
4062 copy_tv(tv, rettv);
4063}
4064
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004065#ifdef FEAT_SIGNS
4066/*
4067 * Returns information about signs placed in a buffer as list of dicts.
4068 */
4069 static void
4070get_buffer_signs(buf_T *buf, list_T *l)
4071{
4072 signlist_T *sign;
4073
4074 for (sign = buf->b_signlist; sign; sign = sign->next)
4075 {
4076 dict_T *d = dict_alloc();
4077
4078 if (d != NULL)
4079 {
4080 dict_add_nr_str(d, "id", sign->id, NULL);
4081 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004082 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004083
4084 list_append_dict(l, d);
4085 }
4086 }
4087}
4088#endif
4089
4090/*
4091 * Returns buffer options, variables and other attributes in a dictionary.
4092 */
4093 static dict_T *
4094get_buffer_info(buf_T *buf)
4095{
4096 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004097 tabpage_T *tp;
4098 win_T *wp;
4099 list_T *windows;
4100
4101 dict = dict_alloc();
4102 if (dict == NULL)
4103 return NULL;
4104
Bram Moolenaar33928832016-08-18 21:22:04 +02004105 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004106 dict_add_nr_str(dict, "name", 0L,
4107 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004108 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4109 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004110 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4111 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4112 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004113 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004114 dict_add_nr_str(dict, "hidden",
4115 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4116 NULL);
4117
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004118 /* Get a reference to buffer variables */
4119 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004120
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004121 /* List of windows displaying this buffer */
4122 windows = list_alloc();
4123 if (windows != NULL)
4124 {
4125 FOR_ALL_TAB_WINDOWS(tp, wp)
4126 if (wp->w_buffer == buf)
4127 list_append_number(windows, (varnumber_T)wp->w_id);
4128 dict_add_list(dict, "windows", windows);
4129 }
4130
4131#ifdef FEAT_SIGNS
4132 if (buf->b_signlist != NULL)
4133 {
4134 /* List of signs placed in this buffer */
4135 list_T *signs = list_alloc();
4136 if (signs != NULL)
4137 {
4138 get_buffer_signs(buf, signs);
4139 dict_add_list(dict, "signs", signs);
4140 }
4141 }
4142#endif
4143
4144 return dict;
4145}
4146
4147/*
4148 * "getbufinfo()" function
4149 */
4150 static void
4151f_getbufinfo(typval_T *argvars, typval_T *rettv)
4152{
4153 buf_T *buf = NULL;
4154 buf_T *argbuf = NULL;
4155 dict_T *d;
4156 int filtered = FALSE;
4157 int sel_buflisted = FALSE;
4158 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004159 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004160
4161 if (rettv_list_alloc(rettv) != OK)
4162 return;
4163
4164 /* List of all the buffers or selected buffers */
4165 if (argvars[0].v_type == VAR_DICT)
4166 {
4167 dict_T *sel_d = argvars[0].vval.v_dict;
4168
4169 if (sel_d != NULL)
4170 {
4171 dictitem_T *di;
4172
4173 filtered = TRUE;
4174
4175 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4176 if (di != NULL && get_tv_number(&di->di_tv))
4177 sel_buflisted = TRUE;
4178
4179 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4180 if (di != NULL && get_tv_number(&di->di_tv))
4181 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004182
4183 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4184 if (di != NULL && get_tv_number(&di->di_tv))
4185 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004186 }
4187 }
4188 else if (argvars[0].v_type != VAR_UNKNOWN)
4189 {
4190 /* Information about one buffer. Argument specifies the buffer */
4191 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4192 ++emsg_off;
4193 argbuf = get_buf_tv(&argvars[0], FALSE);
4194 --emsg_off;
4195 if (argbuf == NULL)
4196 return;
4197 }
4198
4199 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004200 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004201 {
4202 if (argbuf != NULL && argbuf != buf)
4203 continue;
4204 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004205 || (sel_buflisted && !buf->b_p_bl)
4206 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004207 continue;
4208
4209 d = get_buffer_info(buf);
4210 if (d != NULL)
4211 list_append_dict(rettv->vval.v_list, d);
4212 if (argbuf != NULL)
4213 return;
4214 }
4215}
4216
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004217static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4218
4219/*
4220 * Get line or list of lines from buffer "buf" into "rettv".
4221 * Return a range (from start to end) of lines in rettv from the specified
4222 * buffer.
4223 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4224 */
4225 static void
4226get_buffer_lines(
4227 buf_T *buf,
4228 linenr_T start,
4229 linenr_T end,
4230 int retlist,
4231 typval_T *rettv)
4232{
4233 char_u *p;
4234
4235 rettv->v_type = VAR_STRING;
4236 rettv->vval.v_string = NULL;
4237 if (retlist && rettv_list_alloc(rettv) == FAIL)
4238 return;
4239
4240 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4241 return;
4242
4243 if (!retlist)
4244 {
4245 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4246 p = ml_get_buf(buf, start, FALSE);
4247 else
4248 p = (char_u *)"";
4249 rettv->vval.v_string = vim_strsave(p);
4250 }
4251 else
4252 {
4253 if (end < start)
4254 return;
4255
4256 if (start < 1)
4257 start = 1;
4258 if (end > buf->b_ml.ml_line_count)
4259 end = buf->b_ml.ml_line_count;
4260 while (start <= end)
4261 if (list_append_string(rettv->vval.v_list,
4262 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4263 break;
4264 }
4265}
4266
4267/*
4268 * Get the lnum from the first argument.
4269 * Also accepts "$", then "buf" is used.
4270 * Returns 0 on error.
4271 */
4272 static linenr_T
4273get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4274{
4275 if (argvars[0].v_type == VAR_STRING
4276 && argvars[0].vval.v_string != NULL
4277 && argvars[0].vval.v_string[0] == '$'
4278 && buf != NULL)
4279 return buf->b_ml.ml_line_count;
4280 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4281}
4282
4283/*
4284 * "getbufline()" function
4285 */
4286 static void
4287f_getbufline(typval_T *argvars, typval_T *rettv)
4288{
4289 linenr_T lnum;
4290 linenr_T end;
4291 buf_T *buf;
4292
4293 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4294 ++emsg_off;
4295 buf = get_buf_tv(&argvars[0], FALSE);
4296 --emsg_off;
4297
4298 lnum = get_tv_lnum_buf(&argvars[1], buf);
4299 if (argvars[2].v_type == VAR_UNKNOWN)
4300 end = lnum;
4301 else
4302 end = get_tv_lnum_buf(&argvars[2], buf);
4303
4304 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4305}
4306
4307/*
4308 * "getbufvar()" function
4309 */
4310 static void
4311f_getbufvar(typval_T *argvars, typval_T *rettv)
4312{
4313 buf_T *buf;
4314 buf_T *save_curbuf;
4315 char_u *varname;
4316 dictitem_T *v;
4317 int done = FALSE;
4318
4319 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4320 varname = get_tv_string_chk(&argvars[1]);
4321 ++emsg_off;
4322 buf = get_buf_tv(&argvars[0], FALSE);
4323
4324 rettv->v_type = VAR_STRING;
4325 rettv->vval.v_string = NULL;
4326
4327 if (buf != NULL && varname != NULL)
4328 {
4329 /* set curbuf to be our buf, temporarily */
4330 save_curbuf = curbuf;
4331 curbuf = buf;
4332
Bram Moolenaar30567352016-08-27 21:25:44 +02004333 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004334 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004335 if (varname[1] == NUL)
4336 {
4337 /* get all buffer-local options in a dict */
4338 dict_T *opts = get_winbuf_options(TRUE);
4339
4340 if (opts != NULL)
4341 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004342 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004343 done = TRUE;
4344 }
4345 }
4346 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4347 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004348 done = TRUE;
4349 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004350 else
4351 {
4352 /* Look up the variable. */
4353 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4354 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4355 'b', varname, FALSE);
4356 if (v != NULL)
4357 {
4358 copy_tv(&v->di_tv, rettv);
4359 done = TRUE;
4360 }
4361 }
4362
4363 /* restore previous notion of curbuf */
4364 curbuf = save_curbuf;
4365 }
4366
4367 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4368 /* use the default value */
4369 copy_tv(&argvars[2], rettv);
4370
4371 --emsg_off;
4372}
4373
4374/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004375 * "getchangelist()" function
4376 */
4377 static void
4378f_getchangelist(typval_T *argvars, typval_T *rettv)
4379{
4380#ifdef FEAT_JUMPLIST
4381 buf_T *buf;
4382 int i;
4383 list_T *l;
4384 dict_T *d;
4385#endif
4386
4387 if (rettv_list_alloc(rettv) != OK)
4388 return;
4389
4390#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004391 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4392 ++emsg_off;
4393 buf = get_buf_tv(&argvars[0], FALSE);
4394 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004395 if (buf == NULL)
4396 return;
4397
4398 l = list_alloc();
4399 if (l == NULL)
4400 return;
4401
4402 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4403 return;
4404 /*
4405 * The current window change list index tracks only the position in the
4406 * current buffer change list. For other buffers, use the change list
4407 * length as the current index.
4408 */
4409 list_append_number(rettv->vval.v_list,
4410 (varnumber_T)((buf == curwin->w_buffer)
4411 ? curwin->w_changelistidx : buf->b_changelistlen));
4412
4413 for (i = 0; i < buf->b_changelistlen; ++i)
4414 {
4415 if (buf->b_changelist[i].lnum == 0)
4416 continue;
4417 if ((d = dict_alloc()) == NULL)
4418 return;
4419 if (list_append_dict(l, d) == FAIL)
4420 return;
4421 dict_add_nr_str(d, "lnum", (long)buf->b_changelist[i].lnum, NULL);
4422 dict_add_nr_str(d, "col", (long)buf->b_changelist[i].col, NULL);
4423# ifdef FEAT_VIRTUALEDIT
4424 dict_add_nr_str(d, "coladd", (long)buf->b_changelist[i].coladd, NULL);
4425# endif
4426 }
4427#endif
4428}
4429/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004430 * "getchar()" function
4431 */
4432 static void
4433f_getchar(typval_T *argvars, typval_T *rettv)
4434{
4435 varnumber_T n;
4436 int error = FALSE;
4437
4438 /* Position the cursor. Needed after a message that ends in a space. */
4439 windgoto(msg_row, msg_col);
4440
4441 ++no_mapping;
4442 ++allow_keys;
4443 for (;;)
4444 {
4445 if (argvars[0].v_type == VAR_UNKNOWN)
4446 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004447 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4449 /* getchar(1): only check if char avail */
4450 n = vpeekc_any();
4451 else if (error || vpeekc_any() == NUL)
4452 /* illegal argument or getchar(0) and no char avail: return zero */
4453 n = 0;
4454 else
4455 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004456 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457
4458 if (n == K_IGNORE)
4459 continue;
4460 break;
4461 }
4462 --no_mapping;
4463 --allow_keys;
4464
4465 set_vim_var_nr(VV_MOUSE_WIN, 0);
4466 set_vim_var_nr(VV_MOUSE_WINID, 0);
4467 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4468 set_vim_var_nr(VV_MOUSE_COL, 0);
4469
4470 rettv->vval.v_number = n;
4471 if (IS_SPECIAL(n) || mod_mask != 0)
4472 {
4473 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4474 int i = 0;
4475
4476 /* Turn a special key into three bytes, plus modifier. */
4477 if (mod_mask != 0)
4478 {
4479 temp[i++] = K_SPECIAL;
4480 temp[i++] = KS_MODIFIER;
4481 temp[i++] = mod_mask;
4482 }
4483 if (IS_SPECIAL(n))
4484 {
4485 temp[i++] = K_SPECIAL;
4486 temp[i++] = K_SECOND(n);
4487 temp[i++] = K_THIRD(n);
4488 }
4489#ifdef FEAT_MBYTE
4490 else if (has_mbyte)
4491 i += (*mb_char2bytes)(n, temp + i);
4492#endif
4493 else
4494 temp[i++] = n;
4495 temp[i++] = NUL;
4496 rettv->v_type = VAR_STRING;
4497 rettv->vval.v_string = vim_strsave(temp);
4498
4499#ifdef FEAT_MOUSE
4500 if (is_mouse_key(n))
4501 {
4502 int row = mouse_row;
4503 int col = mouse_col;
4504 win_T *win;
4505 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004506 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 int winnr = 1;
4508
4509 if (row >= 0 && col >= 0)
4510 {
4511 /* Find the window at the mouse coordinates and compute the
4512 * text position. */
4513 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004514 if (win == NULL)
4515 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004516 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517 for (wp = firstwin; wp != win; wp = wp->w_next)
4518 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4520 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4521 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4522 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4523 }
4524 }
4525#endif
4526 }
4527}
4528
4529/*
4530 * "getcharmod()" function
4531 */
4532 static void
4533f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4534{
4535 rettv->vval.v_number = mod_mask;
4536}
4537
4538/*
4539 * "getcharsearch()" function
4540 */
4541 static void
4542f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4543{
4544 if (rettv_dict_alloc(rettv) != FAIL)
4545 {
4546 dict_T *dict = rettv->vval.v_dict;
4547
4548 dict_add_nr_str(dict, "char", 0L, last_csearch());
4549 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4550 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4551 }
4552}
4553
4554/*
4555 * "getcmdline()" function
4556 */
4557 static void
4558f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4559{
4560 rettv->v_type = VAR_STRING;
4561 rettv->vval.v_string = get_cmdline_str();
4562}
4563
4564/*
4565 * "getcmdpos()" function
4566 */
4567 static void
4568f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4569{
4570 rettv->vval.v_number = get_cmdline_pos() + 1;
4571}
4572
4573/*
4574 * "getcmdtype()" function
4575 */
4576 static void
4577f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4578{
4579 rettv->v_type = VAR_STRING;
4580 rettv->vval.v_string = alloc(2);
4581 if (rettv->vval.v_string != NULL)
4582 {
4583 rettv->vval.v_string[0] = get_cmdline_type();
4584 rettv->vval.v_string[1] = NUL;
4585 }
4586}
4587
4588/*
4589 * "getcmdwintype()" function
4590 */
4591 static void
4592f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4593{
4594 rettv->v_type = VAR_STRING;
4595 rettv->vval.v_string = NULL;
4596#ifdef FEAT_CMDWIN
4597 rettv->vval.v_string = alloc(2);
4598 if (rettv->vval.v_string != NULL)
4599 {
4600 rettv->vval.v_string[0] = cmdwin_type;
4601 rettv->vval.v_string[1] = NUL;
4602 }
4603#endif
4604}
4605
4606#if defined(FEAT_CMDL_COMPL)
4607/*
4608 * "getcompletion()" function
4609 */
4610 static void
4611f_getcompletion(typval_T *argvars, typval_T *rettv)
4612{
4613 char_u *pat;
4614 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004615 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004616 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4617 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004618
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004619 if (argvars[2].v_type != VAR_UNKNOWN)
4620 filtered = get_tv_number_chk(&argvars[2], NULL);
4621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622 if (p_wic)
4623 options |= WILD_ICASE;
4624
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004625 /* For filtered results, 'wildignore' is used */
4626 if (!filtered)
4627 options |= WILD_KEEP_ALL;
4628
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004629 ExpandInit(&xpc);
4630 xpc.xp_pattern = get_tv_string(&argvars[0]);
4631 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4632 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4633 if (xpc.xp_context == EXPAND_NOTHING)
4634 {
4635 if (argvars[1].v_type == VAR_STRING)
4636 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4637 else
4638 EMSG(_(e_invarg));
4639 return;
4640 }
4641
4642# if defined(FEAT_MENU)
4643 if (xpc.xp_context == EXPAND_MENUS)
4644 {
4645 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4646 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4647 }
4648# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004649#ifdef FEAT_CSCOPE
4650 if (xpc.xp_context == EXPAND_CSCOPE)
4651 {
4652 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4653 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4654 }
4655#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004656#ifdef FEAT_SIGNS
4657 if (xpc.xp_context == EXPAND_SIGN)
4658 {
4659 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4660 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4661 }
4662#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663
4664 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4665 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4666 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004667 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004668
4669 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4670
4671 for (i = 0; i < xpc.xp_numfiles; i++)
4672 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4673 }
4674 vim_free(pat);
4675 ExpandCleanup(&xpc);
4676}
4677#endif
4678
4679/*
4680 * "getcwd()" function
4681 */
4682 static void
4683f_getcwd(typval_T *argvars, typval_T *rettv)
4684{
4685 win_T *wp = NULL;
4686 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004687 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004688
4689 rettv->v_type = VAR_STRING;
4690 rettv->vval.v_string = NULL;
4691
Bram Moolenaar54591292018-02-09 20:53:59 +01004692 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4693 global = TRUE;
4694 else
4695 wp = find_tabwin(&argvars[0], &argvars[1]);
4696
4697 if (wp != NULL && wp->w_localdir != NULL)
4698 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4699 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004701 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702 rettv->vval.v_string = vim_strsave(globaldir);
4703 else
4704 {
4705 cwd = alloc(MAXPATHL);
4706 if (cwd != NULL)
4707 {
4708 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4709 rettv->vval.v_string = vim_strsave(cwd);
4710 vim_free(cwd);
4711 }
4712 }
4713#ifdef BACKSLASH_IN_FILENAME
4714 if (rettv->vval.v_string != NULL)
4715 slash_adjust(rettv->vval.v_string);
4716#endif
4717 }
4718}
4719
4720/*
4721 * "getfontname()" function
4722 */
4723 static void
4724f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4725{
4726 rettv->v_type = VAR_STRING;
4727 rettv->vval.v_string = NULL;
4728#ifdef FEAT_GUI
4729 if (gui.in_use)
4730 {
4731 GuiFont font;
4732 char_u *name = NULL;
4733
4734 if (argvars[0].v_type == VAR_UNKNOWN)
4735 {
4736 /* Get the "Normal" font. Either the name saved by
4737 * hl_set_font_name() or from the font ID. */
4738 font = gui.norm_font;
4739 name = hl_get_font_name();
4740 }
4741 else
4742 {
4743 name = get_tv_string(&argvars[0]);
4744 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4745 return;
4746 font = gui_mch_get_font(name, FALSE);
4747 if (font == NOFONT)
4748 return; /* Invalid font name, return empty string. */
4749 }
4750 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4751 if (argvars[0].v_type != VAR_UNKNOWN)
4752 gui_mch_free_font(font);
4753 }
4754#endif
4755}
4756
4757/*
4758 * "getfperm({fname})" function
4759 */
4760 static void
4761f_getfperm(typval_T *argvars, typval_T *rettv)
4762{
4763 char_u *fname;
4764 stat_T st;
4765 char_u *perm = NULL;
4766 char_u flags[] = "rwx";
4767 int i;
4768
4769 fname = get_tv_string(&argvars[0]);
4770
4771 rettv->v_type = VAR_STRING;
4772 if (mch_stat((char *)fname, &st) >= 0)
4773 {
4774 perm = vim_strsave((char_u *)"---------");
4775 if (perm != NULL)
4776 {
4777 for (i = 0; i < 9; i++)
4778 {
4779 if (st.st_mode & (1 << (8 - i)))
4780 perm[i] = flags[i % 3];
4781 }
4782 }
4783 }
4784 rettv->vval.v_string = perm;
4785}
4786
4787/*
4788 * "getfsize({fname})" function
4789 */
4790 static void
4791f_getfsize(typval_T *argvars, typval_T *rettv)
4792{
4793 char_u *fname;
4794 stat_T st;
4795
4796 fname = get_tv_string(&argvars[0]);
4797
4798 rettv->v_type = VAR_NUMBER;
4799
4800 if (mch_stat((char *)fname, &st) >= 0)
4801 {
4802 if (mch_isdir(fname))
4803 rettv->vval.v_number = 0;
4804 else
4805 {
4806 rettv->vval.v_number = (varnumber_T)st.st_size;
4807
4808 /* non-perfect check for overflow */
4809 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4810 rettv->vval.v_number = -2;
4811 }
4812 }
4813 else
4814 rettv->vval.v_number = -1;
4815}
4816
4817/*
4818 * "getftime({fname})" function
4819 */
4820 static void
4821f_getftime(typval_T *argvars, typval_T *rettv)
4822{
4823 char_u *fname;
4824 stat_T st;
4825
4826 fname = get_tv_string(&argvars[0]);
4827
4828 if (mch_stat((char *)fname, &st) >= 0)
4829 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4830 else
4831 rettv->vval.v_number = -1;
4832}
4833
4834/*
4835 * "getftype({fname})" function
4836 */
4837 static void
4838f_getftype(typval_T *argvars, typval_T *rettv)
4839{
4840 char_u *fname;
4841 stat_T st;
4842 char_u *type = NULL;
4843 char *t;
4844
4845 fname = get_tv_string(&argvars[0]);
4846
4847 rettv->v_type = VAR_STRING;
4848 if (mch_lstat((char *)fname, &st) >= 0)
4849 {
4850#ifdef S_ISREG
4851 if (S_ISREG(st.st_mode))
4852 t = "file";
4853 else if (S_ISDIR(st.st_mode))
4854 t = "dir";
4855# ifdef S_ISLNK
4856 else if (S_ISLNK(st.st_mode))
4857 t = "link";
4858# endif
4859# ifdef S_ISBLK
4860 else if (S_ISBLK(st.st_mode))
4861 t = "bdev";
4862# endif
4863# ifdef S_ISCHR
4864 else if (S_ISCHR(st.st_mode))
4865 t = "cdev";
4866# endif
4867# ifdef S_ISFIFO
4868 else if (S_ISFIFO(st.st_mode))
4869 t = "fifo";
4870# endif
4871# ifdef S_ISSOCK
4872 else if (S_ISSOCK(st.st_mode))
4873 t = "fifo";
4874# endif
4875 else
4876 t = "other";
4877#else
4878# ifdef S_IFMT
4879 switch (st.st_mode & S_IFMT)
4880 {
4881 case S_IFREG: t = "file"; break;
4882 case S_IFDIR: t = "dir"; break;
4883# ifdef S_IFLNK
4884 case S_IFLNK: t = "link"; break;
4885# endif
4886# ifdef S_IFBLK
4887 case S_IFBLK: t = "bdev"; break;
4888# endif
4889# ifdef S_IFCHR
4890 case S_IFCHR: t = "cdev"; break;
4891# endif
4892# ifdef S_IFIFO
4893 case S_IFIFO: t = "fifo"; break;
4894# endif
4895# ifdef S_IFSOCK
4896 case S_IFSOCK: t = "socket"; break;
4897# endif
4898 default: t = "other";
4899 }
4900# else
4901 if (mch_isdir(fname))
4902 t = "dir";
4903 else
4904 t = "file";
4905# endif
4906#endif
4907 type = vim_strsave((char_u *)t);
4908 }
4909 rettv->vval.v_string = type;
4910}
4911
4912/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004913 * "getjumplist()" function
4914 */
4915 static void
4916f_getjumplist(typval_T *argvars, typval_T *rettv)
4917{
4918#ifdef FEAT_JUMPLIST
4919 win_T *wp;
4920 int i;
4921 list_T *l;
4922 dict_T *d;
4923#endif
4924
4925 if (rettv_list_alloc(rettv) != OK)
4926 return;
4927
4928#ifdef FEAT_JUMPLIST
4929 wp = find_tabwin(&argvars[0], &argvars[1]);
4930 if (wp == NULL)
4931 return;
4932
4933 l = list_alloc();
4934 if (l == NULL)
4935 return;
4936
4937 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4938 return;
4939 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4940
Bram Moolenaar48679742018-02-13 13:33:29 +01004941 cleanup_jumplist(wp, TRUE);
4942
Bram Moolenaar4f505882018-02-10 21:06:32 +01004943 for (i = 0; i < wp->w_jumplistlen; ++i)
4944 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004945 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4946 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004947 if ((d = dict_alloc()) == NULL)
4948 return;
4949 if (list_append_dict(l, d) == FAIL)
4950 return;
4951 dict_add_nr_str(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum,
4952 NULL);
4953 dict_add_nr_str(d, "col", (long)wp->w_jumplist[i].fmark.mark.col,
4954 NULL);
4955# ifdef FEAT_VIRTUALEDIT
4956 dict_add_nr_str(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd,
4957 NULL);
4958# endif
4959 dict_add_nr_str(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum, NULL);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004960 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaar4f505882018-02-10 21:06:32 +01004961 dict_add_nr_str(d, "filename", 0L, wp->w_jumplist[i].fname);
4962 }
4963#endif
4964}
4965
4966/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004967 * "getline(lnum, [end])" function
4968 */
4969 static void
4970f_getline(typval_T *argvars, typval_T *rettv)
4971{
4972 linenr_T lnum;
4973 linenr_T end;
4974 int retlist;
4975
4976 lnum = get_tv_lnum(argvars);
4977 if (argvars[1].v_type == VAR_UNKNOWN)
4978 {
4979 end = 0;
4980 retlist = FALSE;
4981 }
4982 else
4983 {
4984 end = get_tv_lnum(&argvars[1]);
4985 retlist = TRUE;
4986 }
4987
4988 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4989}
4990
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004991#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004992 static void
4993get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4994{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004995 if (what_arg->v_type == VAR_UNKNOWN)
4996 {
4997 if (rettv_list_alloc(rettv) == OK)
4998 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004999 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005000 }
5001 else
5002 {
5003 if (rettv_dict_alloc(rettv) == OK)
5004 if (is_qf || (wp != NULL))
5005 {
5006 if (what_arg->v_type == VAR_DICT)
5007 {
5008 dict_T *d = what_arg->vval.v_dict;
5009
5010 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005011 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005012 }
5013 else
5014 EMSG(_(e_dictreq));
5015 }
5016 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005017}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005018#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005019
5020/*
5021 * "getloclist()" function
5022 */
5023 static void
5024f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5025{
5026#ifdef FEAT_QUICKFIX
5027 win_T *wp;
5028
5029 wp = find_win_by_nr(&argvars[0], NULL);
5030 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5031#endif
5032}
5033
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034/*
5035 * "getmatches()" function
5036 */
5037 static void
5038f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5039{
5040#ifdef FEAT_SEARCH_EXTRA
5041 dict_T *dict;
5042 matchitem_T *cur = curwin->w_match_head;
5043 int i;
5044
5045 if (rettv_list_alloc(rettv) == OK)
5046 {
5047 while (cur != NULL)
5048 {
5049 dict = dict_alloc();
5050 if (dict == NULL)
5051 return;
5052 if (cur->match.regprog == NULL)
5053 {
5054 /* match added with matchaddpos() */
5055 for (i = 0; i < MAXPOSMATCH; ++i)
5056 {
5057 llpos_T *llpos;
5058 char buf[6];
5059 list_T *l;
5060
5061 llpos = &cur->pos.pos[i];
5062 if (llpos->lnum == 0)
5063 break;
5064 l = list_alloc();
5065 if (l == NULL)
5066 break;
5067 list_append_number(l, (varnumber_T)llpos->lnum);
5068 if (llpos->col > 0)
5069 {
5070 list_append_number(l, (varnumber_T)llpos->col);
5071 list_append_number(l, (varnumber_T)llpos->len);
5072 }
5073 sprintf(buf, "pos%d", i + 1);
5074 dict_add_list(dict, buf, l);
5075 }
5076 }
5077 else
5078 {
5079 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
5080 }
5081 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
5082 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
5083 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
5084# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5085 if (cur->conceal_char)
5086 {
5087 char_u buf[MB_MAXBYTES + 1];
5088
5089 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5090 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
5091 }
5092# endif
5093 list_append_dict(rettv->vval.v_list, dict);
5094 cur = cur->next;
5095 }
5096 }
5097#endif
5098}
5099
5100/*
5101 * "getpid()" function
5102 */
5103 static void
5104f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5105{
5106 rettv->vval.v_number = mch_get_pid();
5107}
5108
5109 static void
5110getpos_both(
5111 typval_T *argvars,
5112 typval_T *rettv,
5113 int getcurpos)
5114{
5115 pos_T *fp;
5116 list_T *l;
5117 int fnum = -1;
5118
5119 if (rettv_list_alloc(rettv) == OK)
5120 {
5121 l = rettv->vval.v_list;
5122 if (getcurpos)
5123 fp = &curwin->w_cursor;
5124 else
5125 fp = var2fpos(&argvars[0], TRUE, &fnum);
5126 if (fnum != -1)
5127 list_append_number(l, (varnumber_T)fnum);
5128 else
5129 list_append_number(l, (varnumber_T)0);
5130 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5131 : (varnumber_T)0);
5132 list_append_number(l, (fp != NULL)
5133 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5134 : (varnumber_T)0);
5135 list_append_number(l,
5136#ifdef FEAT_VIRTUALEDIT
5137 (fp != NULL) ? (varnumber_T)fp->coladd :
5138#endif
5139 (varnumber_T)0);
5140 if (getcurpos)
5141 {
5142 update_curswant();
5143 list_append_number(l, curwin->w_curswant == MAXCOL ?
5144 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5145 }
5146 }
5147 else
5148 rettv->vval.v_number = FALSE;
5149}
5150
5151
5152/*
5153 * "getcurpos()" function
5154 */
5155 static void
5156f_getcurpos(typval_T *argvars, typval_T *rettv)
5157{
5158 getpos_both(argvars, rettv, TRUE);
5159}
5160
5161/*
5162 * "getpos(string)" function
5163 */
5164 static void
5165f_getpos(typval_T *argvars, typval_T *rettv)
5166{
5167 getpos_both(argvars, rettv, FALSE);
5168}
5169
5170/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005171 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005172 */
5173 static void
5174f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5175{
5176#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005177 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005178#endif
5179}
5180
5181/*
5182 * "getreg()" function
5183 */
5184 static void
5185f_getreg(typval_T *argvars, typval_T *rettv)
5186{
5187 char_u *strregname;
5188 int regname;
5189 int arg2 = FALSE;
5190 int return_list = FALSE;
5191 int error = FALSE;
5192
5193 if (argvars[0].v_type != VAR_UNKNOWN)
5194 {
5195 strregname = get_tv_string_chk(&argvars[0]);
5196 error = strregname == NULL;
5197 if (argvars[1].v_type != VAR_UNKNOWN)
5198 {
5199 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5200 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5201 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5202 }
5203 }
5204 else
5205 strregname = get_vim_var_str(VV_REG);
5206
5207 if (error)
5208 return;
5209
5210 regname = (strregname == NULL ? '"' : *strregname);
5211 if (regname == 0)
5212 regname = '"';
5213
5214 if (return_list)
5215 {
5216 rettv->v_type = VAR_LIST;
5217 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5218 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5219 if (rettv->vval.v_list == NULL)
5220 (void)rettv_list_alloc(rettv);
5221 else
5222 ++rettv->vval.v_list->lv_refcount;
5223 }
5224 else
5225 {
5226 rettv->v_type = VAR_STRING;
5227 rettv->vval.v_string = get_reg_contents(regname,
5228 arg2 ? GREG_EXPR_SRC : 0);
5229 }
5230}
5231
5232/*
5233 * "getregtype()" function
5234 */
5235 static void
5236f_getregtype(typval_T *argvars, typval_T *rettv)
5237{
5238 char_u *strregname;
5239 int regname;
5240 char_u buf[NUMBUFLEN + 2];
5241 long reglen = 0;
5242
5243 if (argvars[0].v_type != VAR_UNKNOWN)
5244 {
5245 strregname = get_tv_string_chk(&argvars[0]);
5246 if (strregname == NULL) /* type error; errmsg already given */
5247 {
5248 rettv->v_type = VAR_STRING;
5249 rettv->vval.v_string = NULL;
5250 return;
5251 }
5252 }
5253 else
5254 /* Default to v:register */
5255 strregname = get_vim_var_str(VV_REG);
5256
5257 regname = (strregname == NULL ? '"' : *strregname);
5258 if (regname == 0)
5259 regname = '"';
5260
5261 buf[0] = NUL;
5262 buf[1] = NUL;
5263 switch (get_reg_type(regname, &reglen))
5264 {
5265 case MLINE: buf[0] = 'V'; break;
5266 case MCHAR: buf[0] = 'v'; break;
5267 case MBLOCK:
5268 buf[0] = Ctrl_V;
5269 sprintf((char *)buf + 1, "%ld", reglen + 1);
5270 break;
5271 }
5272 rettv->v_type = VAR_STRING;
5273 rettv->vval.v_string = vim_strsave(buf);
5274}
5275
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005276/*
5277 * Returns information (variables, options, etc.) about a tab page
5278 * as a dictionary.
5279 */
5280 static dict_T *
5281get_tabpage_info(tabpage_T *tp, int tp_idx)
5282{
5283 win_T *wp;
5284 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005285 list_T *l;
5286
5287 dict = dict_alloc();
5288 if (dict == NULL)
5289 return NULL;
5290
Bram Moolenaar33928832016-08-18 21:22:04 +02005291 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005292
5293 l = list_alloc();
5294 if (l != NULL)
5295 {
5296 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5297 wp; wp = wp->w_next)
5298 list_append_number(l, (varnumber_T)wp->w_id);
5299 dict_add_list(dict, "windows", l);
5300 }
5301
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005302 /* Make a reference to tabpage variables */
5303 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005304
5305 return dict;
5306}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005307
5308/*
5309 * "gettabinfo()" function
5310 */
5311 static void
5312f_gettabinfo(typval_T *argvars, typval_T *rettv)
5313{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005314 tabpage_T *tp, *tparg = NULL;
5315 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005316 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005317
5318 if (rettv_list_alloc(rettv) != OK)
5319 return;
5320
5321 if (argvars[0].v_type != VAR_UNKNOWN)
5322 {
5323 /* Information about one tab page */
5324 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5325 if (tparg == NULL)
5326 return;
5327 }
5328
5329 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005330 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005331 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005332 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005333 if (tparg != NULL && tp != tparg)
5334 continue;
5335 d = get_tabpage_info(tp, tpnr);
5336 if (d != NULL)
5337 list_append_dict(rettv->vval.v_list, d);
5338 if (tparg != NULL)
5339 return;
5340 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005341}
5342
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005343/*
5344 * "gettabvar()" function
5345 */
5346 static void
5347f_gettabvar(typval_T *argvars, typval_T *rettv)
5348{
5349 win_T *oldcurwin;
5350 tabpage_T *tp, *oldtabpage;
5351 dictitem_T *v;
5352 char_u *varname;
5353 int done = FALSE;
5354
5355 rettv->v_type = VAR_STRING;
5356 rettv->vval.v_string = NULL;
5357
5358 varname = get_tv_string_chk(&argvars[1]);
5359 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5360 if (tp != NULL && varname != NULL)
5361 {
5362 /* Set tp to be our tabpage, temporarily. Also set the window to the
5363 * first window in the tabpage, otherwise the window is not valid. */
5364 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005365 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5366 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005367 {
5368 /* look up the variable */
5369 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5370 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5371 if (v != NULL)
5372 {
5373 copy_tv(&v->di_tv, rettv);
5374 done = TRUE;
5375 }
5376 }
5377
5378 /* restore previous notion of curwin */
5379 restore_win(oldcurwin, oldtabpage, TRUE);
5380 }
5381
5382 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5383 copy_tv(&argvars[2], rettv);
5384}
5385
5386/*
5387 * "gettabwinvar()" function
5388 */
5389 static void
5390f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5391{
5392 getwinvar(argvars, rettv, 1);
5393}
5394
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005395/*
5396 * Returns information about a window as a dictionary.
5397 */
5398 static dict_T *
5399get_win_info(win_T *wp, short tpnr, short winnr)
5400{
5401 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005402
5403 dict = dict_alloc();
5404 if (dict == NULL)
5405 return NULL;
5406
Bram Moolenaar33928832016-08-18 21:22:04 +02005407 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5408 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005409 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5410 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005411#ifdef FEAT_MENU
5412 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5413#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005414 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005415 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005416
Bram Moolenaar69905d12017-08-13 18:14:47 +02005417#ifdef FEAT_TERMINAL
5418 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5419#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005420#ifdef FEAT_QUICKFIX
5421 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5422 dict_add_nr_str(dict, "loclist",
5423 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5424#endif
5425
Bram Moolenaar30567352016-08-27 21:25:44 +02005426 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005427 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005428
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005429 return dict;
5430}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005431
5432/*
5433 * "getwininfo()" function
5434 */
5435 static void
5436f_getwininfo(typval_T *argvars, typval_T *rettv)
5437{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005438 tabpage_T *tp;
5439 win_T *wp = NULL, *wparg = NULL;
5440 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005441 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005442
5443 if (rettv_list_alloc(rettv) != OK)
5444 return;
5445
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005446 if (argvars[0].v_type != VAR_UNKNOWN)
5447 {
5448 wparg = win_id2wp(argvars);
5449 if (wparg == NULL)
5450 return;
5451 }
5452
5453 /* Collect information about either all the windows across all the tab
5454 * pages or one particular window.
5455 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005456 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005457 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005458 tabnr++;
5459 winnr = 0;
5460 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005461 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005462 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005463 if (wparg != NULL && wp != wparg)
5464 continue;
5465 d = get_win_info(wp, tabnr, winnr);
5466 if (d != NULL)
5467 list_append_dict(rettv->vval.v_list, d);
5468 if (wparg != NULL)
5469 /* found information about a specific window */
5470 return;
5471 }
5472 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005473}
5474
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005475/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005476 * "win_findbuf()" function
5477 */
5478 static void
5479f_win_findbuf(typval_T *argvars, typval_T *rettv)
5480{
5481 if (rettv_list_alloc(rettv) != FAIL)
5482 win_findbuf(argvars, rettv->vval.v_list);
5483}
5484
5485/*
5486 * "win_getid()" function
5487 */
5488 static void
5489f_win_getid(typval_T *argvars, typval_T *rettv)
5490{
5491 rettv->vval.v_number = win_getid(argvars);
5492}
5493
5494/*
5495 * "win_gotoid()" function
5496 */
5497 static void
5498f_win_gotoid(typval_T *argvars, typval_T *rettv)
5499{
5500 rettv->vval.v_number = win_gotoid(argvars);
5501}
5502
5503/*
5504 * "win_id2tabwin()" function
5505 */
5506 static void
5507f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5508{
5509 if (rettv_list_alloc(rettv) != FAIL)
5510 win_id2tabwin(argvars, rettv->vval.v_list);
5511}
5512
5513/*
5514 * "win_id2win()" function
5515 */
5516 static void
5517f_win_id2win(typval_T *argvars, typval_T *rettv)
5518{
5519 rettv->vval.v_number = win_id2win(argvars);
5520}
5521
5522/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005523 * "win_screenpos()" function
5524 */
5525 static void
5526f_win_screenpos(typval_T *argvars, typval_T *rettv)
5527{
5528 win_T *wp;
5529
5530 if (rettv_list_alloc(rettv) == FAIL)
5531 return;
5532
5533 wp = find_win_by_nr(&argvars[0], NULL);
5534 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5535 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5536}
5537
5538/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005539 * "getwinpos({timeout})" function
5540 */
5541 static void
5542f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5543{
5544 int x = -1;
5545 int y = -1;
5546
5547 if (rettv_list_alloc(rettv) == FAIL)
5548 return;
5549#ifdef FEAT_GUI
5550 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005551 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005552# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5553 else
5554# endif
5555#endif
5556#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5557 {
5558 varnumber_T timeout = 100;
5559
5560 if (argvars[0].v_type != VAR_UNKNOWN)
5561 timeout = get_tv_number(&argvars[0]);
5562 term_get_winpos(&x, &y, timeout);
5563 }
5564#endif
5565 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5566 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5567}
5568
5569
5570/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005571 * "getwinposx()" function
5572 */
5573 static void
5574f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5575{
5576 rettv->vval.v_number = -1;
5577#ifdef FEAT_GUI
5578 if (gui.in_use)
5579 {
5580 int x, y;
5581
5582 if (gui_mch_get_winpos(&x, &y) == OK)
5583 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005584 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005585 }
5586#endif
5587#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5588 {
5589 int x, y;
5590
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005591 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005592 rettv->vval.v_number = x;
5593 }
5594#endif
5595}
5596
5597/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005598 * "getwinposy()" function
5599 */
5600 static void
5601f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5602{
5603 rettv->vval.v_number = -1;
5604#ifdef FEAT_GUI
5605 if (gui.in_use)
5606 {
5607 int x, y;
5608
5609 if (gui_mch_get_winpos(&x, &y) == OK)
5610 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005611 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005612 }
5613#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005614#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5615 {
5616 int x, y;
5617
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005618 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005619 rettv->vval.v_number = y;
5620 }
5621#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005622}
5623
5624/*
5625 * "getwinvar()" function
5626 */
5627 static void
5628f_getwinvar(typval_T *argvars, typval_T *rettv)
5629{
5630 getwinvar(argvars, rettv, 0);
5631}
5632
5633/*
5634 * "glob()" function
5635 */
5636 static void
5637f_glob(typval_T *argvars, typval_T *rettv)
5638{
5639 int options = WILD_SILENT|WILD_USE_NL;
5640 expand_T xpc;
5641 int error = FALSE;
5642
5643 /* When the optional second argument is non-zero, don't remove matches
5644 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5645 rettv->v_type = VAR_STRING;
5646 if (argvars[1].v_type != VAR_UNKNOWN)
5647 {
5648 if (get_tv_number_chk(&argvars[1], &error))
5649 options |= WILD_KEEP_ALL;
5650 if (argvars[2].v_type != VAR_UNKNOWN)
5651 {
5652 if (get_tv_number_chk(&argvars[2], &error))
5653 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005654 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005655 }
5656 if (argvars[3].v_type != VAR_UNKNOWN
5657 && get_tv_number_chk(&argvars[3], &error))
5658 options |= WILD_ALLLINKS;
5659 }
5660 }
5661 if (!error)
5662 {
5663 ExpandInit(&xpc);
5664 xpc.xp_context = EXPAND_FILES;
5665 if (p_wic)
5666 options += WILD_ICASE;
5667 if (rettv->v_type == VAR_STRING)
5668 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5669 NULL, options, WILD_ALL);
5670 else if (rettv_list_alloc(rettv) != FAIL)
5671 {
5672 int i;
5673
5674 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5675 NULL, options, WILD_ALL_KEEP);
5676 for (i = 0; i < xpc.xp_numfiles; i++)
5677 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5678
5679 ExpandCleanup(&xpc);
5680 }
5681 }
5682 else
5683 rettv->vval.v_string = NULL;
5684}
5685
5686/*
5687 * "globpath()" function
5688 */
5689 static void
5690f_globpath(typval_T *argvars, typval_T *rettv)
5691{
5692 int flags = 0;
5693 char_u buf1[NUMBUFLEN];
5694 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5695 int error = FALSE;
5696 garray_T ga;
5697 int i;
5698
5699 /* When the optional second argument is non-zero, don't remove matches
5700 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5701 rettv->v_type = VAR_STRING;
5702 if (argvars[2].v_type != VAR_UNKNOWN)
5703 {
5704 if (get_tv_number_chk(&argvars[2], &error))
5705 flags |= WILD_KEEP_ALL;
5706 if (argvars[3].v_type != VAR_UNKNOWN)
5707 {
5708 if (get_tv_number_chk(&argvars[3], &error))
5709 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005710 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005711 }
5712 if (argvars[4].v_type != VAR_UNKNOWN
5713 && get_tv_number_chk(&argvars[4], &error))
5714 flags |= WILD_ALLLINKS;
5715 }
5716 }
5717 if (file != NULL && !error)
5718 {
5719 ga_init2(&ga, (int)sizeof(char_u *), 10);
5720 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5721 if (rettv->v_type == VAR_STRING)
5722 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5723 else if (rettv_list_alloc(rettv) != FAIL)
5724 for (i = 0; i < ga.ga_len; ++i)
5725 list_append_string(rettv->vval.v_list,
5726 ((char_u **)(ga.ga_data))[i], -1);
5727 ga_clear_strings(&ga);
5728 }
5729 else
5730 rettv->vval.v_string = NULL;
5731}
5732
5733/*
5734 * "glob2regpat()" function
5735 */
5736 static void
5737f_glob2regpat(typval_T *argvars, typval_T *rettv)
5738{
5739 char_u *pat = get_tv_string_chk(&argvars[0]);
5740
5741 rettv->v_type = VAR_STRING;
5742 rettv->vval.v_string = (pat == NULL)
5743 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5744}
5745
5746/* for VIM_VERSION_ defines */
5747#include "version.h"
5748
5749/*
5750 * "has()" function
5751 */
5752 static void
5753f_has(typval_T *argvars, typval_T *rettv)
5754{
5755 int i;
5756 char_u *name;
5757 int n = FALSE;
5758 static char *(has_list[]) =
5759 {
5760#ifdef AMIGA
5761 "amiga",
5762# ifdef FEAT_ARP
5763 "arp",
5764# endif
5765#endif
5766#ifdef __BEOS__
5767 "beos",
5768#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005769#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005770 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5771 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005772# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005773 "macunix", /* Mac OS X, with the darwin feature */
5774 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005775# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005776#endif
5777#ifdef __QNX__
5778 "qnx",
5779#endif
5780#ifdef UNIX
5781 "unix",
5782#endif
5783#ifdef VMS
5784 "vms",
5785#endif
5786#ifdef WIN32
5787 "win32",
5788#endif
5789#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5790 "win32unix",
5791#endif
5792#if defined(WIN64) || defined(_WIN64)
5793 "win64",
5794#endif
5795#ifdef EBCDIC
5796 "ebcdic",
5797#endif
5798#ifndef CASE_INSENSITIVE_FILENAME
5799 "fname_case",
5800#endif
5801#ifdef HAVE_ACL
5802 "acl",
5803#endif
5804#ifdef FEAT_ARABIC
5805 "arabic",
5806#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005807 "autocmd",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005808#ifdef FEAT_AUTOSERVERNAME
5809 "autoservername",
5810#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005811#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005812 "balloon_eval",
5813# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5814 "balloon_multiline",
5815# endif
5816#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005817#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005818 "balloon_eval_term",
5819#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005820#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5821 "builtin_terms",
5822# ifdef ALL_BUILTIN_TCAPS
5823 "all_builtin_terms",
5824# endif
5825#endif
5826#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5827 || defined(FEAT_GUI_W32) \
5828 || defined(FEAT_GUI_MOTIF))
5829 "browsefilter",
5830#endif
5831#ifdef FEAT_BYTEOFF
5832 "byte_offset",
5833#endif
5834#ifdef FEAT_JOB_CHANNEL
5835 "channel",
5836#endif
5837#ifdef FEAT_CINDENT
5838 "cindent",
5839#endif
5840#ifdef FEAT_CLIENTSERVER
5841 "clientserver",
5842#endif
5843#ifdef FEAT_CLIPBOARD
5844 "clipboard",
5845#endif
5846#ifdef FEAT_CMDL_COMPL
5847 "cmdline_compl",
5848#endif
5849#ifdef FEAT_CMDHIST
5850 "cmdline_hist",
5851#endif
5852#ifdef FEAT_COMMENTS
5853 "comments",
5854#endif
5855#ifdef FEAT_CONCEAL
5856 "conceal",
5857#endif
5858#ifdef FEAT_CRYPT
5859 "cryptv",
5860 "crypt-blowfish",
5861 "crypt-blowfish2",
5862#endif
5863#ifdef FEAT_CSCOPE
5864 "cscope",
5865#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005866 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005867#ifdef CURSOR_SHAPE
5868 "cursorshape",
5869#endif
5870#ifdef DEBUG
5871 "debug",
5872#endif
5873#ifdef FEAT_CON_DIALOG
5874 "dialog_con",
5875#endif
5876#ifdef FEAT_GUI_DIALOG
5877 "dialog_gui",
5878#endif
5879#ifdef FEAT_DIFF
5880 "diff",
5881#endif
5882#ifdef FEAT_DIGRAPHS
5883 "digraphs",
5884#endif
5885#ifdef FEAT_DIRECTX
5886 "directx",
5887#endif
5888#ifdef FEAT_DND
5889 "dnd",
5890#endif
5891#ifdef FEAT_EMACS_TAGS
5892 "emacs_tags",
5893#endif
5894 "eval", /* always present, of course! */
5895 "ex_extra", /* graduated feature */
5896#ifdef FEAT_SEARCH_EXTRA
5897 "extra_search",
5898#endif
5899#ifdef FEAT_FKMAP
5900 "farsi",
5901#endif
5902#ifdef FEAT_SEARCHPATH
5903 "file_in_path",
5904#endif
5905#ifdef FEAT_FILTERPIPE
5906 "filterpipe",
5907#endif
5908#ifdef FEAT_FIND_ID
5909 "find_in_path",
5910#endif
5911#ifdef FEAT_FLOAT
5912 "float",
5913#endif
5914#ifdef FEAT_FOLDING
5915 "folding",
5916#endif
5917#ifdef FEAT_FOOTER
5918 "footer",
5919#endif
5920#if !defined(USE_SYSTEM) && defined(UNIX)
5921 "fork",
5922#endif
5923#ifdef FEAT_GETTEXT
5924 "gettext",
5925#endif
5926#ifdef FEAT_GUI
5927 "gui",
5928#endif
5929#ifdef FEAT_GUI_ATHENA
5930# ifdef FEAT_GUI_NEXTAW
5931 "gui_neXtaw",
5932# else
5933 "gui_athena",
5934# endif
5935#endif
5936#ifdef FEAT_GUI_GTK
5937 "gui_gtk",
5938# ifdef USE_GTK3
5939 "gui_gtk3",
5940# else
5941 "gui_gtk2",
5942# endif
5943#endif
5944#ifdef FEAT_GUI_GNOME
5945 "gui_gnome",
5946#endif
5947#ifdef FEAT_GUI_MAC
5948 "gui_mac",
5949#endif
5950#ifdef FEAT_GUI_MOTIF
5951 "gui_motif",
5952#endif
5953#ifdef FEAT_GUI_PHOTON
5954 "gui_photon",
5955#endif
5956#ifdef FEAT_GUI_W32
5957 "gui_win32",
5958#endif
5959#ifdef FEAT_HANGULIN
5960 "hangul_input",
5961#endif
5962#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5963 "iconv",
5964#endif
5965#ifdef FEAT_INS_EXPAND
5966 "insert_expand",
5967#endif
5968#ifdef FEAT_JOB_CHANNEL
5969 "job",
5970#endif
5971#ifdef FEAT_JUMPLIST
5972 "jumplist",
5973#endif
5974#ifdef FEAT_KEYMAP
5975 "keymap",
5976#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005977 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978#ifdef FEAT_LANGMAP
5979 "langmap",
5980#endif
5981#ifdef FEAT_LIBCALL
5982 "libcall",
5983#endif
5984#ifdef FEAT_LINEBREAK
5985 "linebreak",
5986#endif
5987#ifdef FEAT_LISP
5988 "lispindent",
5989#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005990 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005991#ifdef FEAT_LOCALMAP
5992 "localmap",
5993#endif
5994#ifdef FEAT_LUA
5995# ifndef DYNAMIC_LUA
5996 "lua",
5997# endif
5998#endif
5999#ifdef FEAT_MENU
6000 "menu",
6001#endif
6002#ifdef FEAT_SESSION
6003 "mksession",
6004#endif
6005#ifdef FEAT_MODIFY_FNAME
6006 "modify_fname",
6007#endif
6008#ifdef FEAT_MOUSE
6009 "mouse",
6010#endif
6011#ifdef FEAT_MOUSESHAPE
6012 "mouseshape",
6013#endif
6014#if defined(UNIX) || defined(VMS)
6015# ifdef FEAT_MOUSE_DEC
6016 "mouse_dec",
6017# endif
6018# ifdef FEAT_MOUSE_GPM
6019 "mouse_gpm",
6020# endif
6021# ifdef FEAT_MOUSE_JSB
6022 "mouse_jsbterm",
6023# endif
6024# ifdef FEAT_MOUSE_NET
6025 "mouse_netterm",
6026# endif
6027# ifdef FEAT_MOUSE_PTERM
6028 "mouse_pterm",
6029# endif
6030# ifdef FEAT_MOUSE_SGR
6031 "mouse_sgr",
6032# endif
6033# ifdef FEAT_SYSMOUSE
6034 "mouse_sysmouse",
6035# endif
6036# ifdef FEAT_MOUSE_URXVT
6037 "mouse_urxvt",
6038# endif
6039# ifdef FEAT_MOUSE_XTERM
6040 "mouse_xterm",
6041# endif
6042#endif
6043#ifdef FEAT_MBYTE
6044 "multi_byte",
6045#endif
6046#ifdef FEAT_MBYTE_IME
6047 "multi_byte_ime",
6048#endif
6049#ifdef FEAT_MULTI_LANG
6050 "multi_lang",
6051#endif
6052#ifdef FEAT_MZSCHEME
6053#ifndef DYNAMIC_MZSCHEME
6054 "mzscheme",
6055#endif
6056#endif
6057#ifdef FEAT_NUM64
6058 "num64",
6059#endif
6060#ifdef FEAT_OLE
6061 "ole",
6062#endif
6063 "packages",
6064#ifdef FEAT_PATH_EXTRA
6065 "path_extra",
6066#endif
6067#ifdef FEAT_PERL
6068#ifndef DYNAMIC_PERL
6069 "perl",
6070#endif
6071#endif
6072#ifdef FEAT_PERSISTENT_UNDO
6073 "persistent_undo",
6074#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006075#if defined(FEAT_PYTHON)
6076 "python_compiled",
6077# if defined(DYNAMIC_PYTHON)
6078 "python_dynamic",
6079# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006080 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006081 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006082# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006084#if defined(FEAT_PYTHON3)
6085 "python3_compiled",
6086# if defined(DYNAMIC_PYTHON3)
6087 "python3_dynamic",
6088# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006089 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006090 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006091# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006092#endif
6093#ifdef FEAT_POSTSCRIPT
6094 "postscript",
6095#endif
6096#ifdef FEAT_PRINTER
6097 "printer",
6098#endif
6099#ifdef FEAT_PROFILE
6100 "profile",
6101#endif
6102#ifdef FEAT_RELTIME
6103 "reltime",
6104#endif
6105#ifdef FEAT_QUICKFIX
6106 "quickfix",
6107#endif
6108#ifdef FEAT_RIGHTLEFT
6109 "rightleft",
6110#endif
6111#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6112 "ruby",
6113#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006114 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006115#ifdef FEAT_CMDL_INFO
6116 "showcmd",
6117 "cmdline_info",
6118#endif
6119#ifdef FEAT_SIGNS
6120 "signs",
6121#endif
6122#ifdef FEAT_SMARTINDENT
6123 "smartindent",
6124#endif
6125#ifdef STARTUPTIME
6126 "startuptime",
6127#endif
6128#ifdef FEAT_STL_OPT
6129 "statusline",
6130#endif
6131#ifdef FEAT_SUN_WORKSHOP
6132 "sun_workshop",
6133#endif
6134#ifdef FEAT_NETBEANS_INTG
6135 "netbeans_intg",
6136#endif
6137#ifdef FEAT_SPELL
6138 "spell",
6139#endif
6140#ifdef FEAT_SYN_HL
6141 "syntax",
6142#endif
6143#if defined(USE_SYSTEM) || !defined(UNIX)
6144 "system",
6145#endif
6146#ifdef FEAT_TAG_BINS
6147 "tag_binary",
6148#endif
6149#ifdef FEAT_TAG_OLDSTATIC
6150 "tag_old_static",
6151#endif
6152#ifdef FEAT_TAG_ANYWHITE
6153 "tag_any_white",
6154#endif
6155#ifdef FEAT_TCL
6156# ifndef DYNAMIC_TCL
6157 "tcl",
6158# endif
6159#endif
6160#ifdef FEAT_TERMGUICOLORS
6161 "termguicolors",
6162#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006163#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006164 "terminal",
6165#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166#ifdef TERMINFO
6167 "terminfo",
6168#endif
6169#ifdef FEAT_TERMRESPONSE
6170 "termresponse",
6171#endif
6172#ifdef FEAT_TEXTOBJ
6173 "textobjects",
6174#endif
6175#ifdef HAVE_TGETENT
6176 "tgetent",
6177#endif
6178#ifdef FEAT_TIMERS
6179 "timers",
6180#endif
6181#ifdef FEAT_TITLE
6182 "title",
6183#endif
6184#ifdef FEAT_TOOLBAR
6185 "toolbar",
6186#endif
6187#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6188 "unnamedplus",
6189#endif
6190#ifdef FEAT_USR_CMDS
6191 "user-commands", /* was accidentally included in 5.4 */
6192 "user_commands",
6193#endif
6194#ifdef FEAT_VIMINFO
6195 "viminfo",
6196#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198#ifdef FEAT_VIRTUALEDIT
6199 "virtualedit",
6200#endif
6201 "visual",
6202#ifdef FEAT_VISUALEXTRA
6203 "visualextra",
6204#endif
6205#ifdef FEAT_VREPLACE
6206 "vreplace",
6207#endif
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006208#ifdef FEAT_VTP
6209 "vtp",
6210#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006211#ifdef FEAT_WILDIGN
6212 "wildignore",
6213#endif
6214#ifdef FEAT_WILDMENU
6215 "wildmenu",
6216#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006217 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218#ifdef FEAT_WAK
6219 "winaltkeys",
6220#endif
6221#ifdef FEAT_WRITEBACKUP
6222 "writebackup",
6223#endif
6224#ifdef FEAT_XIM
6225 "xim",
6226#endif
6227#ifdef FEAT_XFONTSET
6228 "xfontset",
6229#endif
6230#ifdef FEAT_XPM_W32
6231 "xpm",
6232 "xpm_w32", /* for backward compatibility */
6233#else
6234# if defined(HAVE_XPM)
6235 "xpm",
6236# endif
6237#endif
6238#ifdef USE_XSMP
6239 "xsmp",
6240#endif
6241#ifdef USE_XSMP_INTERACT
6242 "xsmp_interact",
6243#endif
6244#ifdef FEAT_XCLIPBOARD
6245 "xterm_clipboard",
6246#endif
6247#ifdef FEAT_XTERM_SAVE
6248 "xterm_save",
6249#endif
6250#if defined(UNIX) && defined(FEAT_X11)
6251 "X11",
6252#endif
6253 NULL
6254 };
6255
6256 name = get_tv_string(&argvars[0]);
6257 for (i = 0; has_list[i] != NULL; ++i)
6258 if (STRICMP(name, has_list[i]) == 0)
6259 {
6260 n = TRUE;
6261 break;
6262 }
6263
6264 if (n == FALSE)
6265 {
6266 if (STRNICMP(name, "patch", 5) == 0)
6267 {
6268 if (name[5] == '-'
6269 && STRLEN(name) >= 11
6270 && vim_isdigit(name[6])
6271 && vim_isdigit(name[8])
6272 && vim_isdigit(name[10]))
6273 {
6274 int major = atoi((char *)name + 6);
6275 int minor = atoi((char *)name + 8);
6276
6277 /* Expect "patch-9.9.01234". */
6278 n = (major < VIM_VERSION_MAJOR
6279 || (major == VIM_VERSION_MAJOR
6280 && (minor < VIM_VERSION_MINOR
6281 || (minor == VIM_VERSION_MINOR
6282 && has_patch(atoi((char *)name + 10))))));
6283 }
6284 else
6285 n = has_patch(atoi((char *)name + 5));
6286 }
6287 else if (STRICMP(name, "vim_starting") == 0)
6288 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006289 else if (STRICMP(name, "ttyin") == 0)
6290 n = mch_input_isatty();
6291 else if (STRICMP(name, "ttyout") == 0)
6292 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293#ifdef FEAT_MBYTE
6294 else if (STRICMP(name, "multi_byte_encoding") == 0)
6295 n = has_mbyte;
6296#endif
6297#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6298 else if (STRICMP(name, "balloon_multiline") == 0)
6299 n = multiline_balloon_available();
6300#endif
6301#ifdef DYNAMIC_TCL
6302 else if (STRICMP(name, "tcl") == 0)
6303 n = tcl_enabled(FALSE);
6304#endif
6305#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6306 else if (STRICMP(name, "iconv") == 0)
6307 n = iconv_enabled(FALSE);
6308#endif
6309#ifdef DYNAMIC_LUA
6310 else if (STRICMP(name, "lua") == 0)
6311 n = lua_enabled(FALSE);
6312#endif
6313#ifdef DYNAMIC_MZSCHEME
6314 else if (STRICMP(name, "mzscheme") == 0)
6315 n = mzscheme_enabled(FALSE);
6316#endif
6317#ifdef DYNAMIC_RUBY
6318 else if (STRICMP(name, "ruby") == 0)
6319 n = ruby_enabled(FALSE);
6320#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321#ifdef DYNAMIC_PYTHON
6322 else if (STRICMP(name, "python") == 0)
6323 n = python_enabled(FALSE);
6324#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325#ifdef DYNAMIC_PYTHON3
6326 else if (STRICMP(name, "python3") == 0)
6327 n = python3_enabled(FALSE);
6328#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006329#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6330 else if (STRICMP(name, "pythonx") == 0)
6331 {
6332# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6333 if (p_pyx == 0)
6334 n = python3_enabled(FALSE) || python_enabled(FALSE);
6335 else if (p_pyx == 3)
6336 n = python3_enabled(FALSE);
6337 else if (p_pyx == 2)
6338 n = python_enabled(FALSE);
6339# elif defined(DYNAMIC_PYTHON)
6340 n = python_enabled(FALSE);
6341# elif defined(DYNAMIC_PYTHON3)
6342 n = python3_enabled(FALSE);
6343# endif
6344 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345#endif
6346#ifdef DYNAMIC_PERL
6347 else if (STRICMP(name, "perl") == 0)
6348 n = perl_enabled(FALSE);
6349#endif
6350#ifdef FEAT_GUI
6351 else if (STRICMP(name, "gui_running") == 0)
6352 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353# ifdef FEAT_BROWSE
6354 else if (STRICMP(name, "browse") == 0)
6355 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6356# endif
6357#endif
6358#ifdef FEAT_SYN_HL
6359 else if (STRICMP(name, "syntax_items") == 0)
6360 n = syntax_present(curwin);
6361#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006362#ifdef FEAT_VTP
6363 else if (STRICMP(name, "vcon") == 0)
6364 n = has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365#endif
6366#ifdef FEAT_NETBEANS_INTG
6367 else if (STRICMP(name, "netbeans_enabled") == 0)
6368 n = netbeans_active();
6369#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006370#if defined(FEAT_TERMINAL) && defined(WIN3264)
6371 else if (STRICMP(name, "terminal") == 0)
6372 n = terminal_enabled();
6373#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006374 }
6375
6376 rettv->vval.v_number = n;
6377}
6378
6379/*
6380 * "has_key()" function
6381 */
6382 static void
6383f_has_key(typval_T *argvars, typval_T *rettv)
6384{
6385 if (argvars[0].v_type != VAR_DICT)
6386 {
6387 EMSG(_(e_dictreq));
6388 return;
6389 }
6390 if (argvars[0].vval.v_dict == NULL)
6391 return;
6392
6393 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6394 get_tv_string(&argvars[1]), -1) != NULL;
6395}
6396
6397/*
6398 * "haslocaldir()" function
6399 */
6400 static void
6401f_haslocaldir(typval_T *argvars, typval_T *rettv)
6402{
6403 win_T *wp = NULL;
6404
6405 wp = find_tabwin(&argvars[0], &argvars[1]);
6406 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6407}
6408
6409/*
6410 * "hasmapto()" function
6411 */
6412 static void
6413f_hasmapto(typval_T *argvars, typval_T *rettv)
6414{
6415 char_u *name;
6416 char_u *mode;
6417 char_u buf[NUMBUFLEN];
6418 int abbr = FALSE;
6419
6420 name = get_tv_string(&argvars[0]);
6421 if (argvars[1].v_type == VAR_UNKNOWN)
6422 mode = (char_u *)"nvo";
6423 else
6424 {
6425 mode = get_tv_string_buf(&argvars[1], buf);
6426 if (argvars[2].v_type != VAR_UNKNOWN)
6427 abbr = (int)get_tv_number(&argvars[2]);
6428 }
6429
6430 if (map_to_exists(name, mode, abbr))
6431 rettv->vval.v_number = TRUE;
6432 else
6433 rettv->vval.v_number = FALSE;
6434}
6435
6436/*
6437 * "histadd()" function
6438 */
6439 static void
6440f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6441{
6442#ifdef FEAT_CMDHIST
6443 int histype;
6444 char_u *str;
6445 char_u buf[NUMBUFLEN];
6446#endif
6447
6448 rettv->vval.v_number = FALSE;
6449 if (check_restricted() || check_secure())
6450 return;
6451#ifdef FEAT_CMDHIST
6452 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6453 histype = str != NULL ? get_histtype(str) : -1;
6454 if (histype >= 0)
6455 {
6456 str = get_tv_string_buf(&argvars[1], buf);
6457 if (*str != NUL)
6458 {
6459 init_history();
6460 add_to_history(histype, str, FALSE, NUL);
6461 rettv->vval.v_number = TRUE;
6462 return;
6463 }
6464 }
6465#endif
6466}
6467
6468/*
6469 * "histdel()" function
6470 */
6471 static void
6472f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6473{
6474#ifdef FEAT_CMDHIST
6475 int n;
6476 char_u buf[NUMBUFLEN];
6477 char_u *str;
6478
6479 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6480 if (str == NULL)
6481 n = 0;
6482 else if (argvars[1].v_type == VAR_UNKNOWN)
6483 /* only one argument: clear entire history */
6484 n = clr_history(get_histtype(str));
6485 else if (argvars[1].v_type == VAR_NUMBER)
6486 /* index given: remove that entry */
6487 n = del_history_idx(get_histtype(str),
6488 (int)get_tv_number(&argvars[1]));
6489 else
6490 /* string given: remove all matching entries */
6491 n = del_history_entry(get_histtype(str),
6492 get_tv_string_buf(&argvars[1], buf));
6493 rettv->vval.v_number = n;
6494#endif
6495}
6496
6497/*
6498 * "histget()" function
6499 */
6500 static void
6501f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6502{
6503#ifdef FEAT_CMDHIST
6504 int type;
6505 int idx;
6506 char_u *str;
6507
6508 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6509 if (str == NULL)
6510 rettv->vval.v_string = NULL;
6511 else
6512 {
6513 type = get_histtype(str);
6514 if (argvars[1].v_type == VAR_UNKNOWN)
6515 idx = get_history_idx(type);
6516 else
6517 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6518 /* -1 on type error */
6519 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6520 }
6521#else
6522 rettv->vval.v_string = NULL;
6523#endif
6524 rettv->v_type = VAR_STRING;
6525}
6526
6527/*
6528 * "histnr()" function
6529 */
6530 static void
6531f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6532{
6533 int i;
6534
6535#ifdef FEAT_CMDHIST
6536 char_u *history = get_tv_string_chk(&argvars[0]);
6537
6538 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6539 if (i >= HIST_CMD && i < HIST_COUNT)
6540 i = get_history_idx(i);
6541 else
6542#endif
6543 i = -1;
6544 rettv->vval.v_number = i;
6545}
6546
6547/*
6548 * "highlightID(name)" function
6549 */
6550 static void
6551f_hlID(typval_T *argvars, typval_T *rettv)
6552{
6553 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6554}
6555
6556/*
6557 * "highlight_exists()" function
6558 */
6559 static void
6560f_hlexists(typval_T *argvars, typval_T *rettv)
6561{
6562 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6563}
6564
6565/*
6566 * "hostname()" function
6567 */
6568 static void
6569f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6570{
6571 char_u hostname[256];
6572
6573 mch_get_host_name(hostname, 256);
6574 rettv->v_type = VAR_STRING;
6575 rettv->vval.v_string = vim_strsave(hostname);
6576}
6577
6578/*
6579 * iconv() function
6580 */
6581 static void
6582f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6583{
6584#ifdef FEAT_MBYTE
6585 char_u buf1[NUMBUFLEN];
6586 char_u buf2[NUMBUFLEN];
6587 char_u *from, *to, *str;
6588 vimconv_T vimconv;
6589#endif
6590
6591 rettv->v_type = VAR_STRING;
6592 rettv->vval.v_string = NULL;
6593
6594#ifdef FEAT_MBYTE
6595 str = get_tv_string(&argvars[0]);
6596 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6597 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6598 vimconv.vc_type = CONV_NONE;
6599 convert_setup(&vimconv, from, to);
6600
6601 /* If the encodings are equal, no conversion needed. */
6602 if (vimconv.vc_type == CONV_NONE)
6603 rettv->vval.v_string = vim_strsave(str);
6604 else
6605 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6606
6607 convert_setup(&vimconv, NULL, NULL);
6608 vim_free(from);
6609 vim_free(to);
6610#endif
6611}
6612
6613/*
6614 * "indent()" function
6615 */
6616 static void
6617f_indent(typval_T *argvars, typval_T *rettv)
6618{
6619 linenr_T lnum;
6620
6621 lnum = get_tv_lnum(argvars);
6622 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6623 rettv->vval.v_number = get_indent_lnum(lnum);
6624 else
6625 rettv->vval.v_number = -1;
6626}
6627
6628/*
6629 * "index()" function
6630 */
6631 static void
6632f_index(typval_T *argvars, typval_T *rettv)
6633{
6634 list_T *l;
6635 listitem_T *item;
6636 long idx = 0;
6637 int ic = FALSE;
6638
6639 rettv->vval.v_number = -1;
6640 if (argvars[0].v_type != VAR_LIST)
6641 {
6642 EMSG(_(e_listreq));
6643 return;
6644 }
6645 l = argvars[0].vval.v_list;
6646 if (l != NULL)
6647 {
6648 item = l->lv_first;
6649 if (argvars[2].v_type != VAR_UNKNOWN)
6650 {
6651 int error = FALSE;
6652
6653 /* Start at specified item. Use the cached index that list_find()
6654 * sets, so that a negative number also works. */
6655 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6656 idx = l->lv_idx;
6657 if (argvars[3].v_type != VAR_UNKNOWN)
6658 ic = (int)get_tv_number_chk(&argvars[3], &error);
6659 if (error)
6660 item = NULL;
6661 }
6662
6663 for ( ; item != NULL; item = item->li_next, ++idx)
6664 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6665 {
6666 rettv->vval.v_number = idx;
6667 break;
6668 }
6669 }
6670}
6671
6672static int inputsecret_flag = 0;
6673
6674/*
6675 * "input()" function
6676 * Also handles inputsecret() when inputsecret is set.
6677 */
6678 static void
6679f_input(typval_T *argvars, typval_T *rettv)
6680{
6681 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6682}
6683
6684/*
6685 * "inputdialog()" function
6686 */
6687 static void
6688f_inputdialog(typval_T *argvars, typval_T *rettv)
6689{
6690#if defined(FEAT_GUI_TEXTDIALOG)
6691 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6692 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6693 {
6694 char_u *message;
6695 char_u buf[NUMBUFLEN];
6696 char_u *defstr = (char_u *)"";
6697
6698 message = get_tv_string_chk(&argvars[0]);
6699 if (argvars[1].v_type != VAR_UNKNOWN
6700 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6701 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6702 else
6703 IObuff[0] = NUL;
6704 if (message != NULL && defstr != NULL
6705 && do_dialog(VIM_QUESTION, NULL, message,
6706 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6707 rettv->vval.v_string = vim_strsave(IObuff);
6708 else
6709 {
6710 if (message != NULL && defstr != NULL
6711 && argvars[1].v_type != VAR_UNKNOWN
6712 && argvars[2].v_type != VAR_UNKNOWN)
6713 rettv->vval.v_string = vim_strsave(
6714 get_tv_string_buf(&argvars[2], buf));
6715 else
6716 rettv->vval.v_string = NULL;
6717 }
6718 rettv->v_type = VAR_STRING;
6719 }
6720 else
6721#endif
6722 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6723}
6724
6725/*
6726 * "inputlist()" function
6727 */
6728 static void
6729f_inputlist(typval_T *argvars, typval_T *rettv)
6730{
6731 listitem_T *li;
6732 int selected;
6733 int mouse_used;
6734
6735#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006736 /* While starting up, there is no place to enter text. When running tests
6737 * with --not-a-term we assume feedkeys() will be used. */
6738 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 return;
6740#endif
6741 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6742 {
6743 EMSG2(_(e_listarg), "inputlist()");
6744 return;
6745 }
6746
6747 msg_start();
6748 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6749 lines_left = Rows; /* avoid more prompt */
6750 msg_scroll = TRUE;
6751 msg_clr_eos();
6752
6753 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6754 {
6755 msg_puts(get_tv_string(&li->li_tv));
6756 msg_putchar('\n');
6757 }
6758
6759 /* Ask for choice. */
6760 selected = prompt_for_number(&mouse_used);
6761 if (mouse_used)
6762 selected -= lines_left;
6763
6764 rettv->vval.v_number = selected;
6765}
6766
6767
6768static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6769
6770/*
6771 * "inputrestore()" function
6772 */
6773 static void
6774f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6775{
6776 if (ga_userinput.ga_len > 0)
6777 {
6778 --ga_userinput.ga_len;
6779 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6780 + ga_userinput.ga_len);
6781 /* default return is zero == OK */
6782 }
6783 else if (p_verbose > 1)
6784 {
6785 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6786 rettv->vval.v_number = 1; /* Failed */
6787 }
6788}
6789
6790/*
6791 * "inputsave()" function
6792 */
6793 static void
6794f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6795{
6796 /* Add an entry to the stack of typeahead storage. */
6797 if (ga_grow(&ga_userinput, 1) == OK)
6798 {
6799 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6800 + ga_userinput.ga_len);
6801 ++ga_userinput.ga_len;
6802 /* default return is zero == OK */
6803 }
6804 else
6805 rettv->vval.v_number = 1; /* Failed */
6806}
6807
6808/*
6809 * "inputsecret()" function
6810 */
6811 static void
6812f_inputsecret(typval_T *argvars, typval_T *rettv)
6813{
6814 ++cmdline_star;
6815 ++inputsecret_flag;
6816 f_input(argvars, rettv);
6817 --cmdline_star;
6818 --inputsecret_flag;
6819}
6820
6821/*
6822 * "insert()" function
6823 */
6824 static void
6825f_insert(typval_T *argvars, typval_T *rettv)
6826{
6827 long before = 0;
6828 listitem_T *item;
6829 list_T *l;
6830 int error = FALSE;
6831
6832 if (argvars[0].v_type != VAR_LIST)
6833 EMSG2(_(e_listarg), "insert()");
6834 else if ((l = argvars[0].vval.v_list) != NULL
6835 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6836 {
6837 if (argvars[2].v_type != VAR_UNKNOWN)
6838 before = (long)get_tv_number_chk(&argvars[2], &error);
6839 if (error)
6840 return; /* type error; errmsg already given */
6841
6842 if (before == l->lv_len)
6843 item = NULL;
6844 else
6845 {
6846 item = list_find(l, before);
6847 if (item == NULL)
6848 {
6849 EMSGN(_(e_listidx), before);
6850 l = NULL;
6851 }
6852 }
6853 if (l != NULL)
6854 {
6855 list_insert_tv(l, &argvars[1], item);
6856 copy_tv(&argvars[0], rettv);
6857 }
6858 }
6859}
6860
6861/*
6862 * "invert(expr)" function
6863 */
6864 static void
6865f_invert(typval_T *argvars, typval_T *rettv)
6866{
6867 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6868}
6869
6870/*
6871 * "isdirectory()" function
6872 */
6873 static void
6874f_isdirectory(typval_T *argvars, typval_T *rettv)
6875{
6876 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6877}
6878
6879/*
6880 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6881 * or it refers to a List or Dictionary that is locked.
6882 */
6883 static int
6884tv_islocked(typval_T *tv)
6885{
6886 return (tv->v_lock & VAR_LOCKED)
6887 || (tv->v_type == VAR_LIST
6888 && tv->vval.v_list != NULL
6889 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6890 || (tv->v_type == VAR_DICT
6891 && tv->vval.v_dict != NULL
6892 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6893}
6894
6895/*
6896 * "islocked()" function
6897 */
6898 static void
6899f_islocked(typval_T *argvars, typval_T *rettv)
6900{
6901 lval_T lv;
6902 char_u *end;
6903 dictitem_T *di;
6904
6905 rettv->vval.v_number = -1;
6906 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006907 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 if (end != NULL && lv.ll_name != NULL)
6909 {
6910 if (*end != NUL)
6911 EMSG(_(e_trailing));
6912 else
6913 {
6914 if (lv.ll_tv == NULL)
6915 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006916 di = find_var(lv.ll_name, NULL, TRUE);
6917 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006918 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006919 /* Consider a variable locked when:
6920 * 1. the variable itself is locked
6921 * 2. the value of the variable is locked.
6922 * 3. the List or Dict value is locked.
6923 */
6924 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6925 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 }
6927 }
6928 else if (lv.ll_range)
6929 EMSG(_("E786: Range not allowed"));
6930 else if (lv.ll_newkey != NULL)
6931 EMSG2(_(e_dictkey), lv.ll_newkey);
6932 else if (lv.ll_list != NULL)
6933 /* List item. */
6934 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6935 else
6936 /* Dictionary item. */
6937 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6938 }
6939 }
6940
6941 clear_lval(&lv);
6942}
6943
6944#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6945/*
6946 * "isnan()" function
6947 */
6948 static void
6949f_isnan(typval_T *argvars, typval_T *rettv)
6950{
6951 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6952 && isnan(argvars[0].vval.v_float);
6953}
6954#endif
6955
6956/*
6957 * "items(dict)" function
6958 */
6959 static void
6960f_items(typval_T *argvars, typval_T *rettv)
6961{
6962 dict_list(argvars, rettv, 2);
6963}
6964
6965#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6966/*
6967 * Get the job from the argument.
6968 * Returns NULL if the job is invalid.
6969 */
6970 static job_T *
6971get_job_arg(typval_T *tv)
6972{
6973 job_T *job;
6974
6975 if (tv->v_type != VAR_JOB)
6976 {
6977 EMSG2(_(e_invarg2), get_tv_string(tv));
6978 return NULL;
6979 }
6980 job = tv->vval.v_job;
6981
6982 if (job == NULL)
6983 EMSG(_("E916: not a valid job"));
6984 return job;
6985}
6986
6987/*
6988 * "job_getchannel()" function
6989 */
6990 static void
6991f_job_getchannel(typval_T *argvars, typval_T *rettv)
6992{
6993 job_T *job = get_job_arg(&argvars[0]);
6994
6995 if (job != NULL)
6996 {
6997 rettv->v_type = VAR_CHANNEL;
6998 rettv->vval.v_channel = job->jv_channel;
6999 if (job->jv_channel != NULL)
7000 ++job->jv_channel->ch_refcount;
7001 }
7002}
7003
7004/*
7005 * "job_info()" function
7006 */
7007 static void
7008f_job_info(typval_T *argvars, typval_T *rettv)
7009{
7010 job_T *job = get_job_arg(&argvars[0]);
7011
7012 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7013 job_info(job, rettv->vval.v_dict);
7014}
7015
7016/*
7017 * "job_setoptions()" function
7018 */
7019 static void
7020f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7021{
7022 job_T *job = get_job_arg(&argvars[0]);
7023 jobopt_T opt;
7024
7025 if (job == NULL)
7026 return;
7027 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007028 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029 job_set_options(job, &opt);
7030 free_job_options(&opt);
7031}
7032
7033/*
7034 * "job_start()" function
7035 */
7036 static void
7037f_job_start(typval_T *argvars, typval_T *rettv)
7038{
7039 rettv->v_type = VAR_JOB;
7040 if (check_restricted() || check_secure())
7041 return;
Bram Moolenaar13568252018-03-16 20:46:58 +01007042 rettv->vval.v_job = job_start(argvars, NULL, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007043}
7044
7045/*
7046 * "job_status()" function
7047 */
7048 static void
7049f_job_status(typval_T *argvars, typval_T *rettv)
7050{
7051 job_T *job = get_job_arg(&argvars[0]);
7052
7053 if (job != NULL)
7054 {
7055 rettv->v_type = VAR_STRING;
7056 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7057 }
7058}
7059
7060/*
7061 * "job_stop()" function
7062 */
7063 static void
7064f_job_stop(typval_T *argvars, typval_T *rettv)
7065{
7066 job_T *job = get_job_arg(&argvars[0]);
7067
7068 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007069 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007070}
7071#endif
7072
7073/*
7074 * "join()" function
7075 */
7076 static void
7077f_join(typval_T *argvars, typval_T *rettv)
7078{
7079 garray_T ga;
7080 char_u *sep;
7081
7082 if (argvars[0].v_type != VAR_LIST)
7083 {
7084 EMSG(_(e_listreq));
7085 return;
7086 }
7087 if (argvars[0].vval.v_list == NULL)
7088 return;
7089 if (argvars[1].v_type == VAR_UNKNOWN)
7090 sep = (char_u *)" ";
7091 else
7092 sep = get_tv_string_chk(&argvars[1]);
7093
7094 rettv->v_type = VAR_STRING;
7095
7096 if (sep != NULL)
7097 {
7098 ga_init2(&ga, (int)sizeof(char), 80);
7099 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7100 ga_append(&ga, NUL);
7101 rettv->vval.v_string = (char_u *)ga.ga_data;
7102 }
7103 else
7104 rettv->vval.v_string = NULL;
7105}
7106
7107/*
7108 * "js_decode()" function
7109 */
7110 static void
7111f_js_decode(typval_T *argvars, typval_T *rettv)
7112{
7113 js_read_T reader;
7114
7115 reader.js_buf = get_tv_string(&argvars[0]);
7116 reader.js_fill = NULL;
7117 reader.js_used = 0;
7118 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7119 EMSG(_(e_invarg));
7120}
7121
7122/*
7123 * "js_encode()" function
7124 */
7125 static void
7126f_js_encode(typval_T *argvars, typval_T *rettv)
7127{
7128 rettv->v_type = VAR_STRING;
7129 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7130}
7131
7132/*
7133 * "json_decode()" function
7134 */
7135 static void
7136f_json_decode(typval_T *argvars, typval_T *rettv)
7137{
7138 js_read_T reader;
7139
7140 reader.js_buf = get_tv_string(&argvars[0]);
7141 reader.js_fill = NULL;
7142 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007143 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007144}
7145
7146/*
7147 * "json_encode()" function
7148 */
7149 static void
7150f_json_encode(typval_T *argvars, typval_T *rettv)
7151{
7152 rettv->v_type = VAR_STRING;
7153 rettv->vval.v_string = json_encode(&argvars[0], 0);
7154}
7155
7156/*
7157 * "keys()" function
7158 */
7159 static void
7160f_keys(typval_T *argvars, typval_T *rettv)
7161{
7162 dict_list(argvars, rettv, 0);
7163}
7164
7165/*
7166 * "last_buffer_nr()" function.
7167 */
7168 static void
7169f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7170{
7171 int n = 0;
7172 buf_T *buf;
7173
Bram Moolenaar29323592016-07-24 22:04:11 +02007174 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007175 if (n < buf->b_fnum)
7176 n = buf->b_fnum;
7177
7178 rettv->vval.v_number = n;
7179}
7180
7181/*
7182 * "len()" function
7183 */
7184 static void
7185f_len(typval_T *argvars, typval_T *rettv)
7186{
7187 switch (argvars[0].v_type)
7188 {
7189 case VAR_STRING:
7190 case VAR_NUMBER:
7191 rettv->vval.v_number = (varnumber_T)STRLEN(
7192 get_tv_string(&argvars[0]));
7193 break;
7194 case VAR_LIST:
7195 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7196 break;
7197 case VAR_DICT:
7198 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7199 break;
7200 case VAR_UNKNOWN:
7201 case VAR_SPECIAL:
7202 case VAR_FLOAT:
7203 case VAR_FUNC:
7204 case VAR_PARTIAL:
7205 case VAR_JOB:
7206 case VAR_CHANNEL:
7207 EMSG(_("E701: Invalid type for len()"));
7208 break;
7209 }
7210}
7211
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007212 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007213libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007214{
7215#ifdef FEAT_LIBCALL
7216 char_u *string_in;
7217 char_u **string_result;
7218 int nr_result;
7219#endif
7220
7221 rettv->v_type = type;
7222 if (type != VAR_NUMBER)
7223 rettv->vval.v_string = NULL;
7224
7225 if (check_restricted() || check_secure())
7226 return;
7227
7228#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007229 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7231 {
7232 string_in = NULL;
7233 if (argvars[2].v_type == VAR_STRING)
7234 string_in = argvars[2].vval.v_string;
7235 if (type == VAR_NUMBER)
7236 string_result = NULL;
7237 else
7238 string_result = &rettv->vval.v_string;
7239 if (mch_libcall(argvars[0].vval.v_string,
7240 argvars[1].vval.v_string,
7241 string_in,
7242 argvars[2].vval.v_number,
7243 string_result,
7244 &nr_result) == OK
7245 && type == VAR_NUMBER)
7246 rettv->vval.v_number = nr_result;
7247 }
7248#endif
7249}
7250
7251/*
7252 * "libcall()" function
7253 */
7254 static void
7255f_libcall(typval_T *argvars, typval_T *rettv)
7256{
7257 libcall_common(argvars, rettv, VAR_STRING);
7258}
7259
7260/*
7261 * "libcallnr()" function
7262 */
7263 static void
7264f_libcallnr(typval_T *argvars, typval_T *rettv)
7265{
7266 libcall_common(argvars, rettv, VAR_NUMBER);
7267}
7268
7269/*
7270 * "line(string)" function
7271 */
7272 static void
7273f_line(typval_T *argvars, typval_T *rettv)
7274{
7275 linenr_T lnum = 0;
7276 pos_T *fp;
7277 int fnum;
7278
7279 fp = var2fpos(&argvars[0], TRUE, &fnum);
7280 if (fp != NULL)
7281 lnum = fp->lnum;
7282 rettv->vval.v_number = lnum;
7283}
7284
7285/*
7286 * "line2byte(lnum)" function
7287 */
7288 static void
7289f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7290{
7291#ifndef FEAT_BYTEOFF
7292 rettv->vval.v_number = -1;
7293#else
7294 linenr_T lnum;
7295
7296 lnum = get_tv_lnum(argvars);
7297 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7298 rettv->vval.v_number = -1;
7299 else
7300 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7301 if (rettv->vval.v_number >= 0)
7302 ++rettv->vval.v_number;
7303#endif
7304}
7305
7306/*
7307 * "lispindent(lnum)" function
7308 */
7309 static void
7310f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7311{
7312#ifdef FEAT_LISP
7313 pos_T pos;
7314 linenr_T lnum;
7315
7316 pos = curwin->w_cursor;
7317 lnum = get_tv_lnum(argvars);
7318 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7319 {
7320 curwin->w_cursor.lnum = lnum;
7321 rettv->vval.v_number = get_lisp_indent();
7322 curwin->w_cursor = pos;
7323 }
7324 else
7325#endif
7326 rettv->vval.v_number = -1;
7327}
7328
7329/*
7330 * "localtime()" function
7331 */
7332 static void
7333f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7334{
7335 rettv->vval.v_number = (varnumber_T)time(NULL);
7336}
7337
7338static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7339
7340 static void
7341get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7342{
7343 char_u *keys;
7344 char_u *which;
7345 char_u buf[NUMBUFLEN];
7346 char_u *keys_buf = NULL;
7347 char_u *rhs;
7348 int mode;
7349 int abbr = FALSE;
7350 int get_dict = FALSE;
7351 mapblock_T *mp;
7352 int buffer_local;
7353
7354 /* return empty string for failure */
7355 rettv->v_type = VAR_STRING;
7356 rettv->vval.v_string = NULL;
7357
7358 keys = get_tv_string(&argvars[0]);
7359 if (*keys == NUL)
7360 return;
7361
7362 if (argvars[1].v_type != VAR_UNKNOWN)
7363 {
7364 which = get_tv_string_buf_chk(&argvars[1], buf);
7365 if (argvars[2].v_type != VAR_UNKNOWN)
7366 {
7367 abbr = (int)get_tv_number(&argvars[2]);
7368 if (argvars[3].v_type != VAR_UNKNOWN)
7369 get_dict = (int)get_tv_number(&argvars[3]);
7370 }
7371 }
7372 else
7373 which = (char_u *)"";
7374 if (which == NULL)
7375 return;
7376
7377 mode = get_map_mode(&which, 0);
7378
7379 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7380 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7381 vim_free(keys_buf);
7382
7383 if (!get_dict)
7384 {
7385 /* Return a string. */
7386 if (rhs != NULL)
7387 rettv->vval.v_string = str2special_save(rhs, FALSE);
7388
7389 }
7390 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7391 {
7392 /* Return a dictionary. */
7393 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7394 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7395 dict_T *dict = rettv->vval.v_dict;
7396
7397 dict_add_nr_str(dict, "lhs", 0L, lhs);
7398 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7399 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7400 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7401 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7402 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7403 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7404 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7405 dict_add_nr_str(dict, "mode", 0L, mapmode);
7406
7407 vim_free(lhs);
7408 vim_free(mapmode);
7409 }
7410}
7411
7412#ifdef FEAT_FLOAT
7413/*
7414 * "log()" function
7415 */
7416 static void
7417f_log(typval_T *argvars, typval_T *rettv)
7418{
7419 float_T f = 0.0;
7420
7421 rettv->v_type = VAR_FLOAT;
7422 if (get_float_arg(argvars, &f) == OK)
7423 rettv->vval.v_float = log(f);
7424 else
7425 rettv->vval.v_float = 0.0;
7426}
7427
7428/*
7429 * "log10()" function
7430 */
7431 static void
7432f_log10(typval_T *argvars, typval_T *rettv)
7433{
7434 float_T f = 0.0;
7435
7436 rettv->v_type = VAR_FLOAT;
7437 if (get_float_arg(argvars, &f) == OK)
7438 rettv->vval.v_float = log10(f);
7439 else
7440 rettv->vval.v_float = 0.0;
7441}
7442#endif
7443
7444#ifdef FEAT_LUA
7445/*
7446 * "luaeval()" function
7447 */
7448 static void
7449f_luaeval(typval_T *argvars, typval_T *rettv)
7450{
7451 char_u *str;
7452 char_u buf[NUMBUFLEN];
7453
7454 str = get_tv_string_buf(&argvars[0], buf);
7455 do_luaeval(str, argvars + 1, rettv);
7456}
7457#endif
7458
7459/*
7460 * "map()" function
7461 */
7462 static void
7463f_map(typval_T *argvars, typval_T *rettv)
7464{
7465 filter_map(argvars, rettv, TRUE);
7466}
7467
7468/*
7469 * "maparg()" function
7470 */
7471 static void
7472f_maparg(typval_T *argvars, typval_T *rettv)
7473{
7474 get_maparg(argvars, rettv, TRUE);
7475}
7476
7477/*
7478 * "mapcheck()" function
7479 */
7480 static void
7481f_mapcheck(typval_T *argvars, typval_T *rettv)
7482{
7483 get_maparg(argvars, rettv, FALSE);
7484}
7485
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007486typedef enum
7487{
7488 MATCH_END, /* matchend() */
7489 MATCH_MATCH, /* match() */
7490 MATCH_STR, /* matchstr() */
7491 MATCH_LIST, /* matchlist() */
7492 MATCH_POS /* matchstrpos() */
7493} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007494
7495 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007496find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007497{
7498 char_u *str = NULL;
7499 long len = 0;
7500 char_u *expr = NULL;
7501 char_u *pat;
7502 regmatch_T regmatch;
7503 char_u patbuf[NUMBUFLEN];
7504 char_u strbuf[NUMBUFLEN];
7505 char_u *save_cpo;
7506 long start = 0;
7507 long nth = 1;
7508 colnr_T startcol = 0;
7509 int match = 0;
7510 list_T *l = NULL;
7511 listitem_T *li = NULL;
7512 long idx = 0;
7513 char_u *tofree = NULL;
7514
7515 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7516 save_cpo = p_cpo;
7517 p_cpo = (char_u *)"";
7518
7519 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007520 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007522 /* type MATCH_LIST: return empty list when there are no matches.
7523 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524 if (rettv_list_alloc(rettv) == FAIL)
7525 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007526 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527 && (list_append_string(rettv->vval.v_list,
7528 (char_u *)"", 0) == FAIL
7529 || list_append_number(rettv->vval.v_list,
7530 (varnumber_T)-1) == FAIL
7531 || list_append_number(rettv->vval.v_list,
7532 (varnumber_T)-1) == FAIL
7533 || list_append_number(rettv->vval.v_list,
7534 (varnumber_T)-1) == FAIL))
7535 {
7536 list_free(rettv->vval.v_list);
7537 rettv->vval.v_list = NULL;
7538 goto theend;
7539 }
7540 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007541 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007542 {
7543 rettv->v_type = VAR_STRING;
7544 rettv->vval.v_string = NULL;
7545 }
7546
7547 if (argvars[0].v_type == VAR_LIST)
7548 {
7549 if ((l = argvars[0].vval.v_list) == NULL)
7550 goto theend;
7551 li = l->lv_first;
7552 }
7553 else
7554 {
7555 expr = str = get_tv_string(&argvars[0]);
7556 len = (long)STRLEN(str);
7557 }
7558
7559 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7560 if (pat == NULL)
7561 goto theend;
7562
7563 if (argvars[2].v_type != VAR_UNKNOWN)
7564 {
7565 int error = FALSE;
7566
7567 start = (long)get_tv_number_chk(&argvars[2], &error);
7568 if (error)
7569 goto theend;
7570 if (l != NULL)
7571 {
7572 li = list_find(l, start);
7573 if (li == NULL)
7574 goto theend;
7575 idx = l->lv_idx; /* use the cached index */
7576 }
7577 else
7578 {
7579 if (start < 0)
7580 start = 0;
7581 if (start > len)
7582 goto theend;
7583 /* When "count" argument is there ignore matches before "start",
7584 * otherwise skip part of the string. Differs when pattern is "^"
7585 * or "\<". */
7586 if (argvars[3].v_type != VAR_UNKNOWN)
7587 startcol = start;
7588 else
7589 {
7590 str += start;
7591 len -= start;
7592 }
7593 }
7594
7595 if (argvars[3].v_type != VAR_UNKNOWN)
7596 nth = (long)get_tv_number_chk(&argvars[3], &error);
7597 if (error)
7598 goto theend;
7599 }
7600
7601 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7602 if (regmatch.regprog != NULL)
7603 {
7604 regmatch.rm_ic = p_ic;
7605
7606 for (;;)
7607 {
7608 if (l != NULL)
7609 {
7610 if (li == NULL)
7611 {
7612 match = FALSE;
7613 break;
7614 }
7615 vim_free(tofree);
7616 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7617 if (str == NULL)
7618 break;
7619 }
7620
7621 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7622
7623 if (match && --nth <= 0)
7624 break;
7625 if (l == NULL && !match)
7626 break;
7627
7628 /* Advance to just after the match. */
7629 if (l != NULL)
7630 {
7631 li = li->li_next;
7632 ++idx;
7633 }
7634 else
7635 {
7636#ifdef FEAT_MBYTE
7637 startcol = (colnr_T)(regmatch.startp[0]
7638 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7639#else
7640 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7641#endif
7642 if (startcol > (colnr_T)len
7643 || str + startcol <= regmatch.startp[0])
7644 {
7645 match = FALSE;
7646 break;
7647 }
7648 }
7649 }
7650
7651 if (match)
7652 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007653 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007654 {
7655 listitem_T *li1 = rettv->vval.v_list->lv_first;
7656 listitem_T *li2 = li1->li_next;
7657 listitem_T *li3 = li2->li_next;
7658 listitem_T *li4 = li3->li_next;
7659
7660 vim_free(li1->li_tv.vval.v_string);
7661 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7662 (int)(regmatch.endp[0] - regmatch.startp[0]));
7663 li3->li_tv.vval.v_number =
7664 (varnumber_T)(regmatch.startp[0] - expr);
7665 li4->li_tv.vval.v_number =
7666 (varnumber_T)(regmatch.endp[0] - expr);
7667 if (l != NULL)
7668 li2->li_tv.vval.v_number = (varnumber_T)idx;
7669 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007670 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007671 {
7672 int i;
7673
7674 /* return list with matched string and submatches */
7675 for (i = 0; i < NSUBEXP; ++i)
7676 {
7677 if (regmatch.endp[i] == NULL)
7678 {
7679 if (list_append_string(rettv->vval.v_list,
7680 (char_u *)"", 0) == FAIL)
7681 break;
7682 }
7683 else if (list_append_string(rettv->vval.v_list,
7684 regmatch.startp[i],
7685 (int)(regmatch.endp[i] - regmatch.startp[i]))
7686 == FAIL)
7687 break;
7688 }
7689 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007690 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007691 {
7692 /* return matched string */
7693 if (l != NULL)
7694 copy_tv(&li->li_tv, rettv);
7695 else
7696 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7697 (int)(regmatch.endp[0] - regmatch.startp[0]));
7698 }
7699 else if (l != NULL)
7700 rettv->vval.v_number = idx;
7701 else
7702 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007703 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007704 rettv->vval.v_number =
7705 (varnumber_T)(regmatch.startp[0] - str);
7706 else
7707 rettv->vval.v_number =
7708 (varnumber_T)(regmatch.endp[0] - str);
7709 rettv->vval.v_number += (varnumber_T)(str - expr);
7710 }
7711 }
7712 vim_regfree(regmatch.regprog);
7713 }
7714
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007715theend:
7716 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717 /* matchstrpos() without a list: drop the second item. */
7718 listitem_remove(rettv->vval.v_list,
7719 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007720 vim_free(tofree);
7721 p_cpo = save_cpo;
7722}
7723
7724/*
7725 * "match()" function
7726 */
7727 static void
7728f_match(typval_T *argvars, typval_T *rettv)
7729{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007730 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007731}
7732
7733/*
7734 * "matchadd()" function
7735 */
7736 static void
7737f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7738{
7739#ifdef FEAT_SEARCH_EXTRA
7740 char_u buf[NUMBUFLEN];
7741 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7742 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7743 int prio = 10; /* default priority */
7744 int id = -1;
7745 int error = FALSE;
7746 char_u *conceal_char = NULL;
7747
7748 rettv->vval.v_number = -1;
7749
7750 if (grp == NULL || pat == NULL)
7751 return;
7752 if (argvars[2].v_type != VAR_UNKNOWN)
7753 {
7754 prio = (int)get_tv_number_chk(&argvars[2], &error);
7755 if (argvars[3].v_type != VAR_UNKNOWN)
7756 {
7757 id = (int)get_tv_number_chk(&argvars[3], &error);
7758 if (argvars[4].v_type != VAR_UNKNOWN)
7759 {
7760 if (argvars[4].v_type != VAR_DICT)
7761 {
7762 EMSG(_(e_dictreq));
7763 return;
7764 }
7765 if (dict_find(argvars[4].vval.v_dict,
7766 (char_u *)"conceal", -1) != NULL)
7767 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7768 (char_u *)"conceal", FALSE);
7769 }
7770 }
7771 }
7772 if (error == TRUE)
7773 return;
7774 if (id >= 1 && id <= 3)
7775 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007776 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777 return;
7778 }
7779
7780 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7781 conceal_char);
7782#endif
7783}
7784
7785/*
7786 * "matchaddpos()" function
7787 */
7788 static void
7789f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7790{
7791#ifdef FEAT_SEARCH_EXTRA
7792 char_u buf[NUMBUFLEN];
7793 char_u *group;
7794 int prio = 10;
7795 int id = -1;
7796 int error = FALSE;
7797 list_T *l;
7798 char_u *conceal_char = NULL;
7799
7800 rettv->vval.v_number = -1;
7801
7802 group = get_tv_string_buf_chk(&argvars[0], buf);
7803 if (group == NULL)
7804 return;
7805
7806 if (argvars[1].v_type != VAR_LIST)
7807 {
7808 EMSG2(_(e_listarg), "matchaddpos()");
7809 return;
7810 }
7811 l = argvars[1].vval.v_list;
7812 if (l == NULL)
7813 return;
7814
7815 if (argvars[2].v_type != VAR_UNKNOWN)
7816 {
7817 prio = (int)get_tv_number_chk(&argvars[2], &error);
7818 if (argvars[3].v_type != VAR_UNKNOWN)
7819 {
7820 id = (int)get_tv_number_chk(&argvars[3], &error);
7821 if (argvars[4].v_type != VAR_UNKNOWN)
7822 {
7823 if (argvars[4].v_type != VAR_DICT)
7824 {
7825 EMSG(_(e_dictreq));
7826 return;
7827 }
7828 if (dict_find(argvars[4].vval.v_dict,
7829 (char_u *)"conceal", -1) != NULL)
7830 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7831 (char_u *)"conceal", FALSE);
7832 }
7833 }
7834 }
7835 if (error == TRUE)
7836 return;
7837
7838 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7839 if (id == 1 || id == 2)
7840 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007841 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007842 return;
7843 }
7844
7845 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7846 conceal_char);
7847#endif
7848}
7849
7850/*
7851 * "matcharg()" function
7852 */
7853 static void
7854f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7855{
7856 if (rettv_list_alloc(rettv) == OK)
7857 {
7858#ifdef FEAT_SEARCH_EXTRA
7859 int id = (int)get_tv_number(&argvars[0]);
7860 matchitem_T *m;
7861
7862 if (id >= 1 && id <= 3)
7863 {
7864 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7865 {
7866 list_append_string(rettv->vval.v_list,
7867 syn_id2name(m->hlg_id), -1);
7868 list_append_string(rettv->vval.v_list, m->pattern, -1);
7869 }
7870 else
7871 {
7872 list_append_string(rettv->vval.v_list, NULL, -1);
7873 list_append_string(rettv->vval.v_list, NULL, -1);
7874 }
7875 }
7876#endif
7877 }
7878}
7879
7880/*
7881 * "matchdelete()" function
7882 */
7883 static void
7884f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7885{
7886#ifdef FEAT_SEARCH_EXTRA
7887 rettv->vval.v_number = match_delete(curwin,
7888 (int)get_tv_number(&argvars[0]), TRUE);
7889#endif
7890}
7891
7892/*
7893 * "matchend()" function
7894 */
7895 static void
7896f_matchend(typval_T *argvars, typval_T *rettv)
7897{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007898 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007899}
7900
7901/*
7902 * "matchlist()" function
7903 */
7904 static void
7905f_matchlist(typval_T *argvars, typval_T *rettv)
7906{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007907 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908}
7909
7910/*
7911 * "matchstr()" function
7912 */
7913 static void
7914f_matchstr(typval_T *argvars, typval_T *rettv)
7915{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007916 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007917}
7918
7919/*
7920 * "matchstrpos()" function
7921 */
7922 static void
7923f_matchstrpos(typval_T *argvars, typval_T *rettv)
7924{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007925 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007926}
7927
7928static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7929
7930 static void
7931max_min(typval_T *argvars, typval_T *rettv, int domax)
7932{
7933 varnumber_T n = 0;
7934 varnumber_T i;
7935 int error = FALSE;
7936
7937 if (argvars[0].v_type == VAR_LIST)
7938 {
7939 list_T *l;
7940 listitem_T *li;
7941
7942 l = argvars[0].vval.v_list;
7943 if (l != NULL)
7944 {
7945 li = l->lv_first;
7946 if (li != NULL)
7947 {
7948 n = get_tv_number_chk(&li->li_tv, &error);
7949 for (;;)
7950 {
7951 li = li->li_next;
7952 if (li == NULL)
7953 break;
7954 i = get_tv_number_chk(&li->li_tv, &error);
7955 if (domax ? i > n : i < n)
7956 n = i;
7957 }
7958 }
7959 }
7960 }
7961 else if (argvars[0].v_type == VAR_DICT)
7962 {
7963 dict_T *d;
7964 int first = TRUE;
7965 hashitem_T *hi;
7966 int todo;
7967
7968 d = argvars[0].vval.v_dict;
7969 if (d != NULL)
7970 {
7971 todo = (int)d->dv_hashtab.ht_used;
7972 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7973 {
7974 if (!HASHITEM_EMPTY(hi))
7975 {
7976 --todo;
7977 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7978 if (first)
7979 {
7980 n = i;
7981 first = FALSE;
7982 }
7983 else if (domax ? i > n : i < n)
7984 n = i;
7985 }
7986 }
7987 }
7988 }
7989 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007990 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991 rettv->vval.v_number = error ? 0 : n;
7992}
7993
7994/*
7995 * "max()" function
7996 */
7997 static void
7998f_max(typval_T *argvars, typval_T *rettv)
7999{
8000 max_min(argvars, rettv, TRUE);
8001}
8002
8003/*
8004 * "min()" function
8005 */
8006 static void
8007f_min(typval_T *argvars, typval_T *rettv)
8008{
8009 max_min(argvars, rettv, FALSE);
8010}
8011
8012static int mkdir_recurse(char_u *dir, int prot);
8013
8014/*
8015 * Create the directory in which "dir" is located, and higher levels when
8016 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008017 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008018 */
8019 static int
8020mkdir_recurse(char_u *dir, int prot)
8021{
8022 char_u *p;
8023 char_u *updir;
8024 int r = FAIL;
8025
8026 /* Get end of directory name in "dir".
8027 * We're done when it's "/" or "c:/". */
8028 p = gettail_sep(dir);
8029 if (p <= get_past_head(dir))
8030 return OK;
8031
8032 /* If the directory exists we're done. Otherwise: create it.*/
8033 updir = vim_strnsave(dir, (int)(p - dir));
8034 if (updir == NULL)
8035 return FAIL;
8036 if (mch_isdir(updir))
8037 r = OK;
8038 else if (mkdir_recurse(updir, prot) == OK)
8039 r = vim_mkdir_emsg(updir, prot);
8040 vim_free(updir);
8041 return r;
8042}
8043
8044#ifdef vim_mkdir
8045/*
8046 * "mkdir()" function
8047 */
8048 static void
8049f_mkdir(typval_T *argvars, typval_T *rettv)
8050{
8051 char_u *dir;
8052 char_u buf[NUMBUFLEN];
8053 int prot = 0755;
8054
8055 rettv->vval.v_number = FAIL;
8056 if (check_restricted() || check_secure())
8057 return;
8058
8059 dir = get_tv_string_buf(&argvars[0], buf);
8060 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008061 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008062
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008063 if (*gettail(dir) == NUL)
8064 /* remove trailing slashes */
8065 *gettail_sep(dir) = NUL;
8066
8067 if (argvars[1].v_type != VAR_UNKNOWN)
8068 {
8069 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008071 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8072 if (prot == -1)
8073 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008074 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008075 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8076 {
8077 if (mch_isdir(dir))
8078 {
8079 /* With the "p" flag it's OK if the dir already exists. */
8080 rettv->vval.v_number = OK;
8081 return;
8082 }
8083 mkdir_recurse(dir, prot);
8084 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008085 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008086 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087}
8088#endif
8089
8090/*
8091 * "mode()" function
8092 */
8093 static void
8094f_mode(typval_T *argvars, typval_T *rettv)
8095{
8096 char_u buf[3];
8097
8098 buf[1] = NUL;
8099 buf[2] = NUL;
8100
8101 if (time_for_testing == 93784)
8102 {
8103 /* Testing the two-character code. */
8104 buf[0] = 'x';
8105 buf[1] = '!';
8106 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008107#ifdef FEAT_TERMINAL
8108 else if (term_use_loop())
8109 buf[0] = 't';
8110#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111 else if (VIsual_active)
8112 {
8113 if (VIsual_select)
8114 buf[0] = VIsual_mode + 's' - 'v';
8115 else
8116 buf[0] = VIsual_mode;
8117 }
8118 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8119 || State == CONFIRM)
8120 {
8121 buf[0] = 'r';
8122 if (State == ASKMORE)
8123 buf[1] = 'm';
8124 else if (State == CONFIRM)
8125 buf[1] = '?';
8126 }
8127 else if (State == EXTERNCMD)
8128 buf[0] = '!';
8129 else if (State & INSERT)
8130 {
8131#ifdef FEAT_VREPLACE
8132 if (State & VREPLACE_FLAG)
8133 {
8134 buf[0] = 'R';
8135 buf[1] = 'v';
8136 }
8137 else
8138#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01008139 {
8140 if (State & REPLACE_FLAG)
8141 buf[0] = 'R';
8142 else
8143 buf[0] = 'i';
8144#ifdef FEAT_INS_EXPAND
8145 if (ins_compl_active())
8146 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008147 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008148 buf[1] = 'x';
8149#endif
8150 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008151 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008152 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153 {
8154 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008155 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008156 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008157 else if (exmode_active == EXMODE_NORMAL)
8158 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 }
8160 else
8161 {
8162 buf[0] = 'n';
8163 if (finish_op)
8164 buf[1] = 'o';
8165 }
8166
8167 /* Clear out the minor mode when the argument is not a non-zero number or
8168 * non-empty string. */
8169 if (!non_zero_arg(&argvars[0]))
8170 buf[1] = NUL;
8171
8172 rettv->vval.v_string = vim_strsave(buf);
8173 rettv->v_type = VAR_STRING;
8174}
8175
8176#if defined(FEAT_MZSCHEME) || defined(PROTO)
8177/*
8178 * "mzeval()" function
8179 */
8180 static void
8181f_mzeval(typval_T *argvars, typval_T *rettv)
8182{
8183 char_u *str;
8184 char_u buf[NUMBUFLEN];
8185
8186 str = get_tv_string_buf(&argvars[0], buf);
8187 do_mzeval(str, rettv);
8188}
8189
8190 void
8191mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8192{
8193 typval_T argvars[3];
8194
8195 argvars[0].v_type = VAR_STRING;
8196 argvars[0].vval.v_string = name;
8197 copy_tv(args, &argvars[1]);
8198 argvars[2].v_type = VAR_UNKNOWN;
8199 f_call(argvars, rettv);
8200 clear_tv(&argvars[1]);
8201}
8202#endif
8203
8204/*
8205 * "nextnonblank()" function
8206 */
8207 static void
8208f_nextnonblank(typval_T *argvars, typval_T *rettv)
8209{
8210 linenr_T lnum;
8211
8212 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8213 {
8214 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8215 {
8216 lnum = 0;
8217 break;
8218 }
8219 if (*skipwhite(ml_get(lnum)) != NUL)
8220 break;
8221 }
8222 rettv->vval.v_number = lnum;
8223}
8224
8225/*
8226 * "nr2char()" function
8227 */
8228 static void
8229f_nr2char(typval_T *argvars, typval_T *rettv)
8230{
8231 char_u buf[NUMBUFLEN];
8232
8233#ifdef FEAT_MBYTE
8234 if (has_mbyte)
8235 {
8236 int utf8 = 0;
8237
8238 if (argvars[1].v_type != VAR_UNKNOWN)
8239 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8240 if (utf8)
8241 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8242 else
8243 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8244 }
8245 else
8246#endif
8247 {
8248 buf[0] = (char_u)get_tv_number(&argvars[0]);
8249 buf[1] = NUL;
8250 }
8251 rettv->v_type = VAR_STRING;
8252 rettv->vval.v_string = vim_strsave(buf);
8253}
8254
8255/*
8256 * "or(expr, expr)" function
8257 */
8258 static void
8259f_or(typval_T *argvars, typval_T *rettv)
8260{
8261 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8262 | get_tv_number_chk(&argvars[1], NULL);
8263}
8264
8265/*
8266 * "pathshorten()" function
8267 */
8268 static void
8269f_pathshorten(typval_T *argvars, typval_T *rettv)
8270{
8271 char_u *p;
8272
8273 rettv->v_type = VAR_STRING;
8274 p = get_tv_string_chk(&argvars[0]);
8275 if (p == NULL)
8276 rettv->vval.v_string = NULL;
8277 else
8278 {
8279 p = vim_strsave(p);
8280 rettv->vval.v_string = p;
8281 if (p != NULL)
8282 shorten_dir(p);
8283 }
8284}
8285
8286#ifdef FEAT_PERL
8287/*
8288 * "perleval()" function
8289 */
8290 static void
8291f_perleval(typval_T *argvars, typval_T *rettv)
8292{
8293 char_u *str;
8294 char_u buf[NUMBUFLEN];
8295
8296 str = get_tv_string_buf(&argvars[0], buf);
8297 do_perleval(str, rettv);
8298}
8299#endif
8300
8301#ifdef FEAT_FLOAT
8302/*
8303 * "pow()" function
8304 */
8305 static void
8306f_pow(typval_T *argvars, typval_T *rettv)
8307{
8308 float_T fx = 0.0, fy = 0.0;
8309
8310 rettv->v_type = VAR_FLOAT;
8311 if (get_float_arg(argvars, &fx) == OK
8312 && get_float_arg(&argvars[1], &fy) == OK)
8313 rettv->vval.v_float = pow(fx, fy);
8314 else
8315 rettv->vval.v_float = 0.0;
8316}
8317#endif
8318
8319/*
8320 * "prevnonblank()" function
8321 */
8322 static void
8323f_prevnonblank(typval_T *argvars, typval_T *rettv)
8324{
8325 linenr_T lnum;
8326
8327 lnum = get_tv_lnum(argvars);
8328 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8329 lnum = 0;
8330 else
8331 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8332 --lnum;
8333 rettv->vval.v_number = lnum;
8334}
8335
8336/* This dummy va_list is here because:
8337 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8338 * - locally in the function results in a "used before set" warning
8339 * - using va_start() to initialize it gives "function with fixed args" error */
8340static va_list ap;
8341
8342/*
8343 * "printf()" function
8344 */
8345 static void
8346f_printf(typval_T *argvars, typval_T *rettv)
8347{
8348 char_u buf[NUMBUFLEN];
8349 int len;
8350 char_u *s;
8351 int saved_did_emsg = did_emsg;
8352 char *fmt;
8353
8354 rettv->v_type = VAR_STRING;
8355 rettv->vval.v_string = NULL;
8356
8357 /* Get the required length, allocate the buffer and do it for real. */
8358 did_emsg = FALSE;
8359 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008360 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008361 if (!did_emsg)
8362 {
8363 s = alloc(len + 1);
8364 if (s != NULL)
8365 {
8366 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008367 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8368 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 }
8370 }
8371 did_emsg |= saved_did_emsg;
8372}
8373
8374/*
8375 * "pumvisible()" function
8376 */
8377 static void
8378f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8379{
8380#ifdef FEAT_INS_EXPAND
8381 if (pum_visible())
8382 rettv->vval.v_number = 1;
8383#endif
8384}
8385
8386#ifdef FEAT_PYTHON3
8387/*
8388 * "py3eval()" function
8389 */
8390 static void
8391f_py3eval(typval_T *argvars, typval_T *rettv)
8392{
8393 char_u *str;
8394 char_u buf[NUMBUFLEN];
8395
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008396 if (p_pyx == 0)
8397 p_pyx = 3;
8398
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008399 str = get_tv_string_buf(&argvars[0], buf);
8400 do_py3eval(str, rettv);
8401}
8402#endif
8403
8404#ifdef FEAT_PYTHON
8405/*
8406 * "pyeval()" function
8407 */
8408 static void
8409f_pyeval(typval_T *argvars, typval_T *rettv)
8410{
8411 char_u *str;
8412 char_u buf[NUMBUFLEN];
8413
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008414 if (p_pyx == 0)
8415 p_pyx = 2;
8416
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008417 str = get_tv_string_buf(&argvars[0], buf);
8418 do_pyeval(str, rettv);
8419}
8420#endif
8421
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008422#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8423/*
8424 * "pyxeval()" function
8425 */
8426 static void
8427f_pyxeval(typval_T *argvars, typval_T *rettv)
8428{
8429# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8430 init_pyxversion();
8431 if (p_pyx == 2)
8432 f_pyeval(argvars, rettv);
8433 else
8434 f_py3eval(argvars, rettv);
8435# elif defined(FEAT_PYTHON)
8436 f_pyeval(argvars, rettv);
8437# elif defined(FEAT_PYTHON3)
8438 f_py3eval(argvars, rettv);
8439# endif
8440}
8441#endif
8442
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008443/*
8444 * "range()" function
8445 */
8446 static void
8447f_range(typval_T *argvars, typval_T *rettv)
8448{
8449 varnumber_T start;
8450 varnumber_T end;
8451 varnumber_T stride = 1;
8452 varnumber_T i;
8453 int error = FALSE;
8454
8455 start = get_tv_number_chk(&argvars[0], &error);
8456 if (argvars[1].v_type == VAR_UNKNOWN)
8457 {
8458 end = start - 1;
8459 start = 0;
8460 }
8461 else
8462 {
8463 end = get_tv_number_chk(&argvars[1], &error);
8464 if (argvars[2].v_type != VAR_UNKNOWN)
8465 stride = get_tv_number_chk(&argvars[2], &error);
8466 }
8467
8468 if (error)
8469 return; /* type error; errmsg already given */
8470 if (stride == 0)
8471 EMSG(_("E726: Stride is zero"));
8472 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8473 EMSG(_("E727: Start past end"));
8474 else
8475 {
8476 if (rettv_list_alloc(rettv) == OK)
8477 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8478 if (list_append_number(rettv->vval.v_list,
8479 (varnumber_T)i) == FAIL)
8480 break;
8481 }
8482}
8483
8484/*
8485 * "readfile()" function
8486 */
8487 static void
8488f_readfile(typval_T *argvars, typval_T *rettv)
8489{
8490 int binary = FALSE;
8491 int failed = FALSE;
8492 char_u *fname;
8493 FILE *fd;
8494 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8495 int io_size = sizeof(buf);
8496 int readlen; /* size of last fread() */
8497 char_u *prev = NULL; /* previously read bytes, if any */
8498 long prevlen = 0; /* length of data in prev */
8499 long prevsize = 0; /* size of prev buffer */
8500 long maxline = MAXLNUM;
8501 long cnt = 0;
8502 char_u *p; /* position in buf */
8503 char_u *start; /* start of current line */
8504
8505 if (argvars[1].v_type != VAR_UNKNOWN)
8506 {
8507 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8508 binary = TRUE;
8509 if (argvars[2].v_type != VAR_UNKNOWN)
8510 maxline = (long)get_tv_number(&argvars[2]);
8511 }
8512
8513 if (rettv_list_alloc(rettv) == FAIL)
8514 return;
8515
8516 /* Always open the file in binary mode, library functions have a mind of
8517 * their own about CR-LF conversion. */
8518 fname = get_tv_string(&argvars[0]);
8519 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8520 {
8521 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8522 return;
8523 }
8524
8525 while (cnt < maxline || maxline < 0)
8526 {
8527 readlen = (int)fread(buf, 1, io_size, fd);
8528
8529 /* This for loop processes what was read, but is also entered at end
8530 * of file so that either:
8531 * - an incomplete line gets written
8532 * - a "binary" file gets an empty line at the end if it ends in a
8533 * newline. */
8534 for (p = buf, start = buf;
8535 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8536 ++p)
8537 {
8538 if (*p == '\n' || readlen <= 0)
8539 {
8540 listitem_T *li;
8541 char_u *s = NULL;
8542 long_u len = p - start;
8543
8544 /* Finished a line. Remove CRs before NL. */
8545 if (readlen > 0 && !binary)
8546 {
8547 while (len > 0 && start[len - 1] == '\r')
8548 --len;
8549 /* removal may cross back to the "prev" string */
8550 if (len == 0)
8551 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8552 --prevlen;
8553 }
8554 if (prevlen == 0)
8555 s = vim_strnsave(start, (int)len);
8556 else
8557 {
8558 /* Change "prev" buffer to be the right size. This way
8559 * the bytes are only copied once, and very long lines are
8560 * allocated only once. */
8561 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8562 {
8563 mch_memmove(s + prevlen, start, len);
8564 s[prevlen + len] = NUL;
8565 prev = NULL; /* the list will own the string */
8566 prevlen = prevsize = 0;
8567 }
8568 }
8569 if (s == NULL)
8570 {
8571 do_outofmem_msg((long_u) prevlen + len + 1);
8572 failed = TRUE;
8573 break;
8574 }
8575
8576 if ((li = listitem_alloc()) == NULL)
8577 {
8578 vim_free(s);
8579 failed = TRUE;
8580 break;
8581 }
8582 li->li_tv.v_type = VAR_STRING;
8583 li->li_tv.v_lock = 0;
8584 li->li_tv.vval.v_string = s;
8585 list_append(rettv->vval.v_list, li);
8586
8587 start = p + 1; /* step over newline */
8588 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8589 break;
8590 }
8591 else if (*p == NUL)
8592 *p = '\n';
8593#ifdef FEAT_MBYTE
8594 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8595 * when finding the BF and check the previous two bytes. */
8596 else if (*p == 0xbf && enc_utf8 && !binary)
8597 {
8598 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8599 * + 1, these may be in the "prev" string. */
8600 char_u back1 = p >= buf + 1 ? p[-1]
8601 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8602 char_u back2 = p >= buf + 2 ? p[-2]
8603 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8604 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8605
8606 if (back2 == 0xef && back1 == 0xbb)
8607 {
8608 char_u *dest = p - 2;
8609
8610 /* Usually a BOM is at the beginning of a file, and so at
8611 * the beginning of a line; then we can just step over it.
8612 */
8613 if (start == dest)
8614 start = p + 1;
8615 else
8616 {
8617 /* have to shuffle buf to close gap */
8618 int adjust_prevlen = 0;
8619
8620 if (dest < buf)
8621 {
8622 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8623 dest = buf;
8624 }
8625 if (readlen > p - buf + 1)
8626 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8627 readlen -= 3 - adjust_prevlen;
8628 prevlen -= adjust_prevlen;
8629 p = dest - 1;
8630 }
8631 }
8632 }
8633#endif
8634 } /* for */
8635
8636 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8637 break;
8638 if (start < p)
8639 {
8640 /* There's part of a line in buf, store it in "prev". */
8641 if (p - start + prevlen >= prevsize)
8642 {
8643 /* need bigger "prev" buffer */
8644 char_u *newprev;
8645
8646 /* A common use case is ordinary text files and "prev" gets a
8647 * fragment of a line, so the first allocation is made
8648 * small, to avoid repeatedly 'allocing' large and
8649 * 'reallocing' small. */
8650 if (prevsize == 0)
8651 prevsize = (long)(p - start);
8652 else
8653 {
8654 long grow50pc = (prevsize * 3) / 2;
8655 long growmin = (long)((p - start) * 2 + prevlen);
8656 prevsize = grow50pc > growmin ? grow50pc : growmin;
8657 }
8658 newprev = prev == NULL ? alloc(prevsize)
8659 : vim_realloc(prev, prevsize);
8660 if (newprev == NULL)
8661 {
8662 do_outofmem_msg((long_u)prevsize);
8663 failed = TRUE;
8664 break;
8665 }
8666 prev = newprev;
8667 }
8668 /* Add the line part to end of "prev". */
8669 mch_memmove(prev + prevlen, start, p - start);
8670 prevlen += (long)(p - start);
8671 }
8672 } /* while */
8673
8674 /*
8675 * For a negative line count use only the lines at the end of the file,
8676 * free the rest.
8677 */
8678 if (!failed && maxline < 0)
8679 while (cnt > -maxline)
8680 {
8681 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8682 --cnt;
8683 }
8684
8685 if (failed)
8686 {
8687 list_free(rettv->vval.v_list);
8688 /* readfile doc says an empty list is returned on error */
8689 rettv->vval.v_list = list_alloc();
8690 }
8691
8692 vim_free(prev);
8693 fclose(fd);
8694}
8695
8696#if defined(FEAT_RELTIME)
8697static int list2proftime(typval_T *arg, proftime_T *tm);
8698
8699/*
8700 * Convert a List to proftime_T.
8701 * Return FAIL when there is something wrong.
8702 */
8703 static int
8704list2proftime(typval_T *arg, proftime_T *tm)
8705{
8706 long n1, n2;
8707 int error = FALSE;
8708
8709 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8710 || arg->vval.v_list->lv_len != 2)
8711 return FAIL;
8712 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8713 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8714# ifdef WIN3264
8715 tm->HighPart = n1;
8716 tm->LowPart = n2;
8717# else
8718 tm->tv_sec = n1;
8719 tm->tv_usec = n2;
8720# endif
8721 return error ? FAIL : OK;
8722}
8723#endif /* FEAT_RELTIME */
8724
8725/*
8726 * "reltime()" function
8727 */
8728 static void
8729f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8730{
8731#ifdef FEAT_RELTIME
8732 proftime_T res;
8733 proftime_T start;
8734
8735 if (argvars[0].v_type == VAR_UNKNOWN)
8736 {
8737 /* No arguments: get current time. */
8738 profile_start(&res);
8739 }
8740 else if (argvars[1].v_type == VAR_UNKNOWN)
8741 {
8742 if (list2proftime(&argvars[0], &res) == FAIL)
8743 return;
8744 profile_end(&res);
8745 }
8746 else
8747 {
8748 /* Two arguments: compute the difference. */
8749 if (list2proftime(&argvars[0], &start) == FAIL
8750 || list2proftime(&argvars[1], &res) == FAIL)
8751 return;
8752 profile_sub(&res, &start);
8753 }
8754
8755 if (rettv_list_alloc(rettv) == OK)
8756 {
8757 long n1, n2;
8758
8759# ifdef WIN3264
8760 n1 = res.HighPart;
8761 n2 = res.LowPart;
8762# else
8763 n1 = res.tv_sec;
8764 n2 = res.tv_usec;
8765# endif
8766 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8767 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8768 }
8769#endif
8770}
8771
8772#ifdef FEAT_FLOAT
8773/*
8774 * "reltimefloat()" function
8775 */
8776 static void
8777f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8778{
8779# ifdef FEAT_RELTIME
8780 proftime_T tm;
8781# endif
8782
8783 rettv->v_type = VAR_FLOAT;
8784 rettv->vval.v_float = 0;
8785# ifdef FEAT_RELTIME
8786 if (list2proftime(&argvars[0], &tm) == OK)
8787 rettv->vval.v_float = profile_float(&tm);
8788# endif
8789}
8790#endif
8791
8792/*
8793 * "reltimestr()" function
8794 */
8795 static void
8796f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8797{
8798#ifdef FEAT_RELTIME
8799 proftime_T tm;
8800#endif
8801
8802 rettv->v_type = VAR_STRING;
8803 rettv->vval.v_string = NULL;
8804#ifdef FEAT_RELTIME
8805 if (list2proftime(&argvars[0], &tm) == OK)
8806 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8807#endif
8808}
8809
8810#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8811static void make_connection(void);
8812static int check_connection(void);
8813
8814 static void
8815make_connection(void)
8816{
8817 if (X_DISPLAY == NULL
8818# ifdef FEAT_GUI
8819 && !gui.in_use
8820# endif
8821 )
8822 {
8823 x_force_connect = TRUE;
8824 setup_term_clip();
8825 x_force_connect = FALSE;
8826 }
8827}
8828
8829 static int
8830check_connection(void)
8831{
8832 make_connection();
8833 if (X_DISPLAY == NULL)
8834 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008835 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008836 return FAIL;
8837 }
8838 return OK;
8839}
8840#endif
8841
8842#ifdef FEAT_CLIENTSERVER
8843 static void
8844remote_common(typval_T *argvars, typval_T *rettv, int expr)
8845{
8846 char_u *server_name;
8847 char_u *keys;
8848 char_u *r = NULL;
8849 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008850 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008851# ifdef WIN32
8852 HWND w;
8853# else
8854 Window w;
8855# endif
8856
8857 if (check_restricted() || check_secure())
8858 return;
8859
8860# ifdef FEAT_X11
8861 if (check_connection() == FAIL)
8862 return;
8863# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008864 if (argvars[2].v_type != VAR_UNKNOWN
8865 && argvars[3].v_type != VAR_UNKNOWN)
8866 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008867
8868 server_name = get_tv_string_chk(&argvars[0]);
8869 if (server_name == NULL)
8870 return; /* type error; errmsg already given */
8871 keys = get_tv_string_buf(&argvars[1], buf);
8872# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008873 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008874# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008875 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8876 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008877# endif
8878 {
8879 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008880 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008881 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008882 vim_free(r);
8883 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008884 else
8885 EMSG2(_("E241: Unable to send to %s"), server_name);
8886 return;
8887 }
8888
8889 rettv->vval.v_string = r;
8890
8891 if (argvars[2].v_type != VAR_UNKNOWN)
8892 {
8893 dictitem_T v;
8894 char_u str[30];
8895 char_u *idvar;
8896
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008897 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008898 if (idvar != NULL && *idvar != NUL)
8899 {
8900 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8901 v.di_tv.v_type = VAR_STRING;
8902 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008903 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008904 vim_free(v.di_tv.vval.v_string);
8905 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008906 }
8907}
8908#endif
8909
8910/*
8911 * "remote_expr()" function
8912 */
8913 static void
8914f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8915{
8916 rettv->v_type = VAR_STRING;
8917 rettv->vval.v_string = NULL;
8918#ifdef FEAT_CLIENTSERVER
8919 remote_common(argvars, rettv, TRUE);
8920#endif
8921}
8922
8923/*
8924 * "remote_foreground()" function
8925 */
8926 static void
8927f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8928{
8929#ifdef FEAT_CLIENTSERVER
8930# ifdef WIN32
8931 /* On Win32 it's done in this application. */
8932 {
8933 char_u *server_name = get_tv_string_chk(&argvars[0]);
8934
8935 if (server_name != NULL)
8936 serverForeground(server_name);
8937 }
8938# else
8939 /* Send a foreground() expression to the server. */
8940 argvars[1].v_type = VAR_STRING;
8941 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8942 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008943 rettv->v_type = VAR_STRING;
8944 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008945 remote_common(argvars, rettv, TRUE);
8946 vim_free(argvars[1].vval.v_string);
8947# endif
8948#endif
8949}
8950
8951 static void
8952f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8953{
8954#ifdef FEAT_CLIENTSERVER
8955 dictitem_T v;
8956 char_u *s = NULL;
8957# ifdef WIN32
8958 long_u n = 0;
8959# endif
8960 char_u *serverid;
8961
8962 if (check_restricted() || check_secure())
8963 {
8964 rettv->vval.v_number = -1;
8965 return;
8966 }
8967 serverid = get_tv_string_chk(&argvars[0]);
8968 if (serverid == NULL)
8969 {
8970 rettv->vval.v_number = -1;
8971 return; /* type error; errmsg already given */
8972 }
8973# ifdef WIN32
8974 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8975 if (n == 0)
8976 rettv->vval.v_number = -1;
8977 else
8978 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008979 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008980 rettv->vval.v_number = (s != NULL);
8981 }
8982# else
8983 if (check_connection() == FAIL)
8984 return;
8985
8986 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8987 serverStrToWin(serverid), &s);
8988# endif
8989
8990 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8991 {
8992 char_u *retvar;
8993
8994 v.di_tv.v_type = VAR_STRING;
8995 v.di_tv.vval.v_string = vim_strsave(s);
8996 retvar = get_tv_string_chk(&argvars[1]);
8997 if (retvar != NULL)
8998 set_var(retvar, &v.di_tv, FALSE);
8999 vim_free(v.di_tv.vval.v_string);
9000 }
9001#else
9002 rettv->vval.v_number = -1;
9003#endif
9004}
9005
9006 static void
9007f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9008{
9009 char_u *r = NULL;
9010
9011#ifdef FEAT_CLIENTSERVER
9012 char_u *serverid = get_tv_string_chk(&argvars[0]);
9013
9014 if (serverid != NULL && !check_restricted() && !check_secure())
9015 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009016 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009017# ifdef WIN32
9018 /* The server's HWND is encoded in the 'id' parameter */
9019 long_u n = 0;
9020# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009021
9022 if (argvars[1].v_type != VAR_UNKNOWN)
9023 timeout = get_tv_number(&argvars[1]);
9024
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009025# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9027 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009028 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009029 if (r == NULL)
9030# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009031 if (check_connection() == FAIL
9032 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9033 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009034# endif
9035 EMSG(_("E277: Unable to read a server reply"));
9036 }
9037#endif
9038 rettv->v_type = VAR_STRING;
9039 rettv->vval.v_string = r;
9040}
9041
9042/*
9043 * "remote_send()" function
9044 */
9045 static void
9046f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9047{
9048 rettv->v_type = VAR_STRING;
9049 rettv->vval.v_string = NULL;
9050#ifdef FEAT_CLIENTSERVER
9051 remote_common(argvars, rettv, FALSE);
9052#endif
9053}
9054
9055/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009056 * "remote_startserver()" function
9057 */
9058 static void
9059f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9060{
9061#ifdef FEAT_CLIENTSERVER
9062 char_u *server = get_tv_string_chk(&argvars[0]);
9063
9064 if (server == NULL)
9065 return; /* type error; errmsg already given */
9066 if (serverName != NULL)
9067 EMSG(_("E941: already started a server"));
9068 else
9069 {
9070# ifdef FEAT_X11
9071 if (check_connection() == OK)
9072 serverRegisterName(X_DISPLAY, server);
9073# else
9074 serverSetName(server);
9075# endif
9076 }
9077#else
9078 EMSG(_("E942: +clientserver feature not available"));
9079#endif
9080}
9081
9082/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009083 * "remove()" function
9084 */
9085 static void
9086f_remove(typval_T *argvars, typval_T *rettv)
9087{
9088 list_T *l;
9089 listitem_T *item, *item2;
9090 listitem_T *li;
9091 long idx;
9092 long end;
9093 char_u *key;
9094 dict_T *d;
9095 dictitem_T *di;
9096 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9097
9098 if (argvars[0].v_type == VAR_DICT)
9099 {
9100 if (argvars[2].v_type != VAR_UNKNOWN)
9101 EMSG2(_(e_toomanyarg), "remove()");
9102 else if ((d = argvars[0].vval.v_dict) != NULL
9103 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9104 {
9105 key = get_tv_string_chk(&argvars[1]);
9106 if (key != NULL)
9107 {
9108 di = dict_find(d, key, -1);
9109 if (di == NULL)
9110 EMSG2(_(e_dictkey), key);
9111 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9112 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9113 {
9114 *rettv = di->di_tv;
9115 init_tv(&di->di_tv);
9116 dictitem_remove(d, di);
9117 }
9118 }
9119 }
9120 }
9121 else if (argvars[0].v_type != VAR_LIST)
9122 EMSG2(_(e_listdictarg), "remove()");
9123 else if ((l = argvars[0].vval.v_list) != NULL
9124 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9125 {
9126 int error = FALSE;
9127
9128 idx = (long)get_tv_number_chk(&argvars[1], &error);
9129 if (error)
9130 ; /* type error: do nothing, errmsg already given */
9131 else if ((item = list_find(l, idx)) == NULL)
9132 EMSGN(_(e_listidx), idx);
9133 else
9134 {
9135 if (argvars[2].v_type == VAR_UNKNOWN)
9136 {
9137 /* Remove one item, return its value. */
9138 vimlist_remove(l, item, item);
9139 *rettv = item->li_tv;
9140 vim_free(item);
9141 }
9142 else
9143 {
9144 /* Remove range of items, return list with values. */
9145 end = (long)get_tv_number_chk(&argvars[2], &error);
9146 if (error)
9147 ; /* type error: do nothing */
9148 else if ((item2 = list_find(l, end)) == NULL)
9149 EMSGN(_(e_listidx), end);
9150 else
9151 {
9152 int cnt = 0;
9153
9154 for (li = item; li != NULL; li = li->li_next)
9155 {
9156 ++cnt;
9157 if (li == item2)
9158 break;
9159 }
9160 if (li == NULL) /* didn't find "item2" after "item" */
9161 EMSG(_(e_invrange));
9162 else
9163 {
9164 vimlist_remove(l, item, item2);
9165 if (rettv_list_alloc(rettv) == OK)
9166 {
9167 l = rettv->vval.v_list;
9168 l->lv_first = item;
9169 l->lv_last = item2;
9170 item->li_prev = NULL;
9171 item2->li_next = NULL;
9172 l->lv_len = cnt;
9173 }
9174 }
9175 }
9176 }
9177 }
9178 }
9179}
9180
9181/*
9182 * "rename({from}, {to})" function
9183 */
9184 static void
9185f_rename(typval_T *argvars, typval_T *rettv)
9186{
9187 char_u buf[NUMBUFLEN];
9188
9189 if (check_restricted() || check_secure())
9190 rettv->vval.v_number = -1;
9191 else
9192 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9193 get_tv_string_buf(&argvars[1], buf));
9194}
9195
9196/*
9197 * "repeat()" function
9198 */
9199 static void
9200f_repeat(typval_T *argvars, typval_T *rettv)
9201{
9202 char_u *p;
9203 int n;
9204 int slen;
9205 int len;
9206 char_u *r;
9207 int i;
9208
9209 n = (int)get_tv_number(&argvars[1]);
9210 if (argvars[0].v_type == VAR_LIST)
9211 {
9212 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9213 while (n-- > 0)
9214 if (list_extend(rettv->vval.v_list,
9215 argvars[0].vval.v_list, NULL) == FAIL)
9216 break;
9217 }
9218 else
9219 {
9220 p = get_tv_string(&argvars[0]);
9221 rettv->v_type = VAR_STRING;
9222 rettv->vval.v_string = NULL;
9223
9224 slen = (int)STRLEN(p);
9225 len = slen * n;
9226 if (len <= 0)
9227 return;
9228
9229 r = alloc(len + 1);
9230 if (r != NULL)
9231 {
9232 for (i = 0; i < n; i++)
9233 mch_memmove(r + i * slen, p, (size_t)slen);
9234 r[len] = NUL;
9235 }
9236
9237 rettv->vval.v_string = r;
9238 }
9239}
9240
9241/*
9242 * "resolve()" function
9243 */
9244 static void
9245f_resolve(typval_T *argvars, typval_T *rettv)
9246{
9247 char_u *p;
9248#ifdef HAVE_READLINK
9249 char_u *buf = NULL;
9250#endif
9251
9252 p = get_tv_string(&argvars[0]);
9253#ifdef FEAT_SHORTCUT
9254 {
9255 char_u *v = NULL;
9256
9257 v = mch_resolve_shortcut(p);
9258 if (v != NULL)
9259 rettv->vval.v_string = v;
9260 else
9261 rettv->vval.v_string = vim_strsave(p);
9262 }
9263#else
9264# ifdef HAVE_READLINK
9265 {
9266 char_u *cpy;
9267 int len;
9268 char_u *remain = NULL;
9269 char_u *q;
9270 int is_relative_to_current = FALSE;
9271 int has_trailing_pathsep = FALSE;
9272 int limit = 100;
9273
9274 p = vim_strsave(p);
9275
9276 if (p[0] == '.' && (vim_ispathsep(p[1])
9277 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9278 is_relative_to_current = TRUE;
9279
9280 len = STRLEN(p);
9281 if (len > 0 && after_pathsep(p, p + len))
9282 {
9283 has_trailing_pathsep = TRUE;
9284 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9285 }
9286
9287 q = getnextcomp(p);
9288 if (*q != NUL)
9289 {
9290 /* Separate the first path component in "p", and keep the
9291 * remainder (beginning with the path separator). */
9292 remain = vim_strsave(q - 1);
9293 q[-1] = NUL;
9294 }
9295
9296 buf = alloc(MAXPATHL + 1);
9297 if (buf == NULL)
9298 goto fail;
9299
9300 for (;;)
9301 {
9302 for (;;)
9303 {
9304 len = readlink((char *)p, (char *)buf, MAXPATHL);
9305 if (len <= 0)
9306 break;
9307 buf[len] = NUL;
9308
9309 if (limit-- == 0)
9310 {
9311 vim_free(p);
9312 vim_free(remain);
9313 EMSG(_("E655: Too many symbolic links (cycle?)"));
9314 rettv->vval.v_string = NULL;
9315 goto fail;
9316 }
9317
9318 /* Ensure that the result will have a trailing path separator
9319 * if the argument has one. */
9320 if (remain == NULL && has_trailing_pathsep)
9321 add_pathsep(buf);
9322
9323 /* Separate the first path component in the link value and
9324 * concatenate the remainders. */
9325 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9326 if (*q != NUL)
9327 {
9328 if (remain == NULL)
9329 remain = vim_strsave(q - 1);
9330 else
9331 {
9332 cpy = concat_str(q - 1, remain);
9333 if (cpy != NULL)
9334 {
9335 vim_free(remain);
9336 remain = cpy;
9337 }
9338 }
9339 q[-1] = NUL;
9340 }
9341
9342 q = gettail(p);
9343 if (q > p && *q == NUL)
9344 {
9345 /* Ignore trailing path separator. */
9346 q[-1] = NUL;
9347 q = gettail(p);
9348 }
9349 if (q > p && !mch_isFullName(buf))
9350 {
9351 /* symlink is relative to directory of argument */
9352 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9353 if (cpy != NULL)
9354 {
9355 STRCPY(cpy, p);
9356 STRCPY(gettail(cpy), buf);
9357 vim_free(p);
9358 p = cpy;
9359 }
9360 }
9361 else
9362 {
9363 vim_free(p);
9364 p = vim_strsave(buf);
9365 }
9366 }
9367
9368 if (remain == NULL)
9369 break;
9370
9371 /* Append the first path component of "remain" to "p". */
9372 q = getnextcomp(remain + 1);
9373 len = q - remain - (*q != NUL);
9374 cpy = vim_strnsave(p, STRLEN(p) + len);
9375 if (cpy != NULL)
9376 {
9377 STRNCAT(cpy, remain, len);
9378 vim_free(p);
9379 p = cpy;
9380 }
9381 /* Shorten "remain". */
9382 if (*q != NUL)
9383 STRMOVE(remain, q - 1);
9384 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009385 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009386 }
9387
9388 /* If the result is a relative path name, make it explicitly relative to
9389 * the current directory if and only if the argument had this form. */
9390 if (!vim_ispathsep(*p))
9391 {
9392 if (is_relative_to_current
9393 && *p != NUL
9394 && !(p[0] == '.'
9395 && (p[1] == NUL
9396 || vim_ispathsep(p[1])
9397 || (p[1] == '.'
9398 && (p[2] == NUL
9399 || vim_ispathsep(p[2]))))))
9400 {
9401 /* Prepend "./". */
9402 cpy = concat_str((char_u *)"./", p);
9403 if (cpy != NULL)
9404 {
9405 vim_free(p);
9406 p = cpy;
9407 }
9408 }
9409 else if (!is_relative_to_current)
9410 {
9411 /* Strip leading "./". */
9412 q = p;
9413 while (q[0] == '.' && vim_ispathsep(q[1]))
9414 q += 2;
9415 if (q > p)
9416 STRMOVE(p, p + 2);
9417 }
9418 }
9419
9420 /* Ensure that the result will have no trailing path separator
9421 * if the argument had none. But keep "/" or "//". */
9422 if (!has_trailing_pathsep)
9423 {
9424 q = p + STRLEN(p);
9425 if (after_pathsep(p, q))
9426 *gettail_sep(p) = NUL;
9427 }
9428
9429 rettv->vval.v_string = p;
9430 }
9431# else
9432 rettv->vval.v_string = vim_strsave(p);
9433# endif
9434#endif
9435
9436 simplify_filename(rettv->vval.v_string);
9437
9438#ifdef HAVE_READLINK
9439fail:
9440 vim_free(buf);
9441#endif
9442 rettv->v_type = VAR_STRING;
9443}
9444
9445/*
9446 * "reverse({list})" function
9447 */
9448 static void
9449f_reverse(typval_T *argvars, typval_T *rettv)
9450{
9451 list_T *l;
9452 listitem_T *li, *ni;
9453
9454 if (argvars[0].v_type != VAR_LIST)
9455 EMSG2(_(e_listarg), "reverse()");
9456 else if ((l = argvars[0].vval.v_list) != NULL
9457 && !tv_check_lock(l->lv_lock,
9458 (char_u *)N_("reverse() argument"), TRUE))
9459 {
9460 li = l->lv_last;
9461 l->lv_first = l->lv_last = NULL;
9462 l->lv_len = 0;
9463 while (li != NULL)
9464 {
9465 ni = li->li_prev;
9466 list_append(l, li);
9467 li = ni;
9468 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009469 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009470 l->lv_idx = l->lv_len - l->lv_idx - 1;
9471 }
9472}
9473
9474#define SP_NOMOVE 0x01 /* don't move cursor */
9475#define SP_REPEAT 0x02 /* repeat to find outer pair */
9476#define SP_RETCOUNT 0x04 /* return matchcount */
9477#define SP_SETPCMARK 0x08 /* set previous context mark */
9478#define SP_START 0x10 /* accept match at start position */
9479#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9480#define SP_END 0x40 /* leave cursor at end of match */
9481#define SP_COLUMN 0x80 /* start at cursor column */
9482
9483static int get_search_arg(typval_T *varp, int *flagsp);
9484
9485/*
9486 * Get flags for a search function.
9487 * Possibly sets "p_ws".
9488 * Returns BACKWARD, FORWARD or zero (for an error).
9489 */
9490 static int
9491get_search_arg(typval_T *varp, int *flagsp)
9492{
9493 int dir = FORWARD;
9494 char_u *flags;
9495 char_u nbuf[NUMBUFLEN];
9496 int mask;
9497
9498 if (varp->v_type != VAR_UNKNOWN)
9499 {
9500 flags = get_tv_string_buf_chk(varp, nbuf);
9501 if (flags == NULL)
9502 return 0; /* type error; errmsg already given */
9503 while (*flags != NUL)
9504 {
9505 switch (*flags)
9506 {
9507 case 'b': dir = BACKWARD; break;
9508 case 'w': p_ws = TRUE; break;
9509 case 'W': p_ws = FALSE; break;
9510 default: mask = 0;
9511 if (flagsp != NULL)
9512 switch (*flags)
9513 {
9514 case 'c': mask = SP_START; break;
9515 case 'e': mask = SP_END; break;
9516 case 'm': mask = SP_RETCOUNT; break;
9517 case 'n': mask = SP_NOMOVE; break;
9518 case 'p': mask = SP_SUBPAT; break;
9519 case 'r': mask = SP_REPEAT; break;
9520 case 's': mask = SP_SETPCMARK; break;
9521 case 'z': mask = SP_COLUMN; break;
9522 }
9523 if (mask == 0)
9524 {
9525 EMSG2(_(e_invarg2), flags);
9526 dir = 0;
9527 }
9528 else
9529 *flagsp |= mask;
9530 }
9531 if (dir == 0)
9532 break;
9533 ++flags;
9534 }
9535 }
9536 return dir;
9537}
9538
9539/*
9540 * Shared by search() and searchpos() functions.
9541 */
9542 static int
9543search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9544{
9545 int flags;
9546 char_u *pat;
9547 pos_T pos;
9548 pos_T save_cursor;
9549 int save_p_ws = p_ws;
9550 int dir;
9551 int retval = 0; /* default: FAIL */
9552 long lnum_stop = 0;
9553 proftime_T tm;
9554#ifdef FEAT_RELTIME
9555 long time_limit = 0;
9556#endif
9557 int options = SEARCH_KEEP;
9558 int subpatnum;
9559
9560 pat = get_tv_string(&argvars[0]);
9561 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9562 if (dir == 0)
9563 goto theend;
9564 flags = *flagsp;
9565 if (flags & SP_START)
9566 options |= SEARCH_START;
9567 if (flags & SP_END)
9568 options |= SEARCH_END;
9569 if (flags & SP_COLUMN)
9570 options |= SEARCH_COL;
9571
9572 /* Optional arguments: line number to stop searching and timeout. */
9573 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9574 {
9575 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9576 if (lnum_stop < 0)
9577 goto theend;
9578#ifdef FEAT_RELTIME
9579 if (argvars[3].v_type != VAR_UNKNOWN)
9580 {
9581 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9582 if (time_limit < 0)
9583 goto theend;
9584 }
9585#endif
9586 }
9587
9588#ifdef FEAT_RELTIME
9589 /* Set the time limit, if there is one. */
9590 profile_setlimit(time_limit, &tm);
9591#endif
9592
9593 /*
9594 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9595 * Check to make sure only those flags are set.
9596 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9597 * flags cannot be set. Check for that condition also.
9598 */
9599 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9600 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9601 {
9602 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9603 goto theend;
9604 }
9605
9606 pos = save_cursor = curwin->w_cursor;
9607 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009608 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009609 if (subpatnum != FAIL)
9610 {
9611 if (flags & SP_SUBPAT)
9612 retval = subpatnum;
9613 else
9614 retval = pos.lnum;
9615 if (flags & SP_SETPCMARK)
9616 setpcmark();
9617 curwin->w_cursor = pos;
9618 if (match_pos != NULL)
9619 {
9620 /* Store the match cursor position */
9621 match_pos->lnum = pos.lnum;
9622 match_pos->col = pos.col + 1;
9623 }
9624 /* "/$" will put the cursor after the end of the line, may need to
9625 * correct that here */
9626 check_cursor();
9627 }
9628
9629 /* If 'n' flag is used: restore cursor position. */
9630 if (flags & SP_NOMOVE)
9631 curwin->w_cursor = save_cursor;
9632 else
9633 curwin->w_set_curswant = TRUE;
9634theend:
9635 p_ws = save_p_ws;
9636
9637 return retval;
9638}
9639
9640#ifdef FEAT_FLOAT
9641
9642/*
9643 * round() is not in C90, use ceil() or floor() instead.
9644 */
9645 float_T
9646vim_round(float_T f)
9647{
9648 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9649}
9650
9651/*
9652 * "round({float})" function
9653 */
9654 static void
9655f_round(typval_T *argvars, typval_T *rettv)
9656{
9657 float_T f = 0.0;
9658
9659 rettv->v_type = VAR_FLOAT;
9660 if (get_float_arg(argvars, &f) == OK)
9661 rettv->vval.v_float = vim_round(f);
9662 else
9663 rettv->vval.v_float = 0.0;
9664}
9665#endif
9666
9667/*
9668 * "screenattr()" function
9669 */
9670 static void
9671f_screenattr(typval_T *argvars, typval_T *rettv)
9672{
9673 int row;
9674 int col;
9675 int c;
9676
9677 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9678 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9679 if (row < 0 || row >= screen_Rows
9680 || col < 0 || col >= screen_Columns)
9681 c = -1;
9682 else
9683 c = ScreenAttrs[LineOffset[row] + col];
9684 rettv->vval.v_number = c;
9685}
9686
9687/*
9688 * "screenchar()" function
9689 */
9690 static void
9691f_screenchar(typval_T *argvars, typval_T *rettv)
9692{
9693 int row;
9694 int col;
9695 int off;
9696 int c;
9697
9698 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9699 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9700 if (row < 0 || row >= screen_Rows
9701 || col < 0 || col >= screen_Columns)
9702 c = -1;
9703 else
9704 {
9705 off = LineOffset[row] + col;
9706#ifdef FEAT_MBYTE
9707 if (enc_utf8 && ScreenLinesUC[off] != 0)
9708 c = ScreenLinesUC[off];
9709 else
9710#endif
9711 c = ScreenLines[off];
9712 }
9713 rettv->vval.v_number = c;
9714}
9715
9716/*
9717 * "screencol()" function
9718 *
9719 * First column is 1 to be consistent with virtcol().
9720 */
9721 static void
9722f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9723{
9724 rettv->vval.v_number = screen_screencol() + 1;
9725}
9726
9727/*
9728 * "screenrow()" function
9729 */
9730 static void
9731f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9732{
9733 rettv->vval.v_number = screen_screenrow() + 1;
9734}
9735
9736/*
9737 * "search()" function
9738 */
9739 static void
9740f_search(typval_T *argvars, typval_T *rettv)
9741{
9742 int flags = 0;
9743
9744 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9745}
9746
9747/*
9748 * "searchdecl()" function
9749 */
9750 static void
9751f_searchdecl(typval_T *argvars, typval_T *rettv)
9752{
9753 int locally = 1;
9754 int thisblock = 0;
9755 int error = FALSE;
9756 char_u *name;
9757
9758 rettv->vval.v_number = 1; /* default: FAIL */
9759
9760 name = get_tv_string_chk(&argvars[0]);
9761 if (argvars[1].v_type != VAR_UNKNOWN)
9762 {
9763 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9764 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9765 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9766 }
9767 if (!error && name != NULL)
9768 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9769 locally, thisblock, SEARCH_KEEP) == FAIL;
9770}
9771
9772/*
9773 * Used by searchpair() and searchpairpos()
9774 */
9775 static int
9776searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9777{
9778 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009779 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009780 int save_p_ws = p_ws;
9781 int dir;
9782 int flags = 0;
9783 char_u nbuf1[NUMBUFLEN];
9784 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009785 int retval = 0; /* default: FAIL */
9786 long lnum_stop = 0;
9787 long time_limit = 0;
9788
9789 /* Get the three pattern arguments: start, middle, end. */
9790 spat = get_tv_string_chk(&argvars[0]);
9791 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9792 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9793 if (spat == NULL || mpat == NULL || epat == NULL)
9794 goto theend; /* type error */
9795
9796 /* Handle the optional fourth argument: flags */
9797 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9798 if (dir == 0)
9799 goto theend;
9800
9801 /* Don't accept SP_END or SP_SUBPAT.
9802 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9803 */
9804 if ((flags & (SP_END | SP_SUBPAT)) != 0
9805 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9806 {
9807 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9808 goto theend;
9809 }
9810
9811 /* Using 'r' implies 'W', otherwise it doesn't work. */
9812 if (flags & SP_REPEAT)
9813 p_ws = FALSE;
9814
9815 /* Optional fifth argument: skip expression */
9816 if (argvars[3].v_type == VAR_UNKNOWN
9817 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009818 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009819 else
9820 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009821 skip = &argvars[4];
9822 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9823 && skip->v_type != VAR_STRING)
9824 {
9825 /* Type error */
9826 goto theend;
9827 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009828 if (argvars[5].v_type != VAR_UNKNOWN)
9829 {
9830 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9831 if (lnum_stop < 0)
9832 goto theend;
9833#ifdef FEAT_RELTIME
9834 if (argvars[6].v_type != VAR_UNKNOWN)
9835 {
9836 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9837 if (time_limit < 0)
9838 goto theend;
9839 }
9840#endif
9841 }
9842 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009843
9844 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9845 match_pos, lnum_stop, time_limit);
9846
9847theend:
9848 p_ws = save_p_ws;
9849
9850 return retval;
9851}
9852
9853/*
9854 * "searchpair()" function
9855 */
9856 static void
9857f_searchpair(typval_T *argvars, typval_T *rettv)
9858{
9859 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9860}
9861
9862/*
9863 * "searchpairpos()" function
9864 */
9865 static void
9866f_searchpairpos(typval_T *argvars, typval_T *rettv)
9867{
9868 pos_T match_pos;
9869 int lnum = 0;
9870 int col = 0;
9871
9872 if (rettv_list_alloc(rettv) == FAIL)
9873 return;
9874
9875 if (searchpair_cmn(argvars, &match_pos) > 0)
9876 {
9877 lnum = match_pos.lnum;
9878 col = match_pos.col;
9879 }
9880
9881 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9882 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9883}
9884
9885/*
9886 * Search for a start/middle/end thing.
9887 * Used by searchpair(), see its documentation for the details.
9888 * Returns 0 or -1 for no match,
9889 */
9890 long
9891do_searchpair(
9892 char_u *spat, /* start pattern */
9893 char_u *mpat, /* middle pattern */
9894 char_u *epat, /* end pattern */
9895 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009896 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009897 int flags, /* SP_SETPCMARK and other SP_ values */
9898 pos_T *match_pos,
9899 linenr_T lnum_stop, /* stop at this line if not zero */
9900 long time_limit UNUSED) /* stop after this many msec */
9901{
9902 char_u *save_cpo;
9903 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9904 long retval = 0;
9905 pos_T pos;
9906 pos_T firstpos;
9907 pos_T foundpos;
9908 pos_T save_cursor;
9909 pos_T save_pos;
9910 int n;
9911 int r;
9912 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009913 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009914 int err;
9915 int options = SEARCH_KEEP;
9916 proftime_T tm;
9917
9918 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9919 save_cpo = p_cpo;
9920 p_cpo = empty_option;
9921
9922#ifdef FEAT_RELTIME
9923 /* Set the time limit, if there is one. */
9924 profile_setlimit(time_limit, &tm);
9925#endif
9926
9927 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9928 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009929 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9930 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009931 if (pat2 == NULL || pat3 == NULL)
9932 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009933 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009934 if (*mpat == NUL)
9935 STRCPY(pat3, pat2);
9936 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009937 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009938 spat, epat, mpat);
9939 if (flags & SP_START)
9940 options |= SEARCH_START;
9941
Bram Moolenaar48570482017-10-30 21:48:41 +01009942 if (skip != NULL)
9943 {
9944 /* Empty string means to not use the skip expression. */
9945 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9946 use_skip = skip->vval.v_string != NULL
9947 && *skip->vval.v_string != NUL;
9948 }
9949
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009950 save_cursor = curwin->w_cursor;
9951 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009952 CLEAR_POS(&firstpos);
9953 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009954 pat = pat3;
9955 for (;;)
9956 {
9957 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009958 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009959 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009960 /* didn't find it or found the first match again: FAIL */
9961 break;
9962
9963 if (firstpos.lnum == 0)
9964 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009965 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009966 {
9967 /* Found the same position again. Can happen with a pattern that
9968 * has "\zs" at the end and searching backwards. Advance one
9969 * character and try again. */
9970 if (dir == BACKWARD)
9971 decl(&pos);
9972 else
9973 incl(&pos);
9974 }
9975 foundpos = pos;
9976
9977 /* clear the start flag to avoid getting stuck here */
9978 options &= ~SEARCH_START;
9979
9980 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009981 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009982 {
9983 save_pos = curwin->w_cursor;
9984 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009985 err = FALSE;
9986 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009987 curwin->w_cursor = save_pos;
9988 if (err)
9989 {
9990 /* Evaluating {skip} caused an error, break here. */
9991 curwin->w_cursor = save_cursor;
9992 retval = -1;
9993 break;
9994 }
9995 if (r)
9996 continue;
9997 }
9998
9999 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10000 {
10001 /* Found end when searching backwards or start when searching
10002 * forward: nested pair. */
10003 ++nest;
10004 pat = pat2; /* nested, don't search for middle */
10005 }
10006 else
10007 {
10008 /* Found end when searching forward or start when searching
10009 * backward: end of (nested) pair; or found middle in outer pair. */
10010 if (--nest == 1)
10011 pat = pat3; /* outer level, search for middle */
10012 }
10013
10014 if (nest == 0)
10015 {
10016 /* Found the match: return matchcount or line number. */
10017 if (flags & SP_RETCOUNT)
10018 ++retval;
10019 else
10020 retval = pos.lnum;
10021 if (flags & SP_SETPCMARK)
10022 setpcmark();
10023 curwin->w_cursor = pos;
10024 if (!(flags & SP_REPEAT))
10025 break;
10026 nest = 1; /* search for next unmatched */
10027 }
10028 }
10029
10030 if (match_pos != NULL)
10031 {
10032 /* Store the match cursor position */
10033 match_pos->lnum = curwin->w_cursor.lnum;
10034 match_pos->col = curwin->w_cursor.col + 1;
10035 }
10036
10037 /* If 'n' flag is used or search failed: restore cursor position. */
10038 if ((flags & SP_NOMOVE) || retval == 0)
10039 curwin->w_cursor = save_cursor;
10040
10041theend:
10042 vim_free(pat2);
10043 vim_free(pat3);
10044 if (p_cpo == empty_option)
10045 p_cpo = save_cpo;
10046 else
10047 /* Darn, evaluating the {skip} expression changed the value. */
10048 free_string_option(save_cpo);
10049
10050 return retval;
10051}
10052
10053/*
10054 * "searchpos()" function
10055 */
10056 static void
10057f_searchpos(typval_T *argvars, typval_T *rettv)
10058{
10059 pos_T match_pos;
10060 int lnum = 0;
10061 int col = 0;
10062 int n;
10063 int flags = 0;
10064
10065 if (rettv_list_alloc(rettv) == FAIL)
10066 return;
10067
10068 n = search_cmn(argvars, &match_pos, &flags);
10069 if (n > 0)
10070 {
10071 lnum = match_pos.lnum;
10072 col = match_pos.col;
10073 }
10074
10075 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10076 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10077 if (flags & SP_SUBPAT)
10078 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10079}
10080
10081 static void
10082f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10083{
10084#ifdef FEAT_CLIENTSERVER
10085 char_u buf[NUMBUFLEN];
10086 char_u *server = get_tv_string_chk(&argvars[0]);
10087 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10088
10089 rettv->vval.v_number = -1;
10090 if (server == NULL || reply == NULL)
10091 return;
10092 if (check_restricted() || check_secure())
10093 return;
10094# ifdef FEAT_X11
10095 if (check_connection() == FAIL)
10096 return;
10097# endif
10098
10099 if (serverSendReply(server, reply) < 0)
10100 {
10101 EMSG(_("E258: Unable to send to client"));
10102 return;
10103 }
10104 rettv->vval.v_number = 0;
10105#else
10106 rettv->vval.v_number = -1;
10107#endif
10108}
10109
10110 static void
10111f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10112{
10113 char_u *r = NULL;
10114
10115#ifdef FEAT_CLIENTSERVER
10116# ifdef WIN32
10117 r = serverGetVimNames();
10118# else
10119 make_connection();
10120 if (X_DISPLAY != NULL)
10121 r = serverGetVimNames(X_DISPLAY);
10122# endif
10123#endif
10124 rettv->v_type = VAR_STRING;
10125 rettv->vval.v_string = r;
10126}
10127
10128/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010129 * Set line or list of lines in buffer "buf".
10130 */
10131 static void
10132set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
10133{
10134 char_u *line = NULL;
10135 list_T *l = NULL;
10136 listitem_T *li = NULL;
10137 long added = 0;
10138 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010139 buf_T *curbuf_save = NULL;
10140 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010141 int is_curbuf = buf == curbuf;
10142
Bram Moolenaar9d954202017-09-04 20:34:19 +020010143 /* When using the current buffer ml_mfp will be set if needed. Useful when
10144 * setline() is used on startup. For other buffers the buffer must be
10145 * loaded. */
10146 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010147 {
10148 rettv->vval.v_number = 1; /* FAIL */
10149 return;
10150 }
10151
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010152 if (!is_curbuf)
10153 {
10154 wininfo_T *wip;
10155
10156 curbuf_save = curbuf;
10157 curwin_save = curwin;
10158 curbuf = buf;
10159 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
10160 {
10161 if (wip->wi_win != NULL)
10162 {
10163 curwin = wip->wi_win;
10164 break;
10165 }
10166 }
10167 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010168
10169 lcount = curbuf->b_ml.ml_line_count;
10170
10171 if (lines->v_type == VAR_LIST)
10172 {
10173 l = lines->vval.v_list;
10174 li = l->lv_first;
10175 }
10176 else
10177 line = get_tv_string_chk(lines);
10178
10179 /* default result is zero == OK */
10180 for (;;)
10181 {
10182 if (l != NULL)
10183 {
10184 /* list argument, get next string */
10185 if (li == NULL)
10186 break;
10187 line = get_tv_string_chk(&li->li_tv);
10188 li = li->li_next;
10189 }
10190
10191 rettv->vval.v_number = 1; /* FAIL */
10192 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10193 break;
10194
10195 /* When coming here from Insert mode, sync undo, so that this can be
10196 * undone separately from what was previously inserted. */
10197 if (u_sync_once == 2)
10198 {
10199 u_sync_once = 1; /* notify that u_sync() was called */
10200 u_sync(TRUE);
10201 }
10202
10203 if (lnum <= curbuf->b_ml.ml_line_count)
10204 {
10205 /* existing line, replace it */
10206 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10207 {
10208 changed_bytes(lnum, 0);
10209 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10210 check_cursor_col();
10211 rettv->vval.v_number = 0; /* OK */
10212 }
10213 }
10214 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10215 {
10216 /* lnum is one past the last line, append the line */
10217 ++added;
10218 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10219 rettv->vval.v_number = 0; /* OK */
10220 }
10221
10222 if (l == NULL) /* only one string argument */
10223 break;
10224 ++lnum;
10225 }
10226
10227 if (added > 0)
10228 appended_lines_mark(lcount, added);
10229
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010230 if (!is_curbuf)
10231 {
10232 curbuf = curbuf_save;
10233 curwin = curwin_save;
10234 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010235}
10236
10237/*
10238 * "setbufline()" function
10239 */
10240 static void
10241f_setbufline(argvars, rettv)
10242 typval_T *argvars;
10243 typval_T *rettv;
10244{
10245 linenr_T lnum;
10246 buf_T *buf;
10247
10248 buf = get_buf_tv(&argvars[0], FALSE);
10249 if (buf == NULL)
10250 rettv->vval.v_number = 1; /* FAIL */
10251 else
10252 {
10253 lnum = get_tv_lnum_buf(&argvars[1], buf);
10254
10255 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10256 }
10257}
10258
10259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010260 * "setbufvar()" function
10261 */
10262 static void
10263f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10264{
10265 buf_T *buf;
10266 char_u *varname, *bufvarname;
10267 typval_T *varp;
10268 char_u nbuf[NUMBUFLEN];
10269
10270 if (check_restricted() || check_secure())
10271 return;
10272 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10273 varname = get_tv_string_chk(&argvars[1]);
10274 buf = get_buf_tv(&argvars[0], FALSE);
10275 varp = &argvars[2];
10276
10277 if (buf != NULL && varname != NULL && varp != NULL)
10278 {
10279 if (*varname == '&')
10280 {
10281 long numval;
10282 char_u *strval;
10283 int error = FALSE;
10284 aco_save_T aco;
10285
10286 /* set curbuf to be our buf, temporarily */
10287 aucmd_prepbuf(&aco, buf);
10288
10289 ++varname;
10290 numval = (long)get_tv_number_chk(varp, &error);
10291 strval = get_tv_string_buf_chk(varp, nbuf);
10292 if (!error && strval != NULL)
10293 set_option_value(varname, numval, strval, OPT_LOCAL);
10294
10295 /* reset notion of buffer */
10296 aucmd_restbuf(&aco);
10297 }
10298 else
10299 {
10300 buf_T *save_curbuf = curbuf;
10301
10302 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10303 if (bufvarname != NULL)
10304 {
10305 curbuf = buf;
10306 STRCPY(bufvarname, "b:");
10307 STRCPY(bufvarname + 2, varname);
10308 set_var(bufvarname, varp, TRUE);
10309 vim_free(bufvarname);
10310 curbuf = save_curbuf;
10311 }
10312 }
10313 }
10314}
10315
10316 static void
10317f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10318{
10319 dict_T *d;
10320 dictitem_T *di;
10321 char_u *csearch;
10322
10323 if (argvars[0].v_type != VAR_DICT)
10324 {
10325 EMSG(_(e_dictreq));
10326 return;
10327 }
10328
10329 if ((d = argvars[0].vval.v_dict) != NULL)
10330 {
10331 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10332 if (csearch != NULL)
10333 {
10334#ifdef FEAT_MBYTE
10335 if (enc_utf8)
10336 {
10337 int pcc[MAX_MCO];
10338 int c = utfc_ptr2char(csearch, pcc);
10339
10340 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10341 }
10342 else
10343#endif
10344 set_last_csearch(PTR2CHAR(csearch),
10345 csearch, MB_PTR2LEN(csearch));
10346 }
10347
10348 di = dict_find(d, (char_u *)"forward", -1);
10349 if (di != NULL)
10350 set_csearch_direction((int)get_tv_number(&di->di_tv)
10351 ? FORWARD : BACKWARD);
10352
10353 di = dict_find(d, (char_u *)"until", -1);
10354 if (di != NULL)
10355 set_csearch_until(!!get_tv_number(&di->di_tv));
10356 }
10357}
10358
10359/*
10360 * "setcmdpos()" function
10361 */
10362 static void
10363f_setcmdpos(typval_T *argvars, typval_T *rettv)
10364{
10365 int pos = (int)get_tv_number(&argvars[0]) - 1;
10366
10367 if (pos >= 0)
10368 rettv->vval.v_number = set_cmdline_pos(pos);
10369}
10370
10371/*
10372 * "setfperm({fname}, {mode})" function
10373 */
10374 static void
10375f_setfperm(typval_T *argvars, typval_T *rettv)
10376{
10377 char_u *fname;
10378 char_u modebuf[NUMBUFLEN];
10379 char_u *mode_str;
10380 int i;
10381 int mask;
10382 int mode = 0;
10383
10384 rettv->vval.v_number = 0;
10385 fname = get_tv_string_chk(&argvars[0]);
10386 if (fname == NULL)
10387 return;
10388 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10389 if (mode_str == NULL)
10390 return;
10391 if (STRLEN(mode_str) != 9)
10392 {
10393 EMSG2(_(e_invarg2), mode_str);
10394 return;
10395 }
10396
10397 mask = 1;
10398 for (i = 8; i >= 0; --i)
10399 {
10400 if (mode_str[i] != '-')
10401 mode |= mask;
10402 mask = mask << 1;
10403 }
10404 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10405}
10406
10407/*
10408 * "setline()" function
10409 */
10410 static void
10411f_setline(typval_T *argvars, typval_T *rettv)
10412{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010413 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010414
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010415 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010416}
10417
Bram Moolenaard823fa92016-08-12 16:29:27 +020010418static 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 +020010419
10420/*
10421 * Used by "setqflist()" and "setloclist()" functions
10422 */
10423 static void
10424set_qf_ll_list(
10425 win_T *wp UNUSED,
10426 typval_T *list_arg UNUSED,
10427 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010428 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010429 typval_T *rettv)
10430{
10431#ifdef FEAT_QUICKFIX
10432 static char *e_invact = N_("E927: Invalid action: '%s'");
10433 char_u *act;
10434 int action = 0;
10435#endif
10436
10437 rettv->vval.v_number = -1;
10438
10439#ifdef FEAT_QUICKFIX
10440 if (list_arg->v_type != VAR_LIST)
10441 EMSG(_(e_listreq));
10442 else
10443 {
10444 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010445 dict_T *d = NULL;
10446 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010447
10448 if (action_arg->v_type == VAR_STRING)
10449 {
10450 act = get_tv_string_chk(action_arg);
10451 if (act == NULL)
10452 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010453 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10454 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010455 action = *act;
10456 else
10457 EMSG2(_(e_invact), act);
10458 }
10459 else if (action_arg->v_type == VAR_UNKNOWN)
10460 action = ' ';
10461 else
10462 EMSG(_(e_stringreq));
10463
Bram Moolenaard823fa92016-08-12 16:29:27 +020010464 if (action_arg->v_type != VAR_UNKNOWN
10465 && what_arg->v_type != VAR_UNKNOWN)
10466 {
10467 if (what_arg->v_type == VAR_DICT)
10468 d = what_arg->vval.v_dict;
10469 else
10470 {
10471 EMSG(_(e_dictreq));
10472 valid_dict = FALSE;
10473 }
10474 }
10475
10476 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10477 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010478 rettv->vval.v_number = 0;
10479 }
10480#endif
10481}
10482
10483/*
10484 * "setloclist()" function
10485 */
10486 static void
10487f_setloclist(typval_T *argvars, typval_T *rettv)
10488{
10489 win_T *win;
10490
10491 rettv->vval.v_number = -1;
10492
10493 win = find_win_by_nr(&argvars[0], NULL);
10494 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010495 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010496}
10497
10498/*
10499 * "setmatches()" function
10500 */
10501 static void
10502f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10503{
10504#ifdef FEAT_SEARCH_EXTRA
10505 list_T *l;
10506 listitem_T *li;
10507 dict_T *d;
10508 list_T *s = NULL;
10509
10510 rettv->vval.v_number = -1;
10511 if (argvars[0].v_type != VAR_LIST)
10512 {
10513 EMSG(_(e_listreq));
10514 return;
10515 }
10516 if ((l = argvars[0].vval.v_list) != NULL)
10517 {
10518
10519 /* To some extent make sure that we are dealing with a list from
10520 * "getmatches()". */
10521 li = l->lv_first;
10522 while (li != NULL)
10523 {
10524 if (li->li_tv.v_type != VAR_DICT
10525 || (d = li->li_tv.vval.v_dict) == NULL)
10526 {
10527 EMSG(_(e_invarg));
10528 return;
10529 }
10530 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10531 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10532 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10533 && dict_find(d, (char_u *)"priority", -1) != NULL
10534 && dict_find(d, (char_u *)"id", -1) != NULL))
10535 {
10536 EMSG(_(e_invarg));
10537 return;
10538 }
10539 li = li->li_next;
10540 }
10541
10542 clear_matches(curwin);
10543 li = l->lv_first;
10544 while (li != NULL)
10545 {
10546 int i = 0;
10547 char_u buf[5];
10548 dictitem_T *di;
10549 char_u *group;
10550 int priority;
10551 int id;
10552 char_u *conceal;
10553
10554 d = li->li_tv.vval.v_dict;
10555 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10556 {
10557 if (s == NULL)
10558 {
10559 s = list_alloc();
10560 if (s == NULL)
10561 return;
10562 }
10563
10564 /* match from matchaddpos() */
10565 for (i = 1; i < 9; i++)
10566 {
10567 sprintf((char *)buf, (char *)"pos%d", i);
10568 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10569 {
10570 if (di->di_tv.v_type != VAR_LIST)
10571 return;
10572
10573 list_append_tv(s, &di->di_tv);
10574 s->lv_refcount++;
10575 }
10576 else
10577 break;
10578 }
10579 }
10580
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010581 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010582 priority = (int)get_dict_number(d, (char_u *)"priority");
10583 id = (int)get_dict_number(d, (char_u *)"id");
10584 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010585 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010586 : NULL;
10587 if (i == 0)
10588 {
10589 match_add(curwin, group,
10590 get_dict_string(d, (char_u *)"pattern", FALSE),
10591 priority, id, NULL, conceal);
10592 }
10593 else
10594 {
10595 match_add(curwin, group, NULL, priority, id, s, conceal);
10596 list_unref(s);
10597 s = NULL;
10598 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010599 vim_free(group);
10600 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010601
10602 li = li->li_next;
10603 }
10604 rettv->vval.v_number = 0;
10605 }
10606#endif
10607}
10608
10609/*
10610 * "setpos()" function
10611 */
10612 static void
10613f_setpos(typval_T *argvars, typval_T *rettv)
10614{
10615 pos_T pos;
10616 int fnum;
10617 char_u *name;
10618 colnr_T curswant = -1;
10619
10620 rettv->vval.v_number = -1;
10621 name = get_tv_string_chk(argvars);
10622 if (name != NULL)
10623 {
10624 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10625 {
10626 if (--pos.col < 0)
10627 pos.col = 0;
10628 if (name[0] == '.' && name[1] == NUL)
10629 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010630 /* set cursor; "fnum" is ignored */
10631 curwin->w_cursor = pos;
10632 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010633 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010634 curwin->w_curswant = curswant - 1;
10635 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010636 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010637 check_cursor();
10638 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010639 }
10640 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10641 {
10642 /* set mark */
10643 if (setmark_pos(name[1], &pos, fnum) == OK)
10644 rettv->vval.v_number = 0;
10645 }
10646 else
10647 EMSG(_(e_invarg));
10648 }
10649 }
10650}
10651
10652/*
10653 * "setqflist()" function
10654 */
10655 static void
10656f_setqflist(typval_T *argvars, typval_T *rettv)
10657{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010658 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010659}
10660
10661/*
10662 * "setreg()" function
10663 */
10664 static void
10665f_setreg(typval_T *argvars, typval_T *rettv)
10666{
10667 int regname;
10668 char_u *strregname;
10669 char_u *stropt;
10670 char_u *strval;
10671 int append;
10672 char_u yank_type;
10673 long block_len;
10674
10675 block_len = -1;
10676 yank_type = MAUTO;
10677 append = FALSE;
10678
10679 strregname = get_tv_string_chk(argvars);
10680 rettv->vval.v_number = 1; /* FAIL is default */
10681
10682 if (strregname == NULL)
10683 return; /* type error; errmsg already given */
10684 regname = *strregname;
10685 if (regname == 0 || regname == '@')
10686 regname = '"';
10687
10688 if (argvars[2].v_type != VAR_UNKNOWN)
10689 {
10690 stropt = get_tv_string_chk(&argvars[2]);
10691 if (stropt == NULL)
10692 return; /* type error */
10693 for (; *stropt != NUL; ++stropt)
10694 switch (*stropt)
10695 {
10696 case 'a': case 'A': /* append */
10697 append = TRUE;
10698 break;
10699 case 'v': case 'c': /* character-wise selection */
10700 yank_type = MCHAR;
10701 break;
10702 case 'V': case 'l': /* line-wise selection */
10703 yank_type = MLINE;
10704 break;
10705 case 'b': case Ctrl_V: /* block-wise selection */
10706 yank_type = MBLOCK;
10707 if (VIM_ISDIGIT(stropt[1]))
10708 {
10709 ++stropt;
10710 block_len = getdigits(&stropt) - 1;
10711 --stropt;
10712 }
10713 break;
10714 }
10715 }
10716
10717 if (argvars[1].v_type == VAR_LIST)
10718 {
10719 char_u **lstval;
10720 char_u **allocval;
10721 char_u buf[NUMBUFLEN];
10722 char_u **curval;
10723 char_u **curallocval;
10724 list_T *ll = argvars[1].vval.v_list;
10725 listitem_T *li;
10726 int len;
10727
10728 /* If the list is NULL handle like an empty list. */
10729 len = ll == NULL ? 0 : ll->lv_len;
10730
10731 /* First half: use for pointers to result lines; second half: use for
10732 * pointers to allocated copies. */
10733 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10734 if (lstval == NULL)
10735 return;
10736 curval = lstval;
10737 allocval = lstval + len + 2;
10738 curallocval = allocval;
10739
10740 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10741 li = li->li_next)
10742 {
10743 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10744 if (strval == NULL)
10745 goto free_lstval;
10746 if (strval == buf)
10747 {
10748 /* Need to make a copy, next get_tv_string_buf_chk() will
10749 * overwrite the string. */
10750 strval = vim_strsave(buf);
10751 if (strval == NULL)
10752 goto free_lstval;
10753 *curallocval++ = strval;
10754 }
10755 *curval++ = strval;
10756 }
10757 *curval++ = NULL;
10758
10759 write_reg_contents_lst(regname, lstval, -1,
10760 append, yank_type, block_len);
10761free_lstval:
10762 while (curallocval > allocval)
10763 vim_free(*--curallocval);
10764 vim_free(lstval);
10765 }
10766 else
10767 {
10768 strval = get_tv_string_chk(&argvars[1]);
10769 if (strval == NULL)
10770 return;
10771 write_reg_contents_ex(regname, strval, -1,
10772 append, yank_type, block_len);
10773 }
10774 rettv->vval.v_number = 0;
10775}
10776
10777/*
10778 * "settabvar()" function
10779 */
10780 static void
10781f_settabvar(typval_T *argvars, typval_T *rettv)
10782{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010783 tabpage_T *save_curtab;
10784 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010785 char_u *varname, *tabvarname;
10786 typval_T *varp;
10787
10788 rettv->vval.v_number = 0;
10789
10790 if (check_restricted() || check_secure())
10791 return;
10792
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010793 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010794 varname = get_tv_string_chk(&argvars[1]);
10795 varp = &argvars[2];
10796
Bram Moolenaar4033c552017-09-16 20:54:51 +020010797 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010798 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010799 save_curtab = curtab;
10800 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010801
10802 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10803 if (tabvarname != NULL)
10804 {
10805 STRCPY(tabvarname, "t:");
10806 STRCPY(tabvarname + 2, varname);
10807 set_var(tabvarname, varp, TRUE);
10808 vim_free(tabvarname);
10809 }
10810
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010811 /* Restore current tabpage */
10812 if (valid_tabpage(save_curtab))
10813 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010814 }
10815}
10816
10817/*
10818 * "settabwinvar()" function
10819 */
10820 static void
10821f_settabwinvar(typval_T *argvars, typval_T *rettv)
10822{
10823 setwinvar(argvars, rettv, 1);
10824}
10825
10826/*
10827 * "setwinvar()" function
10828 */
10829 static void
10830f_setwinvar(typval_T *argvars, typval_T *rettv)
10831{
10832 setwinvar(argvars, rettv, 0);
10833}
10834
10835#ifdef FEAT_CRYPT
10836/*
10837 * "sha256({string})" function
10838 */
10839 static void
10840f_sha256(typval_T *argvars, typval_T *rettv)
10841{
10842 char_u *p;
10843
10844 p = get_tv_string(&argvars[0]);
10845 rettv->vval.v_string = vim_strsave(
10846 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10847 rettv->v_type = VAR_STRING;
10848}
10849#endif /* FEAT_CRYPT */
10850
10851/*
10852 * "shellescape({string})" function
10853 */
10854 static void
10855f_shellescape(typval_T *argvars, typval_T *rettv)
10856{
Bram Moolenaar20615522017-06-05 18:46:26 +020010857 int do_special = non_zero_arg(&argvars[1]);
10858
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010859 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010860 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010861 rettv->v_type = VAR_STRING;
10862}
10863
10864/*
10865 * shiftwidth() function
10866 */
10867 static void
10868f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10869{
10870 rettv->vval.v_number = get_sw_value(curbuf);
10871}
10872
10873/*
10874 * "simplify()" function
10875 */
10876 static void
10877f_simplify(typval_T *argvars, typval_T *rettv)
10878{
10879 char_u *p;
10880
10881 p = get_tv_string(&argvars[0]);
10882 rettv->vval.v_string = vim_strsave(p);
10883 simplify_filename(rettv->vval.v_string); /* simplify in place */
10884 rettv->v_type = VAR_STRING;
10885}
10886
10887#ifdef FEAT_FLOAT
10888/*
10889 * "sin()" function
10890 */
10891 static void
10892f_sin(typval_T *argvars, typval_T *rettv)
10893{
10894 float_T f = 0.0;
10895
10896 rettv->v_type = VAR_FLOAT;
10897 if (get_float_arg(argvars, &f) == OK)
10898 rettv->vval.v_float = sin(f);
10899 else
10900 rettv->vval.v_float = 0.0;
10901}
10902
10903/*
10904 * "sinh()" function
10905 */
10906 static void
10907f_sinh(typval_T *argvars, typval_T *rettv)
10908{
10909 float_T f = 0.0;
10910
10911 rettv->v_type = VAR_FLOAT;
10912 if (get_float_arg(argvars, &f) == OK)
10913 rettv->vval.v_float = sinh(f);
10914 else
10915 rettv->vval.v_float = 0.0;
10916}
10917#endif
10918
10919static int
10920#ifdef __BORLANDC__
10921 _RTLENTRYF
10922#endif
10923 item_compare(const void *s1, const void *s2);
10924static int
10925#ifdef __BORLANDC__
10926 _RTLENTRYF
10927#endif
10928 item_compare2(const void *s1, const void *s2);
10929
10930/* struct used in the array that's given to qsort() */
10931typedef struct
10932{
10933 listitem_T *item;
10934 int idx;
10935} sortItem_T;
10936
10937/* struct storing information about current sort */
10938typedef struct
10939{
10940 int item_compare_ic;
10941 int item_compare_numeric;
10942 int item_compare_numbers;
10943#ifdef FEAT_FLOAT
10944 int item_compare_float;
10945#endif
10946 char_u *item_compare_func;
10947 partial_T *item_compare_partial;
10948 dict_T *item_compare_selfdict;
10949 int item_compare_func_err;
10950 int item_compare_keep_zero;
10951} sortinfo_T;
10952static sortinfo_T *sortinfo = NULL;
10953static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10954#define ITEM_COMPARE_FAIL 999
10955
10956/*
10957 * Compare functions for f_sort() and f_uniq() below.
10958 */
10959 static int
10960#ifdef __BORLANDC__
10961_RTLENTRYF
10962#endif
10963item_compare(const void *s1, const void *s2)
10964{
10965 sortItem_T *si1, *si2;
10966 typval_T *tv1, *tv2;
10967 char_u *p1, *p2;
10968 char_u *tofree1 = NULL, *tofree2 = NULL;
10969 int res;
10970 char_u numbuf1[NUMBUFLEN];
10971 char_u numbuf2[NUMBUFLEN];
10972
10973 si1 = (sortItem_T *)s1;
10974 si2 = (sortItem_T *)s2;
10975 tv1 = &si1->item->li_tv;
10976 tv2 = &si2->item->li_tv;
10977
10978 if (sortinfo->item_compare_numbers)
10979 {
10980 varnumber_T v1 = get_tv_number(tv1);
10981 varnumber_T v2 = get_tv_number(tv2);
10982
10983 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10984 }
10985
10986#ifdef FEAT_FLOAT
10987 if (sortinfo->item_compare_float)
10988 {
10989 float_T v1 = get_tv_float(tv1);
10990 float_T v2 = get_tv_float(tv2);
10991
10992 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10993 }
10994#endif
10995
10996 /* tv2string() puts quotes around a string and allocates memory. Don't do
10997 * that for string variables. Use a single quote when comparing with a
10998 * non-string to do what the docs promise. */
10999 if (tv1->v_type == VAR_STRING)
11000 {
11001 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11002 p1 = (char_u *)"'";
11003 else
11004 p1 = tv1->vval.v_string;
11005 }
11006 else
11007 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11008 if (tv2->v_type == VAR_STRING)
11009 {
11010 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11011 p2 = (char_u *)"'";
11012 else
11013 p2 = tv2->vval.v_string;
11014 }
11015 else
11016 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11017 if (p1 == NULL)
11018 p1 = (char_u *)"";
11019 if (p2 == NULL)
11020 p2 = (char_u *)"";
11021 if (!sortinfo->item_compare_numeric)
11022 {
11023 if (sortinfo->item_compare_ic)
11024 res = STRICMP(p1, p2);
11025 else
11026 res = STRCMP(p1, p2);
11027 }
11028 else
11029 {
11030 double n1, n2;
11031 n1 = strtod((char *)p1, (char **)&p1);
11032 n2 = strtod((char *)p2, (char **)&p2);
11033 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11034 }
11035
11036 /* When the result would be zero, compare the item indexes. Makes the
11037 * sort stable. */
11038 if (res == 0 && !sortinfo->item_compare_keep_zero)
11039 res = si1->idx > si2->idx ? 1 : -1;
11040
11041 vim_free(tofree1);
11042 vim_free(tofree2);
11043 return res;
11044}
11045
11046 static int
11047#ifdef __BORLANDC__
11048_RTLENTRYF
11049#endif
11050item_compare2(const void *s1, const void *s2)
11051{
11052 sortItem_T *si1, *si2;
11053 int res;
11054 typval_T rettv;
11055 typval_T argv[3];
11056 int dummy;
11057 char_u *func_name;
11058 partial_T *partial = sortinfo->item_compare_partial;
11059
11060 /* shortcut after failure in previous call; compare all items equal */
11061 if (sortinfo->item_compare_func_err)
11062 return 0;
11063
11064 si1 = (sortItem_T *)s1;
11065 si2 = (sortItem_T *)s2;
11066
11067 if (partial == NULL)
11068 func_name = sortinfo->item_compare_func;
11069 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011070 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011071
11072 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11073 * in the copy without changing the original list items. */
11074 copy_tv(&si1->item->li_tv, &argv[0]);
11075 copy_tv(&si2->item->li_tv, &argv[1]);
11076
11077 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11078 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011079 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080 partial, sortinfo->item_compare_selfdict);
11081 clear_tv(&argv[0]);
11082 clear_tv(&argv[1]);
11083
11084 if (res == FAIL)
11085 res = ITEM_COMPARE_FAIL;
11086 else
11087 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11088 if (sortinfo->item_compare_func_err)
11089 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11090 clear_tv(&rettv);
11091
11092 /* When the result would be zero, compare the pointers themselves. Makes
11093 * the sort stable. */
11094 if (res == 0 && !sortinfo->item_compare_keep_zero)
11095 res = si1->idx > si2->idx ? 1 : -1;
11096
11097 return res;
11098}
11099
11100/*
11101 * "sort({list})" function
11102 */
11103 static void
11104do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11105{
11106 list_T *l;
11107 listitem_T *li;
11108 sortItem_T *ptrs;
11109 sortinfo_T *old_sortinfo;
11110 sortinfo_T info;
11111 long len;
11112 long i;
11113
11114 /* Pointer to current info struct used in compare function. Save and
11115 * restore the current one for nested calls. */
11116 old_sortinfo = sortinfo;
11117 sortinfo = &info;
11118
11119 if (argvars[0].v_type != VAR_LIST)
11120 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11121 else
11122 {
11123 l = argvars[0].vval.v_list;
11124 if (l == NULL || tv_check_lock(l->lv_lock,
11125 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11126 TRUE))
11127 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011128 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011129
11130 len = list_len(l);
11131 if (len <= 1)
11132 goto theend; /* short list sorts pretty quickly */
11133
11134 info.item_compare_ic = FALSE;
11135 info.item_compare_numeric = FALSE;
11136 info.item_compare_numbers = FALSE;
11137#ifdef FEAT_FLOAT
11138 info.item_compare_float = FALSE;
11139#endif
11140 info.item_compare_func = NULL;
11141 info.item_compare_partial = NULL;
11142 info.item_compare_selfdict = NULL;
11143 if (argvars[1].v_type != VAR_UNKNOWN)
11144 {
11145 /* optional second argument: {func} */
11146 if (argvars[1].v_type == VAR_FUNC)
11147 info.item_compare_func = argvars[1].vval.v_string;
11148 else if (argvars[1].v_type == VAR_PARTIAL)
11149 info.item_compare_partial = argvars[1].vval.v_partial;
11150 else
11151 {
11152 int error = FALSE;
11153
11154 i = (long)get_tv_number_chk(&argvars[1], &error);
11155 if (error)
11156 goto theend; /* type error; errmsg already given */
11157 if (i == 1)
11158 info.item_compare_ic = TRUE;
11159 else if (argvars[1].v_type != VAR_NUMBER)
11160 info.item_compare_func = get_tv_string(&argvars[1]);
11161 else if (i != 0)
11162 {
11163 EMSG(_(e_invarg));
11164 goto theend;
11165 }
11166 if (info.item_compare_func != NULL)
11167 {
11168 if (*info.item_compare_func == NUL)
11169 {
11170 /* empty string means default sort */
11171 info.item_compare_func = NULL;
11172 }
11173 else if (STRCMP(info.item_compare_func, "n") == 0)
11174 {
11175 info.item_compare_func = NULL;
11176 info.item_compare_numeric = TRUE;
11177 }
11178 else if (STRCMP(info.item_compare_func, "N") == 0)
11179 {
11180 info.item_compare_func = NULL;
11181 info.item_compare_numbers = TRUE;
11182 }
11183#ifdef FEAT_FLOAT
11184 else if (STRCMP(info.item_compare_func, "f") == 0)
11185 {
11186 info.item_compare_func = NULL;
11187 info.item_compare_float = TRUE;
11188 }
11189#endif
11190 else if (STRCMP(info.item_compare_func, "i") == 0)
11191 {
11192 info.item_compare_func = NULL;
11193 info.item_compare_ic = TRUE;
11194 }
11195 }
11196 }
11197
11198 if (argvars[2].v_type != VAR_UNKNOWN)
11199 {
11200 /* optional third argument: {dict} */
11201 if (argvars[2].v_type != VAR_DICT)
11202 {
11203 EMSG(_(e_dictreq));
11204 goto theend;
11205 }
11206 info.item_compare_selfdict = argvars[2].vval.v_dict;
11207 }
11208 }
11209
11210 /* Make an array with each entry pointing to an item in the List. */
11211 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11212 if (ptrs == NULL)
11213 goto theend;
11214
11215 i = 0;
11216 if (sort)
11217 {
11218 /* sort(): ptrs will be the list to sort */
11219 for (li = l->lv_first; li != NULL; li = li->li_next)
11220 {
11221 ptrs[i].item = li;
11222 ptrs[i].idx = i;
11223 ++i;
11224 }
11225
11226 info.item_compare_func_err = FALSE;
11227 info.item_compare_keep_zero = FALSE;
11228 /* test the compare function */
11229 if ((info.item_compare_func != NULL
11230 || info.item_compare_partial != NULL)
11231 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11232 == ITEM_COMPARE_FAIL)
11233 EMSG(_("E702: Sort compare function failed"));
11234 else
11235 {
11236 /* Sort the array with item pointers. */
11237 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11238 info.item_compare_func == NULL
11239 && info.item_compare_partial == NULL
11240 ? item_compare : item_compare2);
11241
11242 if (!info.item_compare_func_err)
11243 {
11244 /* Clear the List and append the items in sorted order. */
11245 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11246 l->lv_len = 0;
11247 for (i = 0; i < len; ++i)
11248 list_append(l, ptrs[i].item);
11249 }
11250 }
11251 }
11252 else
11253 {
11254 int (*item_compare_func_ptr)(const void *, const void *);
11255
11256 /* f_uniq(): ptrs will be a stack of items to remove */
11257 info.item_compare_func_err = FALSE;
11258 info.item_compare_keep_zero = TRUE;
11259 item_compare_func_ptr = info.item_compare_func != NULL
11260 || info.item_compare_partial != NULL
11261 ? item_compare2 : item_compare;
11262
11263 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11264 li = li->li_next)
11265 {
11266 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11267 == 0)
11268 ptrs[i++].item = li;
11269 if (info.item_compare_func_err)
11270 {
11271 EMSG(_("E882: Uniq compare function failed"));
11272 break;
11273 }
11274 }
11275
11276 if (!info.item_compare_func_err)
11277 {
11278 while (--i >= 0)
11279 {
11280 li = ptrs[i].item->li_next;
11281 ptrs[i].item->li_next = li->li_next;
11282 if (li->li_next != NULL)
11283 li->li_next->li_prev = ptrs[i].item;
11284 else
11285 l->lv_last = ptrs[i].item;
11286 list_fix_watch(l, li);
11287 listitem_free(li);
11288 l->lv_len--;
11289 }
11290 }
11291 }
11292
11293 vim_free(ptrs);
11294 }
11295theend:
11296 sortinfo = old_sortinfo;
11297}
11298
11299/*
11300 * "sort({list})" function
11301 */
11302 static void
11303f_sort(typval_T *argvars, typval_T *rettv)
11304{
11305 do_sort_uniq(argvars, rettv, TRUE);
11306}
11307
11308/*
11309 * "uniq({list})" function
11310 */
11311 static void
11312f_uniq(typval_T *argvars, typval_T *rettv)
11313{
11314 do_sort_uniq(argvars, rettv, FALSE);
11315}
11316
11317/*
11318 * "soundfold({word})" function
11319 */
11320 static void
11321f_soundfold(typval_T *argvars, typval_T *rettv)
11322{
11323 char_u *s;
11324
11325 rettv->v_type = VAR_STRING;
11326 s = get_tv_string(&argvars[0]);
11327#ifdef FEAT_SPELL
11328 rettv->vval.v_string = eval_soundfold(s);
11329#else
11330 rettv->vval.v_string = vim_strsave(s);
11331#endif
11332}
11333
11334/*
11335 * "spellbadword()" function
11336 */
11337 static void
11338f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11339{
11340 char_u *word = (char_u *)"";
11341 hlf_T attr = HLF_COUNT;
11342 int len = 0;
11343
11344 if (rettv_list_alloc(rettv) == FAIL)
11345 return;
11346
11347#ifdef FEAT_SPELL
11348 if (argvars[0].v_type == VAR_UNKNOWN)
11349 {
11350 /* Find the start and length of the badly spelled word. */
11351 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11352 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011353 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011354 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011355 curwin->w_set_curswant = TRUE;
11356 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011357 }
11358 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11359 {
11360 char_u *str = get_tv_string_chk(&argvars[0]);
11361 int capcol = -1;
11362
11363 if (str != NULL)
11364 {
11365 /* Check the argument for spelling. */
11366 while (*str != NUL)
11367 {
11368 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11369 if (attr != HLF_COUNT)
11370 {
11371 word = str;
11372 break;
11373 }
11374 str += len;
11375 }
11376 }
11377 }
11378#endif
11379
11380 list_append_string(rettv->vval.v_list, word, len);
11381 list_append_string(rettv->vval.v_list, (char_u *)(
11382 attr == HLF_SPB ? "bad" :
11383 attr == HLF_SPR ? "rare" :
11384 attr == HLF_SPL ? "local" :
11385 attr == HLF_SPC ? "caps" :
11386 ""), -1);
11387}
11388
11389/*
11390 * "spellsuggest()" function
11391 */
11392 static void
11393f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11394{
11395#ifdef FEAT_SPELL
11396 char_u *str;
11397 int typeerr = FALSE;
11398 int maxcount;
11399 garray_T ga;
11400 int i;
11401 listitem_T *li;
11402 int need_capital = FALSE;
11403#endif
11404
11405 if (rettv_list_alloc(rettv) == FAIL)
11406 return;
11407
11408#ifdef FEAT_SPELL
11409 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11410 {
11411 str = get_tv_string(&argvars[0]);
11412 if (argvars[1].v_type != VAR_UNKNOWN)
11413 {
11414 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11415 if (maxcount <= 0)
11416 return;
11417 if (argvars[2].v_type != VAR_UNKNOWN)
11418 {
11419 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11420 if (typeerr)
11421 return;
11422 }
11423 }
11424 else
11425 maxcount = 25;
11426
11427 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11428
11429 for (i = 0; i < ga.ga_len; ++i)
11430 {
11431 str = ((char_u **)ga.ga_data)[i];
11432
11433 li = listitem_alloc();
11434 if (li == NULL)
11435 vim_free(str);
11436 else
11437 {
11438 li->li_tv.v_type = VAR_STRING;
11439 li->li_tv.v_lock = 0;
11440 li->li_tv.vval.v_string = str;
11441 list_append(rettv->vval.v_list, li);
11442 }
11443 }
11444 ga_clear(&ga);
11445 }
11446#endif
11447}
11448
11449 static void
11450f_split(typval_T *argvars, typval_T *rettv)
11451{
11452 char_u *str;
11453 char_u *end;
11454 char_u *pat = NULL;
11455 regmatch_T regmatch;
11456 char_u patbuf[NUMBUFLEN];
11457 char_u *save_cpo;
11458 int match;
11459 colnr_T col = 0;
11460 int keepempty = FALSE;
11461 int typeerr = FALSE;
11462
11463 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11464 save_cpo = p_cpo;
11465 p_cpo = (char_u *)"";
11466
11467 str = get_tv_string(&argvars[0]);
11468 if (argvars[1].v_type != VAR_UNKNOWN)
11469 {
11470 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11471 if (pat == NULL)
11472 typeerr = TRUE;
11473 if (argvars[2].v_type != VAR_UNKNOWN)
11474 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11475 }
11476 if (pat == NULL || *pat == NUL)
11477 pat = (char_u *)"[\\x01- ]\\+";
11478
11479 if (rettv_list_alloc(rettv) == FAIL)
11480 return;
11481 if (typeerr)
11482 return;
11483
11484 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11485 if (regmatch.regprog != NULL)
11486 {
11487 regmatch.rm_ic = FALSE;
11488 while (*str != NUL || keepempty)
11489 {
11490 if (*str == NUL)
11491 match = FALSE; /* empty item at the end */
11492 else
11493 match = vim_regexec_nl(&regmatch, str, col);
11494 if (match)
11495 end = regmatch.startp[0];
11496 else
11497 end = str + STRLEN(str);
11498 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11499 && *str != NUL && match && end < regmatch.endp[0]))
11500 {
11501 if (list_append_string(rettv->vval.v_list, str,
11502 (int)(end - str)) == FAIL)
11503 break;
11504 }
11505 if (!match)
11506 break;
11507 /* Advance to just after the match. */
11508 if (regmatch.endp[0] > str)
11509 col = 0;
11510 else
11511 {
11512 /* Don't get stuck at the same match. */
11513#ifdef FEAT_MBYTE
11514 col = (*mb_ptr2len)(regmatch.endp[0]);
11515#else
11516 col = 1;
11517#endif
11518 }
11519 str = regmatch.endp[0];
11520 }
11521
11522 vim_regfree(regmatch.regprog);
11523 }
11524
11525 p_cpo = save_cpo;
11526}
11527
11528#ifdef FEAT_FLOAT
11529/*
11530 * "sqrt()" function
11531 */
11532 static void
11533f_sqrt(typval_T *argvars, typval_T *rettv)
11534{
11535 float_T f = 0.0;
11536
11537 rettv->v_type = VAR_FLOAT;
11538 if (get_float_arg(argvars, &f) == OK)
11539 rettv->vval.v_float = sqrt(f);
11540 else
11541 rettv->vval.v_float = 0.0;
11542}
11543
11544/*
11545 * "str2float()" function
11546 */
11547 static void
11548f_str2float(typval_T *argvars, typval_T *rettv)
11549{
11550 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011551 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011552
Bram Moolenaar08243d22017-01-10 16:12:29 +010011553 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011554 p = skipwhite(p + 1);
11555 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011556 if (isneg)
11557 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011558 rettv->v_type = VAR_FLOAT;
11559}
11560#endif
11561
11562/*
11563 * "str2nr()" function
11564 */
11565 static void
11566f_str2nr(typval_T *argvars, typval_T *rettv)
11567{
11568 int base = 10;
11569 char_u *p;
11570 varnumber_T n;
11571 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011572 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011573
11574 if (argvars[1].v_type != VAR_UNKNOWN)
11575 {
11576 base = (int)get_tv_number(&argvars[1]);
11577 if (base != 2 && base != 8 && base != 10 && base != 16)
11578 {
11579 EMSG(_(e_invarg));
11580 return;
11581 }
11582 }
11583
11584 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011585 isneg = (*p == '-');
11586 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011587 p = skipwhite(p + 1);
11588 switch (base)
11589 {
11590 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11591 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11592 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11593 default: what = 0;
11594 }
11595 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011596 if (isneg)
11597 rettv->vval.v_number = -n;
11598 else
11599 rettv->vval.v_number = n;
11600
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011601}
11602
11603#ifdef HAVE_STRFTIME
11604/*
11605 * "strftime({format}[, {time}])" function
11606 */
11607 static void
11608f_strftime(typval_T *argvars, typval_T *rettv)
11609{
11610 char_u result_buf[256];
11611 struct tm *curtime;
11612 time_t seconds;
11613 char_u *p;
11614
11615 rettv->v_type = VAR_STRING;
11616
11617 p = get_tv_string(&argvars[0]);
11618 if (argvars[1].v_type == VAR_UNKNOWN)
11619 seconds = time(NULL);
11620 else
11621 seconds = (time_t)get_tv_number(&argvars[1]);
11622 curtime = localtime(&seconds);
11623 /* MSVC returns NULL for an invalid value of seconds. */
11624 if (curtime == NULL)
11625 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11626 else
11627 {
11628# ifdef FEAT_MBYTE
11629 vimconv_T conv;
11630 char_u *enc;
11631
11632 conv.vc_type = CONV_NONE;
11633 enc = enc_locale();
11634 convert_setup(&conv, p_enc, enc);
11635 if (conv.vc_type != CONV_NONE)
11636 p = string_convert(&conv, p, NULL);
11637# endif
11638 if (p != NULL)
11639 (void)strftime((char *)result_buf, sizeof(result_buf),
11640 (char *)p, curtime);
11641 else
11642 result_buf[0] = NUL;
11643
11644# ifdef FEAT_MBYTE
11645 if (conv.vc_type != CONV_NONE)
11646 vim_free(p);
11647 convert_setup(&conv, enc, p_enc);
11648 if (conv.vc_type != CONV_NONE)
11649 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11650 else
11651# endif
11652 rettv->vval.v_string = vim_strsave(result_buf);
11653
11654# ifdef FEAT_MBYTE
11655 /* Release conversion descriptors */
11656 convert_setup(&conv, NULL, NULL);
11657 vim_free(enc);
11658# endif
11659 }
11660}
11661#endif
11662
11663/*
11664 * "strgetchar()" function
11665 */
11666 static void
11667f_strgetchar(typval_T *argvars, typval_T *rettv)
11668{
11669 char_u *str;
11670 int len;
11671 int error = FALSE;
11672 int charidx;
11673
11674 rettv->vval.v_number = -1;
11675 str = get_tv_string_chk(&argvars[0]);
11676 if (str == NULL)
11677 return;
11678 len = (int)STRLEN(str);
11679 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11680 if (error)
11681 return;
11682#ifdef FEAT_MBYTE
11683 {
11684 int byteidx = 0;
11685
11686 while (charidx >= 0 && byteidx < len)
11687 {
11688 if (charidx == 0)
11689 {
11690 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11691 break;
11692 }
11693 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011694 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011695 }
11696 }
11697#else
11698 if (charidx < len)
11699 rettv->vval.v_number = str[charidx];
11700#endif
11701}
11702
11703/*
11704 * "stridx()" function
11705 */
11706 static void
11707f_stridx(typval_T *argvars, typval_T *rettv)
11708{
11709 char_u buf[NUMBUFLEN];
11710 char_u *needle;
11711 char_u *haystack;
11712 char_u *save_haystack;
11713 char_u *pos;
11714 int start_idx;
11715
11716 needle = get_tv_string_chk(&argvars[1]);
11717 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11718 rettv->vval.v_number = -1;
11719 if (needle == NULL || haystack == NULL)
11720 return; /* type error; errmsg already given */
11721
11722 if (argvars[2].v_type != VAR_UNKNOWN)
11723 {
11724 int error = FALSE;
11725
11726 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11727 if (error || start_idx >= (int)STRLEN(haystack))
11728 return;
11729 if (start_idx >= 0)
11730 haystack += start_idx;
11731 }
11732
11733 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11734 if (pos != NULL)
11735 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11736}
11737
11738/*
11739 * "string()" function
11740 */
11741 static void
11742f_string(typval_T *argvars, typval_T *rettv)
11743{
11744 char_u *tofree;
11745 char_u numbuf[NUMBUFLEN];
11746
11747 rettv->v_type = VAR_STRING;
11748 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11749 get_copyID());
11750 /* Make a copy if we have a value but it's not in allocated memory. */
11751 if (rettv->vval.v_string != NULL && tofree == NULL)
11752 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11753}
11754
11755/*
11756 * "strlen()" function
11757 */
11758 static void
11759f_strlen(typval_T *argvars, typval_T *rettv)
11760{
11761 rettv->vval.v_number = (varnumber_T)(STRLEN(
11762 get_tv_string(&argvars[0])));
11763}
11764
11765/*
11766 * "strchars()" function
11767 */
11768 static void
11769f_strchars(typval_T *argvars, typval_T *rettv)
11770{
11771 char_u *s = get_tv_string(&argvars[0]);
11772 int skipcc = 0;
11773#ifdef FEAT_MBYTE
11774 varnumber_T len = 0;
11775 int (*func_mb_ptr2char_adv)(char_u **pp);
11776#endif
11777
11778 if (argvars[1].v_type != VAR_UNKNOWN)
11779 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11780 if (skipcc < 0 || skipcc > 1)
11781 EMSG(_(e_invarg));
11782 else
11783 {
11784#ifdef FEAT_MBYTE
11785 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11786 while (*s != NUL)
11787 {
11788 func_mb_ptr2char_adv(&s);
11789 ++len;
11790 }
11791 rettv->vval.v_number = len;
11792#else
11793 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11794#endif
11795 }
11796}
11797
11798/*
11799 * "strdisplaywidth()" function
11800 */
11801 static void
11802f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11803{
11804 char_u *s = get_tv_string(&argvars[0]);
11805 int col = 0;
11806
11807 if (argvars[1].v_type != VAR_UNKNOWN)
11808 col = (int)get_tv_number(&argvars[1]);
11809
11810 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11811}
11812
11813/*
11814 * "strwidth()" function
11815 */
11816 static void
11817f_strwidth(typval_T *argvars, typval_T *rettv)
11818{
11819 char_u *s = get_tv_string(&argvars[0]);
11820
11821 rettv->vval.v_number = (varnumber_T)(
11822#ifdef FEAT_MBYTE
11823 mb_string2cells(s, -1)
11824#else
11825 STRLEN(s)
11826#endif
11827 );
11828}
11829
11830/*
11831 * "strcharpart()" function
11832 */
11833 static void
11834f_strcharpart(typval_T *argvars, typval_T *rettv)
11835{
11836#ifdef FEAT_MBYTE
11837 char_u *p;
11838 int nchar;
11839 int nbyte = 0;
11840 int charlen;
11841 int len = 0;
11842 int slen;
11843 int error = FALSE;
11844
11845 p = get_tv_string(&argvars[0]);
11846 slen = (int)STRLEN(p);
11847
11848 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11849 if (!error)
11850 {
11851 if (nchar > 0)
11852 while (nchar > 0 && nbyte < slen)
11853 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011854 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011855 --nchar;
11856 }
11857 else
11858 nbyte = nchar;
11859 if (argvars[2].v_type != VAR_UNKNOWN)
11860 {
11861 charlen = (int)get_tv_number(&argvars[2]);
11862 while (charlen > 0 && nbyte + len < slen)
11863 {
11864 int off = nbyte + len;
11865
11866 if (off < 0)
11867 len += 1;
11868 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011869 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011870 --charlen;
11871 }
11872 }
11873 else
11874 len = slen - nbyte; /* default: all bytes that are available. */
11875 }
11876
11877 /*
11878 * Only return the overlap between the specified part and the actual
11879 * string.
11880 */
11881 if (nbyte < 0)
11882 {
11883 len += nbyte;
11884 nbyte = 0;
11885 }
11886 else if (nbyte > slen)
11887 nbyte = slen;
11888 if (len < 0)
11889 len = 0;
11890 else if (nbyte + len > slen)
11891 len = slen - nbyte;
11892
11893 rettv->v_type = VAR_STRING;
11894 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11895#else
11896 f_strpart(argvars, rettv);
11897#endif
11898}
11899
11900/*
11901 * "strpart()" function
11902 */
11903 static void
11904f_strpart(typval_T *argvars, typval_T *rettv)
11905{
11906 char_u *p;
11907 int n;
11908 int len;
11909 int slen;
11910 int error = FALSE;
11911
11912 p = get_tv_string(&argvars[0]);
11913 slen = (int)STRLEN(p);
11914
11915 n = (int)get_tv_number_chk(&argvars[1], &error);
11916 if (error)
11917 len = 0;
11918 else if (argvars[2].v_type != VAR_UNKNOWN)
11919 len = (int)get_tv_number(&argvars[2]);
11920 else
11921 len = slen - n; /* default len: all bytes that are available. */
11922
11923 /*
11924 * Only return the overlap between the specified part and the actual
11925 * string.
11926 */
11927 if (n < 0)
11928 {
11929 len += n;
11930 n = 0;
11931 }
11932 else if (n > slen)
11933 n = slen;
11934 if (len < 0)
11935 len = 0;
11936 else if (n + len > slen)
11937 len = slen - n;
11938
11939 rettv->v_type = VAR_STRING;
11940 rettv->vval.v_string = vim_strnsave(p + n, len);
11941}
11942
11943/*
11944 * "strridx()" function
11945 */
11946 static void
11947f_strridx(typval_T *argvars, typval_T *rettv)
11948{
11949 char_u buf[NUMBUFLEN];
11950 char_u *needle;
11951 char_u *haystack;
11952 char_u *rest;
11953 char_u *lastmatch = NULL;
11954 int haystack_len, end_idx;
11955
11956 needle = get_tv_string_chk(&argvars[1]);
11957 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11958
11959 rettv->vval.v_number = -1;
11960 if (needle == NULL || haystack == NULL)
11961 return; /* type error; errmsg already given */
11962
11963 haystack_len = (int)STRLEN(haystack);
11964 if (argvars[2].v_type != VAR_UNKNOWN)
11965 {
11966 /* Third argument: upper limit for index */
11967 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11968 if (end_idx < 0)
11969 return; /* can never find a match */
11970 }
11971 else
11972 end_idx = haystack_len;
11973
11974 if (*needle == NUL)
11975 {
11976 /* Empty string matches past the end. */
11977 lastmatch = haystack + end_idx;
11978 }
11979 else
11980 {
11981 for (rest = haystack; *rest != '\0'; ++rest)
11982 {
11983 rest = (char_u *)strstr((char *)rest, (char *)needle);
11984 if (rest == NULL || rest > haystack + end_idx)
11985 break;
11986 lastmatch = rest;
11987 }
11988 }
11989
11990 if (lastmatch == NULL)
11991 rettv->vval.v_number = -1;
11992 else
11993 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11994}
11995
11996/*
11997 * "strtrans()" function
11998 */
11999 static void
12000f_strtrans(typval_T *argvars, typval_T *rettv)
12001{
12002 rettv->v_type = VAR_STRING;
12003 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12004}
12005
12006/*
12007 * "submatch()" function
12008 */
12009 static void
12010f_submatch(typval_T *argvars, typval_T *rettv)
12011{
12012 int error = FALSE;
12013 int no;
12014 int retList = 0;
12015
12016 no = (int)get_tv_number_chk(&argvars[0], &error);
12017 if (error)
12018 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012019 if (no < 0 || no >= NSUBEXP)
12020 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012021 EMSGN(_("E935: invalid submatch number: %d"), no);
12022 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012023 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012024 if (argvars[1].v_type != VAR_UNKNOWN)
12025 retList = (int)get_tv_number_chk(&argvars[1], &error);
12026 if (error)
12027 return;
12028
12029 if (retList == 0)
12030 {
12031 rettv->v_type = VAR_STRING;
12032 rettv->vval.v_string = reg_submatch(no);
12033 }
12034 else
12035 {
12036 rettv->v_type = VAR_LIST;
12037 rettv->vval.v_list = reg_submatch_list(no);
12038 }
12039}
12040
12041/*
12042 * "substitute()" function
12043 */
12044 static void
12045f_substitute(typval_T *argvars, typval_T *rettv)
12046{
12047 char_u patbuf[NUMBUFLEN];
12048 char_u subbuf[NUMBUFLEN];
12049 char_u flagsbuf[NUMBUFLEN];
12050
12051 char_u *str = get_tv_string_chk(&argvars[0]);
12052 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012053 char_u *sub = NULL;
12054 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012055 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12056
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012057 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12058 expr = &argvars[2];
12059 else
12060 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012062 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012063 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12064 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012065 rettv->vval.v_string = NULL;
12066 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012067 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012068}
12069
12070/*
12071 * "synID(lnum, col, trans)" function
12072 */
12073 static void
12074f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12075{
12076 int id = 0;
12077#ifdef FEAT_SYN_HL
12078 linenr_T lnum;
12079 colnr_T col;
12080 int trans;
12081 int transerr = FALSE;
12082
12083 lnum = get_tv_lnum(argvars); /* -1 on type error */
12084 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12085 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12086
12087 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12088 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12089 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12090#endif
12091
12092 rettv->vval.v_number = id;
12093}
12094
12095/*
12096 * "synIDattr(id, what [, mode])" function
12097 */
12098 static void
12099f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12100{
12101 char_u *p = NULL;
12102#ifdef FEAT_SYN_HL
12103 int id;
12104 char_u *what;
12105 char_u *mode;
12106 char_u modebuf[NUMBUFLEN];
12107 int modec;
12108
12109 id = (int)get_tv_number(&argvars[0]);
12110 what = get_tv_string(&argvars[1]);
12111 if (argvars[2].v_type != VAR_UNKNOWN)
12112 {
12113 mode = get_tv_string_buf(&argvars[2], modebuf);
12114 modec = TOLOWER_ASC(mode[0]);
12115 if (modec != 't' && modec != 'c' && modec != 'g')
12116 modec = 0; /* replace invalid with current */
12117 }
12118 else
12119 {
12120#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12121 if (USE_24BIT)
12122 modec = 'g';
12123 else
12124#endif
12125 if (t_colors > 1)
12126 modec = 'c';
12127 else
12128 modec = 't';
12129 }
12130
12131
12132 switch (TOLOWER_ASC(what[0]))
12133 {
12134 case 'b':
12135 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12136 p = highlight_color(id, what, modec);
12137 else /* bold */
12138 p = highlight_has_attr(id, HL_BOLD, modec);
12139 break;
12140
12141 case 'f': /* fg[#] or font */
12142 p = highlight_color(id, what, modec);
12143 break;
12144
12145 case 'i':
12146 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12147 p = highlight_has_attr(id, HL_INVERSE, modec);
12148 else /* italic */
12149 p = highlight_has_attr(id, HL_ITALIC, modec);
12150 break;
12151
12152 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012153 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012154 break;
12155
12156 case 'r': /* reverse */
12157 p = highlight_has_attr(id, HL_INVERSE, modec);
12158 break;
12159
12160 case 's':
12161 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12162 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012163 /* strikeout */
12164 else if (TOLOWER_ASC(what[1]) == 't' &&
12165 TOLOWER_ASC(what[2]) == 'r')
12166 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012167 else /* standout */
12168 p = highlight_has_attr(id, HL_STANDOUT, modec);
12169 break;
12170
12171 case 'u':
12172 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12173 /* underline */
12174 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12175 else
12176 /* undercurl */
12177 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12178 break;
12179 }
12180
12181 if (p != NULL)
12182 p = vim_strsave(p);
12183#endif
12184 rettv->v_type = VAR_STRING;
12185 rettv->vval.v_string = p;
12186}
12187
12188/*
12189 * "synIDtrans(id)" function
12190 */
12191 static void
12192f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12193{
12194 int id;
12195
12196#ifdef FEAT_SYN_HL
12197 id = (int)get_tv_number(&argvars[0]);
12198
12199 if (id > 0)
12200 id = syn_get_final_id(id);
12201 else
12202#endif
12203 id = 0;
12204
12205 rettv->vval.v_number = id;
12206}
12207
12208/*
12209 * "synconcealed(lnum, col)" function
12210 */
12211 static void
12212f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12213{
12214#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12215 linenr_T lnum;
12216 colnr_T col;
12217 int syntax_flags = 0;
12218 int cchar;
12219 int matchid = 0;
12220 char_u str[NUMBUFLEN];
12221#endif
12222
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012223 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012224
12225#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12226 lnum = get_tv_lnum(argvars); /* -1 on type error */
12227 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12228
12229 vim_memset(str, NUL, sizeof(str));
12230
12231 if (rettv_list_alloc(rettv) != FAIL)
12232 {
12233 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12234 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12235 && curwin->w_p_cole > 0)
12236 {
12237 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12238 syntax_flags = get_syntax_info(&matchid);
12239
12240 /* get the conceal character */
12241 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12242 {
12243 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012244 if (cchar == NUL && curwin->w_p_cole == 1)
12245 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012246 if (cchar != NUL)
12247 {
12248# ifdef FEAT_MBYTE
12249 if (has_mbyte)
12250 (*mb_char2bytes)(cchar, str);
12251 else
12252# endif
12253 str[0] = cchar;
12254 }
12255 }
12256 }
12257
12258 list_append_number(rettv->vval.v_list,
12259 (syntax_flags & HL_CONCEAL) != 0);
12260 /* -1 to auto-determine strlen */
12261 list_append_string(rettv->vval.v_list, str, -1);
12262 list_append_number(rettv->vval.v_list, matchid);
12263 }
12264#endif
12265}
12266
12267/*
12268 * "synstack(lnum, col)" function
12269 */
12270 static void
12271f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12272{
12273#ifdef FEAT_SYN_HL
12274 linenr_T lnum;
12275 colnr_T col;
12276 int i;
12277 int id;
12278#endif
12279
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012280 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012281
12282#ifdef FEAT_SYN_HL
12283 lnum = get_tv_lnum(argvars); /* -1 on type error */
12284 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12285
12286 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12287 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12288 && rettv_list_alloc(rettv) != FAIL)
12289 {
12290 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12291 for (i = 0; ; ++i)
12292 {
12293 id = syn_get_stack_item(i);
12294 if (id < 0)
12295 break;
12296 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12297 break;
12298 }
12299 }
12300#endif
12301}
12302
12303 static void
12304get_cmd_output_as_rettv(
12305 typval_T *argvars,
12306 typval_T *rettv,
12307 int retlist)
12308{
12309 char_u *res = NULL;
12310 char_u *p;
12311 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012312 int err = FALSE;
12313 FILE *fd;
12314 list_T *list = NULL;
12315 int flags = SHELL_SILENT;
12316
12317 rettv->v_type = VAR_STRING;
12318 rettv->vval.v_string = NULL;
12319 if (check_restricted() || check_secure())
12320 goto errret;
12321
12322 if (argvars[1].v_type != VAR_UNKNOWN)
12323 {
12324 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012325 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012326 * command.
12327 */
12328 if ((infile = vim_tempname('i', TRUE)) == NULL)
12329 {
12330 EMSG(_(e_notmp));
12331 goto errret;
12332 }
12333
12334 fd = mch_fopen((char *)infile, WRITEBIN);
12335 if (fd == NULL)
12336 {
12337 EMSG2(_(e_notopen), infile);
12338 goto errret;
12339 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012340 if (argvars[1].v_type == VAR_NUMBER)
12341 {
12342 linenr_T lnum;
12343 buf_T *buf;
12344
12345 buf = buflist_findnr(argvars[1].vval.v_number);
12346 if (buf == NULL)
12347 {
12348 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012349 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012350 goto errret;
12351 }
12352
12353 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12354 {
12355 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12356 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12357 {
12358 err = TRUE;
12359 break;
12360 }
12361 if (putc(NL, fd) == EOF)
12362 {
12363 err = TRUE;
12364 break;
12365 }
12366 }
12367 }
12368 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012369 {
12370 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12371 err = TRUE;
12372 }
12373 else
12374 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012375 size_t len;
12376 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012377
12378 p = get_tv_string_buf_chk(&argvars[1], buf);
12379 if (p == NULL)
12380 {
12381 fclose(fd);
12382 goto errret; /* type error; errmsg already given */
12383 }
12384 len = STRLEN(p);
12385 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12386 err = TRUE;
12387 }
12388 if (fclose(fd) != 0)
12389 err = TRUE;
12390 if (err)
12391 {
12392 EMSG(_("E677: Error writing temp file"));
12393 goto errret;
12394 }
12395 }
12396
12397 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12398 * echoes typeahead, that messes up the display. */
12399 if (!msg_silent)
12400 flags += SHELL_COOKED;
12401
12402 if (retlist)
12403 {
12404 int len;
12405 listitem_T *li;
12406 char_u *s = NULL;
12407 char_u *start;
12408 char_u *end;
12409 int i;
12410
12411 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12412 if (res == NULL)
12413 goto errret;
12414
12415 list = list_alloc();
12416 if (list == NULL)
12417 goto errret;
12418
12419 for (i = 0; i < len; ++i)
12420 {
12421 start = res + i;
12422 while (i < len && res[i] != NL)
12423 ++i;
12424 end = res + i;
12425
12426 s = alloc((unsigned)(end - start + 1));
12427 if (s == NULL)
12428 goto errret;
12429
12430 for (p = s; start < end; ++p, ++start)
12431 *p = *start == NUL ? NL : *start;
12432 *p = NUL;
12433
12434 li = listitem_alloc();
12435 if (li == NULL)
12436 {
12437 vim_free(s);
12438 goto errret;
12439 }
12440 li->li_tv.v_type = VAR_STRING;
12441 li->li_tv.v_lock = 0;
12442 li->li_tv.vval.v_string = s;
12443 list_append(list, li);
12444 }
12445
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012446 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012447 list = NULL;
12448 }
12449 else
12450 {
12451 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12452#ifdef USE_CR
12453 /* translate <CR> into <NL> */
12454 if (res != NULL)
12455 {
12456 char_u *s;
12457
12458 for (s = res; *s; ++s)
12459 {
12460 if (*s == CAR)
12461 *s = NL;
12462 }
12463 }
12464#else
12465# ifdef USE_CRNL
12466 /* translate <CR><NL> into <NL> */
12467 if (res != NULL)
12468 {
12469 char_u *s, *d;
12470
12471 d = res;
12472 for (s = res; *s; ++s)
12473 {
12474 if (s[0] == CAR && s[1] == NL)
12475 ++s;
12476 *d++ = *s;
12477 }
12478 *d = NUL;
12479 }
12480# endif
12481#endif
12482 rettv->vval.v_string = res;
12483 res = NULL;
12484 }
12485
12486errret:
12487 if (infile != NULL)
12488 {
12489 mch_remove(infile);
12490 vim_free(infile);
12491 }
12492 if (res != NULL)
12493 vim_free(res);
12494 if (list != NULL)
12495 list_free(list);
12496}
12497
12498/*
12499 * "system()" function
12500 */
12501 static void
12502f_system(typval_T *argvars, typval_T *rettv)
12503{
12504 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12505}
12506
12507/*
12508 * "systemlist()" function
12509 */
12510 static void
12511f_systemlist(typval_T *argvars, typval_T *rettv)
12512{
12513 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12514}
12515
12516/*
12517 * "tabpagebuflist()" function
12518 */
12519 static void
12520f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12521{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012522 tabpage_T *tp;
12523 win_T *wp = NULL;
12524
12525 if (argvars[0].v_type == VAR_UNKNOWN)
12526 wp = firstwin;
12527 else
12528 {
12529 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12530 if (tp != NULL)
12531 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12532 }
12533 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12534 {
12535 for (; wp != NULL; wp = wp->w_next)
12536 if (list_append_number(rettv->vval.v_list,
12537 wp->w_buffer->b_fnum) == FAIL)
12538 break;
12539 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012540}
12541
12542
12543/*
12544 * "tabpagenr()" function
12545 */
12546 static void
12547f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12548{
12549 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012550 char_u *arg;
12551
12552 if (argvars[0].v_type != VAR_UNKNOWN)
12553 {
12554 arg = get_tv_string_chk(&argvars[0]);
12555 nr = 0;
12556 if (arg != NULL)
12557 {
12558 if (STRCMP(arg, "$") == 0)
12559 nr = tabpage_index(NULL) - 1;
12560 else
12561 EMSG2(_(e_invexpr2), arg);
12562 }
12563 }
12564 else
12565 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012566 rettv->vval.v_number = nr;
12567}
12568
12569
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012570static int get_winnr(tabpage_T *tp, typval_T *argvar);
12571
12572/*
12573 * Common code for tabpagewinnr() and winnr().
12574 */
12575 static int
12576get_winnr(tabpage_T *tp, typval_T *argvar)
12577{
12578 win_T *twin;
12579 int nr = 1;
12580 win_T *wp;
12581 char_u *arg;
12582
12583 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12584 if (argvar->v_type != VAR_UNKNOWN)
12585 {
12586 arg = get_tv_string_chk(argvar);
12587 if (arg == NULL)
12588 nr = 0; /* type error; errmsg already given */
12589 else if (STRCMP(arg, "$") == 0)
12590 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12591 else if (STRCMP(arg, "#") == 0)
12592 {
12593 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12594 if (twin == NULL)
12595 nr = 0;
12596 }
12597 else
12598 {
12599 EMSG2(_(e_invexpr2), arg);
12600 nr = 0;
12601 }
12602 }
12603
12604 if (nr > 0)
12605 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12606 wp != twin; wp = wp->w_next)
12607 {
12608 if (wp == NULL)
12609 {
12610 /* didn't find it in this tabpage */
12611 nr = 0;
12612 break;
12613 }
12614 ++nr;
12615 }
12616 return nr;
12617}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012618
12619/*
12620 * "tabpagewinnr()" function
12621 */
12622 static void
12623f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12624{
12625 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012626 tabpage_T *tp;
12627
12628 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12629 if (tp == NULL)
12630 nr = 0;
12631 else
12632 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012633 rettv->vval.v_number = nr;
12634}
12635
12636
12637/*
12638 * "tagfiles()" function
12639 */
12640 static void
12641f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12642{
12643 char_u *fname;
12644 tagname_T tn;
12645 int first;
12646
12647 if (rettv_list_alloc(rettv) == FAIL)
12648 return;
12649 fname = alloc(MAXPATHL);
12650 if (fname == NULL)
12651 return;
12652
12653 for (first = TRUE; ; first = FALSE)
12654 if (get_tagfname(&tn, first, fname) == FAIL
12655 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12656 break;
12657 tagname_free(&tn);
12658 vim_free(fname);
12659}
12660
12661/*
12662 * "taglist()" function
12663 */
12664 static void
12665f_taglist(typval_T *argvars, typval_T *rettv)
12666{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012667 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012668 char_u *tag_pattern;
12669
12670 tag_pattern = get_tv_string(&argvars[0]);
12671
12672 rettv->vval.v_number = FALSE;
12673 if (*tag_pattern == NUL)
12674 return;
12675
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012676 if (argvars[1].v_type != VAR_UNKNOWN)
12677 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012678 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012679 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012680}
12681
12682/*
12683 * "tempname()" function
12684 */
12685 static void
12686f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12687{
12688 static int x = 'A';
12689
12690 rettv->v_type = VAR_STRING;
12691 rettv->vval.v_string = vim_tempname(x, FALSE);
12692
12693 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12694 * names. Skip 'I' and 'O', they are used for shell redirection. */
12695 do
12696 {
12697 if (x == 'Z')
12698 x = '0';
12699 else if (x == '9')
12700 x = 'A';
12701 else
12702 {
12703#ifdef EBCDIC
12704 if (x == 'I')
12705 x = 'J';
12706 else if (x == 'R')
12707 x = 'S';
12708 else
12709#endif
12710 ++x;
12711 }
12712 } while (x == 'I' || x == 'O');
12713}
12714
12715#ifdef FEAT_FLOAT
12716/*
12717 * "tan()" function
12718 */
12719 static void
12720f_tan(typval_T *argvars, typval_T *rettv)
12721{
12722 float_T f = 0.0;
12723
12724 rettv->v_type = VAR_FLOAT;
12725 if (get_float_arg(argvars, &f) == OK)
12726 rettv->vval.v_float = tan(f);
12727 else
12728 rettv->vval.v_float = 0.0;
12729}
12730
12731/*
12732 * "tanh()" function
12733 */
12734 static void
12735f_tanh(typval_T *argvars, typval_T *rettv)
12736{
12737 float_T f = 0.0;
12738
12739 rettv->v_type = VAR_FLOAT;
12740 if (get_float_arg(argvars, &f) == OK)
12741 rettv->vval.v_float = tanh(f);
12742 else
12743 rettv->vval.v_float = 0.0;
12744}
12745#endif
12746
12747/*
12748 * "test_alloc_fail(id, countdown, repeat)" function
12749 */
12750 static void
12751f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12752{
12753 if (argvars[0].v_type != VAR_NUMBER
12754 || argvars[0].vval.v_number <= 0
12755 || argvars[1].v_type != VAR_NUMBER
12756 || argvars[1].vval.v_number < 0
12757 || argvars[2].v_type != VAR_NUMBER)
12758 EMSG(_(e_invarg));
12759 else
12760 {
12761 alloc_fail_id = argvars[0].vval.v_number;
12762 if (alloc_fail_id >= aid_last)
12763 EMSG(_(e_invarg));
12764 alloc_fail_countdown = argvars[1].vval.v_number;
12765 alloc_fail_repeat = argvars[2].vval.v_number;
12766 did_outofmem_msg = FALSE;
12767 }
12768}
12769
12770/*
12771 * "test_autochdir()"
12772 */
12773 static void
12774f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12775{
12776#if defined(FEAT_AUTOCHDIR)
12777 test_autochdir = TRUE;
12778#endif
12779}
12780
12781/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012782 * "test_feedinput()"
12783 */
12784 static void
12785f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12786{
12787#ifdef USE_INPUT_BUF
12788 char_u *val = get_tv_string_chk(&argvars[0]);
12789
12790 if (val != NULL)
12791 {
12792 trash_input_buf();
12793 add_to_input_buf_csi(val, (int)STRLEN(val));
12794 }
12795#endif
12796}
12797
12798/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012799 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012800 */
12801 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012802f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012803{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012804 char_u *name = (char_u *)"";
12805 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012806 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012807
12808 if (argvars[0].v_type != VAR_STRING
12809 || (argvars[1].v_type) != VAR_NUMBER)
12810 EMSG(_(e_invarg));
12811 else
12812 {
12813 name = get_tv_string_chk(&argvars[0]);
12814 val = (int)get_tv_number(&argvars[1]);
12815
12816 if (STRCMP(name, (char_u *)"redraw") == 0)
12817 disable_redraw_for_testing = val;
12818 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12819 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012820 else if (STRCMP(name, (char_u *)"starting") == 0)
12821 {
12822 if (val)
12823 {
12824 if (save_starting < 0)
12825 save_starting = starting;
12826 starting = 0;
12827 }
12828 else
12829 {
12830 starting = save_starting;
12831 save_starting = -1;
12832 }
12833 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012834 else if (STRCMP(name, (char_u *)"ALL") == 0)
12835 {
12836 disable_char_avail_for_testing = FALSE;
12837 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012838 if (save_starting >= 0)
12839 {
12840 starting = save_starting;
12841 save_starting = -1;
12842 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012843 }
12844 else
12845 EMSG2(_(e_invarg2), name);
12846 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012847}
12848
12849/*
12850 * "test_garbagecollect_now()" function
12851 */
12852 static void
12853f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12854{
12855 /* This is dangerous, any Lists and Dicts used internally may be freed
12856 * while still in use. */
12857 garbage_collect(TRUE);
12858}
12859
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012860/*
12861 * "test_ignore_error()" function
12862 */
12863 static void
12864f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12865{
12866 ignore_error_for_testing(get_tv_string(&argvars[0]));
12867}
12868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012869#ifdef FEAT_JOB_CHANNEL
12870 static void
12871f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12872{
12873 rettv->v_type = VAR_CHANNEL;
12874 rettv->vval.v_channel = NULL;
12875}
12876#endif
12877
12878 static void
12879f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12880{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012881 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012882}
12883
12884#ifdef FEAT_JOB_CHANNEL
12885 static void
12886f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12887{
12888 rettv->v_type = VAR_JOB;
12889 rettv->vval.v_job = NULL;
12890}
12891#endif
12892
12893 static void
12894f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12895{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012896 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012897}
12898
12899 static void
12900f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12901{
12902 rettv->v_type = VAR_PARTIAL;
12903 rettv->vval.v_partial = NULL;
12904}
12905
12906 static void
12907f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12908{
12909 rettv->v_type = VAR_STRING;
12910 rettv->vval.v_string = NULL;
12911}
12912
12913 static void
12914f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12915{
12916 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12917}
12918
12919#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12920/*
12921 * Get a callback from "arg". It can be a Funcref or a function name.
12922 * When "arg" is zero return an empty string.
12923 * Return NULL for an invalid argument.
12924 */
12925 char_u *
12926get_callback(typval_T *arg, partial_T **pp)
12927{
12928 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12929 {
12930 *pp = arg->vval.v_partial;
12931 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012932 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012933 }
12934 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012935 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012936 {
12937 func_ref(arg->vval.v_string);
12938 return arg->vval.v_string;
12939 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012940 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12941 return (char_u *)"";
12942 EMSG(_("E921: Invalid callback argument"));
12943 return NULL;
12944}
12945
12946/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020012947 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012948 */
12949 void
12950free_callback(char_u *callback, partial_T *partial)
12951{
12952 if (partial != NULL)
12953 partial_unref(partial);
12954 else if (callback != NULL)
12955 {
12956 func_unref(callback);
12957 vim_free(callback);
12958 }
12959}
12960#endif
12961
12962#ifdef FEAT_TIMERS
12963/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012964 * "timer_info([timer])" function
12965 */
12966 static void
12967f_timer_info(typval_T *argvars, typval_T *rettv)
12968{
12969 timer_T *timer = NULL;
12970
12971 if (rettv_list_alloc(rettv) != OK)
12972 return;
12973 if (argvars[0].v_type != VAR_UNKNOWN)
12974 {
12975 if (argvars[0].v_type != VAR_NUMBER)
12976 EMSG(_(e_number_exp));
12977 else
12978 {
12979 timer = find_timer((int)get_tv_number(&argvars[0]));
12980 if (timer != NULL)
12981 add_timer_info(rettv, timer);
12982 }
12983 }
12984 else
12985 add_timer_info_all(rettv);
12986}
12987
12988/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012989 * "timer_pause(timer, paused)" function
12990 */
12991 static void
12992f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12993{
12994 timer_T *timer = NULL;
12995 int paused = (int)get_tv_number(&argvars[1]);
12996
12997 if (argvars[0].v_type != VAR_NUMBER)
12998 EMSG(_(e_number_exp));
12999 else
13000 {
13001 timer = find_timer((int)get_tv_number(&argvars[0]));
13002 if (timer != NULL)
13003 timer->tr_paused = paused;
13004 }
13005}
13006
13007/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013008 * "timer_start(time, callback [, options])" function
13009 */
13010 static void
13011f_timer_start(typval_T *argvars, typval_T *rettv)
13012{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013013 long msec = (long)get_tv_number(&argvars[0]);
13014 timer_T *timer;
13015 int repeat = 0;
13016 char_u *callback;
13017 dict_T *dict;
13018 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013019
Bram Moolenaar75537a92016-09-05 22:45:28 +020013020 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013021 if (check_secure())
13022 return;
13023 if (argvars[2].v_type != VAR_UNKNOWN)
13024 {
13025 if (argvars[2].v_type != VAR_DICT
13026 || (dict = argvars[2].vval.v_dict) == NULL)
13027 {
13028 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13029 return;
13030 }
13031 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13032 repeat = get_dict_number(dict, (char_u *)"repeat");
13033 }
13034
Bram Moolenaar75537a92016-09-05 22:45:28 +020013035 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013036 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013037 return;
13038
13039 timer = create_timer(msec, repeat);
13040 if (timer == NULL)
13041 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013042 else
13043 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013044 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013045 timer->tr_callback = vim_strsave(callback);
13046 else
13047 /* pointer into the partial */
13048 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013049 timer->tr_partial = partial;
13050 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013051 }
13052}
13053
13054/*
13055 * "timer_stop(timer)" function
13056 */
13057 static void
13058f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13059{
13060 timer_T *timer;
13061
13062 if (argvars[0].v_type != VAR_NUMBER)
13063 {
13064 EMSG(_(e_number_exp));
13065 return;
13066 }
13067 timer = find_timer((int)get_tv_number(&argvars[0]));
13068 if (timer != NULL)
13069 stop_timer(timer);
13070}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013071
13072/*
13073 * "timer_stopall()" function
13074 */
13075 static void
13076f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13077{
13078 stop_all_timers();
13079}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013080#endif
13081
13082/*
13083 * "tolower(string)" function
13084 */
13085 static void
13086f_tolower(typval_T *argvars, typval_T *rettv)
13087{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013088 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013089 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013090}
13091
13092/*
13093 * "toupper(string)" function
13094 */
13095 static void
13096f_toupper(typval_T *argvars, typval_T *rettv)
13097{
13098 rettv->v_type = VAR_STRING;
13099 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13100}
13101
13102/*
13103 * "tr(string, fromstr, tostr)" function
13104 */
13105 static void
13106f_tr(typval_T *argvars, typval_T *rettv)
13107{
13108 char_u *in_str;
13109 char_u *fromstr;
13110 char_u *tostr;
13111 char_u *p;
13112#ifdef FEAT_MBYTE
13113 int inlen;
13114 int fromlen;
13115 int tolen;
13116 int idx;
13117 char_u *cpstr;
13118 int cplen;
13119 int first = TRUE;
13120#endif
13121 char_u buf[NUMBUFLEN];
13122 char_u buf2[NUMBUFLEN];
13123 garray_T ga;
13124
13125 in_str = get_tv_string(&argvars[0]);
13126 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13127 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13128
13129 /* Default return value: empty string. */
13130 rettv->v_type = VAR_STRING;
13131 rettv->vval.v_string = NULL;
13132 if (fromstr == NULL || tostr == NULL)
13133 return; /* type error; errmsg already given */
13134 ga_init2(&ga, (int)sizeof(char), 80);
13135
13136#ifdef FEAT_MBYTE
13137 if (!has_mbyte)
13138#endif
13139 /* not multi-byte: fromstr and tostr must be the same length */
13140 if (STRLEN(fromstr) != STRLEN(tostr))
13141 {
13142#ifdef FEAT_MBYTE
13143error:
13144#endif
13145 EMSG2(_(e_invarg2), fromstr);
13146 ga_clear(&ga);
13147 return;
13148 }
13149
13150 /* fromstr and tostr have to contain the same number of chars */
13151 while (*in_str != NUL)
13152 {
13153#ifdef FEAT_MBYTE
13154 if (has_mbyte)
13155 {
13156 inlen = (*mb_ptr2len)(in_str);
13157 cpstr = in_str;
13158 cplen = inlen;
13159 idx = 0;
13160 for (p = fromstr; *p != NUL; p += fromlen)
13161 {
13162 fromlen = (*mb_ptr2len)(p);
13163 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13164 {
13165 for (p = tostr; *p != NUL; p += tolen)
13166 {
13167 tolen = (*mb_ptr2len)(p);
13168 if (idx-- == 0)
13169 {
13170 cplen = tolen;
13171 cpstr = p;
13172 break;
13173 }
13174 }
13175 if (*p == NUL) /* tostr is shorter than fromstr */
13176 goto error;
13177 break;
13178 }
13179 ++idx;
13180 }
13181
13182 if (first && cpstr == in_str)
13183 {
13184 /* Check that fromstr and tostr have the same number of
13185 * (multi-byte) characters. Done only once when a character
13186 * of in_str doesn't appear in fromstr. */
13187 first = FALSE;
13188 for (p = tostr; *p != NUL; p += tolen)
13189 {
13190 tolen = (*mb_ptr2len)(p);
13191 --idx;
13192 }
13193 if (idx != 0)
13194 goto error;
13195 }
13196
13197 (void)ga_grow(&ga, cplen);
13198 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13199 ga.ga_len += cplen;
13200
13201 in_str += inlen;
13202 }
13203 else
13204#endif
13205 {
13206 /* When not using multi-byte chars we can do it faster. */
13207 p = vim_strchr(fromstr, *in_str);
13208 if (p != NULL)
13209 ga_append(&ga, tostr[p - fromstr]);
13210 else
13211 ga_append(&ga, *in_str);
13212 ++in_str;
13213 }
13214 }
13215
13216 /* add a terminating NUL */
13217 (void)ga_grow(&ga, 1);
13218 ga_append(&ga, NUL);
13219
13220 rettv->vval.v_string = ga.ga_data;
13221}
13222
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013223/*
13224 * "trim({expr})" function
13225 */
13226 static void
13227f_trim(typval_T *argvars, typval_T *rettv)
13228{
13229 char_u buf1[NUMBUFLEN];
13230 char_u buf2[NUMBUFLEN];
13231 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13232 char_u *mask = NULL;
13233 char_u *tail;
13234 char_u *prev;
13235 char_u *p;
13236 int c1;
13237
13238 rettv->v_type = VAR_STRING;
13239 if (head == NULL)
13240 {
13241 rettv->vval.v_string = NULL;
13242 return;
13243 }
13244
13245 if (argvars[1].v_type == VAR_STRING)
13246 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13247
13248 while (*head != NUL)
13249 {
13250 c1 = PTR2CHAR(head);
13251 if (mask == NULL)
13252 {
13253 if (c1 > ' ' && c1 != 0xa0)
13254 break;
13255 }
13256 else
13257 {
13258 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13259 if (c1 == PTR2CHAR(p))
13260 break;
13261 if (*p == NUL)
13262 break;
13263 }
13264 MB_PTR_ADV(head);
13265 }
13266
13267 for (tail = head + STRLEN(head); tail > head; tail = prev)
13268 {
13269 prev = tail;
13270 MB_PTR_BACK(head, prev);
13271 c1 = PTR2CHAR(prev);
13272 if (mask == NULL)
13273 {
13274 if (c1 > ' ' && c1 != 0xa0)
13275 break;
13276 }
13277 else
13278 {
13279 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13280 if (c1 == PTR2CHAR(p))
13281 break;
13282 if (*p == NUL)
13283 break;
13284 }
13285 }
13286 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13287}
13288
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013289#ifdef FEAT_FLOAT
13290/*
13291 * "trunc({float})" function
13292 */
13293 static void
13294f_trunc(typval_T *argvars, typval_T *rettv)
13295{
13296 float_T f = 0.0;
13297
13298 rettv->v_type = VAR_FLOAT;
13299 if (get_float_arg(argvars, &f) == OK)
13300 /* trunc() is not in C90, use floor() or ceil() instead. */
13301 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13302 else
13303 rettv->vval.v_float = 0.0;
13304}
13305#endif
13306
13307/*
13308 * "type(expr)" function
13309 */
13310 static void
13311f_type(typval_T *argvars, typval_T *rettv)
13312{
13313 int n = -1;
13314
13315 switch (argvars[0].v_type)
13316 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013317 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13318 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013319 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013320 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13321 case VAR_LIST: n = VAR_TYPE_LIST; break;
13322 case VAR_DICT: n = VAR_TYPE_DICT; break;
13323 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013324 case VAR_SPECIAL:
13325 if (argvars[0].vval.v_number == VVAL_FALSE
13326 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013327 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013328 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013329 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013330 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013331 case VAR_JOB: n = VAR_TYPE_JOB; break;
13332 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013333 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013334 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013335 n = -1;
13336 break;
13337 }
13338 rettv->vval.v_number = n;
13339}
13340
13341/*
13342 * "undofile(name)" function
13343 */
13344 static void
13345f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13346{
13347 rettv->v_type = VAR_STRING;
13348#ifdef FEAT_PERSISTENT_UNDO
13349 {
13350 char_u *fname = get_tv_string(&argvars[0]);
13351
13352 if (*fname == NUL)
13353 {
13354 /* If there is no file name there will be no undo file. */
13355 rettv->vval.v_string = NULL;
13356 }
13357 else
13358 {
13359 char_u *ffname = FullName_save(fname, FALSE);
13360
13361 if (ffname != NULL)
13362 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13363 vim_free(ffname);
13364 }
13365 }
13366#else
13367 rettv->vval.v_string = NULL;
13368#endif
13369}
13370
13371/*
13372 * "undotree()" function
13373 */
13374 static void
13375f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13376{
13377 if (rettv_dict_alloc(rettv) == OK)
13378 {
13379 dict_T *dict = rettv->vval.v_dict;
13380 list_T *list;
13381
13382 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13383 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13384 dict_add_nr_str(dict, "save_last",
13385 (long)curbuf->b_u_save_nr_last, NULL);
13386 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13387 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13388 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13389
13390 list = list_alloc();
13391 if (list != NULL)
13392 {
13393 u_eval_tree(curbuf->b_u_oldhead, list);
13394 dict_add_list(dict, "entries", list);
13395 }
13396 }
13397}
13398
13399/*
13400 * "values(dict)" function
13401 */
13402 static void
13403f_values(typval_T *argvars, typval_T *rettv)
13404{
13405 dict_list(argvars, rettv, 1);
13406}
13407
13408/*
13409 * "virtcol(string)" function
13410 */
13411 static void
13412f_virtcol(typval_T *argvars, typval_T *rettv)
13413{
13414 colnr_T vcol = 0;
13415 pos_T *fp;
13416 int fnum = curbuf->b_fnum;
13417
13418 fp = var2fpos(&argvars[0], FALSE, &fnum);
13419 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13420 && fnum == curbuf->b_fnum)
13421 {
13422 getvvcol(curwin, fp, NULL, NULL, &vcol);
13423 ++vcol;
13424 }
13425
13426 rettv->vval.v_number = vcol;
13427}
13428
13429/*
13430 * "visualmode()" function
13431 */
13432 static void
13433f_visualmode(typval_T *argvars, typval_T *rettv)
13434{
13435 char_u str[2];
13436
13437 rettv->v_type = VAR_STRING;
13438 str[0] = curbuf->b_visual_mode_eval;
13439 str[1] = NUL;
13440 rettv->vval.v_string = vim_strsave(str);
13441
13442 /* A non-zero number or non-empty string argument: reset mode. */
13443 if (non_zero_arg(&argvars[0]))
13444 curbuf->b_visual_mode_eval = NUL;
13445}
13446
13447/*
13448 * "wildmenumode()" function
13449 */
13450 static void
13451f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13452{
13453#ifdef FEAT_WILDMENU
13454 if (wild_menu_showing)
13455 rettv->vval.v_number = 1;
13456#endif
13457}
13458
13459/*
13460 * "winbufnr(nr)" function
13461 */
13462 static void
13463f_winbufnr(typval_T *argvars, typval_T *rettv)
13464{
13465 win_T *wp;
13466
13467 wp = find_win_by_nr(&argvars[0], NULL);
13468 if (wp == NULL)
13469 rettv->vval.v_number = -1;
13470 else
13471 rettv->vval.v_number = wp->w_buffer->b_fnum;
13472}
13473
13474/*
13475 * "wincol()" function
13476 */
13477 static void
13478f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13479{
13480 validate_cursor();
13481 rettv->vval.v_number = curwin->w_wcol + 1;
13482}
13483
13484/*
13485 * "winheight(nr)" function
13486 */
13487 static void
13488f_winheight(typval_T *argvars, typval_T *rettv)
13489{
13490 win_T *wp;
13491
13492 wp = find_win_by_nr(&argvars[0], NULL);
13493 if (wp == NULL)
13494 rettv->vval.v_number = -1;
13495 else
13496 rettv->vval.v_number = wp->w_height;
13497}
13498
13499/*
13500 * "winline()" function
13501 */
13502 static void
13503f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13504{
13505 validate_cursor();
13506 rettv->vval.v_number = curwin->w_wrow + 1;
13507}
13508
13509/*
13510 * "winnr()" function
13511 */
13512 static void
13513f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13514{
13515 int nr = 1;
13516
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013517 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013518 rettv->vval.v_number = nr;
13519}
13520
13521/*
13522 * "winrestcmd()" function
13523 */
13524 static void
13525f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13526{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013527 win_T *wp;
13528 int winnr = 1;
13529 garray_T ga;
13530 char_u buf[50];
13531
13532 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013533 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013534 {
13535 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13536 ga_concat(&ga, buf);
13537 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13538 ga_concat(&ga, buf);
13539 ++winnr;
13540 }
13541 ga_append(&ga, NUL);
13542
13543 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013544 rettv->v_type = VAR_STRING;
13545}
13546
13547/*
13548 * "winrestview()" function
13549 */
13550 static void
13551f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13552{
13553 dict_T *dict;
13554
13555 if (argvars[0].v_type != VAR_DICT
13556 || (dict = argvars[0].vval.v_dict) == NULL)
13557 EMSG(_(e_invarg));
13558 else
13559 {
13560 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13561 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13562 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13563 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13564#ifdef FEAT_VIRTUALEDIT
13565 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13566 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13567#endif
13568 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13569 {
13570 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13571 curwin->w_set_curswant = FALSE;
13572 }
13573
13574 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13575 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13576#ifdef FEAT_DIFF
13577 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13578 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13579#endif
13580 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13581 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13582 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13583 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13584
13585 check_cursor();
13586 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013587 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013588 changed_window_setting();
13589
13590 if (curwin->w_topline <= 0)
13591 curwin->w_topline = 1;
13592 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13593 curwin->w_topline = curbuf->b_ml.ml_line_count;
13594#ifdef FEAT_DIFF
13595 check_topfill(curwin, TRUE);
13596#endif
13597 }
13598}
13599
13600/*
13601 * "winsaveview()" function
13602 */
13603 static void
13604f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13605{
13606 dict_T *dict;
13607
13608 if (rettv_dict_alloc(rettv) == FAIL)
13609 return;
13610 dict = rettv->vval.v_dict;
13611
13612 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13613 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13614#ifdef FEAT_VIRTUALEDIT
13615 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13616#endif
13617 update_curswant();
13618 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13619
13620 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13621#ifdef FEAT_DIFF
13622 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13623#endif
13624 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13625 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13626}
13627
13628/*
13629 * "winwidth(nr)" function
13630 */
13631 static void
13632f_winwidth(typval_T *argvars, typval_T *rettv)
13633{
13634 win_T *wp;
13635
13636 wp = find_win_by_nr(&argvars[0], NULL);
13637 if (wp == NULL)
13638 rettv->vval.v_number = -1;
13639 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013640 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013641}
13642
13643/*
13644 * "wordcount()" function
13645 */
13646 static void
13647f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13648{
13649 if (rettv_dict_alloc(rettv) == FAIL)
13650 return;
13651 cursor_pos_info(rettv->vval.v_dict);
13652}
13653
13654/*
13655 * "writefile()" function
13656 */
13657 static void
13658f_writefile(typval_T *argvars, typval_T *rettv)
13659{
13660 int binary = FALSE;
13661 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013662#ifdef HAVE_FSYNC
13663 int do_fsync = p_fs;
13664#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013665 char_u *fname;
13666 FILE *fd;
13667 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013668 listitem_T *li;
13669 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013670
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013671 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013672 if (check_restricted() || check_secure())
13673 return;
13674
13675 if (argvars[0].v_type != VAR_LIST)
13676 {
13677 EMSG2(_(e_listarg), "writefile()");
13678 return;
13679 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013680 list = argvars[0].vval.v_list;
13681 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013682 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013683 for (li = list->lv_first; li != NULL; li = li->li_next)
13684 if (get_tv_string_chk(&li->li_tv) == NULL)
13685 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013686
13687 if (argvars[2].v_type != VAR_UNKNOWN)
13688 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013689 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13690
13691 if (arg2 == NULL)
13692 return;
13693 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013694 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013695 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013696 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013697#ifdef HAVE_FSYNC
13698 if (vim_strchr(arg2, 's') != NULL)
13699 do_fsync = TRUE;
13700 else if (vim_strchr(arg2, 'S') != NULL)
13701 do_fsync = FALSE;
13702#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013703 }
13704
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013705 fname = get_tv_string_chk(&argvars[1]);
13706 if (fname == NULL)
13707 return;
13708
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013709 /* Always open the file in binary mode, library functions have a mind of
13710 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013711 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13712 append ? APPENDBIN : WRITEBIN)) == NULL)
13713 {
13714 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13715 ret = -1;
13716 }
13717 else
13718 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013719 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013720 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013721#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013722 else if (do_fsync)
13723 /* Ignore the error, the user wouldn't know what to do about it.
13724 * May happen for a device. */
13725 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013726#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013727 fclose(fd);
13728 }
13729
13730 rettv->vval.v_number = ret;
13731}
13732
13733/*
13734 * "xor(expr, expr)" function
13735 */
13736 static void
13737f_xor(typval_T *argvars, typval_T *rettv)
13738{
13739 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13740 ^ get_tv_number_chk(&argvars[1], NULL);
13741}
13742
13743
13744#endif /* FEAT_EVAL */