blob: b02c956132523f13244244f3283dae860ff33ef2 [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);
433#ifdef FEAT_FLOAT
434static void f_trunc(typval_T *argvars, typval_T *rettv);
435#endif
436static void f_type(typval_T *argvars, typval_T *rettv);
437static void f_undofile(typval_T *argvars, typval_T *rettv);
438static void f_undotree(typval_T *argvars, typval_T *rettv);
439static void f_uniq(typval_T *argvars, typval_T *rettv);
440static void f_values(typval_T *argvars, typval_T *rettv);
441static void f_virtcol(typval_T *argvars, typval_T *rettv);
442static void f_visualmode(typval_T *argvars, typval_T *rettv);
443static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
444static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
445static void f_win_getid(typval_T *argvars, typval_T *rettv);
446static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
447static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
448static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100449static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200450static void f_winbufnr(typval_T *argvars, typval_T *rettv);
451static void f_wincol(typval_T *argvars, typval_T *rettv);
452static void f_winheight(typval_T *argvars, typval_T *rettv);
453static void f_winline(typval_T *argvars, typval_T *rettv);
454static void f_winnr(typval_T *argvars, typval_T *rettv);
455static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
456static void f_winrestview(typval_T *argvars, typval_T *rettv);
457static void f_winsaveview(typval_T *argvars, typval_T *rettv);
458static void f_winwidth(typval_T *argvars, typval_T *rettv);
459static void f_writefile(typval_T *argvars, typval_T *rettv);
460static void f_wordcount(typval_T *argvars, typval_T *rettv);
461static void f_xor(typval_T *argvars, typval_T *rettv);
462
463/*
464 * Array with names and number of arguments of all internal functions
465 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
466 */
467static struct fst
468{
469 char *f_name; /* function name */
470 char f_min_argc; /* minimal number of arguments */
471 char f_max_argc; /* maximal number of arguments */
472 void (*f_func)(typval_T *args, typval_T *rvar);
473 /* implementation of function */
474} functions[] =
475{
476#ifdef FEAT_FLOAT
477 {"abs", 1, 1, f_abs},
478 {"acos", 1, 1, f_acos}, /* WJMc */
479#endif
480 {"add", 2, 2, f_add},
481 {"and", 2, 2, f_and},
482 {"append", 2, 2, f_append},
483 {"argc", 0, 0, f_argc},
484 {"argidx", 0, 0, f_argidx},
485 {"arglistid", 0, 2, f_arglistid},
486 {"argv", 0, 1, f_argv},
487#ifdef FEAT_FLOAT
488 {"asin", 1, 1, f_asin}, /* WJMc */
489#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100490 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200491 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100492 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200493 {"assert_exception", 1, 2, f_assert_exception},
494 {"assert_fails", 1, 2, f_assert_fails},
495 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100496 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200497 {"assert_match", 2, 3, f_assert_match},
498 {"assert_notequal", 2, 3, f_assert_notequal},
499 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100500 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200501 {"assert_true", 1, 2, f_assert_true},
502#ifdef FEAT_FLOAT
503 {"atan", 1, 1, f_atan},
504 {"atan2", 2, 2, f_atan2},
505#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100506#ifdef FEAT_BEVAL
507 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100508# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100509 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100510# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100511#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200512 {"browse", 4, 4, f_browse},
513 {"browsedir", 2, 2, f_browsedir},
514 {"bufexists", 1, 1, f_bufexists},
515 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
516 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
517 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
518 {"buflisted", 1, 1, f_buflisted},
519 {"bufloaded", 1, 1, f_bufloaded},
520 {"bufname", 1, 1, f_bufname},
521 {"bufnr", 1, 2, f_bufnr},
522 {"bufwinid", 1, 1, f_bufwinid},
523 {"bufwinnr", 1, 1, f_bufwinnr},
524 {"byte2line", 1, 1, f_byte2line},
525 {"byteidx", 2, 2, f_byteidx},
526 {"byteidxcomp", 2, 2, f_byteidxcomp},
527 {"call", 2, 3, f_call},
528#ifdef FEAT_FLOAT
529 {"ceil", 1, 1, f_ceil},
530#endif
531#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100532 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200534 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200535 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
536 {"ch_evalraw", 2, 3, f_ch_evalraw},
537 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
538 {"ch_getjob", 1, 1, f_ch_getjob},
539 {"ch_info", 1, 1, f_ch_info},
540 {"ch_log", 1, 2, f_ch_log},
541 {"ch_logfile", 1, 2, f_ch_logfile},
542 {"ch_open", 1, 2, f_ch_open},
543 {"ch_read", 1, 2, f_ch_read},
544 {"ch_readraw", 1, 2, f_ch_readraw},
545 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
546 {"ch_sendraw", 2, 3, f_ch_sendraw},
547 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200548 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200549#endif
550 {"changenr", 0, 0, f_changenr},
551 {"char2nr", 1, 2, f_char2nr},
552 {"cindent", 1, 1, f_cindent},
553 {"clearmatches", 0, 0, f_clearmatches},
554 {"col", 1, 1, f_col},
555#if defined(FEAT_INS_EXPAND)
556 {"complete", 2, 2, f_complete},
557 {"complete_add", 1, 1, f_complete_add},
558 {"complete_check", 0, 0, f_complete_check},
559#endif
560 {"confirm", 1, 4, f_confirm},
561 {"copy", 1, 1, f_copy},
562#ifdef FEAT_FLOAT
563 {"cos", 1, 1, f_cos},
564 {"cosh", 1, 1, f_cosh},
565#endif
566 {"count", 2, 4, f_count},
567 {"cscope_connection",0,3, f_cscope_connection},
568 {"cursor", 1, 3, f_cursor},
569 {"deepcopy", 1, 2, f_deepcopy},
570 {"delete", 1, 2, f_delete},
571 {"did_filetype", 0, 0, f_did_filetype},
572 {"diff_filler", 1, 1, f_diff_filler},
573 {"diff_hlID", 2, 2, f_diff_hlID},
574 {"empty", 1, 1, f_empty},
575 {"escape", 2, 2, f_escape},
576 {"eval", 1, 1, f_eval},
577 {"eventhandler", 0, 0, f_eventhandler},
578 {"executable", 1, 1, f_executable},
579 {"execute", 1, 2, f_execute},
580 {"exepath", 1, 1, f_exepath},
581 {"exists", 1, 1, f_exists},
582#ifdef FEAT_FLOAT
583 {"exp", 1, 1, f_exp},
584#endif
585 {"expand", 1, 3, f_expand},
586 {"extend", 2, 3, f_extend},
587 {"feedkeys", 1, 2, f_feedkeys},
588 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
589 {"filereadable", 1, 1, f_filereadable},
590 {"filewritable", 1, 1, f_filewritable},
591 {"filter", 2, 2, f_filter},
592 {"finddir", 1, 3, f_finddir},
593 {"findfile", 1, 3, f_findfile},
594#ifdef FEAT_FLOAT
595 {"float2nr", 1, 1, f_float2nr},
596 {"floor", 1, 1, f_floor},
597 {"fmod", 2, 2, f_fmod},
598#endif
599 {"fnameescape", 1, 1, f_fnameescape},
600 {"fnamemodify", 2, 2, f_fnamemodify},
601 {"foldclosed", 1, 1, f_foldclosed},
602 {"foldclosedend", 1, 1, f_foldclosedend},
603 {"foldlevel", 1, 1, f_foldlevel},
604 {"foldtext", 0, 0, f_foldtext},
605 {"foldtextresult", 1, 1, f_foldtextresult},
606 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200607 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200608 {"function", 1, 3, f_function},
609 {"garbagecollect", 0, 1, f_garbagecollect},
610 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200611 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200612 {"getbufline", 2, 3, f_getbufline},
613 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100614 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200615 {"getchar", 0, 1, f_getchar},
616 {"getcharmod", 0, 0, f_getcharmod},
617 {"getcharsearch", 0, 0, f_getcharsearch},
618 {"getcmdline", 0, 0, f_getcmdline},
619 {"getcmdpos", 0, 0, f_getcmdpos},
620 {"getcmdtype", 0, 0, f_getcmdtype},
621 {"getcmdwintype", 0, 0, f_getcmdwintype},
622#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200623 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200624#endif
625 {"getcurpos", 0, 0, f_getcurpos},
626 {"getcwd", 0, 2, f_getcwd},
627 {"getfontname", 0, 1, f_getfontname},
628 {"getfperm", 1, 1, f_getfperm},
629 {"getfsize", 1, 1, f_getfsize},
630 {"getftime", 1, 1, f_getftime},
631 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100632 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200634 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635 {"getmatches", 0, 0, f_getmatches},
636 {"getpid", 0, 0, f_getpid},
637 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200638 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200639 {"getreg", 0, 3, f_getreg},
640 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200641 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200642 {"gettabvar", 2, 3, f_gettabvar},
643 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200644 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100645 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200646 {"getwinposx", 0, 0, f_getwinposx},
647 {"getwinposy", 0, 0, f_getwinposy},
648 {"getwinvar", 2, 3, f_getwinvar},
649 {"glob", 1, 4, f_glob},
650 {"glob2regpat", 1, 1, f_glob2regpat},
651 {"globpath", 2, 5, f_globpath},
652 {"has", 1, 1, f_has},
653 {"has_key", 2, 2, f_has_key},
654 {"haslocaldir", 0, 2, f_haslocaldir},
655 {"hasmapto", 1, 3, f_hasmapto},
656 {"highlightID", 1, 1, f_hlID}, /* obsolete */
657 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
658 {"histadd", 2, 2, f_histadd},
659 {"histdel", 1, 2, f_histdel},
660 {"histget", 1, 2, f_histget},
661 {"histnr", 1, 1, f_histnr},
662 {"hlID", 1, 1, f_hlID},
663 {"hlexists", 1, 1, f_hlexists},
664 {"hostname", 0, 0, f_hostname},
665 {"iconv", 3, 3, f_iconv},
666 {"indent", 1, 1, f_indent},
667 {"index", 2, 4, f_index},
668 {"input", 1, 3, f_input},
669 {"inputdialog", 1, 3, f_inputdialog},
670 {"inputlist", 1, 1, f_inputlist},
671 {"inputrestore", 0, 0, f_inputrestore},
672 {"inputsave", 0, 0, f_inputsave},
673 {"inputsecret", 1, 2, f_inputsecret},
674 {"insert", 2, 3, f_insert},
675 {"invert", 1, 1, f_invert},
676 {"isdirectory", 1, 1, f_isdirectory},
677 {"islocked", 1, 1, f_islocked},
678#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
679 {"isnan", 1, 1, f_isnan},
680#endif
681 {"items", 1, 1, f_items},
682#ifdef FEAT_JOB_CHANNEL
683 {"job_getchannel", 1, 1, f_job_getchannel},
684 {"job_info", 1, 1, f_job_info},
685 {"job_setoptions", 2, 2, f_job_setoptions},
686 {"job_start", 1, 2, f_job_start},
687 {"job_status", 1, 1, f_job_status},
688 {"job_stop", 1, 2, f_job_stop},
689#endif
690 {"join", 1, 2, f_join},
691 {"js_decode", 1, 1, f_js_decode},
692 {"js_encode", 1, 1, f_js_encode},
693 {"json_decode", 1, 1, f_json_decode},
694 {"json_encode", 1, 1, f_json_encode},
695 {"keys", 1, 1, f_keys},
696 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
697 {"len", 1, 1, f_len},
698 {"libcall", 3, 3, f_libcall},
699 {"libcallnr", 3, 3, f_libcallnr},
700 {"line", 1, 1, f_line},
701 {"line2byte", 1, 1, f_line2byte},
702 {"lispindent", 1, 1, f_lispindent},
703 {"localtime", 0, 0, f_localtime},
704#ifdef FEAT_FLOAT
705 {"log", 1, 1, f_log},
706 {"log10", 1, 1, f_log10},
707#endif
708#ifdef FEAT_LUA
709 {"luaeval", 1, 2, f_luaeval},
710#endif
711 {"map", 2, 2, f_map},
712 {"maparg", 1, 4, f_maparg},
713 {"mapcheck", 1, 3, f_mapcheck},
714 {"match", 2, 4, f_match},
715 {"matchadd", 2, 5, f_matchadd},
716 {"matchaddpos", 2, 5, f_matchaddpos},
717 {"matcharg", 1, 1, f_matcharg},
718 {"matchdelete", 1, 1, f_matchdelete},
719 {"matchend", 2, 4, f_matchend},
720 {"matchlist", 2, 4, f_matchlist},
721 {"matchstr", 2, 4, f_matchstr},
722 {"matchstrpos", 2, 4, f_matchstrpos},
723 {"max", 1, 1, f_max},
724 {"min", 1, 1, f_min},
725#ifdef vim_mkdir
726 {"mkdir", 1, 3, f_mkdir},
727#endif
728 {"mode", 0, 1, f_mode},
729#ifdef FEAT_MZSCHEME
730 {"mzeval", 1, 1, f_mzeval},
731#endif
732 {"nextnonblank", 1, 1, f_nextnonblank},
733 {"nr2char", 1, 2, f_nr2char},
734 {"or", 2, 2, f_or},
735 {"pathshorten", 1, 1, f_pathshorten},
736#ifdef FEAT_PERL
737 {"perleval", 1, 1, f_perleval},
738#endif
739#ifdef FEAT_FLOAT
740 {"pow", 2, 2, f_pow},
741#endif
742 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100743 {"printf", 1, 19, f_printf},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744 {"pumvisible", 0, 0, f_pumvisible},
745#ifdef FEAT_PYTHON3
746 {"py3eval", 1, 1, f_py3eval},
747#endif
748#ifdef FEAT_PYTHON
749 {"pyeval", 1, 1, f_pyeval},
750#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100751#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
752 {"pyxeval", 1, 1, f_pyxeval},
753#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200754 {"range", 1, 3, f_range},
755 {"readfile", 1, 3, f_readfile},
756 {"reltime", 0, 2, f_reltime},
757#ifdef FEAT_FLOAT
758 {"reltimefloat", 1, 1, f_reltimefloat},
759#endif
760 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100761 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762 {"remote_foreground", 1, 1, f_remote_foreground},
763 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100764 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200765 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100766 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200767 {"remove", 2, 3, f_remove},
768 {"rename", 2, 2, f_rename},
769 {"repeat", 2, 2, f_repeat},
770 {"resolve", 1, 1, f_resolve},
771 {"reverse", 1, 1, f_reverse},
772#ifdef FEAT_FLOAT
773 {"round", 1, 1, f_round},
774#endif
775 {"screenattr", 2, 2, f_screenattr},
776 {"screenchar", 2, 2, f_screenchar},
777 {"screencol", 0, 0, f_screencol},
778 {"screenrow", 0, 0, f_screenrow},
779 {"search", 1, 4, f_search},
780 {"searchdecl", 1, 3, f_searchdecl},
781 {"searchpair", 3, 7, f_searchpair},
782 {"searchpairpos", 3, 7, f_searchpairpos},
783 {"searchpos", 1, 4, f_searchpos},
784 {"server2client", 2, 2, f_server2client},
785 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200786 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200787 {"setbufvar", 3, 3, f_setbufvar},
788 {"setcharsearch", 1, 1, f_setcharsearch},
789 {"setcmdpos", 1, 1, f_setcmdpos},
790 {"setfperm", 2, 2, f_setfperm},
791 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200792 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793 {"setmatches", 1, 1, f_setmatches},
794 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200795 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200796 {"setreg", 2, 3, f_setreg},
797 {"settabvar", 3, 3, f_settabvar},
798 {"settabwinvar", 4, 4, f_settabwinvar},
799 {"setwinvar", 3, 3, f_setwinvar},
800#ifdef FEAT_CRYPT
801 {"sha256", 1, 1, f_sha256},
802#endif
803 {"shellescape", 1, 2, f_shellescape},
804 {"shiftwidth", 0, 0, f_shiftwidth},
805 {"simplify", 1, 1, f_simplify},
806#ifdef FEAT_FLOAT
807 {"sin", 1, 1, f_sin},
808 {"sinh", 1, 1, f_sinh},
809#endif
810 {"sort", 1, 3, f_sort},
811 {"soundfold", 1, 1, f_soundfold},
812 {"spellbadword", 0, 1, f_spellbadword},
813 {"spellsuggest", 1, 3, f_spellsuggest},
814 {"split", 1, 3, f_split},
815#ifdef FEAT_FLOAT
816 {"sqrt", 1, 1, f_sqrt},
817 {"str2float", 1, 1, f_str2float},
818#endif
819 {"str2nr", 1, 2, f_str2nr},
820 {"strcharpart", 2, 3, f_strcharpart},
821 {"strchars", 1, 2, f_strchars},
822 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
823#ifdef HAVE_STRFTIME
824 {"strftime", 1, 2, f_strftime},
825#endif
826 {"strgetchar", 2, 2, f_strgetchar},
827 {"stridx", 2, 3, f_stridx},
828 {"string", 1, 1, f_string},
829 {"strlen", 1, 1, f_strlen},
830 {"strpart", 2, 3, f_strpart},
831 {"strridx", 2, 3, f_strridx},
832 {"strtrans", 1, 1, f_strtrans},
833 {"strwidth", 1, 1, f_strwidth},
834 {"submatch", 1, 2, f_submatch},
835 {"substitute", 4, 4, f_substitute},
836 {"synID", 3, 3, f_synID},
837 {"synIDattr", 2, 3, f_synIDattr},
838 {"synIDtrans", 1, 1, f_synIDtrans},
839 {"synconcealed", 2, 2, f_synconcealed},
840 {"synstack", 2, 2, f_synstack},
841 {"system", 1, 2, f_system},
842 {"systemlist", 1, 2, f_systemlist},
843 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
844 {"tabpagenr", 0, 1, f_tabpagenr},
845 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
846 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100847 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848#ifdef FEAT_FLOAT
849 {"tan", 1, 1, f_tan},
850 {"tanh", 1, 1, f_tanh},
851#endif
852 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200853#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100854 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
855 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100856 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200857 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200858 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200859 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200860 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200861 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200862 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200863 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200864 {"term_getstatus", 1, 1, f_term_getstatus},
865 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200866 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200867 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200868 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200869 {"term_sendkeys", 2, 2, f_term_sendkeys},
870 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200871 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200872#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200873 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
874 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200875 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100877 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200878#ifdef FEAT_JOB_CHANNEL
879 {"test_null_channel", 0, 0, f_test_null_channel},
880#endif
881 {"test_null_dict", 0, 0, f_test_null_dict},
882#ifdef FEAT_JOB_CHANNEL
883 {"test_null_job", 0, 0, f_test_null_job},
884#endif
885 {"test_null_list", 0, 0, f_test_null_list},
886 {"test_null_partial", 0, 0, f_test_null_partial},
887 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100888 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200889 {"test_settime", 1, 1, f_test_settime},
890#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200891 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200892 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200893 {"timer_start", 2, 3, f_timer_start},
894 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200895 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200896#endif
897 {"tolower", 1, 1, f_tolower},
898 {"toupper", 1, 1, f_toupper},
899 {"tr", 3, 3, f_tr},
900#ifdef FEAT_FLOAT
901 {"trunc", 1, 1, f_trunc},
902#endif
903 {"type", 1, 1, f_type},
904 {"undofile", 1, 1, f_undofile},
905 {"undotree", 0, 0, f_undotree},
906 {"uniq", 1, 3, f_uniq},
907 {"values", 1, 1, f_values},
908 {"virtcol", 1, 1, f_virtcol},
909 {"visualmode", 0, 1, f_visualmode},
910 {"wildmenumode", 0, 0, f_wildmenumode},
911 {"win_findbuf", 1, 1, f_win_findbuf},
912 {"win_getid", 0, 2, f_win_getid},
913 {"win_gotoid", 1, 1, f_win_gotoid},
914 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
915 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100916 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917 {"winbufnr", 1, 1, f_winbufnr},
918 {"wincol", 0, 0, f_wincol},
919 {"winheight", 1, 1, f_winheight},
920 {"winline", 0, 0, f_winline},
921 {"winnr", 0, 1, f_winnr},
922 {"winrestcmd", 0, 0, f_winrestcmd},
923 {"winrestview", 1, 1, f_winrestview},
924 {"winsaveview", 0, 0, f_winsaveview},
925 {"winwidth", 1, 1, f_winwidth},
926 {"wordcount", 0, 0, f_wordcount},
927 {"writefile", 2, 3, f_writefile},
928 {"xor", 2, 2, f_xor},
929};
930
931#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
932
933/*
934 * Function given to ExpandGeneric() to obtain the list of internal
935 * or user defined function names.
936 */
937 char_u *
938get_function_name(expand_T *xp, int idx)
939{
940 static int intidx = -1;
941 char_u *name;
942
943 if (idx == 0)
944 intidx = -1;
945 if (intidx < 0)
946 {
947 name = get_user_func_name(xp, idx);
948 if (name != NULL)
949 return name;
950 }
951 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
952 {
953 STRCPY(IObuff, functions[intidx].f_name);
954 STRCAT(IObuff, "(");
955 if (functions[intidx].f_max_argc == 0)
956 STRCAT(IObuff, ")");
957 return IObuff;
958 }
959
960 return NULL;
961}
962
963/*
964 * Function given to ExpandGeneric() to obtain the list of internal or
965 * user defined variable or function names.
966 */
967 char_u *
968get_expr_name(expand_T *xp, int idx)
969{
970 static int intidx = -1;
971 char_u *name;
972
973 if (idx == 0)
974 intidx = -1;
975 if (intidx < 0)
976 {
977 name = get_function_name(xp, idx);
978 if (name != NULL)
979 return name;
980 }
981 return get_user_var_name(xp, ++intidx);
982}
983
984#endif /* FEAT_CMDL_COMPL */
985
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200986/*
987 * Find internal function in table above.
988 * Return index, or -1 if not found
989 */
990 int
991find_internal_func(
992 char_u *name) /* name of the function */
993{
994 int first = 0;
995 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
996 int cmp;
997 int x;
998
999 /*
1000 * Find the function name in the table. Binary search.
1001 */
1002 while (first <= last)
1003 {
1004 x = first + ((unsigned)(last - first) >> 1);
1005 cmp = STRCMP(name, functions[x].f_name);
1006 if (cmp < 0)
1007 last = x - 1;
1008 else if (cmp > 0)
1009 first = x + 1;
1010 else
1011 return x;
1012 }
1013 return -1;
1014}
1015
1016 int
1017call_internal_func(
1018 char_u *name,
1019 int argcount,
1020 typval_T *argvars,
1021 typval_T *rettv)
1022{
1023 int i;
1024
1025 i = find_internal_func(name);
1026 if (i < 0)
1027 return ERROR_UNKNOWN;
1028 if (argcount < functions[i].f_min_argc)
1029 return ERROR_TOOFEW;
1030 if (argcount > functions[i].f_max_argc)
1031 return ERROR_TOOMANY;
1032 argvars[argcount].v_type = VAR_UNKNOWN;
1033 functions[i].f_func(argvars, rettv);
1034 return ERROR_NONE;
1035}
1036
1037/*
1038 * Return TRUE for a non-zero Number and a non-empty String.
1039 */
1040 static int
1041non_zero_arg(typval_T *argvars)
1042{
1043 return ((argvars[0].v_type == VAR_NUMBER
1044 && argvars[0].vval.v_number != 0)
1045 || (argvars[0].v_type == VAR_SPECIAL
1046 && argvars[0].vval.v_number == VVAL_TRUE)
1047 || (argvars[0].v_type == VAR_STRING
1048 && argvars[0].vval.v_string != NULL
1049 && *argvars[0].vval.v_string != NUL));
1050}
1051
1052/*
1053 * Get the lnum from the first argument.
1054 * Also accepts ".", "$", etc., but that only works for the current buffer.
1055 * Returns -1 on error.
1056 */
1057 static linenr_T
1058get_tv_lnum(typval_T *argvars)
1059{
1060 typval_T rettv;
1061 linenr_T lnum;
1062
1063 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1064 if (lnum == 0) /* no valid number, try using line() */
1065 {
1066 rettv.v_type = VAR_NUMBER;
1067 f_line(argvars, &rettv);
1068 lnum = (linenr_T)rettv.vval.v_number;
1069 clear_tv(&rettv);
1070 }
1071 return lnum;
1072}
1073
1074#ifdef FEAT_FLOAT
1075static int get_float_arg(typval_T *argvars, float_T *f);
1076
1077/*
1078 * Get the float value of "argvars[0]" into "f".
1079 * Returns FAIL when the argument is not a Number or Float.
1080 */
1081 static int
1082get_float_arg(typval_T *argvars, float_T *f)
1083{
1084 if (argvars[0].v_type == VAR_FLOAT)
1085 {
1086 *f = argvars[0].vval.v_float;
1087 return OK;
1088 }
1089 if (argvars[0].v_type == VAR_NUMBER)
1090 {
1091 *f = (float_T)argvars[0].vval.v_number;
1092 return OK;
1093 }
1094 EMSG(_("E808: Number or Float required"));
1095 return FAIL;
1096}
1097
1098/*
1099 * "abs(expr)" function
1100 */
1101 static void
1102f_abs(typval_T *argvars, typval_T *rettv)
1103{
1104 if (argvars[0].v_type == VAR_FLOAT)
1105 {
1106 rettv->v_type = VAR_FLOAT;
1107 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1108 }
1109 else
1110 {
1111 varnumber_T n;
1112 int error = FALSE;
1113
1114 n = get_tv_number_chk(&argvars[0], &error);
1115 if (error)
1116 rettv->vval.v_number = -1;
1117 else if (n > 0)
1118 rettv->vval.v_number = n;
1119 else
1120 rettv->vval.v_number = -n;
1121 }
1122}
1123
1124/*
1125 * "acos()" function
1126 */
1127 static void
1128f_acos(typval_T *argvars, typval_T *rettv)
1129{
1130 float_T f = 0.0;
1131
1132 rettv->v_type = VAR_FLOAT;
1133 if (get_float_arg(argvars, &f) == OK)
1134 rettv->vval.v_float = acos(f);
1135 else
1136 rettv->vval.v_float = 0.0;
1137}
1138#endif
1139
1140/*
1141 * "add(list, item)" function
1142 */
1143 static void
1144f_add(typval_T *argvars, typval_T *rettv)
1145{
1146 list_T *l;
1147
1148 rettv->vval.v_number = 1; /* Default: Failed */
1149 if (argvars[0].v_type == VAR_LIST)
1150 {
1151 if ((l = argvars[0].vval.v_list) != NULL
1152 && !tv_check_lock(l->lv_lock,
1153 (char_u *)N_("add() argument"), TRUE)
1154 && list_append_tv(l, &argvars[1]) == OK)
1155 copy_tv(&argvars[0], rettv);
1156 }
1157 else
1158 EMSG(_(e_listreq));
1159}
1160
1161/*
1162 * "and(expr, expr)" function
1163 */
1164 static void
1165f_and(typval_T *argvars, typval_T *rettv)
1166{
1167 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1168 & get_tv_number_chk(&argvars[1], NULL);
1169}
1170
1171/*
1172 * "append(lnum, string/list)" function
1173 */
1174 static void
1175f_append(typval_T *argvars, typval_T *rettv)
1176{
1177 long lnum;
1178 char_u *line;
1179 list_T *l = NULL;
1180 listitem_T *li = NULL;
1181 typval_T *tv;
1182 long added = 0;
1183
1184 /* When coming here from Insert mode, sync undo, so that this can be
1185 * undone separately from what was previously inserted. */
1186 if (u_sync_once == 2)
1187 {
1188 u_sync_once = 1; /* notify that u_sync() was called */
1189 u_sync(TRUE);
1190 }
1191
1192 lnum = get_tv_lnum(argvars);
1193 if (lnum >= 0
1194 && lnum <= curbuf->b_ml.ml_line_count
1195 && u_save(lnum, lnum + 1) == OK)
1196 {
1197 if (argvars[1].v_type == VAR_LIST)
1198 {
1199 l = argvars[1].vval.v_list;
1200 if (l == NULL)
1201 return;
1202 li = l->lv_first;
1203 }
1204 for (;;)
1205 {
1206 if (l == NULL)
1207 tv = &argvars[1]; /* append a string */
1208 else if (li == NULL)
1209 break; /* end of list */
1210 else
1211 tv = &li->li_tv; /* append item from list */
1212 line = get_tv_string_chk(tv);
1213 if (line == NULL) /* type error */
1214 {
1215 rettv->vval.v_number = 1; /* Failed */
1216 break;
1217 }
1218 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1219 ++added;
1220 if (l == NULL)
1221 break;
1222 li = li->li_next;
1223 }
1224
1225 appended_lines_mark(lnum, added);
1226 if (curwin->w_cursor.lnum > lnum)
1227 curwin->w_cursor.lnum += added;
1228 }
1229 else
1230 rettv->vval.v_number = 1; /* Failed */
1231}
1232
1233/*
1234 * "argc()" function
1235 */
1236 static void
1237f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1238{
1239 rettv->vval.v_number = ARGCOUNT;
1240}
1241
1242/*
1243 * "argidx()" function
1244 */
1245 static void
1246f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1247{
1248 rettv->vval.v_number = curwin->w_arg_idx;
1249}
1250
1251/*
1252 * "arglistid()" function
1253 */
1254 static void
1255f_arglistid(typval_T *argvars, typval_T *rettv)
1256{
1257 win_T *wp;
1258
1259 rettv->vval.v_number = -1;
1260 wp = find_tabwin(&argvars[0], &argvars[1]);
1261 if (wp != NULL)
1262 rettv->vval.v_number = wp->w_alist->id;
1263}
1264
1265/*
1266 * "argv(nr)" function
1267 */
1268 static void
1269f_argv(typval_T *argvars, typval_T *rettv)
1270{
1271 int idx;
1272
1273 if (argvars[0].v_type != VAR_UNKNOWN)
1274 {
1275 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1276 if (idx >= 0 && idx < ARGCOUNT)
1277 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1278 else
1279 rettv->vval.v_string = NULL;
1280 rettv->v_type = VAR_STRING;
1281 }
1282 else if (rettv_list_alloc(rettv) == OK)
1283 for (idx = 0; idx < ARGCOUNT; ++idx)
1284 list_append_string(rettv->vval.v_list,
1285 alist_name(&ARGLIST[idx]), -1);
1286}
1287
1288/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001289 * "assert_beeps(cmd [, error])" function
1290 */
1291 static void
1292f_assert_beeps(typval_T *argvars, typval_T *rettv UNUSED)
1293{
1294 assert_beeps(argvars);
1295}
1296
1297/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001298 * "assert_equal(expected, actual[, msg])" function
1299 */
1300 static void
1301f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1302{
1303 assert_equal_common(argvars, ASSERT_EQUAL);
1304}
1305
1306/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001307 * "assert_equalfile(fname-one, fname-two)" function
1308 */
1309 static void
1310f_assert_equalfile(typval_T *argvars, typval_T *rettv UNUSED)
1311{
1312 assert_equalfile(argvars);
1313}
1314
1315/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001316 * "assert_notequal(expected, actual[, msg])" function
1317 */
1318 static void
1319f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1320{
1321 assert_equal_common(argvars, ASSERT_NOTEQUAL);
1322}
1323
1324/*
1325 * "assert_exception(string[, msg])" function
1326 */
1327 static void
1328f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1329{
1330 assert_exception(argvars);
1331}
1332
1333/*
1334 * "assert_fails(cmd [, error])" function
1335 */
1336 static void
1337f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1338{
1339 assert_fails(argvars);
1340}
1341
1342/*
1343 * "assert_false(actual[, msg])" function
1344 */
1345 static void
1346f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1347{
1348 assert_bool(argvars, FALSE);
1349}
1350
1351/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001352 * "assert_inrange(lower, upper[, msg])" function
1353 */
1354 static void
1355f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1356{
1357 assert_inrange(argvars);
1358}
1359
1360/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 * "assert_match(pattern, actual[, msg])" function
1362 */
1363 static void
1364f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1365{
1366 assert_match_common(argvars, ASSERT_MATCH);
1367}
1368
1369/*
1370 * "assert_notmatch(pattern, actual[, msg])" function
1371 */
1372 static void
1373f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1374{
1375 assert_match_common(argvars, ASSERT_NOTMATCH);
1376}
1377
1378/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001379 * "assert_report(msg)" function
1380 */
1381 static void
1382f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
1383{
1384 assert_report(argvars);
1385}
1386
1387/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001388 * "assert_true(actual[, msg])" function
1389 */
1390 static void
1391f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1392{
1393 assert_bool(argvars, TRUE);
1394}
1395
1396#ifdef FEAT_FLOAT
1397/*
1398 * "asin()" function
1399 */
1400 static void
1401f_asin(typval_T *argvars, typval_T *rettv)
1402{
1403 float_T f = 0.0;
1404
1405 rettv->v_type = VAR_FLOAT;
1406 if (get_float_arg(argvars, &f) == OK)
1407 rettv->vval.v_float = asin(f);
1408 else
1409 rettv->vval.v_float = 0.0;
1410}
1411
1412/*
1413 * "atan()" function
1414 */
1415 static void
1416f_atan(typval_T *argvars, typval_T *rettv)
1417{
1418 float_T f = 0.0;
1419
1420 rettv->v_type = VAR_FLOAT;
1421 if (get_float_arg(argvars, &f) == OK)
1422 rettv->vval.v_float = atan(f);
1423 else
1424 rettv->vval.v_float = 0.0;
1425}
1426
1427/*
1428 * "atan2()" function
1429 */
1430 static void
1431f_atan2(typval_T *argvars, typval_T *rettv)
1432{
1433 float_T fx = 0.0, fy = 0.0;
1434
1435 rettv->v_type = VAR_FLOAT;
1436 if (get_float_arg(argvars, &fx) == OK
1437 && get_float_arg(&argvars[1], &fy) == OK)
1438 rettv->vval.v_float = atan2(fx, fy);
1439 else
1440 rettv->vval.v_float = 0.0;
1441}
1442#endif
1443
1444/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001445 * "balloon_show()" function
1446 */
1447#ifdef FEAT_BEVAL
1448 static void
1449f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1450{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001451 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001452 {
1453 if (argvars[0].v_type == VAR_LIST
1454# ifdef FEAT_GUI
1455 && !gui.in_use
1456# endif
1457 )
1458 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1459 else
1460 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1461 }
1462}
1463
Bram Moolenaar669a8282017-11-19 20:13:05 +01001464# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001465 static void
1466f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1467{
1468 if (rettv_list_alloc(rettv) == OK)
1469 {
1470 char_u *msg = get_tv_string_chk(&argvars[0]);
1471
1472 if (msg != NULL)
1473 {
1474 pumitem_T *array;
1475 int size = split_message(msg, &array);
1476 int i;
1477
1478 /* Skip the first and last item, they are always empty. */
1479 for (i = 1; i < size - 1; ++i)
1480 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001481 while (size > 0)
1482 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001483 vim_free(array);
1484 }
1485 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001486}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001487# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001488#endif
1489
1490/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001491 * "browse(save, title, initdir, default)" function
1492 */
1493 static void
1494f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1495{
1496#ifdef FEAT_BROWSE
1497 int save;
1498 char_u *title;
1499 char_u *initdir;
1500 char_u *defname;
1501 char_u buf[NUMBUFLEN];
1502 char_u buf2[NUMBUFLEN];
1503 int error = FALSE;
1504
1505 save = (int)get_tv_number_chk(&argvars[0], &error);
1506 title = get_tv_string_chk(&argvars[1]);
1507 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1508 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1509
1510 if (error || title == NULL || initdir == NULL || defname == NULL)
1511 rettv->vval.v_string = NULL;
1512 else
1513 rettv->vval.v_string =
1514 do_browse(save ? BROWSE_SAVE : 0,
1515 title, defname, NULL, initdir, NULL, curbuf);
1516#else
1517 rettv->vval.v_string = NULL;
1518#endif
1519 rettv->v_type = VAR_STRING;
1520}
1521
1522/*
1523 * "browsedir(title, initdir)" function
1524 */
1525 static void
1526f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1527{
1528#ifdef FEAT_BROWSE
1529 char_u *title;
1530 char_u *initdir;
1531 char_u buf[NUMBUFLEN];
1532
1533 title = get_tv_string_chk(&argvars[0]);
1534 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1535
1536 if (title == NULL || initdir == NULL)
1537 rettv->vval.v_string = NULL;
1538 else
1539 rettv->vval.v_string = do_browse(BROWSE_DIR,
1540 title, NULL, NULL, initdir, NULL, curbuf);
1541#else
1542 rettv->vval.v_string = NULL;
1543#endif
1544 rettv->v_type = VAR_STRING;
1545}
1546
1547static buf_T *find_buffer(typval_T *avar);
1548
1549/*
1550 * Find a buffer by number or exact name.
1551 */
1552 static buf_T *
1553find_buffer(typval_T *avar)
1554{
1555 buf_T *buf = NULL;
1556
1557 if (avar->v_type == VAR_NUMBER)
1558 buf = buflist_findnr((int)avar->vval.v_number);
1559 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1560 {
1561 buf = buflist_findname_exp(avar->vval.v_string);
1562 if (buf == NULL)
1563 {
1564 /* No full path name match, try a match with a URL or a "nofile"
1565 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001566 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567 if (buf->b_fname != NULL
1568 && (path_with_url(buf->b_fname)
1569#ifdef FEAT_QUICKFIX
1570 || bt_nofile(buf)
1571#endif
1572 )
1573 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1574 break;
1575 }
1576 }
1577 return buf;
1578}
1579
1580/*
1581 * "bufexists(expr)" function
1582 */
1583 static void
1584f_bufexists(typval_T *argvars, typval_T *rettv)
1585{
1586 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1587}
1588
1589/*
1590 * "buflisted(expr)" function
1591 */
1592 static void
1593f_buflisted(typval_T *argvars, typval_T *rettv)
1594{
1595 buf_T *buf;
1596
1597 buf = find_buffer(&argvars[0]);
1598 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1599}
1600
1601/*
1602 * "bufloaded(expr)" function
1603 */
1604 static void
1605f_bufloaded(typval_T *argvars, typval_T *rettv)
1606{
1607 buf_T *buf;
1608
1609 buf = find_buffer(&argvars[0]);
1610 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1611}
1612
1613 buf_T *
1614buflist_find_by_name(char_u *name, int curtab_only)
1615{
1616 int save_magic;
1617 char_u *save_cpo;
1618 buf_T *buf;
1619
1620 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1621 save_magic = p_magic;
1622 p_magic = TRUE;
1623 save_cpo = p_cpo;
1624 p_cpo = (char_u *)"";
1625
1626 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1627 TRUE, FALSE, curtab_only));
1628
1629 p_magic = save_magic;
1630 p_cpo = save_cpo;
1631 return buf;
1632}
1633
1634/*
1635 * Get buffer by number or pattern.
1636 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001637 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001638get_buf_tv(typval_T *tv, int curtab_only)
1639{
1640 char_u *name = tv->vval.v_string;
1641 buf_T *buf;
1642
1643 if (tv->v_type == VAR_NUMBER)
1644 return buflist_findnr((int)tv->vval.v_number);
1645 if (tv->v_type != VAR_STRING)
1646 return NULL;
1647 if (name == NULL || *name == NUL)
1648 return curbuf;
1649 if (name[0] == '$' && name[1] == NUL)
1650 return lastbuf;
1651
1652 buf = buflist_find_by_name(name, curtab_only);
1653
1654 /* If not found, try expanding the name, like done for bufexists(). */
1655 if (buf == NULL)
1656 buf = find_buffer(tv);
1657
1658 return buf;
1659}
1660
1661/*
1662 * "bufname(expr)" function
1663 */
1664 static void
1665f_bufname(typval_T *argvars, typval_T *rettv)
1666{
1667 buf_T *buf;
1668
1669 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1670 ++emsg_off;
1671 buf = get_buf_tv(&argvars[0], FALSE);
1672 rettv->v_type = VAR_STRING;
1673 if (buf != NULL && buf->b_fname != NULL)
1674 rettv->vval.v_string = vim_strsave(buf->b_fname);
1675 else
1676 rettv->vval.v_string = NULL;
1677 --emsg_off;
1678}
1679
1680/*
1681 * "bufnr(expr)" function
1682 */
1683 static void
1684f_bufnr(typval_T *argvars, typval_T *rettv)
1685{
1686 buf_T *buf;
1687 int error = FALSE;
1688 char_u *name;
1689
1690 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1691 ++emsg_off;
1692 buf = get_buf_tv(&argvars[0], FALSE);
1693 --emsg_off;
1694
1695 /* If the buffer isn't found and the second argument is not zero create a
1696 * new buffer. */
1697 if (buf == NULL
1698 && argvars[1].v_type != VAR_UNKNOWN
1699 && get_tv_number_chk(&argvars[1], &error) != 0
1700 && !error
1701 && (name = get_tv_string_chk(&argvars[0])) != NULL
1702 && !error)
1703 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1704
1705 if (buf != NULL)
1706 rettv->vval.v_number = buf->b_fnum;
1707 else
1708 rettv->vval.v_number = -1;
1709}
1710
1711 static void
1712buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1713{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 win_T *wp;
1715 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 buf_T *buf;
1717
1718 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1719 ++emsg_off;
1720 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001721 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722 {
1723 ++winnr;
1724 if (wp->w_buffer == buf)
1725 break;
1726 }
1727 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728 --emsg_off;
1729}
1730
1731/*
1732 * "bufwinid(nr)" function
1733 */
1734 static void
1735f_bufwinid(typval_T *argvars, typval_T *rettv)
1736{
1737 buf_win_common(argvars, rettv, FALSE);
1738}
1739
1740/*
1741 * "bufwinnr(nr)" function
1742 */
1743 static void
1744f_bufwinnr(typval_T *argvars, typval_T *rettv)
1745{
1746 buf_win_common(argvars, rettv, TRUE);
1747}
1748
1749/*
1750 * "byte2line(byte)" function
1751 */
1752 static void
1753f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1754{
1755#ifndef FEAT_BYTEOFF
1756 rettv->vval.v_number = -1;
1757#else
1758 long boff = 0;
1759
1760 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1761 if (boff < 0)
1762 rettv->vval.v_number = -1;
1763 else
1764 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1765 (linenr_T)0, &boff);
1766#endif
1767}
1768
1769 static void
1770byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1771{
1772#ifdef FEAT_MBYTE
1773 char_u *t;
1774#endif
1775 char_u *str;
1776 varnumber_T idx;
1777
1778 str = get_tv_string_chk(&argvars[0]);
1779 idx = get_tv_number_chk(&argvars[1], NULL);
1780 rettv->vval.v_number = -1;
1781 if (str == NULL || idx < 0)
1782 return;
1783
1784#ifdef FEAT_MBYTE
1785 t = str;
1786 for ( ; idx > 0; idx--)
1787 {
1788 if (*t == NUL) /* EOL reached */
1789 return;
1790 if (enc_utf8 && comp)
1791 t += utf_ptr2len(t);
1792 else
1793 t += (*mb_ptr2len)(t);
1794 }
1795 rettv->vval.v_number = (varnumber_T)(t - str);
1796#else
1797 if ((size_t)idx <= STRLEN(str))
1798 rettv->vval.v_number = idx;
1799#endif
1800}
1801
1802/*
1803 * "byteidx()" function
1804 */
1805 static void
1806f_byteidx(typval_T *argvars, typval_T *rettv)
1807{
1808 byteidx(argvars, rettv, FALSE);
1809}
1810
1811/*
1812 * "byteidxcomp()" function
1813 */
1814 static void
1815f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1816{
1817 byteidx(argvars, rettv, TRUE);
1818}
1819
1820/*
1821 * "call(func, arglist [, dict])" function
1822 */
1823 static void
1824f_call(typval_T *argvars, typval_T *rettv)
1825{
1826 char_u *func;
1827 partial_T *partial = NULL;
1828 dict_T *selfdict = NULL;
1829
1830 if (argvars[1].v_type != VAR_LIST)
1831 {
1832 EMSG(_(e_listreq));
1833 return;
1834 }
1835 if (argvars[1].vval.v_list == NULL)
1836 return;
1837
1838 if (argvars[0].v_type == VAR_FUNC)
1839 func = argvars[0].vval.v_string;
1840 else if (argvars[0].v_type == VAR_PARTIAL)
1841 {
1842 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001843 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844 }
1845 else
1846 func = get_tv_string(&argvars[0]);
1847 if (*func == NUL)
1848 return; /* type error or empty name */
1849
1850 if (argvars[2].v_type != VAR_UNKNOWN)
1851 {
1852 if (argvars[2].v_type != VAR_DICT)
1853 {
1854 EMSG(_(e_dictreq));
1855 return;
1856 }
1857 selfdict = argvars[2].vval.v_dict;
1858 }
1859
1860 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1861}
1862
1863#ifdef FEAT_FLOAT
1864/*
1865 * "ceil({float})" function
1866 */
1867 static void
1868f_ceil(typval_T *argvars, typval_T *rettv)
1869{
1870 float_T f = 0.0;
1871
1872 rettv->v_type = VAR_FLOAT;
1873 if (get_float_arg(argvars, &f) == OK)
1874 rettv->vval.v_float = ceil(f);
1875 else
1876 rettv->vval.v_float = 0.0;
1877}
1878#endif
1879
1880#ifdef FEAT_JOB_CHANNEL
1881/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001882 * "ch_canread()" function
1883 */
1884 static void
1885f_ch_canread(typval_T *argvars, typval_T *rettv)
1886{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001887 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001888
1889 rettv->vval.v_number = 0;
1890 if (channel != NULL)
1891 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1892 || channel_has_readahead(channel, PART_OUT)
1893 || channel_has_readahead(channel, PART_ERR);
1894}
1895
1896/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001897 * "ch_close()" function
1898 */
1899 static void
1900f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1901{
1902 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1903
1904 if (channel != NULL)
1905 {
1906 channel_close(channel, FALSE);
1907 channel_clear(channel);
1908 }
1909}
1910
1911/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001912 * "ch_close()" function
1913 */
1914 static void
1915f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1916{
1917 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1918
1919 if (channel != NULL)
1920 channel_close_in(channel);
1921}
1922
1923/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001924 * "ch_getbufnr()" function
1925 */
1926 static void
1927f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1928{
1929 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1930
1931 rettv->vval.v_number = -1;
1932 if (channel != NULL)
1933 {
1934 char_u *what = get_tv_string(&argvars[1]);
1935 int part;
1936
1937 if (STRCMP(what, "err") == 0)
1938 part = PART_ERR;
1939 else if (STRCMP(what, "out") == 0)
1940 part = PART_OUT;
1941 else if (STRCMP(what, "in") == 0)
1942 part = PART_IN;
1943 else
1944 part = PART_SOCK;
1945 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1946 rettv->vval.v_number =
1947 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1948 }
1949}
1950
1951/*
1952 * "ch_getjob()" function
1953 */
1954 static void
1955f_ch_getjob(typval_T *argvars, typval_T *rettv)
1956{
1957 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1958
1959 if (channel != NULL)
1960 {
1961 rettv->v_type = VAR_JOB;
1962 rettv->vval.v_job = channel->ch_job;
1963 if (channel->ch_job != NULL)
1964 ++channel->ch_job->jv_refcount;
1965 }
1966}
1967
1968/*
1969 * "ch_info()" function
1970 */
1971 static void
1972f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1973{
1974 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1975
1976 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1977 channel_info(channel, rettv->vval.v_dict);
1978}
1979
1980/*
1981 * "ch_log()" function
1982 */
1983 static void
1984f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1985{
1986 char_u *msg = get_tv_string(&argvars[0]);
1987 channel_T *channel = NULL;
1988
1989 if (argvars[1].v_type != VAR_UNKNOWN)
1990 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
1991
1992 ch_log(channel, (char *)msg);
1993}
1994
1995/*
1996 * "ch_logfile()" function
1997 */
1998 static void
1999f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2000{
2001 char_u *fname;
2002 char_u *opt = (char_u *)"";
2003 char_u buf[NUMBUFLEN];
2004
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002005 /* Don't open a file in restricted mode. */
2006 if (check_restricted() || check_secure())
2007 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002008 fname = get_tv_string(&argvars[0]);
2009 if (argvars[1].v_type == VAR_STRING)
2010 opt = get_tv_string_buf(&argvars[1], buf);
2011 ch_logfile(fname, opt);
2012}
2013
2014/*
2015 * "ch_open()" function
2016 */
2017 static void
2018f_ch_open(typval_T *argvars, typval_T *rettv)
2019{
2020 rettv->v_type = VAR_CHANNEL;
2021 if (check_restricted() || check_secure())
2022 return;
2023 rettv->vval.v_channel = channel_open_func(argvars);
2024}
2025
2026/*
2027 * "ch_read()" function
2028 */
2029 static void
2030f_ch_read(typval_T *argvars, typval_T *rettv)
2031{
2032 common_channel_read(argvars, rettv, FALSE);
2033}
2034
2035/*
2036 * "ch_readraw()" function
2037 */
2038 static void
2039f_ch_readraw(typval_T *argvars, typval_T *rettv)
2040{
2041 common_channel_read(argvars, rettv, TRUE);
2042}
2043
2044/*
2045 * "ch_evalexpr()" function
2046 */
2047 static void
2048f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2049{
2050 ch_expr_common(argvars, rettv, TRUE);
2051}
2052
2053/*
2054 * "ch_sendexpr()" function
2055 */
2056 static void
2057f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2058{
2059 ch_expr_common(argvars, rettv, FALSE);
2060}
2061
2062/*
2063 * "ch_evalraw()" function
2064 */
2065 static void
2066f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2067{
2068 ch_raw_common(argvars, rettv, TRUE);
2069}
2070
2071/*
2072 * "ch_sendraw()" function
2073 */
2074 static void
2075f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2076{
2077 ch_raw_common(argvars, rettv, FALSE);
2078}
2079
2080/*
2081 * "ch_setoptions()" function
2082 */
2083 static void
2084f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2085{
2086 channel_T *channel;
2087 jobopt_T opt;
2088
2089 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2090 if (channel == NULL)
2091 return;
2092 clear_job_options(&opt);
2093 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002094 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 channel_set_options(channel, &opt);
2096 free_job_options(&opt);
2097}
2098
2099/*
2100 * "ch_status()" function
2101 */
2102 static void
2103f_ch_status(typval_T *argvars, typval_T *rettv)
2104{
2105 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002106 jobopt_T opt;
2107 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002108
2109 /* return an empty string by default */
2110 rettv->v_type = VAR_STRING;
2111 rettv->vval.v_string = NULL;
2112
2113 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002114
2115 if (argvars[1].v_type != VAR_UNKNOWN)
2116 {
2117 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002118 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002119 && (opt.jo_set & JO_PART))
2120 part = opt.jo_part;
2121 }
2122
2123 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002124}
2125#endif
2126
2127/*
2128 * "changenr()" function
2129 */
2130 static void
2131f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2132{
2133 rettv->vval.v_number = curbuf->b_u_seq_cur;
2134}
2135
2136/*
2137 * "char2nr(string)" function
2138 */
2139 static void
2140f_char2nr(typval_T *argvars, typval_T *rettv)
2141{
2142#ifdef FEAT_MBYTE
2143 if (has_mbyte)
2144 {
2145 int utf8 = 0;
2146
2147 if (argvars[1].v_type != VAR_UNKNOWN)
2148 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2149
2150 if (utf8)
2151 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2152 else
2153 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2154 }
2155 else
2156#endif
2157 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2158}
2159
2160/*
2161 * "cindent(lnum)" function
2162 */
2163 static void
2164f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2165{
2166#ifdef FEAT_CINDENT
2167 pos_T pos;
2168 linenr_T lnum;
2169
2170 pos = curwin->w_cursor;
2171 lnum = get_tv_lnum(argvars);
2172 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2173 {
2174 curwin->w_cursor.lnum = lnum;
2175 rettv->vval.v_number = get_c_indent();
2176 curwin->w_cursor = pos;
2177 }
2178 else
2179#endif
2180 rettv->vval.v_number = -1;
2181}
2182
2183/*
2184 * "clearmatches()" function
2185 */
2186 static void
2187f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2188{
2189#ifdef FEAT_SEARCH_EXTRA
2190 clear_matches(curwin);
2191#endif
2192}
2193
2194/*
2195 * "col(string)" function
2196 */
2197 static void
2198f_col(typval_T *argvars, typval_T *rettv)
2199{
2200 colnr_T col = 0;
2201 pos_T *fp;
2202 int fnum = curbuf->b_fnum;
2203
2204 fp = var2fpos(&argvars[0], FALSE, &fnum);
2205 if (fp != NULL && fnum == curbuf->b_fnum)
2206 {
2207 if (fp->col == MAXCOL)
2208 {
2209 /* '> can be MAXCOL, get the length of the line then */
2210 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2211 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2212 else
2213 col = MAXCOL;
2214 }
2215 else
2216 {
2217 col = fp->col + 1;
2218#ifdef FEAT_VIRTUALEDIT
2219 /* col(".") when the cursor is on the NUL at the end of the line
2220 * because of "coladd" can be seen as an extra column. */
2221 if (virtual_active() && fp == &curwin->w_cursor)
2222 {
2223 char_u *p = ml_get_cursor();
2224
2225 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2226 curwin->w_virtcol - curwin->w_cursor.coladd))
2227 {
2228# ifdef FEAT_MBYTE
2229 int l;
2230
2231 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2232 col += l;
2233# else
2234 if (*p != NUL && p[1] == NUL)
2235 ++col;
2236# endif
2237 }
2238 }
2239#endif
2240 }
2241 }
2242 rettv->vval.v_number = col;
2243}
2244
2245#if defined(FEAT_INS_EXPAND)
2246/*
2247 * "complete()" function
2248 */
2249 static void
2250f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2251{
2252 int startcol;
2253
2254 if ((State & INSERT) == 0)
2255 {
2256 EMSG(_("E785: complete() can only be used in Insert mode"));
2257 return;
2258 }
2259
2260 /* Check for undo allowed here, because if something was already inserted
2261 * the line was already saved for undo and this check isn't done. */
2262 if (!undo_allowed())
2263 return;
2264
2265 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2266 {
2267 EMSG(_(e_invarg));
2268 return;
2269 }
2270
2271 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2272 if (startcol <= 0)
2273 return;
2274
2275 set_completion(startcol - 1, argvars[1].vval.v_list);
2276}
2277
2278/*
2279 * "complete_add()" function
2280 */
2281 static void
2282f_complete_add(typval_T *argvars, typval_T *rettv)
2283{
2284 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2285}
2286
2287/*
2288 * "complete_check()" function
2289 */
2290 static void
2291f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2292{
2293 int saved = RedrawingDisabled;
2294
2295 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002296 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 rettv->vval.v_number = compl_interrupted;
2298 RedrawingDisabled = saved;
2299}
2300#endif
2301
2302/*
2303 * "confirm(message, buttons[, default [, type]])" function
2304 */
2305 static void
2306f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2307{
2308#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2309 char_u *message;
2310 char_u *buttons = NULL;
2311 char_u buf[NUMBUFLEN];
2312 char_u buf2[NUMBUFLEN];
2313 int def = 1;
2314 int type = VIM_GENERIC;
2315 char_u *typestr;
2316 int error = FALSE;
2317
2318 message = get_tv_string_chk(&argvars[0]);
2319 if (message == NULL)
2320 error = TRUE;
2321 if (argvars[1].v_type != VAR_UNKNOWN)
2322 {
2323 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2324 if (buttons == NULL)
2325 error = TRUE;
2326 if (argvars[2].v_type != VAR_UNKNOWN)
2327 {
2328 def = (int)get_tv_number_chk(&argvars[2], &error);
2329 if (argvars[3].v_type != VAR_UNKNOWN)
2330 {
2331 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2332 if (typestr == NULL)
2333 error = TRUE;
2334 else
2335 {
2336 switch (TOUPPER_ASC(*typestr))
2337 {
2338 case 'E': type = VIM_ERROR; break;
2339 case 'Q': type = VIM_QUESTION; break;
2340 case 'I': type = VIM_INFO; break;
2341 case 'W': type = VIM_WARNING; break;
2342 case 'G': type = VIM_GENERIC; break;
2343 }
2344 }
2345 }
2346 }
2347 }
2348
2349 if (buttons == NULL || *buttons == NUL)
2350 buttons = (char_u *)_("&Ok");
2351
2352 if (!error)
2353 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2354 def, NULL, FALSE);
2355#endif
2356}
2357
2358/*
2359 * "copy()" function
2360 */
2361 static void
2362f_copy(typval_T *argvars, typval_T *rettv)
2363{
2364 item_copy(&argvars[0], rettv, FALSE, 0);
2365}
2366
2367#ifdef FEAT_FLOAT
2368/*
2369 * "cos()" function
2370 */
2371 static void
2372f_cos(typval_T *argvars, typval_T *rettv)
2373{
2374 float_T f = 0.0;
2375
2376 rettv->v_type = VAR_FLOAT;
2377 if (get_float_arg(argvars, &f) == OK)
2378 rettv->vval.v_float = cos(f);
2379 else
2380 rettv->vval.v_float = 0.0;
2381}
2382
2383/*
2384 * "cosh()" function
2385 */
2386 static void
2387f_cosh(typval_T *argvars, typval_T *rettv)
2388{
2389 float_T f = 0.0;
2390
2391 rettv->v_type = VAR_FLOAT;
2392 if (get_float_arg(argvars, &f) == OK)
2393 rettv->vval.v_float = cosh(f);
2394 else
2395 rettv->vval.v_float = 0.0;
2396}
2397#endif
2398
2399/*
2400 * "count()" function
2401 */
2402 static void
2403f_count(typval_T *argvars, typval_T *rettv)
2404{
2405 long n = 0;
2406 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002407 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002408
Bram Moolenaar9966b212017-07-28 16:46:57 +02002409 if (argvars[2].v_type != VAR_UNKNOWN)
2410 ic = (int)get_tv_number_chk(&argvars[2], &error);
2411
2412 if (argvars[0].v_type == VAR_STRING)
2413 {
2414 char_u *expr = get_tv_string_chk(&argvars[1]);
2415 char_u *p = argvars[0].vval.v_string;
2416 char_u *next;
2417
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002418 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002419 {
2420 if (ic)
2421 {
2422 size_t len = STRLEN(expr);
2423
2424 while (*p != NUL)
2425 {
2426 if (MB_STRNICMP(p, expr, len) == 0)
2427 {
2428 ++n;
2429 p += len;
2430 }
2431 else
2432 MB_PTR_ADV(p);
2433 }
2434 }
2435 else
2436 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2437 != NULL)
2438 {
2439 ++n;
2440 p = next + STRLEN(expr);
2441 }
2442 }
2443
2444 }
2445 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446 {
2447 listitem_T *li;
2448 list_T *l;
2449 long idx;
2450
2451 if ((l = argvars[0].vval.v_list) != NULL)
2452 {
2453 li = l->lv_first;
2454 if (argvars[2].v_type != VAR_UNKNOWN)
2455 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002456 if (argvars[3].v_type != VAR_UNKNOWN)
2457 {
2458 idx = (long)get_tv_number_chk(&argvars[3], &error);
2459 if (!error)
2460 {
2461 li = list_find(l, idx);
2462 if (li == NULL)
2463 EMSGN(_(e_listidx), idx);
2464 }
2465 }
2466 if (error)
2467 li = NULL;
2468 }
2469
2470 for ( ; li != NULL; li = li->li_next)
2471 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2472 ++n;
2473 }
2474 }
2475 else if (argvars[0].v_type == VAR_DICT)
2476 {
2477 int todo;
2478 dict_T *d;
2479 hashitem_T *hi;
2480
2481 if ((d = argvars[0].vval.v_dict) != NULL)
2482 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002483 if (argvars[2].v_type != VAR_UNKNOWN)
2484 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002485 if (argvars[3].v_type != VAR_UNKNOWN)
2486 EMSG(_(e_invarg));
2487 }
2488
2489 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2490 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2491 {
2492 if (!HASHITEM_EMPTY(hi))
2493 {
2494 --todo;
2495 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2496 ++n;
2497 }
2498 }
2499 }
2500 }
2501 else
2502 EMSG2(_(e_listdictarg), "count()");
2503 rettv->vval.v_number = n;
2504}
2505
2506/*
2507 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2508 *
2509 * Checks the existence of a cscope connection.
2510 */
2511 static void
2512f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2513{
2514#ifdef FEAT_CSCOPE
2515 int num = 0;
2516 char_u *dbpath = NULL;
2517 char_u *prepend = NULL;
2518 char_u buf[NUMBUFLEN];
2519
2520 if (argvars[0].v_type != VAR_UNKNOWN
2521 && argvars[1].v_type != VAR_UNKNOWN)
2522 {
2523 num = (int)get_tv_number(&argvars[0]);
2524 dbpath = get_tv_string(&argvars[1]);
2525 if (argvars[2].v_type != VAR_UNKNOWN)
2526 prepend = get_tv_string_buf(&argvars[2], buf);
2527 }
2528
2529 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2530#endif
2531}
2532
2533/*
2534 * "cursor(lnum, col)" function, or
2535 * "cursor(list)"
2536 *
2537 * Moves the cursor to the specified line and column.
2538 * Returns 0 when the position could be set, -1 otherwise.
2539 */
2540 static void
2541f_cursor(typval_T *argvars, typval_T *rettv)
2542{
2543 long line, col;
2544#ifdef FEAT_VIRTUALEDIT
2545 long coladd = 0;
2546#endif
2547 int set_curswant = TRUE;
2548
2549 rettv->vval.v_number = -1;
2550 if (argvars[1].v_type == VAR_UNKNOWN)
2551 {
2552 pos_T pos;
2553 colnr_T curswant = -1;
2554
2555 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2556 {
2557 EMSG(_(e_invarg));
2558 return;
2559 }
2560 line = pos.lnum;
2561 col = pos.col;
2562#ifdef FEAT_VIRTUALEDIT
2563 coladd = pos.coladd;
2564#endif
2565 if (curswant >= 0)
2566 {
2567 curwin->w_curswant = curswant - 1;
2568 set_curswant = FALSE;
2569 }
2570 }
2571 else
2572 {
2573 line = get_tv_lnum(argvars);
2574 col = (long)get_tv_number_chk(&argvars[1], NULL);
2575#ifdef FEAT_VIRTUALEDIT
2576 if (argvars[2].v_type != VAR_UNKNOWN)
2577 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2578#endif
2579 }
2580 if (line < 0 || col < 0
2581#ifdef FEAT_VIRTUALEDIT
2582 || coladd < 0
2583#endif
2584 )
2585 return; /* type error; errmsg already given */
2586 if (line > 0)
2587 curwin->w_cursor.lnum = line;
2588 if (col > 0)
2589 curwin->w_cursor.col = col - 1;
2590#ifdef FEAT_VIRTUALEDIT
2591 curwin->w_cursor.coladd = coladd;
2592#endif
2593
2594 /* Make sure the cursor is in a valid position. */
2595 check_cursor();
2596#ifdef FEAT_MBYTE
2597 /* Correct cursor for multi-byte character. */
2598 if (has_mbyte)
2599 mb_adjust_cursor();
2600#endif
2601
2602 curwin->w_set_curswant = set_curswant;
2603 rettv->vval.v_number = 0;
2604}
2605
2606/*
2607 * "deepcopy()" function
2608 */
2609 static void
2610f_deepcopy(typval_T *argvars, typval_T *rettv)
2611{
2612 int noref = 0;
2613 int copyID;
2614
2615 if (argvars[1].v_type != VAR_UNKNOWN)
2616 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2617 if (noref < 0 || noref > 1)
2618 EMSG(_(e_invarg));
2619 else
2620 {
2621 copyID = get_copyID();
2622 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2623 }
2624}
2625
2626/*
2627 * "delete()" function
2628 */
2629 static void
2630f_delete(typval_T *argvars, typval_T *rettv)
2631{
2632 char_u nbuf[NUMBUFLEN];
2633 char_u *name;
2634 char_u *flags;
2635
2636 rettv->vval.v_number = -1;
2637 if (check_restricted() || check_secure())
2638 return;
2639
2640 name = get_tv_string(&argvars[0]);
2641 if (name == NULL || *name == NUL)
2642 {
2643 EMSG(_(e_invarg));
2644 return;
2645 }
2646
2647 if (argvars[1].v_type != VAR_UNKNOWN)
2648 flags = get_tv_string_buf(&argvars[1], nbuf);
2649 else
2650 flags = (char_u *)"";
2651
2652 if (*flags == NUL)
2653 /* delete a file */
2654 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2655 else if (STRCMP(flags, "d") == 0)
2656 /* delete an empty directory */
2657 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2658 else if (STRCMP(flags, "rf") == 0)
2659 /* delete a directory recursively */
2660 rettv->vval.v_number = delete_recursive(name);
2661 else
2662 EMSG2(_(e_invexpr2), flags);
2663}
2664
2665/*
2666 * "did_filetype()" function
2667 */
2668 static void
2669f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2670{
2671#ifdef FEAT_AUTOCMD
2672 rettv->vval.v_number = did_filetype;
2673#endif
2674}
2675
2676/*
2677 * "diff_filler()" function
2678 */
2679 static void
2680f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2681{
2682#ifdef FEAT_DIFF
2683 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2684#endif
2685}
2686
2687/*
2688 * "diff_hlID()" function
2689 */
2690 static void
2691f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2692{
2693#ifdef FEAT_DIFF
2694 linenr_T lnum = get_tv_lnum(argvars);
2695 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002696 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002697 static int fnum = 0;
2698 static int change_start = 0;
2699 static int change_end = 0;
2700 static hlf_T hlID = (hlf_T)0;
2701 int filler_lines;
2702 int col;
2703
2704 if (lnum < 0) /* ignore type error in {lnum} arg */
2705 lnum = 0;
2706 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002707 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002708 || fnum != curbuf->b_fnum)
2709 {
2710 /* New line, buffer, change: need to get the values. */
2711 filler_lines = diff_check(curwin, lnum);
2712 if (filler_lines < 0)
2713 {
2714 if (filler_lines == -1)
2715 {
2716 change_start = MAXCOL;
2717 change_end = -1;
2718 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2719 hlID = HLF_ADD; /* added line */
2720 else
2721 hlID = HLF_CHD; /* changed line */
2722 }
2723 else
2724 hlID = HLF_ADD; /* added line */
2725 }
2726 else
2727 hlID = (hlf_T)0;
2728 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002729 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002730 fnum = curbuf->b_fnum;
2731 }
2732
2733 if (hlID == HLF_CHD || hlID == HLF_TXD)
2734 {
2735 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2736 if (col >= change_start && col <= change_end)
2737 hlID = HLF_TXD; /* changed text */
2738 else
2739 hlID = HLF_CHD; /* changed line */
2740 }
2741 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2742#endif
2743}
2744
2745/*
2746 * "empty({expr})" function
2747 */
2748 static void
2749f_empty(typval_T *argvars, typval_T *rettv)
2750{
2751 int n = FALSE;
2752
2753 switch (argvars[0].v_type)
2754 {
2755 case VAR_STRING:
2756 case VAR_FUNC:
2757 n = argvars[0].vval.v_string == NULL
2758 || *argvars[0].vval.v_string == NUL;
2759 break;
2760 case VAR_PARTIAL:
2761 n = FALSE;
2762 break;
2763 case VAR_NUMBER:
2764 n = argvars[0].vval.v_number == 0;
2765 break;
2766 case VAR_FLOAT:
2767#ifdef FEAT_FLOAT
2768 n = argvars[0].vval.v_float == 0.0;
2769 break;
2770#endif
2771 case VAR_LIST:
2772 n = argvars[0].vval.v_list == NULL
2773 || argvars[0].vval.v_list->lv_first == NULL;
2774 break;
2775 case VAR_DICT:
2776 n = argvars[0].vval.v_dict == NULL
2777 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2778 break;
2779 case VAR_SPECIAL:
2780 n = argvars[0].vval.v_number != VVAL_TRUE;
2781 break;
2782
2783 case VAR_JOB:
2784#ifdef FEAT_JOB_CHANNEL
2785 n = argvars[0].vval.v_job == NULL
2786 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2787 break;
2788#endif
2789 case VAR_CHANNEL:
2790#ifdef FEAT_JOB_CHANNEL
2791 n = argvars[0].vval.v_channel == NULL
2792 || !channel_is_open(argvars[0].vval.v_channel);
2793 break;
2794#endif
2795 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002796 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002797 n = TRUE;
2798 break;
2799 }
2800
2801 rettv->vval.v_number = n;
2802}
2803
2804/*
2805 * "escape({string}, {chars})" function
2806 */
2807 static void
2808f_escape(typval_T *argvars, typval_T *rettv)
2809{
2810 char_u buf[NUMBUFLEN];
2811
2812 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2813 get_tv_string_buf(&argvars[1], buf));
2814 rettv->v_type = VAR_STRING;
2815}
2816
2817/*
2818 * "eval()" function
2819 */
2820 static void
2821f_eval(typval_T *argvars, typval_T *rettv)
2822{
2823 char_u *s, *p;
2824
2825 s = get_tv_string_chk(&argvars[0]);
2826 if (s != NULL)
2827 s = skipwhite(s);
2828
2829 p = s;
2830 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2831 {
2832 if (p != NULL && !aborting())
2833 EMSG2(_(e_invexpr2), p);
2834 need_clr_eos = FALSE;
2835 rettv->v_type = VAR_NUMBER;
2836 rettv->vval.v_number = 0;
2837 }
2838 else if (*s != NUL)
2839 EMSG(_(e_trailing));
2840}
2841
2842/*
2843 * "eventhandler()" function
2844 */
2845 static void
2846f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2847{
2848 rettv->vval.v_number = vgetc_busy;
2849}
2850
2851/*
2852 * "executable()" function
2853 */
2854 static void
2855f_executable(typval_T *argvars, typval_T *rettv)
2856{
2857 char_u *name = get_tv_string(&argvars[0]);
2858
2859 /* Check in $PATH and also check directly if there is a directory name. */
2860 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2861 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2862}
2863
2864static garray_T redir_execute_ga;
2865
2866/*
2867 * Append "value[value_len]" to the execute() output.
2868 */
2869 void
2870execute_redir_str(char_u *value, int value_len)
2871{
2872 int len;
2873
2874 if (value_len == -1)
2875 len = (int)STRLEN(value); /* Append the entire string */
2876 else
2877 len = value_len; /* Append only "value_len" characters */
2878 if (ga_grow(&redir_execute_ga, len) == OK)
2879 {
2880 mch_memmove((char *)redir_execute_ga.ga_data
2881 + redir_execute_ga.ga_len, value, len);
2882 redir_execute_ga.ga_len += len;
2883 }
2884}
2885
2886/*
2887 * Get next line from a list.
2888 * Called by do_cmdline() to get the next line.
2889 * Returns allocated string, or NULL for end of function.
2890 */
2891
2892 static char_u *
2893get_list_line(
2894 int c UNUSED,
2895 void *cookie,
2896 int indent UNUSED)
2897{
2898 listitem_T **p = (listitem_T **)cookie;
2899 listitem_T *item = *p;
2900 char_u buf[NUMBUFLEN];
2901 char_u *s;
2902
2903 if (item == NULL)
2904 return NULL;
2905 s = get_tv_string_buf_chk(&item->li_tv, buf);
2906 *p = item->li_next;
2907 return s == NULL ? NULL : vim_strsave(s);
2908}
2909
2910/*
2911 * "execute()" function
2912 */
2913 static void
2914f_execute(typval_T *argvars, typval_T *rettv)
2915{
2916 char_u *cmd = NULL;
2917 list_T *list = NULL;
2918 int save_msg_silent = msg_silent;
2919 int save_emsg_silent = emsg_silent;
2920 int save_emsg_noredir = emsg_noredir;
2921 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002922 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002923 garray_T save_ga;
2924
2925 rettv->vval.v_string = NULL;
2926 rettv->v_type = VAR_STRING;
2927
2928 if (argvars[0].v_type == VAR_LIST)
2929 {
2930 list = argvars[0].vval.v_list;
2931 if (list == NULL || list->lv_first == NULL)
2932 /* empty list, no commands, empty output */
2933 return;
2934 ++list->lv_refcount;
2935 }
2936 else
2937 {
2938 cmd = get_tv_string_chk(&argvars[0]);
2939 if (cmd == NULL)
2940 return;
2941 }
2942
2943 if (argvars[1].v_type != VAR_UNKNOWN)
2944 {
2945 char_u buf[NUMBUFLEN];
2946 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2947
2948 if (s == NULL)
2949 return;
2950 if (STRNCMP(s, "silent", 6) == 0)
2951 ++msg_silent;
2952 if (STRCMP(s, "silent!") == 0)
2953 {
2954 emsg_silent = TRUE;
2955 emsg_noredir = TRUE;
2956 }
2957 }
2958 else
2959 ++msg_silent;
2960
2961 if (redir_execute)
2962 save_ga = redir_execute_ga;
2963 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2964 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002965 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002966
2967 if (cmd != NULL)
2968 do_cmdline_cmd(cmd);
2969 else
2970 {
2971 listitem_T *item = list->lv_first;
2972
2973 do_cmdline(NULL, get_list_line, (void *)&item,
2974 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2975 --list->lv_refcount;
2976 }
2977
Bram Moolenaard297f352017-01-29 20:31:21 +01002978 /* Need to append a NUL to the result. */
2979 if (ga_grow(&redir_execute_ga, 1) == OK)
2980 {
2981 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2982 rettv->vval.v_string = redir_execute_ga.ga_data;
2983 }
2984 else
2985 {
2986 ga_clear(&redir_execute_ga);
2987 rettv->vval.v_string = NULL;
2988 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 msg_silent = save_msg_silent;
2990 emsg_silent = save_emsg_silent;
2991 emsg_noredir = save_emsg_noredir;
2992
2993 redir_execute = save_redir_execute;
2994 if (redir_execute)
2995 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002996 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002997
2998 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
2999 * line. Put it back in the first column. */
3000 msg_col = 0;
3001}
3002
3003/*
3004 * "exepath()" function
3005 */
3006 static void
3007f_exepath(typval_T *argvars, typval_T *rettv)
3008{
3009 char_u *p = NULL;
3010
3011 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3012 rettv->v_type = VAR_STRING;
3013 rettv->vval.v_string = p;
3014}
3015
3016/*
3017 * "exists()" function
3018 */
3019 static void
3020f_exists(typval_T *argvars, typval_T *rettv)
3021{
3022 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003023 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003024
3025 p = get_tv_string(&argvars[0]);
3026 if (*p == '$') /* environment variable */
3027 {
3028 /* first try "normal" environment variables (fast) */
3029 if (mch_getenv(p + 1) != NULL)
3030 n = TRUE;
3031 else
3032 {
3033 /* try expanding things like $VIM and ${HOME} */
3034 p = expand_env_save(p);
3035 if (p != NULL && *p != '$')
3036 n = TRUE;
3037 vim_free(p);
3038 }
3039 }
3040 else if (*p == '&' || *p == '+') /* option */
3041 {
3042 n = (get_option_tv(&p, NULL, TRUE) == OK);
3043 if (*skipwhite(p) != NUL)
3044 n = FALSE; /* trailing garbage */
3045 }
3046 else if (*p == '*') /* internal or user defined function */
3047 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003048 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003049 }
3050 else if (*p == ':')
3051 {
3052 n = cmd_exists(p + 1);
3053 }
3054 else if (*p == '#')
3055 {
3056#ifdef FEAT_AUTOCMD
3057 if (p[1] == '#')
3058 n = autocmd_supported(p + 2);
3059 else
3060 n = au_exists(p + 1);
3061#endif
3062 }
3063 else /* internal variable */
3064 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003065 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003066 }
3067
3068 rettv->vval.v_number = n;
3069}
3070
3071#ifdef FEAT_FLOAT
3072/*
3073 * "exp()" function
3074 */
3075 static void
3076f_exp(typval_T *argvars, typval_T *rettv)
3077{
3078 float_T f = 0.0;
3079
3080 rettv->v_type = VAR_FLOAT;
3081 if (get_float_arg(argvars, &f) == OK)
3082 rettv->vval.v_float = exp(f);
3083 else
3084 rettv->vval.v_float = 0.0;
3085}
3086#endif
3087
3088/*
3089 * "expand()" function
3090 */
3091 static void
3092f_expand(typval_T *argvars, typval_T *rettv)
3093{
3094 char_u *s;
3095 int len;
3096 char_u *errormsg;
3097 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3098 expand_T xpc;
3099 int error = FALSE;
3100 char_u *result;
3101
3102 rettv->v_type = VAR_STRING;
3103 if (argvars[1].v_type != VAR_UNKNOWN
3104 && argvars[2].v_type != VAR_UNKNOWN
3105 && get_tv_number_chk(&argvars[2], &error)
3106 && !error)
3107 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003108 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003109 }
3110
3111 s = get_tv_string(&argvars[0]);
3112 if (*s == '%' || *s == '#' || *s == '<')
3113 {
3114 ++emsg_off;
3115 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3116 --emsg_off;
3117 if (rettv->v_type == VAR_LIST)
3118 {
3119 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3120 list_append_string(rettv->vval.v_list, result, -1);
3121 else
3122 vim_free(result);
3123 }
3124 else
3125 rettv->vval.v_string = result;
3126 }
3127 else
3128 {
3129 /* When the optional second argument is non-zero, don't remove matches
3130 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3131 if (argvars[1].v_type != VAR_UNKNOWN
3132 && get_tv_number_chk(&argvars[1], &error))
3133 options |= WILD_KEEP_ALL;
3134 if (!error)
3135 {
3136 ExpandInit(&xpc);
3137 xpc.xp_context = EXPAND_FILES;
3138 if (p_wic)
3139 options += WILD_ICASE;
3140 if (rettv->v_type == VAR_STRING)
3141 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3142 options, WILD_ALL);
3143 else if (rettv_list_alloc(rettv) != FAIL)
3144 {
3145 int i;
3146
3147 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3148 for (i = 0; i < xpc.xp_numfiles; i++)
3149 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3150 ExpandCleanup(&xpc);
3151 }
3152 }
3153 else
3154 rettv->vval.v_string = NULL;
3155 }
3156}
3157
3158/*
3159 * "extend(list, list [, idx])" function
3160 * "extend(dict, dict [, action])" function
3161 */
3162 static void
3163f_extend(typval_T *argvars, typval_T *rettv)
3164{
3165 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3166
3167 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3168 {
3169 list_T *l1, *l2;
3170 listitem_T *item;
3171 long before;
3172 int error = FALSE;
3173
3174 l1 = argvars[0].vval.v_list;
3175 l2 = argvars[1].vval.v_list;
3176 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3177 && l2 != NULL)
3178 {
3179 if (argvars[2].v_type != VAR_UNKNOWN)
3180 {
3181 before = (long)get_tv_number_chk(&argvars[2], &error);
3182 if (error)
3183 return; /* type error; errmsg already given */
3184
3185 if (before == l1->lv_len)
3186 item = NULL;
3187 else
3188 {
3189 item = list_find(l1, before);
3190 if (item == NULL)
3191 {
3192 EMSGN(_(e_listidx), before);
3193 return;
3194 }
3195 }
3196 }
3197 else
3198 item = NULL;
3199 list_extend(l1, l2, item);
3200
3201 copy_tv(&argvars[0], rettv);
3202 }
3203 }
3204 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3205 {
3206 dict_T *d1, *d2;
3207 char_u *action;
3208 int i;
3209
3210 d1 = argvars[0].vval.v_dict;
3211 d2 = argvars[1].vval.v_dict;
3212 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3213 && d2 != NULL)
3214 {
3215 /* Check the third argument. */
3216 if (argvars[2].v_type != VAR_UNKNOWN)
3217 {
3218 static char *(av[]) = {"keep", "force", "error"};
3219
3220 action = get_tv_string_chk(&argvars[2]);
3221 if (action == NULL)
3222 return; /* type error; errmsg already given */
3223 for (i = 0; i < 3; ++i)
3224 if (STRCMP(action, av[i]) == 0)
3225 break;
3226 if (i == 3)
3227 {
3228 EMSG2(_(e_invarg2), action);
3229 return;
3230 }
3231 }
3232 else
3233 action = (char_u *)"force";
3234
3235 dict_extend(d1, d2, action);
3236
3237 copy_tv(&argvars[0], rettv);
3238 }
3239 }
3240 else
3241 EMSG2(_(e_listdictarg), "extend()");
3242}
3243
3244/*
3245 * "feedkeys()" function
3246 */
3247 static void
3248f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3249{
3250 int remap = TRUE;
3251 int insert = FALSE;
3252 char_u *keys, *flags;
3253 char_u nbuf[NUMBUFLEN];
3254 int typed = FALSE;
3255 int execute = FALSE;
3256 int dangerous = FALSE;
3257 char_u *keys_esc;
3258
3259 /* This is not allowed in the sandbox. If the commands would still be
3260 * executed in the sandbox it would be OK, but it probably happens later,
3261 * when "sandbox" is no longer set. */
3262 if (check_secure())
3263 return;
3264
3265 keys = get_tv_string(&argvars[0]);
3266
3267 if (argvars[1].v_type != VAR_UNKNOWN)
3268 {
3269 flags = get_tv_string_buf(&argvars[1], nbuf);
3270 for ( ; *flags != NUL; ++flags)
3271 {
3272 switch (*flags)
3273 {
3274 case 'n': remap = FALSE; break;
3275 case 'm': remap = TRUE; break;
3276 case 't': typed = TRUE; break;
3277 case 'i': insert = TRUE; break;
3278 case 'x': execute = TRUE; break;
3279 case '!': dangerous = TRUE; break;
3280 }
3281 }
3282 }
3283
3284 if (*keys != NUL || execute)
3285 {
3286 /* Need to escape K_SPECIAL and CSI before putting the string in the
3287 * typeahead buffer. */
3288 keys_esc = vim_strsave_escape_csi(keys);
3289 if (keys_esc != NULL)
3290 {
3291 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3292 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3293 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003294 if (vgetc_busy
3295#ifdef FEAT_TIMERS
3296 || timer_busy
3297#endif
3298 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299 typebuf_was_filled = TRUE;
3300 if (execute)
3301 {
3302 int save_msg_scroll = msg_scroll;
3303
3304 /* Avoid a 1 second delay when the keys start Insert mode. */
3305 msg_scroll = FALSE;
3306
Bram Moolenaar69fbc9e2017-09-14 20:37:57 +02003307#ifdef FEAT_TERMINAL
3308 if (term_use_loop())
3309 terminal_loop(FALSE);
3310 else
3311#endif
3312 {
3313 if (!dangerous)
3314 ++ex_normal_busy;
3315 exec_normal(TRUE);
3316 if (!dangerous)
3317 --ex_normal_busy;
3318 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003319 msg_scroll |= save_msg_scroll;
3320 }
3321 }
3322 }
3323}
3324
3325/*
3326 * "filereadable()" function
3327 */
3328 static void
3329f_filereadable(typval_T *argvars, typval_T *rettv)
3330{
3331 int fd;
3332 char_u *p;
3333 int n;
3334
3335#ifndef O_NONBLOCK
3336# define O_NONBLOCK 0
3337#endif
3338 p = get_tv_string(&argvars[0]);
3339 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3340 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3341 {
3342 n = TRUE;
3343 close(fd);
3344 }
3345 else
3346 n = FALSE;
3347
3348 rettv->vval.v_number = n;
3349}
3350
3351/*
3352 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3353 * rights to write into.
3354 */
3355 static void
3356f_filewritable(typval_T *argvars, typval_T *rettv)
3357{
3358 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3359}
3360
3361 static void
3362findfilendir(
3363 typval_T *argvars UNUSED,
3364 typval_T *rettv,
3365 int find_what UNUSED)
3366{
3367#ifdef FEAT_SEARCHPATH
3368 char_u *fname;
3369 char_u *fresult = NULL;
3370 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3371 char_u *p;
3372 char_u pathbuf[NUMBUFLEN];
3373 int count = 1;
3374 int first = TRUE;
3375 int error = FALSE;
3376#endif
3377
3378 rettv->vval.v_string = NULL;
3379 rettv->v_type = VAR_STRING;
3380
3381#ifdef FEAT_SEARCHPATH
3382 fname = get_tv_string(&argvars[0]);
3383
3384 if (argvars[1].v_type != VAR_UNKNOWN)
3385 {
3386 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3387 if (p == NULL)
3388 error = TRUE;
3389 else
3390 {
3391 if (*p != NUL)
3392 path = p;
3393
3394 if (argvars[2].v_type != VAR_UNKNOWN)
3395 count = (int)get_tv_number_chk(&argvars[2], &error);
3396 }
3397 }
3398
3399 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3400 error = TRUE;
3401
3402 if (*fname != NUL && !error)
3403 {
3404 do
3405 {
3406 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3407 vim_free(fresult);
3408 fresult = find_file_in_path_option(first ? fname : NULL,
3409 first ? (int)STRLEN(fname) : 0,
3410 0, first, path,
3411 find_what,
3412 curbuf->b_ffname,
3413 find_what == FINDFILE_DIR
3414 ? (char_u *)"" : curbuf->b_p_sua);
3415 first = FALSE;
3416
3417 if (fresult != NULL && rettv->v_type == VAR_LIST)
3418 list_append_string(rettv->vval.v_list, fresult, -1);
3419
3420 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3421 }
3422
3423 if (rettv->v_type == VAR_STRING)
3424 rettv->vval.v_string = fresult;
3425#endif
3426}
3427
3428/*
3429 * "filter()" function
3430 */
3431 static void
3432f_filter(typval_T *argvars, typval_T *rettv)
3433{
3434 filter_map(argvars, rettv, FALSE);
3435}
3436
3437/*
3438 * "finddir({fname}[, {path}[, {count}]])" function
3439 */
3440 static void
3441f_finddir(typval_T *argvars, typval_T *rettv)
3442{
3443 findfilendir(argvars, rettv, FINDFILE_DIR);
3444}
3445
3446/*
3447 * "findfile({fname}[, {path}[, {count}]])" function
3448 */
3449 static void
3450f_findfile(typval_T *argvars, typval_T *rettv)
3451{
3452 findfilendir(argvars, rettv, FINDFILE_FILE);
3453}
3454
3455#ifdef FEAT_FLOAT
3456/*
3457 * "float2nr({float})" function
3458 */
3459 static void
3460f_float2nr(typval_T *argvars, typval_T *rettv)
3461{
3462 float_T f = 0.0;
3463
3464 if (get_float_arg(argvars, &f) == OK)
3465 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003466 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003467 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003468 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003469 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470 else
3471 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472 }
3473}
3474
3475/*
3476 * "floor({float})" function
3477 */
3478 static void
3479f_floor(typval_T *argvars, typval_T *rettv)
3480{
3481 float_T f = 0.0;
3482
3483 rettv->v_type = VAR_FLOAT;
3484 if (get_float_arg(argvars, &f) == OK)
3485 rettv->vval.v_float = floor(f);
3486 else
3487 rettv->vval.v_float = 0.0;
3488}
3489
3490/*
3491 * "fmod()" function
3492 */
3493 static void
3494f_fmod(typval_T *argvars, typval_T *rettv)
3495{
3496 float_T fx = 0.0, fy = 0.0;
3497
3498 rettv->v_type = VAR_FLOAT;
3499 if (get_float_arg(argvars, &fx) == OK
3500 && get_float_arg(&argvars[1], &fy) == OK)
3501 rettv->vval.v_float = fmod(fx, fy);
3502 else
3503 rettv->vval.v_float = 0.0;
3504}
3505#endif
3506
3507/*
3508 * "fnameescape({string})" function
3509 */
3510 static void
3511f_fnameescape(typval_T *argvars, typval_T *rettv)
3512{
3513 rettv->vval.v_string = vim_strsave_fnameescape(
3514 get_tv_string(&argvars[0]), FALSE);
3515 rettv->v_type = VAR_STRING;
3516}
3517
3518/*
3519 * "fnamemodify({fname}, {mods})" function
3520 */
3521 static void
3522f_fnamemodify(typval_T *argvars, typval_T *rettv)
3523{
3524 char_u *fname;
3525 char_u *mods;
3526 int usedlen = 0;
3527 int len;
3528 char_u *fbuf = NULL;
3529 char_u buf[NUMBUFLEN];
3530
3531 fname = get_tv_string_chk(&argvars[0]);
3532 mods = get_tv_string_buf_chk(&argvars[1], buf);
3533 if (fname == NULL || mods == NULL)
3534 fname = NULL;
3535 else
3536 {
3537 len = (int)STRLEN(fname);
3538 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3539 }
3540
3541 rettv->v_type = VAR_STRING;
3542 if (fname == NULL)
3543 rettv->vval.v_string = NULL;
3544 else
3545 rettv->vval.v_string = vim_strnsave(fname, len);
3546 vim_free(fbuf);
3547}
3548
3549static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3550
3551/*
3552 * "foldclosed()" function
3553 */
3554 static void
3555foldclosed_both(
3556 typval_T *argvars UNUSED,
3557 typval_T *rettv,
3558 int end UNUSED)
3559{
3560#ifdef FEAT_FOLDING
3561 linenr_T lnum;
3562 linenr_T first, last;
3563
3564 lnum = get_tv_lnum(argvars);
3565 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3566 {
3567 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3568 {
3569 if (end)
3570 rettv->vval.v_number = (varnumber_T)last;
3571 else
3572 rettv->vval.v_number = (varnumber_T)first;
3573 return;
3574 }
3575 }
3576#endif
3577 rettv->vval.v_number = -1;
3578}
3579
3580/*
3581 * "foldclosed()" function
3582 */
3583 static void
3584f_foldclosed(typval_T *argvars, typval_T *rettv)
3585{
3586 foldclosed_both(argvars, rettv, FALSE);
3587}
3588
3589/*
3590 * "foldclosedend()" function
3591 */
3592 static void
3593f_foldclosedend(typval_T *argvars, typval_T *rettv)
3594{
3595 foldclosed_both(argvars, rettv, TRUE);
3596}
3597
3598/*
3599 * "foldlevel()" function
3600 */
3601 static void
3602f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3603{
3604#ifdef FEAT_FOLDING
3605 linenr_T lnum;
3606
3607 lnum = get_tv_lnum(argvars);
3608 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3609 rettv->vval.v_number = foldLevel(lnum);
3610#endif
3611}
3612
3613/*
3614 * "foldtext()" function
3615 */
3616 static void
3617f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3618{
3619#ifdef FEAT_FOLDING
3620 linenr_T foldstart;
3621 linenr_T foldend;
3622 char_u *dashes;
3623 linenr_T lnum;
3624 char_u *s;
3625 char_u *r;
3626 int len;
3627 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003628 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003629#endif
3630
3631 rettv->v_type = VAR_STRING;
3632 rettv->vval.v_string = NULL;
3633#ifdef FEAT_FOLDING
3634 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3635 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3636 dashes = get_vim_var_str(VV_FOLDDASHES);
3637 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3638 && dashes != NULL)
3639 {
3640 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003641 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003642 if (!linewhite(lnum))
3643 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644
3645 /* Find interesting text in this line. */
3646 s = skipwhite(ml_get(lnum));
3647 /* skip C comment-start */
3648 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3649 {
3650 s = skipwhite(s + 2);
3651 if (*skipwhite(s) == NUL
3652 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3653 {
3654 s = skipwhite(ml_get(lnum + 1));
3655 if (*s == '*')
3656 s = skipwhite(s + 1);
3657 }
3658 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003659 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003660 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661 r = alloc((unsigned)(STRLEN(txt)
3662 + STRLEN(dashes) /* for %s */
3663 + 20 /* for %3ld */
3664 + STRLEN(s))); /* concatenated */
3665 if (r != NULL)
3666 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003667 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003668 len = (int)STRLEN(r);
3669 STRCAT(r, s);
3670 /* remove 'foldmarker' and 'commentstring' */
3671 foldtext_cleanup(r + len);
3672 rettv->vval.v_string = r;
3673 }
3674 }
3675#endif
3676}
3677
3678/*
3679 * "foldtextresult(lnum)" function
3680 */
3681 static void
3682f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3683{
3684#ifdef FEAT_FOLDING
3685 linenr_T lnum;
3686 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003687 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003688 foldinfo_T foldinfo;
3689 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003690 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003691#endif
3692
3693 rettv->v_type = VAR_STRING;
3694 rettv->vval.v_string = NULL;
3695#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003696 if (entered)
3697 return; /* reject recursive use */
3698 entered = TRUE;
3699
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003700 lnum = get_tv_lnum(argvars);
3701 /* treat illegal types and illegal string values for {lnum} the same */
3702 if (lnum < 0)
3703 lnum = 0;
3704 fold_count = foldedCount(curwin, lnum, &foldinfo);
3705 if (fold_count > 0)
3706 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003707 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3708 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003709 if (text == buf)
3710 text = vim_strsave(text);
3711 rettv->vval.v_string = text;
3712 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003713
3714 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003715#endif
3716}
3717
3718/*
3719 * "foreground()" function
3720 */
3721 static void
3722f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3723{
3724#ifdef FEAT_GUI
3725 if (gui.in_use)
3726 gui_mch_set_foreground();
3727#else
3728# ifdef WIN32
3729 win32_set_foreground();
3730# endif
3731#endif
3732}
3733
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003734 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003735common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003736{
3737 char_u *s;
3738 char_u *name;
3739 int use_string = FALSE;
3740 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003741 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742
3743 if (argvars[0].v_type == VAR_FUNC)
3744 {
3745 /* function(MyFunc, [arg], dict) */
3746 s = argvars[0].vval.v_string;
3747 }
3748 else if (argvars[0].v_type == VAR_PARTIAL
3749 && argvars[0].vval.v_partial != NULL)
3750 {
3751 /* function(dict.MyFunc, [arg]) */
3752 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003753 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003754 }
3755 else
3756 {
3757 /* function('MyFunc', [arg], dict) */
3758 s = get_tv_string(&argvars[0]);
3759 use_string = TRUE;
3760 }
3761
Bram Moolenaar843b8842016-08-21 14:36:15 +02003762 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003763 {
3764 name = s;
3765 trans_name = trans_function_name(&name, FALSE,
3766 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3767 if (*name != NUL)
3768 s = NULL;
3769 }
3770
Bram Moolenaar843b8842016-08-21 14:36:15 +02003771 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3772 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003773 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003774 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003775 else if (trans_name != NULL && (is_funcref
3776 ? find_func(trans_name) == NULL
3777 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003778 EMSG2(_("E700: Unknown function: %s"), s);
3779 else
3780 {
3781 int dict_idx = 0;
3782 int arg_idx = 0;
3783 list_T *list = NULL;
3784
3785 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3786 {
3787 char sid_buf[25];
3788 int off = *s == 's' ? 2 : 5;
3789
3790 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3791 * also be called from another script. Using trans_function_name()
3792 * would also work, but some plugins depend on the name being
3793 * printable text. */
3794 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3795 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3796 if (name != NULL)
3797 {
3798 STRCPY(name, sid_buf);
3799 STRCAT(name, s + off);
3800 }
3801 }
3802 else
3803 name = vim_strsave(s);
3804
3805 if (argvars[1].v_type != VAR_UNKNOWN)
3806 {
3807 if (argvars[2].v_type != VAR_UNKNOWN)
3808 {
3809 /* function(name, [args], dict) */
3810 arg_idx = 1;
3811 dict_idx = 2;
3812 }
3813 else if (argvars[1].v_type == VAR_DICT)
3814 /* function(name, dict) */
3815 dict_idx = 1;
3816 else
3817 /* function(name, [args]) */
3818 arg_idx = 1;
3819 if (dict_idx > 0)
3820 {
3821 if (argvars[dict_idx].v_type != VAR_DICT)
3822 {
3823 EMSG(_("E922: expected a dict"));
3824 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003825 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826 }
3827 if (argvars[dict_idx].vval.v_dict == NULL)
3828 dict_idx = 0;
3829 }
3830 if (arg_idx > 0)
3831 {
3832 if (argvars[arg_idx].v_type != VAR_LIST)
3833 {
3834 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3835 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003836 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003837 }
3838 list = argvars[arg_idx].vval.v_list;
3839 if (list == NULL || list->lv_len == 0)
3840 arg_idx = 0;
3841 }
3842 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003843 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003844 {
3845 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3846
3847 /* result is a VAR_PARTIAL */
3848 if (pt == NULL)
3849 vim_free(name);
3850 else
3851 {
3852 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3853 {
3854 listitem_T *li;
3855 int i = 0;
3856 int arg_len = 0;
3857 int lv_len = 0;
3858
3859 if (arg_pt != NULL)
3860 arg_len = arg_pt->pt_argc;
3861 if (list != NULL)
3862 lv_len = list->lv_len;
3863 pt->pt_argc = arg_len + lv_len;
3864 pt->pt_argv = (typval_T *)alloc(
3865 sizeof(typval_T) * pt->pt_argc);
3866 if (pt->pt_argv == NULL)
3867 {
3868 vim_free(pt);
3869 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003870 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003872 for (i = 0; i < arg_len; i++)
3873 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3874 if (lv_len > 0)
3875 for (li = list->lv_first; li != NULL;
3876 li = li->li_next)
3877 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003878 }
3879
3880 /* For "function(dict.func, [], dict)" and "func" is a partial
3881 * use "dict". That is backwards compatible. */
3882 if (dict_idx > 0)
3883 {
3884 /* The dict is bound explicitly, pt_auto is FALSE. */
3885 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3886 ++pt->pt_dict->dv_refcount;
3887 }
3888 else if (arg_pt != NULL)
3889 {
3890 /* If the dict was bound automatically the result is also
3891 * bound automatically. */
3892 pt->pt_dict = arg_pt->pt_dict;
3893 pt->pt_auto = arg_pt->pt_auto;
3894 if (pt->pt_dict != NULL)
3895 ++pt->pt_dict->dv_refcount;
3896 }
3897
3898 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003899 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3900 {
3901 pt->pt_func = arg_pt->pt_func;
3902 func_ptr_ref(pt->pt_func);
3903 vim_free(name);
3904 }
3905 else if (is_funcref)
3906 {
3907 pt->pt_func = find_func(trans_name);
3908 func_ptr_ref(pt->pt_func);
3909 vim_free(name);
3910 }
3911 else
3912 {
3913 pt->pt_name = name;
3914 func_ref(name);
3915 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003916 }
3917 rettv->v_type = VAR_PARTIAL;
3918 rettv->vval.v_partial = pt;
3919 }
3920 else
3921 {
3922 /* result is a VAR_FUNC */
3923 rettv->v_type = VAR_FUNC;
3924 rettv->vval.v_string = name;
3925 func_ref(name);
3926 }
3927 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003928theend:
3929 vim_free(trans_name);
3930}
3931
3932/*
3933 * "funcref()" function
3934 */
3935 static void
3936f_funcref(typval_T *argvars, typval_T *rettv)
3937{
3938 common_function(argvars, rettv, TRUE);
3939}
3940
3941/*
3942 * "function()" function
3943 */
3944 static void
3945f_function(typval_T *argvars, typval_T *rettv)
3946{
3947 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003948}
3949
3950/*
3951 * "garbagecollect()" function
3952 */
3953 static void
3954f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3955{
3956 /* This is postponed until we are back at the toplevel, because we may be
3957 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3958 want_garbage_collect = TRUE;
3959
3960 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3961 garbage_collect_at_exit = TRUE;
3962}
3963
3964/*
3965 * "get()" function
3966 */
3967 static void
3968f_get(typval_T *argvars, typval_T *rettv)
3969{
3970 listitem_T *li;
3971 list_T *l;
3972 dictitem_T *di;
3973 dict_T *d;
3974 typval_T *tv = NULL;
3975
3976 if (argvars[0].v_type == VAR_LIST)
3977 {
3978 if ((l = argvars[0].vval.v_list) != NULL)
3979 {
3980 int error = FALSE;
3981
3982 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3983 if (!error && li != NULL)
3984 tv = &li->li_tv;
3985 }
3986 }
3987 else if (argvars[0].v_type == VAR_DICT)
3988 {
3989 if ((d = argvars[0].vval.v_dict) != NULL)
3990 {
3991 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3992 if (di != NULL)
3993 tv = &di->di_tv;
3994 }
3995 }
3996 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3997 {
3998 partial_T *pt;
3999 partial_T fref_pt;
4000
4001 if (argvars[0].v_type == VAR_PARTIAL)
4002 pt = argvars[0].vval.v_partial;
4003 else
4004 {
4005 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4006 fref_pt.pt_name = argvars[0].vval.v_string;
4007 pt = &fref_pt;
4008 }
4009
4010 if (pt != NULL)
4011 {
4012 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004013 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004014
4015 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4016 {
4017 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004018 n = partial_name(pt);
4019 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 rettv->vval.v_string = NULL;
4021 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004022 {
4023 rettv->vval.v_string = vim_strsave(n);
4024 if (rettv->v_type == VAR_FUNC)
4025 func_ref(rettv->vval.v_string);
4026 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004027 }
4028 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004029 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004030 else if (STRCMP(what, "args") == 0)
4031 {
4032 rettv->v_type = VAR_LIST;
4033 if (rettv_list_alloc(rettv) == OK)
4034 {
4035 int i;
4036
4037 for (i = 0; i < pt->pt_argc; ++i)
4038 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4039 }
4040 }
4041 else
4042 EMSG2(_(e_invarg2), what);
4043 return;
4044 }
4045 }
4046 else
4047 EMSG2(_(e_listdictarg), "get()");
4048
4049 if (tv == NULL)
4050 {
4051 if (argvars[2].v_type != VAR_UNKNOWN)
4052 copy_tv(&argvars[2], rettv);
4053 }
4054 else
4055 copy_tv(tv, rettv);
4056}
4057
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004058#ifdef FEAT_SIGNS
4059/*
4060 * Returns information about signs placed in a buffer as list of dicts.
4061 */
4062 static void
4063get_buffer_signs(buf_T *buf, list_T *l)
4064{
4065 signlist_T *sign;
4066
4067 for (sign = buf->b_signlist; sign; sign = sign->next)
4068 {
4069 dict_T *d = dict_alloc();
4070
4071 if (d != NULL)
4072 {
4073 dict_add_nr_str(d, "id", sign->id, NULL);
4074 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004075 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004076
4077 list_append_dict(l, d);
4078 }
4079 }
4080}
4081#endif
4082
4083/*
4084 * Returns buffer options, variables and other attributes in a dictionary.
4085 */
4086 static dict_T *
4087get_buffer_info(buf_T *buf)
4088{
4089 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004090 tabpage_T *tp;
4091 win_T *wp;
4092 list_T *windows;
4093
4094 dict = dict_alloc();
4095 if (dict == NULL)
4096 return NULL;
4097
Bram Moolenaar33928832016-08-18 21:22:04 +02004098 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004099 dict_add_nr_str(dict, "name", 0L,
4100 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004101 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4102 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004103 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4104 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4105 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004106 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004107 dict_add_nr_str(dict, "hidden",
4108 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4109 NULL);
4110
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004111 /* Get a reference to buffer variables */
4112 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004113
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004114 /* List of windows displaying this buffer */
4115 windows = list_alloc();
4116 if (windows != NULL)
4117 {
4118 FOR_ALL_TAB_WINDOWS(tp, wp)
4119 if (wp->w_buffer == buf)
4120 list_append_number(windows, (varnumber_T)wp->w_id);
4121 dict_add_list(dict, "windows", windows);
4122 }
4123
4124#ifdef FEAT_SIGNS
4125 if (buf->b_signlist != NULL)
4126 {
4127 /* List of signs placed in this buffer */
4128 list_T *signs = list_alloc();
4129 if (signs != NULL)
4130 {
4131 get_buffer_signs(buf, signs);
4132 dict_add_list(dict, "signs", signs);
4133 }
4134 }
4135#endif
4136
4137 return dict;
4138}
4139
4140/*
4141 * "getbufinfo()" function
4142 */
4143 static void
4144f_getbufinfo(typval_T *argvars, typval_T *rettv)
4145{
4146 buf_T *buf = NULL;
4147 buf_T *argbuf = NULL;
4148 dict_T *d;
4149 int filtered = FALSE;
4150 int sel_buflisted = FALSE;
4151 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004152 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004153
4154 if (rettv_list_alloc(rettv) != OK)
4155 return;
4156
4157 /* List of all the buffers or selected buffers */
4158 if (argvars[0].v_type == VAR_DICT)
4159 {
4160 dict_T *sel_d = argvars[0].vval.v_dict;
4161
4162 if (sel_d != NULL)
4163 {
4164 dictitem_T *di;
4165
4166 filtered = TRUE;
4167
4168 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4169 if (di != NULL && get_tv_number(&di->di_tv))
4170 sel_buflisted = TRUE;
4171
4172 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4173 if (di != NULL && get_tv_number(&di->di_tv))
4174 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004175
4176 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4177 if (di != NULL && get_tv_number(&di->di_tv))
4178 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004179 }
4180 }
4181 else if (argvars[0].v_type != VAR_UNKNOWN)
4182 {
4183 /* Information about one buffer. Argument specifies the buffer */
4184 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4185 ++emsg_off;
4186 argbuf = get_buf_tv(&argvars[0], FALSE);
4187 --emsg_off;
4188 if (argbuf == NULL)
4189 return;
4190 }
4191
4192 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004193 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004194 {
4195 if (argbuf != NULL && argbuf != buf)
4196 continue;
4197 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004198 || (sel_buflisted && !buf->b_p_bl)
4199 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004200 continue;
4201
4202 d = get_buffer_info(buf);
4203 if (d != NULL)
4204 list_append_dict(rettv->vval.v_list, d);
4205 if (argbuf != NULL)
4206 return;
4207 }
4208}
4209
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004210static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4211
4212/*
4213 * Get line or list of lines from buffer "buf" into "rettv".
4214 * Return a range (from start to end) of lines in rettv from the specified
4215 * buffer.
4216 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4217 */
4218 static void
4219get_buffer_lines(
4220 buf_T *buf,
4221 linenr_T start,
4222 linenr_T end,
4223 int retlist,
4224 typval_T *rettv)
4225{
4226 char_u *p;
4227
4228 rettv->v_type = VAR_STRING;
4229 rettv->vval.v_string = NULL;
4230 if (retlist && rettv_list_alloc(rettv) == FAIL)
4231 return;
4232
4233 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4234 return;
4235
4236 if (!retlist)
4237 {
4238 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4239 p = ml_get_buf(buf, start, FALSE);
4240 else
4241 p = (char_u *)"";
4242 rettv->vval.v_string = vim_strsave(p);
4243 }
4244 else
4245 {
4246 if (end < start)
4247 return;
4248
4249 if (start < 1)
4250 start = 1;
4251 if (end > buf->b_ml.ml_line_count)
4252 end = buf->b_ml.ml_line_count;
4253 while (start <= end)
4254 if (list_append_string(rettv->vval.v_list,
4255 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4256 break;
4257 }
4258}
4259
4260/*
4261 * Get the lnum from the first argument.
4262 * Also accepts "$", then "buf" is used.
4263 * Returns 0 on error.
4264 */
4265 static linenr_T
4266get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4267{
4268 if (argvars[0].v_type == VAR_STRING
4269 && argvars[0].vval.v_string != NULL
4270 && argvars[0].vval.v_string[0] == '$'
4271 && buf != NULL)
4272 return buf->b_ml.ml_line_count;
4273 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4274}
4275
4276/*
4277 * "getbufline()" function
4278 */
4279 static void
4280f_getbufline(typval_T *argvars, typval_T *rettv)
4281{
4282 linenr_T lnum;
4283 linenr_T end;
4284 buf_T *buf;
4285
4286 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4287 ++emsg_off;
4288 buf = get_buf_tv(&argvars[0], FALSE);
4289 --emsg_off;
4290
4291 lnum = get_tv_lnum_buf(&argvars[1], buf);
4292 if (argvars[2].v_type == VAR_UNKNOWN)
4293 end = lnum;
4294 else
4295 end = get_tv_lnum_buf(&argvars[2], buf);
4296
4297 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4298}
4299
4300/*
4301 * "getbufvar()" function
4302 */
4303 static void
4304f_getbufvar(typval_T *argvars, typval_T *rettv)
4305{
4306 buf_T *buf;
4307 buf_T *save_curbuf;
4308 char_u *varname;
4309 dictitem_T *v;
4310 int done = FALSE;
4311
4312 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4313 varname = get_tv_string_chk(&argvars[1]);
4314 ++emsg_off;
4315 buf = get_buf_tv(&argvars[0], FALSE);
4316
4317 rettv->v_type = VAR_STRING;
4318 rettv->vval.v_string = NULL;
4319
4320 if (buf != NULL && varname != NULL)
4321 {
4322 /* set curbuf to be our buf, temporarily */
4323 save_curbuf = curbuf;
4324 curbuf = buf;
4325
Bram Moolenaar30567352016-08-27 21:25:44 +02004326 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004327 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004328 if (varname[1] == NUL)
4329 {
4330 /* get all buffer-local options in a dict */
4331 dict_T *opts = get_winbuf_options(TRUE);
4332
4333 if (opts != NULL)
4334 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004335 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004336 done = TRUE;
4337 }
4338 }
4339 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4340 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004341 done = TRUE;
4342 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004343 else
4344 {
4345 /* Look up the variable. */
4346 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4347 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4348 'b', varname, FALSE);
4349 if (v != NULL)
4350 {
4351 copy_tv(&v->di_tv, rettv);
4352 done = TRUE;
4353 }
4354 }
4355
4356 /* restore previous notion of curbuf */
4357 curbuf = save_curbuf;
4358 }
4359
4360 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4361 /* use the default value */
4362 copy_tv(&argvars[2], rettv);
4363
4364 --emsg_off;
4365}
4366
4367/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004368 * "getchangelist()" function
4369 */
4370 static void
4371f_getchangelist(typval_T *argvars, typval_T *rettv)
4372{
4373#ifdef FEAT_JUMPLIST
4374 buf_T *buf;
4375 int i;
4376 list_T *l;
4377 dict_T *d;
4378#endif
4379
4380 if (rettv_list_alloc(rettv) != OK)
4381 return;
4382
4383#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004384 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4385 ++emsg_off;
4386 buf = get_buf_tv(&argvars[0], FALSE);
4387 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004388 if (buf == NULL)
4389 return;
4390
4391 l = list_alloc();
4392 if (l == NULL)
4393 return;
4394
4395 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4396 return;
4397 /*
4398 * The current window change list index tracks only the position in the
4399 * current buffer change list. For other buffers, use the change list
4400 * length as the current index.
4401 */
4402 list_append_number(rettv->vval.v_list,
4403 (varnumber_T)((buf == curwin->w_buffer)
4404 ? curwin->w_changelistidx : buf->b_changelistlen));
4405
4406 for (i = 0; i < buf->b_changelistlen; ++i)
4407 {
4408 if (buf->b_changelist[i].lnum == 0)
4409 continue;
4410 if ((d = dict_alloc()) == NULL)
4411 return;
4412 if (list_append_dict(l, d) == FAIL)
4413 return;
4414 dict_add_nr_str(d, "lnum", (long)buf->b_changelist[i].lnum, NULL);
4415 dict_add_nr_str(d, "col", (long)buf->b_changelist[i].col, NULL);
4416# ifdef FEAT_VIRTUALEDIT
4417 dict_add_nr_str(d, "coladd", (long)buf->b_changelist[i].coladd, NULL);
4418# endif
4419 }
4420#endif
4421}
4422/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004423 * "getchar()" function
4424 */
4425 static void
4426f_getchar(typval_T *argvars, typval_T *rettv)
4427{
4428 varnumber_T n;
4429 int error = FALSE;
4430
4431 /* Position the cursor. Needed after a message that ends in a space. */
4432 windgoto(msg_row, msg_col);
4433
4434 ++no_mapping;
4435 ++allow_keys;
4436 for (;;)
4437 {
4438 if (argvars[0].v_type == VAR_UNKNOWN)
4439 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004440 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004441 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4442 /* getchar(1): only check if char avail */
4443 n = vpeekc_any();
4444 else if (error || vpeekc_any() == NUL)
4445 /* illegal argument or getchar(0) and no char avail: return zero */
4446 n = 0;
4447 else
4448 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004449 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004450
4451 if (n == K_IGNORE)
4452 continue;
4453 break;
4454 }
4455 --no_mapping;
4456 --allow_keys;
4457
4458 set_vim_var_nr(VV_MOUSE_WIN, 0);
4459 set_vim_var_nr(VV_MOUSE_WINID, 0);
4460 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4461 set_vim_var_nr(VV_MOUSE_COL, 0);
4462
4463 rettv->vval.v_number = n;
4464 if (IS_SPECIAL(n) || mod_mask != 0)
4465 {
4466 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4467 int i = 0;
4468
4469 /* Turn a special key into three bytes, plus modifier. */
4470 if (mod_mask != 0)
4471 {
4472 temp[i++] = K_SPECIAL;
4473 temp[i++] = KS_MODIFIER;
4474 temp[i++] = mod_mask;
4475 }
4476 if (IS_SPECIAL(n))
4477 {
4478 temp[i++] = K_SPECIAL;
4479 temp[i++] = K_SECOND(n);
4480 temp[i++] = K_THIRD(n);
4481 }
4482#ifdef FEAT_MBYTE
4483 else if (has_mbyte)
4484 i += (*mb_char2bytes)(n, temp + i);
4485#endif
4486 else
4487 temp[i++] = n;
4488 temp[i++] = NUL;
4489 rettv->v_type = VAR_STRING;
4490 rettv->vval.v_string = vim_strsave(temp);
4491
4492#ifdef FEAT_MOUSE
4493 if (is_mouse_key(n))
4494 {
4495 int row = mouse_row;
4496 int col = mouse_col;
4497 win_T *win;
4498 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004499 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004500 int winnr = 1;
4501
4502 if (row >= 0 && col >= 0)
4503 {
4504 /* Find the window at the mouse coordinates and compute the
4505 * text position. */
4506 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004507 if (win == NULL)
4508 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004509 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004510 for (wp = firstwin; wp != win; wp = wp->w_next)
4511 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004512 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4513 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4514 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4515 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4516 }
4517 }
4518#endif
4519 }
4520}
4521
4522/*
4523 * "getcharmod()" function
4524 */
4525 static void
4526f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4527{
4528 rettv->vval.v_number = mod_mask;
4529}
4530
4531/*
4532 * "getcharsearch()" function
4533 */
4534 static void
4535f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4536{
4537 if (rettv_dict_alloc(rettv) != FAIL)
4538 {
4539 dict_T *dict = rettv->vval.v_dict;
4540
4541 dict_add_nr_str(dict, "char", 0L, last_csearch());
4542 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4543 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4544 }
4545}
4546
4547/*
4548 * "getcmdline()" function
4549 */
4550 static void
4551f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4552{
4553 rettv->v_type = VAR_STRING;
4554 rettv->vval.v_string = get_cmdline_str();
4555}
4556
4557/*
4558 * "getcmdpos()" function
4559 */
4560 static void
4561f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4562{
4563 rettv->vval.v_number = get_cmdline_pos() + 1;
4564}
4565
4566/*
4567 * "getcmdtype()" function
4568 */
4569 static void
4570f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4571{
4572 rettv->v_type = VAR_STRING;
4573 rettv->vval.v_string = alloc(2);
4574 if (rettv->vval.v_string != NULL)
4575 {
4576 rettv->vval.v_string[0] = get_cmdline_type();
4577 rettv->vval.v_string[1] = NUL;
4578 }
4579}
4580
4581/*
4582 * "getcmdwintype()" function
4583 */
4584 static void
4585f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4586{
4587 rettv->v_type = VAR_STRING;
4588 rettv->vval.v_string = NULL;
4589#ifdef FEAT_CMDWIN
4590 rettv->vval.v_string = alloc(2);
4591 if (rettv->vval.v_string != NULL)
4592 {
4593 rettv->vval.v_string[0] = cmdwin_type;
4594 rettv->vval.v_string[1] = NUL;
4595 }
4596#endif
4597}
4598
4599#if defined(FEAT_CMDL_COMPL)
4600/*
4601 * "getcompletion()" function
4602 */
4603 static void
4604f_getcompletion(typval_T *argvars, typval_T *rettv)
4605{
4606 char_u *pat;
4607 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004608 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004609 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4610 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004612 if (argvars[2].v_type != VAR_UNKNOWN)
4613 filtered = get_tv_number_chk(&argvars[2], NULL);
4614
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004615 if (p_wic)
4616 options |= WILD_ICASE;
4617
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004618 /* For filtered results, 'wildignore' is used */
4619 if (!filtered)
4620 options |= WILD_KEEP_ALL;
4621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622 ExpandInit(&xpc);
4623 xpc.xp_pattern = get_tv_string(&argvars[0]);
4624 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4625 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4626 if (xpc.xp_context == EXPAND_NOTHING)
4627 {
4628 if (argvars[1].v_type == VAR_STRING)
4629 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4630 else
4631 EMSG(_(e_invarg));
4632 return;
4633 }
4634
4635# if defined(FEAT_MENU)
4636 if (xpc.xp_context == EXPAND_MENUS)
4637 {
4638 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4639 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4640 }
4641# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004642#ifdef FEAT_CSCOPE
4643 if (xpc.xp_context == EXPAND_CSCOPE)
4644 {
4645 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4646 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4647 }
4648#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004649#ifdef FEAT_SIGNS
4650 if (xpc.xp_context == EXPAND_SIGN)
4651 {
4652 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4653 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4654 }
4655#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004656
4657 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4658 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4659 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004660 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661
4662 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4663
4664 for (i = 0; i < xpc.xp_numfiles; i++)
4665 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4666 }
4667 vim_free(pat);
4668 ExpandCleanup(&xpc);
4669}
4670#endif
4671
4672/*
4673 * "getcwd()" function
4674 */
4675 static void
4676f_getcwd(typval_T *argvars, typval_T *rettv)
4677{
4678 win_T *wp = NULL;
4679 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004680 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004681
4682 rettv->v_type = VAR_STRING;
4683 rettv->vval.v_string = NULL;
4684
Bram Moolenaar54591292018-02-09 20:53:59 +01004685 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4686 global = TRUE;
4687 else
4688 wp = find_tabwin(&argvars[0], &argvars[1]);
4689
4690 if (wp != NULL && wp->w_localdir != NULL)
4691 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4692 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004694 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004695 rettv->vval.v_string = vim_strsave(globaldir);
4696 else
4697 {
4698 cwd = alloc(MAXPATHL);
4699 if (cwd != NULL)
4700 {
4701 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4702 rettv->vval.v_string = vim_strsave(cwd);
4703 vim_free(cwd);
4704 }
4705 }
4706#ifdef BACKSLASH_IN_FILENAME
4707 if (rettv->vval.v_string != NULL)
4708 slash_adjust(rettv->vval.v_string);
4709#endif
4710 }
4711}
4712
4713/*
4714 * "getfontname()" function
4715 */
4716 static void
4717f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4718{
4719 rettv->v_type = VAR_STRING;
4720 rettv->vval.v_string = NULL;
4721#ifdef FEAT_GUI
4722 if (gui.in_use)
4723 {
4724 GuiFont font;
4725 char_u *name = NULL;
4726
4727 if (argvars[0].v_type == VAR_UNKNOWN)
4728 {
4729 /* Get the "Normal" font. Either the name saved by
4730 * hl_set_font_name() or from the font ID. */
4731 font = gui.norm_font;
4732 name = hl_get_font_name();
4733 }
4734 else
4735 {
4736 name = get_tv_string(&argvars[0]);
4737 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4738 return;
4739 font = gui_mch_get_font(name, FALSE);
4740 if (font == NOFONT)
4741 return; /* Invalid font name, return empty string. */
4742 }
4743 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4744 if (argvars[0].v_type != VAR_UNKNOWN)
4745 gui_mch_free_font(font);
4746 }
4747#endif
4748}
4749
4750/*
4751 * "getfperm({fname})" function
4752 */
4753 static void
4754f_getfperm(typval_T *argvars, typval_T *rettv)
4755{
4756 char_u *fname;
4757 stat_T st;
4758 char_u *perm = NULL;
4759 char_u flags[] = "rwx";
4760 int i;
4761
4762 fname = get_tv_string(&argvars[0]);
4763
4764 rettv->v_type = VAR_STRING;
4765 if (mch_stat((char *)fname, &st) >= 0)
4766 {
4767 perm = vim_strsave((char_u *)"---------");
4768 if (perm != NULL)
4769 {
4770 for (i = 0; i < 9; i++)
4771 {
4772 if (st.st_mode & (1 << (8 - i)))
4773 perm[i] = flags[i % 3];
4774 }
4775 }
4776 }
4777 rettv->vval.v_string = perm;
4778}
4779
4780/*
4781 * "getfsize({fname})" function
4782 */
4783 static void
4784f_getfsize(typval_T *argvars, typval_T *rettv)
4785{
4786 char_u *fname;
4787 stat_T st;
4788
4789 fname = get_tv_string(&argvars[0]);
4790
4791 rettv->v_type = VAR_NUMBER;
4792
4793 if (mch_stat((char *)fname, &st) >= 0)
4794 {
4795 if (mch_isdir(fname))
4796 rettv->vval.v_number = 0;
4797 else
4798 {
4799 rettv->vval.v_number = (varnumber_T)st.st_size;
4800
4801 /* non-perfect check for overflow */
4802 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4803 rettv->vval.v_number = -2;
4804 }
4805 }
4806 else
4807 rettv->vval.v_number = -1;
4808}
4809
4810/*
4811 * "getftime({fname})" function
4812 */
4813 static void
4814f_getftime(typval_T *argvars, typval_T *rettv)
4815{
4816 char_u *fname;
4817 stat_T st;
4818
4819 fname = get_tv_string(&argvars[0]);
4820
4821 if (mch_stat((char *)fname, &st) >= 0)
4822 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4823 else
4824 rettv->vval.v_number = -1;
4825}
4826
4827/*
4828 * "getftype({fname})" function
4829 */
4830 static void
4831f_getftype(typval_T *argvars, typval_T *rettv)
4832{
4833 char_u *fname;
4834 stat_T st;
4835 char_u *type = NULL;
4836 char *t;
4837
4838 fname = get_tv_string(&argvars[0]);
4839
4840 rettv->v_type = VAR_STRING;
4841 if (mch_lstat((char *)fname, &st) >= 0)
4842 {
4843#ifdef S_ISREG
4844 if (S_ISREG(st.st_mode))
4845 t = "file";
4846 else if (S_ISDIR(st.st_mode))
4847 t = "dir";
4848# ifdef S_ISLNK
4849 else if (S_ISLNK(st.st_mode))
4850 t = "link";
4851# endif
4852# ifdef S_ISBLK
4853 else if (S_ISBLK(st.st_mode))
4854 t = "bdev";
4855# endif
4856# ifdef S_ISCHR
4857 else if (S_ISCHR(st.st_mode))
4858 t = "cdev";
4859# endif
4860# ifdef S_ISFIFO
4861 else if (S_ISFIFO(st.st_mode))
4862 t = "fifo";
4863# endif
4864# ifdef S_ISSOCK
4865 else if (S_ISSOCK(st.st_mode))
4866 t = "fifo";
4867# endif
4868 else
4869 t = "other";
4870#else
4871# ifdef S_IFMT
4872 switch (st.st_mode & S_IFMT)
4873 {
4874 case S_IFREG: t = "file"; break;
4875 case S_IFDIR: t = "dir"; break;
4876# ifdef S_IFLNK
4877 case S_IFLNK: t = "link"; break;
4878# endif
4879# ifdef S_IFBLK
4880 case S_IFBLK: t = "bdev"; break;
4881# endif
4882# ifdef S_IFCHR
4883 case S_IFCHR: t = "cdev"; break;
4884# endif
4885# ifdef S_IFIFO
4886 case S_IFIFO: t = "fifo"; break;
4887# endif
4888# ifdef S_IFSOCK
4889 case S_IFSOCK: t = "socket"; break;
4890# endif
4891 default: t = "other";
4892 }
4893# else
4894 if (mch_isdir(fname))
4895 t = "dir";
4896 else
4897 t = "file";
4898# endif
4899#endif
4900 type = vim_strsave((char_u *)t);
4901 }
4902 rettv->vval.v_string = type;
4903}
4904
4905/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004906 * "getjumplist()" function
4907 */
4908 static void
4909f_getjumplist(typval_T *argvars, typval_T *rettv)
4910{
4911#ifdef FEAT_JUMPLIST
4912 win_T *wp;
4913 int i;
4914 list_T *l;
4915 dict_T *d;
4916#endif
4917
4918 if (rettv_list_alloc(rettv) != OK)
4919 return;
4920
4921#ifdef FEAT_JUMPLIST
4922 wp = find_tabwin(&argvars[0], &argvars[1]);
4923 if (wp == NULL)
4924 return;
4925
4926 l = list_alloc();
4927 if (l == NULL)
4928 return;
4929
4930 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4931 return;
4932 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4933
Bram Moolenaar48679742018-02-13 13:33:29 +01004934 cleanup_jumplist(wp, TRUE);
4935
Bram Moolenaar4f505882018-02-10 21:06:32 +01004936 for (i = 0; i < wp->w_jumplistlen; ++i)
4937 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004938 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4939 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004940 if ((d = dict_alloc()) == NULL)
4941 return;
4942 if (list_append_dict(l, d) == FAIL)
4943 return;
4944 dict_add_nr_str(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum,
4945 NULL);
4946 dict_add_nr_str(d, "col", (long)wp->w_jumplist[i].fmark.mark.col,
4947 NULL);
4948# ifdef FEAT_VIRTUALEDIT
4949 dict_add_nr_str(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd,
4950 NULL);
4951# endif
4952 dict_add_nr_str(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum, NULL);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004953 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaar4f505882018-02-10 21:06:32 +01004954 dict_add_nr_str(d, "filename", 0L, wp->w_jumplist[i].fname);
4955 }
4956#endif
4957}
4958
4959/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004960 * "getline(lnum, [end])" function
4961 */
4962 static void
4963f_getline(typval_T *argvars, typval_T *rettv)
4964{
4965 linenr_T lnum;
4966 linenr_T end;
4967 int retlist;
4968
4969 lnum = get_tv_lnum(argvars);
4970 if (argvars[1].v_type == VAR_UNKNOWN)
4971 {
4972 end = 0;
4973 retlist = FALSE;
4974 }
4975 else
4976 {
4977 end = get_tv_lnum(&argvars[1]);
4978 retlist = TRUE;
4979 }
4980
4981 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4982}
4983
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004984#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004985 static void
4986get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4987{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004988 if (what_arg->v_type == VAR_UNKNOWN)
4989 {
4990 if (rettv_list_alloc(rettv) == OK)
4991 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004992 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004993 }
4994 else
4995 {
4996 if (rettv_dict_alloc(rettv) == OK)
4997 if (is_qf || (wp != NULL))
4998 {
4999 if (what_arg->v_type == VAR_DICT)
5000 {
5001 dict_T *d = what_arg->vval.v_dict;
5002
5003 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005004 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005005 }
5006 else
5007 EMSG(_(e_dictreq));
5008 }
5009 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005010}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005011#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005012
5013/*
5014 * "getloclist()" function
5015 */
5016 static void
5017f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5018{
5019#ifdef FEAT_QUICKFIX
5020 win_T *wp;
5021
5022 wp = find_win_by_nr(&argvars[0], NULL);
5023 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5024#endif
5025}
5026
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005027/*
5028 * "getmatches()" function
5029 */
5030 static void
5031f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5032{
5033#ifdef FEAT_SEARCH_EXTRA
5034 dict_T *dict;
5035 matchitem_T *cur = curwin->w_match_head;
5036 int i;
5037
5038 if (rettv_list_alloc(rettv) == OK)
5039 {
5040 while (cur != NULL)
5041 {
5042 dict = dict_alloc();
5043 if (dict == NULL)
5044 return;
5045 if (cur->match.regprog == NULL)
5046 {
5047 /* match added with matchaddpos() */
5048 for (i = 0; i < MAXPOSMATCH; ++i)
5049 {
5050 llpos_T *llpos;
5051 char buf[6];
5052 list_T *l;
5053
5054 llpos = &cur->pos.pos[i];
5055 if (llpos->lnum == 0)
5056 break;
5057 l = list_alloc();
5058 if (l == NULL)
5059 break;
5060 list_append_number(l, (varnumber_T)llpos->lnum);
5061 if (llpos->col > 0)
5062 {
5063 list_append_number(l, (varnumber_T)llpos->col);
5064 list_append_number(l, (varnumber_T)llpos->len);
5065 }
5066 sprintf(buf, "pos%d", i + 1);
5067 dict_add_list(dict, buf, l);
5068 }
5069 }
5070 else
5071 {
5072 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
5073 }
5074 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
5075 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
5076 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
5077# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5078 if (cur->conceal_char)
5079 {
5080 char_u buf[MB_MAXBYTES + 1];
5081
5082 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5083 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
5084 }
5085# endif
5086 list_append_dict(rettv->vval.v_list, dict);
5087 cur = cur->next;
5088 }
5089 }
5090#endif
5091}
5092
5093/*
5094 * "getpid()" function
5095 */
5096 static void
5097f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5098{
5099 rettv->vval.v_number = mch_get_pid();
5100}
5101
5102 static void
5103getpos_both(
5104 typval_T *argvars,
5105 typval_T *rettv,
5106 int getcurpos)
5107{
5108 pos_T *fp;
5109 list_T *l;
5110 int fnum = -1;
5111
5112 if (rettv_list_alloc(rettv) == OK)
5113 {
5114 l = rettv->vval.v_list;
5115 if (getcurpos)
5116 fp = &curwin->w_cursor;
5117 else
5118 fp = var2fpos(&argvars[0], TRUE, &fnum);
5119 if (fnum != -1)
5120 list_append_number(l, (varnumber_T)fnum);
5121 else
5122 list_append_number(l, (varnumber_T)0);
5123 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5124 : (varnumber_T)0);
5125 list_append_number(l, (fp != NULL)
5126 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5127 : (varnumber_T)0);
5128 list_append_number(l,
5129#ifdef FEAT_VIRTUALEDIT
5130 (fp != NULL) ? (varnumber_T)fp->coladd :
5131#endif
5132 (varnumber_T)0);
5133 if (getcurpos)
5134 {
5135 update_curswant();
5136 list_append_number(l, curwin->w_curswant == MAXCOL ?
5137 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5138 }
5139 }
5140 else
5141 rettv->vval.v_number = FALSE;
5142}
5143
5144
5145/*
5146 * "getcurpos()" function
5147 */
5148 static void
5149f_getcurpos(typval_T *argvars, typval_T *rettv)
5150{
5151 getpos_both(argvars, rettv, TRUE);
5152}
5153
5154/*
5155 * "getpos(string)" function
5156 */
5157 static void
5158f_getpos(typval_T *argvars, typval_T *rettv)
5159{
5160 getpos_both(argvars, rettv, FALSE);
5161}
5162
5163/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005164 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005165 */
5166 static void
5167f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5168{
5169#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005170 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171#endif
5172}
5173
5174/*
5175 * "getreg()" function
5176 */
5177 static void
5178f_getreg(typval_T *argvars, typval_T *rettv)
5179{
5180 char_u *strregname;
5181 int regname;
5182 int arg2 = FALSE;
5183 int return_list = FALSE;
5184 int error = FALSE;
5185
5186 if (argvars[0].v_type != VAR_UNKNOWN)
5187 {
5188 strregname = get_tv_string_chk(&argvars[0]);
5189 error = strregname == NULL;
5190 if (argvars[1].v_type != VAR_UNKNOWN)
5191 {
5192 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5193 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5194 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5195 }
5196 }
5197 else
5198 strregname = get_vim_var_str(VV_REG);
5199
5200 if (error)
5201 return;
5202
5203 regname = (strregname == NULL ? '"' : *strregname);
5204 if (regname == 0)
5205 regname = '"';
5206
5207 if (return_list)
5208 {
5209 rettv->v_type = VAR_LIST;
5210 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5211 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5212 if (rettv->vval.v_list == NULL)
5213 (void)rettv_list_alloc(rettv);
5214 else
5215 ++rettv->vval.v_list->lv_refcount;
5216 }
5217 else
5218 {
5219 rettv->v_type = VAR_STRING;
5220 rettv->vval.v_string = get_reg_contents(regname,
5221 arg2 ? GREG_EXPR_SRC : 0);
5222 }
5223}
5224
5225/*
5226 * "getregtype()" function
5227 */
5228 static void
5229f_getregtype(typval_T *argvars, typval_T *rettv)
5230{
5231 char_u *strregname;
5232 int regname;
5233 char_u buf[NUMBUFLEN + 2];
5234 long reglen = 0;
5235
5236 if (argvars[0].v_type != VAR_UNKNOWN)
5237 {
5238 strregname = get_tv_string_chk(&argvars[0]);
5239 if (strregname == NULL) /* type error; errmsg already given */
5240 {
5241 rettv->v_type = VAR_STRING;
5242 rettv->vval.v_string = NULL;
5243 return;
5244 }
5245 }
5246 else
5247 /* Default to v:register */
5248 strregname = get_vim_var_str(VV_REG);
5249
5250 regname = (strregname == NULL ? '"' : *strregname);
5251 if (regname == 0)
5252 regname = '"';
5253
5254 buf[0] = NUL;
5255 buf[1] = NUL;
5256 switch (get_reg_type(regname, &reglen))
5257 {
5258 case MLINE: buf[0] = 'V'; break;
5259 case MCHAR: buf[0] = 'v'; break;
5260 case MBLOCK:
5261 buf[0] = Ctrl_V;
5262 sprintf((char *)buf + 1, "%ld", reglen + 1);
5263 break;
5264 }
5265 rettv->v_type = VAR_STRING;
5266 rettv->vval.v_string = vim_strsave(buf);
5267}
5268
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005269/*
5270 * Returns information (variables, options, etc.) about a tab page
5271 * as a dictionary.
5272 */
5273 static dict_T *
5274get_tabpage_info(tabpage_T *tp, int tp_idx)
5275{
5276 win_T *wp;
5277 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005278 list_T *l;
5279
5280 dict = dict_alloc();
5281 if (dict == NULL)
5282 return NULL;
5283
Bram Moolenaar33928832016-08-18 21:22:04 +02005284 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005285
5286 l = list_alloc();
5287 if (l != NULL)
5288 {
5289 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5290 wp; wp = wp->w_next)
5291 list_append_number(l, (varnumber_T)wp->w_id);
5292 dict_add_list(dict, "windows", l);
5293 }
5294
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005295 /* Make a reference to tabpage variables */
5296 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005297
5298 return dict;
5299}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005300
5301/*
5302 * "gettabinfo()" function
5303 */
5304 static void
5305f_gettabinfo(typval_T *argvars, typval_T *rettv)
5306{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005307 tabpage_T *tp, *tparg = NULL;
5308 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005309 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005310
5311 if (rettv_list_alloc(rettv) != OK)
5312 return;
5313
5314 if (argvars[0].v_type != VAR_UNKNOWN)
5315 {
5316 /* Information about one tab page */
5317 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5318 if (tparg == NULL)
5319 return;
5320 }
5321
5322 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005323 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005324 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005325 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005326 if (tparg != NULL && tp != tparg)
5327 continue;
5328 d = get_tabpage_info(tp, tpnr);
5329 if (d != NULL)
5330 list_append_dict(rettv->vval.v_list, d);
5331 if (tparg != NULL)
5332 return;
5333 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005334}
5335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005336/*
5337 * "gettabvar()" function
5338 */
5339 static void
5340f_gettabvar(typval_T *argvars, typval_T *rettv)
5341{
5342 win_T *oldcurwin;
5343 tabpage_T *tp, *oldtabpage;
5344 dictitem_T *v;
5345 char_u *varname;
5346 int done = FALSE;
5347
5348 rettv->v_type = VAR_STRING;
5349 rettv->vval.v_string = NULL;
5350
5351 varname = get_tv_string_chk(&argvars[1]);
5352 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5353 if (tp != NULL && varname != NULL)
5354 {
5355 /* Set tp to be our tabpage, temporarily. Also set the window to the
5356 * first window in the tabpage, otherwise the window is not valid. */
5357 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005358 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5359 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005360 {
5361 /* look up the variable */
5362 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5363 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5364 if (v != NULL)
5365 {
5366 copy_tv(&v->di_tv, rettv);
5367 done = TRUE;
5368 }
5369 }
5370
5371 /* restore previous notion of curwin */
5372 restore_win(oldcurwin, oldtabpage, TRUE);
5373 }
5374
5375 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5376 copy_tv(&argvars[2], rettv);
5377}
5378
5379/*
5380 * "gettabwinvar()" function
5381 */
5382 static void
5383f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5384{
5385 getwinvar(argvars, rettv, 1);
5386}
5387
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005388/*
5389 * Returns information about a window as a dictionary.
5390 */
5391 static dict_T *
5392get_win_info(win_T *wp, short tpnr, short winnr)
5393{
5394 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005395
5396 dict = dict_alloc();
5397 if (dict == NULL)
5398 return NULL;
5399
Bram Moolenaar33928832016-08-18 21:22:04 +02005400 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5401 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005402 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5403 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005404#ifdef FEAT_MENU
5405 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5406#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005407 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005408 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005409
Bram Moolenaar69905d12017-08-13 18:14:47 +02005410#ifdef FEAT_TERMINAL
5411 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5412#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005413#ifdef FEAT_QUICKFIX
5414 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5415 dict_add_nr_str(dict, "loclist",
5416 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5417#endif
5418
Bram Moolenaar30567352016-08-27 21:25:44 +02005419 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005420 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005421
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005422 return dict;
5423}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005424
5425/*
5426 * "getwininfo()" function
5427 */
5428 static void
5429f_getwininfo(typval_T *argvars, typval_T *rettv)
5430{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005431 tabpage_T *tp;
5432 win_T *wp = NULL, *wparg = NULL;
5433 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005434 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005435
5436 if (rettv_list_alloc(rettv) != OK)
5437 return;
5438
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005439 if (argvars[0].v_type != VAR_UNKNOWN)
5440 {
5441 wparg = win_id2wp(argvars);
5442 if (wparg == NULL)
5443 return;
5444 }
5445
5446 /* Collect information about either all the windows across all the tab
5447 * pages or one particular window.
5448 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005449 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005450 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005451 tabnr++;
5452 winnr = 0;
5453 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005454 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005455 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005456 if (wparg != NULL && wp != wparg)
5457 continue;
5458 d = get_win_info(wp, tabnr, winnr);
5459 if (d != NULL)
5460 list_append_dict(rettv->vval.v_list, d);
5461 if (wparg != NULL)
5462 /* found information about a specific window */
5463 return;
5464 }
5465 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005466}
5467
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005468/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005469 * "win_findbuf()" function
5470 */
5471 static void
5472f_win_findbuf(typval_T *argvars, typval_T *rettv)
5473{
5474 if (rettv_list_alloc(rettv) != FAIL)
5475 win_findbuf(argvars, rettv->vval.v_list);
5476}
5477
5478/*
5479 * "win_getid()" function
5480 */
5481 static void
5482f_win_getid(typval_T *argvars, typval_T *rettv)
5483{
5484 rettv->vval.v_number = win_getid(argvars);
5485}
5486
5487/*
5488 * "win_gotoid()" function
5489 */
5490 static void
5491f_win_gotoid(typval_T *argvars, typval_T *rettv)
5492{
5493 rettv->vval.v_number = win_gotoid(argvars);
5494}
5495
5496/*
5497 * "win_id2tabwin()" function
5498 */
5499 static void
5500f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5501{
5502 if (rettv_list_alloc(rettv) != FAIL)
5503 win_id2tabwin(argvars, rettv->vval.v_list);
5504}
5505
5506/*
5507 * "win_id2win()" function
5508 */
5509 static void
5510f_win_id2win(typval_T *argvars, typval_T *rettv)
5511{
5512 rettv->vval.v_number = win_id2win(argvars);
5513}
5514
5515/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005516 * "win_screenpos()" function
5517 */
5518 static void
5519f_win_screenpos(typval_T *argvars, typval_T *rettv)
5520{
5521 win_T *wp;
5522
5523 if (rettv_list_alloc(rettv) == FAIL)
5524 return;
5525
5526 wp = find_win_by_nr(&argvars[0], NULL);
5527 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5528 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5529}
5530
5531/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005532 * "getwinpos({timeout})" function
5533 */
5534 static void
5535f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5536{
5537 int x = -1;
5538 int y = -1;
5539
5540 if (rettv_list_alloc(rettv) == FAIL)
5541 return;
5542#ifdef FEAT_GUI
5543 if (gui.in_use)
5544 gui_mch_get_winpos(&x, &y);
5545# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5546 else
5547# endif
5548#endif
5549#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5550 {
5551 varnumber_T timeout = 100;
5552
5553 if (argvars[0].v_type != VAR_UNKNOWN)
5554 timeout = get_tv_number(&argvars[0]);
5555 term_get_winpos(&x, &y, timeout);
5556 }
5557#endif
5558 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5559 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5560}
5561
5562
5563/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005564 * "getwinposx()" function
5565 */
5566 static void
5567f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5568{
5569 rettv->vval.v_number = -1;
5570#ifdef FEAT_GUI
5571 if (gui.in_use)
5572 {
5573 int x, y;
5574
5575 if (gui_mch_get_winpos(&x, &y) == OK)
5576 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005577 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005578 }
5579#endif
5580#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5581 {
5582 int x, y;
5583
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005584 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005585 rettv->vval.v_number = x;
5586 }
5587#endif
5588}
5589
5590/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005591 * "getwinposy()" function
5592 */
5593 static void
5594f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5595{
5596 rettv->vval.v_number = -1;
5597#ifdef FEAT_GUI
5598 if (gui.in_use)
5599 {
5600 int x, y;
5601
5602 if (gui_mch_get_winpos(&x, &y) == OK)
5603 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005604 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605 }
5606#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005607#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5608 {
5609 int x, y;
5610
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005611 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005612 rettv->vval.v_number = y;
5613 }
5614#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005615}
5616
5617/*
5618 * "getwinvar()" function
5619 */
5620 static void
5621f_getwinvar(typval_T *argvars, typval_T *rettv)
5622{
5623 getwinvar(argvars, rettv, 0);
5624}
5625
5626/*
5627 * "glob()" function
5628 */
5629 static void
5630f_glob(typval_T *argvars, typval_T *rettv)
5631{
5632 int options = WILD_SILENT|WILD_USE_NL;
5633 expand_T xpc;
5634 int error = FALSE;
5635
5636 /* When the optional second argument is non-zero, don't remove matches
5637 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5638 rettv->v_type = VAR_STRING;
5639 if (argvars[1].v_type != VAR_UNKNOWN)
5640 {
5641 if (get_tv_number_chk(&argvars[1], &error))
5642 options |= WILD_KEEP_ALL;
5643 if (argvars[2].v_type != VAR_UNKNOWN)
5644 {
5645 if (get_tv_number_chk(&argvars[2], &error))
5646 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005647 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648 }
5649 if (argvars[3].v_type != VAR_UNKNOWN
5650 && get_tv_number_chk(&argvars[3], &error))
5651 options |= WILD_ALLLINKS;
5652 }
5653 }
5654 if (!error)
5655 {
5656 ExpandInit(&xpc);
5657 xpc.xp_context = EXPAND_FILES;
5658 if (p_wic)
5659 options += WILD_ICASE;
5660 if (rettv->v_type == VAR_STRING)
5661 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5662 NULL, options, WILD_ALL);
5663 else if (rettv_list_alloc(rettv) != FAIL)
5664 {
5665 int i;
5666
5667 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5668 NULL, options, WILD_ALL_KEEP);
5669 for (i = 0; i < xpc.xp_numfiles; i++)
5670 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5671
5672 ExpandCleanup(&xpc);
5673 }
5674 }
5675 else
5676 rettv->vval.v_string = NULL;
5677}
5678
5679/*
5680 * "globpath()" function
5681 */
5682 static void
5683f_globpath(typval_T *argvars, typval_T *rettv)
5684{
5685 int flags = 0;
5686 char_u buf1[NUMBUFLEN];
5687 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5688 int error = FALSE;
5689 garray_T ga;
5690 int i;
5691
5692 /* When the optional second argument is non-zero, don't remove matches
5693 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5694 rettv->v_type = VAR_STRING;
5695 if (argvars[2].v_type != VAR_UNKNOWN)
5696 {
5697 if (get_tv_number_chk(&argvars[2], &error))
5698 flags |= WILD_KEEP_ALL;
5699 if (argvars[3].v_type != VAR_UNKNOWN)
5700 {
5701 if (get_tv_number_chk(&argvars[3], &error))
5702 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005703 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005704 }
5705 if (argvars[4].v_type != VAR_UNKNOWN
5706 && get_tv_number_chk(&argvars[4], &error))
5707 flags |= WILD_ALLLINKS;
5708 }
5709 }
5710 if (file != NULL && !error)
5711 {
5712 ga_init2(&ga, (int)sizeof(char_u *), 10);
5713 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5714 if (rettv->v_type == VAR_STRING)
5715 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5716 else if (rettv_list_alloc(rettv) != FAIL)
5717 for (i = 0; i < ga.ga_len; ++i)
5718 list_append_string(rettv->vval.v_list,
5719 ((char_u **)(ga.ga_data))[i], -1);
5720 ga_clear_strings(&ga);
5721 }
5722 else
5723 rettv->vval.v_string = NULL;
5724}
5725
5726/*
5727 * "glob2regpat()" function
5728 */
5729 static void
5730f_glob2regpat(typval_T *argvars, typval_T *rettv)
5731{
5732 char_u *pat = get_tv_string_chk(&argvars[0]);
5733
5734 rettv->v_type = VAR_STRING;
5735 rettv->vval.v_string = (pat == NULL)
5736 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5737}
5738
5739/* for VIM_VERSION_ defines */
5740#include "version.h"
5741
5742/*
5743 * "has()" function
5744 */
5745 static void
5746f_has(typval_T *argvars, typval_T *rettv)
5747{
5748 int i;
5749 char_u *name;
5750 int n = FALSE;
5751 static char *(has_list[]) =
5752 {
5753#ifdef AMIGA
5754 "amiga",
5755# ifdef FEAT_ARP
5756 "arp",
5757# endif
5758#endif
5759#ifdef __BEOS__
5760 "beos",
5761#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005762#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005763 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5764 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005765# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005766 "macunix", /* Mac OS X, with the darwin feature */
5767 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005768# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005769#endif
5770#ifdef __QNX__
5771 "qnx",
5772#endif
5773#ifdef UNIX
5774 "unix",
5775#endif
5776#ifdef VMS
5777 "vms",
5778#endif
5779#ifdef WIN32
5780 "win32",
5781#endif
5782#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5783 "win32unix",
5784#endif
5785#if defined(WIN64) || defined(_WIN64)
5786 "win64",
5787#endif
5788#ifdef EBCDIC
5789 "ebcdic",
5790#endif
5791#ifndef CASE_INSENSITIVE_FILENAME
5792 "fname_case",
5793#endif
5794#ifdef HAVE_ACL
5795 "acl",
5796#endif
5797#ifdef FEAT_ARABIC
5798 "arabic",
5799#endif
5800#ifdef FEAT_AUTOCMD
5801 "autocmd",
5802#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005803#ifdef FEAT_AUTOSERVERNAME
5804 "autoservername",
5805#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005806#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005807 "balloon_eval",
5808# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5809 "balloon_multiline",
5810# endif
5811#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005812#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005813 "balloon_eval_term",
5814#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005815#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5816 "builtin_terms",
5817# ifdef ALL_BUILTIN_TCAPS
5818 "all_builtin_terms",
5819# endif
5820#endif
5821#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5822 || defined(FEAT_GUI_W32) \
5823 || defined(FEAT_GUI_MOTIF))
5824 "browsefilter",
5825#endif
5826#ifdef FEAT_BYTEOFF
5827 "byte_offset",
5828#endif
5829#ifdef FEAT_JOB_CHANNEL
5830 "channel",
5831#endif
5832#ifdef FEAT_CINDENT
5833 "cindent",
5834#endif
5835#ifdef FEAT_CLIENTSERVER
5836 "clientserver",
5837#endif
5838#ifdef FEAT_CLIPBOARD
5839 "clipboard",
5840#endif
5841#ifdef FEAT_CMDL_COMPL
5842 "cmdline_compl",
5843#endif
5844#ifdef FEAT_CMDHIST
5845 "cmdline_hist",
5846#endif
5847#ifdef FEAT_COMMENTS
5848 "comments",
5849#endif
5850#ifdef FEAT_CONCEAL
5851 "conceal",
5852#endif
5853#ifdef FEAT_CRYPT
5854 "cryptv",
5855 "crypt-blowfish",
5856 "crypt-blowfish2",
5857#endif
5858#ifdef FEAT_CSCOPE
5859 "cscope",
5860#endif
5861#ifdef FEAT_CURSORBIND
5862 "cursorbind",
5863#endif
5864#ifdef CURSOR_SHAPE
5865 "cursorshape",
5866#endif
5867#ifdef DEBUG
5868 "debug",
5869#endif
5870#ifdef FEAT_CON_DIALOG
5871 "dialog_con",
5872#endif
5873#ifdef FEAT_GUI_DIALOG
5874 "dialog_gui",
5875#endif
5876#ifdef FEAT_DIFF
5877 "diff",
5878#endif
5879#ifdef FEAT_DIGRAPHS
5880 "digraphs",
5881#endif
5882#ifdef FEAT_DIRECTX
5883 "directx",
5884#endif
5885#ifdef FEAT_DND
5886 "dnd",
5887#endif
5888#ifdef FEAT_EMACS_TAGS
5889 "emacs_tags",
5890#endif
5891 "eval", /* always present, of course! */
5892 "ex_extra", /* graduated feature */
5893#ifdef FEAT_SEARCH_EXTRA
5894 "extra_search",
5895#endif
5896#ifdef FEAT_FKMAP
5897 "farsi",
5898#endif
5899#ifdef FEAT_SEARCHPATH
5900 "file_in_path",
5901#endif
5902#ifdef FEAT_FILTERPIPE
5903 "filterpipe",
5904#endif
5905#ifdef FEAT_FIND_ID
5906 "find_in_path",
5907#endif
5908#ifdef FEAT_FLOAT
5909 "float",
5910#endif
5911#ifdef FEAT_FOLDING
5912 "folding",
5913#endif
5914#ifdef FEAT_FOOTER
5915 "footer",
5916#endif
5917#if !defined(USE_SYSTEM) && defined(UNIX)
5918 "fork",
5919#endif
5920#ifdef FEAT_GETTEXT
5921 "gettext",
5922#endif
5923#ifdef FEAT_GUI
5924 "gui",
5925#endif
5926#ifdef FEAT_GUI_ATHENA
5927# ifdef FEAT_GUI_NEXTAW
5928 "gui_neXtaw",
5929# else
5930 "gui_athena",
5931# endif
5932#endif
5933#ifdef FEAT_GUI_GTK
5934 "gui_gtk",
5935# ifdef USE_GTK3
5936 "gui_gtk3",
5937# else
5938 "gui_gtk2",
5939# endif
5940#endif
5941#ifdef FEAT_GUI_GNOME
5942 "gui_gnome",
5943#endif
5944#ifdef FEAT_GUI_MAC
5945 "gui_mac",
5946#endif
5947#ifdef FEAT_GUI_MOTIF
5948 "gui_motif",
5949#endif
5950#ifdef FEAT_GUI_PHOTON
5951 "gui_photon",
5952#endif
5953#ifdef FEAT_GUI_W32
5954 "gui_win32",
5955#endif
5956#ifdef FEAT_HANGULIN
5957 "hangul_input",
5958#endif
5959#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5960 "iconv",
5961#endif
5962#ifdef FEAT_INS_EXPAND
5963 "insert_expand",
5964#endif
5965#ifdef FEAT_JOB_CHANNEL
5966 "job",
5967#endif
5968#ifdef FEAT_JUMPLIST
5969 "jumplist",
5970#endif
5971#ifdef FEAT_KEYMAP
5972 "keymap",
5973#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005974 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975#ifdef FEAT_LANGMAP
5976 "langmap",
5977#endif
5978#ifdef FEAT_LIBCALL
5979 "libcall",
5980#endif
5981#ifdef FEAT_LINEBREAK
5982 "linebreak",
5983#endif
5984#ifdef FEAT_LISP
5985 "lispindent",
5986#endif
5987#ifdef FEAT_LISTCMDS
5988 "listcmds",
5989#endif
5990#ifdef FEAT_LOCALMAP
5991 "localmap",
5992#endif
5993#ifdef FEAT_LUA
5994# ifndef DYNAMIC_LUA
5995 "lua",
5996# endif
5997#endif
5998#ifdef FEAT_MENU
5999 "menu",
6000#endif
6001#ifdef FEAT_SESSION
6002 "mksession",
6003#endif
6004#ifdef FEAT_MODIFY_FNAME
6005 "modify_fname",
6006#endif
6007#ifdef FEAT_MOUSE
6008 "mouse",
6009#endif
6010#ifdef FEAT_MOUSESHAPE
6011 "mouseshape",
6012#endif
6013#if defined(UNIX) || defined(VMS)
6014# ifdef FEAT_MOUSE_DEC
6015 "mouse_dec",
6016# endif
6017# ifdef FEAT_MOUSE_GPM
6018 "mouse_gpm",
6019# endif
6020# ifdef FEAT_MOUSE_JSB
6021 "mouse_jsbterm",
6022# endif
6023# ifdef FEAT_MOUSE_NET
6024 "mouse_netterm",
6025# endif
6026# ifdef FEAT_MOUSE_PTERM
6027 "mouse_pterm",
6028# endif
6029# ifdef FEAT_MOUSE_SGR
6030 "mouse_sgr",
6031# endif
6032# ifdef FEAT_SYSMOUSE
6033 "mouse_sysmouse",
6034# endif
6035# ifdef FEAT_MOUSE_URXVT
6036 "mouse_urxvt",
6037# endif
6038# ifdef FEAT_MOUSE_XTERM
6039 "mouse_xterm",
6040# endif
6041#endif
6042#ifdef FEAT_MBYTE
6043 "multi_byte",
6044#endif
6045#ifdef FEAT_MBYTE_IME
6046 "multi_byte_ime",
6047#endif
6048#ifdef FEAT_MULTI_LANG
6049 "multi_lang",
6050#endif
6051#ifdef FEAT_MZSCHEME
6052#ifndef DYNAMIC_MZSCHEME
6053 "mzscheme",
6054#endif
6055#endif
6056#ifdef FEAT_NUM64
6057 "num64",
6058#endif
6059#ifdef FEAT_OLE
6060 "ole",
6061#endif
6062 "packages",
6063#ifdef FEAT_PATH_EXTRA
6064 "path_extra",
6065#endif
6066#ifdef FEAT_PERL
6067#ifndef DYNAMIC_PERL
6068 "perl",
6069#endif
6070#endif
6071#ifdef FEAT_PERSISTENT_UNDO
6072 "persistent_undo",
6073#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006074#if defined(FEAT_PYTHON)
6075 "python_compiled",
6076# if defined(DYNAMIC_PYTHON)
6077 "python_dynamic",
6078# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006079 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006080 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006081# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006082#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006083#if defined(FEAT_PYTHON3)
6084 "python3_compiled",
6085# if defined(DYNAMIC_PYTHON3)
6086 "python3_dynamic",
6087# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006088 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006089 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006090# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006091#endif
6092#ifdef FEAT_POSTSCRIPT
6093 "postscript",
6094#endif
6095#ifdef FEAT_PRINTER
6096 "printer",
6097#endif
6098#ifdef FEAT_PROFILE
6099 "profile",
6100#endif
6101#ifdef FEAT_RELTIME
6102 "reltime",
6103#endif
6104#ifdef FEAT_QUICKFIX
6105 "quickfix",
6106#endif
6107#ifdef FEAT_RIGHTLEFT
6108 "rightleft",
6109#endif
6110#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6111 "ruby",
6112#endif
6113#ifdef FEAT_SCROLLBIND
6114 "scrollbind",
6115#endif
6116#ifdef FEAT_CMDL_INFO
6117 "showcmd",
6118 "cmdline_info",
6119#endif
6120#ifdef FEAT_SIGNS
6121 "signs",
6122#endif
6123#ifdef FEAT_SMARTINDENT
6124 "smartindent",
6125#endif
6126#ifdef STARTUPTIME
6127 "startuptime",
6128#endif
6129#ifdef FEAT_STL_OPT
6130 "statusline",
6131#endif
6132#ifdef FEAT_SUN_WORKSHOP
6133 "sun_workshop",
6134#endif
6135#ifdef FEAT_NETBEANS_INTG
6136 "netbeans_intg",
6137#endif
6138#ifdef FEAT_SPELL
6139 "spell",
6140#endif
6141#ifdef FEAT_SYN_HL
6142 "syntax",
6143#endif
6144#if defined(USE_SYSTEM) || !defined(UNIX)
6145 "system",
6146#endif
6147#ifdef FEAT_TAG_BINS
6148 "tag_binary",
6149#endif
6150#ifdef FEAT_TAG_OLDSTATIC
6151 "tag_old_static",
6152#endif
6153#ifdef FEAT_TAG_ANYWHITE
6154 "tag_any_white",
6155#endif
6156#ifdef FEAT_TCL
6157# ifndef DYNAMIC_TCL
6158 "tcl",
6159# endif
6160#endif
6161#ifdef FEAT_TERMGUICOLORS
6162 "termguicolors",
6163#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006164#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006165 "terminal",
6166#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006167#ifdef TERMINFO
6168 "terminfo",
6169#endif
6170#ifdef FEAT_TERMRESPONSE
6171 "termresponse",
6172#endif
6173#ifdef FEAT_TEXTOBJ
6174 "textobjects",
6175#endif
6176#ifdef HAVE_TGETENT
6177 "tgetent",
6178#endif
6179#ifdef FEAT_TIMERS
6180 "timers",
6181#endif
6182#ifdef FEAT_TITLE
6183 "title",
6184#endif
6185#ifdef FEAT_TOOLBAR
6186 "toolbar",
6187#endif
6188#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6189 "unnamedplus",
6190#endif
6191#ifdef FEAT_USR_CMDS
6192 "user-commands", /* was accidentally included in 5.4 */
6193 "user_commands",
6194#endif
6195#ifdef FEAT_VIMINFO
6196 "viminfo",
6197#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006199#ifdef FEAT_VIRTUALEDIT
6200 "virtualedit",
6201#endif
6202 "visual",
6203#ifdef FEAT_VISUALEXTRA
6204 "visualextra",
6205#endif
6206#ifdef FEAT_VREPLACE
6207 "vreplace",
6208#endif
6209#ifdef FEAT_WILDIGN
6210 "wildignore",
6211#endif
6212#ifdef FEAT_WILDMENU
6213 "wildmenu",
6214#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006216#ifdef FEAT_WAK
6217 "winaltkeys",
6218#endif
6219#ifdef FEAT_WRITEBACKUP
6220 "writebackup",
6221#endif
6222#ifdef FEAT_XIM
6223 "xim",
6224#endif
6225#ifdef FEAT_XFONTSET
6226 "xfontset",
6227#endif
6228#ifdef FEAT_XPM_W32
6229 "xpm",
6230 "xpm_w32", /* for backward compatibility */
6231#else
6232# if defined(HAVE_XPM)
6233 "xpm",
6234# endif
6235#endif
6236#ifdef USE_XSMP
6237 "xsmp",
6238#endif
6239#ifdef USE_XSMP_INTERACT
6240 "xsmp_interact",
6241#endif
6242#ifdef FEAT_XCLIPBOARD
6243 "xterm_clipboard",
6244#endif
6245#ifdef FEAT_XTERM_SAVE
6246 "xterm_save",
6247#endif
6248#if defined(UNIX) && defined(FEAT_X11)
6249 "X11",
6250#endif
6251 NULL
6252 };
6253
6254 name = get_tv_string(&argvars[0]);
6255 for (i = 0; has_list[i] != NULL; ++i)
6256 if (STRICMP(name, has_list[i]) == 0)
6257 {
6258 n = TRUE;
6259 break;
6260 }
6261
6262 if (n == FALSE)
6263 {
6264 if (STRNICMP(name, "patch", 5) == 0)
6265 {
6266 if (name[5] == '-'
6267 && STRLEN(name) >= 11
6268 && vim_isdigit(name[6])
6269 && vim_isdigit(name[8])
6270 && vim_isdigit(name[10]))
6271 {
6272 int major = atoi((char *)name + 6);
6273 int minor = atoi((char *)name + 8);
6274
6275 /* Expect "patch-9.9.01234". */
6276 n = (major < VIM_VERSION_MAJOR
6277 || (major == VIM_VERSION_MAJOR
6278 && (minor < VIM_VERSION_MINOR
6279 || (minor == VIM_VERSION_MINOR
6280 && has_patch(atoi((char *)name + 10))))));
6281 }
6282 else
6283 n = has_patch(atoi((char *)name + 5));
6284 }
6285 else if (STRICMP(name, "vim_starting") == 0)
6286 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006287 else if (STRICMP(name, "ttyin") == 0)
6288 n = mch_input_isatty();
6289 else if (STRICMP(name, "ttyout") == 0)
6290 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291#ifdef FEAT_MBYTE
6292 else if (STRICMP(name, "multi_byte_encoding") == 0)
6293 n = has_mbyte;
6294#endif
6295#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6296 else if (STRICMP(name, "balloon_multiline") == 0)
6297 n = multiline_balloon_available();
6298#endif
6299#ifdef DYNAMIC_TCL
6300 else if (STRICMP(name, "tcl") == 0)
6301 n = tcl_enabled(FALSE);
6302#endif
6303#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6304 else if (STRICMP(name, "iconv") == 0)
6305 n = iconv_enabled(FALSE);
6306#endif
6307#ifdef DYNAMIC_LUA
6308 else if (STRICMP(name, "lua") == 0)
6309 n = lua_enabled(FALSE);
6310#endif
6311#ifdef DYNAMIC_MZSCHEME
6312 else if (STRICMP(name, "mzscheme") == 0)
6313 n = mzscheme_enabled(FALSE);
6314#endif
6315#ifdef DYNAMIC_RUBY
6316 else if (STRICMP(name, "ruby") == 0)
6317 n = ruby_enabled(FALSE);
6318#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006319#ifdef DYNAMIC_PYTHON
6320 else if (STRICMP(name, "python") == 0)
6321 n = python_enabled(FALSE);
6322#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323#ifdef DYNAMIC_PYTHON3
6324 else if (STRICMP(name, "python3") == 0)
6325 n = python3_enabled(FALSE);
6326#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006327#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6328 else if (STRICMP(name, "pythonx") == 0)
6329 {
6330# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6331 if (p_pyx == 0)
6332 n = python3_enabled(FALSE) || python_enabled(FALSE);
6333 else if (p_pyx == 3)
6334 n = python3_enabled(FALSE);
6335 else if (p_pyx == 2)
6336 n = python_enabled(FALSE);
6337# elif defined(DYNAMIC_PYTHON)
6338 n = python_enabled(FALSE);
6339# elif defined(DYNAMIC_PYTHON3)
6340 n = python3_enabled(FALSE);
6341# endif
6342 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343#endif
6344#ifdef DYNAMIC_PERL
6345 else if (STRICMP(name, "perl") == 0)
6346 n = perl_enabled(FALSE);
6347#endif
6348#ifdef FEAT_GUI
6349 else if (STRICMP(name, "gui_running") == 0)
6350 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351# ifdef FEAT_BROWSE
6352 else if (STRICMP(name, "browse") == 0)
6353 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6354# endif
6355#endif
6356#ifdef FEAT_SYN_HL
6357 else if (STRICMP(name, "syntax_items") == 0)
6358 n = syntax_present(curwin);
6359#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006360#ifdef FEAT_VTP
6361 else if (STRICMP(name, "vcon") == 0)
6362 n = has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363#endif
6364#ifdef FEAT_NETBEANS_INTG
6365 else if (STRICMP(name, "netbeans_enabled") == 0)
6366 n = netbeans_active();
6367#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006368#if defined(FEAT_TERMINAL) && defined(WIN3264)
6369 else if (STRICMP(name, "terminal") == 0)
6370 n = terminal_enabled();
6371#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372 }
6373
6374 rettv->vval.v_number = n;
6375}
6376
6377/*
6378 * "has_key()" function
6379 */
6380 static void
6381f_has_key(typval_T *argvars, typval_T *rettv)
6382{
6383 if (argvars[0].v_type != VAR_DICT)
6384 {
6385 EMSG(_(e_dictreq));
6386 return;
6387 }
6388 if (argvars[0].vval.v_dict == NULL)
6389 return;
6390
6391 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6392 get_tv_string(&argvars[1]), -1) != NULL;
6393}
6394
6395/*
6396 * "haslocaldir()" function
6397 */
6398 static void
6399f_haslocaldir(typval_T *argvars, typval_T *rettv)
6400{
6401 win_T *wp = NULL;
6402
6403 wp = find_tabwin(&argvars[0], &argvars[1]);
6404 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6405}
6406
6407/*
6408 * "hasmapto()" function
6409 */
6410 static void
6411f_hasmapto(typval_T *argvars, typval_T *rettv)
6412{
6413 char_u *name;
6414 char_u *mode;
6415 char_u buf[NUMBUFLEN];
6416 int abbr = FALSE;
6417
6418 name = get_tv_string(&argvars[0]);
6419 if (argvars[1].v_type == VAR_UNKNOWN)
6420 mode = (char_u *)"nvo";
6421 else
6422 {
6423 mode = get_tv_string_buf(&argvars[1], buf);
6424 if (argvars[2].v_type != VAR_UNKNOWN)
6425 abbr = (int)get_tv_number(&argvars[2]);
6426 }
6427
6428 if (map_to_exists(name, mode, abbr))
6429 rettv->vval.v_number = TRUE;
6430 else
6431 rettv->vval.v_number = FALSE;
6432}
6433
6434/*
6435 * "histadd()" function
6436 */
6437 static void
6438f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6439{
6440#ifdef FEAT_CMDHIST
6441 int histype;
6442 char_u *str;
6443 char_u buf[NUMBUFLEN];
6444#endif
6445
6446 rettv->vval.v_number = FALSE;
6447 if (check_restricted() || check_secure())
6448 return;
6449#ifdef FEAT_CMDHIST
6450 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6451 histype = str != NULL ? get_histtype(str) : -1;
6452 if (histype >= 0)
6453 {
6454 str = get_tv_string_buf(&argvars[1], buf);
6455 if (*str != NUL)
6456 {
6457 init_history();
6458 add_to_history(histype, str, FALSE, NUL);
6459 rettv->vval.v_number = TRUE;
6460 return;
6461 }
6462 }
6463#endif
6464}
6465
6466/*
6467 * "histdel()" function
6468 */
6469 static void
6470f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6471{
6472#ifdef FEAT_CMDHIST
6473 int n;
6474 char_u buf[NUMBUFLEN];
6475 char_u *str;
6476
6477 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6478 if (str == NULL)
6479 n = 0;
6480 else if (argvars[1].v_type == VAR_UNKNOWN)
6481 /* only one argument: clear entire history */
6482 n = clr_history(get_histtype(str));
6483 else if (argvars[1].v_type == VAR_NUMBER)
6484 /* index given: remove that entry */
6485 n = del_history_idx(get_histtype(str),
6486 (int)get_tv_number(&argvars[1]));
6487 else
6488 /* string given: remove all matching entries */
6489 n = del_history_entry(get_histtype(str),
6490 get_tv_string_buf(&argvars[1], buf));
6491 rettv->vval.v_number = n;
6492#endif
6493}
6494
6495/*
6496 * "histget()" function
6497 */
6498 static void
6499f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6500{
6501#ifdef FEAT_CMDHIST
6502 int type;
6503 int idx;
6504 char_u *str;
6505
6506 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6507 if (str == NULL)
6508 rettv->vval.v_string = NULL;
6509 else
6510 {
6511 type = get_histtype(str);
6512 if (argvars[1].v_type == VAR_UNKNOWN)
6513 idx = get_history_idx(type);
6514 else
6515 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6516 /* -1 on type error */
6517 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6518 }
6519#else
6520 rettv->vval.v_string = NULL;
6521#endif
6522 rettv->v_type = VAR_STRING;
6523}
6524
6525/*
6526 * "histnr()" function
6527 */
6528 static void
6529f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6530{
6531 int i;
6532
6533#ifdef FEAT_CMDHIST
6534 char_u *history = get_tv_string_chk(&argvars[0]);
6535
6536 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6537 if (i >= HIST_CMD && i < HIST_COUNT)
6538 i = get_history_idx(i);
6539 else
6540#endif
6541 i = -1;
6542 rettv->vval.v_number = i;
6543}
6544
6545/*
6546 * "highlightID(name)" function
6547 */
6548 static void
6549f_hlID(typval_T *argvars, typval_T *rettv)
6550{
6551 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6552}
6553
6554/*
6555 * "highlight_exists()" function
6556 */
6557 static void
6558f_hlexists(typval_T *argvars, typval_T *rettv)
6559{
6560 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6561}
6562
6563/*
6564 * "hostname()" function
6565 */
6566 static void
6567f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6568{
6569 char_u hostname[256];
6570
6571 mch_get_host_name(hostname, 256);
6572 rettv->v_type = VAR_STRING;
6573 rettv->vval.v_string = vim_strsave(hostname);
6574}
6575
6576/*
6577 * iconv() function
6578 */
6579 static void
6580f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6581{
6582#ifdef FEAT_MBYTE
6583 char_u buf1[NUMBUFLEN];
6584 char_u buf2[NUMBUFLEN];
6585 char_u *from, *to, *str;
6586 vimconv_T vimconv;
6587#endif
6588
6589 rettv->v_type = VAR_STRING;
6590 rettv->vval.v_string = NULL;
6591
6592#ifdef FEAT_MBYTE
6593 str = get_tv_string(&argvars[0]);
6594 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6595 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6596 vimconv.vc_type = CONV_NONE;
6597 convert_setup(&vimconv, from, to);
6598
6599 /* If the encodings are equal, no conversion needed. */
6600 if (vimconv.vc_type == CONV_NONE)
6601 rettv->vval.v_string = vim_strsave(str);
6602 else
6603 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6604
6605 convert_setup(&vimconv, NULL, NULL);
6606 vim_free(from);
6607 vim_free(to);
6608#endif
6609}
6610
6611/*
6612 * "indent()" function
6613 */
6614 static void
6615f_indent(typval_T *argvars, typval_T *rettv)
6616{
6617 linenr_T lnum;
6618
6619 lnum = get_tv_lnum(argvars);
6620 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6621 rettv->vval.v_number = get_indent_lnum(lnum);
6622 else
6623 rettv->vval.v_number = -1;
6624}
6625
6626/*
6627 * "index()" function
6628 */
6629 static void
6630f_index(typval_T *argvars, typval_T *rettv)
6631{
6632 list_T *l;
6633 listitem_T *item;
6634 long idx = 0;
6635 int ic = FALSE;
6636
6637 rettv->vval.v_number = -1;
6638 if (argvars[0].v_type != VAR_LIST)
6639 {
6640 EMSG(_(e_listreq));
6641 return;
6642 }
6643 l = argvars[0].vval.v_list;
6644 if (l != NULL)
6645 {
6646 item = l->lv_first;
6647 if (argvars[2].v_type != VAR_UNKNOWN)
6648 {
6649 int error = FALSE;
6650
6651 /* Start at specified item. Use the cached index that list_find()
6652 * sets, so that a negative number also works. */
6653 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6654 idx = l->lv_idx;
6655 if (argvars[3].v_type != VAR_UNKNOWN)
6656 ic = (int)get_tv_number_chk(&argvars[3], &error);
6657 if (error)
6658 item = NULL;
6659 }
6660
6661 for ( ; item != NULL; item = item->li_next, ++idx)
6662 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6663 {
6664 rettv->vval.v_number = idx;
6665 break;
6666 }
6667 }
6668}
6669
6670static int inputsecret_flag = 0;
6671
6672/*
6673 * "input()" function
6674 * Also handles inputsecret() when inputsecret is set.
6675 */
6676 static void
6677f_input(typval_T *argvars, typval_T *rettv)
6678{
6679 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6680}
6681
6682/*
6683 * "inputdialog()" function
6684 */
6685 static void
6686f_inputdialog(typval_T *argvars, typval_T *rettv)
6687{
6688#if defined(FEAT_GUI_TEXTDIALOG)
6689 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6690 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6691 {
6692 char_u *message;
6693 char_u buf[NUMBUFLEN];
6694 char_u *defstr = (char_u *)"";
6695
6696 message = get_tv_string_chk(&argvars[0]);
6697 if (argvars[1].v_type != VAR_UNKNOWN
6698 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6699 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6700 else
6701 IObuff[0] = NUL;
6702 if (message != NULL && defstr != NULL
6703 && do_dialog(VIM_QUESTION, NULL, message,
6704 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6705 rettv->vval.v_string = vim_strsave(IObuff);
6706 else
6707 {
6708 if (message != NULL && defstr != NULL
6709 && argvars[1].v_type != VAR_UNKNOWN
6710 && argvars[2].v_type != VAR_UNKNOWN)
6711 rettv->vval.v_string = vim_strsave(
6712 get_tv_string_buf(&argvars[2], buf));
6713 else
6714 rettv->vval.v_string = NULL;
6715 }
6716 rettv->v_type = VAR_STRING;
6717 }
6718 else
6719#endif
6720 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6721}
6722
6723/*
6724 * "inputlist()" function
6725 */
6726 static void
6727f_inputlist(typval_T *argvars, typval_T *rettv)
6728{
6729 listitem_T *li;
6730 int selected;
6731 int mouse_used;
6732
6733#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006734 /* While starting up, there is no place to enter text. When running tests
6735 * with --not-a-term we assume feedkeys() will be used. */
6736 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 return;
6738#endif
6739 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6740 {
6741 EMSG2(_(e_listarg), "inputlist()");
6742 return;
6743 }
6744
6745 msg_start();
6746 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6747 lines_left = Rows; /* avoid more prompt */
6748 msg_scroll = TRUE;
6749 msg_clr_eos();
6750
6751 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6752 {
6753 msg_puts(get_tv_string(&li->li_tv));
6754 msg_putchar('\n');
6755 }
6756
6757 /* Ask for choice. */
6758 selected = prompt_for_number(&mouse_used);
6759 if (mouse_used)
6760 selected -= lines_left;
6761
6762 rettv->vval.v_number = selected;
6763}
6764
6765
6766static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6767
6768/*
6769 * "inputrestore()" function
6770 */
6771 static void
6772f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6773{
6774 if (ga_userinput.ga_len > 0)
6775 {
6776 --ga_userinput.ga_len;
6777 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6778 + ga_userinput.ga_len);
6779 /* default return is zero == OK */
6780 }
6781 else if (p_verbose > 1)
6782 {
6783 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6784 rettv->vval.v_number = 1; /* Failed */
6785 }
6786}
6787
6788/*
6789 * "inputsave()" function
6790 */
6791 static void
6792f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6793{
6794 /* Add an entry to the stack of typeahead storage. */
6795 if (ga_grow(&ga_userinput, 1) == OK)
6796 {
6797 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6798 + ga_userinput.ga_len);
6799 ++ga_userinput.ga_len;
6800 /* default return is zero == OK */
6801 }
6802 else
6803 rettv->vval.v_number = 1; /* Failed */
6804}
6805
6806/*
6807 * "inputsecret()" function
6808 */
6809 static void
6810f_inputsecret(typval_T *argvars, typval_T *rettv)
6811{
6812 ++cmdline_star;
6813 ++inputsecret_flag;
6814 f_input(argvars, rettv);
6815 --cmdline_star;
6816 --inputsecret_flag;
6817}
6818
6819/*
6820 * "insert()" function
6821 */
6822 static void
6823f_insert(typval_T *argvars, typval_T *rettv)
6824{
6825 long before = 0;
6826 listitem_T *item;
6827 list_T *l;
6828 int error = FALSE;
6829
6830 if (argvars[0].v_type != VAR_LIST)
6831 EMSG2(_(e_listarg), "insert()");
6832 else if ((l = argvars[0].vval.v_list) != NULL
6833 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6834 {
6835 if (argvars[2].v_type != VAR_UNKNOWN)
6836 before = (long)get_tv_number_chk(&argvars[2], &error);
6837 if (error)
6838 return; /* type error; errmsg already given */
6839
6840 if (before == l->lv_len)
6841 item = NULL;
6842 else
6843 {
6844 item = list_find(l, before);
6845 if (item == NULL)
6846 {
6847 EMSGN(_(e_listidx), before);
6848 l = NULL;
6849 }
6850 }
6851 if (l != NULL)
6852 {
6853 list_insert_tv(l, &argvars[1], item);
6854 copy_tv(&argvars[0], rettv);
6855 }
6856 }
6857}
6858
6859/*
6860 * "invert(expr)" function
6861 */
6862 static void
6863f_invert(typval_T *argvars, typval_T *rettv)
6864{
6865 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6866}
6867
6868/*
6869 * "isdirectory()" function
6870 */
6871 static void
6872f_isdirectory(typval_T *argvars, typval_T *rettv)
6873{
6874 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6875}
6876
6877/*
6878 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6879 * or it refers to a List or Dictionary that is locked.
6880 */
6881 static int
6882tv_islocked(typval_T *tv)
6883{
6884 return (tv->v_lock & VAR_LOCKED)
6885 || (tv->v_type == VAR_LIST
6886 && tv->vval.v_list != NULL
6887 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6888 || (tv->v_type == VAR_DICT
6889 && tv->vval.v_dict != NULL
6890 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6891}
6892
6893/*
6894 * "islocked()" function
6895 */
6896 static void
6897f_islocked(typval_T *argvars, typval_T *rettv)
6898{
6899 lval_T lv;
6900 char_u *end;
6901 dictitem_T *di;
6902
6903 rettv->vval.v_number = -1;
6904 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006905 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 if (end != NULL && lv.ll_name != NULL)
6907 {
6908 if (*end != NUL)
6909 EMSG(_(e_trailing));
6910 else
6911 {
6912 if (lv.ll_tv == NULL)
6913 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006914 di = find_var(lv.ll_name, NULL, TRUE);
6915 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006917 /* Consider a variable locked when:
6918 * 1. the variable itself is locked
6919 * 2. the value of the variable is locked.
6920 * 3. the List or Dict value is locked.
6921 */
6922 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6923 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006924 }
6925 }
6926 else if (lv.ll_range)
6927 EMSG(_("E786: Range not allowed"));
6928 else if (lv.ll_newkey != NULL)
6929 EMSG2(_(e_dictkey), lv.ll_newkey);
6930 else if (lv.ll_list != NULL)
6931 /* List item. */
6932 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6933 else
6934 /* Dictionary item. */
6935 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6936 }
6937 }
6938
6939 clear_lval(&lv);
6940}
6941
6942#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6943/*
6944 * "isnan()" function
6945 */
6946 static void
6947f_isnan(typval_T *argvars, typval_T *rettv)
6948{
6949 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6950 && isnan(argvars[0].vval.v_float);
6951}
6952#endif
6953
6954/*
6955 * "items(dict)" function
6956 */
6957 static void
6958f_items(typval_T *argvars, typval_T *rettv)
6959{
6960 dict_list(argvars, rettv, 2);
6961}
6962
6963#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6964/*
6965 * Get the job from the argument.
6966 * Returns NULL if the job is invalid.
6967 */
6968 static job_T *
6969get_job_arg(typval_T *tv)
6970{
6971 job_T *job;
6972
6973 if (tv->v_type != VAR_JOB)
6974 {
6975 EMSG2(_(e_invarg2), get_tv_string(tv));
6976 return NULL;
6977 }
6978 job = tv->vval.v_job;
6979
6980 if (job == NULL)
6981 EMSG(_("E916: not a valid job"));
6982 return job;
6983}
6984
6985/*
6986 * "job_getchannel()" function
6987 */
6988 static void
6989f_job_getchannel(typval_T *argvars, typval_T *rettv)
6990{
6991 job_T *job = get_job_arg(&argvars[0]);
6992
6993 if (job != NULL)
6994 {
6995 rettv->v_type = VAR_CHANNEL;
6996 rettv->vval.v_channel = job->jv_channel;
6997 if (job->jv_channel != NULL)
6998 ++job->jv_channel->ch_refcount;
6999 }
7000}
7001
7002/*
7003 * "job_info()" function
7004 */
7005 static void
7006f_job_info(typval_T *argvars, typval_T *rettv)
7007{
7008 job_T *job = get_job_arg(&argvars[0]);
7009
7010 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7011 job_info(job, rettv->vval.v_dict);
7012}
7013
7014/*
7015 * "job_setoptions()" function
7016 */
7017 static void
7018f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7019{
7020 job_T *job = get_job_arg(&argvars[0]);
7021 jobopt_T opt;
7022
7023 if (job == NULL)
7024 return;
7025 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007026 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007027 job_set_options(job, &opt);
7028 free_job_options(&opt);
7029}
7030
7031/*
7032 * "job_start()" function
7033 */
7034 static void
7035f_job_start(typval_T *argvars, typval_T *rettv)
7036{
7037 rettv->v_type = VAR_JOB;
7038 if (check_restricted() || check_secure())
7039 return;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02007040 rettv->vval.v_job = job_start(argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007041}
7042
7043/*
7044 * "job_status()" function
7045 */
7046 static void
7047f_job_status(typval_T *argvars, typval_T *rettv)
7048{
7049 job_T *job = get_job_arg(&argvars[0]);
7050
7051 if (job != NULL)
7052 {
7053 rettv->v_type = VAR_STRING;
7054 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7055 }
7056}
7057
7058/*
7059 * "job_stop()" function
7060 */
7061 static void
7062f_job_stop(typval_T *argvars, typval_T *rettv)
7063{
7064 job_T *job = get_job_arg(&argvars[0]);
7065
7066 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007067 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068}
7069#endif
7070
7071/*
7072 * "join()" function
7073 */
7074 static void
7075f_join(typval_T *argvars, typval_T *rettv)
7076{
7077 garray_T ga;
7078 char_u *sep;
7079
7080 if (argvars[0].v_type != VAR_LIST)
7081 {
7082 EMSG(_(e_listreq));
7083 return;
7084 }
7085 if (argvars[0].vval.v_list == NULL)
7086 return;
7087 if (argvars[1].v_type == VAR_UNKNOWN)
7088 sep = (char_u *)" ";
7089 else
7090 sep = get_tv_string_chk(&argvars[1]);
7091
7092 rettv->v_type = VAR_STRING;
7093
7094 if (sep != NULL)
7095 {
7096 ga_init2(&ga, (int)sizeof(char), 80);
7097 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7098 ga_append(&ga, NUL);
7099 rettv->vval.v_string = (char_u *)ga.ga_data;
7100 }
7101 else
7102 rettv->vval.v_string = NULL;
7103}
7104
7105/*
7106 * "js_decode()" function
7107 */
7108 static void
7109f_js_decode(typval_T *argvars, typval_T *rettv)
7110{
7111 js_read_T reader;
7112
7113 reader.js_buf = get_tv_string(&argvars[0]);
7114 reader.js_fill = NULL;
7115 reader.js_used = 0;
7116 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7117 EMSG(_(e_invarg));
7118}
7119
7120/*
7121 * "js_encode()" function
7122 */
7123 static void
7124f_js_encode(typval_T *argvars, typval_T *rettv)
7125{
7126 rettv->v_type = VAR_STRING;
7127 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7128}
7129
7130/*
7131 * "json_decode()" function
7132 */
7133 static void
7134f_json_decode(typval_T *argvars, typval_T *rettv)
7135{
7136 js_read_T reader;
7137
7138 reader.js_buf = get_tv_string(&argvars[0]);
7139 reader.js_fill = NULL;
7140 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007141 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142}
7143
7144/*
7145 * "json_encode()" function
7146 */
7147 static void
7148f_json_encode(typval_T *argvars, typval_T *rettv)
7149{
7150 rettv->v_type = VAR_STRING;
7151 rettv->vval.v_string = json_encode(&argvars[0], 0);
7152}
7153
7154/*
7155 * "keys()" function
7156 */
7157 static void
7158f_keys(typval_T *argvars, typval_T *rettv)
7159{
7160 dict_list(argvars, rettv, 0);
7161}
7162
7163/*
7164 * "last_buffer_nr()" function.
7165 */
7166 static void
7167f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7168{
7169 int n = 0;
7170 buf_T *buf;
7171
Bram Moolenaar29323592016-07-24 22:04:11 +02007172 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007173 if (n < buf->b_fnum)
7174 n = buf->b_fnum;
7175
7176 rettv->vval.v_number = n;
7177}
7178
7179/*
7180 * "len()" function
7181 */
7182 static void
7183f_len(typval_T *argvars, typval_T *rettv)
7184{
7185 switch (argvars[0].v_type)
7186 {
7187 case VAR_STRING:
7188 case VAR_NUMBER:
7189 rettv->vval.v_number = (varnumber_T)STRLEN(
7190 get_tv_string(&argvars[0]));
7191 break;
7192 case VAR_LIST:
7193 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7194 break;
7195 case VAR_DICT:
7196 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7197 break;
7198 case VAR_UNKNOWN:
7199 case VAR_SPECIAL:
7200 case VAR_FLOAT:
7201 case VAR_FUNC:
7202 case VAR_PARTIAL:
7203 case VAR_JOB:
7204 case VAR_CHANNEL:
7205 EMSG(_("E701: Invalid type for len()"));
7206 break;
7207 }
7208}
7209
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007210 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007211libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007212{
7213#ifdef FEAT_LIBCALL
7214 char_u *string_in;
7215 char_u **string_result;
7216 int nr_result;
7217#endif
7218
7219 rettv->v_type = type;
7220 if (type != VAR_NUMBER)
7221 rettv->vval.v_string = NULL;
7222
7223 if (check_restricted() || check_secure())
7224 return;
7225
7226#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007227 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7229 {
7230 string_in = NULL;
7231 if (argvars[2].v_type == VAR_STRING)
7232 string_in = argvars[2].vval.v_string;
7233 if (type == VAR_NUMBER)
7234 string_result = NULL;
7235 else
7236 string_result = &rettv->vval.v_string;
7237 if (mch_libcall(argvars[0].vval.v_string,
7238 argvars[1].vval.v_string,
7239 string_in,
7240 argvars[2].vval.v_number,
7241 string_result,
7242 &nr_result) == OK
7243 && type == VAR_NUMBER)
7244 rettv->vval.v_number = nr_result;
7245 }
7246#endif
7247}
7248
7249/*
7250 * "libcall()" function
7251 */
7252 static void
7253f_libcall(typval_T *argvars, typval_T *rettv)
7254{
7255 libcall_common(argvars, rettv, VAR_STRING);
7256}
7257
7258/*
7259 * "libcallnr()" function
7260 */
7261 static void
7262f_libcallnr(typval_T *argvars, typval_T *rettv)
7263{
7264 libcall_common(argvars, rettv, VAR_NUMBER);
7265}
7266
7267/*
7268 * "line(string)" function
7269 */
7270 static void
7271f_line(typval_T *argvars, typval_T *rettv)
7272{
7273 linenr_T lnum = 0;
7274 pos_T *fp;
7275 int fnum;
7276
7277 fp = var2fpos(&argvars[0], TRUE, &fnum);
7278 if (fp != NULL)
7279 lnum = fp->lnum;
7280 rettv->vval.v_number = lnum;
7281}
7282
7283/*
7284 * "line2byte(lnum)" function
7285 */
7286 static void
7287f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7288{
7289#ifndef FEAT_BYTEOFF
7290 rettv->vval.v_number = -1;
7291#else
7292 linenr_T lnum;
7293
7294 lnum = get_tv_lnum(argvars);
7295 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7296 rettv->vval.v_number = -1;
7297 else
7298 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7299 if (rettv->vval.v_number >= 0)
7300 ++rettv->vval.v_number;
7301#endif
7302}
7303
7304/*
7305 * "lispindent(lnum)" function
7306 */
7307 static void
7308f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7309{
7310#ifdef FEAT_LISP
7311 pos_T pos;
7312 linenr_T lnum;
7313
7314 pos = curwin->w_cursor;
7315 lnum = get_tv_lnum(argvars);
7316 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7317 {
7318 curwin->w_cursor.lnum = lnum;
7319 rettv->vval.v_number = get_lisp_indent();
7320 curwin->w_cursor = pos;
7321 }
7322 else
7323#endif
7324 rettv->vval.v_number = -1;
7325}
7326
7327/*
7328 * "localtime()" function
7329 */
7330 static void
7331f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7332{
7333 rettv->vval.v_number = (varnumber_T)time(NULL);
7334}
7335
7336static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7337
7338 static void
7339get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7340{
7341 char_u *keys;
7342 char_u *which;
7343 char_u buf[NUMBUFLEN];
7344 char_u *keys_buf = NULL;
7345 char_u *rhs;
7346 int mode;
7347 int abbr = FALSE;
7348 int get_dict = FALSE;
7349 mapblock_T *mp;
7350 int buffer_local;
7351
7352 /* return empty string for failure */
7353 rettv->v_type = VAR_STRING;
7354 rettv->vval.v_string = NULL;
7355
7356 keys = get_tv_string(&argvars[0]);
7357 if (*keys == NUL)
7358 return;
7359
7360 if (argvars[1].v_type != VAR_UNKNOWN)
7361 {
7362 which = get_tv_string_buf_chk(&argvars[1], buf);
7363 if (argvars[2].v_type != VAR_UNKNOWN)
7364 {
7365 abbr = (int)get_tv_number(&argvars[2]);
7366 if (argvars[3].v_type != VAR_UNKNOWN)
7367 get_dict = (int)get_tv_number(&argvars[3]);
7368 }
7369 }
7370 else
7371 which = (char_u *)"";
7372 if (which == NULL)
7373 return;
7374
7375 mode = get_map_mode(&which, 0);
7376
7377 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7378 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7379 vim_free(keys_buf);
7380
7381 if (!get_dict)
7382 {
7383 /* Return a string. */
7384 if (rhs != NULL)
7385 rettv->vval.v_string = str2special_save(rhs, FALSE);
7386
7387 }
7388 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7389 {
7390 /* Return a dictionary. */
7391 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7392 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7393 dict_T *dict = rettv->vval.v_dict;
7394
7395 dict_add_nr_str(dict, "lhs", 0L, lhs);
7396 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7397 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7398 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7399 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7400 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7401 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7402 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7403 dict_add_nr_str(dict, "mode", 0L, mapmode);
7404
7405 vim_free(lhs);
7406 vim_free(mapmode);
7407 }
7408}
7409
7410#ifdef FEAT_FLOAT
7411/*
7412 * "log()" function
7413 */
7414 static void
7415f_log(typval_T *argvars, typval_T *rettv)
7416{
7417 float_T f = 0.0;
7418
7419 rettv->v_type = VAR_FLOAT;
7420 if (get_float_arg(argvars, &f) == OK)
7421 rettv->vval.v_float = log(f);
7422 else
7423 rettv->vval.v_float = 0.0;
7424}
7425
7426/*
7427 * "log10()" function
7428 */
7429 static void
7430f_log10(typval_T *argvars, typval_T *rettv)
7431{
7432 float_T f = 0.0;
7433
7434 rettv->v_type = VAR_FLOAT;
7435 if (get_float_arg(argvars, &f) == OK)
7436 rettv->vval.v_float = log10(f);
7437 else
7438 rettv->vval.v_float = 0.0;
7439}
7440#endif
7441
7442#ifdef FEAT_LUA
7443/*
7444 * "luaeval()" function
7445 */
7446 static void
7447f_luaeval(typval_T *argvars, typval_T *rettv)
7448{
7449 char_u *str;
7450 char_u buf[NUMBUFLEN];
7451
7452 str = get_tv_string_buf(&argvars[0], buf);
7453 do_luaeval(str, argvars + 1, rettv);
7454}
7455#endif
7456
7457/*
7458 * "map()" function
7459 */
7460 static void
7461f_map(typval_T *argvars, typval_T *rettv)
7462{
7463 filter_map(argvars, rettv, TRUE);
7464}
7465
7466/*
7467 * "maparg()" function
7468 */
7469 static void
7470f_maparg(typval_T *argvars, typval_T *rettv)
7471{
7472 get_maparg(argvars, rettv, TRUE);
7473}
7474
7475/*
7476 * "mapcheck()" function
7477 */
7478 static void
7479f_mapcheck(typval_T *argvars, typval_T *rettv)
7480{
7481 get_maparg(argvars, rettv, FALSE);
7482}
7483
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007484typedef enum
7485{
7486 MATCH_END, /* matchend() */
7487 MATCH_MATCH, /* match() */
7488 MATCH_STR, /* matchstr() */
7489 MATCH_LIST, /* matchlist() */
7490 MATCH_POS /* matchstrpos() */
7491} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492
7493 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007494find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495{
7496 char_u *str = NULL;
7497 long len = 0;
7498 char_u *expr = NULL;
7499 char_u *pat;
7500 regmatch_T regmatch;
7501 char_u patbuf[NUMBUFLEN];
7502 char_u strbuf[NUMBUFLEN];
7503 char_u *save_cpo;
7504 long start = 0;
7505 long nth = 1;
7506 colnr_T startcol = 0;
7507 int match = 0;
7508 list_T *l = NULL;
7509 listitem_T *li = NULL;
7510 long idx = 0;
7511 char_u *tofree = NULL;
7512
7513 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7514 save_cpo = p_cpo;
7515 p_cpo = (char_u *)"";
7516
7517 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007518 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007520 /* type MATCH_LIST: return empty list when there are no matches.
7521 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 if (rettv_list_alloc(rettv) == FAIL)
7523 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007524 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525 && (list_append_string(rettv->vval.v_list,
7526 (char_u *)"", 0) == FAIL
7527 || list_append_number(rettv->vval.v_list,
7528 (varnumber_T)-1) == 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 {
7534 list_free(rettv->vval.v_list);
7535 rettv->vval.v_list = NULL;
7536 goto theend;
7537 }
7538 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007539 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540 {
7541 rettv->v_type = VAR_STRING;
7542 rettv->vval.v_string = NULL;
7543 }
7544
7545 if (argvars[0].v_type == VAR_LIST)
7546 {
7547 if ((l = argvars[0].vval.v_list) == NULL)
7548 goto theend;
7549 li = l->lv_first;
7550 }
7551 else
7552 {
7553 expr = str = get_tv_string(&argvars[0]);
7554 len = (long)STRLEN(str);
7555 }
7556
7557 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7558 if (pat == NULL)
7559 goto theend;
7560
7561 if (argvars[2].v_type != VAR_UNKNOWN)
7562 {
7563 int error = FALSE;
7564
7565 start = (long)get_tv_number_chk(&argvars[2], &error);
7566 if (error)
7567 goto theend;
7568 if (l != NULL)
7569 {
7570 li = list_find(l, start);
7571 if (li == NULL)
7572 goto theend;
7573 idx = l->lv_idx; /* use the cached index */
7574 }
7575 else
7576 {
7577 if (start < 0)
7578 start = 0;
7579 if (start > len)
7580 goto theend;
7581 /* When "count" argument is there ignore matches before "start",
7582 * otherwise skip part of the string. Differs when pattern is "^"
7583 * or "\<". */
7584 if (argvars[3].v_type != VAR_UNKNOWN)
7585 startcol = start;
7586 else
7587 {
7588 str += start;
7589 len -= start;
7590 }
7591 }
7592
7593 if (argvars[3].v_type != VAR_UNKNOWN)
7594 nth = (long)get_tv_number_chk(&argvars[3], &error);
7595 if (error)
7596 goto theend;
7597 }
7598
7599 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7600 if (regmatch.regprog != NULL)
7601 {
7602 regmatch.rm_ic = p_ic;
7603
7604 for (;;)
7605 {
7606 if (l != NULL)
7607 {
7608 if (li == NULL)
7609 {
7610 match = FALSE;
7611 break;
7612 }
7613 vim_free(tofree);
7614 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7615 if (str == NULL)
7616 break;
7617 }
7618
7619 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7620
7621 if (match && --nth <= 0)
7622 break;
7623 if (l == NULL && !match)
7624 break;
7625
7626 /* Advance to just after the match. */
7627 if (l != NULL)
7628 {
7629 li = li->li_next;
7630 ++idx;
7631 }
7632 else
7633 {
7634#ifdef FEAT_MBYTE
7635 startcol = (colnr_T)(regmatch.startp[0]
7636 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7637#else
7638 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7639#endif
7640 if (startcol > (colnr_T)len
7641 || str + startcol <= regmatch.startp[0])
7642 {
7643 match = FALSE;
7644 break;
7645 }
7646 }
7647 }
7648
7649 if (match)
7650 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007651 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652 {
7653 listitem_T *li1 = rettv->vval.v_list->lv_first;
7654 listitem_T *li2 = li1->li_next;
7655 listitem_T *li3 = li2->li_next;
7656 listitem_T *li4 = li3->li_next;
7657
7658 vim_free(li1->li_tv.vval.v_string);
7659 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7660 (int)(regmatch.endp[0] - regmatch.startp[0]));
7661 li3->li_tv.vval.v_number =
7662 (varnumber_T)(regmatch.startp[0] - expr);
7663 li4->li_tv.vval.v_number =
7664 (varnumber_T)(regmatch.endp[0] - expr);
7665 if (l != NULL)
7666 li2->li_tv.vval.v_number = (varnumber_T)idx;
7667 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007668 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007669 {
7670 int i;
7671
7672 /* return list with matched string and submatches */
7673 for (i = 0; i < NSUBEXP; ++i)
7674 {
7675 if (regmatch.endp[i] == NULL)
7676 {
7677 if (list_append_string(rettv->vval.v_list,
7678 (char_u *)"", 0) == FAIL)
7679 break;
7680 }
7681 else if (list_append_string(rettv->vval.v_list,
7682 regmatch.startp[i],
7683 (int)(regmatch.endp[i] - regmatch.startp[i]))
7684 == FAIL)
7685 break;
7686 }
7687 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007688 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007689 {
7690 /* return matched string */
7691 if (l != NULL)
7692 copy_tv(&li->li_tv, rettv);
7693 else
7694 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7695 (int)(regmatch.endp[0] - regmatch.startp[0]));
7696 }
7697 else if (l != NULL)
7698 rettv->vval.v_number = idx;
7699 else
7700 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007701 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007702 rettv->vval.v_number =
7703 (varnumber_T)(regmatch.startp[0] - str);
7704 else
7705 rettv->vval.v_number =
7706 (varnumber_T)(regmatch.endp[0] - str);
7707 rettv->vval.v_number += (varnumber_T)(str - expr);
7708 }
7709 }
7710 vim_regfree(regmatch.regprog);
7711 }
7712
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007713theend:
7714 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007715 /* matchstrpos() without a list: drop the second item. */
7716 listitem_remove(rettv->vval.v_list,
7717 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007718 vim_free(tofree);
7719 p_cpo = save_cpo;
7720}
7721
7722/*
7723 * "match()" function
7724 */
7725 static void
7726f_match(typval_T *argvars, typval_T *rettv)
7727{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007728 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007729}
7730
7731/*
7732 * "matchadd()" function
7733 */
7734 static void
7735f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7736{
7737#ifdef FEAT_SEARCH_EXTRA
7738 char_u buf[NUMBUFLEN];
7739 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7740 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7741 int prio = 10; /* default priority */
7742 int id = -1;
7743 int error = FALSE;
7744 char_u *conceal_char = NULL;
7745
7746 rettv->vval.v_number = -1;
7747
7748 if (grp == NULL || pat == NULL)
7749 return;
7750 if (argvars[2].v_type != VAR_UNKNOWN)
7751 {
7752 prio = (int)get_tv_number_chk(&argvars[2], &error);
7753 if (argvars[3].v_type != VAR_UNKNOWN)
7754 {
7755 id = (int)get_tv_number_chk(&argvars[3], &error);
7756 if (argvars[4].v_type != VAR_UNKNOWN)
7757 {
7758 if (argvars[4].v_type != VAR_DICT)
7759 {
7760 EMSG(_(e_dictreq));
7761 return;
7762 }
7763 if (dict_find(argvars[4].vval.v_dict,
7764 (char_u *)"conceal", -1) != NULL)
7765 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7766 (char_u *)"conceal", FALSE);
7767 }
7768 }
7769 }
7770 if (error == TRUE)
7771 return;
7772 if (id >= 1 && id <= 3)
7773 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007774 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007775 return;
7776 }
7777
7778 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7779 conceal_char);
7780#endif
7781}
7782
7783/*
7784 * "matchaddpos()" function
7785 */
7786 static void
7787f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7788{
7789#ifdef FEAT_SEARCH_EXTRA
7790 char_u buf[NUMBUFLEN];
7791 char_u *group;
7792 int prio = 10;
7793 int id = -1;
7794 int error = FALSE;
7795 list_T *l;
7796 char_u *conceal_char = NULL;
7797
7798 rettv->vval.v_number = -1;
7799
7800 group = get_tv_string_buf_chk(&argvars[0], buf);
7801 if (group == NULL)
7802 return;
7803
7804 if (argvars[1].v_type != VAR_LIST)
7805 {
7806 EMSG2(_(e_listarg), "matchaddpos()");
7807 return;
7808 }
7809 l = argvars[1].vval.v_list;
7810 if (l == NULL)
7811 return;
7812
7813 if (argvars[2].v_type != VAR_UNKNOWN)
7814 {
7815 prio = (int)get_tv_number_chk(&argvars[2], &error);
7816 if (argvars[3].v_type != VAR_UNKNOWN)
7817 {
7818 id = (int)get_tv_number_chk(&argvars[3], &error);
7819 if (argvars[4].v_type != VAR_UNKNOWN)
7820 {
7821 if (argvars[4].v_type != VAR_DICT)
7822 {
7823 EMSG(_(e_dictreq));
7824 return;
7825 }
7826 if (dict_find(argvars[4].vval.v_dict,
7827 (char_u *)"conceal", -1) != NULL)
7828 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7829 (char_u *)"conceal", FALSE);
7830 }
7831 }
7832 }
7833 if (error == TRUE)
7834 return;
7835
7836 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7837 if (id == 1 || id == 2)
7838 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007839 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 return;
7841 }
7842
7843 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7844 conceal_char);
7845#endif
7846}
7847
7848/*
7849 * "matcharg()" function
7850 */
7851 static void
7852f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7853{
7854 if (rettv_list_alloc(rettv) == OK)
7855 {
7856#ifdef FEAT_SEARCH_EXTRA
7857 int id = (int)get_tv_number(&argvars[0]);
7858 matchitem_T *m;
7859
7860 if (id >= 1 && id <= 3)
7861 {
7862 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7863 {
7864 list_append_string(rettv->vval.v_list,
7865 syn_id2name(m->hlg_id), -1);
7866 list_append_string(rettv->vval.v_list, m->pattern, -1);
7867 }
7868 else
7869 {
7870 list_append_string(rettv->vval.v_list, NULL, -1);
7871 list_append_string(rettv->vval.v_list, NULL, -1);
7872 }
7873 }
7874#endif
7875 }
7876}
7877
7878/*
7879 * "matchdelete()" function
7880 */
7881 static void
7882f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7883{
7884#ifdef FEAT_SEARCH_EXTRA
7885 rettv->vval.v_number = match_delete(curwin,
7886 (int)get_tv_number(&argvars[0]), TRUE);
7887#endif
7888}
7889
7890/*
7891 * "matchend()" function
7892 */
7893 static void
7894f_matchend(typval_T *argvars, typval_T *rettv)
7895{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007896 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897}
7898
7899/*
7900 * "matchlist()" function
7901 */
7902 static void
7903f_matchlist(typval_T *argvars, typval_T *rettv)
7904{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007905 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007906}
7907
7908/*
7909 * "matchstr()" function
7910 */
7911 static void
7912f_matchstr(typval_T *argvars, typval_T *rettv)
7913{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007914 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007915}
7916
7917/*
7918 * "matchstrpos()" function
7919 */
7920 static void
7921f_matchstrpos(typval_T *argvars, typval_T *rettv)
7922{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007923 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924}
7925
7926static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7927
7928 static void
7929max_min(typval_T *argvars, typval_T *rettv, int domax)
7930{
7931 varnumber_T n = 0;
7932 varnumber_T i;
7933 int error = FALSE;
7934
7935 if (argvars[0].v_type == VAR_LIST)
7936 {
7937 list_T *l;
7938 listitem_T *li;
7939
7940 l = argvars[0].vval.v_list;
7941 if (l != NULL)
7942 {
7943 li = l->lv_first;
7944 if (li != NULL)
7945 {
7946 n = get_tv_number_chk(&li->li_tv, &error);
7947 for (;;)
7948 {
7949 li = li->li_next;
7950 if (li == NULL)
7951 break;
7952 i = get_tv_number_chk(&li->li_tv, &error);
7953 if (domax ? i > n : i < n)
7954 n = i;
7955 }
7956 }
7957 }
7958 }
7959 else if (argvars[0].v_type == VAR_DICT)
7960 {
7961 dict_T *d;
7962 int first = TRUE;
7963 hashitem_T *hi;
7964 int todo;
7965
7966 d = argvars[0].vval.v_dict;
7967 if (d != NULL)
7968 {
7969 todo = (int)d->dv_hashtab.ht_used;
7970 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7971 {
7972 if (!HASHITEM_EMPTY(hi))
7973 {
7974 --todo;
7975 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7976 if (first)
7977 {
7978 n = i;
7979 first = FALSE;
7980 }
7981 else if (domax ? i > n : i < n)
7982 n = i;
7983 }
7984 }
7985 }
7986 }
7987 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007988 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007989 rettv->vval.v_number = error ? 0 : n;
7990}
7991
7992/*
7993 * "max()" function
7994 */
7995 static void
7996f_max(typval_T *argvars, typval_T *rettv)
7997{
7998 max_min(argvars, rettv, TRUE);
7999}
8000
8001/*
8002 * "min()" function
8003 */
8004 static void
8005f_min(typval_T *argvars, typval_T *rettv)
8006{
8007 max_min(argvars, rettv, FALSE);
8008}
8009
8010static int mkdir_recurse(char_u *dir, int prot);
8011
8012/*
8013 * Create the directory in which "dir" is located, and higher levels when
8014 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008015 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008016 */
8017 static int
8018mkdir_recurse(char_u *dir, int prot)
8019{
8020 char_u *p;
8021 char_u *updir;
8022 int r = FAIL;
8023
8024 /* Get end of directory name in "dir".
8025 * We're done when it's "/" or "c:/". */
8026 p = gettail_sep(dir);
8027 if (p <= get_past_head(dir))
8028 return OK;
8029
8030 /* If the directory exists we're done. Otherwise: create it.*/
8031 updir = vim_strnsave(dir, (int)(p - dir));
8032 if (updir == NULL)
8033 return FAIL;
8034 if (mch_isdir(updir))
8035 r = OK;
8036 else if (mkdir_recurse(updir, prot) == OK)
8037 r = vim_mkdir_emsg(updir, prot);
8038 vim_free(updir);
8039 return r;
8040}
8041
8042#ifdef vim_mkdir
8043/*
8044 * "mkdir()" function
8045 */
8046 static void
8047f_mkdir(typval_T *argvars, typval_T *rettv)
8048{
8049 char_u *dir;
8050 char_u buf[NUMBUFLEN];
8051 int prot = 0755;
8052
8053 rettv->vval.v_number = FAIL;
8054 if (check_restricted() || check_secure())
8055 return;
8056
8057 dir = get_tv_string_buf(&argvars[0], buf);
8058 if (*dir == NUL)
8059 rettv->vval.v_number = FAIL;
8060 else
8061 {
8062 if (*gettail(dir) == NUL)
8063 /* remove trailing slashes */
8064 *gettail_sep(dir) = NUL;
8065
8066 if (argvars[1].v_type != VAR_UNKNOWN)
8067 {
8068 if (argvars[2].v_type != VAR_UNKNOWN)
8069 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8070 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8071 mkdir_recurse(dir, prot);
8072 }
8073 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
8074 }
8075}
8076#endif
8077
8078/*
8079 * "mode()" function
8080 */
8081 static void
8082f_mode(typval_T *argvars, typval_T *rettv)
8083{
8084 char_u buf[3];
8085
8086 buf[1] = NUL;
8087 buf[2] = NUL;
8088
8089 if (time_for_testing == 93784)
8090 {
8091 /* Testing the two-character code. */
8092 buf[0] = 'x';
8093 buf[1] = '!';
8094 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008095#ifdef FEAT_TERMINAL
8096 else if (term_use_loop())
8097 buf[0] = 't';
8098#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008099 else if (VIsual_active)
8100 {
8101 if (VIsual_select)
8102 buf[0] = VIsual_mode + 's' - 'v';
8103 else
8104 buf[0] = VIsual_mode;
8105 }
8106 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8107 || State == CONFIRM)
8108 {
8109 buf[0] = 'r';
8110 if (State == ASKMORE)
8111 buf[1] = 'm';
8112 else if (State == CONFIRM)
8113 buf[1] = '?';
8114 }
8115 else if (State == EXTERNCMD)
8116 buf[0] = '!';
8117 else if (State & INSERT)
8118 {
8119#ifdef FEAT_VREPLACE
8120 if (State & VREPLACE_FLAG)
8121 {
8122 buf[0] = 'R';
8123 buf[1] = 'v';
8124 }
8125 else
8126#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01008127 {
8128 if (State & REPLACE_FLAG)
8129 buf[0] = 'R';
8130 else
8131 buf[0] = 'i';
8132#ifdef FEAT_INS_EXPAND
8133 if (ins_compl_active())
8134 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008135 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008136 buf[1] = 'x';
8137#endif
8138 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008139 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008140 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141 {
8142 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008143 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008144 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008145 else if (exmode_active == EXMODE_NORMAL)
8146 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008147 }
8148 else
8149 {
8150 buf[0] = 'n';
8151 if (finish_op)
8152 buf[1] = 'o';
8153 }
8154
8155 /* Clear out the minor mode when the argument is not a non-zero number or
8156 * non-empty string. */
8157 if (!non_zero_arg(&argvars[0]))
8158 buf[1] = NUL;
8159
8160 rettv->vval.v_string = vim_strsave(buf);
8161 rettv->v_type = VAR_STRING;
8162}
8163
8164#if defined(FEAT_MZSCHEME) || defined(PROTO)
8165/*
8166 * "mzeval()" function
8167 */
8168 static void
8169f_mzeval(typval_T *argvars, typval_T *rettv)
8170{
8171 char_u *str;
8172 char_u buf[NUMBUFLEN];
8173
8174 str = get_tv_string_buf(&argvars[0], buf);
8175 do_mzeval(str, rettv);
8176}
8177
8178 void
8179mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8180{
8181 typval_T argvars[3];
8182
8183 argvars[0].v_type = VAR_STRING;
8184 argvars[0].vval.v_string = name;
8185 copy_tv(args, &argvars[1]);
8186 argvars[2].v_type = VAR_UNKNOWN;
8187 f_call(argvars, rettv);
8188 clear_tv(&argvars[1]);
8189}
8190#endif
8191
8192/*
8193 * "nextnonblank()" function
8194 */
8195 static void
8196f_nextnonblank(typval_T *argvars, typval_T *rettv)
8197{
8198 linenr_T lnum;
8199
8200 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8201 {
8202 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8203 {
8204 lnum = 0;
8205 break;
8206 }
8207 if (*skipwhite(ml_get(lnum)) != NUL)
8208 break;
8209 }
8210 rettv->vval.v_number = lnum;
8211}
8212
8213/*
8214 * "nr2char()" function
8215 */
8216 static void
8217f_nr2char(typval_T *argvars, typval_T *rettv)
8218{
8219 char_u buf[NUMBUFLEN];
8220
8221#ifdef FEAT_MBYTE
8222 if (has_mbyte)
8223 {
8224 int utf8 = 0;
8225
8226 if (argvars[1].v_type != VAR_UNKNOWN)
8227 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8228 if (utf8)
8229 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8230 else
8231 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8232 }
8233 else
8234#endif
8235 {
8236 buf[0] = (char_u)get_tv_number(&argvars[0]);
8237 buf[1] = NUL;
8238 }
8239 rettv->v_type = VAR_STRING;
8240 rettv->vval.v_string = vim_strsave(buf);
8241}
8242
8243/*
8244 * "or(expr, expr)" function
8245 */
8246 static void
8247f_or(typval_T *argvars, typval_T *rettv)
8248{
8249 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8250 | get_tv_number_chk(&argvars[1], NULL);
8251}
8252
8253/*
8254 * "pathshorten()" function
8255 */
8256 static void
8257f_pathshorten(typval_T *argvars, typval_T *rettv)
8258{
8259 char_u *p;
8260
8261 rettv->v_type = VAR_STRING;
8262 p = get_tv_string_chk(&argvars[0]);
8263 if (p == NULL)
8264 rettv->vval.v_string = NULL;
8265 else
8266 {
8267 p = vim_strsave(p);
8268 rettv->vval.v_string = p;
8269 if (p != NULL)
8270 shorten_dir(p);
8271 }
8272}
8273
8274#ifdef FEAT_PERL
8275/*
8276 * "perleval()" function
8277 */
8278 static void
8279f_perleval(typval_T *argvars, typval_T *rettv)
8280{
8281 char_u *str;
8282 char_u buf[NUMBUFLEN];
8283
8284 str = get_tv_string_buf(&argvars[0], buf);
8285 do_perleval(str, rettv);
8286}
8287#endif
8288
8289#ifdef FEAT_FLOAT
8290/*
8291 * "pow()" function
8292 */
8293 static void
8294f_pow(typval_T *argvars, typval_T *rettv)
8295{
8296 float_T fx = 0.0, fy = 0.0;
8297
8298 rettv->v_type = VAR_FLOAT;
8299 if (get_float_arg(argvars, &fx) == OK
8300 && get_float_arg(&argvars[1], &fy) == OK)
8301 rettv->vval.v_float = pow(fx, fy);
8302 else
8303 rettv->vval.v_float = 0.0;
8304}
8305#endif
8306
8307/*
8308 * "prevnonblank()" function
8309 */
8310 static void
8311f_prevnonblank(typval_T *argvars, typval_T *rettv)
8312{
8313 linenr_T lnum;
8314
8315 lnum = get_tv_lnum(argvars);
8316 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8317 lnum = 0;
8318 else
8319 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8320 --lnum;
8321 rettv->vval.v_number = lnum;
8322}
8323
8324/* This dummy va_list is here because:
8325 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8326 * - locally in the function results in a "used before set" warning
8327 * - using va_start() to initialize it gives "function with fixed args" error */
8328static va_list ap;
8329
8330/*
8331 * "printf()" function
8332 */
8333 static void
8334f_printf(typval_T *argvars, typval_T *rettv)
8335{
8336 char_u buf[NUMBUFLEN];
8337 int len;
8338 char_u *s;
8339 int saved_did_emsg = did_emsg;
8340 char *fmt;
8341
8342 rettv->v_type = VAR_STRING;
8343 rettv->vval.v_string = NULL;
8344
8345 /* Get the required length, allocate the buffer and do it for real. */
8346 did_emsg = FALSE;
8347 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008348 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008349 if (!did_emsg)
8350 {
8351 s = alloc(len + 1);
8352 if (s != NULL)
8353 {
8354 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008355 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8356 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008357 }
8358 }
8359 did_emsg |= saved_did_emsg;
8360}
8361
8362/*
8363 * "pumvisible()" function
8364 */
8365 static void
8366f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8367{
8368#ifdef FEAT_INS_EXPAND
8369 if (pum_visible())
8370 rettv->vval.v_number = 1;
8371#endif
8372}
8373
8374#ifdef FEAT_PYTHON3
8375/*
8376 * "py3eval()" function
8377 */
8378 static void
8379f_py3eval(typval_T *argvars, typval_T *rettv)
8380{
8381 char_u *str;
8382 char_u buf[NUMBUFLEN];
8383
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008384 if (p_pyx == 0)
8385 p_pyx = 3;
8386
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008387 str = get_tv_string_buf(&argvars[0], buf);
8388 do_py3eval(str, rettv);
8389}
8390#endif
8391
8392#ifdef FEAT_PYTHON
8393/*
8394 * "pyeval()" function
8395 */
8396 static void
8397f_pyeval(typval_T *argvars, typval_T *rettv)
8398{
8399 char_u *str;
8400 char_u buf[NUMBUFLEN];
8401
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008402 if (p_pyx == 0)
8403 p_pyx = 2;
8404
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008405 str = get_tv_string_buf(&argvars[0], buf);
8406 do_pyeval(str, rettv);
8407}
8408#endif
8409
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008410#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8411/*
8412 * "pyxeval()" function
8413 */
8414 static void
8415f_pyxeval(typval_T *argvars, typval_T *rettv)
8416{
8417# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8418 init_pyxversion();
8419 if (p_pyx == 2)
8420 f_pyeval(argvars, rettv);
8421 else
8422 f_py3eval(argvars, rettv);
8423# elif defined(FEAT_PYTHON)
8424 f_pyeval(argvars, rettv);
8425# elif defined(FEAT_PYTHON3)
8426 f_py3eval(argvars, rettv);
8427# endif
8428}
8429#endif
8430
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008431/*
8432 * "range()" function
8433 */
8434 static void
8435f_range(typval_T *argvars, typval_T *rettv)
8436{
8437 varnumber_T start;
8438 varnumber_T end;
8439 varnumber_T stride = 1;
8440 varnumber_T i;
8441 int error = FALSE;
8442
8443 start = get_tv_number_chk(&argvars[0], &error);
8444 if (argvars[1].v_type == VAR_UNKNOWN)
8445 {
8446 end = start - 1;
8447 start = 0;
8448 }
8449 else
8450 {
8451 end = get_tv_number_chk(&argvars[1], &error);
8452 if (argvars[2].v_type != VAR_UNKNOWN)
8453 stride = get_tv_number_chk(&argvars[2], &error);
8454 }
8455
8456 if (error)
8457 return; /* type error; errmsg already given */
8458 if (stride == 0)
8459 EMSG(_("E726: Stride is zero"));
8460 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8461 EMSG(_("E727: Start past end"));
8462 else
8463 {
8464 if (rettv_list_alloc(rettv) == OK)
8465 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8466 if (list_append_number(rettv->vval.v_list,
8467 (varnumber_T)i) == FAIL)
8468 break;
8469 }
8470}
8471
8472/*
8473 * "readfile()" function
8474 */
8475 static void
8476f_readfile(typval_T *argvars, typval_T *rettv)
8477{
8478 int binary = FALSE;
8479 int failed = FALSE;
8480 char_u *fname;
8481 FILE *fd;
8482 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8483 int io_size = sizeof(buf);
8484 int readlen; /* size of last fread() */
8485 char_u *prev = NULL; /* previously read bytes, if any */
8486 long prevlen = 0; /* length of data in prev */
8487 long prevsize = 0; /* size of prev buffer */
8488 long maxline = MAXLNUM;
8489 long cnt = 0;
8490 char_u *p; /* position in buf */
8491 char_u *start; /* start of current line */
8492
8493 if (argvars[1].v_type != VAR_UNKNOWN)
8494 {
8495 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8496 binary = TRUE;
8497 if (argvars[2].v_type != VAR_UNKNOWN)
8498 maxline = (long)get_tv_number(&argvars[2]);
8499 }
8500
8501 if (rettv_list_alloc(rettv) == FAIL)
8502 return;
8503
8504 /* Always open the file in binary mode, library functions have a mind of
8505 * their own about CR-LF conversion. */
8506 fname = get_tv_string(&argvars[0]);
8507 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8508 {
8509 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8510 return;
8511 }
8512
8513 while (cnt < maxline || maxline < 0)
8514 {
8515 readlen = (int)fread(buf, 1, io_size, fd);
8516
8517 /* This for loop processes what was read, but is also entered at end
8518 * of file so that either:
8519 * - an incomplete line gets written
8520 * - a "binary" file gets an empty line at the end if it ends in a
8521 * newline. */
8522 for (p = buf, start = buf;
8523 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8524 ++p)
8525 {
8526 if (*p == '\n' || readlen <= 0)
8527 {
8528 listitem_T *li;
8529 char_u *s = NULL;
8530 long_u len = p - start;
8531
8532 /* Finished a line. Remove CRs before NL. */
8533 if (readlen > 0 && !binary)
8534 {
8535 while (len > 0 && start[len - 1] == '\r')
8536 --len;
8537 /* removal may cross back to the "prev" string */
8538 if (len == 0)
8539 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8540 --prevlen;
8541 }
8542 if (prevlen == 0)
8543 s = vim_strnsave(start, (int)len);
8544 else
8545 {
8546 /* Change "prev" buffer to be the right size. This way
8547 * the bytes are only copied once, and very long lines are
8548 * allocated only once. */
8549 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8550 {
8551 mch_memmove(s + prevlen, start, len);
8552 s[prevlen + len] = NUL;
8553 prev = NULL; /* the list will own the string */
8554 prevlen = prevsize = 0;
8555 }
8556 }
8557 if (s == NULL)
8558 {
8559 do_outofmem_msg((long_u) prevlen + len + 1);
8560 failed = TRUE;
8561 break;
8562 }
8563
8564 if ((li = listitem_alloc()) == NULL)
8565 {
8566 vim_free(s);
8567 failed = TRUE;
8568 break;
8569 }
8570 li->li_tv.v_type = VAR_STRING;
8571 li->li_tv.v_lock = 0;
8572 li->li_tv.vval.v_string = s;
8573 list_append(rettv->vval.v_list, li);
8574
8575 start = p + 1; /* step over newline */
8576 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8577 break;
8578 }
8579 else if (*p == NUL)
8580 *p = '\n';
8581#ifdef FEAT_MBYTE
8582 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8583 * when finding the BF and check the previous two bytes. */
8584 else if (*p == 0xbf && enc_utf8 && !binary)
8585 {
8586 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8587 * + 1, these may be in the "prev" string. */
8588 char_u back1 = p >= buf + 1 ? p[-1]
8589 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8590 char_u back2 = p >= buf + 2 ? p[-2]
8591 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8592 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8593
8594 if (back2 == 0xef && back1 == 0xbb)
8595 {
8596 char_u *dest = p - 2;
8597
8598 /* Usually a BOM is at the beginning of a file, and so at
8599 * the beginning of a line; then we can just step over it.
8600 */
8601 if (start == dest)
8602 start = p + 1;
8603 else
8604 {
8605 /* have to shuffle buf to close gap */
8606 int adjust_prevlen = 0;
8607
8608 if (dest < buf)
8609 {
8610 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8611 dest = buf;
8612 }
8613 if (readlen > p - buf + 1)
8614 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8615 readlen -= 3 - adjust_prevlen;
8616 prevlen -= adjust_prevlen;
8617 p = dest - 1;
8618 }
8619 }
8620 }
8621#endif
8622 } /* for */
8623
8624 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8625 break;
8626 if (start < p)
8627 {
8628 /* There's part of a line in buf, store it in "prev". */
8629 if (p - start + prevlen >= prevsize)
8630 {
8631 /* need bigger "prev" buffer */
8632 char_u *newprev;
8633
8634 /* A common use case is ordinary text files and "prev" gets a
8635 * fragment of a line, so the first allocation is made
8636 * small, to avoid repeatedly 'allocing' large and
8637 * 'reallocing' small. */
8638 if (prevsize == 0)
8639 prevsize = (long)(p - start);
8640 else
8641 {
8642 long grow50pc = (prevsize * 3) / 2;
8643 long growmin = (long)((p - start) * 2 + prevlen);
8644 prevsize = grow50pc > growmin ? grow50pc : growmin;
8645 }
8646 newprev = prev == NULL ? alloc(prevsize)
8647 : vim_realloc(prev, prevsize);
8648 if (newprev == NULL)
8649 {
8650 do_outofmem_msg((long_u)prevsize);
8651 failed = TRUE;
8652 break;
8653 }
8654 prev = newprev;
8655 }
8656 /* Add the line part to end of "prev". */
8657 mch_memmove(prev + prevlen, start, p - start);
8658 prevlen += (long)(p - start);
8659 }
8660 } /* while */
8661
8662 /*
8663 * For a negative line count use only the lines at the end of the file,
8664 * free the rest.
8665 */
8666 if (!failed && maxline < 0)
8667 while (cnt > -maxline)
8668 {
8669 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8670 --cnt;
8671 }
8672
8673 if (failed)
8674 {
8675 list_free(rettv->vval.v_list);
8676 /* readfile doc says an empty list is returned on error */
8677 rettv->vval.v_list = list_alloc();
8678 }
8679
8680 vim_free(prev);
8681 fclose(fd);
8682}
8683
8684#if defined(FEAT_RELTIME)
8685static int list2proftime(typval_T *arg, proftime_T *tm);
8686
8687/*
8688 * Convert a List to proftime_T.
8689 * Return FAIL when there is something wrong.
8690 */
8691 static int
8692list2proftime(typval_T *arg, proftime_T *tm)
8693{
8694 long n1, n2;
8695 int error = FALSE;
8696
8697 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8698 || arg->vval.v_list->lv_len != 2)
8699 return FAIL;
8700 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8701 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8702# ifdef WIN3264
8703 tm->HighPart = n1;
8704 tm->LowPart = n2;
8705# else
8706 tm->tv_sec = n1;
8707 tm->tv_usec = n2;
8708# endif
8709 return error ? FAIL : OK;
8710}
8711#endif /* FEAT_RELTIME */
8712
8713/*
8714 * "reltime()" function
8715 */
8716 static void
8717f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8718{
8719#ifdef FEAT_RELTIME
8720 proftime_T res;
8721 proftime_T start;
8722
8723 if (argvars[0].v_type == VAR_UNKNOWN)
8724 {
8725 /* No arguments: get current time. */
8726 profile_start(&res);
8727 }
8728 else if (argvars[1].v_type == VAR_UNKNOWN)
8729 {
8730 if (list2proftime(&argvars[0], &res) == FAIL)
8731 return;
8732 profile_end(&res);
8733 }
8734 else
8735 {
8736 /* Two arguments: compute the difference. */
8737 if (list2proftime(&argvars[0], &start) == FAIL
8738 || list2proftime(&argvars[1], &res) == FAIL)
8739 return;
8740 profile_sub(&res, &start);
8741 }
8742
8743 if (rettv_list_alloc(rettv) == OK)
8744 {
8745 long n1, n2;
8746
8747# ifdef WIN3264
8748 n1 = res.HighPart;
8749 n2 = res.LowPart;
8750# else
8751 n1 = res.tv_sec;
8752 n2 = res.tv_usec;
8753# endif
8754 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8755 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8756 }
8757#endif
8758}
8759
8760#ifdef FEAT_FLOAT
8761/*
8762 * "reltimefloat()" function
8763 */
8764 static void
8765f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8766{
8767# ifdef FEAT_RELTIME
8768 proftime_T tm;
8769# endif
8770
8771 rettv->v_type = VAR_FLOAT;
8772 rettv->vval.v_float = 0;
8773# ifdef FEAT_RELTIME
8774 if (list2proftime(&argvars[0], &tm) == OK)
8775 rettv->vval.v_float = profile_float(&tm);
8776# endif
8777}
8778#endif
8779
8780/*
8781 * "reltimestr()" function
8782 */
8783 static void
8784f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8785{
8786#ifdef FEAT_RELTIME
8787 proftime_T tm;
8788#endif
8789
8790 rettv->v_type = VAR_STRING;
8791 rettv->vval.v_string = NULL;
8792#ifdef FEAT_RELTIME
8793 if (list2proftime(&argvars[0], &tm) == OK)
8794 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8795#endif
8796}
8797
8798#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8799static void make_connection(void);
8800static int check_connection(void);
8801
8802 static void
8803make_connection(void)
8804{
8805 if (X_DISPLAY == NULL
8806# ifdef FEAT_GUI
8807 && !gui.in_use
8808# endif
8809 )
8810 {
8811 x_force_connect = TRUE;
8812 setup_term_clip();
8813 x_force_connect = FALSE;
8814 }
8815}
8816
8817 static int
8818check_connection(void)
8819{
8820 make_connection();
8821 if (X_DISPLAY == NULL)
8822 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008823 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008824 return FAIL;
8825 }
8826 return OK;
8827}
8828#endif
8829
8830#ifdef FEAT_CLIENTSERVER
8831 static void
8832remote_common(typval_T *argvars, typval_T *rettv, int expr)
8833{
8834 char_u *server_name;
8835 char_u *keys;
8836 char_u *r = NULL;
8837 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008838 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008839# ifdef WIN32
8840 HWND w;
8841# else
8842 Window w;
8843# endif
8844
8845 if (check_restricted() || check_secure())
8846 return;
8847
8848# ifdef FEAT_X11
8849 if (check_connection() == FAIL)
8850 return;
8851# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008852 if (argvars[2].v_type != VAR_UNKNOWN
8853 && argvars[3].v_type != VAR_UNKNOWN)
8854 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008855
8856 server_name = get_tv_string_chk(&argvars[0]);
8857 if (server_name == NULL)
8858 return; /* type error; errmsg already given */
8859 keys = get_tv_string_buf(&argvars[1], buf);
8860# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008861 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008862# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008863 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8864 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008865# endif
8866 {
8867 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008868 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008869 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008870 vim_free(r);
8871 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008872 else
8873 EMSG2(_("E241: Unable to send to %s"), server_name);
8874 return;
8875 }
8876
8877 rettv->vval.v_string = r;
8878
8879 if (argvars[2].v_type != VAR_UNKNOWN)
8880 {
8881 dictitem_T v;
8882 char_u str[30];
8883 char_u *idvar;
8884
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008885 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008886 if (idvar != NULL && *idvar != NUL)
8887 {
8888 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8889 v.di_tv.v_type = VAR_STRING;
8890 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008891 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008892 vim_free(v.di_tv.vval.v_string);
8893 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008894 }
8895}
8896#endif
8897
8898/*
8899 * "remote_expr()" function
8900 */
8901 static void
8902f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8903{
8904 rettv->v_type = VAR_STRING;
8905 rettv->vval.v_string = NULL;
8906#ifdef FEAT_CLIENTSERVER
8907 remote_common(argvars, rettv, TRUE);
8908#endif
8909}
8910
8911/*
8912 * "remote_foreground()" function
8913 */
8914 static void
8915f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8916{
8917#ifdef FEAT_CLIENTSERVER
8918# ifdef WIN32
8919 /* On Win32 it's done in this application. */
8920 {
8921 char_u *server_name = get_tv_string_chk(&argvars[0]);
8922
8923 if (server_name != NULL)
8924 serverForeground(server_name);
8925 }
8926# else
8927 /* Send a foreground() expression to the server. */
8928 argvars[1].v_type = VAR_STRING;
8929 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8930 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008931 rettv->v_type = VAR_STRING;
8932 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008933 remote_common(argvars, rettv, TRUE);
8934 vim_free(argvars[1].vval.v_string);
8935# endif
8936#endif
8937}
8938
8939 static void
8940f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8941{
8942#ifdef FEAT_CLIENTSERVER
8943 dictitem_T v;
8944 char_u *s = NULL;
8945# ifdef WIN32
8946 long_u n = 0;
8947# endif
8948 char_u *serverid;
8949
8950 if (check_restricted() || check_secure())
8951 {
8952 rettv->vval.v_number = -1;
8953 return;
8954 }
8955 serverid = get_tv_string_chk(&argvars[0]);
8956 if (serverid == NULL)
8957 {
8958 rettv->vval.v_number = -1;
8959 return; /* type error; errmsg already given */
8960 }
8961# ifdef WIN32
8962 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8963 if (n == 0)
8964 rettv->vval.v_number = -1;
8965 else
8966 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008967 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008968 rettv->vval.v_number = (s != NULL);
8969 }
8970# else
8971 if (check_connection() == FAIL)
8972 return;
8973
8974 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8975 serverStrToWin(serverid), &s);
8976# endif
8977
8978 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8979 {
8980 char_u *retvar;
8981
8982 v.di_tv.v_type = VAR_STRING;
8983 v.di_tv.vval.v_string = vim_strsave(s);
8984 retvar = get_tv_string_chk(&argvars[1]);
8985 if (retvar != NULL)
8986 set_var(retvar, &v.di_tv, FALSE);
8987 vim_free(v.di_tv.vval.v_string);
8988 }
8989#else
8990 rettv->vval.v_number = -1;
8991#endif
8992}
8993
8994 static void
8995f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8996{
8997 char_u *r = NULL;
8998
8999#ifdef FEAT_CLIENTSERVER
9000 char_u *serverid = get_tv_string_chk(&argvars[0]);
9001
9002 if (serverid != NULL && !check_restricted() && !check_secure())
9003 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009004 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009005# ifdef WIN32
9006 /* The server's HWND is encoded in the 'id' parameter */
9007 long_u n = 0;
9008# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009009
9010 if (argvars[1].v_type != VAR_UNKNOWN)
9011 timeout = get_tv_number(&argvars[1]);
9012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009013# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009014 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9015 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009016 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009017 if (r == NULL)
9018# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009019 if (check_connection() == FAIL
9020 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9021 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009022# endif
9023 EMSG(_("E277: Unable to read a server reply"));
9024 }
9025#endif
9026 rettv->v_type = VAR_STRING;
9027 rettv->vval.v_string = r;
9028}
9029
9030/*
9031 * "remote_send()" function
9032 */
9033 static void
9034f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9035{
9036 rettv->v_type = VAR_STRING;
9037 rettv->vval.v_string = NULL;
9038#ifdef FEAT_CLIENTSERVER
9039 remote_common(argvars, rettv, FALSE);
9040#endif
9041}
9042
9043/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009044 * "remote_startserver()" function
9045 */
9046 static void
9047f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9048{
9049#ifdef FEAT_CLIENTSERVER
9050 char_u *server = get_tv_string_chk(&argvars[0]);
9051
9052 if (server == NULL)
9053 return; /* type error; errmsg already given */
9054 if (serverName != NULL)
9055 EMSG(_("E941: already started a server"));
9056 else
9057 {
9058# ifdef FEAT_X11
9059 if (check_connection() == OK)
9060 serverRegisterName(X_DISPLAY, server);
9061# else
9062 serverSetName(server);
9063# endif
9064 }
9065#else
9066 EMSG(_("E942: +clientserver feature not available"));
9067#endif
9068}
9069
9070/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009071 * "remove()" function
9072 */
9073 static void
9074f_remove(typval_T *argvars, typval_T *rettv)
9075{
9076 list_T *l;
9077 listitem_T *item, *item2;
9078 listitem_T *li;
9079 long idx;
9080 long end;
9081 char_u *key;
9082 dict_T *d;
9083 dictitem_T *di;
9084 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9085
9086 if (argvars[0].v_type == VAR_DICT)
9087 {
9088 if (argvars[2].v_type != VAR_UNKNOWN)
9089 EMSG2(_(e_toomanyarg), "remove()");
9090 else if ((d = argvars[0].vval.v_dict) != NULL
9091 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9092 {
9093 key = get_tv_string_chk(&argvars[1]);
9094 if (key != NULL)
9095 {
9096 di = dict_find(d, key, -1);
9097 if (di == NULL)
9098 EMSG2(_(e_dictkey), key);
9099 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9100 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9101 {
9102 *rettv = di->di_tv;
9103 init_tv(&di->di_tv);
9104 dictitem_remove(d, di);
9105 }
9106 }
9107 }
9108 }
9109 else if (argvars[0].v_type != VAR_LIST)
9110 EMSG2(_(e_listdictarg), "remove()");
9111 else if ((l = argvars[0].vval.v_list) != NULL
9112 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9113 {
9114 int error = FALSE;
9115
9116 idx = (long)get_tv_number_chk(&argvars[1], &error);
9117 if (error)
9118 ; /* type error: do nothing, errmsg already given */
9119 else if ((item = list_find(l, idx)) == NULL)
9120 EMSGN(_(e_listidx), idx);
9121 else
9122 {
9123 if (argvars[2].v_type == VAR_UNKNOWN)
9124 {
9125 /* Remove one item, return its value. */
9126 vimlist_remove(l, item, item);
9127 *rettv = item->li_tv;
9128 vim_free(item);
9129 }
9130 else
9131 {
9132 /* Remove range of items, return list with values. */
9133 end = (long)get_tv_number_chk(&argvars[2], &error);
9134 if (error)
9135 ; /* type error: do nothing */
9136 else if ((item2 = list_find(l, end)) == NULL)
9137 EMSGN(_(e_listidx), end);
9138 else
9139 {
9140 int cnt = 0;
9141
9142 for (li = item; li != NULL; li = li->li_next)
9143 {
9144 ++cnt;
9145 if (li == item2)
9146 break;
9147 }
9148 if (li == NULL) /* didn't find "item2" after "item" */
9149 EMSG(_(e_invrange));
9150 else
9151 {
9152 vimlist_remove(l, item, item2);
9153 if (rettv_list_alloc(rettv) == OK)
9154 {
9155 l = rettv->vval.v_list;
9156 l->lv_first = item;
9157 l->lv_last = item2;
9158 item->li_prev = NULL;
9159 item2->li_next = NULL;
9160 l->lv_len = cnt;
9161 }
9162 }
9163 }
9164 }
9165 }
9166 }
9167}
9168
9169/*
9170 * "rename({from}, {to})" function
9171 */
9172 static void
9173f_rename(typval_T *argvars, typval_T *rettv)
9174{
9175 char_u buf[NUMBUFLEN];
9176
9177 if (check_restricted() || check_secure())
9178 rettv->vval.v_number = -1;
9179 else
9180 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9181 get_tv_string_buf(&argvars[1], buf));
9182}
9183
9184/*
9185 * "repeat()" function
9186 */
9187 static void
9188f_repeat(typval_T *argvars, typval_T *rettv)
9189{
9190 char_u *p;
9191 int n;
9192 int slen;
9193 int len;
9194 char_u *r;
9195 int i;
9196
9197 n = (int)get_tv_number(&argvars[1]);
9198 if (argvars[0].v_type == VAR_LIST)
9199 {
9200 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9201 while (n-- > 0)
9202 if (list_extend(rettv->vval.v_list,
9203 argvars[0].vval.v_list, NULL) == FAIL)
9204 break;
9205 }
9206 else
9207 {
9208 p = get_tv_string(&argvars[0]);
9209 rettv->v_type = VAR_STRING;
9210 rettv->vval.v_string = NULL;
9211
9212 slen = (int)STRLEN(p);
9213 len = slen * n;
9214 if (len <= 0)
9215 return;
9216
9217 r = alloc(len + 1);
9218 if (r != NULL)
9219 {
9220 for (i = 0; i < n; i++)
9221 mch_memmove(r + i * slen, p, (size_t)slen);
9222 r[len] = NUL;
9223 }
9224
9225 rettv->vval.v_string = r;
9226 }
9227}
9228
9229/*
9230 * "resolve()" function
9231 */
9232 static void
9233f_resolve(typval_T *argvars, typval_T *rettv)
9234{
9235 char_u *p;
9236#ifdef HAVE_READLINK
9237 char_u *buf = NULL;
9238#endif
9239
9240 p = get_tv_string(&argvars[0]);
9241#ifdef FEAT_SHORTCUT
9242 {
9243 char_u *v = NULL;
9244
9245 v = mch_resolve_shortcut(p);
9246 if (v != NULL)
9247 rettv->vval.v_string = v;
9248 else
9249 rettv->vval.v_string = vim_strsave(p);
9250 }
9251#else
9252# ifdef HAVE_READLINK
9253 {
9254 char_u *cpy;
9255 int len;
9256 char_u *remain = NULL;
9257 char_u *q;
9258 int is_relative_to_current = FALSE;
9259 int has_trailing_pathsep = FALSE;
9260 int limit = 100;
9261
9262 p = vim_strsave(p);
9263
9264 if (p[0] == '.' && (vim_ispathsep(p[1])
9265 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9266 is_relative_to_current = TRUE;
9267
9268 len = STRLEN(p);
9269 if (len > 0 && after_pathsep(p, p + len))
9270 {
9271 has_trailing_pathsep = TRUE;
9272 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9273 }
9274
9275 q = getnextcomp(p);
9276 if (*q != NUL)
9277 {
9278 /* Separate the first path component in "p", and keep the
9279 * remainder (beginning with the path separator). */
9280 remain = vim_strsave(q - 1);
9281 q[-1] = NUL;
9282 }
9283
9284 buf = alloc(MAXPATHL + 1);
9285 if (buf == NULL)
9286 goto fail;
9287
9288 for (;;)
9289 {
9290 for (;;)
9291 {
9292 len = readlink((char *)p, (char *)buf, MAXPATHL);
9293 if (len <= 0)
9294 break;
9295 buf[len] = NUL;
9296
9297 if (limit-- == 0)
9298 {
9299 vim_free(p);
9300 vim_free(remain);
9301 EMSG(_("E655: Too many symbolic links (cycle?)"));
9302 rettv->vval.v_string = NULL;
9303 goto fail;
9304 }
9305
9306 /* Ensure that the result will have a trailing path separator
9307 * if the argument has one. */
9308 if (remain == NULL && has_trailing_pathsep)
9309 add_pathsep(buf);
9310
9311 /* Separate the first path component in the link value and
9312 * concatenate the remainders. */
9313 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9314 if (*q != NUL)
9315 {
9316 if (remain == NULL)
9317 remain = vim_strsave(q - 1);
9318 else
9319 {
9320 cpy = concat_str(q - 1, remain);
9321 if (cpy != NULL)
9322 {
9323 vim_free(remain);
9324 remain = cpy;
9325 }
9326 }
9327 q[-1] = NUL;
9328 }
9329
9330 q = gettail(p);
9331 if (q > p && *q == NUL)
9332 {
9333 /* Ignore trailing path separator. */
9334 q[-1] = NUL;
9335 q = gettail(p);
9336 }
9337 if (q > p && !mch_isFullName(buf))
9338 {
9339 /* symlink is relative to directory of argument */
9340 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9341 if (cpy != NULL)
9342 {
9343 STRCPY(cpy, p);
9344 STRCPY(gettail(cpy), buf);
9345 vim_free(p);
9346 p = cpy;
9347 }
9348 }
9349 else
9350 {
9351 vim_free(p);
9352 p = vim_strsave(buf);
9353 }
9354 }
9355
9356 if (remain == NULL)
9357 break;
9358
9359 /* Append the first path component of "remain" to "p". */
9360 q = getnextcomp(remain + 1);
9361 len = q - remain - (*q != NUL);
9362 cpy = vim_strnsave(p, STRLEN(p) + len);
9363 if (cpy != NULL)
9364 {
9365 STRNCAT(cpy, remain, len);
9366 vim_free(p);
9367 p = cpy;
9368 }
9369 /* Shorten "remain". */
9370 if (*q != NUL)
9371 STRMOVE(remain, q - 1);
9372 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009373 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009374 }
9375
9376 /* If the result is a relative path name, make it explicitly relative to
9377 * the current directory if and only if the argument had this form. */
9378 if (!vim_ispathsep(*p))
9379 {
9380 if (is_relative_to_current
9381 && *p != NUL
9382 && !(p[0] == '.'
9383 && (p[1] == NUL
9384 || vim_ispathsep(p[1])
9385 || (p[1] == '.'
9386 && (p[2] == NUL
9387 || vim_ispathsep(p[2]))))))
9388 {
9389 /* Prepend "./". */
9390 cpy = concat_str((char_u *)"./", p);
9391 if (cpy != NULL)
9392 {
9393 vim_free(p);
9394 p = cpy;
9395 }
9396 }
9397 else if (!is_relative_to_current)
9398 {
9399 /* Strip leading "./". */
9400 q = p;
9401 while (q[0] == '.' && vim_ispathsep(q[1]))
9402 q += 2;
9403 if (q > p)
9404 STRMOVE(p, p + 2);
9405 }
9406 }
9407
9408 /* Ensure that the result will have no trailing path separator
9409 * if the argument had none. But keep "/" or "//". */
9410 if (!has_trailing_pathsep)
9411 {
9412 q = p + STRLEN(p);
9413 if (after_pathsep(p, q))
9414 *gettail_sep(p) = NUL;
9415 }
9416
9417 rettv->vval.v_string = p;
9418 }
9419# else
9420 rettv->vval.v_string = vim_strsave(p);
9421# endif
9422#endif
9423
9424 simplify_filename(rettv->vval.v_string);
9425
9426#ifdef HAVE_READLINK
9427fail:
9428 vim_free(buf);
9429#endif
9430 rettv->v_type = VAR_STRING;
9431}
9432
9433/*
9434 * "reverse({list})" function
9435 */
9436 static void
9437f_reverse(typval_T *argvars, typval_T *rettv)
9438{
9439 list_T *l;
9440 listitem_T *li, *ni;
9441
9442 if (argvars[0].v_type != VAR_LIST)
9443 EMSG2(_(e_listarg), "reverse()");
9444 else if ((l = argvars[0].vval.v_list) != NULL
9445 && !tv_check_lock(l->lv_lock,
9446 (char_u *)N_("reverse() argument"), TRUE))
9447 {
9448 li = l->lv_last;
9449 l->lv_first = l->lv_last = NULL;
9450 l->lv_len = 0;
9451 while (li != NULL)
9452 {
9453 ni = li->li_prev;
9454 list_append(l, li);
9455 li = ni;
9456 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009457 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009458 l->lv_idx = l->lv_len - l->lv_idx - 1;
9459 }
9460}
9461
9462#define SP_NOMOVE 0x01 /* don't move cursor */
9463#define SP_REPEAT 0x02 /* repeat to find outer pair */
9464#define SP_RETCOUNT 0x04 /* return matchcount */
9465#define SP_SETPCMARK 0x08 /* set previous context mark */
9466#define SP_START 0x10 /* accept match at start position */
9467#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9468#define SP_END 0x40 /* leave cursor at end of match */
9469#define SP_COLUMN 0x80 /* start at cursor column */
9470
9471static int get_search_arg(typval_T *varp, int *flagsp);
9472
9473/*
9474 * Get flags for a search function.
9475 * Possibly sets "p_ws".
9476 * Returns BACKWARD, FORWARD or zero (for an error).
9477 */
9478 static int
9479get_search_arg(typval_T *varp, int *flagsp)
9480{
9481 int dir = FORWARD;
9482 char_u *flags;
9483 char_u nbuf[NUMBUFLEN];
9484 int mask;
9485
9486 if (varp->v_type != VAR_UNKNOWN)
9487 {
9488 flags = get_tv_string_buf_chk(varp, nbuf);
9489 if (flags == NULL)
9490 return 0; /* type error; errmsg already given */
9491 while (*flags != NUL)
9492 {
9493 switch (*flags)
9494 {
9495 case 'b': dir = BACKWARD; break;
9496 case 'w': p_ws = TRUE; break;
9497 case 'W': p_ws = FALSE; break;
9498 default: mask = 0;
9499 if (flagsp != NULL)
9500 switch (*flags)
9501 {
9502 case 'c': mask = SP_START; break;
9503 case 'e': mask = SP_END; break;
9504 case 'm': mask = SP_RETCOUNT; break;
9505 case 'n': mask = SP_NOMOVE; break;
9506 case 'p': mask = SP_SUBPAT; break;
9507 case 'r': mask = SP_REPEAT; break;
9508 case 's': mask = SP_SETPCMARK; break;
9509 case 'z': mask = SP_COLUMN; break;
9510 }
9511 if (mask == 0)
9512 {
9513 EMSG2(_(e_invarg2), flags);
9514 dir = 0;
9515 }
9516 else
9517 *flagsp |= mask;
9518 }
9519 if (dir == 0)
9520 break;
9521 ++flags;
9522 }
9523 }
9524 return dir;
9525}
9526
9527/*
9528 * Shared by search() and searchpos() functions.
9529 */
9530 static int
9531search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9532{
9533 int flags;
9534 char_u *pat;
9535 pos_T pos;
9536 pos_T save_cursor;
9537 int save_p_ws = p_ws;
9538 int dir;
9539 int retval = 0; /* default: FAIL */
9540 long lnum_stop = 0;
9541 proftime_T tm;
9542#ifdef FEAT_RELTIME
9543 long time_limit = 0;
9544#endif
9545 int options = SEARCH_KEEP;
9546 int subpatnum;
9547
9548 pat = get_tv_string(&argvars[0]);
9549 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9550 if (dir == 0)
9551 goto theend;
9552 flags = *flagsp;
9553 if (flags & SP_START)
9554 options |= SEARCH_START;
9555 if (flags & SP_END)
9556 options |= SEARCH_END;
9557 if (flags & SP_COLUMN)
9558 options |= SEARCH_COL;
9559
9560 /* Optional arguments: line number to stop searching and timeout. */
9561 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9562 {
9563 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9564 if (lnum_stop < 0)
9565 goto theend;
9566#ifdef FEAT_RELTIME
9567 if (argvars[3].v_type != VAR_UNKNOWN)
9568 {
9569 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9570 if (time_limit < 0)
9571 goto theend;
9572 }
9573#endif
9574 }
9575
9576#ifdef FEAT_RELTIME
9577 /* Set the time limit, if there is one. */
9578 profile_setlimit(time_limit, &tm);
9579#endif
9580
9581 /*
9582 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9583 * Check to make sure only those flags are set.
9584 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9585 * flags cannot be set. Check for that condition also.
9586 */
9587 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9588 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9589 {
9590 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9591 goto theend;
9592 }
9593
9594 pos = save_cursor = curwin->w_cursor;
9595 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009596 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009597 if (subpatnum != FAIL)
9598 {
9599 if (flags & SP_SUBPAT)
9600 retval = subpatnum;
9601 else
9602 retval = pos.lnum;
9603 if (flags & SP_SETPCMARK)
9604 setpcmark();
9605 curwin->w_cursor = pos;
9606 if (match_pos != NULL)
9607 {
9608 /* Store the match cursor position */
9609 match_pos->lnum = pos.lnum;
9610 match_pos->col = pos.col + 1;
9611 }
9612 /* "/$" will put the cursor after the end of the line, may need to
9613 * correct that here */
9614 check_cursor();
9615 }
9616
9617 /* If 'n' flag is used: restore cursor position. */
9618 if (flags & SP_NOMOVE)
9619 curwin->w_cursor = save_cursor;
9620 else
9621 curwin->w_set_curswant = TRUE;
9622theend:
9623 p_ws = save_p_ws;
9624
9625 return retval;
9626}
9627
9628#ifdef FEAT_FLOAT
9629
9630/*
9631 * round() is not in C90, use ceil() or floor() instead.
9632 */
9633 float_T
9634vim_round(float_T f)
9635{
9636 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9637}
9638
9639/*
9640 * "round({float})" function
9641 */
9642 static void
9643f_round(typval_T *argvars, typval_T *rettv)
9644{
9645 float_T f = 0.0;
9646
9647 rettv->v_type = VAR_FLOAT;
9648 if (get_float_arg(argvars, &f) == OK)
9649 rettv->vval.v_float = vim_round(f);
9650 else
9651 rettv->vval.v_float = 0.0;
9652}
9653#endif
9654
9655/*
9656 * "screenattr()" function
9657 */
9658 static void
9659f_screenattr(typval_T *argvars, typval_T *rettv)
9660{
9661 int row;
9662 int col;
9663 int c;
9664
9665 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9666 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9667 if (row < 0 || row >= screen_Rows
9668 || col < 0 || col >= screen_Columns)
9669 c = -1;
9670 else
9671 c = ScreenAttrs[LineOffset[row] + col];
9672 rettv->vval.v_number = c;
9673}
9674
9675/*
9676 * "screenchar()" function
9677 */
9678 static void
9679f_screenchar(typval_T *argvars, typval_T *rettv)
9680{
9681 int row;
9682 int col;
9683 int off;
9684 int c;
9685
9686 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9687 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9688 if (row < 0 || row >= screen_Rows
9689 || col < 0 || col >= screen_Columns)
9690 c = -1;
9691 else
9692 {
9693 off = LineOffset[row] + col;
9694#ifdef FEAT_MBYTE
9695 if (enc_utf8 && ScreenLinesUC[off] != 0)
9696 c = ScreenLinesUC[off];
9697 else
9698#endif
9699 c = ScreenLines[off];
9700 }
9701 rettv->vval.v_number = c;
9702}
9703
9704/*
9705 * "screencol()" function
9706 *
9707 * First column is 1 to be consistent with virtcol().
9708 */
9709 static void
9710f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9711{
9712 rettv->vval.v_number = screen_screencol() + 1;
9713}
9714
9715/*
9716 * "screenrow()" function
9717 */
9718 static void
9719f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9720{
9721 rettv->vval.v_number = screen_screenrow() + 1;
9722}
9723
9724/*
9725 * "search()" function
9726 */
9727 static void
9728f_search(typval_T *argvars, typval_T *rettv)
9729{
9730 int flags = 0;
9731
9732 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9733}
9734
9735/*
9736 * "searchdecl()" function
9737 */
9738 static void
9739f_searchdecl(typval_T *argvars, typval_T *rettv)
9740{
9741 int locally = 1;
9742 int thisblock = 0;
9743 int error = FALSE;
9744 char_u *name;
9745
9746 rettv->vval.v_number = 1; /* default: FAIL */
9747
9748 name = get_tv_string_chk(&argvars[0]);
9749 if (argvars[1].v_type != VAR_UNKNOWN)
9750 {
9751 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9752 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9753 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9754 }
9755 if (!error && name != NULL)
9756 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9757 locally, thisblock, SEARCH_KEEP) == FAIL;
9758}
9759
9760/*
9761 * Used by searchpair() and searchpairpos()
9762 */
9763 static int
9764searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9765{
9766 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009767 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009768 int save_p_ws = p_ws;
9769 int dir;
9770 int flags = 0;
9771 char_u nbuf1[NUMBUFLEN];
9772 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009773 int retval = 0; /* default: FAIL */
9774 long lnum_stop = 0;
9775 long time_limit = 0;
9776
9777 /* Get the three pattern arguments: start, middle, end. */
9778 spat = get_tv_string_chk(&argvars[0]);
9779 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9780 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9781 if (spat == NULL || mpat == NULL || epat == NULL)
9782 goto theend; /* type error */
9783
9784 /* Handle the optional fourth argument: flags */
9785 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9786 if (dir == 0)
9787 goto theend;
9788
9789 /* Don't accept SP_END or SP_SUBPAT.
9790 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9791 */
9792 if ((flags & (SP_END | SP_SUBPAT)) != 0
9793 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9794 {
9795 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9796 goto theend;
9797 }
9798
9799 /* Using 'r' implies 'W', otherwise it doesn't work. */
9800 if (flags & SP_REPEAT)
9801 p_ws = FALSE;
9802
9803 /* Optional fifth argument: skip expression */
9804 if (argvars[3].v_type == VAR_UNKNOWN
9805 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009806 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009807 else
9808 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009809 skip = &argvars[4];
9810 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9811 && skip->v_type != VAR_STRING)
9812 {
9813 /* Type error */
9814 goto theend;
9815 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009816 if (argvars[5].v_type != VAR_UNKNOWN)
9817 {
9818 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9819 if (lnum_stop < 0)
9820 goto theend;
9821#ifdef FEAT_RELTIME
9822 if (argvars[6].v_type != VAR_UNKNOWN)
9823 {
9824 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9825 if (time_limit < 0)
9826 goto theend;
9827 }
9828#endif
9829 }
9830 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009831
9832 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9833 match_pos, lnum_stop, time_limit);
9834
9835theend:
9836 p_ws = save_p_ws;
9837
9838 return retval;
9839}
9840
9841/*
9842 * "searchpair()" function
9843 */
9844 static void
9845f_searchpair(typval_T *argvars, typval_T *rettv)
9846{
9847 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9848}
9849
9850/*
9851 * "searchpairpos()" function
9852 */
9853 static void
9854f_searchpairpos(typval_T *argvars, typval_T *rettv)
9855{
9856 pos_T match_pos;
9857 int lnum = 0;
9858 int col = 0;
9859
9860 if (rettv_list_alloc(rettv) == FAIL)
9861 return;
9862
9863 if (searchpair_cmn(argvars, &match_pos) > 0)
9864 {
9865 lnum = match_pos.lnum;
9866 col = match_pos.col;
9867 }
9868
9869 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9870 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9871}
9872
9873/*
9874 * Search for a start/middle/end thing.
9875 * Used by searchpair(), see its documentation for the details.
9876 * Returns 0 or -1 for no match,
9877 */
9878 long
9879do_searchpair(
9880 char_u *spat, /* start pattern */
9881 char_u *mpat, /* middle pattern */
9882 char_u *epat, /* end pattern */
9883 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009884 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009885 int flags, /* SP_SETPCMARK and other SP_ values */
9886 pos_T *match_pos,
9887 linenr_T lnum_stop, /* stop at this line if not zero */
9888 long time_limit UNUSED) /* stop after this many msec */
9889{
9890 char_u *save_cpo;
9891 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9892 long retval = 0;
9893 pos_T pos;
9894 pos_T firstpos;
9895 pos_T foundpos;
9896 pos_T save_cursor;
9897 pos_T save_pos;
9898 int n;
9899 int r;
9900 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009901 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009902 int err;
9903 int options = SEARCH_KEEP;
9904 proftime_T tm;
9905
9906 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9907 save_cpo = p_cpo;
9908 p_cpo = empty_option;
9909
9910#ifdef FEAT_RELTIME
9911 /* Set the time limit, if there is one. */
9912 profile_setlimit(time_limit, &tm);
9913#endif
9914
9915 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9916 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009917 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9918 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009919 if (pat2 == NULL || pat3 == NULL)
9920 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009921 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009922 if (*mpat == NUL)
9923 STRCPY(pat3, pat2);
9924 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009925 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009926 spat, epat, mpat);
9927 if (flags & SP_START)
9928 options |= SEARCH_START;
9929
Bram Moolenaar48570482017-10-30 21:48:41 +01009930 if (skip != NULL)
9931 {
9932 /* Empty string means to not use the skip expression. */
9933 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9934 use_skip = skip->vval.v_string != NULL
9935 && *skip->vval.v_string != NUL;
9936 }
9937
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009938 save_cursor = curwin->w_cursor;
9939 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009940 CLEAR_POS(&firstpos);
9941 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009942 pat = pat3;
9943 for (;;)
9944 {
9945 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009946 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009947 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009948 /* didn't find it or found the first match again: FAIL */
9949 break;
9950
9951 if (firstpos.lnum == 0)
9952 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009953 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009954 {
9955 /* Found the same position again. Can happen with a pattern that
9956 * has "\zs" at the end and searching backwards. Advance one
9957 * character and try again. */
9958 if (dir == BACKWARD)
9959 decl(&pos);
9960 else
9961 incl(&pos);
9962 }
9963 foundpos = pos;
9964
9965 /* clear the start flag to avoid getting stuck here */
9966 options &= ~SEARCH_START;
9967
9968 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009969 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009970 {
9971 save_pos = curwin->w_cursor;
9972 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009973 err = FALSE;
9974 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009975 curwin->w_cursor = save_pos;
9976 if (err)
9977 {
9978 /* Evaluating {skip} caused an error, break here. */
9979 curwin->w_cursor = save_cursor;
9980 retval = -1;
9981 break;
9982 }
9983 if (r)
9984 continue;
9985 }
9986
9987 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9988 {
9989 /* Found end when searching backwards or start when searching
9990 * forward: nested pair. */
9991 ++nest;
9992 pat = pat2; /* nested, don't search for middle */
9993 }
9994 else
9995 {
9996 /* Found end when searching forward or start when searching
9997 * backward: end of (nested) pair; or found middle in outer pair. */
9998 if (--nest == 1)
9999 pat = pat3; /* outer level, search for middle */
10000 }
10001
10002 if (nest == 0)
10003 {
10004 /* Found the match: return matchcount or line number. */
10005 if (flags & SP_RETCOUNT)
10006 ++retval;
10007 else
10008 retval = pos.lnum;
10009 if (flags & SP_SETPCMARK)
10010 setpcmark();
10011 curwin->w_cursor = pos;
10012 if (!(flags & SP_REPEAT))
10013 break;
10014 nest = 1; /* search for next unmatched */
10015 }
10016 }
10017
10018 if (match_pos != NULL)
10019 {
10020 /* Store the match cursor position */
10021 match_pos->lnum = curwin->w_cursor.lnum;
10022 match_pos->col = curwin->w_cursor.col + 1;
10023 }
10024
10025 /* If 'n' flag is used or search failed: restore cursor position. */
10026 if ((flags & SP_NOMOVE) || retval == 0)
10027 curwin->w_cursor = save_cursor;
10028
10029theend:
10030 vim_free(pat2);
10031 vim_free(pat3);
10032 if (p_cpo == empty_option)
10033 p_cpo = save_cpo;
10034 else
10035 /* Darn, evaluating the {skip} expression changed the value. */
10036 free_string_option(save_cpo);
10037
10038 return retval;
10039}
10040
10041/*
10042 * "searchpos()" function
10043 */
10044 static void
10045f_searchpos(typval_T *argvars, typval_T *rettv)
10046{
10047 pos_T match_pos;
10048 int lnum = 0;
10049 int col = 0;
10050 int n;
10051 int flags = 0;
10052
10053 if (rettv_list_alloc(rettv) == FAIL)
10054 return;
10055
10056 n = search_cmn(argvars, &match_pos, &flags);
10057 if (n > 0)
10058 {
10059 lnum = match_pos.lnum;
10060 col = match_pos.col;
10061 }
10062
10063 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10064 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10065 if (flags & SP_SUBPAT)
10066 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10067}
10068
10069 static void
10070f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10071{
10072#ifdef FEAT_CLIENTSERVER
10073 char_u buf[NUMBUFLEN];
10074 char_u *server = get_tv_string_chk(&argvars[0]);
10075 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10076
10077 rettv->vval.v_number = -1;
10078 if (server == NULL || reply == NULL)
10079 return;
10080 if (check_restricted() || check_secure())
10081 return;
10082# ifdef FEAT_X11
10083 if (check_connection() == FAIL)
10084 return;
10085# endif
10086
10087 if (serverSendReply(server, reply) < 0)
10088 {
10089 EMSG(_("E258: Unable to send to client"));
10090 return;
10091 }
10092 rettv->vval.v_number = 0;
10093#else
10094 rettv->vval.v_number = -1;
10095#endif
10096}
10097
10098 static void
10099f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10100{
10101 char_u *r = NULL;
10102
10103#ifdef FEAT_CLIENTSERVER
10104# ifdef WIN32
10105 r = serverGetVimNames();
10106# else
10107 make_connection();
10108 if (X_DISPLAY != NULL)
10109 r = serverGetVimNames(X_DISPLAY);
10110# endif
10111#endif
10112 rettv->v_type = VAR_STRING;
10113 rettv->vval.v_string = r;
10114}
10115
10116/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010117 * Set line or list of lines in buffer "buf".
10118 */
10119 static void
10120set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
10121{
10122 char_u *line = NULL;
10123 list_T *l = NULL;
10124 listitem_T *li = NULL;
10125 long added = 0;
10126 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010127 buf_T *curbuf_save = NULL;
10128 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010129 int is_curbuf = buf == curbuf;
10130
Bram Moolenaar9d954202017-09-04 20:34:19 +020010131 /* When using the current buffer ml_mfp will be set if needed. Useful when
10132 * setline() is used on startup. For other buffers the buffer must be
10133 * loaded. */
10134 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010135 {
10136 rettv->vval.v_number = 1; /* FAIL */
10137 return;
10138 }
10139
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010140 if (!is_curbuf)
10141 {
10142 wininfo_T *wip;
10143
10144 curbuf_save = curbuf;
10145 curwin_save = curwin;
10146 curbuf = buf;
10147 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
10148 {
10149 if (wip->wi_win != NULL)
10150 {
10151 curwin = wip->wi_win;
10152 break;
10153 }
10154 }
10155 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010156
10157 lcount = curbuf->b_ml.ml_line_count;
10158
10159 if (lines->v_type == VAR_LIST)
10160 {
10161 l = lines->vval.v_list;
10162 li = l->lv_first;
10163 }
10164 else
10165 line = get_tv_string_chk(lines);
10166
10167 /* default result is zero == OK */
10168 for (;;)
10169 {
10170 if (l != NULL)
10171 {
10172 /* list argument, get next string */
10173 if (li == NULL)
10174 break;
10175 line = get_tv_string_chk(&li->li_tv);
10176 li = li->li_next;
10177 }
10178
10179 rettv->vval.v_number = 1; /* FAIL */
10180 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10181 break;
10182
10183 /* When coming here from Insert mode, sync undo, so that this can be
10184 * undone separately from what was previously inserted. */
10185 if (u_sync_once == 2)
10186 {
10187 u_sync_once = 1; /* notify that u_sync() was called */
10188 u_sync(TRUE);
10189 }
10190
10191 if (lnum <= curbuf->b_ml.ml_line_count)
10192 {
10193 /* existing line, replace it */
10194 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10195 {
10196 changed_bytes(lnum, 0);
10197 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10198 check_cursor_col();
10199 rettv->vval.v_number = 0; /* OK */
10200 }
10201 }
10202 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10203 {
10204 /* lnum is one past the last line, append the line */
10205 ++added;
10206 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10207 rettv->vval.v_number = 0; /* OK */
10208 }
10209
10210 if (l == NULL) /* only one string argument */
10211 break;
10212 ++lnum;
10213 }
10214
10215 if (added > 0)
10216 appended_lines_mark(lcount, added);
10217
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010218 if (!is_curbuf)
10219 {
10220 curbuf = curbuf_save;
10221 curwin = curwin_save;
10222 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010223}
10224
10225/*
10226 * "setbufline()" function
10227 */
10228 static void
10229f_setbufline(argvars, rettv)
10230 typval_T *argvars;
10231 typval_T *rettv;
10232{
10233 linenr_T lnum;
10234 buf_T *buf;
10235
10236 buf = get_buf_tv(&argvars[0], FALSE);
10237 if (buf == NULL)
10238 rettv->vval.v_number = 1; /* FAIL */
10239 else
10240 {
10241 lnum = get_tv_lnum_buf(&argvars[1], buf);
10242
10243 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10244 }
10245}
10246
10247/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010248 * "setbufvar()" function
10249 */
10250 static void
10251f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10252{
10253 buf_T *buf;
10254 char_u *varname, *bufvarname;
10255 typval_T *varp;
10256 char_u nbuf[NUMBUFLEN];
10257
10258 if (check_restricted() || check_secure())
10259 return;
10260 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10261 varname = get_tv_string_chk(&argvars[1]);
10262 buf = get_buf_tv(&argvars[0], FALSE);
10263 varp = &argvars[2];
10264
10265 if (buf != NULL && varname != NULL && varp != NULL)
10266 {
10267 if (*varname == '&')
10268 {
10269 long numval;
10270 char_u *strval;
10271 int error = FALSE;
10272 aco_save_T aco;
10273
10274 /* set curbuf to be our buf, temporarily */
10275 aucmd_prepbuf(&aco, buf);
10276
10277 ++varname;
10278 numval = (long)get_tv_number_chk(varp, &error);
10279 strval = get_tv_string_buf_chk(varp, nbuf);
10280 if (!error && strval != NULL)
10281 set_option_value(varname, numval, strval, OPT_LOCAL);
10282
10283 /* reset notion of buffer */
10284 aucmd_restbuf(&aco);
10285 }
10286 else
10287 {
10288 buf_T *save_curbuf = curbuf;
10289
10290 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10291 if (bufvarname != NULL)
10292 {
10293 curbuf = buf;
10294 STRCPY(bufvarname, "b:");
10295 STRCPY(bufvarname + 2, varname);
10296 set_var(bufvarname, varp, TRUE);
10297 vim_free(bufvarname);
10298 curbuf = save_curbuf;
10299 }
10300 }
10301 }
10302}
10303
10304 static void
10305f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10306{
10307 dict_T *d;
10308 dictitem_T *di;
10309 char_u *csearch;
10310
10311 if (argvars[0].v_type != VAR_DICT)
10312 {
10313 EMSG(_(e_dictreq));
10314 return;
10315 }
10316
10317 if ((d = argvars[0].vval.v_dict) != NULL)
10318 {
10319 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10320 if (csearch != NULL)
10321 {
10322#ifdef FEAT_MBYTE
10323 if (enc_utf8)
10324 {
10325 int pcc[MAX_MCO];
10326 int c = utfc_ptr2char(csearch, pcc);
10327
10328 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10329 }
10330 else
10331#endif
10332 set_last_csearch(PTR2CHAR(csearch),
10333 csearch, MB_PTR2LEN(csearch));
10334 }
10335
10336 di = dict_find(d, (char_u *)"forward", -1);
10337 if (di != NULL)
10338 set_csearch_direction((int)get_tv_number(&di->di_tv)
10339 ? FORWARD : BACKWARD);
10340
10341 di = dict_find(d, (char_u *)"until", -1);
10342 if (di != NULL)
10343 set_csearch_until(!!get_tv_number(&di->di_tv));
10344 }
10345}
10346
10347/*
10348 * "setcmdpos()" function
10349 */
10350 static void
10351f_setcmdpos(typval_T *argvars, typval_T *rettv)
10352{
10353 int pos = (int)get_tv_number(&argvars[0]) - 1;
10354
10355 if (pos >= 0)
10356 rettv->vval.v_number = set_cmdline_pos(pos);
10357}
10358
10359/*
10360 * "setfperm({fname}, {mode})" function
10361 */
10362 static void
10363f_setfperm(typval_T *argvars, typval_T *rettv)
10364{
10365 char_u *fname;
10366 char_u modebuf[NUMBUFLEN];
10367 char_u *mode_str;
10368 int i;
10369 int mask;
10370 int mode = 0;
10371
10372 rettv->vval.v_number = 0;
10373 fname = get_tv_string_chk(&argvars[0]);
10374 if (fname == NULL)
10375 return;
10376 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10377 if (mode_str == NULL)
10378 return;
10379 if (STRLEN(mode_str) != 9)
10380 {
10381 EMSG2(_(e_invarg2), mode_str);
10382 return;
10383 }
10384
10385 mask = 1;
10386 for (i = 8; i >= 0; --i)
10387 {
10388 if (mode_str[i] != '-')
10389 mode |= mask;
10390 mask = mask << 1;
10391 }
10392 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10393}
10394
10395/*
10396 * "setline()" function
10397 */
10398 static void
10399f_setline(typval_T *argvars, typval_T *rettv)
10400{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010401 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010402
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010403 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010404}
10405
Bram Moolenaard823fa92016-08-12 16:29:27 +020010406static 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 +020010407
10408/*
10409 * Used by "setqflist()" and "setloclist()" functions
10410 */
10411 static void
10412set_qf_ll_list(
10413 win_T *wp UNUSED,
10414 typval_T *list_arg UNUSED,
10415 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010416 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010417 typval_T *rettv)
10418{
10419#ifdef FEAT_QUICKFIX
10420 static char *e_invact = N_("E927: Invalid action: '%s'");
10421 char_u *act;
10422 int action = 0;
10423#endif
10424
10425 rettv->vval.v_number = -1;
10426
10427#ifdef FEAT_QUICKFIX
10428 if (list_arg->v_type != VAR_LIST)
10429 EMSG(_(e_listreq));
10430 else
10431 {
10432 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010433 dict_T *d = NULL;
10434 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010435
10436 if (action_arg->v_type == VAR_STRING)
10437 {
10438 act = get_tv_string_chk(action_arg);
10439 if (act == NULL)
10440 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010441 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10442 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010443 action = *act;
10444 else
10445 EMSG2(_(e_invact), act);
10446 }
10447 else if (action_arg->v_type == VAR_UNKNOWN)
10448 action = ' ';
10449 else
10450 EMSG(_(e_stringreq));
10451
Bram Moolenaard823fa92016-08-12 16:29:27 +020010452 if (action_arg->v_type != VAR_UNKNOWN
10453 && what_arg->v_type != VAR_UNKNOWN)
10454 {
10455 if (what_arg->v_type == VAR_DICT)
10456 d = what_arg->vval.v_dict;
10457 else
10458 {
10459 EMSG(_(e_dictreq));
10460 valid_dict = FALSE;
10461 }
10462 }
10463
10464 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10465 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010466 rettv->vval.v_number = 0;
10467 }
10468#endif
10469}
10470
10471/*
10472 * "setloclist()" function
10473 */
10474 static void
10475f_setloclist(typval_T *argvars, typval_T *rettv)
10476{
10477 win_T *win;
10478
10479 rettv->vval.v_number = -1;
10480
10481 win = find_win_by_nr(&argvars[0], NULL);
10482 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010483 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010484}
10485
10486/*
10487 * "setmatches()" function
10488 */
10489 static void
10490f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10491{
10492#ifdef FEAT_SEARCH_EXTRA
10493 list_T *l;
10494 listitem_T *li;
10495 dict_T *d;
10496 list_T *s = NULL;
10497
10498 rettv->vval.v_number = -1;
10499 if (argvars[0].v_type != VAR_LIST)
10500 {
10501 EMSG(_(e_listreq));
10502 return;
10503 }
10504 if ((l = argvars[0].vval.v_list) != NULL)
10505 {
10506
10507 /* To some extent make sure that we are dealing with a list from
10508 * "getmatches()". */
10509 li = l->lv_first;
10510 while (li != NULL)
10511 {
10512 if (li->li_tv.v_type != VAR_DICT
10513 || (d = li->li_tv.vval.v_dict) == NULL)
10514 {
10515 EMSG(_(e_invarg));
10516 return;
10517 }
10518 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10519 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10520 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10521 && dict_find(d, (char_u *)"priority", -1) != NULL
10522 && dict_find(d, (char_u *)"id", -1) != NULL))
10523 {
10524 EMSG(_(e_invarg));
10525 return;
10526 }
10527 li = li->li_next;
10528 }
10529
10530 clear_matches(curwin);
10531 li = l->lv_first;
10532 while (li != NULL)
10533 {
10534 int i = 0;
10535 char_u buf[5];
10536 dictitem_T *di;
10537 char_u *group;
10538 int priority;
10539 int id;
10540 char_u *conceal;
10541
10542 d = li->li_tv.vval.v_dict;
10543 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10544 {
10545 if (s == NULL)
10546 {
10547 s = list_alloc();
10548 if (s == NULL)
10549 return;
10550 }
10551
10552 /* match from matchaddpos() */
10553 for (i = 1; i < 9; i++)
10554 {
10555 sprintf((char *)buf, (char *)"pos%d", i);
10556 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10557 {
10558 if (di->di_tv.v_type != VAR_LIST)
10559 return;
10560
10561 list_append_tv(s, &di->di_tv);
10562 s->lv_refcount++;
10563 }
10564 else
10565 break;
10566 }
10567 }
10568
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010569 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010570 priority = (int)get_dict_number(d, (char_u *)"priority");
10571 id = (int)get_dict_number(d, (char_u *)"id");
10572 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010573 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010574 : NULL;
10575 if (i == 0)
10576 {
10577 match_add(curwin, group,
10578 get_dict_string(d, (char_u *)"pattern", FALSE),
10579 priority, id, NULL, conceal);
10580 }
10581 else
10582 {
10583 match_add(curwin, group, NULL, priority, id, s, conceal);
10584 list_unref(s);
10585 s = NULL;
10586 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010587 vim_free(group);
10588 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010589
10590 li = li->li_next;
10591 }
10592 rettv->vval.v_number = 0;
10593 }
10594#endif
10595}
10596
10597/*
10598 * "setpos()" function
10599 */
10600 static void
10601f_setpos(typval_T *argvars, typval_T *rettv)
10602{
10603 pos_T pos;
10604 int fnum;
10605 char_u *name;
10606 colnr_T curswant = -1;
10607
10608 rettv->vval.v_number = -1;
10609 name = get_tv_string_chk(argvars);
10610 if (name != NULL)
10611 {
10612 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10613 {
10614 if (--pos.col < 0)
10615 pos.col = 0;
10616 if (name[0] == '.' && name[1] == NUL)
10617 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010618 /* set cursor; "fnum" is ignored */
10619 curwin->w_cursor = pos;
10620 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010621 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010622 curwin->w_curswant = curswant - 1;
10623 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010624 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010625 check_cursor();
10626 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010627 }
10628 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10629 {
10630 /* set mark */
10631 if (setmark_pos(name[1], &pos, fnum) == OK)
10632 rettv->vval.v_number = 0;
10633 }
10634 else
10635 EMSG(_(e_invarg));
10636 }
10637 }
10638}
10639
10640/*
10641 * "setqflist()" function
10642 */
10643 static void
10644f_setqflist(typval_T *argvars, typval_T *rettv)
10645{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010646 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010647}
10648
10649/*
10650 * "setreg()" function
10651 */
10652 static void
10653f_setreg(typval_T *argvars, typval_T *rettv)
10654{
10655 int regname;
10656 char_u *strregname;
10657 char_u *stropt;
10658 char_u *strval;
10659 int append;
10660 char_u yank_type;
10661 long block_len;
10662
10663 block_len = -1;
10664 yank_type = MAUTO;
10665 append = FALSE;
10666
10667 strregname = get_tv_string_chk(argvars);
10668 rettv->vval.v_number = 1; /* FAIL is default */
10669
10670 if (strregname == NULL)
10671 return; /* type error; errmsg already given */
10672 regname = *strregname;
10673 if (regname == 0 || regname == '@')
10674 regname = '"';
10675
10676 if (argvars[2].v_type != VAR_UNKNOWN)
10677 {
10678 stropt = get_tv_string_chk(&argvars[2]);
10679 if (stropt == NULL)
10680 return; /* type error */
10681 for (; *stropt != NUL; ++stropt)
10682 switch (*stropt)
10683 {
10684 case 'a': case 'A': /* append */
10685 append = TRUE;
10686 break;
10687 case 'v': case 'c': /* character-wise selection */
10688 yank_type = MCHAR;
10689 break;
10690 case 'V': case 'l': /* line-wise selection */
10691 yank_type = MLINE;
10692 break;
10693 case 'b': case Ctrl_V: /* block-wise selection */
10694 yank_type = MBLOCK;
10695 if (VIM_ISDIGIT(stropt[1]))
10696 {
10697 ++stropt;
10698 block_len = getdigits(&stropt) - 1;
10699 --stropt;
10700 }
10701 break;
10702 }
10703 }
10704
10705 if (argvars[1].v_type == VAR_LIST)
10706 {
10707 char_u **lstval;
10708 char_u **allocval;
10709 char_u buf[NUMBUFLEN];
10710 char_u **curval;
10711 char_u **curallocval;
10712 list_T *ll = argvars[1].vval.v_list;
10713 listitem_T *li;
10714 int len;
10715
10716 /* If the list is NULL handle like an empty list. */
10717 len = ll == NULL ? 0 : ll->lv_len;
10718
10719 /* First half: use for pointers to result lines; second half: use for
10720 * pointers to allocated copies. */
10721 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10722 if (lstval == NULL)
10723 return;
10724 curval = lstval;
10725 allocval = lstval + len + 2;
10726 curallocval = allocval;
10727
10728 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10729 li = li->li_next)
10730 {
10731 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10732 if (strval == NULL)
10733 goto free_lstval;
10734 if (strval == buf)
10735 {
10736 /* Need to make a copy, next get_tv_string_buf_chk() will
10737 * overwrite the string. */
10738 strval = vim_strsave(buf);
10739 if (strval == NULL)
10740 goto free_lstval;
10741 *curallocval++ = strval;
10742 }
10743 *curval++ = strval;
10744 }
10745 *curval++ = NULL;
10746
10747 write_reg_contents_lst(regname, lstval, -1,
10748 append, yank_type, block_len);
10749free_lstval:
10750 while (curallocval > allocval)
10751 vim_free(*--curallocval);
10752 vim_free(lstval);
10753 }
10754 else
10755 {
10756 strval = get_tv_string_chk(&argvars[1]);
10757 if (strval == NULL)
10758 return;
10759 write_reg_contents_ex(regname, strval, -1,
10760 append, yank_type, block_len);
10761 }
10762 rettv->vval.v_number = 0;
10763}
10764
10765/*
10766 * "settabvar()" function
10767 */
10768 static void
10769f_settabvar(typval_T *argvars, typval_T *rettv)
10770{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010771 tabpage_T *save_curtab;
10772 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010773 char_u *varname, *tabvarname;
10774 typval_T *varp;
10775
10776 rettv->vval.v_number = 0;
10777
10778 if (check_restricted() || check_secure())
10779 return;
10780
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010781 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782 varname = get_tv_string_chk(&argvars[1]);
10783 varp = &argvars[2];
10784
Bram Moolenaar4033c552017-09-16 20:54:51 +020010785 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010786 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010787 save_curtab = curtab;
10788 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010789
10790 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10791 if (tabvarname != NULL)
10792 {
10793 STRCPY(tabvarname, "t:");
10794 STRCPY(tabvarname + 2, varname);
10795 set_var(tabvarname, varp, TRUE);
10796 vim_free(tabvarname);
10797 }
10798
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010799 /* Restore current tabpage */
10800 if (valid_tabpage(save_curtab))
10801 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010802 }
10803}
10804
10805/*
10806 * "settabwinvar()" function
10807 */
10808 static void
10809f_settabwinvar(typval_T *argvars, typval_T *rettv)
10810{
10811 setwinvar(argvars, rettv, 1);
10812}
10813
10814/*
10815 * "setwinvar()" function
10816 */
10817 static void
10818f_setwinvar(typval_T *argvars, typval_T *rettv)
10819{
10820 setwinvar(argvars, rettv, 0);
10821}
10822
10823#ifdef FEAT_CRYPT
10824/*
10825 * "sha256({string})" function
10826 */
10827 static void
10828f_sha256(typval_T *argvars, typval_T *rettv)
10829{
10830 char_u *p;
10831
10832 p = get_tv_string(&argvars[0]);
10833 rettv->vval.v_string = vim_strsave(
10834 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10835 rettv->v_type = VAR_STRING;
10836}
10837#endif /* FEAT_CRYPT */
10838
10839/*
10840 * "shellescape({string})" function
10841 */
10842 static void
10843f_shellescape(typval_T *argvars, typval_T *rettv)
10844{
Bram Moolenaar20615522017-06-05 18:46:26 +020010845 int do_special = non_zero_arg(&argvars[1]);
10846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010847 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010848 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010849 rettv->v_type = VAR_STRING;
10850}
10851
10852/*
10853 * shiftwidth() function
10854 */
10855 static void
10856f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10857{
10858 rettv->vval.v_number = get_sw_value(curbuf);
10859}
10860
10861/*
10862 * "simplify()" function
10863 */
10864 static void
10865f_simplify(typval_T *argvars, typval_T *rettv)
10866{
10867 char_u *p;
10868
10869 p = get_tv_string(&argvars[0]);
10870 rettv->vval.v_string = vim_strsave(p);
10871 simplify_filename(rettv->vval.v_string); /* simplify in place */
10872 rettv->v_type = VAR_STRING;
10873}
10874
10875#ifdef FEAT_FLOAT
10876/*
10877 * "sin()" function
10878 */
10879 static void
10880f_sin(typval_T *argvars, typval_T *rettv)
10881{
10882 float_T f = 0.0;
10883
10884 rettv->v_type = VAR_FLOAT;
10885 if (get_float_arg(argvars, &f) == OK)
10886 rettv->vval.v_float = sin(f);
10887 else
10888 rettv->vval.v_float = 0.0;
10889}
10890
10891/*
10892 * "sinh()" function
10893 */
10894 static void
10895f_sinh(typval_T *argvars, typval_T *rettv)
10896{
10897 float_T f = 0.0;
10898
10899 rettv->v_type = VAR_FLOAT;
10900 if (get_float_arg(argvars, &f) == OK)
10901 rettv->vval.v_float = sinh(f);
10902 else
10903 rettv->vval.v_float = 0.0;
10904}
10905#endif
10906
10907static int
10908#ifdef __BORLANDC__
10909 _RTLENTRYF
10910#endif
10911 item_compare(const void *s1, const void *s2);
10912static int
10913#ifdef __BORLANDC__
10914 _RTLENTRYF
10915#endif
10916 item_compare2(const void *s1, const void *s2);
10917
10918/* struct used in the array that's given to qsort() */
10919typedef struct
10920{
10921 listitem_T *item;
10922 int idx;
10923} sortItem_T;
10924
10925/* struct storing information about current sort */
10926typedef struct
10927{
10928 int item_compare_ic;
10929 int item_compare_numeric;
10930 int item_compare_numbers;
10931#ifdef FEAT_FLOAT
10932 int item_compare_float;
10933#endif
10934 char_u *item_compare_func;
10935 partial_T *item_compare_partial;
10936 dict_T *item_compare_selfdict;
10937 int item_compare_func_err;
10938 int item_compare_keep_zero;
10939} sortinfo_T;
10940static sortinfo_T *sortinfo = NULL;
10941static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10942#define ITEM_COMPARE_FAIL 999
10943
10944/*
10945 * Compare functions for f_sort() and f_uniq() below.
10946 */
10947 static int
10948#ifdef __BORLANDC__
10949_RTLENTRYF
10950#endif
10951item_compare(const void *s1, const void *s2)
10952{
10953 sortItem_T *si1, *si2;
10954 typval_T *tv1, *tv2;
10955 char_u *p1, *p2;
10956 char_u *tofree1 = NULL, *tofree2 = NULL;
10957 int res;
10958 char_u numbuf1[NUMBUFLEN];
10959 char_u numbuf2[NUMBUFLEN];
10960
10961 si1 = (sortItem_T *)s1;
10962 si2 = (sortItem_T *)s2;
10963 tv1 = &si1->item->li_tv;
10964 tv2 = &si2->item->li_tv;
10965
10966 if (sortinfo->item_compare_numbers)
10967 {
10968 varnumber_T v1 = get_tv_number(tv1);
10969 varnumber_T v2 = get_tv_number(tv2);
10970
10971 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10972 }
10973
10974#ifdef FEAT_FLOAT
10975 if (sortinfo->item_compare_float)
10976 {
10977 float_T v1 = get_tv_float(tv1);
10978 float_T v2 = get_tv_float(tv2);
10979
10980 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10981 }
10982#endif
10983
10984 /* tv2string() puts quotes around a string and allocates memory. Don't do
10985 * that for string variables. Use a single quote when comparing with a
10986 * non-string to do what the docs promise. */
10987 if (tv1->v_type == VAR_STRING)
10988 {
10989 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10990 p1 = (char_u *)"'";
10991 else
10992 p1 = tv1->vval.v_string;
10993 }
10994 else
10995 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10996 if (tv2->v_type == VAR_STRING)
10997 {
10998 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10999 p2 = (char_u *)"'";
11000 else
11001 p2 = tv2->vval.v_string;
11002 }
11003 else
11004 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11005 if (p1 == NULL)
11006 p1 = (char_u *)"";
11007 if (p2 == NULL)
11008 p2 = (char_u *)"";
11009 if (!sortinfo->item_compare_numeric)
11010 {
11011 if (sortinfo->item_compare_ic)
11012 res = STRICMP(p1, p2);
11013 else
11014 res = STRCMP(p1, p2);
11015 }
11016 else
11017 {
11018 double n1, n2;
11019 n1 = strtod((char *)p1, (char **)&p1);
11020 n2 = strtod((char *)p2, (char **)&p2);
11021 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11022 }
11023
11024 /* When the result would be zero, compare the item indexes. Makes the
11025 * sort stable. */
11026 if (res == 0 && !sortinfo->item_compare_keep_zero)
11027 res = si1->idx > si2->idx ? 1 : -1;
11028
11029 vim_free(tofree1);
11030 vim_free(tofree2);
11031 return res;
11032}
11033
11034 static int
11035#ifdef __BORLANDC__
11036_RTLENTRYF
11037#endif
11038item_compare2(const void *s1, const void *s2)
11039{
11040 sortItem_T *si1, *si2;
11041 int res;
11042 typval_T rettv;
11043 typval_T argv[3];
11044 int dummy;
11045 char_u *func_name;
11046 partial_T *partial = sortinfo->item_compare_partial;
11047
11048 /* shortcut after failure in previous call; compare all items equal */
11049 if (sortinfo->item_compare_func_err)
11050 return 0;
11051
11052 si1 = (sortItem_T *)s1;
11053 si2 = (sortItem_T *)s2;
11054
11055 if (partial == NULL)
11056 func_name = sortinfo->item_compare_func;
11057 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011058 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059
11060 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11061 * in the copy without changing the original list items. */
11062 copy_tv(&si1->item->li_tv, &argv[0]);
11063 copy_tv(&si2->item->li_tv, &argv[1]);
11064
11065 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11066 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011067 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011068 partial, sortinfo->item_compare_selfdict);
11069 clear_tv(&argv[0]);
11070 clear_tv(&argv[1]);
11071
11072 if (res == FAIL)
11073 res = ITEM_COMPARE_FAIL;
11074 else
11075 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11076 if (sortinfo->item_compare_func_err)
11077 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11078 clear_tv(&rettv);
11079
11080 /* When the result would be zero, compare the pointers themselves. Makes
11081 * the sort stable. */
11082 if (res == 0 && !sortinfo->item_compare_keep_zero)
11083 res = si1->idx > si2->idx ? 1 : -1;
11084
11085 return res;
11086}
11087
11088/*
11089 * "sort({list})" function
11090 */
11091 static void
11092do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11093{
11094 list_T *l;
11095 listitem_T *li;
11096 sortItem_T *ptrs;
11097 sortinfo_T *old_sortinfo;
11098 sortinfo_T info;
11099 long len;
11100 long i;
11101
11102 /* Pointer to current info struct used in compare function. Save and
11103 * restore the current one for nested calls. */
11104 old_sortinfo = sortinfo;
11105 sortinfo = &info;
11106
11107 if (argvars[0].v_type != VAR_LIST)
11108 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11109 else
11110 {
11111 l = argvars[0].vval.v_list;
11112 if (l == NULL || tv_check_lock(l->lv_lock,
11113 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11114 TRUE))
11115 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011116 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011117
11118 len = list_len(l);
11119 if (len <= 1)
11120 goto theend; /* short list sorts pretty quickly */
11121
11122 info.item_compare_ic = FALSE;
11123 info.item_compare_numeric = FALSE;
11124 info.item_compare_numbers = FALSE;
11125#ifdef FEAT_FLOAT
11126 info.item_compare_float = FALSE;
11127#endif
11128 info.item_compare_func = NULL;
11129 info.item_compare_partial = NULL;
11130 info.item_compare_selfdict = NULL;
11131 if (argvars[1].v_type != VAR_UNKNOWN)
11132 {
11133 /* optional second argument: {func} */
11134 if (argvars[1].v_type == VAR_FUNC)
11135 info.item_compare_func = argvars[1].vval.v_string;
11136 else if (argvars[1].v_type == VAR_PARTIAL)
11137 info.item_compare_partial = argvars[1].vval.v_partial;
11138 else
11139 {
11140 int error = FALSE;
11141
11142 i = (long)get_tv_number_chk(&argvars[1], &error);
11143 if (error)
11144 goto theend; /* type error; errmsg already given */
11145 if (i == 1)
11146 info.item_compare_ic = TRUE;
11147 else if (argvars[1].v_type != VAR_NUMBER)
11148 info.item_compare_func = get_tv_string(&argvars[1]);
11149 else if (i != 0)
11150 {
11151 EMSG(_(e_invarg));
11152 goto theend;
11153 }
11154 if (info.item_compare_func != NULL)
11155 {
11156 if (*info.item_compare_func == NUL)
11157 {
11158 /* empty string means default sort */
11159 info.item_compare_func = NULL;
11160 }
11161 else if (STRCMP(info.item_compare_func, "n") == 0)
11162 {
11163 info.item_compare_func = NULL;
11164 info.item_compare_numeric = TRUE;
11165 }
11166 else if (STRCMP(info.item_compare_func, "N") == 0)
11167 {
11168 info.item_compare_func = NULL;
11169 info.item_compare_numbers = TRUE;
11170 }
11171#ifdef FEAT_FLOAT
11172 else if (STRCMP(info.item_compare_func, "f") == 0)
11173 {
11174 info.item_compare_func = NULL;
11175 info.item_compare_float = TRUE;
11176 }
11177#endif
11178 else if (STRCMP(info.item_compare_func, "i") == 0)
11179 {
11180 info.item_compare_func = NULL;
11181 info.item_compare_ic = TRUE;
11182 }
11183 }
11184 }
11185
11186 if (argvars[2].v_type != VAR_UNKNOWN)
11187 {
11188 /* optional third argument: {dict} */
11189 if (argvars[2].v_type != VAR_DICT)
11190 {
11191 EMSG(_(e_dictreq));
11192 goto theend;
11193 }
11194 info.item_compare_selfdict = argvars[2].vval.v_dict;
11195 }
11196 }
11197
11198 /* Make an array with each entry pointing to an item in the List. */
11199 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11200 if (ptrs == NULL)
11201 goto theend;
11202
11203 i = 0;
11204 if (sort)
11205 {
11206 /* sort(): ptrs will be the list to sort */
11207 for (li = l->lv_first; li != NULL; li = li->li_next)
11208 {
11209 ptrs[i].item = li;
11210 ptrs[i].idx = i;
11211 ++i;
11212 }
11213
11214 info.item_compare_func_err = FALSE;
11215 info.item_compare_keep_zero = FALSE;
11216 /* test the compare function */
11217 if ((info.item_compare_func != NULL
11218 || info.item_compare_partial != NULL)
11219 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11220 == ITEM_COMPARE_FAIL)
11221 EMSG(_("E702: Sort compare function failed"));
11222 else
11223 {
11224 /* Sort the array with item pointers. */
11225 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11226 info.item_compare_func == NULL
11227 && info.item_compare_partial == NULL
11228 ? item_compare : item_compare2);
11229
11230 if (!info.item_compare_func_err)
11231 {
11232 /* Clear the List and append the items in sorted order. */
11233 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11234 l->lv_len = 0;
11235 for (i = 0; i < len; ++i)
11236 list_append(l, ptrs[i].item);
11237 }
11238 }
11239 }
11240 else
11241 {
11242 int (*item_compare_func_ptr)(const void *, const void *);
11243
11244 /* f_uniq(): ptrs will be a stack of items to remove */
11245 info.item_compare_func_err = FALSE;
11246 info.item_compare_keep_zero = TRUE;
11247 item_compare_func_ptr = info.item_compare_func != NULL
11248 || info.item_compare_partial != NULL
11249 ? item_compare2 : item_compare;
11250
11251 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11252 li = li->li_next)
11253 {
11254 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11255 == 0)
11256 ptrs[i++].item = li;
11257 if (info.item_compare_func_err)
11258 {
11259 EMSG(_("E882: Uniq compare function failed"));
11260 break;
11261 }
11262 }
11263
11264 if (!info.item_compare_func_err)
11265 {
11266 while (--i >= 0)
11267 {
11268 li = ptrs[i].item->li_next;
11269 ptrs[i].item->li_next = li->li_next;
11270 if (li->li_next != NULL)
11271 li->li_next->li_prev = ptrs[i].item;
11272 else
11273 l->lv_last = ptrs[i].item;
11274 list_fix_watch(l, li);
11275 listitem_free(li);
11276 l->lv_len--;
11277 }
11278 }
11279 }
11280
11281 vim_free(ptrs);
11282 }
11283theend:
11284 sortinfo = old_sortinfo;
11285}
11286
11287/*
11288 * "sort({list})" function
11289 */
11290 static void
11291f_sort(typval_T *argvars, typval_T *rettv)
11292{
11293 do_sort_uniq(argvars, rettv, TRUE);
11294}
11295
11296/*
11297 * "uniq({list})" function
11298 */
11299 static void
11300f_uniq(typval_T *argvars, typval_T *rettv)
11301{
11302 do_sort_uniq(argvars, rettv, FALSE);
11303}
11304
11305/*
11306 * "soundfold({word})" function
11307 */
11308 static void
11309f_soundfold(typval_T *argvars, typval_T *rettv)
11310{
11311 char_u *s;
11312
11313 rettv->v_type = VAR_STRING;
11314 s = get_tv_string(&argvars[0]);
11315#ifdef FEAT_SPELL
11316 rettv->vval.v_string = eval_soundfold(s);
11317#else
11318 rettv->vval.v_string = vim_strsave(s);
11319#endif
11320}
11321
11322/*
11323 * "spellbadword()" function
11324 */
11325 static void
11326f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11327{
11328 char_u *word = (char_u *)"";
11329 hlf_T attr = HLF_COUNT;
11330 int len = 0;
11331
11332 if (rettv_list_alloc(rettv) == FAIL)
11333 return;
11334
11335#ifdef FEAT_SPELL
11336 if (argvars[0].v_type == VAR_UNKNOWN)
11337 {
11338 /* Find the start and length of the badly spelled word. */
11339 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11340 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011341 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011342 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011343 curwin->w_set_curswant = TRUE;
11344 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011345 }
11346 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11347 {
11348 char_u *str = get_tv_string_chk(&argvars[0]);
11349 int capcol = -1;
11350
11351 if (str != NULL)
11352 {
11353 /* Check the argument for spelling. */
11354 while (*str != NUL)
11355 {
11356 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11357 if (attr != HLF_COUNT)
11358 {
11359 word = str;
11360 break;
11361 }
11362 str += len;
11363 }
11364 }
11365 }
11366#endif
11367
11368 list_append_string(rettv->vval.v_list, word, len);
11369 list_append_string(rettv->vval.v_list, (char_u *)(
11370 attr == HLF_SPB ? "bad" :
11371 attr == HLF_SPR ? "rare" :
11372 attr == HLF_SPL ? "local" :
11373 attr == HLF_SPC ? "caps" :
11374 ""), -1);
11375}
11376
11377/*
11378 * "spellsuggest()" function
11379 */
11380 static void
11381f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11382{
11383#ifdef FEAT_SPELL
11384 char_u *str;
11385 int typeerr = FALSE;
11386 int maxcount;
11387 garray_T ga;
11388 int i;
11389 listitem_T *li;
11390 int need_capital = FALSE;
11391#endif
11392
11393 if (rettv_list_alloc(rettv) == FAIL)
11394 return;
11395
11396#ifdef FEAT_SPELL
11397 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11398 {
11399 str = get_tv_string(&argvars[0]);
11400 if (argvars[1].v_type != VAR_UNKNOWN)
11401 {
11402 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11403 if (maxcount <= 0)
11404 return;
11405 if (argvars[2].v_type != VAR_UNKNOWN)
11406 {
11407 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11408 if (typeerr)
11409 return;
11410 }
11411 }
11412 else
11413 maxcount = 25;
11414
11415 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11416
11417 for (i = 0; i < ga.ga_len; ++i)
11418 {
11419 str = ((char_u **)ga.ga_data)[i];
11420
11421 li = listitem_alloc();
11422 if (li == NULL)
11423 vim_free(str);
11424 else
11425 {
11426 li->li_tv.v_type = VAR_STRING;
11427 li->li_tv.v_lock = 0;
11428 li->li_tv.vval.v_string = str;
11429 list_append(rettv->vval.v_list, li);
11430 }
11431 }
11432 ga_clear(&ga);
11433 }
11434#endif
11435}
11436
11437 static void
11438f_split(typval_T *argvars, typval_T *rettv)
11439{
11440 char_u *str;
11441 char_u *end;
11442 char_u *pat = NULL;
11443 regmatch_T regmatch;
11444 char_u patbuf[NUMBUFLEN];
11445 char_u *save_cpo;
11446 int match;
11447 colnr_T col = 0;
11448 int keepempty = FALSE;
11449 int typeerr = FALSE;
11450
11451 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11452 save_cpo = p_cpo;
11453 p_cpo = (char_u *)"";
11454
11455 str = get_tv_string(&argvars[0]);
11456 if (argvars[1].v_type != VAR_UNKNOWN)
11457 {
11458 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11459 if (pat == NULL)
11460 typeerr = TRUE;
11461 if (argvars[2].v_type != VAR_UNKNOWN)
11462 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11463 }
11464 if (pat == NULL || *pat == NUL)
11465 pat = (char_u *)"[\\x01- ]\\+";
11466
11467 if (rettv_list_alloc(rettv) == FAIL)
11468 return;
11469 if (typeerr)
11470 return;
11471
11472 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11473 if (regmatch.regprog != NULL)
11474 {
11475 regmatch.rm_ic = FALSE;
11476 while (*str != NUL || keepempty)
11477 {
11478 if (*str == NUL)
11479 match = FALSE; /* empty item at the end */
11480 else
11481 match = vim_regexec_nl(&regmatch, str, col);
11482 if (match)
11483 end = regmatch.startp[0];
11484 else
11485 end = str + STRLEN(str);
11486 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11487 && *str != NUL && match && end < regmatch.endp[0]))
11488 {
11489 if (list_append_string(rettv->vval.v_list, str,
11490 (int)(end - str)) == FAIL)
11491 break;
11492 }
11493 if (!match)
11494 break;
11495 /* Advance to just after the match. */
11496 if (regmatch.endp[0] > str)
11497 col = 0;
11498 else
11499 {
11500 /* Don't get stuck at the same match. */
11501#ifdef FEAT_MBYTE
11502 col = (*mb_ptr2len)(regmatch.endp[0]);
11503#else
11504 col = 1;
11505#endif
11506 }
11507 str = regmatch.endp[0];
11508 }
11509
11510 vim_regfree(regmatch.regprog);
11511 }
11512
11513 p_cpo = save_cpo;
11514}
11515
11516#ifdef FEAT_FLOAT
11517/*
11518 * "sqrt()" function
11519 */
11520 static void
11521f_sqrt(typval_T *argvars, typval_T *rettv)
11522{
11523 float_T f = 0.0;
11524
11525 rettv->v_type = VAR_FLOAT;
11526 if (get_float_arg(argvars, &f) == OK)
11527 rettv->vval.v_float = sqrt(f);
11528 else
11529 rettv->vval.v_float = 0.0;
11530}
11531
11532/*
11533 * "str2float()" function
11534 */
11535 static void
11536f_str2float(typval_T *argvars, typval_T *rettv)
11537{
11538 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011539 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011540
Bram Moolenaar08243d22017-01-10 16:12:29 +010011541 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011542 p = skipwhite(p + 1);
11543 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011544 if (isneg)
11545 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011546 rettv->v_type = VAR_FLOAT;
11547}
11548#endif
11549
11550/*
11551 * "str2nr()" function
11552 */
11553 static void
11554f_str2nr(typval_T *argvars, typval_T *rettv)
11555{
11556 int base = 10;
11557 char_u *p;
11558 varnumber_T n;
11559 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011560 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011561
11562 if (argvars[1].v_type != VAR_UNKNOWN)
11563 {
11564 base = (int)get_tv_number(&argvars[1]);
11565 if (base != 2 && base != 8 && base != 10 && base != 16)
11566 {
11567 EMSG(_(e_invarg));
11568 return;
11569 }
11570 }
11571
11572 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011573 isneg = (*p == '-');
11574 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011575 p = skipwhite(p + 1);
11576 switch (base)
11577 {
11578 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11579 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11580 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11581 default: what = 0;
11582 }
11583 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011584 if (isneg)
11585 rettv->vval.v_number = -n;
11586 else
11587 rettv->vval.v_number = n;
11588
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011589}
11590
11591#ifdef HAVE_STRFTIME
11592/*
11593 * "strftime({format}[, {time}])" function
11594 */
11595 static void
11596f_strftime(typval_T *argvars, typval_T *rettv)
11597{
11598 char_u result_buf[256];
11599 struct tm *curtime;
11600 time_t seconds;
11601 char_u *p;
11602
11603 rettv->v_type = VAR_STRING;
11604
11605 p = get_tv_string(&argvars[0]);
11606 if (argvars[1].v_type == VAR_UNKNOWN)
11607 seconds = time(NULL);
11608 else
11609 seconds = (time_t)get_tv_number(&argvars[1]);
11610 curtime = localtime(&seconds);
11611 /* MSVC returns NULL for an invalid value of seconds. */
11612 if (curtime == NULL)
11613 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11614 else
11615 {
11616# ifdef FEAT_MBYTE
11617 vimconv_T conv;
11618 char_u *enc;
11619
11620 conv.vc_type = CONV_NONE;
11621 enc = enc_locale();
11622 convert_setup(&conv, p_enc, enc);
11623 if (conv.vc_type != CONV_NONE)
11624 p = string_convert(&conv, p, NULL);
11625# endif
11626 if (p != NULL)
11627 (void)strftime((char *)result_buf, sizeof(result_buf),
11628 (char *)p, curtime);
11629 else
11630 result_buf[0] = NUL;
11631
11632# ifdef FEAT_MBYTE
11633 if (conv.vc_type != CONV_NONE)
11634 vim_free(p);
11635 convert_setup(&conv, enc, p_enc);
11636 if (conv.vc_type != CONV_NONE)
11637 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11638 else
11639# endif
11640 rettv->vval.v_string = vim_strsave(result_buf);
11641
11642# ifdef FEAT_MBYTE
11643 /* Release conversion descriptors */
11644 convert_setup(&conv, NULL, NULL);
11645 vim_free(enc);
11646# endif
11647 }
11648}
11649#endif
11650
11651/*
11652 * "strgetchar()" function
11653 */
11654 static void
11655f_strgetchar(typval_T *argvars, typval_T *rettv)
11656{
11657 char_u *str;
11658 int len;
11659 int error = FALSE;
11660 int charidx;
11661
11662 rettv->vval.v_number = -1;
11663 str = get_tv_string_chk(&argvars[0]);
11664 if (str == NULL)
11665 return;
11666 len = (int)STRLEN(str);
11667 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11668 if (error)
11669 return;
11670#ifdef FEAT_MBYTE
11671 {
11672 int byteidx = 0;
11673
11674 while (charidx >= 0 && byteidx < len)
11675 {
11676 if (charidx == 0)
11677 {
11678 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11679 break;
11680 }
11681 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011682 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011683 }
11684 }
11685#else
11686 if (charidx < len)
11687 rettv->vval.v_number = str[charidx];
11688#endif
11689}
11690
11691/*
11692 * "stridx()" function
11693 */
11694 static void
11695f_stridx(typval_T *argvars, typval_T *rettv)
11696{
11697 char_u buf[NUMBUFLEN];
11698 char_u *needle;
11699 char_u *haystack;
11700 char_u *save_haystack;
11701 char_u *pos;
11702 int start_idx;
11703
11704 needle = get_tv_string_chk(&argvars[1]);
11705 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11706 rettv->vval.v_number = -1;
11707 if (needle == NULL || haystack == NULL)
11708 return; /* type error; errmsg already given */
11709
11710 if (argvars[2].v_type != VAR_UNKNOWN)
11711 {
11712 int error = FALSE;
11713
11714 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11715 if (error || start_idx >= (int)STRLEN(haystack))
11716 return;
11717 if (start_idx >= 0)
11718 haystack += start_idx;
11719 }
11720
11721 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11722 if (pos != NULL)
11723 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11724}
11725
11726/*
11727 * "string()" function
11728 */
11729 static void
11730f_string(typval_T *argvars, typval_T *rettv)
11731{
11732 char_u *tofree;
11733 char_u numbuf[NUMBUFLEN];
11734
11735 rettv->v_type = VAR_STRING;
11736 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11737 get_copyID());
11738 /* Make a copy if we have a value but it's not in allocated memory. */
11739 if (rettv->vval.v_string != NULL && tofree == NULL)
11740 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11741}
11742
11743/*
11744 * "strlen()" function
11745 */
11746 static void
11747f_strlen(typval_T *argvars, typval_T *rettv)
11748{
11749 rettv->vval.v_number = (varnumber_T)(STRLEN(
11750 get_tv_string(&argvars[0])));
11751}
11752
11753/*
11754 * "strchars()" function
11755 */
11756 static void
11757f_strchars(typval_T *argvars, typval_T *rettv)
11758{
11759 char_u *s = get_tv_string(&argvars[0]);
11760 int skipcc = 0;
11761#ifdef FEAT_MBYTE
11762 varnumber_T len = 0;
11763 int (*func_mb_ptr2char_adv)(char_u **pp);
11764#endif
11765
11766 if (argvars[1].v_type != VAR_UNKNOWN)
11767 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11768 if (skipcc < 0 || skipcc > 1)
11769 EMSG(_(e_invarg));
11770 else
11771 {
11772#ifdef FEAT_MBYTE
11773 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11774 while (*s != NUL)
11775 {
11776 func_mb_ptr2char_adv(&s);
11777 ++len;
11778 }
11779 rettv->vval.v_number = len;
11780#else
11781 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11782#endif
11783 }
11784}
11785
11786/*
11787 * "strdisplaywidth()" function
11788 */
11789 static void
11790f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11791{
11792 char_u *s = get_tv_string(&argvars[0]);
11793 int col = 0;
11794
11795 if (argvars[1].v_type != VAR_UNKNOWN)
11796 col = (int)get_tv_number(&argvars[1]);
11797
11798 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11799}
11800
11801/*
11802 * "strwidth()" function
11803 */
11804 static void
11805f_strwidth(typval_T *argvars, typval_T *rettv)
11806{
11807 char_u *s = get_tv_string(&argvars[0]);
11808
11809 rettv->vval.v_number = (varnumber_T)(
11810#ifdef FEAT_MBYTE
11811 mb_string2cells(s, -1)
11812#else
11813 STRLEN(s)
11814#endif
11815 );
11816}
11817
11818/*
11819 * "strcharpart()" function
11820 */
11821 static void
11822f_strcharpart(typval_T *argvars, typval_T *rettv)
11823{
11824#ifdef FEAT_MBYTE
11825 char_u *p;
11826 int nchar;
11827 int nbyte = 0;
11828 int charlen;
11829 int len = 0;
11830 int slen;
11831 int error = FALSE;
11832
11833 p = get_tv_string(&argvars[0]);
11834 slen = (int)STRLEN(p);
11835
11836 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11837 if (!error)
11838 {
11839 if (nchar > 0)
11840 while (nchar > 0 && nbyte < slen)
11841 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011842 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011843 --nchar;
11844 }
11845 else
11846 nbyte = nchar;
11847 if (argvars[2].v_type != VAR_UNKNOWN)
11848 {
11849 charlen = (int)get_tv_number(&argvars[2]);
11850 while (charlen > 0 && nbyte + len < slen)
11851 {
11852 int off = nbyte + len;
11853
11854 if (off < 0)
11855 len += 1;
11856 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011857 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011858 --charlen;
11859 }
11860 }
11861 else
11862 len = slen - nbyte; /* default: all bytes that are available. */
11863 }
11864
11865 /*
11866 * Only return the overlap between the specified part and the actual
11867 * string.
11868 */
11869 if (nbyte < 0)
11870 {
11871 len += nbyte;
11872 nbyte = 0;
11873 }
11874 else if (nbyte > slen)
11875 nbyte = slen;
11876 if (len < 0)
11877 len = 0;
11878 else if (nbyte + len > slen)
11879 len = slen - nbyte;
11880
11881 rettv->v_type = VAR_STRING;
11882 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11883#else
11884 f_strpart(argvars, rettv);
11885#endif
11886}
11887
11888/*
11889 * "strpart()" function
11890 */
11891 static void
11892f_strpart(typval_T *argvars, typval_T *rettv)
11893{
11894 char_u *p;
11895 int n;
11896 int len;
11897 int slen;
11898 int error = FALSE;
11899
11900 p = get_tv_string(&argvars[0]);
11901 slen = (int)STRLEN(p);
11902
11903 n = (int)get_tv_number_chk(&argvars[1], &error);
11904 if (error)
11905 len = 0;
11906 else if (argvars[2].v_type != VAR_UNKNOWN)
11907 len = (int)get_tv_number(&argvars[2]);
11908 else
11909 len = slen - n; /* default len: all bytes that are available. */
11910
11911 /*
11912 * Only return the overlap between the specified part and the actual
11913 * string.
11914 */
11915 if (n < 0)
11916 {
11917 len += n;
11918 n = 0;
11919 }
11920 else if (n > slen)
11921 n = slen;
11922 if (len < 0)
11923 len = 0;
11924 else if (n + len > slen)
11925 len = slen - n;
11926
11927 rettv->v_type = VAR_STRING;
11928 rettv->vval.v_string = vim_strnsave(p + n, len);
11929}
11930
11931/*
11932 * "strridx()" function
11933 */
11934 static void
11935f_strridx(typval_T *argvars, typval_T *rettv)
11936{
11937 char_u buf[NUMBUFLEN];
11938 char_u *needle;
11939 char_u *haystack;
11940 char_u *rest;
11941 char_u *lastmatch = NULL;
11942 int haystack_len, end_idx;
11943
11944 needle = get_tv_string_chk(&argvars[1]);
11945 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11946
11947 rettv->vval.v_number = -1;
11948 if (needle == NULL || haystack == NULL)
11949 return; /* type error; errmsg already given */
11950
11951 haystack_len = (int)STRLEN(haystack);
11952 if (argvars[2].v_type != VAR_UNKNOWN)
11953 {
11954 /* Third argument: upper limit for index */
11955 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11956 if (end_idx < 0)
11957 return; /* can never find a match */
11958 }
11959 else
11960 end_idx = haystack_len;
11961
11962 if (*needle == NUL)
11963 {
11964 /* Empty string matches past the end. */
11965 lastmatch = haystack + end_idx;
11966 }
11967 else
11968 {
11969 for (rest = haystack; *rest != '\0'; ++rest)
11970 {
11971 rest = (char_u *)strstr((char *)rest, (char *)needle);
11972 if (rest == NULL || rest > haystack + end_idx)
11973 break;
11974 lastmatch = rest;
11975 }
11976 }
11977
11978 if (lastmatch == NULL)
11979 rettv->vval.v_number = -1;
11980 else
11981 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11982}
11983
11984/*
11985 * "strtrans()" function
11986 */
11987 static void
11988f_strtrans(typval_T *argvars, typval_T *rettv)
11989{
11990 rettv->v_type = VAR_STRING;
11991 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11992}
11993
11994/*
11995 * "submatch()" function
11996 */
11997 static void
11998f_submatch(typval_T *argvars, typval_T *rettv)
11999{
12000 int error = FALSE;
12001 int no;
12002 int retList = 0;
12003
12004 no = (int)get_tv_number_chk(&argvars[0], &error);
12005 if (error)
12006 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012007 if (no < 0 || no >= NSUBEXP)
12008 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012009 EMSGN(_("E935: invalid submatch number: %d"), no);
12010 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012011 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012012 if (argvars[1].v_type != VAR_UNKNOWN)
12013 retList = (int)get_tv_number_chk(&argvars[1], &error);
12014 if (error)
12015 return;
12016
12017 if (retList == 0)
12018 {
12019 rettv->v_type = VAR_STRING;
12020 rettv->vval.v_string = reg_submatch(no);
12021 }
12022 else
12023 {
12024 rettv->v_type = VAR_LIST;
12025 rettv->vval.v_list = reg_submatch_list(no);
12026 }
12027}
12028
12029/*
12030 * "substitute()" function
12031 */
12032 static void
12033f_substitute(typval_T *argvars, typval_T *rettv)
12034{
12035 char_u patbuf[NUMBUFLEN];
12036 char_u subbuf[NUMBUFLEN];
12037 char_u flagsbuf[NUMBUFLEN];
12038
12039 char_u *str = get_tv_string_chk(&argvars[0]);
12040 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012041 char_u *sub = NULL;
12042 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012043 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12044
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012045 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12046 expr = &argvars[2];
12047 else
12048 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12049
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012050 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012051 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12052 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012053 rettv->vval.v_string = NULL;
12054 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012055 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012056}
12057
12058/*
12059 * "synID(lnum, col, trans)" function
12060 */
12061 static void
12062f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12063{
12064 int id = 0;
12065#ifdef FEAT_SYN_HL
12066 linenr_T lnum;
12067 colnr_T col;
12068 int trans;
12069 int transerr = FALSE;
12070
12071 lnum = get_tv_lnum(argvars); /* -1 on type error */
12072 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12073 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12074
12075 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12076 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12077 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12078#endif
12079
12080 rettv->vval.v_number = id;
12081}
12082
12083/*
12084 * "synIDattr(id, what [, mode])" function
12085 */
12086 static void
12087f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12088{
12089 char_u *p = NULL;
12090#ifdef FEAT_SYN_HL
12091 int id;
12092 char_u *what;
12093 char_u *mode;
12094 char_u modebuf[NUMBUFLEN];
12095 int modec;
12096
12097 id = (int)get_tv_number(&argvars[0]);
12098 what = get_tv_string(&argvars[1]);
12099 if (argvars[2].v_type != VAR_UNKNOWN)
12100 {
12101 mode = get_tv_string_buf(&argvars[2], modebuf);
12102 modec = TOLOWER_ASC(mode[0]);
12103 if (modec != 't' && modec != 'c' && modec != 'g')
12104 modec = 0; /* replace invalid with current */
12105 }
12106 else
12107 {
12108#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12109 if (USE_24BIT)
12110 modec = 'g';
12111 else
12112#endif
12113 if (t_colors > 1)
12114 modec = 'c';
12115 else
12116 modec = 't';
12117 }
12118
12119
12120 switch (TOLOWER_ASC(what[0]))
12121 {
12122 case 'b':
12123 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12124 p = highlight_color(id, what, modec);
12125 else /* bold */
12126 p = highlight_has_attr(id, HL_BOLD, modec);
12127 break;
12128
12129 case 'f': /* fg[#] or font */
12130 p = highlight_color(id, what, modec);
12131 break;
12132
12133 case 'i':
12134 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12135 p = highlight_has_attr(id, HL_INVERSE, modec);
12136 else /* italic */
12137 p = highlight_has_attr(id, HL_ITALIC, modec);
12138 break;
12139
12140 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012141 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012142 break;
12143
12144 case 'r': /* reverse */
12145 p = highlight_has_attr(id, HL_INVERSE, modec);
12146 break;
12147
12148 case 's':
12149 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12150 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012151 /* strikeout */
12152 else if (TOLOWER_ASC(what[1]) == 't' &&
12153 TOLOWER_ASC(what[2]) == 'r')
12154 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012155 else /* standout */
12156 p = highlight_has_attr(id, HL_STANDOUT, modec);
12157 break;
12158
12159 case 'u':
12160 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12161 /* underline */
12162 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12163 else
12164 /* undercurl */
12165 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12166 break;
12167 }
12168
12169 if (p != NULL)
12170 p = vim_strsave(p);
12171#endif
12172 rettv->v_type = VAR_STRING;
12173 rettv->vval.v_string = p;
12174}
12175
12176/*
12177 * "synIDtrans(id)" function
12178 */
12179 static void
12180f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12181{
12182 int id;
12183
12184#ifdef FEAT_SYN_HL
12185 id = (int)get_tv_number(&argvars[0]);
12186
12187 if (id > 0)
12188 id = syn_get_final_id(id);
12189 else
12190#endif
12191 id = 0;
12192
12193 rettv->vval.v_number = id;
12194}
12195
12196/*
12197 * "synconcealed(lnum, col)" function
12198 */
12199 static void
12200f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12201{
12202#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12203 linenr_T lnum;
12204 colnr_T col;
12205 int syntax_flags = 0;
12206 int cchar;
12207 int matchid = 0;
12208 char_u str[NUMBUFLEN];
12209#endif
12210
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012211 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012212
12213#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12214 lnum = get_tv_lnum(argvars); /* -1 on type error */
12215 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12216
12217 vim_memset(str, NUL, sizeof(str));
12218
12219 if (rettv_list_alloc(rettv) != FAIL)
12220 {
12221 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12222 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12223 && curwin->w_p_cole > 0)
12224 {
12225 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12226 syntax_flags = get_syntax_info(&matchid);
12227
12228 /* get the conceal character */
12229 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12230 {
12231 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012232 if (cchar == NUL && curwin->w_p_cole == 1)
12233 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012234 if (cchar != NUL)
12235 {
12236# ifdef FEAT_MBYTE
12237 if (has_mbyte)
12238 (*mb_char2bytes)(cchar, str);
12239 else
12240# endif
12241 str[0] = cchar;
12242 }
12243 }
12244 }
12245
12246 list_append_number(rettv->vval.v_list,
12247 (syntax_flags & HL_CONCEAL) != 0);
12248 /* -1 to auto-determine strlen */
12249 list_append_string(rettv->vval.v_list, str, -1);
12250 list_append_number(rettv->vval.v_list, matchid);
12251 }
12252#endif
12253}
12254
12255/*
12256 * "synstack(lnum, col)" function
12257 */
12258 static void
12259f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12260{
12261#ifdef FEAT_SYN_HL
12262 linenr_T lnum;
12263 colnr_T col;
12264 int i;
12265 int id;
12266#endif
12267
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012268 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012269
12270#ifdef FEAT_SYN_HL
12271 lnum = get_tv_lnum(argvars); /* -1 on type error */
12272 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12273
12274 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12275 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12276 && rettv_list_alloc(rettv) != FAIL)
12277 {
12278 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12279 for (i = 0; ; ++i)
12280 {
12281 id = syn_get_stack_item(i);
12282 if (id < 0)
12283 break;
12284 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12285 break;
12286 }
12287 }
12288#endif
12289}
12290
12291 static void
12292get_cmd_output_as_rettv(
12293 typval_T *argvars,
12294 typval_T *rettv,
12295 int retlist)
12296{
12297 char_u *res = NULL;
12298 char_u *p;
12299 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012300 int err = FALSE;
12301 FILE *fd;
12302 list_T *list = NULL;
12303 int flags = SHELL_SILENT;
12304
12305 rettv->v_type = VAR_STRING;
12306 rettv->vval.v_string = NULL;
12307 if (check_restricted() || check_secure())
12308 goto errret;
12309
12310 if (argvars[1].v_type != VAR_UNKNOWN)
12311 {
12312 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012313 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012314 * command.
12315 */
12316 if ((infile = vim_tempname('i', TRUE)) == NULL)
12317 {
12318 EMSG(_(e_notmp));
12319 goto errret;
12320 }
12321
12322 fd = mch_fopen((char *)infile, WRITEBIN);
12323 if (fd == NULL)
12324 {
12325 EMSG2(_(e_notopen), infile);
12326 goto errret;
12327 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012328 if (argvars[1].v_type == VAR_NUMBER)
12329 {
12330 linenr_T lnum;
12331 buf_T *buf;
12332
12333 buf = buflist_findnr(argvars[1].vval.v_number);
12334 if (buf == NULL)
12335 {
12336 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012337 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012338 goto errret;
12339 }
12340
12341 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12342 {
12343 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12344 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12345 {
12346 err = TRUE;
12347 break;
12348 }
12349 if (putc(NL, fd) == EOF)
12350 {
12351 err = TRUE;
12352 break;
12353 }
12354 }
12355 }
12356 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357 {
12358 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12359 err = TRUE;
12360 }
12361 else
12362 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012363 size_t len;
12364 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012365
12366 p = get_tv_string_buf_chk(&argvars[1], buf);
12367 if (p == NULL)
12368 {
12369 fclose(fd);
12370 goto errret; /* type error; errmsg already given */
12371 }
12372 len = STRLEN(p);
12373 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12374 err = TRUE;
12375 }
12376 if (fclose(fd) != 0)
12377 err = TRUE;
12378 if (err)
12379 {
12380 EMSG(_("E677: Error writing temp file"));
12381 goto errret;
12382 }
12383 }
12384
12385 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12386 * echoes typeahead, that messes up the display. */
12387 if (!msg_silent)
12388 flags += SHELL_COOKED;
12389
12390 if (retlist)
12391 {
12392 int len;
12393 listitem_T *li;
12394 char_u *s = NULL;
12395 char_u *start;
12396 char_u *end;
12397 int i;
12398
12399 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12400 if (res == NULL)
12401 goto errret;
12402
12403 list = list_alloc();
12404 if (list == NULL)
12405 goto errret;
12406
12407 for (i = 0; i < len; ++i)
12408 {
12409 start = res + i;
12410 while (i < len && res[i] != NL)
12411 ++i;
12412 end = res + i;
12413
12414 s = alloc((unsigned)(end - start + 1));
12415 if (s == NULL)
12416 goto errret;
12417
12418 for (p = s; start < end; ++p, ++start)
12419 *p = *start == NUL ? NL : *start;
12420 *p = NUL;
12421
12422 li = listitem_alloc();
12423 if (li == NULL)
12424 {
12425 vim_free(s);
12426 goto errret;
12427 }
12428 li->li_tv.v_type = VAR_STRING;
12429 li->li_tv.v_lock = 0;
12430 li->li_tv.vval.v_string = s;
12431 list_append(list, li);
12432 }
12433
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012434 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012435 list = NULL;
12436 }
12437 else
12438 {
12439 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12440#ifdef USE_CR
12441 /* translate <CR> into <NL> */
12442 if (res != NULL)
12443 {
12444 char_u *s;
12445
12446 for (s = res; *s; ++s)
12447 {
12448 if (*s == CAR)
12449 *s = NL;
12450 }
12451 }
12452#else
12453# ifdef USE_CRNL
12454 /* translate <CR><NL> into <NL> */
12455 if (res != NULL)
12456 {
12457 char_u *s, *d;
12458
12459 d = res;
12460 for (s = res; *s; ++s)
12461 {
12462 if (s[0] == CAR && s[1] == NL)
12463 ++s;
12464 *d++ = *s;
12465 }
12466 *d = NUL;
12467 }
12468# endif
12469#endif
12470 rettv->vval.v_string = res;
12471 res = NULL;
12472 }
12473
12474errret:
12475 if (infile != NULL)
12476 {
12477 mch_remove(infile);
12478 vim_free(infile);
12479 }
12480 if (res != NULL)
12481 vim_free(res);
12482 if (list != NULL)
12483 list_free(list);
12484}
12485
12486/*
12487 * "system()" function
12488 */
12489 static void
12490f_system(typval_T *argvars, typval_T *rettv)
12491{
12492 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12493}
12494
12495/*
12496 * "systemlist()" function
12497 */
12498 static void
12499f_systemlist(typval_T *argvars, typval_T *rettv)
12500{
12501 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12502}
12503
12504/*
12505 * "tabpagebuflist()" function
12506 */
12507 static void
12508f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12509{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012510 tabpage_T *tp;
12511 win_T *wp = NULL;
12512
12513 if (argvars[0].v_type == VAR_UNKNOWN)
12514 wp = firstwin;
12515 else
12516 {
12517 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12518 if (tp != NULL)
12519 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12520 }
12521 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12522 {
12523 for (; wp != NULL; wp = wp->w_next)
12524 if (list_append_number(rettv->vval.v_list,
12525 wp->w_buffer->b_fnum) == FAIL)
12526 break;
12527 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012528}
12529
12530
12531/*
12532 * "tabpagenr()" function
12533 */
12534 static void
12535f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12536{
12537 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012538 char_u *arg;
12539
12540 if (argvars[0].v_type != VAR_UNKNOWN)
12541 {
12542 arg = get_tv_string_chk(&argvars[0]);
12543 nr = 0;
12544 if (arg != NULL)
12545 {
12546 if (STRCMP(arg, "$") == 0)
12547 nr = tabpage_index(NULL) - 1;
12548 else
12549 EMSG2(_(e_invexpr2), arg);
12550 }
12551 }
12552 else
12553 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012554 rettv->vval.v_number = nr;
12555}
12556
12557
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012558static int get_winnr(tabpage_T *tp, typval_T *argvar);
12559
12560/*
12561 * Common code for tabpagewinnr() and winnr().
12562 */
12563 static int
12564get_winnr(tabpage_T *tp, typval_T *argvar)
12565{
12566 win_T *twin;
12567 int nr = 1;
12568 win_T *wp;
12569 char_u *arg;
12570
12571 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12572 if (argvar->v_type != VAR_UNKNOWN)
12573 {
12574 arg = get_tv_string_chk(argvar);
12575 if (arg == NULL)
12576 nr = 0; /* type error; errmsg already given */
12577 else if (STRCMP(arg, "$") == 0)
12578 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12579 else if (STRCMP(arg, "#") == 0)
12580 {
12581 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12582 if (twin == NULL)
12583 nr = 0;
12584 }
12585 else
12586 {
12587 EMSG2(_(e_invexpr2), arg);
12588 nr = 0;
12589 }
12590 }
12591
12592 if (nr > 0)
12593 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12594 wp != twin; wp = wp->w_next)
12595 {
12596 if (wp == NULL)
12597 {
12598 /* didn't find it in this tabpage */
12599 nr = 0;
12600 break;
12601 }
12602 ++nr;
12603 }
12604 return nr;
12605}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012606
12607/*
12608 * "tabpagewinnr()" function
12609 */
12610 static void
12611f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12612{
12613 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012614 tabpage_T *tp;
12615
12616 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12617 if (tp == NULL)
12618 nr = 0;
12619 else
12620 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012621 rettv->vval.v_number = nr;
12622}
12623
12624
12625/*
12626 * "tagfiles()" function
12627 */
12628 static void
12629f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12630{
12631 char_u *fname;
12632 tagname_T tn;
12633 int first;
12634
12635 if (rettv_list_alloc(rettv) == FAIL)
12636 return;
12637 fname = alloc(MAXPATHL);
12638 if (fname == NULL)
12639 return;
12640
12641 for (first = TRUE; ; first = FALSE)
12642 if (get_tagfname(&tn, first, fname) == FAIL
12643 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12644 break;
12645 tagname_free(&tn);
12646 vim_free(fname);
12647}
12648
12649/*
12650 * "taglist()" function
12651 */
12652 static void
12653f_taglist(typval_T *argvars, typval_T *rettv)
12654{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012655 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012656 char_u *tag_pattern;
12657
12658 tag_pattern = get_tv_string(&argvars[0]);
12659
12660 rettv->vval.v_number = FALSE;
12661 if (*tag_pattern == NUL)
12662 return;
12663
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012664 if (argvars[1].v_type != VAR_UNKNOWN)
12665 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012666 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012667 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012668}
12669
12670/*
12671 * "tempname()" function
12672 */
12673 static void
12674f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12675{
12676 static int x = 'A';
12677
12678 rettv->v_type = VAR_STRING;
12679 rettv->vval.v_string = vim_tempname(x, FALSE);
12680
12681 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12682 * names. Skip 'I' and 'O', they are used for shell redirection. */
12683 do
12684 {
12685 if (x == 'Z')
12686 x = '0';
12687 else if (x == '9')
12688 x = 'A';
12689 else
12690 {
12691#ifdef EBCDIC
12692 if (x == 'I')
12693 x = 'J';
12694 else if (x == 'R')
12695 x = 'S';
12696 else
12697#endif
12698 ++x;
12699 }
12700 } while (x == 'I' || x == 'O');
12701}
12702
12703#ifdef FEAT_FLOAT
12704/*
12705 * "tan()" function
12706 */
12707 static void
12708f_tan(typval_T *argvars, typval_T *rettv)
12709{
12710 float_T f = 0.0;
12711
12712 rettv->v_type = VAR_FLOAT;
12713 if (get_float_arg(argvars, &f) == OK)
12714 rettv->vval.v_float = tan(f);
12715 else
12716 rettv->vval.v_float = 0.0;
12717}
12718
12719/*
12720 * "tanh()" function
12721 */
12722 static void
12723f_tanh(typval_T *argvars, typval_T *rettv)
12724{
12725 float_T f = 0.0;
12726
12727 rettv->v_type = VAR_FLOAT;
12728 if (get_float_arg(argvars, &f) == OK)
12729 rettv->vval.v_float = tanh(f);
12730 else
12731 rettv->vval.v_float = 0.0;
12732}
12733#endif
12734
12735/*
12736 * "test_alloc_fail(id, countdown, repeat)" function
12737 */
12738 static void
12739f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12740{
12741 if (argvars[0].v_type != VAR_NUMBER
12742 || argvars[0].vval.v_number <= 0
12743 || argvars[1].v_type != VAR_NUMBER
12744 || argvars[1].vval.v_number < 0
12745 || argvars[2].v_type != VAR_NUMBER)
12746 EMSG(_(e_invarg));
12747 else
12748 {
12749 alloc_fail_id = argvars[0].vval.v_number;
12750 if (alloc_fail_id >= aid_last)
12751 EMSG(_(e_invarg));
12752 alloc_fail_countdown = argvars[1].vval.v_number;
12753 alloc_fail_repeat = argvars[2].vval.v_number;
12754 did_outofmem_msg = FALSE;
12755 }
12756}
12757
12758/*
12759 * "test_autochdir()"
12760 */
12761 static void
12762f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12763{
12764#if defined(FEAT_AUTOCHDIR)
12765 test_autochdir = TRUE;
12766#endif
12767}
12768
12769/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012770 * "test_feedinput()"
12771 */
12772 static void
12773f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12774{
12775#ifdef USE_INPUT_BUF
12776 char_u *val = get_tv_string_chk(&argvars[0]);
12777
12778 if (val != NULL)
12779 {
12780 trash_input_buf();
12781 add_to_input_buf_csi(val, (int)STRLEN(val));
12782 }
12783#endif
12784}
12785
12786/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012787 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012788 */
12789 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012790f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012792 char_u *name = (char_u *)"";
12793 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012794 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012795
12796 if (argvars[0].v_type != VAR_STRING
12797 || (argvars[1].v_type) != VAR_NUMBER)
12798 EMSG(_(e_invarg));
12799 else
12800 {
12801 name = get_tv_string_chk(&argvars[0]);
12802 val = (int)get_tv_number(&argvars[1]);
12803
12804 if (STRCMP(name, (char_u *)"redraw") == 0)
12805 disable_redraw_for_testing = val;
12806 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12807 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012808 else if (STRCMP(name, (char_u *)"starting") == 0)
12809 {
12810 if (val)
12811 {
12812 if (save_starting < 0)
12813 save_starting = starting;
12814 starting = 0;
12815 }
12816 else
12817 {
12818 starting = save_starting;
12819 save_starting = -1;
12820 }
12821 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012822 else if (STRCMP(name, (char_u *)"ALL") == 0)
12823 {
12824 disable_char_avail_for_testing = FALSE;
12825 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012826 if (save_starting >= 0)
12827 {
12828 starting = save_starting;
12829 save_starting = -1;
12830 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012831 }
12832 else
12833 EMSG2(_(e_invarg2), name);
12834 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012835}
12836
12837/*
12838 * "test_garbagecollect_now()" function
12839 */
12840 static void
12841f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12842{
12843 /* This is dangerous, any Lists and Dicts used internally may be freed
12844 * while still in use. */
12845 garbage_collect(TRUE);
12846}
12847
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012848/*
12849 * "test_ignore_error()" function
12850 */
12851 static void
12852f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12853{
12854 ignore_error_for_testing(get_tv_string(&argvars[0]));
12855}
12856
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012857#ifdef FEAT_JOB_CHANNEL
12858 static void
12859f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12860{
12861 rettv->v_type = VAR_CHANNEL;
12862 rettv->vval.v_channel = NULL;
12863}
12864#endif
12865
12866 static void
12867f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12868{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012869 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012870}
12871
12872#ifdef FEAT_JOB_CHANNEL
12873 static void
12874f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12875{
12876 rettv->v_type = VAR_JOB;
12877 rettv->vval.v_job = NULL;
12878}
12879#endif
12880
12881 static void
12882f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12883{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012884 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012885}
12886
12887 static void
12888f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12889{
12890 rettv->v_type = VAR_PARTIAL;
12891 rettv->vval.v_partial = NULL;
12892}
12893
12894 static void
12895f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12896{
12897 rettv->v_type = VAR_STRING;
12898 rettv->vval.v_string = NULL;
12899}
12900
12901 static void
12902f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12903{
12904 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12905}
12906
12907#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12908/*
12909 * Get a callback from "arg". It can be a Funcref or a function name.
12910 * When "arg" is zero return an empty string.
12911 * Return NULL for an invalid argument.
12912 */
12913 char_u *
12914get_callback(typval_T *arg, partial_T **pp)
12915{
12916 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12917 {
12918 *pp = arg->vval.v_partial;
12919 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012920 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012921 }
12922 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012923 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012924 {
12925 func_ref(arg->vval.v_string);
12926 return arg->vval.v_string;
12927 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012928 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12929 return (char_u *)"";
12930 EMSG(_("E921: Invalid callback argument"));
12931 return NULL;
12932}
12933
12934/*
12935 * Unref/free "callback" and "partial" retured by get_callback().
12936 */
12937 void
12938free_callback(char_u *callback, partial_T *partial)
12939{
12940 if (partial != NULL)
12941 partial_unref(partial);
12942 else if (callback != NULL)
12943 {
12944 func_unref(callback);
12945 vim_free(callback);
12946 }
12947}
12948#endif
12949
12950#ifdef FEAT_TIMERS
12951/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012952 * "timer_info([timer])" function
12953 */
12954 static void
12955f_timer_info(typval_T *argvars, typval_T *rettv)
12956{
12957 timer_T *timer = NULL;
12958
12959 if (rettv_list_alloc(rettv) != OK)
12960 return;
12961 if (argvars[0].v_type != VAR_UNKNOWN)
12962 {
12963 if (argvars[0].v_type != VAR_NUMBER)
12964 EMSG(_(e_number_exp));
12965 else
12966 {
12967 timer = find_timer((int)get_tv_number(&argvars[0]));
12968 if (timer != NULL)
12969 add_timer_info(rettv, timer);
12970 }
12971 }
12972 else
12973 add_timer_info_all(rettv);
12974}
12975
12976/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012977 * "timer_pause(timer, paused)" function
12978 */
12979 static void
12980f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12981{
12982 timer_T *timer = NULL;
12983 int paused = (int)get_tv_number(&argvars[1]);
12984
12985 if (argvars[0].v_type != VAR_NUMBER)
12986 EMSG(_(e_number_exp));
12987 else
12988 {
12989 timer = find_timer((int)get_tv_number(&argvars[0]));
12990 if (timer != NULL)
12991 timer->tr_paused = paused;
12992 }
12993}
12994
12995/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012996 * "timer_start(time, callback [, options])" function
12997 */
12998 static void
12999f_timer_start(typval_T *argvars, typval_T *rettv)
13000{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013001 long msec = (long)get_tv_number(&argvars[0]);
13002 timer_T *timer;
13003 int repeat = 0;
13004 char_u *callback;
13005 dict_T *dict;
13006 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013007
Bram Moolenaar75537a92016-09-05 22:45:28 +020013008 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013009 if (check_secure())
13010 return;
13011 if (argvars[2].v_type != VAR_UNKNOWN)
13012 {
13013 if (argvars[2].v_type != VAR_DICT
13014 || (dict = argvars[2].vval.v_dict) == NULL)
13015 {
13016 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13017 return;
13018 }
13019 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13020 repeat = get_dict_number(dict, (char_u *)"repeat");
13021 }
13022
Bram Moolenaar75537a92016-09-05 22:45:28 +020013023 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013024 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013025 return;
13026
13027 timer = create_timer(msec, repeat);
13028 if (timer == NULL)
13029 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013030 else
13031 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013032 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013033 timer->tr_callback = vim_strsave(callback);
13034 else
13035 /* pointer into the partial */
13036 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013037 timer->tr_partial = partial;
13038 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013039 }
13040}
13041
13042/*
13043 * "timer_stop(timer)" function
13044 */
13045 static void
13046f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13047{
13048 timer_T *timer;
13049
13050 if (argvars[0].v_type != VAR_NUMBER)
13051 {
13052 EMSG(_(e_number_exp));
13053 return;
13054 }
13055 timer = find_timer((int)get_tv_number(&argvars[0]));
13056 if (timer != NULL)
13057 stop_timer(timer);
13058}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013059
13060/*
13061 * "timer_stopall()" function
13062 */
13063 static void
13064f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13065{
13066 stop_all_timers();
13067}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013068#endif
13069
13070/*
13071 * "tolower(string)" function
13072 */
13073 static void
13074f_tolower(typval_T *argvars, typval_T *rettv)
13075{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013076 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013077 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013078}
13079
13080/*
13081 * "toupper(string)" function
13082 */
13083 static void
13084f_toupper(typval_T *argvars, typval_T *rettv)
13085{
13086 rettv->v_type = VAR_STRING;
13087 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13088}
13089
13090/*
13091 * "tr(string, fromstr, tostr)" function
13092 */
13093 static void
13094f_tr(typval_T *argvars, typval_T *rettv)
13095{
13096 char_u *in_str;
13097 char_u *fromstr;
13098 char_u *tostr;
13099 char_u *p;
13100#ifdef FEAT_MBYTE
13101 int inlen;
13102 int fromlen;
13103 int tolen;
13104 int idx;
13105 char_u *cpstr;
13106 int cplen;
13107 int first = TRUE;
13108#endif
13109 char_u buf[NUMBUFLEN];
13110 char_u buf2[NUMBUFLEN];
13111 garray_T ga;
13112
13113 in_str = get_tv_string(&argvars[0]);
13114 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13115 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13116
13117 /* Default return value: empty string. */
13118 rettv->v_type = VAR_STRING;
13119 rettv->vval.v_string = NULL;
13120 if (fromstr == NULL || tostr == NULL)
13121 return; /* type error; errmsg already given */
13122 ga_init2(&ga, (int)sizeof(char), 80);
13123
13124#ifdef FEAT_MBYTE
13125 if (!has_mbyte)
13126#endif
13127 /* not multi-byte: fromstr and tostr must be the same length */
13128 if (STRLEN(fromstr) != STRLEN(tostr))
13129 {
13130#ifdef FEAT_MBYTE
13131error:
13132#endif
13133 EMSG2(_(e_invarg2), fromstr);
13134 ga_clear(&ga);
13135 return;
13136 }
13137
13138 /* fromstr and tostr have to contain the same number of chars */
13139 while (*in_str != NUL)
13140 {
13141#ifdef FEAT_MBYTE
13142 if (has_mbyte)
13143 {
13144 inlen = (*mb_ptr2len)(in_str);
13145 cpstr = in_str;
13146 cplen = inlen;
13147 idx = 0;
13148 for (p = fromstr; *p != NUL; p += fromlen)
13149 {
13150 fromlen = (*mb_ptr2len)(p);
13151 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13152 {
13153 for (p = tostr; *p != NUL; p += tolen)
13154 {
13155 tolen = (*mb_ptr2len)(p);
13156 if (idx-- == 0)
13157 {
13158 cplen = tolen;
13159 cpstr = p;
13160 break;
13161 }
13162 }
13163 if (*p == NUL) /* tostr is shorter than fromstr */
13164 goto error;
13165 break;
13166 }
13167 ++idx;
13168 }
13169
13170 if (first && cpstr == in_str)
13171 {
13172 /* Check that fromstr and tostr have the same number of
13173 * (multi-byte) characters. Done only once when a character
13174 * of in_str doesn't appear in fromstr. */
13175 first = FALSE;
13176 for (p = tostr; *p != NUL; p += tolen)
13177 {
13178 tolen = (*mb_ptr2len)(p);
13179 --idx;
13180 }
13181 if (idx != 0)
13182 goto error;
13183 }
13184
13185 (void)ga_grow(&ga, cplen);
13186 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13187 ga.ga_len += cplen;
13188
13189 in_str += inlen;
13190 }
13191 else
13192#endif
13193 {
13194 /* When not using multi-byte chars we can do it faster. */
13195 p = vim_strchr(fromstr, *in_str);
13196 if (p != NULL)
13197 ga_append(&ga, tostr[p - fromstr]);
13198 else
13199 ga_append(&ga, *in_str);
13200 ++in_str;
13201 }
13202 }
13203
13204 /* add a terminating NUL */
13205 (void)ga_grow(&ga, 1);
13206 ga_append(&ga, NUL);
13207
13208 rettv->vval.v_string = ga.ga_data;
13209}
13210
13211#ifdef FEAT_FLOAT
13212/*
13213 * "trunc({float})" function
13214 */
13215 static void
13216f_trunc(typval_T *argvars, typval_T *rettv)
13217{
13218 float_T f = 0.0;
13219
13220 rettv->v_type = VAR_FLOAT;
13221 if (get_float_arg(argvars, &f) == OK)
13222 /* trunc() is not in C90, use floor() or ceil() instead. */
13223 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13224 else
13225 rettv->vval.v_float = 0.0;
13226}
13227#endif
13228
13229/*
13230 * "type(expr)" function
13231 */
13232 static void
13233f_type(typval_T *argvars, typval_T *rettv)
13234{
13235 int n = -1;
13236
13237 switch (argvars[0].v_type)
13238 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013239 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13240 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013241 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013242 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13243 case VAR_LIST: n = VAR_TYPE_LIST; break;
13244 case VAR_DICT: n = VAR_TYPE_DICT; break;
13245 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013246 case VAR_SPECIAL:
13247 if (argvars[0].vval.v_number == VVAL_FALSE
13248 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013249 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013250 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013251 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013252 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013253 case VAR_JOB: n = VAR_TYPE_JOB; break;
13254 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013255 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013256 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013257 n = -1;
13258 break;
13259 }
13260 rettv->vval.v_number = n;
13261}
13262
13263/*
13264 * "undofile(name)" function
13265 */
13266 static void
13267f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13268{
13269 rettv->v_type = VAR_STRING;
13270#ifdef FEAT_PERSISTENT_UNDO
13271 {
13272 char_u *fname = get_tv_string(&argvars[0]);
13273
13274 if (*fname == NUL)
13275 {
13276 /* If there is no file name there will be no undo file. */
13277 rettv->vval.v_string = NULL;
13278 }
13279 else
13280 {
13281 char_u *ffname = FullName_save(fname, FALSE);
13282
13283 if (ffname != NULL)
13284 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13285 vim_free(ffname);
13286 }
13287 }
13288#else
13289 rettv->vval.v_string = NULL;
13290#endif
13291}
13292
13293/*
13294 * "undotree()" function
13295 */
13296 static void
13297f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13298{
13299 if (rettv_dict_alloc(rettv) == OK)
13300 {
13301 dict_T *dict = rettv->vval.v_dict;
13302 list_T *list;
13303
13304 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13305 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13306 dict_add_nr_str(dict, "save_last",
13307 (long)curbuf->b_u_save_nr_last, NULL);
13308 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13309 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13310 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13311
13312 list = list_alloc();
13313 if (list != NULL)
13314 {
13315 u_eval_tree(curbuf->b_u_oldhead, list);
13316 dict_add_list(dict, "entries", list);
13317 }
13318 }
13319}
13320
13321/*
13322 * "values(dict)" function
13323 */
13324 static void
13325f_values(typval_T *argvars, typval_T *rettv)
13326{
13327 dict_list(argvars, rettv, 1);
13328}
13329
13330/*
13331 * "virtcol(string)" function
13332 */
13333 static void
13334f_virtcol(typval_T *argvars, typval_T *rettv)
13335{
13336 colnr_T vcol = 0;
13337 pos_T *fp;
13338 int fnum = curbuf->b_fnum;
13339
13340 fp = var2fpos(&argvars[0], FALSE, &fnum);
13341 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13342 && fnum == curbuf->b_fnum)
13343 {
13344 getvvcol(curwin, fp, NULL, NULL, &vcol);
13345 ++vcol;
13346 }
13347
13348 rettv->vval.v_number = vcol;
13349}
13350
13351/*
13352 * "visualmode()" function
13353 */
13354 static void
13355f_visualmode(typval_T *argvars, typval_T *rettv)
13356{
13357 char_u str[2];
13358
13359 rettv->v_type = VAR_STRING;
13360 str[0] = curbuf->b_visual_mode_eval;
13361 str[1] = NUL;
13362 rettv->vval.v_string = vim_strsave(str);
13363
13364 /* A non-zero number or non-empty string argument: reset mode. */
13365 if (non_zero_arg(&argvars[0]))
13366 curbuf->b_visual_mode_eval = NUL;
13367}
13368
13369/*
13370 * "wildmenumode()" function
13371 */
13372 static void
13373f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13374{
13375#ifdef FEAT_WILDMENU
13376 if (wild_menu_showing)
13377 rettv->vval.v_number = 1;
13378#endif
13379}
13380
13381/*
13382 * "winbufnr(nr)" function
13383 */
13384 static void
13385f_winbufnr(typval_T *argvars, typval_T *rettv)
13386{
13387 win_T *wp;
13388
13389 wp = find_win_by_nr(&argvars[0], NULL);
13390 if (wp == NULL)
13391 rettv->vval.v_number = -1;
13392 else
13393 rettv->vval.v_number = wp->w_buffer->b_fnum;
13394}
13395
13396/*
13397 * "wincol()" function
13398 */
13399 static void
13400f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13401{
13402 validate_cursor();
13403 rettv->vval.v_number = curwin->w_wcol + 1;
13404}
13405
13406/*
13407 * "winheight(nr)" function
13408 */
13409 static void
13410f_winheight(typval_T *argvars, typval_T *rettv)
13411{
13412 win_T *wp;
13413
13414 wp = find_win_by_nr(&argvars[0], NULL);
13415 if (wp == NULL)
13416 rettv->vval.v_number = -1;
13417 else
13418 rettv->vval.v_number = wp->w_height;
13419}
13420
13421/*
13422 * "winline()" function
13423 */
13424 static void
13425f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13426{
13427 validate_cursor();
13428 rettv->vval.v_number = curwin->w_wrow + 1;
13429}
13430
13431/*
13432 * "winnr()" function
13433 */
13434 static void
13435f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13436{
13437 int nr = 1;
13438
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013439 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013440 rettv->vval.v_number = nr;
13441}
13442
13443/*
13444 * "winrestcmd()" function
13445 */
13446 static void
13447f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13448{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013449 win_T *wp;
13450 int winnr = 1;
13451 garray_T ga;
13452 char_u buf[50];
13453
13454 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013455 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013456 {
13457 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13458 ga_concat(&ga, buf);
13459 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13460 ga_concat(&ga, buf);
13461 ++winnr;
13462 }
13463 ga_append(&ga, NUL);
13464
13465 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013466 rettv->v_type = VAR_STRING;
13467}
13468
13469/*
13470 * "winrestview()" function
13471 */
13472 static void
13473f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13474{
13475 dict_T *dict;
13476
13477 if (argvars[0].v_type != VAR_DICT
13478 || (dict = argvars[0].vval.v_dict) == NULL)
13479 EMSG(_(e_invarg));
13480 else
13481 {
13482 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13483 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13484 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13485 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13486#ifdef FEAT_VIRTUALEDIT
13487 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13488 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13489#endif
13490 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13491 {
13492 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13493 curwin->w_set_curswant = FALSE;
13494 }
13495
13496 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13497 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13498#ifdef FEAT_DIFF
13499 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13500 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13501#endif
13502 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13503 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13504 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13505 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13506
13507 check_cursor();
13508 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013509 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013510 changed_window_setting();
13511
13512 if (curwin->w_topline <= 0)
13513 curwin->w_topline = 1;
13514 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13515 curwin->w_topline = curbuf->b_ml.ml_line_count;
13516#ifdef FEAT_DIFF
13517 check_topfill(curwin, TRUE);
13518#endif
13519 }
13520}
13521
13522/*
13523 * "winsaveview()" function
13524 */
13525 static void
13526f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13527{
13528 dict_T *dict;
13529
13530 if (rettv_dict_alloc(rettv) == FAIL)
13531 return;
13532 dict = rettv->vval.v_dict;
13533
13534 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13535 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13536#ifdef FEAT_VIRTUALEDIT
13537 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13538#endif
13539 update_curswant();
13540 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13541
13542 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13543#ifdef FEAT_DIFF
13544 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13545#endif
13546 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13547 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13548}
13549
13550/*
13551 * "winwidth(nr)" function
13552 */
13553 static void
13554f_winwidth(typval_T *argvars, typval_T *rettv)
13555{
13556 win_T *wp;
13557
13558 wp = find_win_by_nr(&argvars[0], NULL);
13559 if (wp == NULL)
13560 rettv->vval.v_number = -1;
13561 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013562 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013563}
13564
13565/*
13566 * "wordcount()" function
13567 */
13568 static void
13569f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13570{
13571 if (rettv_dict_alloc(rettv) == FAIL)
13572 return;
13573 cursor_pos_info(rettv->vval.v_dict);
13574}
13575
13576/*
13577 * "writefile()" function
13578 */
13579 static void
13580f_writefile(typval_T *argvars, typval_T *rettv)
13581{
13582 int binary = FALSE;
13583 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013584#ifdef HAVE_FSYNC
13585 int do_fsync = p_fs;
13586#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013587 char_u *fname;
13588 FILE *fd;
13589 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013590 listitem_T *li;
13591 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013592
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013593 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013594 if (check_restricted() || check_secure())
13595 return;
13596
13597 if (argvars[0].v_type != VAR_LIST)
13598 {
13599 EMSG2(_(e_listarg), "writefile()");
13600 return;
13601 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013602 list = argvars[0].vval.v_list;
13603 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013604 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013605 for (li = list->lv_first; li != NULL; li = li->li_next)
13606 if (get_tv_string_chk(&li->li_tv) == NULL)
13607 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013608
13609 if (argvars[2].v_type != VAR_UNKNOWN)
13610 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013611 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13612
13613 if (arg2 == NULL)
13614 return;
13615 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013616 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013617 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013618 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013619#ifdef HAVE_FSYNC
13620 if (vim_strchr(arg2, 's') != NULL)
13621 do_fsync = TRUE;
13622 else if (vim_strchr(arg2, 'S') != NULL)
13623 do_fsync = FALSE;
13624#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013625 }
13626
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013627 fname = get_tv_string_chk(&argvars[1]);
13628 if (fname == NULL)
13629 return;
13630
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013631 /* Always open the file in binary mode, library functions have a mind of
13632 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013633 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13634 append ? APPENDBIN : WRITEBIN)) == NULL)
13635 {
13636 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13637 ret = -1;
13638 }
13639 else
13640 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013641 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013642 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013643#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013644 else if (do_fsync)
13645 /* Ignore the error, the user wouldn't know what to do about it.
13646 * May happen for a device. */
13647 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013648#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013649 fclose(fd);
13650 }
13651
13652 rettv->vval.v_number = ret;
13653}
13654
13655/*
13656 * "xor(expr, expr)" function
13657 */
13658 static void
13659f_xor(typval_T *argvars, typval_T *rettv)
13660{
13661 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13662 ^ get_tv_number_chk(&argvars[1], NULL);
13663}
13664
13665
13666#endif /* FEAT_EVAL */