blob: ae1425e53bbdb7861900c50cf2767af3c0a0d7ed [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
19#ifdef AMIGA
20# include <time.h> /* for strftime() */
21#endif
22
23#ifdef VMS
24# include <float.h>
25#endif
26
Bram Moolenaard0573012017-10-28 21:11:06 +020027#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028# include <time.h> /* for time_t */
29#endif
30
31static char *e_listarg = N_("E686: Argument of %s must be a List");
32#ifdef FEAT_QUICKFIX
33static char *e_stringreq = N_("E928: String required");
34#endif
35
36#ifdef FEAT_FLOAT
37static void f_abs(typval_T *argvars, typval_T *rettv);
38static void f_acos(typval_T *argvars, typval_T *rettv);
39#endif
40static void f_add(typval_T *argvars, typval_T *rettv);
41static void f_and(typval_T *argvars, typval_T *rettv);
42static void f_append(typval_T *argvars, typval_T *rettv);
43static void f_argc(typval_T *argvars, typval_T *rettv);
44static void f_argidx(typval_T *argvars, typval_T *rettv);
45static void f_arglistid(typval_T *argvars, typval_T *rettv);
46static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010047static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010049static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_assert_exception(typval_T *argvars, typval_T *rettv);
51static void f_assert_fails(typval_T *argvars, typval_T *rettv);
52static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020053static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_assert_match(typval_T *argvars, typval_T *rettv);
55static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
56static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010057static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020058static void f_assert_true(typval_T *argvars, typval_T *rettv);
59#ifdef FEAT_FLOAT
60static void f_asin(typval_T *argvars, typval_T *rettv);
61static void f_atan(typval_T *argvars, typval_T *rettv);
62static void f_atan2(typval_T *argvars, typval_T *rettv);
63#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010064#ifdef FEAT_BEVAL
65static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010066# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010067static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010068# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010069#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_browse(typval_T *argvars, typval_T *rettv);
71static void f_browsedir(typval_T *argvars, typval_T *rettv);
72static void f_bufexists(typval_T *argvars, typval_T *rettv);
73static void f_buflisted(typval_T *argvars, typval_T *rettv);
74static void f_bufloaded(typval_T *argvars, typval_T *rettv);
75static void f_bufname(typval_T *argvars, typval_T *rettv);
76static void f_bufnr(typval_T *argvars, typval_T *rettv);
77static void f_bufwinid(typval_T *argvars, typval_T *rettv);
78static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
79static void f_byte2line(typval_T *argvars, typval_T *rettv);
80static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
81static void f_byteidx(typval_T *argvars, typval_T *rettv);
82static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
83static void f_call(typval_T *argvars, typval_T *rettv);
84#ifdef FEAT_FLOAT
85static void f_ceil(typval_T *argvars, typval_T *rettv);
86#endif
87#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010088static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020090static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
92static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
93static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
94static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
95static void f_ch_info(typval_T *argvars, typval_T *rettv);
96static void f_ch_log(typval_T *argvars, typval_T *rettv);
97static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
98static void f_ch_open(typval_T *argvars, typval_T *rettv);
99static void f_ch_read(typval_T *argvars, typval_T *rettv);
100static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
101static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
102static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
103static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
104static void f_ch_status(typval_T *argvars, typval_T *rettv);
105#endif
106static void f_changenr(typval_T *argvars, typval_T *rettv);
107static void f_char2nr(typval_T *argvars, typval_T *rettv);
108static void f_cindent(typval_T *argvars, typval_T *rettv);
109static void f_clearmatches(typval_T *argvars, typval_T *rettv);
110static void f_col(typval_T *argvars, typval_T *rettv);
111#if defined(FEAT_INS_EXPAND)
112static void f_complete(typval_T *argvars, typval_T *rettv);
113static void f_complete_add(typval_T *argvars, typval_T *rettv);
114static void f_complete_check(typval_T *argvars, typval_T *rettv);
115#endif
116static void f_confirm(typval_T *argvars, typval_T *rettv);
117static void f_copy(typval_T *argvars, typval_T *rettv);
118#ifdef FEAT_FLOAT
119static void f_cos(typval_T *argvars, typval_T *rettv);
120static void f_cosh(typval_T *argvars, typval_T *rettv);
121#endif
122static void f_count(typval_T *argvars, typval_T *rettv);
123static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
124static void f_cursor(typval_T *argsvars, typval_T *rettv);
125static void f_deepcopy(typval_T *argvars, typval_T *rettv);
126static void f_delete(typval_T *argvars, typval_T *rettv);
127static void f_did_filetype(typval_T *argvars, typval_T *rettv);
128static void f_diff_filler(typval_T *argvars, typval_T *rettv);
129static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
130static void f_empty(typval_T *argvars, typval_T *rettv);
131static void f_escape(typval_T *argvars, typval_T *rettv);
132static void f_eval(typval_T *argvars, typval_T *rettv);
133static void f_eventhandler(typval_T *argvars, typval_T *rettv);
134static void f_executable(typval_T *argvars, typval_T *rettv);
135static void f_execute(typval_T *argvars, typval_T *rettv);
136static void f_exepath(typval_T *argvars, typval_T *rettv);
137static void f_exists(typval_T *argvars, typval_T *rettv);
138#ifdef FEAT_FLOAT
139static void f_exp(typval_T *argvars, typval_T *rettv);
140#endif
141static void f_expand(typval_T *argvars, typval_T *rettv);
142static void f_extend(typval_T *argvars, typval_T *rettv);
143static void f_feedkeys(typval_T *argvars, typval_T *rettv);
144static void f_filereadable(typval_T *argvars, typval_T *rettv);
145static void f_filewritable(typval_T *argvars, typval_T *rettv);
146static void f_filter(typval_T *argvars, typval_T *rettv);
147static void f_finddir(typval_T *argvars, typval_T *rettv);
148static void f_findfile(typval_T *argvars, typval_T *rettv);
149#ifdef FEAT_FLOAT
150static void f_float2nr(typval_T *argvars, typval_T *rettv);
151static void f_floor(typval_T *argvars, typval_T *rettv);
152static void f_fmod(typval_T *argvars, typval_T *rettv);
153#endif
154static void f_fnameescape(typval_T *argvars, typval_T *rettv);
155static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
156static void f_foldclosed(typval_T *argvars, typval_T *rettv);
157static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
158static void f_foldlevel(typval_T *argvars, typval_T *rettv);
159static void f_foldtext(typval_T *argvars, typval_T *rettv);
160static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
161static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200162static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200163static void f_function(typval_T *argvars, typval_T *rettv);
164static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
165static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200166static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200167static void f_getbufline(typval_T *argvars, typval_T *rettv);
168static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100169static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_getchar(typval_T *argvars, typval_T *rettv);
171static void f_getcharmod(typval_T *argvars, typval_T *rettv);
172static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
173static void f_getcmdline(typval_T *argvars, typval_T *rettv);
174#if defined(FEAT_CMDL_COMPL)
175static void f_getcompletion(typval_T *argvars, typval_T *rettv);
176#endif
177static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
178static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
179static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
180static void f_getcwd(typval_T *argvars, typval_T *rettv);
181static void f_getfontname(typval_T *argvars, typval_T *rettv);
182static void f_getfperm(typval_T *argvars, typval_T *rettv);
183static void f_getfsize(typval_T *argvars, typval_T *rettv);
184static void f_getftime(typval_T *argvars, typval_T *rettv);
185static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100186static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200188static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200189static void f_getmatches(typval_T *argvars, typval_T *rettv);
190static void f_getpid(typval_T *argvars, typval_T *rettv);
191static void f_getcurpos(typval_T *argvars, typval_T *rettv);
192static void f_getpos(typval_T *argvars, typval_T *rettv);
193static void f_getqflist(typval_T *argvars, typval_T *rettv);
194static void f_getreg(typval_T *argvars, typval_T *rettv);
195static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200196static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_gettabvar(typval_T *argvars, typval_T *rettv);
198static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200199static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100200static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_getwinposx(typval_T *argvars, typval_T *rettv);
202static void f_getwinposy(typval_T *argvars, typval_T *rettv);
203static void f_getwinvar(typval_T *argvars, typval_T *rettv);
204static void f_glob(typval_T *argvars, typval_T *rettv);
205static void f_globpath(typval_T *argvars, typval_T *rettv);
206static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
207static void f_has(typval_T *argvars, typval_T *rettv);
208static void f_has_key(typval_T *argvars, typval_T *rettv);
209static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
210static void f_hasmapto(typval_T *argvars, typval_T *rettv);
211static void f_histadd(typval_T *argvars, typval_T *rettv);
212static void f_histdel(typval_T *argvars, typval_T *rettv);
213static void f_histget(typval_T *argvars, typval_T *rettv);
214static void f_histnr(typval_T *argvars, typval_T *rettv);
215static void f_hlID(typval_T *argvars, typval_T *rettv);
216static void f_hlexists(typval_T *argvars, typval_T *rettv);
217static void f_hostname(typval_T *argvars, typval_T *rettv);
218static void f_iconv(typval_T *argvars, typval_T *rettv);
219static void f_indent(typval_T *argvars, typval_T *rettv);
220static void f_index(typval_T *argvars, typval_T *rettv);
221static void f_input(typval_T *argvars, typval_T *rettv);
222static void f_inputdialog(typval_T *argvars, typval_T *rettv);
223static void f_inputlist(typval_T *argvars, typval_T *rettv);
224static void f_inputrestore(typval_T *argvars, typval_T *rettv);
225static void f_inputsave(typval_T *argvars, typval_T *rettv);
226static void f_inputsecret(typval_T *argvars, typval_T *rettv);
227static void f_insert(typval_T *argvars, typval_T *rettv);
228static void f_invert(typval_T *argvars, typval_T *rettv);
229static void f_isdirectory(typval_T *argvars, typval_T *rettv);
230static void f_islocked(typval_T *argvars, typval_T *rettv);
231#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
232static void f_isnan(typval_T *argvars, typval_T *rettv);
233#endif
234static void f_items(typval_T *argvars, typval_T *rettv);
235#ifdef FEAT_JOB_CHANNEL
236static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
237static void f_job_info(typval_T *argvars, typval_T *rettv);
238static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
239static void f_job_start(typval_T *argvars, typval_T *rettv);
240static void f_job_stop(typval_T *argvars, typval_T *rettv);
241static void f_job_status(typval_T *argvars, typval_T *rettv);
242#endif
243static void f_join(typval_T *argvars, typval_T *rettv);
244static void f_js_decode(typval_T *argvars, typval_T *rettv);
245static void f_js_encode(typval_T *argvars, typval_T *rettv);
246static void f_json_decode(typval_T *argvars, typval_T *rettv);
247static void f_json_encode(typval_T *argvars, typval_T *rettv);
248static void f_keys(typval_T *argvars, typval_T *rettv);
249static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
250static void f_len(typval_T *argvars, typval_T *rettv);
251static void f_libcall(typval_T *argvars, typval_T *rettv);
252static void f_libcallnr(typval_T *argvars, typval_T *rettv);
253static void f_line(typval_T *argvars, typval_T *rettv);
254static void f_line2byte(typval_T *argvars, typval_T *rettv);
255static void f_lispindent(typval_T *argvars, typval_T *rettv);
256static void f_localtime(typval_T *argvars, typval_T *rettv);
257#ifdef FEAT_FLOAT
258static void f_log(typval_T *argvars, typval_T *rettv);
259static void f_log10(typval_T *argvars, typval_T *rettv);
260#endif
261#ifdef FEAT_LUA
262static void f_luaeval(typval_T *argvars, typval_T *rettv);
263#endif
264static void f_map(typval_T *argvars, typval_T *rettv);
265static void f_maparg(typval_T *argvars, typval_T *rettv);
266static void f_mapcheck(typval_T *argvars, typval_T *rettv);
267static void f_match(typval_T *argvars, typval_T *rettv);
268static void f_matchadd(typval_T *argvars, typval_T *rettv);
269static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
270static void f_matcharg(typval_T *argvars, typval_T *rettv);
271static void f_matchdelete(typval_T *argvars, typval_T *rettv);
272static void f_matchend(typval_T *argvars, typval_T *rettv);
273static void f_matchlist(typval_T *argvars, typval_T *rettv);
274static void f_matchstr(typval_T *argvars, typval_T *rettv);
275static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
276static void f_max(typval_T *argvars, typval_T *rettv);
277static void f_min(typval_T *argvars, typval_T *rettv);
278#ifdef vim_mkdir
279static void f_mkdir(typval_T *argvars, typval_T *rettv);
280#endif
281static void f_mode(typval_T *argvars, typval_T *rettv);
282#ifdef FEAT_MZSCHEME
283static void f_mzeval(typval_T *argvars, typval_T *rettv);
284#endif
285static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
286static void f_nr2char(typval_T *argvars, typval_T *rettv);
287static void f_or(typval_T *argvars, typval_T *rettv);
288static void f_pathshorten(typval_T *argvars, typval_T *rettv);
289#ifdef FEAT_PERL
290static void f_perleval(typval_T *argvars, typval_T *rettv);
291#endif
292#ifdef FEAT_FLOAT
293static void f_pow(typval_T *argvars, typval_T *rettv);
294#endif
295static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
296static void f_printf(typval_T *argvars, typval_T *rettv);
297static void f_pumvisible(typval_T *argvars, typval_T *rettv);
298#ifdef FEAT_PYTHON3
299static void f_py3eval(typval_T *argvars, typval_T *rettv);
300#endif
301#ifdef FEAT_PYTHON
302static void f_pyeval(typval_T *argvars, typval_T *rettv);
303#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100304#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
305static void f_pyxeval(typval_T *argvars, typval_T *rettv);
306#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200307static void f_range(typval_T *argvars, typval_T *rettv);
308static void f_readfile(typval_T *argvars, typval_T *rettv);
309static void f_reltime(typval_T *argvars, typval_T *rettv);
310#ifdef FEAT_FLOAT
311static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
312#endif
313static void f_reltimestr(typval_T *argvars, typval_T *rettv);
314static void f_remote_expr(typval_T *argvars, typval_T *rettv);
315static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
316static void f_remote_peek(typval_T *argvars, typval_T *rettv);
317static void f_remote_read(typval_T *argvars, typval_T *rettv);
318static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100319static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200320static void f_remove(typval_T *argvars, typval_T *rettv);
321static void f_rename(typval_T *argvars, typval_T *rettv);
322static void f_repeat(typval_T *argvars, typval_T *rettv);
323static void f_resolve(typval_T *argvars, typval_T *rettv);
324static void f_reverse(typval_T *argvars, typval_T *rettv);
325#ifdef FEAT_FLOAT
326static void f_round(typval_T *argvars, typval_T *rettv);
327#endif
328static void f_screenattr(typval_T *argvars, typval_T *rettv);
329static void f_screenchar(typval_T *argvars, typval_T *rettv);
330static void f_screencol(typval_T *argvars, typval_T *rettv);
331static void f_screenrow(typval_T *argvars, typval_T *rettv);
332static void f_search(typval_T *argvars, typval_T *rettv);
333static void f_searchdecl(typval_T *argvars, typval_T *rettv);
334static void f_searchpair(typval_T *argvars, typval_T *rettv);
335static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
336static void f_searchpos(typval_T *argvars, typval_T *rettv);
337static void f_server2client(typval_T *argvars, typval_T *rettv);
338static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200339static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200340static void f_setbufvar(typval_T *argvars, typval_T *rettv);
341static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
342static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
343static void f_setfperm(typval_T *argvars, typval_T *rettv);
344static void f_setline(typval_T *argvars, typval_T *rettv);
345static void f_setloclist(typval_T *argvars, typval_T *rettv);
346static void f_setmatches(typval_T *argvars, typval_T *rettv);
347static void f_setpos(typval_T *argvars, typval_T *rettv);
348static void f_setqflist(typval_T *argvars, typval_T *rettv);
349static void f_setreg(typval_T *argvars, typval_T *rettv);
350static void f_settabvar(typval_T *argvars, typval_T *rettv);
351static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
352static void f_setwinvar(typval_T *argvars, typval_T *rettv);
353#ifdef FEAT_CRYPT
354static void f_sha256(typval_T *argvars, typval_T *rettv);
355#endif /* FEAT_CRYPT */
356static void f_shellescape(typval_T *argvars, typval_T *rettv);
357static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
358static void f_simplify(typval_T *argvars, typval_T *rettv);
359#ifdef FEAT_FLOAT
360static void f_sin(typval_T *argvars, typval_T *rettv);
361static void f_sinh(typval_T *argvars, typval_T *rettv);
362#endif
363static void f_sort(typval_T *argvars, typval_T *rettv);
364static void f_soundfold(typval_T *argvars, typval_T *rettv);
365static void f_spellbadword(typval_T *argvars, typval_T *rettv);
366static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
367static void f_split(typval_T *argvars, typval_T *rettv);
368#ifdef FEAT_FLOAT
369static void f_sqrt(typval_T *argvars, typval_T *rettv);
370static void f_str2float(typval_T *argvars, typval_T *rettv);
371#endif
372static void f_str2nr(typval_T *argvars, typval_T *rettv);
373static void f_strchars(typval_T *argvars, typval_T *rettv);
374#ifdef HAVE_STRFTIME
375static void f_strftime(typval_T *argvars, typval_T *rettv);
376#endif
377static void f_strgetchar(typval_T *argvars, typval_T *rettv);
378static void f_stridx(typval_T *argvars, typval_T *rettv);
379static void f_string(typval_T *argvars, typval_T *rettv);
380static void f_strlen(typval_T *argvars, typval_T *rettv);
381static void f_strcharpart(typval_T *argvars, typval_T *rettv);
382static void f_strpart(typval_T *argvars, typval_T *rettv);
383static void f_strridx(typval_T *argvars, typval_T *rettv);
384static void f_strtrans(typval_T *argvars, typval_T *rettv);
385static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
386static void f_strwidth(typval_T *argvars, typval_T *rettv);
387static void f_submatch(typval_T *argvars, typval_T *rettv);
388static void f_substitute(typval_T *argvars, typval_T *rettv);
389static void f_synID(typval_T *argvars, typval_T *rettv);
390static void f_synIDattr(typval_T *argvars, typval_T *rettv);
391static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
392static void f_synstack(typval_T *argvars, typval_T *rettv);
393static void f_synconcealed(typval_T *argvars, typval_T *rettv);
394static void f_system(typval_T *argvars, typval_T *rettv);
395static void f_systemlist(typval_T *argvars, typval_T *rettv);
396static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
397static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
398static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
399static void f_taglist(typval_T *argvars, typval_T *rettv);
400static void f_tagfiles(typval_T *argvars, typval_T *rettv);
401static void f_tempname(typval_T *argvars, typval_T *rettv);
402static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
403static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200404static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100405static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100407static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200408#ifdef FEAT_JOB_CHANNEL
409static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
410#endif
411static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
412#ifdef FEAT_JOB_CHANNEL
413static void f_test_null_job(typval_T *argvars, typval_T *rettv);
414#endif
415static void f_test_null_list(typval_T *argvars, typval_T *rettv);
416static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
417static void f_test_null_string(typval_T *argvars, typval_T *rettv);
418static void f_test_settime(typval_T *argvars, typval_T *rettv);
419#ifdef FEAT_FLOAT
420static void f_tan(typval_T *argvars, typval_T *rettv);
421static void f_tanh(typval_T *argvars, typval_T *rettv);
422#endif
423#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200424static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200425static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200426static void f_timer_start(typval_T *argvars, typval_T *rettv);
427static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200428static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429#endif
430static void f_tolower(typval_T *argvars, typval_T *rettv);
431static void f_toupper(typval_T *argvars, typval_T *rettv);
432static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100433static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434#ifdef FEAT_FLOAT
435static void f_trunc(typval_T *argvars, typval_T *rettv);
436#endif
437static void f_type(typval_T *argvars, typval_T *rettv);
438static void f_undofile(typval_T *argvars, typval_T *rettv);
439static void f_undotree(typval_T *argvars, typval_T *rettv);
440static void f_uniq(typval_T *argvars, typval_T *rettv);
441static void f_values(typval_T *argvars, typval_T *rettv);
442static void f_virtcol(typval_T *argvars, typval_T *rettv);
443static void f_visualmode(typval_T *argvars, typval_T *rettv);
444static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
445static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
446static void f_win_getid(typval_T *argvars, typval_T *rettv);
447static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
448static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
449static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100450static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200451static void f_winbufnr(typval_T *argvars, typval_T *rettv);
452static void f_wincol(typval_T *argvars, typval_T *rettv);
453static void f_winheight(typval_T *argvars, typval_T *rettv);
454static void f_winline(typval_T *argvars, typval_T *rettv);
455static void f_winnr(typval_T *argvars, typval_T *rettv);
456static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
457static void f_winrestview(typval_T *argvars, typval_T *rettv);
458static void f_winsaveview(typval_T *argvars, typval_T *rettv);
459static void f_winwidth(typval_T *argvars, typval_T *rettv);
460static void f_writefile(typval_T *argvars, typval_T *rettv);
461static void f_wordcount(typval_T *argvars, typval_T *rettv);
462static void f_xor(typval_T *argvars, typval_T *rettv);
463
464/*
465 * Array with names and number of arguments of all internal functions
466 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
467 */
468static struct fst
469{
470 char *f_name; /* function name */
471 char f_min_argc; /* minimal number of arguments */
472 char f_max_argc; /* maximal number of arguments */
473 void (*f_func)(typval_T *args, typval_T *rvar);
474 /* implementation of function */
475} functions[] =
476{
477#ifdef FEAT_FLOAT
478 {"abs", 1, 1, f_abs},
479 {"acos", 1, 1, f_acos}, /* WJMc */
480#endif
481 {"add", 2, 2, f_add},
482 {"and", 2, 2, f_and},
483 {"append", 2, 2, f_append},
484 {"argc", 0, 0, f_argc},
485 {"argidx", 0, 0, f_argidx},
486 {"arglistid", 0, 2, f_arglistid},
487 {"argv", 0, 1, f_argv},
488#ifdef FEAT_FLOAT
489 {"asin", 1, 1, f_asin}, /* WJMc */
490#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100491 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200492 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100493 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200494 {"assert_exception", 1, 2, f_assert_exception},
495 {"assert_fails", 1, 2, f_assert_fails},
496 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100497 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498 {"assert_match", 2, 3, f_assert_match},
499 {"assert_notequal", 2, 3, f_assert_notequal},
500 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100501 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200502 {"assert_true", 1, 2, f_assert_true},
503#ifdef FEAT_FLOAT
504 {"atan", 1, 1, f_atan},
505 {"atan2", 2, 2, f_atan2},
506#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100507#ifdef FEAT_BEVAL
508 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100509# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100510 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100511# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100512#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513 {"browse", 4, 4, f_browse},
514 {"browsedir", 2, 2, f_browsedir},
515 {"bufexists", 1, 1, f_bufexists},
516 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
517 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
518 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
519 {"buflisted", 1, 1, f_buflisted},
520 {"bufloaded", 1, 1, f_bufloaded},
521 {"bufname", 1, 1, f_bufname},
522 {"bufnr", 1, 2, f_bufnr},
523 {"bufwinid", 1, 1, f_bufwinid},
524 {"bufwinnr", 1, 1, f_bufwinnr},
525 {"byte2line", 1, 1, f_byte2line},
526 {"byteidx", 2, 2, f_byteidx},
527 {"byteidxcomp", 2, 2, f_byteidxcomp},
528 {"call", 2, 3, f_call},
529#ifdef FEAT_FLOAT
530 {"ceil", 1, 1, f_ceil},
531#endif
532#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100533 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200534 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200535 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
537 {"ch_evalraw", 2, 3, f_ch_evalraw},
538 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
539 {"ch_getjob", 1, 1, f_ch_getjob},
540 {"ch_info", 1, 1, f_ch_info},
541 {"ch_log", 1, 2, f_ch_log},
542 {"ch_logfile", 1, 2, f_ch_logfile},
543 {"ch_open", 1, 2, f_ch_open},
544 {"ch_read", 1, 2, f_ch_read},
545 {"ch_readraw", 1, 2, f_ch_readraw},
546 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
547 {"ch_sendraw", 2, 3, f_ch_sendraw},
548 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200549 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#endif
551 {"changenr", 0, 0, f_changenr},
552 {"char2nr", 1, 2, f_char2nr},
553 {"cindent", 1, 1, f_cindent},
554 {"clearmatches", 0, 0, f_clearmatches},
555 {"col", 1, 1, f_col},
556#if defined(FEAT_INS_EXPAND)
557 {"complete", 2, 2, f_complete},
558 {"complete_add", 1, 1, f_complete_add},
559 {"complete_check", 0, 0, f_complete_check},
560#endif
561 {"confirm", 1, 4, f_confirm},
562 {"copy", 1, 1, f_copy},
563#ifdef FEAT_FLOAT
564 {"cos", 1, 1, f_cos},
565 {"cosh", 1, 1, f_cosh},
566#endif
567 {"count", 2, 4, f_count},
568 {"cscope_connection",0,3, f_cscope_connection},
569 {"cursor", 1, 3, f_cursor},
570 {"deepcopy", 1, 2, f_deepcopy},
571 {"delete", 1, 2, f_delete},
572 {"did_filetype", 0, 0, f_did_filetype},
573 {"diff_filler", 1, 1, f_diff_filler},
574 {"diff_hlID", 2, 2, f_diff_hlID},
575 {"empty", 1, 1, f_empty},
576 {"escape", 2, 2, f_escape},
577 {"eval", 1, 1, f_eval},
578 {"eventhandler", 0, 0, f_eventhandler},
579 {"executable", 1, 1, f_executable},
580 {"execute", 1, 2, f_execute},
581 {"exepath", 1, 1, f_exepath},
582 {"exists", 1, 1, f_exists},
583#ifdef FEAT_FLOAT
584 {"exp", 1, 1, f_exp},
585#endif
586 {"expand", 1, 3, f_expand},
587 {"extend", 2, 3, f_extend},
588 {"feedkeys", 1, 2, f_feedkeys},
589 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
590 {"filereadable", 1, 1, f_filereadable},
591 {"filewritable", 1, 1, f_filewritable},
592 {"filter", 2, 2, f_filter},
593 {"finddir", 1, 3, f_finddir},
594 {"findfile", 1, 3, f_findfile},
595#ifdef FEAT_FLOAT
596 {"float2nr", 1, 1, f_float2nr},
597 {"floor", 1, 1, f_floor},
598 {"fmod", 2, 2, f_fmod},
599#endif
600 {"fnameescape", 1, 1, f_fnameescape},
601 {"fnamemodify", 2, 2, f_fnamemodify},
602 {"foldclosed", 1, 1, f_foldclosed},
603 {"foldclosedend", 1, 1, f_foldclosedend},
604 {"foldlevel", 1, 1, f_foldlevel},
605 {"foldtext", 0, 0, f_foldtext},
606 {"foldtextresult", 1, 1, f_foldtextresult},
607 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200608 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200609 {"function", 1, 3, f_function},
610 {"garbagecollect", 0, 1, f_garbagecollect},
611 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200612 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200613 {"getbufline", 2, 3, f_getbufline},
614 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100615 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200616 {"getchar", 0, 1, f_getchar},
617 {"getcharmod", 0, 0, f_getcharmod},
618 {"getcharsearch", 0, 0, f_getcharsearch},
619 {"getcmdline", 0, 0, f_getcmdline},
620 {"getcmdpos", 0, 0, f_getcmdpos},
621 {"getcmdtype", 0, 0, f_getcmdtype},
622 {"getcmdwintype", 0, 0, f_getcmdwintype},
623#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200624 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625#endif
626 {"getcurpos", 0, 0, f_getcurpos},
627 {"getcwd", 0, 2, f_getcwd},
628 {"getfontname", 0, 1, f_getfontname},
629 {"getfperm", 1, 1, f_getfperm},
630 {"getfsize", 1, 1, f_getfsize},
631 {"getftime", 1, 1, f_getftime},
632 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100633 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200634 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200635 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636 {"getmatches", 0, 0, f_getmatches},
637 {"getpid", 0, 0, f_getpid},
638 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200639 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640 {"getreg", 0, 3, f_getreg},
641 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200642 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643 {"gettabvar", 2, 3, f_gettabvar},
644 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200645 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100646 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200647 {"getwinposx", 0, 0, f_getwinposx},
648 {"getwinposy", 0, 0, f_getwinposy},
649 {"getwinvar", 2, 3, f_getwinvar},
650 {"glob", 1, 4, f_glob},
651 {"glob2regpat", 1, 1, f_glob2regpat},
652 {"globpath", 2, 5, f_globpath},
653 {"has", 1, 1, f_has},
654 {"has_key", 2, 2, f_has_key},
655 {"haslocaldir", 0, 2, f_haslocaldir},
656 {"hasmapto", 1, 3, f_hasmapto},
657 {"highlightID", 1, 1, f_hlID}, /* obsolete */
658 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
659 {"histadd", 2, 2, f_histadd},
660 {"histdel", 1, 2, f_histdel},
661 {"histget", 1, 2, f_histget},
662 {"histnr", 1, 1, f_histnr},
663 {"hlID", 1, 1, f_hlID},
664 {"hlexists", 1, 1, f_hlexists},
665 {"hostname", 0, 0, f_hostname},
666 {"iconv", 3, 3, f_iconv},
667 {"indent", 1, 1, f_indent},
668 {"index", 2, 4, f_index},
669 {"input", 1, 3, f_input},
670 {"inputdialog", 1, 3, f_inputdialog},
671 {"inputlist", 1, 1, f_inputlist},
672 {"inputrestore", 0, 0, f_inputrestore},
673 {"inputsave", 0, 0, f_inputsave},
674 {"inputsecret", 1, 2, f_inputsecret},
675 {"insert", 2, 3, f_insert},
676 {"invert", 1, 1, f_invert},
677 {"isdirectory", 1, 1, f_isdirectory},
678 {"islocked", 1, 1, f_islocked},
679#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
680 {"isnan", 1, 1, f_isnan},
681#endif
682 {"items", 1, 1, f_items},
683#ifdef FEAT_JOB_CHANNEL
684 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200685 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200686 {"job_setoptions", 2, 2, f_job_setoptions},
687 {"job_start", 1, 2, f_job_start},
688 {"job_status", 1, 1, f_job_status},
689 {"job_stop", 1, 2, f_job_stop},
690#endif
691 {"join", 1, 2, f_join},
692 {"js_decode", 1, 1, f_js_decode},
693 {"js_encode", 1, 1, f_js_encode},
694 {"json_decode", 1, 1, f_json_decode},
695 {"json_encode", 1, 1, f_json_encode},
696 {"keys", 1, 1, f_keys},
697 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
698 {"len", 1, 1, f_len},
699 {"libcall", 3, 3, f_libcall},
700 {"libcallnr", 3, 3, f_libcallnr},
701 {"line", 1, 1, f_line},
702 {"line2byte", 1, 1, f_line2byte},
703 {"lispindent", 1, 1, f_lispindent},
704 {"localtime", 0, 0, f_localtime},
705#ifdef FEAT_FLOAT
706 {"log", 1, 1, f_log},
707 {"log10", 1, 1, f_log10},
708#endif
709#ifdef FEAT_LUA
710 {"luaeval", 1, 2, f_luaeval},
711#endif
712 {"map", 2, 2, f_map},
713 {"maparg", 1, 4, f_maparg},
714 {"mapcheck", 1, 3, f_mapcheck},
715 {"match", 2, 4, f_match},
716 {"matchadd", 2, 5, f_matchadd},
717 {"matchaddpos", 2, 5, f_matchaddpos},
718 {"matcharg", 1, 1, f_matcharg},
719 {"matchdelete", 1, 1, f_matchdelete},
720 {"matchend", 2, 4, f_matchend},
721 {"matchlist", 2, 4, f_matchlist},
722 {"matchstr", 2, 4, f_matchstr},
723 {"matchstrpos", 2, 4, f_matchstrpos},
724 {"max", 1, 1, f_max},
725 {"min", 1, 1, f_min},
726#ifdef vim_mkdir
727 {"mkdir", 1, 3, f_mkdir},
728#endif
729 {"mode", 0, 1, f_mode},
730#ifdef FEAT_MZSCHEME
731 {"mzeval", 1, 1, f_mzeval},
732#endif
733 {"nextnonblank", 1, 1, f_nextnonblank},
734 {"nr2char", 1, 2, f_nr2char},
735 {"or", 2, 2, f_or},
736 {"pathshorten", 1, 1, f_pathshorten},
737#ifdef FEAT_PERL
738 {"perleval", 1, 1, f_perleval},
739#endif
740#ifdef FEAT_FLOAT
741 {"pow", 2, 2, f_pow},
742#endif
743 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100744 {"printf", 1, 19, f_printf},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200745 {"pumvisible", 0, 0, f_pumvisible},
746#ifdef FEAT_PYTHON3
747 {"py3eval", 1, 1, f_py3eval},
748#endif
749#ifdef FEAT_PYTHON
750 {"pyeval", 1, 1, f_pyeval},
751#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100752#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
753 {"pyxeval", 1, 1, f_pyxeval},
754#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200755 {"range", 1, 3, f_range},
756 {"readfile", 1, 3, f_readfile},
757 {"reltime", 0, 2, f_reltime},
758#ifdef FEAT_FLOAT
759 {"reltimefloat", 1, 1, f_reltimefloat},
760#endif
761 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100762 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763 {"remote_foreground", 1, 1, f_remote_foreground},
764 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100765 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200766 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100767 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200768 {"remove", 2, 3, f_remove},
769 {"rename", 2, 2, f_rename},
770 {"repeat", 2, 2, f_repeat},
771 {"resolve", 1, 1, f_resolve},
772 {"reverse", 1, 1, f_reverse},
773#ifdef FEAT_FLOAT
774 {"round", 1, 1, f_round},
775#endif
776 {"screenattr", 2, 2, f_screenattr},
777 {"screenchar", 2, 2, f_screenchar},
778 {"screencol", 0, 0, f_screencol},
779 {"screenrow", 0, 0, f_screenrow},
780 {"search", 1, 4, f_search},
781 {"searchdecl", 1, 3, f_searchdecl},
782 {"searchpair", 3, 7, f_searchpair},
783 {"searchpairpos", 3, 7, f_searchpairpos},
784 {"searchpos", 1, 4, f_searchpos},
785 {"server2client", 2, 2, f_server2client},
786 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200787 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"setbufvar", 3, 3, f_setbufvar},
789 {"setcharsearch", 1, 1, f_setcharsearch},
790 {"setcmdpos", 1, 1, f_setcmdpos},
791 {"setfperm", 2, 2, f_setfperm},
792 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200793 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794 {"setmatches", 1, 1, f_setmatches},
795 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200796 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200797 {"setreg", 2, 3, f_setreg},
798 {"settabvar", 3, 3, f_settabvar},
799 {"settabwinvar", 4, 4, f_settabwinvar},
800 {"setwinvar", 3, 3, f_setwinvar},
801#ifdef FEAT_CRYPT
802 {"sha256", 1, 1, f_sha256},
803#endif
804 {"shellescape", 1, 2, f_shellescape},
805 {"shiftwidth", 0, 0, f_shiftwidth},
806 {"simplify", 1, 1, f_simplify},
807#ifdef FEAT_FLOAT
808 {"sin", 1, 1, f_sin},
809 {"sinh", 1, 1, f_sinh},
810#endif
811 {"sort", 1, 3, f_sort},
812 {"soundfold", 1, 1, f_soundfold},
813 {"spellbadword", 0, 1, f_spellbadword},
814 {"spellsuggest", 1, 3, f_spellsuggest},
815 {"split", 1, 3, f_split},
816#ifdef FEAT_FLOAT
817 {"sqrt", 1, 1, f_sqrt},
818 {"str2float", 1, 1, f_str2float},
819#endif
820 {"str2nr", 1, 2, f_str2nr},
821 {"strcharpart", 2, 3, f_strcharpart},
822 {"strchars", 1, 2, f_strchars},
823 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
824#ifdef HAVE_STRFTIME
825 {"strftime", 1, 2, f_strftime},
826#endif
827 {"strgetchar", 2, 2, f_strgetchar},
828 {"stridx", 2, 3, f_stridx},
829 {"string", 1, 1, f_string},
830 {"strlen", 1, 1, f_strlen},
831 {"strpart", 2, 3, f_strpart},
832 {"strridx", 2, 3, f_strridx},
833 {"strtrans", 1, 1, f_strtrans},
834 {"strwidth", 1, 1, f_strwidth},
835 {"submatch", 1, 2, f_submatch},
836 {"substitute", 4, 4, f_substitute},
837 {"synID", 3, 3, f_synID},
838 {"synIDattr", 2, 3, f_synIDattr},
839 {"synIDtrans", 1, 1, f_synIDtrans},
840 {"synconcealed", 2, 2, f_synconcealed},
841 {"synstack", 2, 2, f_synstack},
842 {"system", 1, 2, f_system},
843 {"systemlist", 1, 2, f_systemlist},
844 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
845 {"tabpagenr", 0, 1, f_tabpagenr},
846 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
847 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100848 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849#ifdef FEAT_FLOAT
850 {"tan", 1, 1, f_tan},
851 {"tanh", 1, 1, f_tanh},
852#endif
853 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200854#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100855 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
856 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100857 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200858 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200859# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
860 {"term_getansicolors", 1, 1, f_term_getansicolors},
861# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200862 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200863 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200864 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200865 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200866 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200867 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200868 {"term_getstatus", 1, 1, f_term_getstatus},
869 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200870 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200871 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200872 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200873 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200874# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
875 {"term_setansicolors", 2, 2, f_term_setansicolors},
876# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100877 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100878 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200879 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200880 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200881 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200882#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
884 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200885 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100887 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888#ifdef FEAT_JOB_CHANNEL
889 {"test_null_channel", 0, 0, f_test_null_channel},
890#endif
891 {"test_null_dict", 0, 0, f_test_null_dict},
892#ifdef FEAT_JOB_CHANNEL
893 {"test_null_job", 0, 0, f_test_null_job},
894#endif
895 {"test_null_list", 0, 0, f_test_null_list},
896 {"test_null_partial", 0, 0, f_test_null_partial},
897 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100898 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200899 {"test_settime", 1, 1, f_test_settime},
900#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200901 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200902 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200903 {"timer_start", 2, 3, f_timer_start},
904 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200905 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200906#endif
907 {"tolower", 1, 1, f_tolower},
908 {"toupper", 1, 1, f_toupper},
909 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100910 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200911#ifdef FEAT_FLOAT
912 {"trunc", 1, 1, f_trunc},
913#endif
914 {"type", 1, 1, f_type},
915 {"undofile", 1, 1, f_undofile},
916 {"undotree", 0, 0, f_undotree},
917 {"uniq", 1, 3, f_uniq},
918 {"values", 1, 1, f_values},
919 {"virtcol", 1, 1, f_virtcol},
920 {"visualmode", 0, 1, f_visualmode},
921 {"wildmenumode", 0, 0, f_wildmenumode},
922 {"win_findbuf", 1, 1, f_win_findbuf},
923 {"win_getid", 0, 2, f_win_getid},
924 {"win_gotoid", 1, 1, f_win_gotoid},
925 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
926 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100927 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928 {"winbufnr", 1, 1, f_winbufnr},
929 {"wincol", 0, 0, f_wincol},
930 {"winheight", 1, 1, f_winheight},
931 {"winline", 0, 0, f_winline},
932 {"winnr", 0, 1, f_winnr},
933 {"winrestcmd", 0, 0, f_winrestcmd},
934 {"winrestview", 1, 1, f_winrestview},
935 {"winsaveview", 0, 0, f_winsaveview},
936 {"winwidth", 1, 1, f_winwidth},
937 {"wordcount", 0, 0, f_wordcount},
938 {"writefile", 2, 3, f_writefile},
939 {"xor", 2, 2, f_xor},
940};
941
942#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
943
944/*
945 * Function given to ExpandGeneric() to obtain the list of internal
946 * or user defined function names.
947 */
948 char_u *
949get_function_name(expand_T *xp, int idx)
950{
951 static int intidx = -1;
952 char_u *name;
953
954 if (idx == 0)
955 intidx = -1;
956 if (intidx < 0)
957 {
958 name = get_user_func_name(xp, idx);
959 if (name != NULL)
960 return name;
961 }
962 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
963 {
964 STRCPY(IObuff, functions[intidx].f_name);
965 STRCAT(IObuff, "(");
966 if (functions[intidx].f_max_argc == 0)
967 STRCAT(IObuff, ")");
968 return IObuff;
969 }
970
971 return NULL;
972}
973
974/*
975 * Function given to ExpandGeneric() to obtain the list of internal or
976 * user defined variable or function names.
977 */
978 char_u *
979get_expr_name(expand_T *xp, int idx)
980{
981 static int intidx = -1;
982 char_u *name;
983
984 if (idx == 0)
985 intidx = -1;
986 if (intidx < 0)
987 {
988 name = get_function_name(xp, idx);
989 if (name != NULL)
990 return name;
991 }
992 return get_user_var_name(xp, ++intidx);
993}
994
995#endif /* FEAT_CMDL_COMPL */
996
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200997/*
998 * Find internal function in table above.
999 * Return index, or -1 if not found
1000 */
1001 int
1002find_internal_func(
1003 char_u *name) /* name of the function */
1004{
1005 int first = 0;
1006 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1007 int cmp;
1008 int x;
1009
1010 /*
1011 * Find the function name in the table. Binary search.
1012 */
1013 while (first <= last)
1014 {
1015 x = first + ((unsigned)(last - first) >> 1);
1016 cmp = STRCMP(name, functions[x].f_name);
1017 if (cmp < 0)
1018 last = x - 1;
1019 else if (cmp > 0)
1020 first = x + 1;
1021 else
1022 return x;
1023 }
1024 return -1;
1025}
1026
1027 int
1028call_internal_func(
1029 char_u *name,
1030 int argcount,
1031 typval_T *argvars,
1032 typval_T *rettv)
1033{
1034 int i;
1035
1036 i = find_internal_func(name);
1037 if (i < 0)
1038 return ERROR_UNKNOWN;
1039 if (argcount < functions[i].f_min_argc)
1040 return ERROR_TOOFEW;
1041 if (argcount > functions[i].f_max_argc)
1042 return ERROR_TOOMANY;
1043 argvars[argcount].v_type = VAR_UNKNOWN;
1044 functions[i].f_func(argvars, rettv);
1045 return ERROR_NONE;
1046}
1047
1048/*
1049 * Return TRUE for a non-zero Number and a non-empty String.
1050 */
1051 static int
1052non_zero_arg(typval_T *argvars)
1053{
1054 return ((argvars[0].v_type == VAR_NUMBER
1055 && argvars[0].vval.v_number != 0)
1056 || (argvars[0].v_type == VAR_SPECIAL
1057 && argvars[0].vval.v_number == VVAL_TRUE)
1058 || (argvars[0].v_type == VAR_STRING
1059 && argvars[0].vval.v_string != NULL
1060 && *argvars[0].vval.v_string != NUL));
1061}
1062
1063/*
1064 * Get the lnum from the first argument.
1065 * Also accepts ".", "$", etc., but that only works for the current buffer.
1066 * Returns -1 on error.
1067 */
1068 static linenr_T
1069get_tv_lnum(typval_T *argvars)
1070{
1071 typval_T rettv;
1072 linenr_T lnum;
1073
1074 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1075 if (lnum == 0) /* no valid number, try using line() */
1076 {
1077 rettv.v_type = VAR_NUMBER;
1078 f_line(argvars, &rettv);
1079 lnum = (linenr_T)rettv.vval.v_number;
1080 clear_tv(&rettv);
1081 }
1082 return lnum;
1083}
1084
1085#ifdef FEAT_FLOAT
1086static int get_float_arg(typval_T *argvars, float_T *f);
1087
1088/*
1089 * Get the float value of "argvars[0]" into "f".
1090 * Returns FAIL when the argument is not a Number or Float.
1091 */
1092 static int
1093get_float_arg(typval_T *argvars, float_T *f)
1094{
1095 if (argvars[0].v_type == VAR_FLOAT)
1096 {
1097 *f = argvars[0].vval.v_float;
1098 return OK;
1099 }
1100 if (argvars[0].v_type == VAR_NUMBER)
1101 {
1102 *f = (float_T)argvars[0].vval.v_number;
1103 return OK;
1104 }
1105 EMSG(_("E808: Number or Float required"));
1106 return FAIL;
1107}
1108
1109/*
1110 * "abs(expr)" function
1111 */
1112 static void
1113f_abs(typval_T *argvars, typval_T *rettv)
1114{
1115 if (argvars[0].v_type == VAR_FLOAT)
1116 {
1117 rettv->v_type = VAR_FLOAT;
1118 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1119 }
1120 else
1121 {
1122 varnumber_T n;
1123 int error = FALSE;
1124
1125 n = get_tv_number_chk(&argvars[0], &error);
1126 if (error)
1127 rettv->vval.v_number = -1;
1128 else if (n > 0)
1129 rettv->vval.v_number = n;
1130 else
1131 rettv->vval.v_number = -n;
1132 }
1133}
1134
1135/*
1136 * "acos()" function
1137 */
1138 static void
1139f_acos(typval_T *argvars, typval_T *rettv)
1140{
1141 float_T f = 0.0;
1142
1143 rettv->v_type = VAR_FLOAT;
1144 if (get_float_arg(argvars, &f) == OK)
1145 rettv->vval.v_float = acos(f);
1146 else
1147 rettv->vval.v_float = 0.0;
1148}
1149#endif
1150
1151/*
1152 * "add(list, item)" function
1153 */
1154 static void
1155f_add(typval_T *argvars, typval_T *rettv)
1156{
1157 list_T *l;
1158
1159 rettv->vval.v_number = 1; /* Default: Failed */
1160 if (argvars[0].v_type == VAR_LIST)
1161 {
1162 if ((l = argvars[0].vval.v_list) != NULL
1163 && !tv_check_lock(l->lv_lock,
1164 (char_u *)N_("add() argument"), TRUE)
1165 && list_append_tv(l, &argvars[1]) == OK)
1166 copy_tv(&argvars[0], rettv);
1167 }
1168 else
1169 EMSG(_(e_listreq));
1170}
1171
1172/*
1173 * "and(expr, expr)" function
1174 */
1175 static void
1176f_and(typval_T *argvars, typval_T *rettv)
1177{
1178 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1179 & get_tv_number_chk(&argvars[1], NULL);
1180}
1181
1182/*
1183 * "append(lnum, string/list)" function
1184 */
1185 static void
1186f_append(typval_T *argvars, typval_T *rettv)
1187{
1188 long lnum;
1189 char_u *line;
1190 list_T *l = NULL;
1191 listitem_T *li = NULL;
1192 typval_T *tv;
1193 long added = 0;
1194
1195 /* When coming here from Insert mode, sync undo, so that this can be
1196 * undone separately from what was previously inserted. */
1197 if (u_sync_once == 2)
1198 {
1199 u_sync_once = 1; /* notify that u_sync() was called */
1200 u_sync(TRUE);
1201 }
1202
1203 lnum = get_tv_lnum(argvars);
1204 if (lnum >= 0
1205 && lnum <= curbuf->b_ml.ml_line_count
1206 && u_save(lnum, lnum + 1) == OK)
1207 {
1208 if (argvars[1].v_type == VAR_LIST)
1209 {
1210 l = argvars[1].vval.v_list;
1211 if (l == NULL)
1212 return;
1213 li = l->lv_first;
1214 }
1215 for (;;)
1216 {
1217 if (l == NULL)
1218 tv = &argvars[1]; /* append a string */
1219 else if (li == NULL)
1220 break; /* end of list */
1221 else
1222 tv = &li->li_tv; /* append item from list */
1223 line = get_tv_string_chk(tv);
1224 if (line == NULL) /* type error */
1225 {
1226 rettv->vval.v_number = 1; /* Failed */
1227 break;
1228 }
1229 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1230 ++added;
1231 if (l == NULL)
1232 break;
1233 li = li->li_next;
1234 }
1235
1236 appended_lines_mark(lnum, added);
1237 if (curwin->w_cursor.lnum > lnum)
1238 curwin->w_cursor.lnum += added;
1239 }
1240 else
1241 rettv->vval.v_number = 1; /* Failed */
1242}
1243
1244/*
1245 * "argc()" function
1246 */
1247 static void
1248f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1249{
1250 rettv->vval.v_number = ARGCOUNT;
1251}
1252
1253/*
1254 * "argidx()" function
1255 */
1256 static void
1257f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1258{
1259 rettv->vval.v_number = curwin->w_arg_idx;
1260}
1261
1262/*
1263 * "arglistid()" function
1264 */
1265 static void
1266f_arglistid(typval_T *argvars, typval_T *rettv)
1267{
1268 win_T *wp;
1269
1270 rettv->vval.v_number = -1;
1271 wp = find_tabwin(&argvars[0], &argvars[1]);
1272 if (wp != NULL)
1273 rettv->vval.v_number = wp->w_alist->id;
1274}
1275
1276/*
1277 * "argv(nr)" function
1278 */
1279 static void
1280f_argv(typval_T *argvars, typval_T *rettv)
1281{
1282 int idx;
1283
1284 if (argvars[0].v_type != VAR_UNKNOWN)
1285 {
1286 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1287 if (idx >= 0 && idx < ARGCOUNT)
1288 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1289 else
1290 rettv->vval.v_string = NULL;
1291 rettv->v_type = VAR_STRING;
1292 }
1293 else if (rettv_list_alloc(rettv) == OK)
1294 for (idx = 0; idx < ARGCOUNT; ++idx)
1295 list_append_string(rettv->vval.v_list,
1296 alist_name(&ARGLIST[idx]), -1);
1297}
1298
1299/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001300 * "assert_beeps(cmd [, error])" function
1301 */
1302 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001303f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001304{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001305 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001306}
1307
1308/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001309 * "assert_equal(expected, actual[, msg])" function
1310 */
1311 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001312f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001314 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001315}
1316
1317/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001318 * "assert_equalfile(fname-one, fname-two)" function
1319 */
1320 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001321f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001322{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001323 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001324}
1325
1326/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001327 * "assert_notequal(expected, actual[, msg])" function
1328 */
1329 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001330f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001331{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001332 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001333}
1334
1335/*
1336 * "assert_exception(string[, msg])" function
1337 */
1338 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001339f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001340{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001341 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001342}
1343
1344/*
1345 * "assert_fails(cmd [, error])" function
1346 */
1347 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001348f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001349{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001350 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001351}
1352
1353/*
1354 * "assert_false(actual[, msg])" function
1355 */
1356 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001357f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001359 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360}
1361
1362/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001363 * "assert_inrange(lower, upper[, msg])" function
1364 */
1365 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001366f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001367{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001368 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001369}
1370
1371/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001372 * "assert_match(pattern, actual[, msg])" function
1373 */
1374 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001375f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001377 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001378}
1379
1380/*
1381 * "assert_notmatch(pattern, actual[, msg])" function
1382 */
1383 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001384f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001385{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001386 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001387}
1388
1389/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001390 * "assert_report(msg)" function
1391 */
1392 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001393f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001394{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001395 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001396}
1397
1398/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001399 * "assert_true(actual[, msg])" function
1400 */
1401 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001402f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001403{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001404 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001405}
1406
1407#ifdef FEAT_FLOAT
1408/*
1409 * "asin()" function
1410 */
1411 static void
1412f_asin(typval_T *argvars, typval_T *rettv)
1413{
1414 float_T f = 0.0;
1415
1416 rettv->v_type = VAR_FLOAT;
1417 if (get_float_arg(argvars, &f) == OK)
1418 rettv->vval.v_float = asin(f);
1419 else
1420 rettv->vval.v_float = 0.0;
1421}
1422
1423/*
1424 * "atan()" function
1425 */
1426 static void
1427f_atan(typval_T *argvars, typval_T *rettv)
1428{
1429 float_T f = 0.0;
1430
1431 rettv->v_type = VAR_FLOAT;
1432 if (get_float_arg(argvars, &f) == OK)
1433 rettv->vval.v_float = atan(f);
1434 else
1435 rettv->vval.v_float = 0.0;
1436}
1437
1438/*
1439 * "atan2()" function
1440 */
1441 static void
1442f_atan2(typval_T *argvars, typval_T *rettv)
1443{
1444 float_T fx = 0.0, fy = 0.0;
1445
1446 rettv->v_type = VAR_FLOAT;
1447 if (get_float_arg(argvars, &fx) == OK
1448 && get_float_arg(&argvars[1], &fy) == OK)
1449 rettv->vval.v_float = atan2(fx, fy);
1450 else
1451 rettv->vval.v_float = 0.0;
1452}
1453#endif
1454
1455/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001456 * "balloon_show()" function
1457 */
1458#ifdef FEAT_BEVAL
1459 static void
1460f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1461{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001462 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001463 {
1464 if (argvars[0].v_type == VAR_LIST
1465# ifdef FEAT_GUI
1466 && !gui.in_use
1467# endif
1468 )
1469 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1470 else
1471 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1472 }
1473}
1474
Bram Moolenaar669a8282017-11-19 20:13:05 +01001475# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001476 static void
1477f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1478{
1479 if (rettv_list_alloc(rettv) == OK)
1480 {
1481 char_u *msg = get_tv_string_chk(&argvars[0]);
1482
1483 if (msg != NULL)
1484 {
1485 pumitem_T *array;
1486 int size = split_message(msg, &array);
1487 int i;
1488
1489 /* Skip the first and last item, they are always empty. */
1490 for (i = 1; i < size - 1; ++i)
1491 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001492 while (size > 0)
1493 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001494 vim_free(array);
1495 }
1496 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001497}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001498# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001499#endif
1500
1501/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502 * "browse(save, title, initdir, default)" function
1503 */
1504 static void
1505f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1506{
1507#ifdef FEAT_BROWSE
1508 int save;
1509 char_u *title;
1510 char_u *initdir;
1511 char_u *defname;
1512 char_u buf[NUMBUFLEN];
1513 char_u buf2[NUMBUFLEN];
1514 int error = FALSE;
1515
1516 save = (int)get_tv_number_chk(&argvars[0], &error);
1517 title = get_tv_string_chk(&argvars[1]);
1518 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1519 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1520
1521 if (error || title == NULL || initdir == NULL || defname == NULL)
1522 rettv->vval.v_string = NULL;
1523 else
1524 rettv->vval.v_string =
1525 do_browse(save ? BROWSE_SAVE : 0,
1526 title, defname, NULL, initdir, NULL, curbuf);
1527#else
1528 rettv->vval.v_string = NULL;
1529#endif
1530 rettv->v_type = VAR_STRING;
1531}
1532
1533/*
1534 * "browsedir(title, initdir)" function
1535 */
1536 static void
1537f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1538{
1539#ifdef FEAT_BROWSE
1540 char_u *title;
1541 char_u *initdir;
1542 char_u buf[NUMBUFLEN];
1543
1544 title = get_tv_string_chk(&argvars[0]);
1545 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1546
1547 if (title == NULL || initdir == NULL)
1548 rettv->vval.v_string = NULL;
1549 else
1550 rettv->vval.v_string = do_browse(BROWSE_DIR,
1551 title, NULL, NULL, initdir, NULL, curbuf);
1552#else
1553 rettv->vval.v_string = NULL;
1554#endif
1555 rettv->v_type = VAR_STRING;
1556}
1557
1558static buf_T *find_buffer(typval_T *avar);
1559
1560/*
1561 * Find a buffer by number or exact name.
1562 */
1563 static buf_T *
1564find_buffer(typval_T *avar)
1565{
1566 buf_T *buf = NULL;
1567
1568 if (avar->v_type == VAR_NUMBER)
1569 buf = buflist_findnr((int)avar->vval.v_number);
1570 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1571 {
1572 buf = buflist_findname_exp(avar->vval.v_string);
1573 if (buf == NULL)
1574 {
1575 /* No full path name match, try a match with a URL or a "nofile"
1576 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001577 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578 if (buf->b_fname != NULL
1579 && (path_with_url(buf->b_fname)
1580#ifdef FEAT_QUICKFIX
1581 || bt_nofile(buf)
1582#endif
1583 )
1584 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1585 break;
1586 }
1587 }
1588 return buf;
1589}
1590
1591/*
1592 * "bufexists(expr)" function
1593 */
1594 static void
1595f_bufexists(typval_T *argvars, typval_T *rettv)
1596{
1597 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1598}
1599
1600/*
1601 * "buflisted(expr)" function
1602 */
1603 static void
1604f_buflisted(typval_T *argvars, typval_T *rettv)
1605{
1606 buf_T *buf;
1607
1608 buf = find_buffer(&argvars[0]);
1609 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1610}
1611
1612/*
1613 * "bufloaded(expr)" function
1614 */
1615 static void
1616f_bufloaded(typval_T *argvars, typval_T *rettv)
1617{
1618 buf_T *buf;
1619
1620 buf = find_buffer(&argvars[0]);
1621 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1622}
1623
1624 buf_T *
1625buflist_find_by_name(char_u *name, int curtab_only)
1626{
1627 int save_magic;
1628 char_u *save_cpo;
1629 buf_T *buf;
1630
1631 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1632 save_magic = p_magic;
1633 p_magic = TRUE;
1634 save_cpo = p_cpo;
1635 p_cpo = (char_u *)"";
1636
1637 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1638 TRUE, FALSE, curtab_only));
1639
1640 p_magic = save_magic;
1641 p_cpo = save_cpo;
1642 return buf;
1643}
1644
1645/*
1646 * Get buffer by number or pattern.
1647 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001648 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649get_buf_tv(typval_T *tv, int curtab_only)
1650{
1651 char_u *name = tv->vval.v_string;
1652 buf_T *buf;
1653
1654 if (tv->v_type == VAR_NUMBER)
1655 return buflist_findnr((int)tv->vval.v_number);
1656 if (tv->v_type != VAR_STRING)
1657 return NULL;
1658 if (name == NULL || *name == NUL)
1659 return curbuf;
1660 if (name[0] == '$' && name[1] == NUL)
1661 return lastbuf;
1662
1663 buf = buflist_find_by_name(name, curtab_only);
1664
1665 /* If not found, try expanding the name, like done for bufexists(). */
1666 if (buf == NULL)
1667 buf = find_buffer(tv);
1668
1669 return buf;
1670}
1671
1672/*
1673 * "bufname(expr)" function
1674 */
1675 static void
1676f_bufname(typval_T *argvars, typval_T *rettv)
1677{
1678 buf_T *buf;
1679
1680 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1681 ++emsg_off;
1682 buf = get_buf_tv(&argvars[0], FALSE);
1683 rettv->v_type = VAR_STRING;
1684 if (buf != NULL && buf->b_fname != NULL)
1685 rettv->vval.v_string = vim_strsave(buf->b_fname);
1686 else
1687 rettv->vval.v_string = NULL;
1688 --emsg_off;
1689}
1690
1691/*
1692 * "bufnr(expr)" function
1693 */
1694 static void
1695f_bufnr(typval_T *argvars, typval_T *rettv)
1696{
1697 buf_T *buf;
1698 int error = FALSE;
1699 char_u *name;
1700
1701 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1702 ++emsg_off;
1703 buf = get_buf_tv(&argvars[0], FALSE);
1704 --emsg_off;
1705
1706 /* If the buffer isn't found and the second argument is not zero create a
1707 * new buffer. */
1708 if (buf == NULL
1709 && argvars[1].v_type != VAR_UNKNOWN
1710 && get_tv_number_chk(&argvars[1], &error) != 0
1711 && !error
1712 && (name = get_tv_string_chk(&argvars[0])) != NULL
1713 && !error)
1714 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1715
1716 if (buf != NULL)
1717 rettv->vval.v_number = buf->b_fnum;
1718 else
1719 rettv->vval.v_number = -1;
1720}
1721
1722 static void
1723buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1724{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 win_T *wp;
1726 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727 buf_T *buf;
1728
1729 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1730 ++emsg_off;
1731 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001732 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001733 {
1734 ++winnr;
1735 if (wp->w_buffer == buf)
1736 break;
1737 }
1738 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001739 --emsg_off;
1740}
1741
1742/*
1743 * "bufwinid(nr)" function
1744 */
1745 static void
1746f_bufwinid(typval_T *argvars, typval_T *rettv)
1747{
1748 buf_win_common(argvars, rettv, FALSE);
1749}
1750
1751/*
1752 * "bufwinnr(nr)" function
1753 */
1754 static void
1755f_bufwinnr(typval_T *argvars, typval_T *rettv)
1756{
1757 buf_win_common(argvars, rettv, TRUE);
1758}
1759
1760/*
1761 * "byte2line(byte)" function
1762 */
1763 static void
1764f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1765{
1766#ifndef FEAT_BYTEOFF
1767 rettv->vval.v_number = -1;
1768#else
1769 long boff = 0;
1770
1771 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1772 if (boff < 0)
1773 rettv->vval.v_number = -1;
1774 else
1775 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1776 (linenr_T)0, &boff);
1777#endif
1778}
1779
1780 static void
1781byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1782{
1783#ifdef FEAT_MBYTE
1784 char_u *t;
1785#endif
1786 char_u *str;
1787 varnumber_T idx;
1788
1789 str = get_tv_string_chk(&argvars[0]);
1790 idx = get_tv_number_chk(&argvars[1], NULL);
1791 rettv->vval.v_number = -1;
1792 if (str == NULL || idx < 0)
1793 return;
1794
1795#ifdef FEAT_MBYTE
1796 t = str;
1797 for ( ; idx > 0; idx--)
1798 {
1799 if (*t == NUL) /* EOL reached */
1800 return;
1801 if (enc_utf8 && comp)
1802 t += utf_ptr2len(t);
1803 else
1804 t += (*mb_ptr2len)(t);
1805 }
1806 rettv->vval.v_number = (varnumber_T)(t - str);
1807#else
1808 if ((size_t)idx <= STRLEN(str))
1809 rettv->vval.v_number = idx;
1810#endif
1811}
1812
1813/*
1814 * "byteidx()" function
1815 */
1816 static void
1817f_byteidx(typval_T *argvars, typval_T *rettv)
1818{
1819 byteidx(argvars, rettv, FALSE);
1820}
1821
1822/*
1823 * "byteidxcomp()" function
1824 */
1825 static void
1826f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1827{
1828 byteidx(argvars, rettv, TRUE);
1829}
1830
1831/*
1832 * "call(func, arglist [, dict])" function
1833 */
1834 static void
1835f_call(typval_T *argvars, typval_T *rettv)
1836{
1837 char_u *func;
1838 partial_T *partial = NULL;
1839 dict_T *selfdict = NULL;
1840
1841 if (argvars[1].v_type != VAR_LIST)
1842 {
1843 EMSG(_(e_listreq));
1844 return;
1845 }
1846 if (argvars[1].vval.v_list == NULL)
1847 return;
1848
1849 if (argvars[0].v_type == VAR_FUNC)
1850 func = argvars[0].vval.v_string;
1851 else if (argvars[0].v_type == VAR_PARTIAL)
1852 {
1853 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001854 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001855 }
1856 else
1857 func = get_tv_string(&argvars[0]);
1858 if (*func == NUL)
1859 return; /* type error or empty name */
1860
1861 if (argvars[2].v_type != VAR_UNKNOWN)
1862 {
1863 if (argvars[2].v_type != VAR_DICT)
1864 {
1865 EMSG(_(e_dictreq));
1866 return;
1867 }
1868 selfdict = argvars[2].vval.v_dict;
1869 }
1870
1871 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1872}
1873
1874#ifdef FEAT_FLOAT
1875/*
1876 * "ceil({float})" function
1877 */
1878 static void
1879f_ceil(typval_T *argvars, typval_T *rettv)
1880{
1881 float_T f = 0.0;
1882
1883 rettv->v_type = VAR_FLOAT;
1884 if (get_float_arg(argvars, &f) == OK)
1885 rettv->vval.v_float = ceil(f);
1886 else
1887 rettv->vval.v_float = 0.0;
1888}
1889#endif
1890
1891#ifdef FEAT_JOB_CHANNEL
1892/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001893 * "ch_canread()" function
1894 */
1895 static void
1896f_ch_canread(typval_T *argvars, typval_T *rettv)
1897{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001898 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001899
1900 rettv->vval.v_number = 0;
1901 if (channel != NULL)
1902 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1903 || channel_has_readahead(channel, PART_OUT)
1904 || channel_has_readahead(channel, PART_ERR);
1905}
1906
1907/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908 * "ch_close()" function
1909 */
1910 static void
1911f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1912{
1913 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1914
1915 if (channel != NULL)
1916 {
1917 channel_close(channel, FALSE);
1918 channel_clear(channel);
1919 }
1920}
1921
1922/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001923 * "ch_close()" function
1924 */
1925 static void
1926f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1927{
1928 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1929
1930 if (channel != NULL)
1931 channel_close_in(channel);
1932}
1933
1934/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935 * "ch_getbufnr()" function
1936 */
1937 static void
1938f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1939{
1940 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1941
1942 rettv->vval.v_number = -1;
1943 if (channel != NULL)
1944 {
1945 char_u *what = get_tv_string(&argvars[1]);
1946 int part;
1947
1948 if (STRCMP(what, "err") == 0)
1949 part = PART_ERR;
1950 else if (STRCMP(what, "out") == 0)
1951 part = PART_OUT;
1952 else if (STRCMP(what, "in") == 0)
1953 part = PART_IN;
1954 else
1955 part = PART_SOCK;
1956 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1957 rettv->vval.v_number =
1958 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1959 }
1960}
1961
1962/*
1963 * "ch_getjob()" function
1964 */
1965 static void
1966f_ch_getjob(typval_T *argvars, typval_T *rettv)
1967{
1968 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1969
1970 if (channel != NULL)
1971 {
1972 rettv->v_type = VAR_JOB;
1973 rettv->vval.v_job = channel->ch_job;
1974 if (channel->ch_job != NULL)
1975 ++channel->ch_job->jv_refcount;
1976 }
1977}
1978
1979/*
1980 * "ch_info()" function
1981 */
1982 static void
1983f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1984{
1985 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1986
1987 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1988 channel_info(channel, rettv->vval.v_dict);
1989}
1990
1991/*
1992 * "ch_log()" function
1993 */
1994 static void
1995f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1996{
1997 char_u *msg = get_tv_string(&argvars[0]);
1998 channel_T *channel = NULL;
1999
2000 if (argvars[1].v_type != VAR_UNKNOWN)
2001 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2002
Bram Moolenaard5359b22018-04-05 22:44:39 +02002003 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004}
2005
2006/*
2007 * "ch_logfile()" function
2008 */
2009 static void
2010f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2011{
2012 char_u *fname;
2013 char_u *opt = (char_u *)"";
2014 char_u buf[NUMBUFLEN];
2015
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002016 /* Don't open a file in restricted mode. */
2017 if (check_restricted() || check_secure())
2018 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 fname = get_tv_string(&argvars[0]);
2020 if (argvars[1].v_type == VAR_STRING)
2021 opt = get_tv_string_buf(&argvars[1], buf);
2022 ch_logfile(fname, opt);
2023}
2024
2025/*
2026 * "ch_open()" function
2027 */
2028 static void
2029f_ch_open(typval_T *argvars, typval_T *rettv)
2030{
2031 rettv->v_type = VAR_CHANNEL;
2032 if (check_restricted() || check_secure())
2033 return;
2034 rettv->vval.v_channel = channel_open_func(argvars);
2035}
2036
2037/*
2038 * "ch_read()" function
2039 */
2040 static void
2041f_ch_read(typval_T *argvars, typval_T *rettv)
2042{
2043 common_channel_read(argvars, rettv, FALSE);
2044}
2045
2046/*
2047 * "ch_readraw()" function
2048 */
2049 static void
2050f_ch_readraw(typval_T *argvars, typval_T *rettv)
2051{
2052 common_channel_read(argvars, rettv, TRUE);
2053}
2054
2055/*
2056 * "ch_evalexpr()" function
2057 */
2058 static void
2059f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2060{
2061 ch_expr_common(argvars, rettv, TRUE);
2062}
2063
2064/*
2065 * "ch_sendexpr()" function
2066 */
2067 static void
2068f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2069{
2070 ch_expr_common(argvars, rettv, FALSE);
2071}
2072
2073/*
2074 * "ch_evalraw()" function
2075 */
2076 static void
2077f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2078{
2079 ch_raw_common(argvars, rettv, TRUE);
2080}
2081
2082/*
2083 * "ch_sendraw()" function
2084 */
2085 static void
2086f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2087{
2088 ch_raw_common(argvars, rettv, FALSE);
2089}
2090
2091/*
2092 * "ch_setoptions()" function
2093 */
2094 static void
2095f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2096{
2097 channel_T *channel;
2098 jobopt_T opt;
2099
2100 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2101 if (channel == NULL)
2102 return;
2103 clear_job_options(&opt);
2104 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002105 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002106 channel_set_options(channel, &opt);
2107 free_job_options(&opt);
2108}
2109
2110/*
2111 * "ch_status()" function
2112 */
2113 static void
2114f_ch_status(typval_T *argvars, typval_T *rettv)
2115{
2116 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002117 jobopt_T opt;
2118 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002119
2120 /* return an empty string by default */
2121 rettv->v_type = VAR_STRING;
2122 rettv->vval.v_string = NULL;
2123
2124 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002125
2126 if (argvars[1].v_type != VAR_UNKNOWN)
2127 {
2128 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002129 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002130 && (opt.jo_set & JO_PART))
2131 part = opt.jo_part;
2132 }
2133
2134 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135}
2136#endif
2137
2138/*
2139 * "changenr()" function
2140 */
2141 static void
2142f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2143{
2144 rettv->vval.v_number = curbuf->b_u_seq_cur;
2145}
2146
2147/*
2148 * "char2nr(string)" function
2149 */
2150 static void
2151f_char2nr(typval_T *argvars, typval_T *rettv)
2152{
2153#ifdef FEAT_MBYTE
2154 if (has_mbyte)
2155 {
2156 int utf8 = 0;
2157
2158 if (argvars[1].v_type != VAR_UNKNOWN)
2159 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2160
2161 if (utf8)
2162 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2163 else
2164 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2165 }
2166 else
2167#endif
2168 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2169}
2170
2171/*
2172 * "cindent(lnum)" function
2173 */
2174 static void
2175f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2176{
2177#ifdef FEAT_CINDENT
2178 pos_T pos;
2179 linenr_T lnum;
2180
2181 pos = curwin->w_cursor;
2182 lnum = get_tv_lnum(argvars);
2183 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2184 {
2185 curwin->w_cursor.lnum = lnum;
2186 rettv->vval.v_number = get_c_indent();
2187 curwin->w_cursor = pos;
2188 }
2189 else
2190#endif
2191 rettv->vval.v_number = -1;
2192}
2193
2194/*
2195 * "clearmatches()" function
2196 */
2197 static void
2198f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2199{
2200#ifdef FEAT_SEARCH_EXTRA
2201 clear_matches(curwin);
2202#endif
2203}
2204
2205/*
2206 * "col(string)" function
2207 */
2208 static void
2209f_col(typval_T *argvars, typval_T *rettv)
2210{
2211 colnr_T col = 0;
2212 pos_T *fp;
2213 int fnum = curbuf->b_fnum;
2214
2215 fp = var2fpos(&argvars[0], FALSE, &fnum);
2216 if (fp != NULL && fnum == curbuf->b_fnum)
2217 {
2218 if (fp->col == MAXCOL)
2219 {
2220 /* '> can be MAXCOL, get the length of the line then */
2221 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2222 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2223 else
2224 col = MAXCOL;
2225 }
2226 else
2227 {
2228 col = fp->col + 1;
2229#ifdef FEAT_VIRTUALEDIT
2230 /* col(".") when the cursor is on the NUL at the end of the line
2231 * because of "coladd" can be seen as an extra column. */
2232 if (virtual_active() && fp == &curwin->w_cursor)
2233 {
2234 char_u *p = ml_get_cursor();
2235
2236 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2237 curwin->w_virtcol - curwin->w_cursor.coladd))
2238 {
2239# ifdef FEAT_MBYTE
2240 int l;
2241
2242 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2243 col += l;
2244# else
2245 if (*p != NUL && p[1] == NUL)
2246 ++col;
2247# endif
2248 }
2249 }
2250#endif
2251 }
2252 }
2253 rettv->vval.v_number = col;
2254}
2255
2256#if defined(FEAT_INS_EXPAND)
2257/*
2258 * "complete()" function
2259 */
2260 static void
2261f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2262{
2263 int startcol;
2264
2265 if ((State & INSERT) == 0)
2266 {
2267 EMSG(_("E785: complete() can only be used in Insert mode"));
2268 return;
2269 }
2270
2271 /* Check for undo allowed here, because if something was already inserted
2272 * the line was already saved for undo and this check isn't done. */
2273 if (!undo_allowed())
2274 return;
2275
2276 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2277 {
2278 EMSG(_(e_invarg));
2279 return;
2280 }
2281
2282 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2283 if (startcol <= 0)
2284 return;
2285
2286 set_completion(startcol - 1, argvars[1].vval.v_list);
2287}
2288
2289/*
2290 * "complete_add()" function
2291 */
2292 static void
2293f_complete_add(typval_T *argvars, typval_T *rettv)
2294{
2295 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2296}
2297
2298/*
2299 * "complete_check()" function
2300 */
2301 static void
2302f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2303{
2304 int saved = RedrawingDisabled;
2305
2306 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002307 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 rettv->vval.v_number = compl_interrupted;
2309 RedrawingDisabled = saved;
2310}
2311#endif
2312
2313/*
2314 * "confirm(message, buttons[, default [, type]])" function
2315 */
2316 static void
2317f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2318{
2319#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2320 char_u *message;
2321 char_u *buttons = NULL;
2322 char_u buf[NUMBUFLEN];
2323 char_u buf2[NUMBUFLEN];
2324 int def = 1;
2325 int type = VIM_GENERIC;
2326 char_u *typestr;
2327 int error = FALSE;
2328
2329 message = get_tv_string_chk(&argvars[0]);
2330 if (message == NULL)
2331 error = TRUE;
2332 if (argvars[1].v_type != VAR_UNKNOWN)
2333 {
2334 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2335 if (buttons == NULL)
2336 error = TRUE;
2337 if (argvars[2].v_type != VAR_UNKNOWN)
2338 {
2339 def = (int)get_tv_number_chk(&argvars[2], &error);
2340 if (argvars[3].v_type != VAR_UNKNOWN)
2341 {
2342 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2343 if (typestr == NULL)
2344 error = TRUE;
2345 else
2346 {
2347 switch (TOUPPER_ASC(*typestr))
2348 {
2349 case 'E': type = VIM_ERROR; break;
2350 case 'Q': type = VIM_QUESTION; break;
2351 case 'I': type = VIM_INFO; break;
2352 case 'W': type = VIM_WARNING; break;
2353 case 'G': type = VIM_GENERIC; break;
2354 }
2355 }
2356 }
2357 }
2358 }
2359
2360 if (buttons == NULL || *buttons == NUL)
2361 buttons = (char_u *)_("&Ok");
2362
2363 if (!error)
2364 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2365 def, NULL, FALSE);
2366#endif
2367}
2368
2369/*
2370 * "copy()" function
2371 */
2372 static void
2373f_copy(typval_T *argvars, typval_T *rettv)
2374{
2375 item_copy(&argvars[0], rettv, FALSE, 0);
2376}
2377
2378#ifdef FEAT_FLOAT
2379/*
2380 * "cos()" function
2381 */
2382 static void
2383f_cos(typval_T *argvars, typval_T *rettv)
2384{
2385 float_T f = 0.0;
2386
2387 rettv->v_type = VAR_FLOAT;
2388 if (get_float_arg(argvars, &f) == OK)
2389 rettv->vval.v_float = cos(f);
2390 else
2391 rettv->vval.v_float = 0.0;
2392}
2393
2394/*
2395 * "cosh()" function
2396 */
2397 static void
2398f_cosh(typval_T *argvars, typval_T *rettv)
2399{
2400 float_T f = 0.0;
2401
2402 rettv->v_type = VAR_FLOAT;
2403 if (get_float_arg(argvars, &f) == OK)
2404 rettv->vval.v_float = cosh(f);
2405 else
2406 rettv->vval.v_float = 0.0;
2407}
2408#endif
2409
2410/*
2411 * "count()" function
2412 */
2413 static void
2414f_count(typval_T *argvars, typval_T *rettv)
2415{
2416 long n = 0;
2417 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002418 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419
Bram Moolenaar9966b212017-07-28 16:46:57 +02002420 if (argvars[2].v_type != VAR_UNKNOWN)
2421 ic = (int)get_tv_number_chk(&argvars[2], &error);
2422
2423 if (argvars[0].v_type == VAR_STRING)
2424 {
2425 char_u *expr = get_tv_string_chk(&argvars[1]);
2426 char_u *p = argvars[0].vval.v_string;
2427 char_u *next;
2428
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002429 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002430 {
2431 if (ic)
2432 {
2433 size_t len = STRLEN(expr);
2434
2435 while (*p != NUL)
2436 {
2437 if (MB_STRNICMP(p, expr, len) == 0)
2438 {
2439 ++n;
2440 p += len;
2441 }
2442 else
2443 MB_PTR_ADV(p);
2444 }
2445 }
2446 else
2447 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2448 != NULL)
2449 {
2450 ++n;
2451 p = next + STRLEN(expr);
2452 }
2453 }
2454
2455 }
2456 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457 {
2458 listitem_T *li;
2459 list_T *l;
2460 long idx;
2461
2462 if ((l = argvars[0].vval.v_list) != NULL)
2463 {
2464 li = l->lv_first;
2465 if (argvars[2].v_type != VAR_UNKNOWN)
2466 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467 if (argvars[3].v_type != VAR_UNKNOWN)
2468 {
2469 idx = (long)get_tv_number_chk(&argvars[3], &error);
2470 if (!error)
2471 {
2472 li = list_find(l, idx);
2473 if (li == NULL)
2474 EMSGN(_(e_listidx), idx);
2475 }
2476 }
2477 if (error)
2478 li = NULL;
2479 }
2480
2481 for ( ; li != NULL; li = li->li_next)
2482 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2483 ++n;
2484 }
2485 }
2486 else if (argvars[0].v_type == VAR_DICT)
2487 {
2488 int todo;
2489 dict_T *d;
2490 hashitem_T *hi;
2491
2492 if ((d = argvars[0].vval.v_dict) != NULL)
2493 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002494 if (argvars[2].v_type != VAR_UNKNOWN)
2495 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496 if (argvars[3].v_type != VAR_UNKNOWN)
2497 EMSG(_(e_invarg));
2498 }
2499
2500 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2501 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2502 {
2503 if (!HASHITEM_EMPTY(hi))
2504 {
2505 --todo;
2506 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2507 ++n;
2508 }
2509 }
2510 }
2511 }
2512 else
2513 EMSG2(_(e_listdictarg), "count()");
2514 rettv->vval.v_number = n;
2515}
2516
2517/*
2518 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2519 *
2520 * Checks the existence of a cscope connection.
2521 */
2522 static void
2523f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2524{
2525#ifdef FEAT_CSCOPE
2526 int num = 0;
2527 char_u *dbpath = NULL;
2528 char_u *prepend = NULL;
2529 char_u buf[NUMBUFLEN];
2530
2531 if (argvars[0].v_type != VAR_UNKNOWN
2532 && argvars[1].v_type != VAR_UNKNOWN)
2533 {
2534 num = (int)get_tv_number(&argvars[0]);
2535 dbpath = get_tv_string(&argvars[1]);
2536 if (argvars[2].v_type != VAR_UNKNOWN)
2537 prepend = get_tv_string_buf(&argvars[2], buf);
2538 }
2539
2540 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2541#endif
2542}
2543
2544/*
2545 * "cursor(lnum, col)" function, or
2546 * "cursor(list)"
2547 *
2548 * Moves the cursor to the specified line and column.
2549 * Returns 0 when the position could be set, -1 otherwise.
2550 */
2551 static void
2552f_cursor(typval_T *argvars, typval_T *rettv)
2553{
2554 long line, col;
2555#ifdef FEAT_VIRTUALEDIT
2556 long coladd = 0;
2557#endif
2558 int set_curswant = TRUE;
2559
2560 rettv->vval.v_number = -1;
2561 if (argvars[1].v_type == VAR_UNKNOWN)
2562 {
2563 pos_T pos;
2564 colnr_T curswant = -1;
2565
2566 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2567 {
2568 EMSG(_(e_invarg));
2569 return;
2570 }
2571 line = pos.lnum;
2572 col = pos.col;
2573#ifdef FEAT_VIRTUALEDIT
2574 coladd = pos.coladd;
2575#endif
2576 if (curswant >= 0)
2577 {
2578 curwin->w_curswant = curswant - 1;
2579 set_curswant = FALSE;
2580 }
2581 }
2582 else
2583 {
2584 line = get_tv_lnum(argvars);
2585 col = (long)get_tv_number_chk(&argvars[1], NULL);
2586#ifdef FEAT_VIRTUALEDIT
2587 if (argvars[2].v_type != VAR_UNKNOWN)
2588 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2589#endif
2590 }
2591 if (line < 0 || col < 0
2592#ifdef FEAT_VIRTUALEDIT
2593 || coladd < 0
2594#endif
2595 )
2596 return; /* type error; errmsg already given */
2597 if (line > 0)
2598 curwin->w_cursor.lnum = line;
2599 if (col > 0)
2600 curwin->w_cursor.col = col - 1;
2601#ifdef FEAT_VIRTUALEDIT
2602 curwin->w_cursor.coladd = coladd;
2603#endif
2604
2605 /* Make sure the cursor is in a valid position. */
2606 check_cursor();
2607#ifdef FEAT_MBYTE
2608 /* Correct cursor for multi-byte character. */
2609 if (has_mbyte)
2610 mb_adjust_cursor();
2611#endif
2612
2613 curwin->w_set_curswant = set_curswant;
2614 rettv->vval.v_number = 0;
2615}
2616
2617/*
2618 * "deepcopy()" function
2619 */
2620 static void
2621f_deepcopy(typval_T *argvars, typval_T *rettv)
2622{
2623 int noref = 0;
2624 int copyID;
2625
2626 if (argvars[1].v_type != VAR_UNKNOWN)
2627 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2628 if (noref < 0 || noref > 1)
2629 EMSG(_(e_invarg));
2630 else
2631 {
2632 copyID = get_copyID();
2633 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2634 }
2635}
2636
2637/*
2638 * "delete()" function
2639 */
2640 static void
2641f_delete(typval_T *argvars, typval_T *rettv)
2642{
2643 char_u nbuf[NUMBUFLEN];
2644 char_u *name;
2645 char_u *flags;
2646
2647 rettv->vval.v_number = -1;
2648 if (check_restricted() || check_secure())
2649 return;
2650
2651 name = get_tv_string(&argvars[0]);
2652 if (name == NULL || *name == NUL)
2653 {
2654 EMSG(_(e_invarg));
2655 return;
2656 }
2657
2658 if (argvars[1].v_type != VAR_UNKNOWN)
2659 flags = get_tv_string_buf(&argvars[1], nbuf);
2660 else
2661 flags = (char_u *)"";
2662
2663 if (*flags == NUL)
2664 /* delete a file */
2665 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2666 else if (STRCMP(flags, "d") == 0)
2667 /* delete an empty directory */
2668 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2669 else if (STRCMP(flags, "rf") == 0)
2670 /* delete a directory recursively */
2671 rettv->vval.v_number = delete_recursive(name);
2672 else
2673 EMSG2(_(e_invexpr2), flags);
2674}
2675
2676/*
2677 * "did_filetype()" function
2678 */
2679 static void
2680f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2681{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002683}
2684
2685/*
2686 * "diff_filler()" function
2687 */
2688 static void
2689f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2690{
2691#ifdef FEAT_DIFF
2692 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2693#endif
2694}
2695
2696/*
2697 * "diff_hlID()" function
2698 */
2699 static void
2700f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2701{
2702#ifdef FEAT_DIFF
2703 linenr_T lnum = get_tv_lnum(argvars);
2704 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002705 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706 static int fnum = 0;
2707 static int change_start = 0;
2708 static int change_end = 0;
2709 static hlf_T hlID = (hlf_T)0;
2710 int filler_lines;
2711 int col;
2712
2713 if (lnum < 0) /* ignore type error in {lnum} arg */
2714 lnum = 0;
2715 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002716 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002717 || fnum != curbuf->b_fnum)
2718 {
2719 /* New line, buffer, change: need to get the values. */
2720 filler_lines = diff_check(curwin, lnum);
2721 if (filler_lines < 0)
2722 {
2723 if (filler_lines == -1)
2724 {
2725 change_start = MAXCOL;
2726 change_end = -1;
2727 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2728 hlID = HLF_ADD; /* added line */
2729 else
2730 hlID = HLF_CHD; /* changed line */
2731 }
2732 else
2733 hlID = HLF_ADD; /* added line */
2734 }
2735 else
2736 hlID = (hlf_T)0;
2737 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002738 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002739 fnum = curbuf->b_fnum;
2740 }
2741
2742 if (hlID == HLF_CHD || hlID == HLF_TXD)
2743 {
2744 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2745 if (col >= change_start && col <= change_end)
2746 hlID = HLF_TXD; /* changed text */
2747 else
2748 hlID = HLF_CHD; /* changed line */
2749 }
2750 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2751#endif
2752}
2753
2754/*
2755 * "empty({expr})" function
2756 */
2757 static void
2758f_empty(typval_T *argvars, typval_T *rettv)
2759{
2760 int n = FALSE;
2761
2762 switch (argvars[0].v_type)
2763 {
2764 case VAR_STRING:
2765 case VAR_FUNC:
2766 n = argvars[0].vval.v_string == NULL
2767 || *argvars[0].vval.v_string == NUL;
2768 break;
2769 case VAR_PARTIAL:
2770 n = FALSE;
2771 break;
2772 case VAR_NUMBER:
2773 n = argvars[0].vval.v_number == 0;
2774 break;
2775 case VAR_FLOAT:
2776#ifdef FEAT_FLOAT
2777 n = argvars[0].vval.v_float == 0.0;
2778 break;
2779#endif
2780 case VAR_LIST:
2781 n = argvars[0].vval.v_list == NULL
2782 || argvars[0].vval.v_list->lv_first == NULL;
2783 break;
2784 case VAR_DICT:
2785 n = argvars[0].vval.v_dict == NULL
2786 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2787 break;
2788 case VAR_SPECIAL:
2789 n = argvars[0].vval.v_number != VVAL_TRUE;
2790 break;
2791
2792 case VAR_JOB:
2793#ifdef FEAT_JOB_CHANNEL
2794 n = argvars[0].vval.v_job == NULL
2795 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2796 break;
2797#endif
2798 case VAR_CHANNEL:
2799#ifdef FEAT_JOB_CHANNEL
2800 n = argvars[0].vval.v_channel == NULL
2801 || !channel_is_open(argvars[0].vval.v_channel);
2802 break;
2803#endif
2804 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002805 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002806 n = TRUE;
2807 break;
2808 }
2809
2810 rettv->vval.v_number = n;
2811}
2812
2813/*
2814 * "escape({string}, {chars})" function
2815 */
2816 static void
2817f_escape(typval_T *argvars, typval_T *rettv)
2818{
2819 char_u buf[NUMBUFLEN];
2820
2821 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2822 get_tv_string_buf(&argvars[1], buf));
2823 rettv->v_type = VAR_STRING;
2824}
2825
2826/*
2827 * "eval()" function
2828 */
2829 static void
2830f_eval(typval_T *argvars, typval_T *rettv)
2831{
2832 char_u *s, *p;
2833
2834 s = get_tv_string_chk(&argvars[0]);
2835 if (s != NULL)
2836 s = skipwhite(s);
2837
2838 p = s;
2839 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2840 {
2841 if (p != NULL && !aborting())
2842 EMSG2(_(e_invexpr2), p);
2843 need_clr_eos = FALSE;
2844 rettv->v_type = VAR_NUMBER;
2845 rettv->vval.v_number = 0;
2846 }
2847 else if (*s != NUL)
2848 EMSG(_(e_trailing));
2849}
2850
2851/*
2852 * "eventhandler()" function
2853 */
2854 static void
2855f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2856{
2857 rettv->vval.v_number = vgetc_busy;
2858}
2859
2860/*
2861 * "executable()" function
2862 */
2863 static void
2864f_executable(typval_T *argvars, typval_T *rettv)
2865{
2866 char_u *name = get_tv_string(&argvars[0]);
2867
2868 /* Check in $PATH and also check directly if there is a directory name. */
2869 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2870 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2871}
2872
2873static garray_T redir_execute_ga;
2874
2875/*
2876 * Append "value[value_len]" to the execute() output.
2877 */
2878 void
2879execute_redir_str(char_u *value, int value_len)
2880{
2881 int len;
2882
2883 if (value_len == -1)
2884 len = (int)STRLEN(value); /* Append the entire string */
2885 else
2886 len = value_len; /* Append only "value_len" characters */
2887 if (ga_grow(&redir_execute_ga, len) == OK)
2888 {
2889 mch_memmove((char *)redir_execute_ga.ga_data
2890 + redir_execute_ga.ga_len, value, len);
2891 redir_execute_ga.ga_len += len;
2892 }
2893}
2894
2895/*
2896 * Get next line from a list.
2897 * Called by do_cmdline() to get the next line.
2898 * Returns allocated string, or NULL for end of function.
2899 */
2900
2901 static char_u *
2902get_list_line(
2903 int c UNUSED,
2904 void *cookie,
2905 int indent UNUSED)
2906{
2907 listitem_T **p = (listitem_T **)cookie;
2908 listitem_T *item = *p;
2909 char_u buf[NUMBUFLEN];
2910 char_u *s;
2911
2912 if (item == NULL)
2913 return NULL;
2914 s = get_tv_string_buf_chk(&item->li_tv, buf);
2915 *p = item->li_next;
2916 return s == NULL ? NULL : vim_strsave(s);
2917}
2918
2919/*
2920 * "execute()" function
2921 */
2922 static void
2923f_execute(typval_T *argvars, typval_T *rettv)
2924{
2925 char_u *cmd = NULL;
2926 list_T *list = NULL;
2927 int save_msg_silent = msg_silent;
2928 int save_emsg_silent = emsg_silent;
2929 int save_emsg_noredir = emsg_noredir;
2930 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002931 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002932 garray_T save_ga;
2933
2934 rettv->vval.v_string = NULL;
2935 rettv->v_type = VAR_STRING;
2936
2937 if (argvars[0].v_type == VAR_LIST)
2938 {
2939 list = argvars[0].vval.v_list;
2940 if (list == NULL || list->lv_first == NULL)
2941 /* empty list, no commands, empty output */
2942 return;
2943 ++list->lv_refcount;
2944 }
2945 else
2946 {
2947 cmd = get_tv_string_chk(&argvars[0]);
2948 if (cmd == NULL)
2949 return;
2950 }
2951
2952 if (argvars[1].v_type != VAR_UNKNOWN)
2953 {
2954 char_u buf[NUMBUFLEN];
2955 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2956
2957 if (s == NULL)
2958 return;
2959 if (STRNCMP(s, "silent", 6) == 0)
2960 ++msg_silent;
2961 if (STRCMP(s, "silent!") == 0)
2962 {
2963 emsg_silent = TRUE;
2964 emsg_noredir = TRUE;
2965 }
2966 }
2967 else
2968 ++msg_silent;
2969
2970 if (redir_execute)
2971 save_ga = redir_execute_ga;
2972 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2973 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002974 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975
2976 if (cmd != NULL)
2977 do_cmdline_cmd(cmd);
2978 else
2979 {
2980 listitem_T *item = list->lv_first;
2981
2982 do_cmdline(NULL, get_list_line, (void *)&item,
2983 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2984 --list->lv_refcount;
2985 }
2986
Bram Moolenaard297f352017-01-29 20:31:21 +01002987 /* Need to append a NUL to the result. */
2988 if (ga_grow(&redir_execute_ga, 1) == OK)
2989 {
2990 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2991 rettv->vval.v_string = redir_execute_ga.ga_data;
2992 }
2993 else
2994 {
2995 ga_clear(&redir_execute_ga);
2996 rettv->vval.v_string = NULL;
2997 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002998 msg_silent = save_msg_silent;
2999 emsg_silent = save_emsg_silent;
3000 emsg_noredir = save_emsg_noredir;
3001
3002 redir_execute = save_redir_execute;
3003 if (redir_execute)
3004 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003005 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006
3007 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3008 * line. Put it back in the first column. */
3009 msg_col = 0;
3010}
3011
3012/*
3013 * "exepath()" function
3014 */
3015 static void
3016f_exepath(typval_T *argvars, typval_T *rettv)
3017{
3018 char_u *p = NULL;
3019
3020 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3021 rettv->v_type = VAR_STRING;
3022 rettv->vval.v_string = p;
3023}
3024
3025/*
3026 * "exists()" function
3027 */
3028 static void
3029f_exists(typval_T *argvars, typval_T *rettv)
3030{
3031 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003032 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003033
3034 p = get_tv_string(&argvars[0]);
3035 if (*p == '$') /* environment variable */
3036 {
3037 /* first try "normal" environment variables (fast) */
3038 if (mch_getenv(p + 1) != NULL)
3039 n = TRUE;
3040 else
3041 {
3042 /* try expanding things like $VIM and ${HOME} */
3043 p = expand_env_save(p);
3044 if (p != NULL && *p != '$')
3045 n = TRUE;
3046 vim_free(p);
3047 }
3048 }
3049 else if (*p == '&' || *p == '+') /* option */
3050 {
3051 n = (get_option_tv(&p, NULL, TRUE) == OK);
3052 if (*skipwhite(p) != NUL)
3053 n = FALSE; /* trailing garbage */
3054 }
3055 else if (*p == '*') /* internal or user defined function */
3056 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003057 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 }
3059 else if (*p == ':')
3060 {
3061 n = cmd_exists(p + 1);
3062 }
3063 else if (*p == '#')
3064 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065 if (p[1] == '#')
3066 n = autocmd_supported(p + 2);
3067 else
3068 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003069 }
3070 else /* internal variable */
3071 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003072 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 }
3074
3075 rettv->vval.v_number = n;
3076}
3077
3078#ifdef FEAT_FLOAT
3079/*
3080 * "exp()" function
3081 */
3082 static void
3083f_exp(typval_T *argvars, typval_T *rettv)
3084{
3085 float_T f = 0.0;
3086
3087 rettv->v_type = VAR_FLOAT;
3088 if (get_float_arg(argvars, &f) == OK)
3089 rettv->vval.v_float = exp(f);
3090 else
3091 rettv->vval.v_float = 0.0;
3092}
3093#endif
3094
3095/*
3096 * "expand()" function
3097 */
3098 static void
3099f_expand(typval_T *argvars, typval_T *rettv)
3100{
3101 char_u *s;
3102 int len;
3103 char_u *errormsg;
3104 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3105 expand_T xpc;
3106 int error = FALSE;
3107 char_u *result;
3108
3109 rettv->v_type = VAR_STRING;
3110 if (argvars[1].v_type != VAR_UNKNOWN
3111 && argvars[2].v_type != VAR_UNKNOWN
3112 && get_tv_number_chk(&argvars[2], &error)
3113 && !error)
3114 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003115 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003116 }
3117
3118 s = get_tv_string(&argvars[0]);
3119 if (*s == '%' || *s == '#' || *s == '<')
3120 {
3121 ++emsg_off;
3122 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3123 --emsg_off;
3124 if (rettv->v_type == VAR_LIST)
3125 {
3126 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3127 list_append_string(rettv->vval.v_list, result, -1);
3128 else
3129 vim_free(result);
3130 }
3131 else
3132 rettv->vval.v_string = result;
3133 }
3134 else
3135 {
3136 /* When the optional second argument is non-zero, don't remove matches
3137 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3138 if (argvars[1].v_type != VAR_UNKNOWN
3139 && get_tv_number_chk(&argvars[1], &error))
3140 options |= WILD_KEEP_ALL;
3141 if (!error)
3142 {
3143 ExpandInit(&xpc);
3144 xpc.xp_context = EXPAND_FILES;
3145 if (p_wic)
3146 options += WILD_ICASE;
3147 if (rettv->v_type == VAR_STRING)
3148 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3149 options, WILD_ALL);
3150 else if (rettv_list_alloc(rettv) != FAIL)
3151 {
3152 int i;
3153
3154 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3155 for (i = 0; i < xpc.xp_numfiles; i++)
3156 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3157 ExpandCleanup(&xpc);
3158 }
3159 }
3160 else
3161 rettv->vval.v_string = NULL;
3162 }
3163}
3164
3165/*
3166 * "extend(list, list [, idx])" function
3167 * "extend(dict, dict [, action])" function
3168 */
3169 static void
3170f_extend(typval_T *argvars, typval_T *rettv)
3171{
3172 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3173
3174 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3175 {
3176 list_T *l1, *l2;
3177 listitem_T *item;
3178 long before;
3179 int error = FALSE;
3180
3181 l1 = argvars[0].vval.v_list;
3182 l2 = argvars[1].vval.v_list;
3183 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3184 && l2 != NULL)
3185 {
3186 if (argvars[2].v_type != VAR_UNKNOWN)
3187 {
3188 before = (long)get_tv_number_chk(&argvars[2], &error);
3189 if (error)
3190 return; /* type error; errmsg already given */
3191
3192 if (before == l1->lv_len)
3193 item = NULL;
3194 else
3195 {
3196 item = list_find(l1, before);
3197 if (item == NULL)
3198 {
3199 EMSGN(_(e_listidx), before);
3200 return;
3201 }
3202 }
3203 }
3204 else
3205 item = NULL;
3206 list_extend(l1, l2, item);
3207
3208 copy_tv(&argvars[0], rettv);
3209 }
3210 }
3211 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3212 {
3213 dict_T *d1, *d2;
3214 char_u *action;
3215 int i;
3216
3217 d1 = argvars[0].vval.v_dict;
3218 d2 = argvars[1].vval.v_dict;
3219 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3220 && d2 != NULL)
3221 {
3222 /* Check the third argument. */
3223 if (argvars[2].v_type != VAR_UNKNOWN)
3224 {
3225 static char *(av[]) = {"keep", "force", "error"};
3226
3227 action = get_tv_string_chk(&argvars[2]);
3228 if (action == NULL)
3229 return; /* type error; errmsg already given */
3230 for (i = 0; i < 3; ++i)
3231 if (STRCMP(action, av[i]) == 0)
3232 break;
3233 if (i == 3)
3234 {
3235 EMSG2(_(e_invarg2), action);
3236 return;
3237 }
3238 }
3239 else
3240 action = (char_u *)"force";
3241
3242 dict_extend(d1, d2, action);
3243
3244 copy_tv(&argvars[0], rettv);
3245 }
3246 }
3247 else
3248 EMSG2(_(e_listdictarg), "extend()");
3249}
3250
3251/*
3252 * "feedkeys()" function
3253 */
3254 static void
3255f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3256{
3257 int remap = TRUE;
3258 int insert = FALSE;
3259 char_u *keys, *flags;
3260 char_u nbuf[NUMBUFLEN];
3261 int typed = FALSE;
3262 int execute = FALSE;
3263 int dangerous = FALSE;
3264 char_u *keys_esc;
3265
3266 /* This is not allowed in the sandbox. If the commands would still be
3267 * executed in the sandbox it would be OK, but it probably happens later,
3268 * when "sandbox" is no longer set. */
3269 if (check_secure())
3270 return;
3271
3272 keys = get_tv_string(&argvars[0]);
3273
3274 if (argvars[1].v_type != VAR_UNKNOWN)
3275 {
3276 flags = get_tv_string_buf(&argvars[1], nbuf);
3277 for ( ; *flags != NUL; ++flags)
3278 {
3279 switch (*flags)
3280 {
3281 case 'n': remap = FALSE; break;
3282 case 'm': remap = TRUE; break;
3283 case 't': typed = TRUE; break;
3284 case 'i': insert = TRUE; break;
3285 case 'x': execute = TRUE; break;
3286 case '!': dangerous = TRUE; break;
3287 }
3288 }
3289 }
3290
3291 if (*keys != NUL || execute)
3292 {
3293 /* Need to escape K_SPECIAL and CSI before putting the string in the
3294 * typeahead buffer. */
3295 keys_esc = vim_strsave_escape_csi(keys);
3296 if (keys_esc != NULL)
3297 {
3298 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3299 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3300 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003301 if (vgetc_busy
3302#ifdef FEAT_TIMERS
3303 || timer_busy
3304#endif
3305 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003306 typebuf_was_filled = TRUE;
3307 if (execute)
3308 {
3309 int save_msg_scroll = msg_scroll;
3310
3311 /* Avoid a 1 second delay when the keys start Insert mode. */
3312 msg_scroll = FALSE;
3313
Bram Moolenaar69fbc9e2017-09-14 20:37:57 +02003314#ifdef FEAT_TERMINAL
3315 if (term_use_loop())
3316 terminal_loop(FALSE);
3317 else
3318#endif
3319 {
3320 if (!dangerous)
3321 ++ex_normal_busy;
3322 exec_normal(TRUE);
3323 if (!dangerous)
3324 --ex_normal_busy;
3325 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003326 msg_scroll |= save_msg_scroll;
3327 }
3328 }
3329 }
3330}
3331
3332/*
3333 * "filereadable()" function
3334 */
3335 static void
3336f_filereadable(typval_T *argvars, typval_T *rettv)
3337{
3338 int fd;
3339 char_u *p;
3340 int n;
3341
3342#ifndef O_NONBLOCK
3343# define O_NONBLOCK 0
3344#endif
3345 p = get_tv_string(&argvars[0]);
3346 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3347 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3348 {
3349 n = TRUE;
3350 close(fd);
3351 }
3352 else
3353 n = FALSE;
3354
3355 rettv->vval.v_number = n;
3356}
3357
3358/*
3359 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3360 * rights to write into.
3361 */
3362 static void
3363f_filewritable(typval_T *argvars, typval_T *rettv)
3364{
3365 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3366}
3367
3368 static void
3369findfilendir(
3370 typval_T *argvars UNUSED,
3371 typval_T *rettv,
3372 int find_what UNUSED)
3373{
3374#ifdef FEAT_SEARCHPATH
3375 char_u *fname;
3376 char_u *fresult = NULL;
3377 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3378 char_u *p;
3379 char_u pathbuf[NUMBUFLEN];
3380 int count = 1;
3381 int first = TRUE;
3382 int error = FALSE;
3383#endif
3384
3385 rettv->vval.v_string = NULL;
3386 rettv->v_type = VAR_STRING;
3387
3388#ifdef FEAT_SEARCHPATH
3389 fname = get_tv_string(&argvars[0]);
3390
3391 if (argvars[1].v_type != VAR_UNKNOWN)
3392 {
3393 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3394 if (p == NULL)
3395 error = TRUE;
3396 else
3397 {
3398 if (*p != NUL)
3399 path = p;
3400
3401 if (argvars[2].v_type != VAR_UNKNOWN)
3402 count = (int)get_tv_number_chk(&argvars[2], &error);
3403 }
3404 }
3405
3406 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3407 error = TRUE;
3408
3409 if (*fname != NUL && !error)
3410 {
3411 do
3412 {
3413 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3414 vim_free(fresult);
3415 fresult = find_file_in_path_option(first ? fname : NULL,
3416 first ? (int)STRLEN(fname) : 0,
3417 0, first, path,
3418 find_what,
3419 curbuf->b_ffname,
3420 find_what == FINDFILE_DIR
3421 ? (char_u *)"" : curbuf->b_p_sua);
3422 first = FALSE;
3423
3424 if (fresult != NULL && rettv->v_type == VAR_LIST)
3425 list_append_string(rettv->vval.v_list, fresult, -1);
3426
3427 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3428 }
3429
3430 if (rettv->v_type == VAR_STRING)
3431 rettv->vval.v_string = fresult;
3432#endif
3433}
3434
3435/*
3436 * "filter()" function
3437 */
3438 static void
3439f_filter(typval_T *argvars, typval_T *rettv)
3440{
3441 filter_map(argvars, rettv, FALSE);
3442}
3443
3444/*
3445 * "finddir({fname}[, {path}[, {count}]])" function
3446 */
3447 static void
3448f_finddir(typval_T *argvars, typval_T *rettv)
3449{
3450 findfilendir(argvars, rettv, FINDFILE_DIR);
3451}
3452
3453/*
3454 * "findfile({fname}[, {path}[, {count}]])" function
3455 */
3456 static void
3457f_findfile(typval_T *argvars, typval_T *rettv)
3458{
3459 findfilendir(argvars, rettv, FINDFILE_FILE);
3460}
3461
3462#ifdef FEAT_FLOAT
3463/*
3464 * "float2nr({float})" function
3465 */
3466 static void
3467f_float2nr(typval_T *argvars, typval_T *rettv)
3468{
3469 float_T f = 0.0;
3470
3471 if (get_float_arg(argvars, &f) == OK)
3472 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003473 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003474 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003475 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003476 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003477 else
3478 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003479 }
3480}
3481
3482/*
3483 * "floor({float})" function
3484 */
3485 static void
3486f_floor(typval_T *argvars, typval_T *rettv)
3487{
3488 float_T f = 0.0;
3489
3490 rettv->v_type = VAR_FLOAT;
3491 if (get_float_arg(argvars, &f) == OK)
3492 rettv->vval.v_float = floor(f);
3493 else
3494 rettv->vval.v_float = 0.0;
3495}
3496
3497/*
3498 * "fmod()" function
3499 */
3500 static void
3501f_fmod(typval_T *argvars, typval_T *rettv)
3502{
3503 float_T fx = 0.0, fy = 0.0;
3504
3505 rettv->v_type = VAR_FLOAT;
3506 if (get_float_arg(argvars, &fx) == OK
3507 && get_float_arg(&argvars[1], &fy) == OK)
3508 rettv->vval.v_float = fmod(fx, fy);
3509 else
3510 rettv->vval.v_float = 0.0;
3511}
3512#endif
3513
3514/*
3515 * "fnameescape({string})" function
3516 */
3517 static void
3518f_fnameescape(typval_T *argvars, typval_T *rettv)
3519{
3520 rettv->vval.v_string = vim_strsave_fnameescape(
3521 get_tv_string(&argvars[0]), FALSE);
3522 rettv->v_type = VAR_STRING;
3523}
3524
3525/*
3526 * "fnamemodify({fname}, {mods})" function
3527 */
3528 static void
3529f_fnamemodify(typval_T *argvars, typval_T *rettv)
3530{
3531 char_u *fname;
3532 char_u *mods;
3533 int usedlen = 0;
3534 int len;
3535 char_u *fbuf = NULL;
3536 char_u buf[NUMBUFLEN];
3537
3538 fname = get_tv_string_chk(&argvars[0]);
3539 mods = get_tv_string_buf_chk(&argvars[1], buf);
3540 if (fname == NULL || mods == NULL)
3541 fname = NULL;
3542 else
3543 {
3544 len = (int)STRLEN(fname);
3545 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3546 }
3547
3548 rettv->v_type = VAR_STRING;
3549 if (fname == NULL)
3550 rettv->vval.v_string = NULL;
3551 else
3552 rettv->vval.v_string = vim_strnsave(fname, len);
3553 vim_free(fbuf);
3554}
3555
3556static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3557
3558/*
3559 * "foldclosed()" function
3560 */
3561 static void
3562foldclosed_both(
3563 typval_T *argvars UNUSED,
3564 typval_T *rettv,
3565 int end UNUSED)
3566{
3567#ifdef FEAT_FOLDING
3568 linenr_T lnum;
3569 linenr_T first, last;
3570
3571 lnum = get_tv_lnum(argvars);
3572 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3573 {
3574 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3575 {
3576 if (end)
3577 rettv->vval.v_number = (varnumber_T)last;
3578 else
3579 rettv->vval.v_number = (varnumber_T)first;
3580 return;
3581 }
3582 }
3583#endif
3584 rettv->vval.v_number = -1;
3585}
3586
3587/*
3588 * "foldclosed()" function
3589 */
3590 static void
3591f_foldclosed(typval_T *argvars, typval_T *rettv)
3592{
3593 foldclosed_both(argvars, rettv, FALSE);
3594}
3595
3596/*
3597 * "foldclosedend()" function
3598 */
3599 static void
3600f_foldclosedend(typval_T *argvars, typval_T *rettv)
3601{
3602 foldclosed_both(argvars, rettv, TRUE);
3603}
3604
3605/*
3606 * "foldlevel()" function
3607 */
3608 static void
3609f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3610{
3611#ifdef FEAT_FOLDING
3612 linenr_T lnum;
3613
3614 lnum = get_tv_lnum(argvars);
3615 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3616 rettv->vval.v_number = foldLevel(lnum);
3617#endif
3618}
3619
3620/*
3621 * "foldtext()" function
3622 */
3623 static void
3624f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3625{
3626#ifdef FEAT_FOLDING
3627 linenr_T foldstart;
3628 linenr_T foldend;
3629 char_u *dashes;
3630 linenr_T lnum;
3631 char_u *s;
3632 char_u *r;
3633 int len;
3634 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003635 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636#endif
3637
3638 rettv->v_type = VAR_STRING;
3639 rettv->vval.v_string = NULL;
3640#ifdef FEAT_FOLDING
3641 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3642 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3643 dashes = get_vim_var_str(VV_FOLDDASHES);
3644 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3645 && dashes != NULL)
3646 {
3647 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003648 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649 if (!linewhite(lnum))
3650 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651
3652 /* Find interesting text in this line. */
3653 s = skipwhite(ml_get(lnum));
3654 /* skip C comment-start */
3655 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3656 {
3657 s = skipwhite(s + 2);
3658 if (*skipwhite(s) == NUL
3659 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3660 {
3661 s = skipwhite(ml_get(lnum + 1));
3662 if (*s == '*')
3663 s = skipwhite(s + 1);
3664 }
3665 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003666 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003667 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003668 r = alloc((unsigned)(STRLEN(txt)
3669 + STRLEN(dashes) /* for %s */
3670 + 20 /* for %3ld */
3671 + STRLEN(s))); /* concatenated */
3672 if (r != NULL)
3673 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003674 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003675 len = (int)STRLEN(r);
3676 STRCAT(r, s);
3677 /* remove 'foldmarker' and 'commentstring' */
3678 foldtext_cleanup(r + len);
3679 rettv->vval.v_string = r;
3680 }
3681 }
3682#endif
3683}
3684
3685/*
3686 * "foldtextresult(lnum)" function
3687 */
3688 static void
3689f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3690{
3691#ifdef FEAT_FOLDING
3692 linenr_T lnum;
3693 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003694 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003695 foldinfo_T foldinfo;
3696 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003697 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003698#endif
3699
3700 rettv->v_type = VAR_STRING;
3701 rettv->vval.v_string = NULL;
3702#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003703 if (entered)
3704 return; /* reject recursive use */
3705 entered = TRUE;
3706
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707 lnum = get_tv_lnum(argvars);
3708 /* treat illegal types and illegal string values for {lnum} the same */
3709 if (lnum < 0)
3710 lnum = 0;
3711 fold_count = foldedCount(curwin, lnum, &foldinfo);
3712 if (fold_count > 0)
3713 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003714 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3715 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003716 if (text == buf)
3717 text = vim_strsave(text);
3718 rettv->vval.v_string = text;
3719 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003720
3721 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722#endif
3723}
3724
3725/*
3726 * "foreground()" function
3727 */
3728 static void
3729f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3730{
3731#ifdef FEAT_GUI
3732 if (gui.in_use)
3733 gui_mch_set_foreground();
3734#else
3735# ifdef WIN32
3736 win32_set_foreground();
3737# endif
3738#endif
3739}
3740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003741 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003742common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003743{
3744 char_u *s;
3745 char_u *name;
3746 int use_string = FALSE;
3747 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003748 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003749
3750 if (argvars[0].v_type == VAR_FUNC)
3751 {
3752 /* function(MyFunc, [arg], dict) */
3753 s = argvars[0].vval.v_string;
3754 }
3755 else if (argvars[0].v_type == VAR_PARTIAL
3756 && argvars[0].vval.v_partial != NULL)
3757 {
3758 /* function(dict.MyFunc, [arg]) */
3759 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003760 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003761 }
3762 else
3763 {
3764 /* function('MyFunc', [arg], dict) */
3765 s = get_tv_string(&argvars[0]);
3766 use_string = TRUE;
3767 }
3768
Bram Moolenaar843b8842016-08-21 14:36:15 +02003769 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003770 {
3771 name = s;
3772 trans_name = trans_function_name(&name, FALSE,
3773 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3774 if (*name != NUL)
3775 s = NULL;
3776 }
3777
Bram Moolenaar843b8842016-08-21 14:36:15 +02003778 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3779 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003780 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003782 else if (trans_name != NULL && (is_funcref
3783 ? find_func(trans_name) == NULL
3784 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003785 EMSG2(_("E700: Unknown function: %s"), s);
3786 else
3787 {
3788 int dict_idx = 0;
3789 int arg_idx = 0;
3790 list_T *list = NULL;
3791
3792 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3793 {
3794 char sid_buf[25];
3795 int off = *s == 's' ? 2 : 5;
3796
3797 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3798 * also be called from another script. Using trans_function_name()
3799 * would also work, but some plugins depend on the name being
3800 * printable text. */
3801 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3802 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3803 if (name != NULL)
3804 {
3805 STRCPY(name, sid_buf);
3806 STRCAT(name, s + off);
3807 }
3808 }
3809 else
3810 name = vim_strsave(s);
3811
3812 if (argvars[1].v_type != VAR_UNKNOWN)
3813 {
3814 if (argvars[2].v_type != VAR_UNKNOWN)
3815 {
3816 /* function(name, [args], dict) */
3817 arg_idx = 1;
3818 dict_idx = 2;
3819 }
3820 else if (argvars[1].v_type == VAR_DICT)
3821 /* function(name, dict) */
3822 dict_idx = 1;
3823 else
3824 /* function(name, [args]) */
3825 arg_idx = 1;
3826 if (dict_idx > 0)
3827 {
3828 if (argvars[dict_idx].v_type != VAR_DICT)
3829 {
3830 EMSG(_("E922: expected a dict"));
3831 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003832 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003833 }
3834 if (argvars[dict_idx].vval.v_dict == NULL)
3835 dict_idx = 0;
3836 }
3837 if (arg_idx > 0)
3838 {
3839 if (argvars[arg_idx].v_type != VAR_LIST)
3840 {
3841 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3842 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003843 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003844 }
3845 list = argvars[arg_idx].vval.v_list;
3846 if (list == NULL || list->lv_len == 0)
3847 arg_idx = 0;
3848 }
3849 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003850 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003851 {
3852 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3853
3854 /* result is a VAR_PARTIAL */
3855 if (pt == NULL)
3856 vim_free(name);
3857 else
3858 {
3859 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3860 {
3861 listitem_T *li;
3862 int i = 0;
3863 int arg_len = 0;
3864 int lv_len = 0;
3865
3866 if (arg_pt != NULL)
3867 arg_len = arg_pt->pt_argc;
3868 if (list != NULL)
3869 lv_len = list->lv_len;
3870 pt->pt_argc = arg_len + lv_len;
3871 pt->pt_argv = (typval_T *)alloc(
3872 sizeof(typval_T) * pt->pt_argc);
3873 if (pt->pt_argv == NULL)
3874 {
3875 vim_free(pt);
3876 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003877 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003878 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003879 for (i = 0; i < arg_len; i++)
3880 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3881 if (lv_len > 0)
3882 for (li = list->lv_first; li != NULL;
3883 li = li->li_next)
3884 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003885 }
3886
3887 /* For "function(dict.func, [], dict)" and "func" is a partial
3888 * use "dict". That is backwards compatible. */
3889 if (dict_idx > 0)
3890 {
3891 /* The dict is bound explicitly, pt_auto is FALSE. */
3892 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3893 ++pt->pt_dict->dv_refcount;
3894 }
3895 else if (arg_pt != NULL)
3896 {
3897 /* If the dict was bound automatically the result is also
3898 * bound automatically. */
3899 pt->pt_dict = arg_pt->pt_dict;
3900 pt->pt_auto = arg_pt->pt_auto;
3901 if (pt->pt_dict != NULL)
3902 ++pt->pt_dict->dv_refcount;
3903 }
3904
3905 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003906 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3907 {
3908 pt->pt_func = arg_pt->pt_func;
3909 func_ptr_ref(pt->pt_func);
3910 vim_free(name);
3911 }
3912 else if (is_funcref)
3913 {
3914 pt->pt_func = find_func(trans_name);
3915 func_ptr_ref(pt->pt_func);
3916 vim_free(name);
3917 }
3918 else
3919 {
3920 pt->pt_name = name;
3921 func_ref(name);
3922 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923 }
3924 rettv->v_type = VAR_PARTIAL;
3925 rettv->vval.v_partial = pt;
3926 }
3927 else
3928 {
3929 /* result is a VAR_FUNC */
3930 rettv->v_type = VAR_FUNC;
3931 rettv->vval.v_string = name;
3932 func_ref(name);
3933 }
3934 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003935theend:
3936 vim_free(trans_name);
3937}
3938
3939/*
3940 * "funcref()" function
3941 */
3942 static void
3943f_funcref(typval_T *argvars, typval_T *rettv)
3944{
3945 common_function(argvars, rettv, TRUE);
3946}
3947
3948/*
3949 * "function()" function
3950 */
3951 static void
3952f_function(typval_T *argvars, typval_T *rettv)
3953{
3954 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003955}
3956
3957/*
3958 * "garbagecollect()" function
3959 */
3960 static void
3961f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3962{
3963 /* This is postponed until we are back at the toplevel, because we may be
3964 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3965 want_garbage_collect = TRUE;
3966
3967 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3968 garbage_collect_at_exit = TRUE;
3969}
3970
3971/*
3972 * "get()" function
3973 */
3974 static void
3975f_get(typval_T *argvars, typval_T *rettv)
3976{
3977 listitem_T *li;
3978 list_T *l;
3979 dictitem_T *di;
3980 dict_T *d;
3981 typval_T *tv = NULL;
3982
3983 if (argvars[0].v_type == VAR_LIST)
3984 {
3985 if ((l = argvars[0].vval.v_list) != NULL)
3986 {
3987 int error = FALSE;
3988
3989 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3990 if (!error && li != NULL)
3991 tv = &li->li_tv;
3992 }
3993 }
3994 else if (argvars[0].v_type == VAR_DICT)
3995 {
3996 if ((d = argvars[0].vval.v_dict) != NULL)
3997 {
3998 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3999 if (di != NULL)
4000 tv = &di->di_tv;
4001 }
4002 }
4003 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4004 {
4005 partial_T *pt;
4006 partial_T fref_pt;
4007
4008 if (argvars[0].v_type == VAR_PARTIAL)
4009 pt = argvars[0].vval.v_partial;
4010 else
4011 {
4012 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4013 fref_pt.pt_name = argvars[0].vval.v_string;
4014 pt = &fref_pt;
4015 }
4016
4017 if (pt != NULL)
4018 {
4019 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004020 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021
4022 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4023 {
4024 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004025 n = partial_name(pt);
4026 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004027 rettv->vval.v_string = NULL;
4028 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004029 {
4030 rettv->vval.v_string = vim_strsave(n);
4031 if (rettv->v_type == VAR_FUNC)
4032 func_ref(rettv->vval.v_string);
4033 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034 }
4035 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004036 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004037 else if (STRCMP(what, "args") == 0)
4038 {
4039 rettv->v_type = VAR_LIST;
4040 if (rettv_list_alloc(rettv) == OK)
4041 {
4042 int i;
4043
4044 for (i = 0; i < pt->pt_argc; ++i)
4045 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4046 }
4047 }
4048 else
4049 EMSG2(_(e_invarg2), what);
4050 return;
4051 }
4052 }
4053 else
4054 EMSG2(_(e_listdictarg), "get()");
4055
4056 if (tv == NULL)
4057 {
4058 if (argvars[2].v_type != VAR_UNKNOWN)
4059 copy_tv(&argvars[2], rettv);
4060 }
4061 else
4062 copy_tv(tv, rettv);
4063}
4064
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004065#ifdef FEAT_SIGNS
4066/*
4067 * Returns information about signs placed in a buffer as list of dicts.
4068 */
4069 static void
4070get_buffer_signs(buf_T *buf, list_T *l)
4071{
4072 signlist_T *sign;
4073
4074 for (sign = buf->b_signlist; sign; sign = sign->next)
4075 {
4076 dict_T *d = dict_alloc();
4077
4078 if (d != NULL)
4079 {
4080 dict_add_nr_str(d, "id", sign->id, NULL);
4081 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004082 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004083
4084 list_append_dict(l, d);
4085 }
4086 }
4087}
4088#endif
4089
4090/*
4091 * Returns buffer options, variables and other attributes in a dictionary.
4092 */
4093 static dict_T *
4094get_buffer_info(buf_T *buf)
4095{
4096 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004097 tabpage_T *tp;
4098 win_T *wp;
4099 list_T *windows;
4100
4101 dict = dict_alloc();
4102 if (dict == NULL)
4103 return NULL;
4104
Bram Moolenaar33928832016-08-18 21:22:04 +02004105 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004106 dict_add_nr_str(dict, "name", 0L,
4107 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004108 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4109 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004110 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4111 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4112 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004113 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004114 dict_add_nr_str(dict, "hidden",
4115 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4116 NULL);
4117
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004118 /* Get a reference to buffer variables */
4119 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004120
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004121 /* List of windows displaying this buffer */
4122 windows = list_alloc();
4123 if (windows != NULL)
4124 {
4125 FOR_ALL_TAB_WINDOWS(tp, wp)
4126 if (wp->w_buffer == buf)
4127 list_append_number(windows, (varnumber_T)wp->w_id);
4128 dict_add_list(dict, "windows", windows);
4129 }
4130
4131#ifdef FEAT_SIGNS
4132 if (buf->b_signlist != NULL)
4133 {
4134 /* List of signs placed in this buffer */
4135 list_T *signs = list_alloc();
4136 if (signs != NULL)
4137 {
4138 get_buffer_signs(buf, signs);
4139 dict_add_list(dict, "signs", signs);
4140 }
4141 }
4142#endif
4143
4144 return dict;
4145}
4146
4147/*
4148 * "getbufinfo()" function
4149 */
4150 static void
4151f_getbufinfo(typval_T *argvars, typval_T *rettv)
4152{
4153 buf_T *buf = NULL;
4154 buf_T *argbuf = NULL;
4155 dict_T *d;
4156 int filtered = FALSE;
4157 int sel_buflisted = FALSE;
4158 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004159 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004160
4161 if (rettv_list_alloc(rettv) != OK)
4162 return;
4163
4164 /* List of all the buffers or selected buffers */
4165 if (argvars[0].v_type == VAR_DICT)
4166 {
4167 dict_T *sel_d = argvars[0].vval.v_dict;
4168
4169 if (sel_d != NULL)
4170 {
4171 dictitem_T *di;
4172
4173 filtered = TRUE;
4174
4175 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4176 if (di != NULL && get_tv_number(&di->di_tv))
4177 sel_buflisted = TRUE;
4178
4179 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4180 if (di != NULL && get_tv_number(&di->di_tv))
4181 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004182
4183 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4184 if (di != NULL && get_tv_number(&di->di_tv))
4185 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004186 }
4187 }
4188 else if (argvars[0].v_type != VAR_UNKNOWN)
4189 {
4190 /* Information about one buffer. Argument specifies the buffer */
4191 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4192 ++emsg_off;
4193 argbuf = get_buf_tv(&argvars[0], FALSE);
4194 --emsg_off;
4195 if (argbuf == NULL)
4196 return;
4197 }
4198
4199 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004200 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004201 {
4202 if (argbuf != NULL && argbuf != buf)
4203 continue;
4204 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004205 || (sel_buflisted && !buf->b_p_bl)
4206 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004207 continue;
4208
4209 d = get_buffer_info(buf);
4210 if (d != NULL)
4211 list_append_dict(rettv->vval.v_list, d);
4212 if (argbuf != NULL)
4213 return;
4214 }
4215}
4216
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004217static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4218
4219/*
4220 * Get line or list of lines from buffer "buf" into "rettv".
4221 * Return a range (from start to end) of lines in rettv from the specified
4222 * buffer.
4223 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4224 */
4225 static void
4226get_buffer_lines(
4227 buf_T *buf,
4228 linenr_T start,
4229 linenr_T end,
4230 int retlist,
4231 typval_T *rettv)
4232{
4233 char_u *p;
4234
4235 rettv->v_type = VAR_STRING;
4236 rettv->vval.v_string = NULL;
4237 if (retlist && rettv_list_alloc(rettv) == FAIL)
4238 return;
4239
4240 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4241 return;
4242
4243 if (!retlist)
4244 {
4245 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4246 p = ml_get_buf(buf, start, FALSE);
4247 else
4248 p = (char_u *)"";
4249 rettv->vval.v_string = vim_strsave(p);
4250 }
4251 else
4252 {
4253 if (end < start)
4254 return;
4255
4256 if (start < 1)
4257 start = 1;
4258 if (end > buf->b_ml.ml_line_count)
4259 end = buf->b_ml.ml_line_count;
4260 while (start <= end)
4261 if (list_append_string(rettv->vval.v_list,
4262 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4263 break;
4264 }
4265}
4266
4267/*
4268 * Get the lnum from the first argument.
4269 * Also accepts "$", then "buf" is used.
4270 * Returns 0 on error.
4271 */
4272 static linenr_T
4273get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4274{
4275 if (argvars[0].v_type == VAR_STRING
4276 && argvars[0].vval.v_string != NULL
4277 && argvars[0].vval.v_string[0] == '$'
4278 && buf != NULL)
4279 return buf->b_ml.ml_line_count;
4280 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4281}
4282
4283/*
4284 * "getbufline()" function
4285 */
4286 static void
4287f_getbufline(typval_T *argvars, typval_T *rettv)
4288{
4289 linenr_T lnum;
4290 linenr_T end;
4291 buf_T *buf;
4292
4293 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4294 ++emsg_off;
4295 buf = get_buf_tv(&argvars[0], FALSE);
4296 --emsg_off;
4297
4298 lnum = get_tv_lnum_buf(&argvars[1], buf);
4299 if (argvars[2].v_type == VAR_UNKNOWN)
4300 end = lnum;
4301 else
4302 end = get_tv_lnum_buf(&argvars[2], buf);
4303
4304 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4305}
4306
4307/*
4308 * "getbufvar()" function
4309 */
4310 static void
4311f_getbufvar(typval_T *argvars, typval_T *rettv)
4312{
4313 buf_T *buf;
4314 buf_T *save_curbuf;
4315 char_u *varname;
4316 dictitem_T *v;
4317 int done = FALSE;
4318
4319 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4320 varname = get_tv_string_chk(&argvars[1]);
4321 ++emsg_off;
4322 buf = get_buf_tv(&argvars[0], FALSE);
4323
4324 rettv->v_type = VAR_STRING;
4325 rettv->vval.v_string = NULL;
4326
4327 if (buf != NULL && varname != NULL)
4328 {
4329 /* set curbuf to be our buf, temporarily */
4330 save_curbuf = curbuf;
4331 curbuf = buf;
4332
Bram Moolenaar30567352016-08-27 21:25:44 +02004333 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004334 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004335 if (varname[1] == NUL)
4336 {
4337 /* get all buffer-local options in a dict */
4338 dict_T *opts = get_winbuf_options(TRUE);
4339
4340 if (opts != NULL)
4341 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004342 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004343 done = TRUE;
4344 }
4345 }
4346 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4347 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004348 done = TRUE;
4349 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004350 else
4351 {
4352 /* Look up the variable. */
4353 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4354 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4355 'b', varname, FALSE);
4356 if (v != NULL)
4357 {
4358 copy_tv(&v->di_tv, rettv);
4359 done = TRUE;
4360 }
4361 }
4362
4363 /* restore previous notion of curbuf */
4364 curbuf = save_curbuf;
4365 }
4366
4367 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4368 /* use the default value */
4369 copy_tv(&argvars[2], rettv);
4370
4371 --emsg_off;
4372}
4373
4374/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004375 * "getchangelist()" function
4376 */
4377 static void
4378f_getchangelist(typval_T *argvars, typval_T *rettv)
4379{
4380#ifdef FEAT_JUMPLIST
4381 buf_T *buf;
4382 int i;
4383 list_T *l;
4384 dict_T *d;
4385#endif
4386
4387 if (rettv_list_alloc(rettv) != OK)
4388 return;
4389
4390#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004391 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4392 ++emsg_off;
4393 buf = get_buf_tv(&argvars[0], FALSE);
4394 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004395 if (buf == NULL)
4396 return;
4397
4398 l = list_alloc();
4399 if (l == NULL)
4400 return;
4401
4402 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4403 return;
4404 /*
4405 * The current window change list index tracks only the position in the
4406 * current buffer change list. For other buffers, use the change list
4407 * length as the current index.
4408 */
4409 list_append_number(rettv->vval.v_list,
4410 (varnumber_T)((buf == curwin->w_buffer)
4411 ? curwin->w_changelistidx : buf->b_changelistlen));
4412
4413 for (i = 0; i < buf->b_changelistlen; ++i)
4414 {
4415 if (buf->b_changelist[i].lnum == 0)
4416 continue;
4417 if ((d = dict_alloc()) == NULL)
4418 return;
4419 if (list_append_dict(l, d) == FAIL)
4420 return;
4421 dict_add_nr_str(d, "lnum", (long)buf->b_changelist[i].lnum, NULL);
4422 dict_add_nr_str(d, "col", (long)buf->b_changelist[i].col, NULL);
4423# ifdef FEAT_VIRTUALEDIT
4424 dict_add_nr_str(d, "coladd", (long)buf->b_changelist[i].coladd, NULL);
4425# endif
4426 }
4427#endif
4428}
4429/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004430 * "getchar()" function
4431 */
4432 static void
4433f_getchar(typval_T *argvars, typval_T *rettv)
4434{
4435 varnumber_T n;
4436 int error = FALSE;
4437
4438 /* Position the cursor. Needed after a message that ends in a space. */
4439 windgoto(msg_row, msg_col);
4440
4441 ++no_mapping;
4442 ++allow_keys;
4443 for (;;)
4444 {
4445 if (argvars[0].v_type == VAR_UNKNOWN)
4446 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004447 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4449 /* getchar(1): only check if char avail */
4450 n = vpeekc_any();
4451 else if (error || vpeekc_any() == NUL)
4452 /* illegal argument or getchar(0) and no char avail: return zero */
4453 n = 0;
4454 else
4455 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004456 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457
4458 if (n == K_IGNORE)
4459 continue;
4460 break;
4461 }
4462 --no_mapping;
4463 --allow_keys;
4464
4465 set_vim_var_nr(VV_MOUSE_WIN, 0);
4466 set_vim_var_nr(VV_MOUSE_WINID, 0);
4467 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4468 set_vim_var_nr(VV_MOUSE_COL, 0);
4469
4470 rettv->vval.v_number = n;
4471 if (IS_SPECIAL(n) || mod_mask != 0)
4472 {
4473 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4474 int i = 0;
4475
4476 /* Turn a special key into three bytes, plus modifier. */
4477 if (mod_mask != 0)
4478 {
4479 temp[i++] = K_SPECIAL;
4480 temp[i++] = KS_MODIFIER;
4481 temp[i++] = mod_mask;
4482 }
4483 if (IS_SPECIAL(n))
4484 {
4485 temp[i++] = K_SPECIAL;
4486 temp[i++] = K_SECOND(n);
4487 temp[i++] = K_THIRD(n);
4488 }
4489#ifdef FEAT_MBYTE
4490 else if (has_mbyte)
4491 i += (*mb_char2bytes)(n, temp + i);
4492#endif
4493 else
4494 temp[i++] = n;
4495 temp[i++] = NUL;
4496 rettv->v_type = VAR_STRING;
4497 rettv->vval.v_string = vim_strsave(temp);
4498
4499#ifdef FEAT_MOUSE
4500 if (is_mouse_key(n))
4501 {
4502 int row = mouse_row;
4503 int col = mouse_col;
4504 win_T *win;
4505 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004506 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 int winnr = 1;
4508
4509 if (row >= 0 && col >= 0)
4510 {
4511 /* Find the window at the mouse coordinates and compute the
4512 * text position. */
4513 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004514 if (win == NULL)
4515 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004516 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517 for (wp = firstwin; wp != win; wp = wp->w_next)
4518 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4520 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4521 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4522 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4523 }
4524 }
4525#endif
4526 }
4527}
4528
4529/*
4530 * "getcharmod()" function
4531 */
4532 static void
4533f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4534{
4535 rettv->vval.v_number = mod_mask;
4536}
4537
4538/*
4539 * "getcharsearch()" function
4540 */
4541 static void
4542f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4543{
4544 if (rettv_dict_alloc(rettv) != FAIL)
4545 {
4546 dict_T *dict = rettv->vval.v_dict;
4547
4548 dict_add_nr_str(dict, "char", 0L, last_csearch());
4549 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4550 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4551 }
4552}
4553
4554/*
4555 * "getcmdline()" function
4556 */
4557 static void
4558f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4559{
4560 rettv->v_type = VAR_STRING;
4561 rettv->vval.v_string = get_cmdline_str();
4562}
4563
4564/*
4565 * "getcmdpos()" function
4566 */
4567 static void
4568f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4569{
4570 rettv->vval.v_number = get_cmdline_pos() + 1;
4571}
4572
4573/*
4574 * "getcmdtype()" function
4575 */
4576 static void
4577f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4578{
4579 rettv->v_type = VAR_STRING;
4580 rettv->vval.v_string = alloc(2);
4581 if (rettv->vval.v_string != NULL)
4582 {
4583 rettv->vval.v_string[0] = get_cmdline_type();
4584 rettv->vval.v_string[1] = NUL;
4585 }
4586}
4587
4588/*
4589 * "getcmdwintype()" function
4590 */
4591 static void
4592f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4593{
4594 rettv->v_type = VAR_STRING;
4595 rettv->vval.v_string = NULL;
4596#ifdef FEAT_CMDWIN
4597 rettv->vval.v_string = alloc(2);
4598 if (rettv->vval.v_string != NULL)
4599 {
4600 rettv->vval.v_string[0] = cmdwin_type;
4601 rettv->vval.v_string[1] = NUL;
4602 }
4603#endif
4604}
4605
4606#if defined(FEAT_CMDL_COMPL)
4607/*
4608 * "getcompletion()" function
4609 */
4610 static void
4611f_getcompletion(typval_T *argvars, typval_T *rettv)
4612{
4613 char_u *pat;
4614 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004615 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004616 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4617 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004618
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004619 if (argvars[2].v_type != VAR_UNKNOWN)
4620 filtered = get_tv_number_chk(&argvars[2], NULL);
4621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622 if (p_wic)
4623 options |= WILD_ICASE;
4624
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004625 /* For filtered results, 'wildignore' is used */
4626 if (!filtered)
4627 options |= WILD_KEEP_ALL;
4628
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004629 ExpandInit(&xpc);
4630 xpc.xp_pattern = get_tv_string(&argvars[0]);
4631 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4632 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4633 if (xpc.xp_context == EXPAND_NOTHING)
4634 {
4635 if (argvars[1].v_type == VAR_STRING)
4636 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4637 else
4638 EMSG(_(e_invarg));
4639 return;
4640 }
4641
4642# if defined(FEAT_MENU)
4643 if (xpc.xp_context == EXPAND_MENUS)
4644 {
4645 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4646 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4647 }
4648# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004649#ifdef FEAT_CSCOPE
4650 if (xpc.xp_context == EXPAND_CSCOPE)
4651 {
4652 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4653 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4654 }
4655#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004656#ifdef FEAT_SIGNS
4657 if (xpc.xp_context == EXPAND_SIGN)
4658 {
4659 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4660 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4661 }
4662#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663
4664 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4665 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4666 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004667 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004668
4669 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4670
4671 for (i = 0; i < xpc.xp_numfiles; i++)
4672 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4673 }
4674 vim_free(pat);
4675 ExpandCleanup(&xpc);
4676}
4677#endif
4678
4679/*
4680 * "getcwd()" function
4681 */
4682 static void
4683f_getcwd(typval_T *argvars, typval_T *rettv)
4684{
4685 win_T *wp = NULL;
4686 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004687 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004688
4689 rettv->v_type = VAR_STRING;
4690 rettv->vval.v_string = NULL;
4691
Bram Moolenaar54591292018-02-09 20:53:59 +01004692 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4693 global = TRUE;
4694 else
4695 wp = find_tabwin(&argvars[0], &argvars[1]);
4696
4697 if (wp != NULL && wp->w_localdir != NULL)
4698 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4699 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004701 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702 rettv->vval.v_string = vim_strsave(globaldir);
4703 else
4704 {
4705 cwd = alloc(MAXPATHL);
4706 if (cwd != NULL)
4707 {
4708 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4709 rettv->vval.v_string = vim_strsave(cwd);
4710 vim_free(cwd);
4711 }
4712 }
4713#ifdef BACKSLASH_IN_FILENAME
4714 if (rettv->vval.v_string != NULL)
4715 slash_adjust(rettv->vval.v_string);
4716#endif
4717 }
4718}
4719
4720/*
4721 * "getfontname()" function
4722 */
4723 static void
4724f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4725{
4726 rettv->v_type = VAR_STRING;
4727 rettv->vval.v_string = NULL;
4728#ifdef FEAT_GUI
4729 if (gui.in_use)
4730 {
4731 GuiFont font;
4732 char_u *name = NULL;
4733
4734 if (argvars[0].v_type == VAR_UNKNOWN)
4735 {
4736 /* Get the "Normal" font. Either the name saved by
4737 * hl_set_font_name() or from the font ID. */
4738 font = gui.norm_font;
4739 name = hl_get_font_name();
4740 }
4741 else
4742 {
4743 name = get_tv_string(&argvars[0]);
4744 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4745 return;
4746 font = gui_mch_get_font(name, FALSE);
4747 if (font == NOFONT)
4748 return; /* Invalid font name, return empty string. */
4749 }
4750 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4751 if (argvars[0].v_type != VAR_UNKNOWN)
4752 gui_mch_free_font(font);
4753 }
4754#endif
4755}
4756
4757/*
4758 * "getfperm({fname})" function
4759 */
4760 static void
4761f_getfperm(typval_T *argvars, typval_T *rettv)
4762{
4763 char_u *fname;
4764 stat_T st;
4765 char_u *perm = NULL;
4766 char_u flags[] = "rwx";
4767 int i;
4768
4769 fname = get_tv_string(&argvars[0]);
4770
4771 rettv->v_type = VAR_STRING;
4772 if (mch_stat((char *)fname, &st) >= 0)
4773 {
4774 perm = vim_strsave((char_u *)"---------");
4775 if (perm != NULL)
4776 {
4777 for (i = 0; i < 9; i++)
4778 {
4779 if (st.st_mode & (1 << (8 - i)))
4780 perm[i] = flags[i % 3];
4781 }
4782 }
4783 }
4784 rettv->vval.v_string = perm;
4785}
4786
4787/*
4788 * "getfsize({fname})" function
4789 */
4790 static void
4791f_getfsize(typval_T *argvars, typval_T *rettv)
4792{
4793 char_u *fname;
4794 stat_T st;
4795
4796 fname = get_tv_string(&argvars[0]);
4797
4798 rettv->v_type = VAR_NUMBER;
4799
4800 if (mch_stat((char *)fname, &st) >= 0)
4801 {
4802 if (mch_isdir(fname))
4803 rettv->vval.v_number = 0;
4804 else
4805 {
4806 rettv->vval.v_number = (varnumber_T)st.st_size;
4807
4808 /* non-perfect check for overflow */
4809 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4810 rettv->vval.v_number = -2;
4811 }
4812 }
4813 else
4814 rettv->vval.v_number = -1;
4815}
4816
4817/*
4818 * "getftime({fname})" function
4819 */
4820 static void
4821f_getftime(typval_T *argvars, typval_T *rettv)
4822{
4823 char_u *fname;
4824 stat_T st;
4825
4826 fname = get_tv_string(&argvars[0]);
4827
4828 if (mch_stat((char *)fname, &st) >= 0)
4829 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4830 else
4831 rettv->vval.v_number = -1;
4832}
4833
4834/*
4835 * "getftype({fname})" function
4836 */
4837 static void
4838f_getftype(typval_T *argvars, typval_T *rettv)
4839{
4840 char_u *fname;
4841 stat_T st;
4842 char_u *type = NULL;
4843 char *t;
4844
4845 fname = get_tv_string(&argvars[0]);
4846
4847 rettv->v_type = VAR_STRING;
4848 if (mch_lstat((char *)fname, &st) >= 0)
4849 {
4850#ifdef S_ISREG
4851 if (S_ISREG(st.st_mode))
4852 t = "file";
4853 else if (S_ISDIR(st.st_mode))
4854 t = "dir";
4855# ifdef S_ISLNK
4856 else if (S_ISLNK(st.st_mode))
4857 t = "link";
4858# endif
4859# ifdef S_ISBLK
4860 else if (S_ISBLK(st.st_mode))
4861 t = "bdev";
4862# endif
4863# ifdef S_ISCHR
4864 else if (S_ISCHR(st.st_mode))
4865 t = "cdev";
4866# endif
4867# ifdef S_ISFIFO
4868 else if (S_ISFIFO(st.st_mode))
4869 t = "fifo";
4870# endif
4871# ifdef S_ISSOCK
4872 else if (S_ISSOCK(st.st_mode))
4873 t = "fifo";
4874# endif
4875 else
4876 t = "other";
4877#else
4878# ifdef S_IFMT
4879 switch (st.st_mode & S_IFMT)
4880 {
4881 case S_IFREG: t = "file"; break;
4882 case S_IFDIR: t = "dir"; break;
4883# ifdef S_IFLNK
4884 case S_IFLNK: t = "link"; break;
4885# endif
4886# ifdef S_IFBLK
4887 case S_IFBLK: t = "bdev"; break;
4888# endif
4889# ifdef S_IFCHR
4890 case S_IFCHR: t = "cdev"; break;
4891# endif
4892# ifdef S_IFIFO
4893 case S_IFIFO: t = "fifo"; break;
4894# endif
4895# ifdef S_IFSOCK
4896 case S_IFSOCK: t = "socket"; break;
4897# endif
4898 default: t = "other";
4899 }
4900# else
4901 if (mch_isdir(fname))
4902 t = "dir";
4903 else
4904 t = "file";
4905# endif
4906#endif
4907 type = vim_strsave((char_u *)t);
4908 }
4909 rettv->vval.v_string = type;
4910}
4911
4912/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004913 * "getjumplist()" function
4914 */
4915 static void
4916f_getjumplist(typval_T *argvars, typval_T *rettv)
4917{
4918#ifdef FEAT_JUMPLIST
4919 win_T *wp;
4920 int i;
4921 list_T *l;
4922 dict_T *d;
4923#endif
4924
4925 if (rettv_list_alloc(rettv) != OK)
4926 return;
4927
4928#ifdef FEAT_JUMPLIST
4929 wp = find_tabwin(&argvars[0], &argvars[1]);
4930 if (wp == NULL)
4931 return;
4932
4933 l = list_alloc();
4934 if (l == NULL)
4935 return;
4936
4937 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4938 return;
4939 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4940
Bram Moolenaar48679742018-02-13 13:33:29 +01004941 cleanup_jumplist(wp, TRUE);
4942
Bram Moolenaar4f505882018-02-10 21:06:32 +01004943 for (i = 0; i < wp->w_jumplistlen; ++i)
4944 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004945 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4946 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004947 if ((d = dict_alloc()) == NULL)
4948 return;
4949 if (list_append_dict(l, d) == FAIL)
4950 return;
4951 dict_add_nr_str(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum,
4952 NULL);
4953 dict_add_nr_str(d, "col", (long)wp->w_jumplist[i].fmark.mark.col,
4954 NULL);
4955# ifdef FEAT_VIRTUALEDIT
4956 dict_add_nr_str(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd,
4957 NULL);
4958# endif
4959 dict_add_nr_str(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum, NULL);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004960 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaar4f505882018-02-10 21:06:32 +01004961 dict_add_nr_str(d, "filename", 0L, wp->w_jumplist[i].fname);
4962 }
4963#endif
4964}
4965
4966/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004967 * "getline(lnum, [end])" function
4968 */
4969 static void
4970f_getline(typval_T *argvars, typval_T *rettv)
4971{
4972 linenr_T lnum;
4973 linenr_T end;
4974 int retlist;
4975
4976 lnum = get_tv_lnum(argvars);
4977 if (argvars[1].v_type == VAR_UNKNOWN)
4978 {
4979 end = 0;
4980 retlist = FALSE;
4981 }
4982 else
4983 {
4984 end = get_tv_lnum(&argvars[1]);
4985 retlist = TRUE;
4986 }
4987
4988 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4989}
4990
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004991#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004992 static void
4993get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4994{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004995 if (what_arg->v_type == VAR_UNKNOWN)
4996 {
4997 if (rettv_list_alloc(rettv) == OK)
4998 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004999 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005000 }
5001 else
5002 {
5003 if (rettv_dict_alloc(rettv) == OK)
5004 if (is_qf || (wp != NULL))
5005 {
5006 if (what_arg->v_type == VAR_DICT)
5007 {
5008 dict_T *d = what_arg->vval.v_dict;
5009
5010 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005011 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005012 }
5013 else
5014 EMSG(_(e_dictreq));
5015 }
5016 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005017}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005018#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005019
5020/*
5021 * "getloclist()" function
5022 */
5023 static void
5024f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5025{
5026#ifdef FEAT_QUICKFIX
5027 win_T *wp;
5028
5029 wp = find_win_by_nr(&argvars[0], NULL);
5030 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5031#endif
5032}
5033
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034/*
5035 * "getmatches()" function
5036 */
5037 static void
5038f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5039{
5040#ifdef FEAT_SEARCH_EXTRA
5041 dict_T *dict;
5042 matchitem_T *cur = curwin->w_match_head;
5043 int i;
5044
5045 if (rettv_list_alloc(rettv) == OK)
5046 {
5047 while (cur != NULL)
5048 {
5049 dict = dict_alloc();
5050 if (dict == NULL)
5051 return;
5052 if (cur->match.regprog == NULL)
5053 {
5054 /* match added with matchaddpos() */
5055 for (i = 0; i < MAXPOSMATCH; ++i)
5056 {
5057 llpos_T *llpos;
5058 char buf[6];
5059 list_T *l;
5060
5061 llpos = &cur->pos.pos[i];
5062 if (llpos->lnum == 0)
5063 break;
5064 l = list_alloc();
5065 if (l == NULL)
5066 break;
5067 list_append_number(l, (varnumber_T)llpos->lnum);
5068 if (llpos->col > 0)
5069 {
5070 list_append_number(l, (varnumber_T)llpos->col);
5071 list_append_number(l, (varnumber_T)llpos->len);
5072 }
5073 sprintf(buf, "pos%d", i + 1);
5074 dict_add_list(dict, buf, l);
5075 }
5076 }
5077 else
5078 {
5079 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
5080 }
5081 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
5082 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
5083 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
5084# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5085 if (cur->conceal_char)
5086 {
5087 char_u buf[MB_MAXBYTES + 1];
5088
5089 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5090 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
5091 }
5092# endif
5093 list_append_dict(rettv->vval.v_list, dict);
5094 cur = cur->next;
5095 }
5096 }
5097#endif
5098}
5099
5100/*
5101 * "getpid()" function
5102 */
5103 static void
5104f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5105{
5106 rettv->vval.v_number = mch_get_pid();
5107}
5108
5109 static void
5110getpos_both(
5111 typval_T *argvars,
5112 typval_T *rettv,
5113 int getcurpos)
5114{
5115 pos_T *fp;
5116 list_T *l;
5117 int fnum = -1;
5118
5119 if (rettv_list_alloc(rettv) == OK)
5120 {
5121 l = rettv->vval.v_list;
5122 if (getcurpos)
5123 fp = &curwin->w_cursor;
5124 else
5125 fp = var2fpos(&argvars[0], TRUE, &fnum);
5126 if (fnum != -1)
5127 list_append_number(l, (varnumber_T)fnum);
5128 else
5129 list_append_number(l, (varnumber_T)0);
5130 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5131 : (varnumber_T)0);
5132 list_append_number(l, (fp != NULL)
5133 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5134 : (varnumber_T)0);
5135 list_append_number(l,
5136#ifdef FEAT_VIRTUALEDIT
5137 (fp != NULL) ? (varnumber_T)fp->coladd :
5138#endif
5139 (varnumber_T)0);
5140 if (getcurpos)
5141 {
5142 update_curswant();
5143 list_append_number(l, curwin->w_curswant == MAXCOL ?
5144 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5145 }
5146 }
5147 else
5148 rettv->vval.v_number = FALSE;
5149}
5150
5151
5152/*
5153 * "getcurpos()" function
5154 */
5155 static void
5156f_getcurpos(typval_T *argvars, typval_T *rettv)
5157{
5158 getpos_both(argvars, rettv, TRUE);
5159}
5160
5161/*
5162 * "getpos(string)" function
5163 */
5164 static void
5165f_getpos(typval_T *argvars, typval_T *rettv)
5166{
5167 getpos_both(argvars, rettv, FALSE);
5168}
5169
5170/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005171 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005172 */
5173 static void
5174f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5175{
5176#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005177 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005178#endif
5179}
5180
5181/*
5182 * "getreg()" function
5183 */
5184 static void
5185f_getreg(typval_T *argvars, typval_T *rettv)
5186{
5187 char_u *strregname;
5188 int regname;
5189 int arg2 = FALSE;
5190 int return_list = FALSE;
5191 int error = FALSE;
5192
5193 if (argvars[0].v_type != VAR_UNKNOWN)
5194 {
5195 strregname = get_tv_string_chk(&argvars[0]);
5196 error = strregname == NULL;
5197 if (argvars[1].v_type != VAR_UNKNOWN)
5198 {
5199 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5200 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5201 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5202 }
5203 }
5204 else
5205 strregname = get_vim_var_str(VV_REG);
5206
5207 if (error)
5208 return;
5209
5210 regname = (strregname == NULL ? '"' : *strregname);
5211 if (regname == 0)
5212 regname = '"';
5213
5214 if (return_list)
5215 {
5216 rettv->v_type = VAR_LIST;
5217 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5218 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5219 if (rettv->vval.v_list == NULL)
5220 (void)rettv_list_alloc(rettv);
5221 else
5222 ++rettv->vval.v_list->lv_refcount;
5223 }
5224 else
5225 {
5226 rettv->v_type = VAR_STRING;
5227 rettv->vval.v_string = get_reg_contents(regname,
5228 arg2 ? GREG_EXPR_SRC : 0);
5229 }
5230}
5231
5232/*
5233 * "getregtype()" function
5234 */
5235 static void
5236f_getregtype(typval_T *argvars, typval_T *rettv)
5237{
5238 char_u *strregname;
5239 int regname;
5240 char_u buf[NUMBUFLEN + 2];
5241 long reglen = 0;
5242
5243 if (argvars[0].v_type != VAR_UNKNOWN)
5244 {
5245 strregname = get_tv_string_chk(&argvars[0]);
5246 if (strregname == NULL) /* type error; errmsg already given */
5247 {
5248 rettv->v_type = VAR_STRING;
5249 rettv->vval.v_string = NULL;
5250 return;
5251 }
5252 }
5253 else
5254 /* Default to v:register */
5255 strregname = get_vim_var_str(VV_REG);
5256
5257 regname = (strregname == NULL ? '"' : *strregname);
5258 if (regname == 0)
5259 regname = '"';
5260
5261 buf[0] = NUL;
5262 buf[1] = NUL;
5263 switch (get_reg_type(regname, &reglen))
5264 {
5265 case MLINE: buf[0] = 'V'; break;
5266 case MCHAR: buf[0] = 'v'; break;
5267 case MBLOCK:
5268 buf[0] = Ctrl_V;
5269 sprintf((char *)buf + 1, "%ld", reglen + 1);
5270 break;
5271 }
5272 rettv->v_type = VAR_STRING;
5273 rettv->vval.v_string = vim_strsave(buf);
5274}
5275
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005276/*
5277 * Returns information (variables, options, etc.) about a tab page
5278 * as a dictionary.
5279 */
5280 static dict_T *
5281get_tabpage_info(tabpage_T *tp, int tp_idx)
5282{
5283 win_T *wp;
5284 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005285 list_T *l;
5286
5287 dict = dict_alloc();
5288 if (dict == NULL)
5289 return NULL;
5290
Bram Moolenaar33928832016-08-18 21:22:04 +02005291 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005292
5293 l = list_alloc();
5294 if (l != NULL)
5295 {
5296 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5297 wp; wp = wp->w_next)
5298 list_append_number(l, (varnumber_T)wp->w_id);
5299 dict_add_list(dict, "windows", l);
5300 }
5301
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005302 /* Make a reference to tabpage variables */
5303 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005304
5305 return dict;
5306}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005307
5308/*
5309 * "gettabinfo()" function
5310 */
5311 static void
5312f_gettabinfo(typval_T *argvars, typval_T *rettv)
5313{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005314 tabpage_T *tp, *tparg = NULL;
5315 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005316 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005317
5318 if (rettv_list_alloc(rettv) != OK)
5319 return;
5320
5321 if (argvars[0].v_type != VAR_UNKNOWN)
5322 {
5323 /* Information about one tab page */
5324 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5325 if (tparg == NULL)
5326 return;
5327 }
5328
5329 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005330 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005331 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005332 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005333 if (tparg != NULL && tp != tparg)
5334 continue;
5335 d = get_tabpage_info(tp, tpnr);
5336 if (d != NULL)
5337 list_append_dict(rettv->vval.v_list, d);
5338 if (tparg != NULL)
5339 return;
5340 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005341}
5342
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005343/*
5344 * "gettabvar()" function
5345 */
5346 static void
5347f_gettabvar(typval_T *argvars, typval_T *rettv)
5348{
5349 win_T *oldcurwin;
5350 tabpage_T *tp, *oldtabpage;
5351 dictitem_T *v;
5352 char_u *varname;
5353 int done = FALSE;
5354
5355 rettv->v_type = VAR_STRING;
5356 rettv->vval.v_string = NULL;
5357
5358 varname = get_tv_string_chk(&argvars[1]);
5359 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5360 if (tp != NULL && varname != NULL)
5361 {
5362 /* Set tp to be our tabpage, temporarily. Also set the window to the
5363 * first window in the tabpage, otherwise the window is not valid. */
5364 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005365 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5366 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005367 {
5368 /* look up the variable */
5369 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5370 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5371 if (v != NULL)
5372 {
5373 copy_tv(&v->di_tv, rettv);
5374 done = TRUE;
5375 }
5376 }
5377
5378 /* restore previous notion of curwin */
5379 restore_win(oldcurwin, oldtabpage, TRUE);
5380 }
5381
5382 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5383 copy_tv(&argvars[2], rettv);
5384}
5385
5386/*
5387 * "gettabwinvar()" function
5388 */
5389 static void
5390f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5391{
5392 getwinvar(argvars, rettv, 1);
5393}
5394
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005395/*
5396 * Returns information about a window as a dictionary.
5397 */
5398 static dict_T *
5399get_win_info(win_T *wp, short tpnr, short winnr)
5400{
5401 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005402
5403 dict = dict_alloc();
5404 if (dict == NULL)
5405 return NULL;
5406
Bram Moolenaar33928832016-08-18 21:22:04 +02005407 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5408 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005409 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5410 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005411#ifdef FEAT_MENU
5412 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5413#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005414 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005415 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005416
Bram Moolenaar69905d12017-08-13 18:14:47 +02005417#ifdef FEAT_TERMINAL
5418 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5419#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005420#ifdef FEAT_QUICKFIX
5421 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5422 dict_add_nr_str(dict, "loclist",
5423 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5424#endif
5425
Bram Moolenaar30567352016-08-27 21:25:44 +02005426 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005427 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005428
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005429 return dict;
5430}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005431
5432/*
5433 * "getwininfo()" function
5434 */
5435 static void
5436f_getwininfo(typval_T *argvars, typval_T *rettv)
5437{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005438 tabpage_T *tp;
5439 win_T *wp = NULL, *wparg = NULL;
5440 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005441 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005442
5443 if (rettv_list_alloc(rettv) != OK)
5444 return;
5445
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005446 if (argvars[0].v_type != VAR_UNKNOWN)
5447 {
5448 wparg = win_id2wp(argvars);
5449 if (wparg == NULL)
5450 return;
5451 }
5452
5453 /* Collect information about either all the windows across all the tab
5454 * pages or one particular window.
5455 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005456 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005457 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005458 tabnr++;
5459 winnr = 0;
5460 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005461 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005462 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005463 if (wparg != NULL && wp != wparg)
5464 continue;
5465 d = get_win_info(wp, tabnr, winnr);
5466 if (d != NULL)
5467 list_append_dict(rettv->vval.v_list, d);
5468 if (wparg != NULL)
5469 /* found information about a specific window */
5470 return;
5471 }
5472 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005473}
5474
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005475/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005476 * "win_findbuf()" function
5477 */
5478 static void
5479f_win_findbuf(typval_T *argvars, typval_T *rettv)
5480{
5481 if (rettv_list_alloc(rettv) != FAIL)
5482 win_findbuf(argvars, rettv->vval.v_list);
5483}
5484
5485/*
5486 * "win_getid()" function
5487 */
5488 static void
5489f_win_getid(typval_T *argvars, typval_T *rettv)
5490{
5491 rettv->vval.v_number = win_getid(argvars);
5492}
5493
5494/*
5495 * "win_gotoid()" function
5496 */
5497 static void
5498f_win_gotoid(typval_T *argvars, typval_T *rettv)
5499{
5500 rettv->vval.v_number = win_gotoid(argvars);
5501}
5502
5503/*
5504 * "win_id2tabwin()" function
5505 */
5506 static void
5507f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5508{
5509 if (rettv_list_alloc(rettv) != FAIL)
5510 win_id2tabwin(argvars, rettv->vval.v_list);
5511}
5512
5513/*
5514 * "win_id2win()" function
5515 */
5516 static void
5517f_win_id2win(typval_T *argvars, typval_T *rettv)
5518{
5519 rettv->vval.v_number = win_id2win(argvars);
5520}
5521
5522/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005523 * "win_screenpos()" function
5524 */
5525 static void
5526f_win_screenpos(typval_T *argvars, typval_T *rettv)
5527{
5528 win_T *wp;
5529
5530 if (rettv_list_alloc(rettv) == FAIL)
5531 return;
5532
5533 wp = find_win_by_nr(&argvars[0], NULL);
5534 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5535 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5536}
5537
5538/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005539 * "getwinpos({timeout})" function
5540 */
5541 static void
5542f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5543{
5544 int x = -1;
5545 int y = -1;
5546
5547 if (rettv_list_alloc(rettv) == FAIL)
5548 return;
5549#ifdef FEAT_GUI
5550 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005551 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005552# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5553 else
5554# endif
5555#endif
5556#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5557 {
5558 varnumber_T timeout = 100;
5559
5560 if (argvars[0].v_type != VAR_UNKNOWN)
5561 timeout = get_tv_number(&argvars[0]);
5562 term_get_winpos(&x, &y, timeout);
5563 }
5564#endif
5565 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5566 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5567}
5568
5569
5570/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005571 * "getwinposx()" function
5572 */
5573 static void
5574f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5575{
5576 rettv->vval.v_number = -1;
5577#ifdef FEAT_GUI
5578 if (gui.in_use)
5579 {
5580 int x, y;
5581
5582 if (gui_mch_get_winpos(&x, &y) == OK)
5583 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005584 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005585 }
5586#endif
5587#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5588 {
5589 int x, y;
5590
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005591 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005592 rettv->vval.v_number = x;
5593 }
5594#endif
5595}
5596
5597/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005598 * "getwinposy()" function
5599 */
5600 static void
5601f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5602{
5603 rettv->vval.v_number = -1;
5604#ifdef FEAT_GUI
5605 if (gui.in_use)
5606 {
5607 int x, y;
5608
5609 if (gui_mch_get_winpos(&x, &y) == OK)
5610 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005611 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005612 }
5613#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005614#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5615 {
5616 int x, y;
5617
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005618 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005619 rettv->vval.v_number = y;
5620 }
5621#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005622}
5623
5624/*
5625 * "getwinvar()" function
5626 */
5627 static void
5628f_getwinvar(typval_T *argvars, typval_T *rettv)
5629{
5630 getwinvar(argvars, rettv, 0);
5631}
5632
5633/*
5634 * "glob()" function
5635 */
5636 static void
5637f_glob(typval_T *argvars, typval_T *rettv)
5638{
5639 int options = WILD_SILENT|WILD_USE_NL;
5640 expand_T xpc;
5641 int error = FALSE;
5642
5643 /* When the optional second argument is non-zero, don't remove matches
5644 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5645 rettv->v_type = VAR_STRING;
5646 if (argvars[1].v_type != VAR_UNKNOWN)
5647 {
5648 if (get_tv_number_chk(&argvars[1], &error))
5649 options |= WILD_KEEP_ALL;
5650 if (argvars[2].v_type != VAR_UNKNOWN)
5651 {
5652 if (get_tv_number_chk(&argvars[2], &error))
5653 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005654 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005655 }
5656 if (argvars[3].v_type != VAR_UNKNOWN
5657 && get_tv_number_chk(&argvars[3], &error))
5658 options |= WILD_ALLLINKS;
5659 }
5660 }
5661 if (!error)
5662 {
5663 ExpandInit(&xpc);
5664 xpc.xp_context = EXPAND_FILES;
5665 if (p_wic)
5666 options += WILD_ICASE;
5667 if (rettv->v_type == VAR_STRING)
5668 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5669 NULL, options, WILD_ALL);
5670 else if (rettv_list_alloc(rettv) != FAIL)
5671 {
5672 int i;
5673
5674 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5675 NULL, options, WILD_ALL_KEEP);
5676 for (i = 0; i < xpc.xp_numfiles; i++)
5677 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5678
5679 ExpandCleanup(&xpc);
5680 }
5681 }
5682 else
5683 rettv->vval.v_string = NULL;
5684}
5685
5686/*
5687 * "globpath()" function
5688 */
5689 static void
5690f_globpath(typval_T *argvars, typval_T *rettv)
5691{
5692 int flags = 0;
5693 char_u buf1[NUMBUFLEN];
5694 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5695 int error = FALSE;
5696 garray_T ga;
5697 int i;
5698
5699 /* When the optional second argument is non-zero, don't remove matches
5700 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5701 rettv->v_type = VAR_STRING;
5702 if (argvars[2].v_type != VAR_UNKNOWN)
5703 {
5704 if (get_tv_number_chk(&argvars[2], &error))
5705 flags |= WILD_KEEP_ALL;
5706 if (argvars[3].v_type != VAR_UNKNOWN)
5707 {
5708 if (get_tv_number_chk(&argvars[3], &error))
5709 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005710 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005711 }
5712 if (argvars[4].v_type != VAR_UNKNOWN
5713 && get_tv_number_chk(&argvars[4], &error))
5714 flags |= WILD_ALLLINKS;
5715 }
5716 }
5717 if (file != NULL && !error)
5718 {
5719 ga_init2(&ga, (int)sizeof(char_u *), 10);
5720 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5721 if (rettv->v_type == VAR_STRING)
5722 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5723 else if (rettv_list_alloc(rettv) != FAIL)
5724 for (i = 0; i < ga.ga_len; ++i)
5725 list_append_string(rettv->vval.v_list,
5726 ((char_u **)(ga.ga_data))[i], -1);
5727 ga_clear_strings(&ga);
5728 }
5729 else
5730 rettv->vval.v_string = NULL;
5731}
5732
5733/*
5734 * "glob2regpat()" function
5735 */
5736 static void
5737f_glob2regpat(typval_T *argvars, typval_T *rettv)
5738{
5739 char_u *pat = get_tv_string_chk(&argvars[0]);
5740
5741 rettv->v_type = VAR_STRING;
5742 rettv->vval.v_string = (pat == NULL)
5743 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5744}
5745
5746/* for VIM_VERSION_ defines */
5747#include "version.h"
5748
5749/*
5750 * "has()" function
5751 */
5752 static void
5753f_has(typval_T *argvars, typval_T *rettv)
5754{
5755 int i;
5756 char_u *name;
5757 int n = FALSE;
5758 static char *(has_list[]) =
5759 {
5760#ifdef AMIGA
5761 "amiga",
5762# ifdef FEAT_ARP
5763 "arp",
5764# endif
5765#endif
5766#ifdef __BEOS__
5767 "beos",
5768#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005769#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005770 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5771 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005772# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005773 "macunix", /* Mac OS X, with the darwin feature */
5774 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005775# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005776#endif
5777#ifdef __QNX__
5778 "qnx",
5779#endif
5780#ifdef UNIX
5781 "unix",
5782#endif
5783#ifdef VMS
5784 "vms",
5785#endif
5786#ifdef WIN32
5787 "win32",
5788#endif
5789#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5790 "win32unix",
5791#endif
5792#if defined(WIN64) || defined(_WIN64)
5793 "win64",
5794#endif
5795#ifdef EBCDIC
5796 "ebcdic",
5797#endif
5798#ifndef CASE_INSENSITIVE_FILENAME
5799 "fname_case",
5800#endif
5801#ifdef HAVE_ACL
5802 "acl",
5803#endif
5804#ifdef FEAT_ARABIC
5805 "arabic",
5806#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005807 "autocmd",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005808#ifdef FEAT_AUTOSERVERNAME
5809 "autoservername",
5810#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005811#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005812 "balloon_eval",
5813# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5814 "balloon_multiline",
5815# endif
5816#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005817#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005818 "balloon_eval_term",
5819#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005820#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5821 "builtin_terms",
5822# ifdef ALL_BUILTIN_TCAPS
5823 "all_builtin_terms",
5824# endif
5825#endif
5826#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5827 || defined(FEAT_GUI_W32) \
5828 || defined(FEAT_GUI_MOTIF))
5829 "browsefilter",
5830#endif
5831#ifdef FEAT_BYTEOFF
5832 "byte_offset",
5833#endif
5834#ifdef FEAT_JOB_CHANNEL
5835 "channel",
5836#endif
5837#ifdef FEAT_CINDENT
5838 "cindent",
5839#endif
5840#ifdef FEAT_CLIENTSERVER
5841 "clientserver",
5842#endif
5843#ifdef FEAT_CLIPBOARD
5844 "clipboard",
5845#endif
5846#ifdef FEAT_CMDL_COMPL
5847 "cmdline_compl",
5848#endif
5849#ifdef FEAT_CMDHIST
5850 "cmdline_hist",
5851#endif
5852#ifdef FEAT_COMMENTS
5853 "comments",
5854#endif
5855#ifdef FEAT_CONCEAL
5856 "conceal",
5857#endif
5858#ifdef FEAT_CRYPT
5859 "cryptv",
5860 "crypt-blowfish",
5861 "crypt-blowfish2",
5862#endif
5863#ifdef FEAT_CSCOPE
5864 "cscope",
5865#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005866 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005867#ifdef CURSOR_SHAPE
5868 "cursorshape",
5869#endif
5870#ifdef DEBUG
5871 "debug",
5872#endif
5873#ifdef FEAT_CON_DIALOG
5874 "dialog_con",
5875#endif
5876#ifdef FEAT_GUI_DIALOG
5877 "dialog_gui",
5878#endif
5879#ifdef FEAT_DIFF
5880 "diff",
5881#endif
5882#ifdef FEAT_DIGRAPHS
5883 "digraphs",
5884#endif
5885#ifdef FEAT_DIRECTX
5886 "directx",
5887#endif
5888#ifdef FEAT_DND
5889 "dnd",
5890#endif
5891#ifdef FEAT_EMACS_TAGS
5892 "emacs_tags",
5893#endif
5894 "eval", /* always present, of course! */
5895 "ex_extra", /* graduated feature */
5896#ifdef FEAT_SEARCH_EXTRA
5897 "extra_search",
5898#endif
5899#ifdef FEAT_FKMAP
5900 "farsi",
5901#endif
5902#ifdef FEAT_SEARCHPATH
5903 "file_in_path",
5904#endif
5905#ifdef FEAT_FILTERPIPE
5906 "filterpipe",
5907#endif
5908#ifdef FEAT_FIND_ID
5909 "find_in_path",
5910#endif
5911#ifdef FEAT_FLOAT
5912 "float",
5913#endif
5914#ifdef FEAT_FOLDING
5915 "folding",
5916#endif
5917#ifdef FEAT_FOOTER
5918 "footer",
5919#endif
5920#if !defined(USE_SYSTEM) && defined(UNIX)
5921 "fork",
5922#endif
5923#ifdef FEAT_GETTEXT
5924 "gettext",
5925#endif
5926#ifdef FEAT_GUI
5927 "gui",
5928#endif
5929#ifdef FEAT_GUI_ATHENA
5930# ifdef FEAT_GUI_NEXTAW
5931 "gui_neXtaw",
5932# else
5933 "gui_athena",
5934# endif
5935#endif
5936#ifdef FEAT_GUI_GTK
5937 "gui_gtk",
5938# ifdef USE_GTK3
5939 "gui_gtk3",
5940# else
5941 "gui_gtk2",
5942# endif
5943#endif
5944#ifdef FEAT_GUI_GNOME
5945 "gui_gnome",
5946#endif
5947#ifdef FEAT_GUI_MAC
5948 "gui_mac",
5949#endif
5950#ifdef FEAT_GUI_MOTIF
5951 "gui_motif",
5952#endif
5953#ifdef FEAT_GUI_PHOTON
5954 "gui_photon",
5955#endif
5956#ifdef FEAT_GUI_W32
5957 "gui_win32",
5958#endif
5959#ifdef FEAT_HANGULIN
5960 "hangul_input",
5961#endif
5962#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5963 "iconv",
5964#endif
5965#ifdef FEAT_INS_EXPAND
5966 "insert_expand",
5967#endif
5968#ifdef FEAT_JOB_CHANNEL
5969 "job",
5970#endif
5971#ifdef FEAT_JUMPLIST
5972 "jumplist",
5973#endif
5974#ifdef FEAT_KEYMAP
5975 "keymap",
5976#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005977 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978#ifdef FEAT_LANGMAP
5979 "langmap",
5980#endif
5981#ifdef FEAT_LIBCALL
5982 "libcall",
5983#endif
5984#ifdef FEAT_LINEBREAK
5985 "linebreak",
5986#endif
5987#ifdef FEAT_LISP
5988 "lispindent",
5989#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005990 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005991#ifdef FEAT_LOCALMAP
5992 "localmap",
5993#endif
5994#ifdef FEAT_LUA
5995# ifndef DYNAMIC_LUA
5996 "lua",
5997# endif
5998#endif
5999#ifdef FEAT_MENU
6000 "menu",
6001#endif
6002#ifdef FEAT_SESSION
6003 "mksession",
6004#endif
6005#ifdef FEAT_MODIFY_FNAME
6006 "modify_fname",
6007#endif
6008#ifdef FEAT_MOUSE
6009 "mouse",
6010#endif
6011#ifdef FEAT_MOUSESHAPE
6012 "mouseshape",
6013#endif
6014#if defined(UNIX) || defined(VMS)
6015# ifdef FEAT_MOUSE_DEC
6016 "mouse_dec",
6017# endif
6018# ifdef FEAT_MOUSE_GPM
6019 "mouse_gpm",
6020# endif
6021# ifdef FEAT_MOUSE_JSB
6022 "mouse_jsbterm",
6023# endif
6024# ifdef FEAT_MOUSE_NET
6025 "mouse_netterm",
6026# endif
6027# ifdef FEAT_MOUSE_PTERM
6028 "mouse_pterm",
6029# endif
6030# ifdef FEAT_MOUSE_SGR
6031 "mouse_sgr",
6032# endif
6033# ifdef FEAT_SYSMOUSE
6034 "mouse_sysmouse",
6035# endif
6036# ifdef FEAT_MOUSE_URXVT
6037 "mouse_urxvt",
6038# endif
6039# ifdef FEAT_MOUSE_XTERM
6040 "mouse_xterm",
6041# endif
6042#endif
6043#ifdef FEAT_MBYTE
6044 "multi_byte",
6045#endif
6046#ifdef FEAT_MBYTE_IME
6047 "multi_byte_ime",
6048#endif
6049#ifdef FEAT_MULTI_LANG
6050 "multi_lang",
6051#endif
6052#ifdef FEAT_MZSCHEME
6053#ifndef DYNAMIC_MZSCHEME
6054 "mzscheme",
6055#endif
6056#endif
6057#ifdef FEAT_NUM64
6058 "num64",
6059#endif
6060#ifdef FEAT_OLE
6061 "ole",
6062#endif
6063 "packages",
6064#ifdef FEAT_PATH_EXTRA
6065 "path_extra",
6066#endif
6067#ifdef FEAT_PERL
6068#ifndef DYNAMIC_PERL
6069 "perl",
6070#endif
6071#endif
6072#ifdef FEAT_PERSISTENT_UNDO
6073 "persistent_undo",
6074#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006075#if defined(FEAT_PYTHON)
6076 "python_compiled",
6077# if defined(DYNAMIC_PYTHON)
6078 "python_dynamic",
6079# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006080 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006081 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006082# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006084#if defined(FEAT_PYTHON3)
6085 "python3_compiled",
6086# if defined(DYNAMIC_PYTHON3)
6087 "python3_dynamic",
6088# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006089 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006090 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006091# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006092#endif
6093#ifdef FEAT_POSTSCRIPT
6094 "postscript",
6095#endif
6096#ifdef FEAT_PRINTER
6097 "printer",
6098#endif
6099#ifdef FEAT_PROFILE
6100 "profile",
6101#endif
6102#ifdef FEAT_RELTIME
6103 "reltime",
6104#endif
6105#ifdef FEAT_QUICKFIX
6106 "quickfix",
6107#endif
6108#ifdef FEAT_RIGHTLEFT
6109 "rightleft",
6110#endif
6111#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6112 "ruby",
6113#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006114 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006115#ifdef FEAT_CMDL_INFO
6116 "showcmd",
6117 "cmdline_info",
6118#endif
6119#ifdef FEAT_SIGNS
6120 "signs",
6121#endif
6122#ifdef FEAT_SMARTINDENT
6123 "smartindent",
6124#endif
6125#ifdef STARTUPTIME
6126 "startuptime",
6127#endif
6128#ifdef FEAT_STL_OPT
6129 "statusline",
6130#endif
6131#ifdef FEAT_SUN_WORKSHOP
6132 "sun_workshop",
6133#endif
6134#ifdef FEAT_NETBEANS_INTG
6135 "netbeans_intg",
6136#endif
6137#ifdef FEAT_SPELL
6138 "spell",
6139#endif
6140#ifdef FEAT_SYN_HL
6141 "syntax",
6142#endif
6143#if defined(USE_SYSTEM) || !defined(UNIX)
6144 "system",
6145#endif
6146#ifdef FEAT_TAG_BINS
6147 "tag_binary",
6148#endif
6149#ifdef FEAT_TAG_OLDSTATIC
6150 "tag_old_static",
6151#endif
6152#ifdef FEAT_TAG_ANYWHITE
6153 "tag_any_white",
6154#endif
6155#ifdef FEAT_TCL
6156# ifndef DYNAMIC_TCL
6157 "tcl",
6158# endif
6159#endif
6160#ifdef FEAT_TERMGUICOLORS
6161 "termguicolors",
6162#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006163#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006164 "terminal",
6165#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166#ifdef TERMINFO
6167 "terminfo",
6168#endif
6169#ifdef FEAT_TERMRESPONSE
6170 "termresponse",
6171#endif
6172#ifdef FEAT_TEXTOBJ
6173 "textobjects",
6174#endif
6175#ifdef HAVE_TGETENT
6176 "tgetent",
6177#endif
6178#ifdef FEAT_TIMERS
6179 "timers",
6180#endif
6181#ifdef FEAT_TITLE
6182 "title",
6183#endif
6184#ifdef FEAT_TOOLBAR
6185 "toolbar",
6186#endif
6187#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6188 "unnamedplus",
6189#endif
6190#ifdef FEAT_USR_CMDS
6191 "user-commands", /* was accidentally included in 5.4 */
6192 "user_commands",
6193#endif
6194#ifdef FEAT_VIMINFO
6195 "viminfo",
6196#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198#ifdef FEAT_VIRTUALEDIT
6199 "virtualedit",
6200#endif
6201 "visual",
6202#ifdef FEAT_VISUALEXTRA
6203 "visualextra",
6204#endif
6205#ifdef FEAT_VREPLACE
6206 "vreplace",
6207#endif
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006208#ifdef FEAT_VTP
6209 "vtp",
6210#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006211#ifdef FEAT_WILDIGN
6212 "wildignore",
6213#endif
6214#ifdef FEAT_WILDMENU
6215 "wildmenu",
6216#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006217 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218#ifdef FEAT_WAK
6219 "winaltkeys",
6220#endif
6221#ifdef FEAT_WRITEBACKUP
6222 "writebackup",
6223#endif
6224#ifdef FEAT_XIM
6225 "xim",
6226#endif
6227#ifdef FEAT_XFONTSET
6228 "xfontset",
6229#endif
6230#ifdef FEAT_XPM_W32
6231 "xpm",
6232 "xpm_w32", /* for backward compatibility */
6233#else
6234# if defined(HAVE_XPM)
6235 "xpm",
6236# endif
6237#endif
6238#ifdef USE_XSMP
6239 "xsmp",
6240#endif
6241#ifdef USE_XSMP_INTERACT
6242 "xsmp_interact",
6243#endif
6244#ifdef FEAT_XCLIPBOARD
6245 "xterm_clipboard",
6246#endif
6247#ifdef FEAT_XTERM_SAVE
6248 "xterm_save",
6249#endif
6250#if defined(UNIX) && defined(FEAT_X11)
6251 "X11",
6252#endif
6253 NULL
6254 };
6255
6256 name = get_tv_string(&argvars[0]);
6257 for (i = 0; has_list[i] != NULL; ++i)
6258 if (STRICMP(name, has_list[i]) == 0)
6259 {
6260 n = TRUE;
6261 break;
6262 }
6263
6264 if (n == FALSE)
6265 {
6266 if (STRNICMP(name, "patch", 5) == 0)
6267 {
6268 if (name[5] == '-'
6269 && STRLEN(name) >= 11
6270 && vim_isdigit(name[6])
6271 && vim_isdigit(name[8])
6272 && vim_isdigit(name[10]))
6273 {
6274 int major = atoi((char *)name + 6);
6275 int minor = atoi((char *)name + 8);
6276
6277 /* Expect "patch-9.9.01234". */
6278 n = (major < VIM_VERSION_MAJOR
6279 || (major == VIM_VERSION_MAJOR
6280 && (minor < VIM_VERSION_MINOR
6281 || (minor == VIM_VERSION_MINOR
6282 && has_patch(atoi((char *)name + 10))))));
6283 }
6284 else
6285 n = has_patch(atoi((char *)name + 5));
6286 }
6287 else if (STRICMP(name, "vim_starting") == 0)
6288 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006289 else if (STRICMP(name, "ttyin") == 0)
6290 n = mch_input_isatty();
6291 else if (STRICMP(name, "ttyout") == 0)
6292 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293#ifdef FEAT_MBYTE
6294 else if (STRICMP(name, "multi_byte_encoding") == 0)
6295 n = has_mbyte;
6296#endif
6297#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6298 else if (STRICMP(name, "balloon_multiline") == 0)
6299 n = multiline_balloon_available();
6300#endif
6301#ifdef DYNAMIC_TCL
6302 else if (STRICMP(name, "tcl") == 0)
6303 n = tcl_enabled(FALSE);
6304#endif
6305#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6306 else if (STRICMP(name, "iconv") == 0)
6307 n = iconv_enabled(FALSE);
6308#endif
6309#ifdef DYNAMIC_LUA
6310 else if (STRICMP(name, "lua") == 0)
6311 n = lua_enabled(FALSE);
6312#endif
6313#ifdef DYNAMIC_MZSCHEME
6314 else if (STRICMP(name, "mzscheme") == 0)
6315 n = mzscheme_enabled(FALSE);
6316#endif
6317#ifdef DYNAMIC_RUBY
6318 else if (STRICMP(name, "ruby") == 0)
6319 n = ruby_enabled(FALSE);
6320#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321#ifdef DYNAMIC_PYTHON
6322 else if (STRICMP(name, "python") == 0)
6323 n = python_enabled(FALSE);
6324#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325#ifdef DYNAMIC_PYTHON3
6326 else if (STRICMP(name, "python3") == 0)
6327 n = python3_enabled(FALSE);
6328#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006329#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6330 else if (STRICMP(name, "pythonx") == 0)
6331 {
6332# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6333 if (p_pyx == 0)
6334 n = python3_enabled(FALSE) || python_enabled(FALSE);
6335 else if (p_pyx == 3)
6336 n = python3_enabled(FALSE);
6337 else if (p_pyx == 2)
6338 n = python_enabled(FALSE);
6339# elif defined(DYNAMIC_PYTHON)
6340 n = python_enabled(FALSE);
6341# elif defined(DYNAMIC_PYTHON3)
6342 n = python3_enabled(FALSE);
6343# endif
6344 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345#endif
6346#ifdef DYNAMIC_PERL
6347 else if (STRICMP(name, "perl") == 0)
6348 n = perl_enabled(FALSE);
6349#endif
6350#ifdef FEAT_GUI
6351 else if (STRICMP(name, "gui_running") == 0)
6352 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353# ifdef FEAT_BROWSE
6354 else if (STRICMP(name, "browse") == 0)
6355 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6356# endif
6357#endif
6358#ifdef FEAT_SYN_HL
6359 else if (STRICMP(name, "syntax_items") == 0)
6360 n = syntax_present(curwin);
6361#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006362#ifdef FEAT_VTP
6363 else if (STRICMP(name, "vcon") == 0)
6364 n = has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365#endif
6366#ifdef FEAT_NETBEANS_INTG
6367 else if (STRICMP(name, "netbeans_enabled") == 0)
6368 n = netbeans_active();
6369#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006370#if defined(FEAT_TERMINAL) && defined(WIN3264)
6371 else if (STRICMP(name, "terminal") == 0)
6372 n = terminal_enabled();
6373#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006374 }
6375
6376 rettv->vval.v_number = n;
6377}
6378
6379/*
6380 * "has_key()" function
6381 */
6382 static void
6383f_has_key(typval_T *argvars, typval_T *rettv)
6384{
6385 if (argvars[0].v_type != VAR_DICT)
6386 {
6387 EMSG(_(e_dictreq));
6388 return;
6389 }
6390 if (argvars[0].vval.v_dict == NULL)
6391 return;
6392
6393 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6394 get_tv_string(&argvars[1]), -1) != NULL;
6395}
6396
6397/*
6398 * "haslocaldir()" function
6399 */
6400 static void
6401f_haslocaldir(typval_T *argvars, typval_T *rettv)
6402{
6403 win_T *wp = NULL;
6404
6405 wp = find_tabwin(&argvars[0], &argvars[1]);
6406 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6407}
6408
6409/*
6410 * "hasmapto()" function
6411 */
6412 static void
6413f_hasmapto(typval_T *argvars, typval_T *rettv)
6414{
6415 char_u *name;
6416 char_u *mode;
6417 char_u buf[NUMBUFLEN];
6418 int abbr = FALSE;
6419
6420 name = get_tv_string(&argvars[0]);
6421 if (argvars[1].v_type == VAR_UNKNOWN)
6422 mode = (char_u *)"nvo";
6423 else
6424 {
6425 mode = get_tv_string_buf(&argvars[1], buf);
6426 if (argvars[2].v_type != VAR_UNKNOWN)
6427 abbr = (int)get_tv_number(&argvars[2]);
6428 }
6429
6430 if (map_to_exists(name, mode, abbr))
6431 rettv->vval.v_number = TRUE;
6432 else
6433 rettv->vval.v_number = FALSE;
6434}
6435
6436/*
6437 * "histadd()" function
6438 */
6439 static void
6440f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6441{
6442#ifdef FEAT_CMDHIST
6443 int histype;
6444 char_u *str;
6445 char_u buf[NUMBUFLEN];
6446#endif
6447
6448 rettv->vval.v_number = FALSE;
6449 if (check_restricted() || check_secure())
6450 return;
6451#ifdef FEAT_CMDHIST
6452 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6453 histype = str != NULL ? get_histtype(str) : -1;
6454 if (histype >= 0)
6455 {
6456 str = get_tv_string_buf(&argvars[1], buf);
6457 if (*str != NUL)
6458 {
6459 init_history();
6460 add_to_history(histype, str, FALSE, NUL);
6461 rettv->vval.v_number = TRUE;
6462 return;
6463 }
6464 }
6465#endif
6466}
6467
6468/*
6469 * "histdel()" function
6470 */
6471 static void
6472f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6473{
6474#ifdef FEAT_CMDHIST
6475 int n;
6476 char_u buf[NUMBUFLEN];
6477 char_u *str;
6478
6479 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6480 if (str == NULL)
6481 n = 0;
6482 else if (argvars[1].v_type == VAR_UNKNOWN)
6483 /* only one argument: clear entire history */
6484 n = clr_history(get_histtype(str));
6485 else if (argvars[1].v_type == VAR_NUMBER)
6486 /* index given: remove that entry */
6487 n = del_history_idx(get_histtype(str),
6488 (int)get_tv_number(&argvars[1]));
6489 else
6490 /* string given: remove all matching entries */
6491 n = del_history_entry(get_histtype(str),
6492 get_tv_string_buf(&argvars[1], buf));
6493 rettv->vval.v_number = n;
6494#endif
6495}
6496
6497/*
6498 * "histget()" function
6499 */
6500 static void
6501f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6502{
6503#ifdef FEAT_CMDHIST
6504 int type;
6505 int idx;
6506 char_u *str;
6507
6508 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6509 if (str == NULL)
6510 rettv->vval.v_string = NULL;
6511 else
6512 {
6513 type = get_histtype(str);
6514 if (argvars[1].v_type == VAR_UNKNOWN)
6515 idx = get_history_idx(type);
6516 else
6517 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6518 /* -1 on type error */
6519 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6520 }
6521#else
6522 rettv->vval.v_string = NULL;
6523#endif
6524 rettv->v_type = VAR_STRING;
6525}
6526
6527/*
6528 * "histnr()" function
6529 */
6530 static void
6531f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6532{
6533 int i;
6534
6535#ifdef FEAT_CMDHIST
6536 char_u *history = get_tv_string_chk(&argvars[0]);
6537
6538 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6539 if (i >= HIST_CMD && i < HIST_COUNT)
6540 i = get_history_idx(i);
6541 else
6542#endif
6543 i = -1;
6544 rettv->vval.v_number = i;
6545}
6546
6547/*
6548 * "highlightID(name)" function
6549 */
6550 static void
6551f_hlID(typval_T *argvars, typval_T *rettv)
6552{
6553 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6554}
6555
6556/*
6557 * "highlight_exists()" function
6558 */
6559 static void
6560f_hlexists(typval_T *argvars, typval_T *rettv)
6561{
6562 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6563}
6564
6565/*
6566 * "hostname()" function
6567 */
6568 static void
6569f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6570{
6571 char_u hostname[256];
6572
6573 mch_get_host_name(hostname, 256);
6574 rettv->v_type = VAR_STRING;
6575 rettv->vval.v_string = vim_strsave(hostname);
6576}
6577
6578/*
6579 * iconv() function
6580 */
6581 static void
6582f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6583{
6584#ifdef FEAT_MBYTE
6585 char_u buf1[NUMBUFLEN];
6586 char_u buf2[NUMBUFLEN];
6587 char_u *from, *to, *str;
6588 vimconv_T vimconv;
6589#endif
6590
6591 rettv->v_type = VAR_STRING;
6592 rettv->vval.v_string = NULL;
6593
6594#ifdef FEAT_MBYTE
6595 str = get_tv_string(&argvars[0]);
6596 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6597 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6598 vimconv.vc_type = CONV_NONE;
6599 convert_setup(&vimconv, from, to);
6600
6601 /* If the encodings are equal, no conversion needed. */
6602 if (vimconv.vc_type == CONV_NONE)
6603 rettv->vval.v_string = vim_strsave(str);
6604 else
6605 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6606
6607 convert_setup(&vimconv, NULL, NULL);
6608 vim_free(from);
6609 vim_free(to);
6610#endif
6611}
6612
6613/*
6614 * "indent()" function
6615 */
6616 static void
6617f_indent(typval_T *argvars, typval_T *rettv)
6618{
6619 linenr_T lnum;
6620
6621 lnum = get_tv_lnum(argvars);
6622 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6623 rettv->vval.v_number = get_indent_lnum(lnum);
6624 else
6625 rettv->vval.v_number = -1;
6626}
6627
6628/*
6629 * "index()" function
6630 */
6631 static void
6632f_index(typval_T *argvars, typval_T *rettv)
6633{
6634 list_T *l;
6635 listitem_T *item;
6636 long idx = 0;
6637 int ic = FALSE;
6638
6639 rettv->vval.v_number = -1;
6640 if (argvars[0].v_type != VAR_LIST)
6641 {
6642 EMSG(_(e_listreq));
6643 return;
6644 }
6645 l = argvars[0].vval.v_list;
6646 if (l != NULL)
6647 {
6648 item = l->lv_first;
6649 if (argvars[2].v_type != VAR_UNKNOWN)
6650 {
6651 int error = FALSE;
6652
6653 /* Start at specified item. Use the cached index that list_find()
6654 * sets, so that a negative number also works. */
6655 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6656 idx = l->lv_idx;
6657 if (argvars[3].v_type != VAR_UNKNOWN)
6658 ic = (int)get_tv_number_chk(&argvars[3], &error);
6659 if (error)
6660 item = NULL;
6661 }
6662
6663 for ( ; item != NULL; item = item->li_next, ++idx)
6664 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6665 {
6666 rettv->vval.v_number = idx;
6667 break;
6668 }
6669 }
6670}
6671
6672static int inputsecret_flag = 0;
6673
6674/*
6675 * "input()" function
6676 * Also handles inputsecret() when inputsecret is set.
6677 */
6678 static void
6679f_input(typval_T *argvars, typval_T *rettv)
6680{
6681 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6682}
6683
6684/*
6685 * "inputdialog()" function
6686 */
6687 static void
6688f_inputdialog(typval_T *argvars, typval_T *rettv)
6689{
6690#if defined(FEAT_GUI_TEXTDIALOG)
6691 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6692 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6693 {
6694 char_u *message;
6695 char_u buf[NUMBUFLEN];
6696 char_u *defstr = (char_u *)"";
6697
6698 message = get_tv_string_chk(&argvars[0]);
6699 if (argvars[1].v_type != VAR_UNKNOWN
6700 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6701 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6702 else
6703 IObuff[0] = NUL;
6704 if (message != NULL && defstr != NULL
6705 && do_dialog(VIM_QUESTION, NULL, message,
6706 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6707 rettv->vval.v_string = vim_strsave(IObuff);
6708 else
6709 {
6710 if (message != NULL && defstr != NULL
6711 && argvars[1].v_type != VAR_UNKNOWN
6712 && argvars[2].v_type != VAR_UNKNOWN)
6713 rettv->vval.v_string = vim_strsave(
6714 get_tv_string_buf(&argvars[2], buf));
6715 else
6716 rettv->vval.v_string = NULL;
6717 }
6718 rettv->v_type = VAR_STRING;
6719 }
6720 else
6721#endif
6722 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6723}
6724
6725/*
6726 * "inputlist()" function
6727 */
6728 static void
6729f_inputlist(typval_T *argvars, typval_T *rettv)
6730{
6731 listitem_T *li;
6732 int selected;
6733 int mouse_used;
6734
6735#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006736 /* While starting up, there is no place to enter text. When running tests
6737 * with --not-a-term we assume feedkeys() will be used. */
6738 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 return;
6740#endif
6741 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6742 {
6743 EMSG2(_(e_listarg), "inputlist()");
6744 return;
6745 }
6746
6747 msg_start();
6748 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6749 lines_left = Rows; /* avoid more prompt */
6750 msg_scroll = TRUE;
6751 msg_clr_eos();
6752
6753 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6754 {
6755 msg_puts(get_tv_string(&li->li_tv));
6756 msg_putchar('\n');
6757 }
6758
6759 /* Ask for choice. */
6760 selected = prompt_for_number(&mouse_used);
6761 if (mouse_used)
6762 selected -= lines_left;
6763
6764 rettv->vval.v_number = selected;
6765}
6766
6767
6768static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6769
6770/*
6771 * "inputrestore()" function
6772 */
6773 static void
6774f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6775{
6776 if (ga_userinput.ga_len > 0)
6777 {
6778 --ga_userinput.ga_len;
6779 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6780 + ga_userinput.ga_len);
6781 /* default return is zero == OK */
6782 }
6783 else if (p_verbose > 1)
6784 {
6785 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6786 rettv->vval.v_number = 1; /* Failed */
6787 }
6788}
6789
6790/*
6791 * "inputsave()" function
6792 */
6793 static void
6794f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6795{
6796 /* Add an entry to the stack of typeahead storage. */
6797 if (ga_grow(&ga_userinput, 1) == OK)
6798 {
6799 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6800 + ga_userinput.ga_len);
6801 ++ga_userinput.ga_len;
6802 /* default return is zero == OK */
6803 }
6804 else
6805 rettv->vval.v_number = 1; /* Failed */
6806}
6807
6808/*
6809 * "inputsecret()" function
6810 */
6811 static void
6812f_inputsecret(typval_T *argvars, typval_T *rettv)
6813{
6814 ++cmdline_star;
6815 ++inputsecret_flag;
6816 f_input(argvars, rettv);
6817 --cmdline_star;
6818 --inputsecret_flag;
6819}
6820
6821/*
6822 * "insert()" function
6823 */
6824 static void
6825f_insert(typval_T *argvars, typval_T *rettv)
6826{
6827 long before = 0;
6828 listitem_T *item;
6829 list_T *l;
6830 int error = FALSE;
6831
6832 if (argvars[0].v_type != VAR_LIST)
6833 EMSG2(_(e_listarg), "insert()");
6834 else if ((l = argvars[0].vval.v_list) != NULL
6835 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6836 {
6837 if (argvars[2].v_type != VAR_UNKNOWN)
6838 before = (long)get_tv_number_chk(&argvars[2], &error);
6839 if (error)
6840 return; /* type error; errmsg already given */
6841
6842 if (before == l->lv_len)
6843 item = NULL;
6844 else
6845 {
6846 item = list_find(l, before);
6847 if (item == NULL)
6848 {
6849 EMSGN(_(e_listidx), before);
6850 l = NULL;
6851 }
6852 }
6853 if (l != NULL)
6854 {
6855 list_insert_tv(l, &argvars[1], item);
6856 copy_tv(&argvars[0], rettv);
6857 }
6858 }
6859}
6860
6861/*
6862 * "invert(expr)" function
6863 */
6864 static void
6865f_invert(typval_T *argvars, typval_T *rettv)
6866{
6867 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6868}
6869
6870/*
6871 * "isdirectory()" function
6872 */
6873 static void
6874f_isdirectory(typval_T *argvars, typval_T *rettv)
6875{
6876 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6877}
6878
6879/*
6880 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6881 * or it refers to a List or Dictionary that is locked.
6882 */
6883 static int
6884tv_islocked(typval_T *tv)
6885{
6886 return (tv->v_lock & VAR_LOCKED)
6887 || (tv->v_type == VAR_LIST
6888 && tv->vval.v_list != NULL
6889 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6890 || (tv->v_type == VAR_DICT
6891 && tv->vval.v_dict != NULL
6892 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6893}
6894
6895/*
6896 * "islocked()" function
6897 */
6898 static void
6899f_islocked(typval_T *argvars, typval_T *rettv)
6900{
6901 lval_T lv;
6902 char_u *end;
6903 dictitem_T *di;
6904
6905 rettv->vval.v_number = -1;
6906 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006907 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 if (end != NULL && lv.ll_name != NULL)
6909 {
6910 if (*end != NUL)
6911 EMSG(_(e_trailing));
6912 else
6913 {
6914 if (lv.ll_tv == NULL)
6915 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006916 di = find_var(lv.ll_name, NULL, TRUE);
6917 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006918 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006919 /* Consider a variable locked when:
6920 * 1. the variable itself is locked
6921 * 2. the value of the variable is locked.
6922 * 3. the List or Dict value is locked.
6923 */
6924 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6925 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 }
6927 }
6928 else if (lv.ll_range)
6929 EMSG(_("E786: Range not allowed"));
6930 else if (lv.ll_newkey != NULL)
6931 EMSG2(_(e_dictkey), lv.ll_newkey);
6932 else if (lv.ll_list != NULL)
6933 /* List item. */
6934 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6935 else
6936 /* Dictionary item. */
6937 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6938 }
6939 }
6940
6941 clear_lval(&lv);
6942}
6943
6944#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6945/*
6946 * "isnan()" function
6947 */
6948 static void
6949f_isnan(typval_T *argvars, typval_T *rettv)
6950{
6951 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6952 && isnan(argvars[0].vval.v_float);
6953}
6954#endif
6955
6956/*
6957 * "items(dict)" function
6958 */
6959 static void
6960f_items(typval_T *argvars, typval_T *rettv)
6961{
6962 dict_list(argvars, rettv, 2);
6963}
6964
6965#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6966/*
6967 * Get the job from the argument.
6968 * Returns NULL if the job is invalid.
6969 */
6970 static job_T *
6971get_job_arg(typval_T *tv)
6972{
6973 job_T *job;
6974
6975 if (tv->v_type != VAR_JOB)
6976 {
6977 EMSG2(_(e_invarg2), get_tv_string(tv));
6978 return NULL;
6979 }
6980 job = tv->vval.v_job;
6981
6982 if (job == NULL)
6983 EMSG(_("E916: not a valid job"));
6984 return job;
6985}
6986
6987/*
6988 * "job_getchannel()" function
6989 */
6990 static void
6991f_job_getchannel(typval_T *argvars, typval_T *rettv)
6992{
6993 job_T *job = get_job_arg(&argvars[0]);
6994
6995 if (job != NULL)
6996 {
6997 rettv->v_type = VAR_CHANNEL;
6998 rettv->vval.v_channel = job->jv_channel;
6999 if (job->jv_channel != NULL)
7000 ++job->jv_channel->ch_refcount;
7001 }
7002}
7003
7004/*
7005 * "job_info()" function
7006 */
7007 static void
7008f_job_info(typval_T *argvars, typval_T *rettv)
7009{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007010 if (argvars[0].v_type != VAR_UNKNOWN)
7011 {
7012 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007013
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007014 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7015 job_info(job, rettv->vval.v_dict);
7016 }
7017 else if (rettv_list_alloc(rettv) == OK)
7018 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007019}
7020
7021/*
7022 * "job_setoptions()" function
7023 */
7024 static void
7025f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7026{
7027 job_T *job = get_job_arg(&argvars[0]);
7028 jobopt_T opt;
7029
7030 if (job == NULL)
7031 return;
7032 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007033 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 job_set_options(job, &opt);
7035 free_job_options(&opt);
7036}
7037
7038/*
7039 * "job_start()" function
7040 */
7041 static void
7042f_job_start(typval_T *argvars, typval_T *rettv)
7043{
7044 rettv->v_type = VAR_JOB;
7045 if (check_restricted() || check_secure())
7046 return;
Bram Moolenaar13568252018-03-16 20:46:58 +01007047 rettv->vval.v_job = job_start(argvars, NULL, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048}
7049
7050/*
7051 * "job_status()" function
7052 */
7053 static void
7054f_job_status(typval_T *argvars, typval_T *rettv)
7055{
7056 job_T *job = get_job_arg(&argvars[0]);
7057
7058 if (job != NULL)
7059 {
7060 rettv->v_type = VAR_STRING;
7061 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7062 }
7063}
7064
7065/*
7066 * "job_stop()" function
7067 */
7068 static void
7069f_job_stop(typval_T *argvars, typval_T *rettv)
7070{
7071 job_T *job = get_job_arg(&argvars[0]);
7072
7073 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007074 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075}
7076#endif
7077
7078/*
7079 * "join()" function
7080 */
7081 static void
7082f_join(typval_T *argvars, typval_T *rettv)
7083{
7084 garray_T ga;
7085 char_u *sep;
7086
7087 if (argvars[0].v_type != VAR_LIST)
7088 {
7089 EMSG(_(e_listreq));
7090 return;
7091 }
7092 if (argvars[0].vval.v_list == NULL)
7093 return;
7094 if (argvars[1].v_type == VAR_UNKNOWN)
7095 sep = (char_u *)" ";
7096 else
7097 sep = get_tv_string_chk(&argvars[1]);
7098
7099 rettv->v_type = VAR_STRING;
7100
7101 if (sep != NULL)
7102 {
7103 ga_init2(&ga, (int)sizeof(char), 80);
7104 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7105 ga_append(&ga, NUL);
7106 rettv->vval.v_string = (char_u *)ga.ga_data;
7107 }
7108 else
7109 rettv->vval.v_string = NULL;
7110}
7111
7112/*
7113 * "js_decode()" function
7114 */
7115 static void
7116f_js_decode(typval_T *argvars, typval_T *rettv)
7117{
7118 js_read_T reader;
7119
7120 reader.js_buf = get_tv_string(&argvars[0]);
7121 reader.js_fill = NULL;
7122 reader.js_used = 0;
7123 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7124 EMSG(_(e_invarg));
7125}
7126
7127/*
7128 * "js_encode()" function
7129 */
7130 static void
7131f_js_encode(typval_T *argvars, typval_T *rettv)
7132{
7133 rettv->v_type = VAR_STRING;
7134 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7135}
7136
7137/*
7138 * "json_decode()" function
7139 */
7140 static void
7141f_json_decode(typval_T *argvars, typval_T *rettv)
7142{
7143 js_read_T reader;
7144
7145 reader.js_buf = get_tv_string(&argvars[0]);
7146 reader.js_fill = NULL;
7147 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007148 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007149}
7150
7151/*
7152 * "json_encode()" function
7153 */
7154 static void
7155f_json_encode(typval_T *argvars, typval_T *rettv)
7156{
7157 rettv->v_type = VAR_STRING;
7158 rettv->vval.v_string = json_encode(&argvars[0], 0);
7159}
7160
7161/*
7162 * "keys()" function
7163 */
7164 static void
7165f_keys(typval_T *argvars, typval_T *rettv)
7166{
7167 dict_list(argvars, rettv, 0);
7168}
7169
7170/*
7171 * "last_buffer_nr()" function.
7172 */
7173 static void
7174f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7175{
7176 int n = 0;
7177 buf_T *buf;
7178
Bram Moolenaar29323592016-07-24 22:04:11 +02007179 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007180 if (n < buf->b_fnum)
7181 n = buf->b_fnum;
7182
7183 rettv->vval.v_number = n;
7184}
7185
7186/*
7187 * "len()" function
7188 */
7189 static void
7190f_len(typval_T *argvars, typval_T *rettv)
7191{
7192 switch (argvars[0].v_type)
7193 {
7194 case VAR_STRING:
7195 case VAR_NUMBER:
7196 rettv->vval.v_number = (varnumber_T)STRLEN(
7197 get_tv_string(&argvars[0]));
7198 break;
7199 case VAR_LIST:
7200 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7201 break;
7202 case VAR_DICT:
7203 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7204 break;
7205 case VAR_UNKNOWN:
7206 case VAR_SPECIAL:
7207 case VAR_FLOAT:
7208 case VAR_FUNC:
7209 case VAR_PARTIAL:
7210 case VAR_JOB:
7211 case VAR_CHANNEL:
7212 EMSG(_("E701: Invalid type for len()"));
7213 break;
7214 }
7215}
7216
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007217 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007218libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007219{
7220#ifdef FEAT_LIBCALL
7221 char_u *string_in;
7222 char_u **string_result;
7223 int nr_result;
7224#endif
7225
7226 rettv->v_type = type;
7227 if (type != VAR_NUMBER)
7228 rettv->vval.v_string = NULL;
7229
7230 if (check_restricted() || check_secure())
7231 return;
7232
7233#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007234 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007235 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7236 {
7237 string_in = NULL;
7238 if (argvars[2].v_type == VAR_STRING)
7239 string_in = argvars[2].vval.v_string;
7240 if (type == VAR_NUMBER)
7241 string_result = NULL;
7242 else
7243 string_result = &rettv->vval.v_string;
7244 if (mch_libcall(argvars[0].vval.v_string,
7245 argvars[1].vval.v_string,
7246 string_in,
7247 argvars[2].vval.v_number,
7248 string_result,
7249 &nr_result) == OK
7250 && type == VAR_NUMBER)
7251 rettv->vval.v_number = nr_result;
7252 }
7253#endif
7254}
7255
7256/*
7257 * "libcall()" function
7258 */
7259 static void
7260f_libcall(typval_T *argvars, typval_T *rettv)
7261{
7262 libcall_common(argvars, rettv, VAR_STRING);
7263}
7264
7265/*
7266 * "libcallnr()" function
7267 */
7268 static void
7269f_libcallnr(typval_T *argvars, typval_T *rettv)
7270{
7271 libcall_common(argvars, rettv, VAR_NUMBER);
7272}
7273
7274/*
7275 * "line(string)" function
7276 */
7277 static void
7278f_line(typval_T *argvars, typval_T *rettv)
7279{
7280 linenr_T lnum = 0;
7281 pos_T *fp;
7282 int fnum;
7283
7284 fp = var2fpos(&argvars[0], TRUE, &fnum);
7285 if (fp != NULL)
7286 lnum = fp->lnum;
7287 rettv->vval.v_number = lnum;
7288}
7289
7290/*
7291 * "line2byte(lnum)" function
7292 */
7293 static void
7294f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7295{
7296#ifndef FEAT_BYTEOFF
7297 rettv->vval.v_number = -1;
7298#else
7299 linenr_T lnum;
7300
7301 lnum = get_tv_lnum(argvars);
7302 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7303 rettv->vval.v_number = -1;
7304 else
7305 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7306 if (rettv->vval.v_number >= 0)
7307 ++rettv->vval.v_number;
7308#endif
7309}
7310
7311/*
7312 * "lispindent(lnum)" function
7313 */
7314 static void
7315f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7316{
7317#ifdef FEAT_LISP
7318 pos_T pos;
7319 linenr_T lnum;
7320
7321 pos = curwin->w_cursor;
7322 lnum = get_tv_lnum(argvars);
7323 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7324 {
7325 curwin->w_cursor.lnum = lnum;
7326 rettv->vval.v_number = get_lisp_indent();
7327 curwin->w_cursor = pos;
7328 }
7329 else
7330#endif
7331 rettv->vval.v_number = -1;
7332}
7333
7334/*
7335 * "localtime()" function
7336 */
7337 static void
7338f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7339{
7340 rettv->vval.v_number = (varnumber_T)time(NULL);
7341}
7342
7343static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7344
7345 static void
7346get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7347{
7348 char_u *keys;
7349 char_u *which;
7350 char_u buf[NUMBUFLEN];
7351 char_u *keys_buf = NULL;
7352 char_u *rhs;
7353 int mode;
7354 int abbr = FALSE;
7355 int get_dict = FALSE;
7356 mapblock_T *mp;
7357 int buffer_local;
7358
7359 /* return empty string for failure */
7360 rettv->v_type = VAR_STRING;
7361 rettv->vval.v_string = NULL;
7362
7363 keys = get_tv_string(&argvars[0]);
7364 if (*keys == NUL)
7365 return;
7366
7367 if (argvars[1].v_type != VAR_UNKNOWN)
7368 {
7369 which = get_tv_string_buf_chk(&argvars[1], buf);
7370 if (argvars[2].v_type != VAR_UNKNOWN)
7371 {
7372 abbr = (int)get_tv_number(&argvars[2]);
7373 if (argvars[3].v_type != VAR_UNKNOWN)
7374 get_dict = (int)get_tv_number(&argvars[3]);
7375 }
7376 }
7377 else
7378 which = (char_u *)"";
7379 if (which == NULL)
7380 return;
7381
7382 mode = get_map_mode(&which, 0);
7383
7384 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7385 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7386 vim_free(keys_buf);
7387
7388 if (!get_dict)
7389 {
7390 /* Return a string. */
7391 if (rhs != NULL)
7392 rettv->vval.v_string = str2special_save(rhs, FALSE);
7393
7394 }
7395 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7396 {
7397 /* Return a dictionary. */
7398 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7399 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7400 dict_T *dict = rettv->vval.v_dict;
7401
7402 dict_add_nr_str(dict, "lhs", 0L, lhs);
7403 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7404 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7405 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7406 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7407 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7408 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7409 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7410 dict_add_nr_str(dict, "mode", 0L, mapmode);
7411
7412 vim_free(lhs);
7413 vim_free(mapmode);
7414 }
7415}
7416
7417#ifdef FEAT_FLOAT
7418/*
7419 * "log()" function
7420 */
7421 static void
7422f_log(typval_T *argvars, typval_T *rettv)
7423{
7424 float_T f = 0.0;
7425
7426 rettv->v_type = VAR_FLOAT;
7427 if (get_float_arg(argvars, &f) == OK)
7428 rettv->vval.v_float = log(f);
7429 else
7430 rettv->vval.v_float = 0.0;
7431}
7432
7433/*
7434 * "log10()" function
7435 */
7436 static void
7437f_log10(typval_T *argvars, typval_T *rettv)
7438{
7439 float_T f = 0.0;
7440
7441 rettv->v_type = VAR_FLOAT;
7442 if (get_float_arg(argvars, &f) == OK)
7443 rettv->vval.v_float = log10(f);
7444 else
7445 rettv->vval.v_float = 0.0;
7446}
7447#endif
7448
7449#ifdef FEAT_LUA
7450/*
7451 * "luaeval()" function
7452 */
7453 static void
7454f_luaeval(typval_T *argvars, typval_T *rettv)
7455{
7456 char_u *str;
7457 char_u buf[NUMBUFLEN];
7458
7459 str = get_tv_string_buf(&argvars[0], buf);
7460 do_luaeval(str, argvars + 1, rettv);
7461}
7462#endif
7463
7464/*
7465 * "map()" function
7466 */
7467 static void
7468f_map(typval_T *argvars, typval_T *rettv)
7469{
7470 filter_map(argvars, rettv, TRUE);
7471}
7472
7473/*
7474 * "maparg()" function
7475 */
7476 static void
7477f_maparg(typval_T *argvars, typval_T *rettv)
7478{
7479 get_maparg(argvars, rettv, TRUE);
7480}
7481
7482/*
7483 * "mapcheck()" function
7484 */
7485 static void
7486f_mapcheck(typval_T *argvars, typval_T *rettv)
7487{
7488 get_maparg(argvars, rettv, FALSE);
7489}
7490
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007491typedef enum
7492{
7493 MATCH_END, /* matchend() */
7494 MATCH_MATCH, /* match() */
7495 MATCH_STR, /* matchstr() */
7496 MATCH_LIST, /* matchlist() */
7497 MATCH_POS /* matchstrpos() */
7498} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007499
7500 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007501find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502{
7503 char_u *str = NULL;
7504 long len = 0;
7505 char_u *expr = NULL;
7506 char_u *pat;
7507 regmatch_T regmatch;
7508 char_u patbuf[NUMBUFLEN];
7509 char_u strbuf[NUMBUFLEN];
7510 char_u *save_cpo;
7511 long start = 0;
7512 long nth = 1;
7513 colnr_T startcol = 0;
7514 int match = 0;
7515 list_T *l = NULL;
7516 listitem_T *li = NULL;
7517 long idx = 0;
7518 char_u *tofree = NULL;
7519
7520 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7521 save_cpo = p_cpo;
7522 p_cpo = (char_u *)"";
7523
7524 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007525 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007527 /* type MATCH_LIST: return empty list when there are no matches.
7528 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 if (rettv_list_alloc(rettv) == FAIL)
7530 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007531 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 && (list_append_string(rettv->vval.v_list,
7533 (char_u *)"", 0) == FAIL
7534 || list_append_number(rettv->vval.v_list,
7535 (varnumber_T)-1) == FAIL
7536 || list_append_number(rettv->vval.v_list,
7537 (varnumber_T)-1) == FAIL
7538 || list_append_number(rettv->vval.v_list,
7539 (varnumber_T)-1) == FAIL))
7540 {
7541 list_free(rettv->vval.v_list);
7542 rettv->vval.v_list = NULL;
7543 goto theend;
7544 }
7545 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007546 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007547 {
7548 rettv->v_type = VAR_STRING;
7549 rettv->vval.v_string = NULL;
7550 }
7551
7552 if (argvars[0].v_type == VAR_LIST)
7553 {
7554 if ((l = argvars[0].vval.v_list) == NULL)
7555 goto theend;
7556 li = l->lv_first;
7557 }
7558 else
7559 {
7560 expr = str = get_tv_string(&argvars[0]);
7561 len = (long)STRLEN(str);
7562 }
7563
7564 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7565 if (pat == NULL)
7566 goto theend;
7567
7568 if (argvars[2].v_type != VAR_UNKNOWN)
7569 {
7570 int error = FALSE;
7571
7572 start = (long)get_tv_number_chk(&argvars[2], &error);
7573 if (error)
7574 goto theend;
7575 if (l != NULL)
7576 {
7577 li = list_find(l, start);
7578 if (li == NULL)
7579 goto theend;
7580 idx = l->lv_idx; /* use the cached index */
7581 }
7582 else
7583 {
7584 if (start < 0)
7585 start = 0;
7586 if (start > len)
7587 goto theend;
7588 /* When "count" argument is there ignore matches before "start",
7589 * otherwise skip part of the string. Differs when pattern is "^"
7590 * or "\<". */
7591 if (argvars[3].v_type != VAR_UNKNOWN)
7592 startcol = start;
7593 else
7594 {
7595 str += start;
7596 len -= start;
7597 }
7598 }
7599
7600 if (argvars[3].v_type != VAR_UNKNOWN)
7601 nth = (long)get_tv_number_chk(&argvars[3], &error);
7602 if (error)
7603 goto theend;
7604 }
7605
7606 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7607 if (regmatch.regprog != NULL)
7608 {
7609 regmatch.rm_ic = p_ic;
7610
7611 for (;;)
7612 {
7613 if (l != NULL)
7614 {
7615 if (li == NULL)
7616 {
7617 match = FALSE;
7618 break;
7619 }
7620 vim_free(tofree);
7621 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7622 if (str == NULL)
7623 break;
7624 }
7625
7626 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7627
7628 if (match && --nth <= 0)
7629 break;
7630 if (l == NULL && !match)
7631 break;
7632
7633 /* Advance to just after the match. */
7634 if (l != NULL)
7635 {
7636 li = li->li_next;
7637 ++idx;
7638 }
7639 else
7640 {
7641#ifdef FEAT_MBYTE
7642 startcol = (colnr_T)(regmatch.startp[0]
7643 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7644#else
7645 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7646#endif
7647 if (startcol > (colnr_T)len
7648 || str + startcol <= regmatch.startp[0])
7649 {
7650 match = FALSE;
7651 break;
7652 }
7653 }
7654 }
7655
7656 if (match)
7657 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007658 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659 {
7660 listitem_T *li1 = rettv->vval.v_list->lv_first;
7661 listitem_T *li2 = li1->li_next;
7662 listitem_T *li3 = li2->li_next;
7663 listitem_T *li4 = li3->li_next;
7664
7665 vim_free(li1->li_tv.vval.v_string);
7666 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7667 (int)(regmatch.endp[0] - regmatch.startp[0]));
7668 li3->li_tv.vval.v_number =
7669 (varnumber_T)(regmatch.startp[0] - expr);
7670 li4->li_tv.vval.v_number =
7671 (varnumber_T)(regmatch.endp[0] - expr);
7672 if (l != NULL)
7673 li2->li_tv.vval.v_number = (varnumber_T)idx;
7674 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007675 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007676 {
7677 int i;
7678
7679 /* return list with matched string and submatches */
7680 for (i = 0; i < NSUBEXP; ++i)
7681 {
7682 if (regmatch.endp[i] == NULL)
7683 {
7684 if (list_append_string(rettv->vval.v_list,
7685 (char_u *)"", 0) == FAIL)
7686 break;
7687 }
7688 else if (list_append_string(rettv->vval.v_list,
7689 regmatch.startp[i],
7690 (int)(regmatch.endp[i] - regmatch.startp[i]))
7691 == FAIL)
7692 break;
7693 }
7694 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007695 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007696 {
7697 /* return matched string */
7698 if (l != NULL)
7699 copy_tv(&li->li_tv, rettv);
7700 else
7701 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7702 (int)(regmatch.endp[0] - regmatch.startp[0]));
7703 }
7704 else if (l != NULL)
7705 rettv->vval.v_number = idx;
7706 else
7707 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007708 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007709 rettv->vval.v_number =
7710 (varnumber_T)(regmatch.startp[0] - str);
7711 else
7712 rettv->vval.v_number =
7713 (varnumber_T)(regmatch.endp[0] - str);
7714 rettv->vval.v_number += (varnumber_T)(str - expr);
7715 }
7716 }
7717 vim_regfree(regmatch.regprog);
7718 }
7719
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007720theend:
7721 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722 /* matchstrpos() without a list: drop the second item. */
7723 listitem_remove(rettv->vval.v_list,
7724 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725 vim_free(tofree);
7726 p_cpo = save_cpo;
7727}
7728
7729/*
7730 * "match()" function
7731 */
7732 static void
7733f_match(typval_T *argvars, typval_T *rettv)
7734{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007735 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007736}
7737
7738/*
7739 * "matchadd()" function
7740 */
7741 static void
7742f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7743{
7744#ifdef FEAT_SEARCH_EXTRA
7745 char_u buf[NUMBUFLEN];
7746 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7747 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7748 int prio = 10; /* default priority */
7749 int id = -1;
7750 int error = FALSE;
7751 char_u *conceal_char = NULL;
7752
7753 rettv->vval.v_number = -1;
7754
7755 if (grp == NULL || pat == NULL)
7756 return;
7757 if (argvars[2].v_type != VAR_UNKNOWN)
7758 {
7759 prio = (int)get_tv_number_chk(&argvars[2], &error);
7760 if (argvars[3].v_type != VAR_UNKNOWN)
7761 {
7762 id = (int)get_tv_number_chk(&argvars[3], &error);
7763 if (argvars[4].v_type != VAR_UNKNOWN)
7764 {
7765 if (argvars[4].v_type != VAR_DICT)
7766 {
7767 EMSG(_(e_dictreq));
7768 return;
7769 }
7770 if (dict_find(argvars[4].vval.v_dict,
7771 (char_u *)"conceal", -1) != NULL)
7772 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7773 (char_u *)"conceal", FALSE);
7774 }
7775 }
7776 }
7777 if (error == TRUE)
7778 return;
7779 if (id >= 1 && id <= 3)
7780 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007781 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007782 return;
7783 }
7784
7785 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7786 conceal_char);
7787#endif
7788}
7789
7790/*
7791 * "matchaddpos()" function
7792 */
7793 static void
7794f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7795{
7796#ifdef FEAT_SEARCH_EXTRA
7797 char_u buf[NUMBUFLEN];
7798 char_u *group;
7799 int prio = 10;
7800 int id = -1;
7801 int error = FALSE;
7802 list_T *l;
7803 char_u *conceal_char = NULL;
7804
7805 rettv->vval.v_number = -1;
7806
7807 group = get_tv_string_buf_chk(&argvars[0], buf);
7808 if (group == NULL)
7809 return;
7810
7811 if (argvars[1].v_type != VAR_LIST)
7812 {
7813 EMSG2(_(e_listarg), "matchaddpos()");
7814 return;
7815 }
7816 l = argvars[1].vval.v_list;
7817 if (l == NULL)
7818 return;
7819
7820 if (argvars[2].v_type != VAR_UNKNOWN)
7821 {
7822 prio = (int)get_tv_number_chk(&argvars[2], &error);
7823 if (argvars[3].v_type != VAR_UNKNOWN)
7824 {
7825 id = (int)get_tv_number_chk(&argvars[3], &error);
7826 if (argvars[4].v_type != VAR_UNKNOWN)
7827 {
7828 if (argvars[4].v_type != VAR_DICT)
7829 {
7830 EMSG(_(e_dictreq));
7831 return;
7832 }
7833 if (dict_find(argvars[4].vval.v_dict,
7834 (char_u *)"conceal", -1) != NULL)
7835 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7836 (char_u *)"conceal", FALSE);
7837 }
7838 }
7839 }
7840 if (error == TRUE)
7841 return;
7842
7843 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7844 if (id == 1 || id == 2)
7845 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007846 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007847 return;
7848 }
7849
7850 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7851 conceal_char);
7852#endif
7853}
7854
7855/*
7856 * "matcharg()" function
7857 */
7858 static void
7859f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7860{
7861 if (rettv_list_alloc(rettv) == OK)
7862 {
7863#ifdef FEAT_SEARCH_EXTRA
7864 int id = (int)get_tv_number(&argvars[0]);
7865 matchitem_T *m;
7866
7867 if (id >= 1 && id <= 3)
7868 {
7869 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7870 {
7871 list_append_string(rettv->vval.v_list,
7872 syn_id2name(m->hlg_id), -1);
7873 list_append_string(rettv->vval.v_list, m->pattern, -1);
7874 }
7875 else
7876 {
7877 list_append_string(rettv->vval.v_list, NULL, -1);
7878 list_append_string(rettv->vval.v_list, NULL, -1);
7879 }
7880 }
7881#endif
7882 }
7883}
7884
7885/*
7886 * "matchdelete()" function
7887 */
7888 static void
7889f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7890{
7891#ifdef FEAT_SEARCH_EXTRA
7892 rettv->vval.v_number = match_delete(curwin,
7893 (int)get_tv_number(&argvars[0]), TRUE);
7894#endif
7895}
7896
7897/*
7898 * "matchend()" function
7899 */
7900 static void
7901f_matchend(typval_T *argvars, typval_T *rettv)
7902{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007903 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904}
7905
7906/*
7907 * "matchlist()" function
7908 */
7909 static void
7910f_matchlist(typval_T *argvars, typval_T *rettv)
7911{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007912 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007913}
7914
7915/*
7916 * "matchstr()" function
7917 */
7918 static void
7919f_matchstr(typval_T *argvars, typval_T *rettv)
7920{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007921 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007922}
7923
7924/*
7925 * "matchstrpos()" function
7926 */
7927 static void
7928f_matchstrpos(typval_T *argvars, typval_T *rettv)
7929{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007930 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931}
7932
7933static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7934
7935 static void
7936max_min(typval_T *argvars, typval_T *rettv, int domax)
7937{
7938 varnumber_T n = 0;
7939 varnumber_T i;
7940 int error = FALSE;
7941
7942 if (argvars[0].v_type == VAR_LIST)
7943 {
7944 list_T *l;
7945 listitem_T *li;
7946
7947 l = argvars[0].vval.v_list;
7948 if (l != NULL)
7949 {
7950 li = l->lv_first;
7951 if (li != NULL)
7952 {
7953 n = get_tv_number_chk(&li->li_tv, &error);
7954 for (;;)
7955 {
7956 li = li->li_next;
7957 if (li == NULL)
7958 break;
7959 i = get_tv_number_chk(&li->li_tv, &error);
7960 if (domax ? i > n : i < n)
7961 n = i;
7962 }
7963 }
7964 }
7965 }
7966 else if (argvars[0].v_type == VAR_DICT)
7967 {
7968 dict_T *d;
7969 int first = TRUE;
7970 hashitem_T *hi;
7971 int todo;
7972
7973 d = argvars[0].vval.v_dict;
7974 if (d != NULL)
7975 {
7976 todo = (int)d->dv_hashtab.ht_used;
7977 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7978 {
7979 if (!HASHITEM_EMPTY(hi))
7980 {
7981 --todo;
7982 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7983 if (first)
7984 {
7985 n = i;
7986 first = FALSE;
7987 }
7988 else if (domax ? i > n : i < n)
7989 n = i;
7990 }
7991 }
7992 }
7993 }
7994 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007995 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007996 rettv->vval.v_number = error ? 0 : n;
7997}
7998
7999/*
8000 * "max()" function
8001 */
8002 static void
8003f_max(typval_T *argvars, typval_T *rettv)
8004{
8005 max_min(argvars, rettv, TRUE);
8006}
8007
8008/*
8009 * "min()" function
8010 */
8011 static void
8012f_min(typval_T *argvars, typval_T *rettv)
8013{
8014 max_min(argvars, rettv, FALSE);
8015}
8016
8017static int mkdir_recurse(char_u *dir, int prot);
8018
8019/*
8020 * Create the directory in which "dir" is located, and higher levels when
8021 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008022 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023 */
8024 static int
8025mkdir_recurse(char_u *dir, int prot)
8026{
8027 char_u *p;
8028 char_u *updir;
8029 int r = FAIL;
8030
8031 /* Get end of directory name in "dir".
8032 * We're done when it's "/" or "c:/". */
8033 p = gettail_sep(dir);
8034 if (p <= get_past_head(dir))
8035 return OK;
8036
8037 /* If the directory exists we're done. Otherwise: create it.*/
8038 updir = vim_strnsave(dir, (int)(p - dir));
8039 if (updir == NULL)
8040 return FAIL;
8041 if (mch_isdir(updir))
8042 r = OK;
8043 else if (mkdir_recurse(updir, prot) == OK)
8044 r = vim_mkdir_emsg(updir, prot);
8045 vim_free(updir);
8046 return r;
8047}
8048
8049#ifdef vim_mkdir
8050/*
8051 * "mkdir()" function
8052 */
8053 static void
8054f_mkdir(typval_T *argvars, typval_T *rettv)
8055{
8056 char_u *dir;
8057 char_u buf[NUMBUFLEN];
8058 int prot = 0755;
8059
8060 rettv->vval.v_number = FAIL;
8061 if (check_restricted() || check_secure())
8062 return;
8063
8064 dir = get_tv_string_buf(&argvars[0], buf);
8065 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008066 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008067
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008068 if (*gettail(dir) == NUL)
8069 /* remove trailing slashes */
8070 *gettail_sep(dir) = NUL;
8071
8072 if (argvars[1].v_type != VAR_UNKNOWN)
8073 {
8074 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008075 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008076 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8077 if (prot == -1)
8078 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008080 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8081 {
8082 if (mch_isdir(dir))
8083 {
8084 /* With the "p" flag it's OK if the dir already exists. */
8085 rettv->vval.v_number = OK;
8086 return;
8087 }
8088 mkdir_recurse(dir, prot);
8089 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008090 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008091 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008092}
8093#endif
8094
8095/*
8096 * "mode()" function
8097 */
8098 static void
8099f_mode(typval_T *argvars, typval_T *rettv)
8100{
8101 char_u buf[3];
8102
8103 buf[1] = NUL;
8104 buf[2] = NUL;
8105
8106 if (time_for_testing == 93784)
8107 {
8108 /* Testing the two-character code. */
8109 buf[0] = 'x';
8110 buf[1] = '!';
8111 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008112#ifdef FEAT_TERMINAL
8113 else if (term_use_loop())
8114 buf[0] = 't';
8115#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116 else if (VIsual_active)
8117 {
8118 if (VIsual_select)
8119 buf[0] = VIsual_mode + 's' - 'v';
8120 else
8121 buf[0] = VIsual_mode;
8122 }
8123 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8124 || State == CONFIRM)
8125 {
8126 buf[0] = 'r';
8127 if (State == ASKMORE)
8128 buf[1] = 'm';
8129 else if (State == CONFIRM)
8130 buf[1] = '?';
8131 }
8132 else if (State == EXTERNCMD)
8133 buf[0] = '!';
8134 else if (State & INSERT)
8135 {
8136#ifdef FEAT_VREPLACE
8137 if (State & VREPLACE_FLAG)
8138 {
8139 buf[0] = 'R';
8140 buf[1] = 'v';
8141 }
8142 else
8143#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01008144 {
8145 if (State & REPLACE_FLAG)
8146 buf[0] = 'R';
8147 else
8148 buf[0] = 'i';
8149#ifdef FEAT_INS_EXPAND
8150 if (ins_compl_active())
8151 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008152 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008153 buf[1] = 'x';
8154#endif
8155 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008156 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008157 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158 {
8159 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008160 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008162 else if (exmode_active == EXMODE_NORMAL)
8163 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164 }
8165 else
8166 {
8167 buf[0] = 'n';
8168 if (finish_op)
8169 buf[1] = 'o';
8170 }
8171
8172 /* Clear out the minor mode when the argument is not a non-zero number or
8173 * non-empty string. */
8174 if (!non_zero_arg(&argvars[0]))
8175 buf[1] = NUL;
8176
8177 rettv->vval.v_string = vim_strsave(buf);
8178 rettv->v_type = VAR_STRING;
8179}
8180
8181#if defined(FEAT_MZSCHEME) || defined(PROTO)
8182/*
8183 * "mzeval()" function
8184 */
8185 static void
8186f_mzeval(typval_T *argvars, typval_T *rettv)
8187{
8188 char_u *str;
8189 char_u buf[NUMBUFLEN];
8190
8191 str = get_tv_string_buf(&argvars[0], buf);
8192 do_mzeval(str, rettv);
8193}
8194
8195 void
8196mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8197{
8198 typval_T argvars[3];
8199
8200 argvars[0].v_type = VAR_STRING;
8201 argvars[0].vval.v_string = name;
8202 copy_tv(args, &argvars[1]);
8203 argvars[2].v_type = VAR_UNKNOWN;
8204 f_call(argvars, rettv);
8205 clear_tv(&argvars[1]);
8206}
8207#endif
8208
8209/*
8210 * "nextnonblank()" function
8211 */
8212 static void
8213f_nextnonblank(typval_T *argvars, typval_T *rettv)
8214{
8215 linenr_T lnum;
8216
8217 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8218 {
8219 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8220 {
8221 lnum = 0;
8222 break;
8223 }
8224 if (*skipwhite(ml_get(lnum)) != NUL)
8225 break;
8226 }
8227 rettv->vval.v_number = lnum;
8228}
8229
8230/*
8231 * "nr2char()" function
8232 */
8233 static void
8234f_nr2char(typval_T *argvars, typval_T *rettv)
8235{
8236 char_u buf[NUMBUFLEN];
8237
8238#ifdef FEAT_MBYTE
8239 if (has_mbyte)
8240 {
8241 int utf8 = 0;
8242
8243 if (argvars[1].v_type != VAR_UNKNOWN)
8244 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8245 if (utf8)
8246 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8247 else
8248 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8249 }
8250 else
8251#endif
8252 {
8253 buf[0] = (char_u)get_tv_number(&argvars[0]);
8254 buf[1] = NUL;
8255 }
8256 rettv->v_type = VAR_STRING;
8257 rettv->vval.v_string = vim_strsave(buf);
8258}
8259
8260/*
8261 * "or(expr, expr)" function
8262 */
8263 static void
8264f_or(typval_T *argvars, typval_T *rettv)
8265{
8266 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8267 | get_tv_number_chk(&argvars[1], NULL);
8268}
8269
8270/*
8271 * "pathshorten()" function
8272 */
8273 static void
8274f_pathshorten(typval_T *argvars, typval_T *rettv)
8275{
8276 char_u *p;
8277
8278 rettv->v_type = VAR_STRING;
8279 p = get_tv_string_chk(&argvars[0]);
8280 if (p == NULL)
8281 rettv->vval.v_string = NULL;
8282 else
8283 {
8284 p = vim_strsave(p);
8285 rettv->vval.v_string = p;
8286 if (p != NULL)
8287 shorten_dir(p);
8288 }
8289}
8290
8291#ifdef FEAT_PERL
8292/*
8293 * "perleval()" function
8294 */
8295 static void
8296f_perleval(typval_T *argvars, typval_T *rettv)
8297{
8298 char_u *str;
8299 char_u buf[NUMBUFLEN];
8300
8301 str = get_tv_string_buf(&argvars[0], buf);
8302 do_perleval(str, rettv);
8303}
8304#endif
8305
8306#ifdef FEAT_FLOAT
8307/*
8308 * "pow()" function
8309 */
8310 static void
8311f_pow(typval_T *argvars, typval_T *rettv)
8312{
8313 float_T fx = 0.0, fy = 0.0;
8314
8315 rettv->v_type = VAR_FLOAT;
8316 if (get_float_arg(argvars, &fx) == OK
8317 && get_float_arg(&argvars[1], &fy) == OK)
8318 rettv->vval.v_float = pow(fx, fy);
8319 else
8320 rettv->vval.v_float = 0.0;
8321}
8322#endif
8323
8324/*
8325 * "prevnonblank()" function
8326 */
8327 static void
8328f_prevnonblank(typval_T *argvars, typval_T *rettv)
8329{
8330 linenr_T lnum;
8331
8332 lnum = get_tv_lnum(argvars);
8333 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8334 lnum = 0;
8335 else
8336 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8337 --lnum;
8338 rettv->vval.v_number = lnum;
8339}
8340
8341/* This dummy va_list is here because:
8342 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8343 * - locally in the function results in a "used before set" warning
8344 * - using va_start() to initialize it gives "function with fixed args" error */
8345static va_list ap;
8346
8347/*
8348 * "printf()" function
8349 */
8350 static void
8351f_printf(typval_T *argvars, typval_T *rettv)
8352{
8353 char_u buf[NUMBUFLEN];
8354 int len;
8355 char_u *s;
8356 int saved_did_emsg = did_emsg;
8357 char *fmt;
8358
8359 rettv->v_type = VAR_STRING;
8360 rettv->vval.v_string = NULL;
8361
8362 /* Get the required length, allocate the buffer and do it for real. */
8363 did_emsg = FALSE;
8364 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008365 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008366 if (!did_emsg)
8367 {
8368 s = alloc(len + 1);
8369 if (s != NULL)
8370 {
8371 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008372 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8373 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374 }
8375 }
8376 did_emsg |= saved_did_emsg;
8377}
8378
8379/*
8380 * "pumvisible()" function
8381 */
8382 static void
8383f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8384{
8385#ifdef FEAT_INS_EXPAND
8386 if (pum_visible())
8387 rettv->vval.v_number = 1;
8388#endif
8389}
8390
8391#ifdef FEAT_PYTHON3
8392/*
8393 * "py3eval()" function
8394 */
8395 static void
8396f_py3eval(typval_T *argvars, typval_T *rettv)
8397{
8398 char_u *str;
8399 char_u buf[NUMBUFLEN];
8400
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008401 if (p_pyx == 0)
8402 p_pyx = 3;
8403
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 str = get_tv_string_buf(&argvars[0], buf);
8405 do_py3eval(str, rettv);
8406}
8407#endif
8408
8409#ifdef FEAT_PYTHON
8410/*
8411 * "pyeval()" function
8412 */
8413 static void
8414f_pyeval(typval_T *argvars, typval_T *rettv)
8415{
8416 char_u *str;
8417 char_u buf[NUMBUFLEN];
8418
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008419 if (p_pyx == 0)
8420 p_pyx = 2;
8421
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008422 str = get_tv_string_buf(&argvars[0], buf);
8423 do_pyeval(str, rettv);
8424}
8425#endif
8426
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008427#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8428/*
8429 * "pyxeval()" function
8430 */
8431 static void
8432f_pyxeval(typval_T *argvars, typval_T *rettv)
8433{
8434# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8435 init_pyxversion();
8436 if (p_pyx == 2)
8437 f_pyeval(argvars, rettv);
8438 else
8439 f_py3eval(argvars, rettv);
8440# elif defined(FEAT_PYTHON)
8441 f_pyeval(argvars, rettv);
8442# elif defined(FEAT_PYTHON3)
8443 f_py3eval(argvars, rettv);
8444# endif
8445}
8446#endif
8447
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448/*
8449 * "range()" function
8450 */
8451 static void
8452f_range(typval_T *argvars, typval_T *rettv)
8453{
8454 varnumber_T start;
8455 varnumber_T end;
8456 varnumber_T stride = 1;
8457 varnumber_T i;
8458 int error = FALSE;
8459
8460 start = get_tv_number_chk(&argvars[0], &error);
8461 if (argvars[1].v_type == VAR_UNKNOWN)
8462 {
8463 end = start - 1;
8464 start = 0;
8465 }
8466 else
8467 {
8468 end = get_tv_number_chk(&argvars[1], &error);
8469 if (argvars[2].v_type != VAR_UNKNOWN)
8470 stride = get_tv_number_chk(&argvars[2], &error);
8471 }
8472
8473 if (error)
8474 return; /* type error; errmsg already given */
8475 if (stride == 0)
8476 EMSG(_("E726: Stride is zero"));
8477 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8478 EMSG(_("E727: Start past end"));
8479 else
8480 {
8481 if (rettv_list_alloc(rettv) == OK)
8482 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8483 if (list_append_number(rettv->vval.v_list,
8484 (varnumber_T)i) == FAIL)
8485 break;
8486 }
8487}
8488
8489/*
8490 * "readfile()" function
8491 */
8492 static void
8493f_readfile(typval_T *argvars, typval_T *rettv)
8494{
8495 int binary = FALSE;
8496 int failed = FALSE;
8497 char_u *fname;
8498 FILE *fd;
8499 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8500 int io_size = sizeof(buf);
8501 int readlen; /* size of last fread() */
8502 char_u *prev = NULL; /* previously read bytes, if any */
8503 long prevlen = 0; /* length of data in prev */
8504 long prevsize = 0; /* size of prev buffer */
8505 long maxline = MAXLNUM;
8506 long cnt = 0;
8507 char_u *p; /* position in buf */
8508 char_u *start; /* start of current line */
8509
8510 if (argvars[1].v_type != VAR_UNKNOWN)
8511 {
8512 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8513 binary = TRUE;
8514 if (argvars[2].v_type != VAR_UNKNOWN)
8515 maxline = (long)get_tv_number(&argvars[2]);
8516 }
8517
8518 if (rettv_list_alloc(rettv) == FAIL)
8519 return;
8520
8521 /* Always open the file in binary mode, library functions have a mind of
8522 * their own about CR-LF conversion. */
8523 fname = get_tv_string(&argvars[0]);
8524 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8525 {
8526 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8527 return;
8528 }
8529
8530 while (cnt < maxline || maxline < 0)
8531 {
8532 readlen = (int)fread(buf, 1, io_size, fd);
8533
8534 /* This for loop processes what was read, but is also entered at end
8535 * of file so that either:
8536 * - an incomplete line gets written
8537 * - a "binary" file gets an empty line at the end if it ends in a
8538 * newline. */
8539 for (p = buf, start = buf;
8540 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8541 ++p)
8542 {
8543 if (*p == '\n' || readlen <= 0)
8544 {
8545 listitem_T *li;
8546 char_u *s = NULL;
8547 long_u len = p - start;
8548
8549 /* Finished a line. Remove CRs before NL. */
8550 if (readlen > 0 && !binary)
8551 {
8552 while (len > 0 && start[len - 1] == '\r')
8553 --len;
8554 /* removal may cross back to the "prev" string */
8555 if (len == 0)
8556 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8557 --prevlen;
8558 }
8559 if (prevlen == 0)
8560 s = vim_strnsave(start, (int)len);
8561 else
8562 {
8563 /* Change "prev" buffer to be the right size. This way
8564 * the bytes are only copied once, and very long lines are
8565 * allocated only once. */
8566 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8567 {
8568 mch_memmove(s + prevlen, start, len);
8569 s[prevlen + len] = NUL;
8570 prev = NULL; /* the list will own the string */
8571 prevlen = prevsize = 0;
8572 }
8573 }
8574 if (s == NULL)
8575 {
8576 do_outofmem_msg((long_u) prevlen + len + 1);
8577 failed = TRUE;
8578 break;
8579 }
8580
8581 if ((li = listitem_alloc()) == NULL)
8582 {
8583 vim_free(s);
8584 failed = TRUE;
8585 break;
8586 }
8587 li->li_tv.v_type = VAR_STRING;
8588 li->li_tv.v_lock = 0;
8589 li->li_tv.vval.v_string = s;
8590 list_append(rettv->vval.v_list, li);
8591
8592 start = p + 1; /* step over newline */
8593 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8594 break;
8595 }
8596 else if (*p == NUL)
8597 *p = '\n';
8598#ifdef FEAT_MBYTE
8599 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8600 * when finding the BF and check the previous two bytes. */
8601 else if (*p == 0xbf && enc_utf8 && !binary)
8602 {
8603 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8604 * + 1, these may be in the "prev" string. */
8605 char_u back1 = p >= buf + 1 ? p[-1]
8606 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8607 char_u back2 = p >= buf + 2 ? p[-2]
8608 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8609 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8610
8611 if (back2 == 0xef && back1 == 0xbb)
8612 {
8613 char_u *dest = p - 2;
8614
8615 /* Usually a BOM is at the beginning of a file, and so at
8616 * the beginning of a line; then we can just step over it.
8617 */
8618 if (start == dest)
8619 start = p + 1;
8620 else
8621 {
8622 /* have to shuffle buf to close gap */
8623 int adjust_prevlen = 0;
8624
8625 if (dest < buf)
8626 {
8627 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8628 dest = buf;
8629 }
8630 if (readlen > p - buf + 1)
8631 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8632 readlen -= 3 - adjust_prevlen;
8633 prevlen -= adjust_prevlen;
8634 p = dest - 1;
8635 }
8636 }
8637 }
8638#endif
8639 } /* for */
8640
8641 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8642 break;
8643 if (start < p)
8644 {
8645 /* There's part of a line in buf, store it in "prev". */
8646 if (p - start + prevlen >= prevsize)
8647 {
8648 /* need bigger "prev" buffer */
8649 char_u *newprev;
8650
8651 /* A common use case is ordinary text files and "prev" gets a
8652 * fragment of a line, so the first allocation is made
8653 * small, to avoid repeatedly 'allocing' large and
8654 * 'reallocing' small. */
8655 if (prevsize == 0)
8656 prevsize = (long)(p - start);
8657 else
8658 {
8659 long grow50pc = (prevsize * 3) / 2;
8660 long growmin = (long)((p - start) * 2 + prevlen);
8661 prevsize = grow50pc > growmin ? grow50pc : growmin;
8662 }
8663 newprev = prev == NULL ? alloc(prevsize)
8664 : vim_realloc(prev, prevsize);
8665 if (newprev == NULL)
8666 {
8667 do_outofmem_msg((long_u)prevsize);
8668 failed = TRUE;
8669 break;
8670 }
8671 prev = newprev;
8672 }
8673 /* Add the line part to end of "prev". */
8674 mch_memmove(prev + prevlen, start, p - start);
8675 prevlen += (long)(p - start);
8676 }
8677 } /* while */
8678
8679 /*
8680 * For a negative line count use only the lines at the end of the file,
8681 * free the rest.
8682 */
8683 if (!failed && maxline < 0)
8684 while (cnt > -maxline)
8685 {
8686 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8687 --cnt;
8688 }
8689
8690 if (failed)
8691 {
8692 list_free(rettv->vval.v_list);
8693 /* readfile doc says an empty list is returned on error */
8694 rettv->vval.v_list = list_alloc();
8695 }
8696
8697 vim_free(prev);
8698 fclose(fd);
8699}
8700
8701#if defined(FEAT_RELTIME)
8702static int list2proftime(typval_T *arg, proftime_T *tm);
8703
8704/*
8705 * Convert a List to proftime_T.
8706 * Return FAIL when there is something wrong.
8707 */
8708 static int
8709list2proftime(typval_T *arg, proftime_T *tm)
8710{
8711 long n1, n2;
8712 int error = FALSE;
8713
8714 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8715 || arg->vval.v_list->lv_len != 2)
8716 return FAIL;
8717 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8718 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8719# ifdef WIN3264
8720 tm->HighPart = n1;
8721 tm->LowPart = n2;
8722# else
8723 tm->tv_sec = n1;
8724 tm->tv_usec = n2;
8725# endif
8726 return error ? FAIL : OK;
8727}
8728#endif /* FEAT_RELTIME */
8729
8730/*
8731 * "reltime()" function
8732 */
8733 static void
8734f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8735{
8736#ifdef FEAT_RELTIME
8737 proftime_T res;
8738 proftime_T start;
8739
8740 if (argvars[0].v_type == VAR_UNKNOWN)
8741 {
8742 /* No arguments: get current time. */
8743 profile_start(&res);
8744 }
8745 else if (argvars[1].v_type == VAR_UNKNOWN)
8746 {
8747 if (list2proftime(&argvars[0], &res) == FAIL)
8748 return;
8749 profile_end(&res);
8750 }
8751 else
8752 {
8753 /* Two arguments: compute the difference. */
8754 if (list2proftime(&argvars[0], &start) == FAIL
8755 || list2proftime(&argvars[1], &res) == FAIL)
8756 return;
8757 profile_sub(&res, &start);
8758 }
8759
8760 if (rettv_list_alloc(rettv) == OK)
8761 {
8762 long n1, n2;
8763
8764# ifdef WIN3264
8765 n1 = res.HighPart;
8766 n2 = res.LowPart;
8767# else
8768 n1 = res.tv_sec;
8769 n2 = res.tv_usec;
8770# endif
8771 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8772 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8773 }
8774#endif
8775}
8776
8777#ifdef FEAT_FLOAT
8778/*
8779 * "reltimefloat()" function
8780 */
8781 static void
8782f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8783{
8784# ifdef FEAT_RELTIME
8785 proftime_T tm;
8786# endif
8787
8788 rettv->v_type = VAR_FLOAT;
8789 rettv->vval.v_float = 0;
8790# ifdef FEAT_RELTIME
8791 if (list2proftime(&argvars[0], &tm) == OK)
8792 rettv->vval.v_float = profile_float(&tm);
8793# endif
8794}
8795#endif
8796
8797/*
8798 * "reltimestr()" function
8799 */
8800 static void
8801f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8802{
8803#ifdef FEAT_RELTIME
8804 proftime_T tm;
8805#endif
8806
8807 rettv->v_type = VAR_STRING;
8808 rettv->vval.v_string = NULL;
8809#ifdef FEAT_RELTIME
8810 if (list2proftime(&argvars[0], &tm) == OK)
8811 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8812#endif
8813}
8814
8815#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8816static void make_connection(void);
8817static int check_connection(void);
8818
8819 static void
8820make_connection(void)
8821{
8822 if (X_DISPLAY == NULL
8823# ifdef FEAT_GUI
8824 && !gui.in_use
8825# endif
8826 )
8827 {
8828 x_force_connect = TRUE;
8829 setup_term_clip();
8830 x_force_connect = FALSE;
8831 }
8832}
8833
8834 static int
8835check_connection(void)
8836{
8837 make_connection();
8838 if (X_DISPLAY == NULL)
8839 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008840 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008841 return FAIL;
8842 }
8843 return OK;
8844}
8845#endif
8846
8847#ifdef FEAT_CLIENTSERVER
8848 static void
8849remote_common(typval_T *argvars, typval_T *rettv, int expr)
8850{
8851 char_u *server_name;
8852 char_u *keys;
8853 char_u *r = NULL;
8854 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008855 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008856# ifdef WIN32
8857 HWND w;
8858# else
8859 Window w;
8860# endif
8861
8862 if (check_restricted() || check_secure())
8863 return;
8864
8865# ifdef FEAT_X11
8866 if (check_connection() == FAIL)
8867 return;
8868# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008869 if (argvars[2].v_type != VAR_UNKNOWN
8870 && argvars[3].v_type != VAR_UNKNOWN)
8871 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008872
8873 server_name = get_tv_string_chk(&argvars[0]);
8874 if (server_name == NULL)
8875 return; /* type error; errmsg already given */
8876 keys = get_tv_string_buf(&argvars[1], buf);
8877# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008878 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008879# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008880 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8881 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008882# endif
8883 {
8884 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008885 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008886 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008887 vim_free(r);
8888 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008889 else
8890 EMSG2(_("E241: Unable to send to %s"), server_name);
8891 return;
8892 }
8893
8894 rettv->vval.v_string = r;
8895
8896 if (argvars[2].v_type != VAR_UNKNOWN)
8897 {
8898 dictitem_T v;
8899 char_u str[30];
8900 char_u *idvar;
8901
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008903 if (idvar != NULL && *idvar != NUL)
8904 {
8905 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8906 v.di_tv.v_type = VAR_STRING;
8907 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008908 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008909 vim_free(v.di_tv.vval.v_string);
8910 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008911 }
8912}
8913#endif
8914
8915/*
8916 * "remote_expr()" function
8917 */
8918 static void
8919f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8920{
8921 rettv->v_type = VAR_STRING;
8922 rettv->vval.v_string = NULL;
8923#ifdef FEAT_CLIENTSERVER
8924 remote_common(argvars, rettv, TRUE);
8925#endif
8926}
8927
8928/*
8929 * "remote_foreground()" function
8930 */
8931 static void
8932f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8933{
8934#ifdef FEAT_CLIENTSERVER
8935# ifdef WIN32
8936 /* On Win32 it's done in this application. */
8937 {
8938 char_u *server_name = get_tv_string_chk(&argvars[0]);
8939
8940 if (server_name != NULL)
8941 serverForeground(server_name);
8942 }
8943# else
8944 /* Send a foreground() expression to the server. */
8945 argvars[1].v_type = VAR_STRING;
8946 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8947 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008948 rettv->v_type = VAR_STRING;
8949 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008950 remote_common(argvars, rettv, TRUE);
8951 vim_free(argvars[1].vval.v_string);
8952# endif
8953#endif
8954}
8955
8956 static void
8957f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8958{
8959#ifdef FEAT_CLIENTSERVER
8960 dictitem_T v;
8961 char_u *s = NULL;
8962# ifdef WIN32
8963 long_u n = 0;
8964# endif
8965 char_u *serverid;
8966
8967 if (check_restricted() || check_secure())
8968 {
8969 rettv->vval.v_number = -1;
8970 return;
8971 }
8972 serverid = get_tv_string_chk(&argvars[0]);
8973 if (serverid == NULL)
8974 {
8975 rettv->vval.v_number = -1;
8976 return; /* type error; errmsg already given */
8977 }
8978# ifdef WIN32
8979 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8980 if (n == 0)
8981 rettv->vval.v_number = -1;
8982 else
8983 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008984 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008985 rettv->vval.v_number = (s != NULL);
8986 }
8987# else
8988 if (check_connection() == FAIL)
8989 return;
8990
8991 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8992 serverStrToWin(serverid), &s);
8993# endif
8994
8995 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8996 {
8997 char_u *retvar;
8998
8999 v.di_tv.v_type = VAR_STRING;
9000 v.di_tv.vval.v_string = vim_strsave(s);
9001 retvar = get_tv_string_chk(&argvars[1]);
9002 if (retvar != NULL)
9003 set_var(retvar, &v.di_tv, FALSE);
9004 vim_free(v.di_tv.vval.v_string);
9005 }
9006#else
9007 rettv->vval.v_number = -1;
9008#endif
9009}
9010
9011 static void
9012f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9013{
9014 char_u *r = NULL;
9015
9016#ifdef FEAT_CLIENTSERVER
9017 char_u *serverid = get_tv_string_chk(&argvars[0]);
9018
9019 if (serverid != NULL && !check_restricted() && !check_secure())
9020 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009021 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009022# ifdef WIN32
9023 /* The server's HWND is encoded in the 'id' parameter */
9024 long_u n = 0;
9025# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009026
9027 if (argvars[1].v_type != VAR_UNKNOWN)
9028 timeout = get_tv_number(&argvars[1]);
9029
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009030# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009031 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9032 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009033 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009034 if (r == NULL)
9035# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009036 if (check_connection() == FAIL
9037 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9038 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009039# endif
9040 EMSG(_("E277: Unable to read a server reply"));
9041 }
9042#endif
9043 rettv->v_type = VAR_STRING;
9044 rettv->vval.v_string = r;
9045}
9046
9047/*
9048 * "remote_send()" function
9049 */
9050 static void
9051f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9052{
9053 rettv->v_type = VAR_STRING;
9054 rettv->vval.v_string = NULL;
9055#ifdef FEAT_CLIENTSERVER
9056 remote_common(argvars, rettv, FALSE);
9057#endif
9058}
9059
9060/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009061 * "remote_startserver()" function
9062 */
9063 static void
9064f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9065{
9066#ifdef FEAT_CLIENTSERVER
9067 char_u *server = get_tv_string_chk(&argvars[0]);
9068
9069 if (server == NULL)
9070 return; /* type error; errmsg already given */
9071 if (serverName != NULL)
9072 EMSG(_("E941: already started a server"));
9073 else
9074 {
9075# ifdef FEAT_X11
9076 if (check_connection() == OK)
9077 serverRegisterName(X_DISPLAY, server);
9078# else
9079 serverSetName(server);
9080# endif
9081 }
9082#else
9083 EMSG(_("E942: +clientserver feature not available"));
9084#endif
9085}
9086
9087/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009088 * "remove()" function
9089 */
9090 static void
9091f_remove(typval_T *argvars, typval_T *rettv)
9092{
9093 list_T *l;
9094 listitem_T *item, *item2;
9095 listitem_T *li;
9096 long idx;
9097 long end;
9098 char_u *key;
9099 dict_T *d;
9100 dictitem_T *di;
9101 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9102
9103 if (argvars[0].v_type == VAR_DICT)
9104 {
9105 if (argvars[2].v_type != VAR_UNKNOWN)
9106 EMSG2(_(e_toomanyarg), "remove()");
9107 else if ((d = argvars[0].vval.v_dict) != NULL
9108 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9109 {
9110 key = get_tv_string_chk(&argvars[1]);
9111 if (key != NULL)
9112 {
9113 di = dict_find(d, key, -1);
9114 if (di == NULL)
9115 EMSG2(_(e_dictkey), key);
9116 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9117 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9118 {
9119 *rettv = di->di_tv;
9120 init_tv(&di->di_tv);
9121 dictitem_remove(d, di);
9122 }
9123 }
9124 }
9125 }
9126 else if (argvars[0].v_type != VAR_LIST)
9127 EMSG2(_(e_listdictarg), "remove()");
9128 else if ((l = argvars[0].vval.v_list) != NULL
9129 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9130 {
9131 int error = FALSE;
9132
9133 idx = (long)get_tv_number_chk(&argvars[1], &error);
9134 if (error)
9135 ; /* type error: do nothing, errmsg already given */
9136 else if ((item = list_find(l, idx)) == NULL)
9137 EMSGN(_(e_listidx), idx);
9138 else
9139 {
9140 if (argvars[2].v_type == VAR_UNKNOWN)
9141 {
9142 /* Remove one item, return its value. */
9143 vimlist_remove(l, item, item);
9144 *rettv = item->li_tv;
9145 vim_free(item);
9146 }
9147 else
9148 {
9149 /* Remove range of items, return list with values. */
9150 end = (long)get_tv_number_chk(&argvars[2], &error);
9151 if (error)
9152 ; /* type error: do nothing */
9153 else if ((item2 = list_find(l, end)) == NULL)
9154 EMSGN(_(e_listidx), end);
9155 else
9156 {
9157 int cnt = 0;
9158
9159 for (li = item; li != NULL; li = li->li_next)
9160 {
9161 ++cnt;
9162 if (li == item2)
9163 break;
9164 }
9165 if (li == NULL) /* didn't find "item2" after "item" */
9166 EMSG(_(e_invrange));
9167 else
9168 {
9169 vimlist_remove(l, item, item2);
9170 if (rettv_list_alloc(rettv) == OK)
9171 {
9172 l = rettv->vval.v_list;
9173 l->lv_first = item;
9174 l->lv_last = item2;
9175 item->li_prev = NULL;
9176 item2->li_next = NULL;
9177 l->lv_len = cnt;
9178 }
9179 }
9180 }
9181 }
9182 }
9183 }
9184}
9185
9186/*
9187 * "rename({from}, {to})" function
9188 */
9189 static void
9190f_rename(typval_T *argvars, typval_T *rettv)
9191{
9192 char_u buf[NUMBUFLEN];
9193
9194 if (check_restricted() || check_secure())
9195 rettv->vval.v_number = -1;
9196 else
9197 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9198 get_tv_string_buf(&argvars[1], buf));
9199}
9200
9201/*
9202 * "repeat()" function
9203 */
9204 static void
9205f_repeat(typval_T *argvars, typval_T *rettv)
9206{
9207 char_u *p;
9208 int n;
9209 int slen;
9210 int len;
9211 char_u *r;
9212 int i;
9213
9214 n = (int)get_tv_number(&argvars[1]);
9215 if (argvars[0].v_type == VAR_LIST)
9216 {
9217 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9218 while (n-- > 0)
9219 if (list_extend(rettv->vval.v_list,
9220 argvars[0].vval.v_list, NULL) == FAIL)
9221 break;
9222 }
9223 else
9224 {
9225 p = get_tv_string(&argvars[0]);
9226 rettv->v_type = VAR_STRING;
9227 rettv->vval.v_string = NULL;
9228
9229 slen = (int)STRLEN(p);
9230 len = slen * n;
9231 if (len <= 0)
9232 return;
9233
9234 r = alloc(len + 1);
9235 if (r != NULL)
9236 {
9237 for (i = 0; i < n; i++)
9238 mch_memmove(r + i * slen, p, (size_t)slen);
9239 r[len] = NUL;
9240 }
9241
9242 rettv->vval.v_string = r;
9243 }
9244}
9245
9246/*
9247 * "resolve()" function
9248 */
9249 static void
9250f_resolve(typval_T *argvars, typval_T *rettv)
9251{
9252 char_u *p;
9253#ifdef HAVE_READLINK
9254 char_u *buf = NULL;
9255#endif
9256
9257 p = get_tv_string(&argvars[0]);
9258#ifdef FEAT_SHORTCUT
9259 {
9260 char_u *v = NULL;
9261
9262 v = mch_resolve_shortcut(p);
9263 if (v != NULL)
9264 rettv->vval.v_string = v;
9265 else
9266 rettv->vval.v_string = vim_strsave(p);
9267 }
9268#else
9269# ifdef HAVE_READLINK
9270 {
9271 char_u *cpy;
9272 int len;
9273 char_u *remain = NULL;
9274 char_u *q;
9275 int is_relative_to_current = FALSE;
9276 int has_trailing_pathsep = FALSE;
9277 int limit = 100;
9278
9279 p = vim_strsave(p);
9280
9281 if (p[0] == '.' && (vim_ispathsep(p[1])
9282 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9283 is_relative_to_current = TRUE;
9284
9285 len = STRLEN(p);
9286 if (len > 0 && after_pathsep(p, p + len))
9287 {
9288 has_trailing_pathsep = TRUE;
9289 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9290 }
9291
9292 q = getnextcomp(p);
9293 if (*q != NUL)
9294 {
9295 /* Separate the first path component in "p", and keep the
9296 * remainder (beginning with the path separator). */
9297 remain = vim_strsave(q - 1);
9298 q[-1] = NUL;
9299 }
9300
9301 buf = alloc(MAXPATHL + 1);
9302 if (buf == NULL)
9303 goto fail;
9304
9305 for (;;)
9306 {
9307 for (;;)
9308 {
9309 len = readlink((char *)p, (char *)buf, MAXPATHL);
9310 if (len <= 0)
9311 break;
9312 buf[len] = NUL;
9313
9314 if (limit-- == 0)
9315 {
9316 vim_free(p);
9317 vim_free(remain);
9318 EMSG(_("E655: Too many symbolic links (cycle?)"));
9319 rettv->vval.v_string = NULL;
9320 goto fail;
9321 }
9322
9323 /* Ensure that the result will have a trailing path separator
9324 * if the argument has one. */
9325 if (remain == NULL && has_trailing_pathsep)
9326 add_pathsep(buf);
9327
9328 /* Separate the first path component in the link value and
9329 * concatenate the remainders. */
9330 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9331 if (*q != NUL)
9332 {
9333 if (remain == NULL)
9334 remain = vim_strsave(q - 1);
9335 else
9336 {
9337 cpy = concat_str(q - 1, remain);
9338 if (cpy != NULL)
9339 {
9340 vim_free(remain);
9341 remain = cpy;
9342 }
9343 }
9344 q[-1] = NUL;
9345 }
9346
9347 q = gettail(p);
9348 if (q > p && *q == NUL)
9349 {
9350 /* Ignore trailing path separator. */
9351 q[-1] = NUL;
9352 q = gettail(p);
9353 }
9354 if (q > p && !mch_isFullName(buf))
9355 {
9356 /* symlink is relative to directory of argument */
9357 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9358 if (cpy != NULL)
9359 {
9360 STRCPY(cpy, p);
9361 STRCPY(gettail(cpy), buf);
9362 vim_free(p);
9363 p = cpy;
9364 }
9365 }
9366 else
9367 {
9368 vim_free(p);
9369 p = vim_strsave(buf);
9370 }
9371 }
9372
9373 if (remain == NULL)
9374 break;
9375
9376 /* Append the first path component of "remain" to "p". */
9377 q = getnextcomp(remain + 1);
9378 len = q - remain - (*q != NUL);
9379 cpy = vim_strnsave(p, STRLEN(p) + len);
9380 if (cpy != NULL)
9381 {
9382 STRNCAT(cpy, remain, len);
9383 vim_free(p);
9384 p = cpy;
9385 }
9386 /* Shorten "remain". */
9387 if (*q != NUL)
9388 STRMOVE(remain, q - 1);
9389 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009390 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009391 }
9392
9393 /* If the result is a relative path name, make it explicitly relative to
9394 * the current directory if and only if the argument had this form. */
9395 if (!vim_ispathsep(*p))
9396 {
9397 if (is_relative_to_current
9398 && *p != NUL
9399 && !(p[0] == '.'
9400 && (p[1] == NUL
9401 || vim_ispathsep(p[1])
9402 || (p[1] == '.'
9403 && (p[2] == NUL
9404 || vim_ispathsep(p[2]))))))
9405 {
9406 /* Prepend "./". */
9407 cpy = concat_str((char_u *)"./", p);
9408 if (cpy != NULL)
9409 {
9410 vim_free(p);
9411 p = cpy;
9412 }
9413 }
9414 else if (!is_relative_to_current)
9415 {
9416 /* Strip leading "./". */
9417 q = p;
9418 while (q[0] == '.' && vim_ispathsep(q[1]))
9419 q += 2;
9420 if (q > p)
9421 STRMOVE(p, p + 2);
9422 }
9423 }
9424
9425 /* Ensure that the result will have no trailing path separator
9426 * if the argument had none. But keep "/" or "//". */
9427 if (!has_trailing_pathsep)
9428 {
9429 q = p + STRLEN(p);
9430 if (after_pathsep(p, q))
9431 *gettail_sep(p) = NUL;
9432 }
9433
9434 rettv->vval.v_string = p;
9435 }
9436# else
9437 rettv->vval.v_string = vim_strsave(p);
9438# endif
9439#endif
9440
9441 simplify_filename(rettv->vval.v_string);
9442
9443#ifdef HAVE_READLINK
9444fail:
9445 vim_free(buf);
9446#endif
9447 rettv->v_type = VAR_STRING;
9448}
9449
9450/*
9451 * "reverse({list})" function
9452 */
9453 static void
9454f_reverse(typval_T *argvars, typval_T *rettv)
9455{
9456 list_T *l;
9457 listitem_T *li, *ni;
9458
9459 if (argvars[0].v_type != VAR_LIST)
9460 EMSG2(_(e_listarg), "reverse()");
9461 else if ((l = argvars[0].vval.v_list) != NULL
9462 && !tv_check_lock(l->lv_lock,
9463 (char_u *)N_("reverse() argument"), TRUE))
9464 {
9465 li = l->lv_last;
9466 l->lv_first = l->lv_last = NULL;
9467 l->lv_len = 0;
9468 while (li != NULL)
9469 {
9470 ni = li->li_prev;
9471 list_append(l, li);
9472 li = ni;
9473 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009474 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009475 l->lv_idx = l->lv_len - l->lv_idx - 1;
9476 }
9477}
9478
9479#define SP_NOMOVE 0x01 /* don't move cursor */
9480#define SP_REPEAT 0x02 /* repeat to find outer pair */
9481#define SP_RETCOUNT 0x04 /* return matchcount */
9482#define SP_SETPCMARK 0x08 /* set previous context mark */
9483#define SP_START 0x10 /* accept match at start position */
9484#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9485#define SP_END 0x40 /* leave cursor at end of match */
9486#define SP_COLUMN 0x80 /* start at cursor column */
9487
9488static int get_search_arg(typval_T *varp, int *flagsp);
9489
9490/*
9491 * Get flags for a search function.
9492 * Possibly sets "p_ws".
9493 * Returns BACKWARD, FORWARD or zero (for an error).
9494 */
9495 static int
9496get_search_arg(typval_T *varp, int *flagsp)
9497{
9498 int dir = FORWARD;
9499 char_u *flags;
9500 char_u nbuf[NUMBUFLEN];
9501 int mask;
9502
9503 if (varp->v_type != VAR_UNKNOWN)
9504 {
9505 flags = get_tv_string_buf_chk(varp, nbuf);
9506 if (flags == NULL)
9507 return 0; /* type error; errmsg already given */
9508 while (*flags != NUL)
9509 {
9510 switch (*flags)
9511 {
9512 case 'b': dir = BACKWARD; break;
9513 case 'w': p_ws = TRUE; break;
9514 case 'W': p_ws = FALSE; break;
9515 default: mask = 0;
9516 if (flagsp != NULL)
9517 switch (*flags)
9518 {
9519 case 'c': mask = SP_START; break;
9520 case 'e': mask = SP_END; break;
9521 case 'm': mask = SP_RETCOUNT; break;
9522 case 'n': mask = SP_NOMOVE; break;
9523 case 'p': mask = SP_SUBPAT; break;
9524 case 'r': mask = SP_REPEAT; break;
9525 case 's': mask = SP_SETPCMARK; break;
9526 case 'z': mask = SP_COLUMN; break;
9527 }
9528 if (mask == 0)
9529 {
9530 EMSG2(_(e_invarg2), flags);
9531 dir = 0;
9532 }
9533 else
9534 *flagsp |= mask;
9535 }
9536 if (dir == 0)
9537 break;
9538 ++flags;
9539 }
9540 }
9541 return dir;
9542}
9543
9544/*
9545 * Shared by search() and searchpos() functions.
9546 */
9547 static int
9548search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9549{
9550 int flags;
9551 char_u *pat;
9552 pos_T pos;
9553 pos_T save_cursor;
9554 int save_p_ws = p_ws;
9555 int dir;
9556 int retval = 0; /* default: FAIL */
9557 long lnum_stop = 0;
9558 proftime_T tm;
9559#ifdef FEAT_RELTIME
9560 long time_limit = 0;
9561#endif
9562 int options = SEARCH_KEEP;
9563 int subpatnum;
9564
9565 pat = get_tv_string(&argvars[0]);
9566 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9567 if (dir == 0)
9568 goto theend;
9569 flags = *flagsp;
9570 if (flags & SP_START)
9571 options |= SEARCH_START;
9572 if (flags & SP_END)
9573 options |= SEARCH_END;
9574 if (flags & SP_COLUMN)
9575 options |= SEARCH_COL;
9576
9577 /* Optional arguments: line number to stop searching and timeout. */
9578 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9579 {
9580 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9581 if (lnum_stop < 0)
9582 goto theend;
9583#ifdef FEAT_RELTIME
9584 if (argvars[3].v_type != VAR_UNKNOWN)
9585 {
9586 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9587 if (time_limit < 0)
9588 goto theend;
9589 }
9590#endif
9591 }
9592
9593#ifdef FEAT_RELTIME
9594 /* Set the time limit, if there is one. */
9595 profile_setlimit(time_limit, &tm);
9596#endif
9597
9598 /*
9599 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9600 * Check to make sure only those flags are set.
9601 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9602 * flags cannot be set. Check for that condition also.
9603 */
9604 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9605 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9606 {
9607 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9608 goto theend;
9609 }
9610
9611 pos = save_cursor = curwin->w_cursor;
9612 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009613 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009614 if (subpatnum != FAIL)
9615 {
9616 if (flags & SP_SUBPAT)
9617 retval = subpatnum;
9618 else
9619 retval = pos.lnum;
9620 if (flags & SP_SETPCMARK)
9621 setpcmark();
9622 curwin->w_cursor = pos;
9623 if (match_pos != NULL)
9624 {
9625 /* Store the match cursor position */
9626 match_pos->lnum = pos.lnum;
9627 match_pos->col = pos.col + 1;
9628 }
9629 /* "/$" will put the cursor after the end of the line, may need to
9630 * correct that here */
9631 check_cursor();
9632 }
9633
9634 /* If 'n' flag is used: restore cursor position. */
9635 if (flags & SP_NOMOVE)
9636 curwin->w_cursor = save_cursor;
9637 else
9638 curwin->w_set_curswant = TRUE;
9639theend:
9640 p_ws = save_p_ws;
9641
9642 return retval;
9643}
9644
9645#ifdef FEAT_FLOAT
9646
9647/*
9648 * round() is not in C90, use ceil() or floor() instead.
9649 */
9650 float_T
9651vim_round(float_T f)
9652{
9653 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9654}
9655
9656/*
9657 * "round({float})" function
9658 */
9659 static void
9660f_round(typval_T *argvars, typval_T *rettv)
9661{
9662 float_T f = 0.0;
9663
9664 rettv->v_type = VAR_FLOAT;
9665 if (get_float_arg(argvars, &f) == OK)
9666 rettv->vval.v_float = vim_round(f);
9667 else
9668 rettv->vval.v_float = 0.0;
9669}
9670#endif
9671
9672/*
9673 * "screenattr()" function
9674 */
9675 static void
9676f_screenattr(typval_T *argvars, typval_T *rettv)
9677{
9678 int row;
9679 int col;
9680 int c;
9681
9682 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9683 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9684 if (row < 0 || row >= screen_Rows
9685 || col < 0 || col >= screen_Columns)
9686 c = -1;
9687 else
9688 c = ScreenAttrs[LineOffset[row] + col];
9689 rettv->vval.v_number = c;
9690}
9691
9692/*
9693 * "screenchar()" function
9694 */
9695 static void
9696f_screenchar(typval_T *argvars, typval_T *rettv)
9697{
9698 int row;
9699 int col;
9700 int off;
9701 int c;
9702
9703 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9704 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9705 if (row < 0 || row >= screen_Rows
9706 || col < 0 || col >= screen_Columns)
9707 c = -1;
9708 else
9709 {
9710 off = LineOffset[row] + col;
9711#ifdef FEAT_MBYTE
9712 if (enc_utf8 && ScreenLinesUC[off] != 0)
9713 c = ScreenLinesUC[off];
9714 else
9715#endif
9716 c = ScreenLines[off];
9717 }
9718 rettv->vval.v_number = c;
9719}
9720
9721/*
9722 * "screencol()" function
9723 *
9724 * First column is 1 to be consistent with virtcol().
9725 */
9726 static void
9727f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9728{
9729 rettv->vval.v_number = screen_screencol() + 1;
9730}
9731
9732/*
9733 * "screenrow()" function
9734 */
9735 static void
9736f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9737{
9738 rettv->vval.v_number = screen_screenrow() + 1;
9739}
9740
9741/*
9742 * "search()" function
9743 */
9744 static void
9745f_search(typval_T *argvars, typval_T *rettv)
9746{
9747 int flags = 0;
9748
9749 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9750}
9751
9752/*
9753 * "searchdecl()" function
9754 */
9755 static void
9756f_searchdecl(typval_T *argvars, typval_T *rettv)
9757{
9758 int locally = 1;
9759 int thisblock = 0;
9760 int error = FALSE;
9761 char_u *name;
9762
9763 rettv->vval.v_number = 1; /* default: FAIL */
9764
9765 name = get_tv_string_chk(&argvars[0]);
9766 if (argvars[1].v_type != VAR_UNKNOWN)
9767 {
9768 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9769 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9770 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9771 }
9772 if (!error && name != NULL)
9773 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9774 locally, thisblock, SEARCH_KEEP) == FAIL;
9775}
9776
9777/*
9778 * Used by searchpair() and searchpairpos()
9779 */
9780 static int
9781searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9782{
9783 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009784 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009785 int save_p_ws = p_ws;
9786 int dir;
9787 int flags = 0;
9788 char_u nbuf1[NUMBUFLEN];
9789 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009790 int retval = 0; /* default: FAIL */
9791 long lnum_stop = 0;
9792 long time_limit = 0;
9793
9794 /* Get the three pattern arguments: start, middle, end. */
9795 spat = get_tv_string_chk(&argvars[0]);
9796 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9797 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9798 if (spat == NULL || mpat == NULL || epat == NULL)
9799 goto theend; /* type error */
9800
9801 /* Handle the optional fourth argument: flags */
9802 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9803 if (dir == 0)
9804 goto theend;
9805
9806 /* Don't accept SP_END or SP_SUBPAT.
9807 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9808 */
9809 if ((flags & (SP_END | SP_SUBPAT)) != 0
9810 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9811 {
9812 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9813 goto theend;
9814 }
9815
9816 /* Using 'r' implies 'W', otherwise it doesn't work. */
9817 if (flags & SP_REPEAT)
9818 p_ws = FALSE;
9819
9820 /* Optional fifth argument: skip expression */
9821 if (argvars[3].v_type == VAR_UNKNOWN
9822 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009823 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009824 else
9825 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009826 skip = &argvars[4];
9827 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9828 && skip->v_type != VAR_STRING)
9829 {
9830 /* Type error */
9831 goto theend;
9832 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009833 if (argvars[5].v_type != VAR_UNKNOWN)
9834 {
9835 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9836 if (lnum_stop < 0)
9837 goto theend;
9838#ifdef FEAT_RELTIME
9839 if (argvars[6].v_type != VAR_UNKNOWN)
9840 {
9841 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9842 if (time_limit < 0)
9843 goto theend;
9844 }
9845#endif
9846 }
9847 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009848
9849 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9850 match_pos, lnum_stop, time_limit);
9851
9852theend:
9853 p_ws = save_p_ws;
9854
9855 return retval;
9856}
9857
9858/*
9859 * "searchpair()" function
9860 */
9861 static void
9862f_searchpair(typval_T *argvars, typval_T *rettv)
9863{
9864 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9865}
9866
9867/*
9868 * "searchpairpos()" function
9869 */
9870 static void
9871f_searchpairpos(typval_T *argvars, typval_T *rettv)
9872{
9873 pos_T match_pos;
9874 int lnum = 0;
9875 int col = 0;
9876
9877 if (rettv_list_alloc(rettv) == FAIL)
9878 return;
9879
9880 if (searchpair_cmn(argvars, &match_pos) > 0)
9881 {
9882 lnum = match_pos.lnum;
9883 col = match_pos.col;
9884 }
9885
9886 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9887 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9888}
9889
9890/*
9891 * Search for a start/middle/end thing.
9892 * Used by searchpair(), see its documentation for the details.
9893 * Returns 0 or -1 for no match,
9894 */
9895 long
9896do_searchpair(
9897 char_u *spat, /* start pattern */
9898 char_u *mpat, /* middle pattern */
9899 char_u *epat, /* end pattern */
9900 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009901 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009902 int flags, /* SP_SETPCMARK and other SP_ values */
9903 pos_T *match_pos,
9904 linenr_T lnum_stop, /* stop at this line if not zero */
9905 long time_limit UNUSED) /* stop after this many msec */
9906{
9907 char_u *save_cpo;
9908 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9909 long retval = 0;
9910 pos_T pos;
9911 pos_T firstpos;
9912 pos_T foundpos;
9913 pos_T save_cursor;
9914 pos_T save_pos;
9915 int n;
9916 int r;
9917 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009918 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009919 int err;
9920 int options = SEARCH_KEEP;
9921 proftime_T tm;
9922
9923 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9924 save_cpo = p_cpo;
9925 p_cpo = empty_option;
9926
9927#ifdef FEAT_RELTIME
9928 /* Set the time limit, if there is one. */
9929 profile_setlimit(time_limit, &tm);
9930#endif
9931
9932 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9933 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009934 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9935 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009936 if (pat2 == NULL || pat3 == NULL)
9937 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009938 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009939 if (*mpat == NUL)
9940 STRCPY(pat3, pat2);
9941 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009942 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009943 spat, epat, mpat);
9944 if (flags & SP_START)
9945 options |= SEARCH_START;
9946
Bram Moolenaar48570482017-10-30 21:48:41 +01009947 if (skip != NULL)
9948 {
9949 /* Empty string means to not use the skip expression. */
9950 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9951 use_skip = skip->vval.v_string != NULL
9952 && *skip->vval.v_string != NUL;
9953 }
9954
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009955 save_cursor = curwin->w_cursor;
9956 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009957 CLEAR_POS(&firstpos);
9958 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009959 pat = pat3;
9960 for (;;)
9961 {
9962 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009963 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009964 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009965 /* didn't find it or found the first match again: FAIL */
9966 break;
9967
9968 if (firstpos.lnum == 0)
9969 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009970 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009971 {
9972 /* Found the same position again. Can happen with a pattern that
9973 * has "\zs" at the end and searching backwards. Advance one
9974 * character and try again. */
9975 if (dir == BACKWARD)
9976 decl(&pos);
9977 else
9978 incl(&pos);
9979 }
9980 foundpos = pos;
9981
9982 /* clear the start flag to avoid getting stuck here */
9983 options &= ~SEARCH_START;
9984
9985 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009986 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009987 {
9988 save_pos = curwin->w_cursor;
9989 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009990 err = FALSE;
9991 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009992 curwin->w_cursor = save_pos;
9993 if (err)
9994 {
9995 /* Evaluating {skip} caused an error, break here. */
9996 curwin->w_cursor = save_cursor;
9997 retval = -1;
9998 break;
9999 }
10000 if (r)
10001 continue;
10002 }
10003
10004 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10005 {
10006 /* Found end when searching backwards or start when searching
10007 * forward: nested pair. */
10008 ++nest;
10009 pat = pat2; /* nested, don't search for middle */
10010 }
10011 else
10012 {
10013 /* Found end when searching forward or start when searching
10014 * backward: end of (nested) pair; or found middle in outer pair. */
10015 if (--nest == 1)
10016 pat = pat3; /* outer level, search for middle */
10017 }
10018
10019 if (nest == 0)
10020 {
10021 /* Found the match: return matchcount or line number. */
10022 if (flags & SP_RETCOUNT)
10023 ++retval;
10024 else
10025 retval = pos.lnum;
10026 if (flags & SP_SETPCMARK)
10027 setpcmark();
10028 curwin->w_cursor = pos;
10029 if (!(flags & SP_REPEAT))
10030 break;
10031 nest = 1; /* search for next unmatched */
10032 }
10033 }
10034
10035 if (match_pos != NULL)
10036 {
10037 /* Store the match cursor position */
10038 match_pos->lnum = curwin->w_cursor.lnum;
10039 match_pos->col = curwin->w_cursor.col + 1;
10040 }
10041
10042 /* If 'n' flag is used or search failed: restore cursor position. */
10043 if ((flags & SP_NOMOVE) || retval == 0)
10044 curwin->w_cursor = save_cursor;
10045
10046theend:
10047 vim_free(pat2);
10048 vim_free(pat3);
10049 if (p_cpo == empty_option)
10050 p_cpo = save_cpo;
10051 else
10052 /* Darn, evaluating the {skip} expression changed the value. */
10053 free_string_option(save_cpo);
10054
10055 return retval;
10056}
10057
10058/*
10059 * "searchpos()" function
10060 */
10061 static void
10062f_searchpos(typval_T *argvars, typval_T *rettv)
10063{
10064 pos_T match_pos;
10065 int lnum = 0;
10066 int col = 0;
10067 int n;
10068 int flags = 0;
10069
10070 if (rettv_list_alloc(rettv) == FAIL)
10071 return;
10072
10073 n = search_cmn(argvars, &match_pos, &flags);
10074 if (n > 0)
10075 {
10076 lnum = match_pos.lnum;
10077 col = match_pos.col;
10078 }
10079
10080 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10081 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10082 if (flags & SP_SUBPAT)
10083 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10084}
10085
10086 static void
10087f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10088{
10089#ifdef FEAT_CLIENTSERVER
10090 char_u buf[NUMBUFLEN];
10091 char_u *server = get_tv_string_chk(&argvars[0]);
10092 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10093
10094 rettv->vval.v_number = -1;
10095 if (server == NULL || reply == NULL)
10096 return;
10097 if (check_restricted() || check_secure())
10098 return;
10099# ifdef FEAT_X11
10100 if (check_connection() == FAIL)
10101 return;
10102# endif
10103
10104 if (serverSendReply(server, reply) < 0)
10105 {
10106 EMSG(_("E258: Unable to send to client"));
10107 return;
10108 }
10109 rettv->vval.v_number = 0;
10110#else
10111 rettv->vval.v_number = -1;
10112#endif
10113}
10114
10115 static void
10116f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10117{
10118 char_u *r = NULL;
10119
10120#ifdef FEAT_CLIENTSERVER
10121# ifdef WIN32
10122 r = serverGetVimNames();
10123# else
10124 make_connection();
10125 if (X_DISPLAY != NULL)
10126 r = serverGetVimNames(X_DISPLAY);
10127# endif
10128#endif
10129 rettv->v_type = VAR_STRING;
10130 rettv->vval.v_string = r;
10131}
10132
10133/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010134 * Set line or list of lines in buffer "buf".
10135 */
10136 static void
10137set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
10138{
10139 char_u *line = NULL;
10140 list_T *l = NULL;
10141 listitem_T *li = NULL;
10142 long added = 0;
10143 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010144 buf_T *curbuf_save = NULL;
10145 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010146 int is_curbuf = buf == curbuf;
10147
Bram Moolenaar9d954202017-09-04 20:34:19 +020010148 /* When using the current buffer ml_mfp will be set if needed. Useful when
10149 * setline() is used on startup. For other buffers the buffer must be
10150 * loaded. */
10151 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010152 {
10153 rettv->vval.v_number = 1; /* FAIL */
10154 return;
10155 }
10156
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010157 if (!is_curbuf)
10158 {
10159 wininfo_T *wip;
10160
10161 curbuf_save = curbuf;
10162 curwin_save = curwin;
10163 curbuf = buf;
10164 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
10165 {
10166 if (wip->wi_win != NULL)
10167 {
10168 curwin = wip->wi_win;
10169 break;
10170 }
10171 }
10172 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010173
10174 lcount = curbuf->b_ml.ml_line_count;
10175
10176 if (lines->v_type == VAR_LIST)
10177 {
10178 l = lines->vval.v_list;
10179 li = l->lv_first;
10180 }
10181 else
10182 line = get_tv_string_chk(lines);
10183
10184 /* default result is zero == OK */
10185 for (;;)
10186 {
10187 if (l != NULL)
10188 {
10189 /* list argument, get next string */
10190 if (li == NULL)
10191 break;
10192 line = get_tv_string_chk(&li->li_tv);
10193 li = li->li_next;
10194 }
10195
10196 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +020010197 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010198 break;
10199
10200 /* When coming here from Insert mode, sync undo, so that this can be
10201 * undone separately from what was previously inserted. */
10202 if (u_sync_once == 2)
10203 {
10204 u_sync_once = 1; /* notify that u_sync() was called */
10205 u_sync(TRUE);
10206 }
10207
10208 if (lnum <= curbuf->b_ml.ml_line_count)
10209 {
10210 /* existing line, replace it */
10211 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10212 {
10213 changed_bytes(lnum, 0);
10214 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10215 check_cursor_col();
10216 rettv->vval.v_number = 0; /* OK */
10217 }
10218 }
10219 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10220 {
10221 /* lnum is one past the last line, append the line */
10222 ++added;
10223 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10224 rettv->vval.v_number = 0; /* OK */
10225 }
10226
10227 if (l == NULL) /* only one string argument */
10228 break;
10229 ++lnum;
10230 }
10231
10232 if (added > 0)
10233 appended_lines_mark(lcount, added);
10234
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010235 if (!is_curbuf)
10236 {
10237 curbuf = curbuf_save;
10238 curwin = curwin_save;
10239 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010240}
10241
10242/*
10243 * "setbufline()" function
10244 */
10245 static void
10246f_setbufline(argvars, rettv)
10247 typval_T *argvars;
10248 typval_T *rettv;
10249{
10250 linenr_T lnum;
10251 buf_T *buf;
10252
10253 buf = get_buf_tv(&argvars[0], FALSE);
10254 if (buf == NULL)
10255 rettv->vval.v_number = 1; /* FAIL */
10256 else
10257 {
10258 lnum = get_tv_lnum_buf(&argvars[1], buf);
10259
10260 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10261 }
10262}
10263
10264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010265 * "setbufvar()" function
10266 */
10267 static void
10268f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10269{
10270 buf_T *buf;
10271 char_u *varname, *bufvarname;
10272 typval_T *varp;
10273 char_u nbuf[NUMBUFLEN];
10274
10275 if (check_restricted() || check_secure())
10276 return;
10277 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10278 varname = get_tv_string_chk(&argvars[1]);
10279 buf = get_buf_tv(&argvars[0], FALSE);
10280 varp = &argvars[2];
10281
10282 if (buf != NULL && varname != NULL && varp != NULL)
10283 {
10284 if (*varname == '&')
10285 {
10286 long numval;
10287 char_u *strval;
10288 int error = FALSE;
10289 aco_save_T aco;
10290
10291 /* set curbuf to be our buf, temporarily */
10292 aucmd_prepbuf(&aco, buf);
10293
10294 ++varname;
10295 numval = (long)get_tv_number_chk(varp, &error);
10296 strval = get_tv_string_buf_chk(varp, nbuf);
10297 if (!error && strval != NULL)
10298 set_option_value(varname, numval, strval, OPT_LOCAL);
10299
10300 /* reset notion of buffer */
10301 aucmd_restbuf(&aco);
10302 }
10303 else
10304 {
10305 buf_T *save_curbuf = curbuf;
10306
10307 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10308 if (bufvarname != NULL)
10309 {
10310 curbuf = buf;
10311 STRCPY(bufvarname, "b:");
10312 STRCPY(bufvarname + 2, varname);
10313 set_var(bufvarname, varp, TRUE);
10314 vim_free(bufvarname);
10315 curbuf = save_curbuf;
10316 }
10317 }
10318 }
10319}
10320
10321 static void
10322f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10323{
10324 dict_T *d;
10325 dictitem_T *di;
10326 char_u *csearch;
10327
10328 if (argvars[0].v_type != VAR_DICT)
10329 {
10330 EMSG(_(e_dictreq));
10331 return;
10332 }
10333
10334 if ((d = argvars[0].vval.v_dict) != NULL)
10335 {
10336 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10337 if (csearch != NULL)
10338 {
10339#ifdef FEAT_MBYTE
10340 if (enc_utf8)
10341 {
10342 int pcc[MAX_MCO];
10343 int c = utfc_ptr2char(csearch, pcc);
10344
10345 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10346 }
10347 else
10348#endif
10349 set_last_csearch(PTR2CHAR(csearch),
10350 csearch, MB_PTR2LEN(csearch));
10351 }
10352
10353 di = dict_find(d, (char_u *)"forward", -1);
10354 if (di != NULL)
10355 set_csearch_direction((int)get_tv_number(&di->di_tv)
10356 ? FORWARD : BACKWARD);
10357
10358 di = dict_find(d, (char_u *)"until", -1);
10359 if (di != NULL)
10360 set_csearch_until(!!get_tv_number(&di->di_tv));
10361 }
10362}
10363
10364/*
10365 * "setcmdpos()" function
10366 */
10367 static void
10368f_setcmdpos(typval_T *argvars, typval_T *rettv)
10369{
10370 int pos = (int)get_tv_number(&argvars[0]) - 1;
10371
10372 if (pos >= 0)
10373 rettv->vval.v_number = set_cmdline_pos(pos);
10374}
10375
10376/*
10377 * "setfperm({fname}, {mode})" function
10378 */
10379 static void
10380f_setfperm(typval_T *argvars, typval_T *rettv)
10381{
10382 char_u *fname;
10383 char_u modebuf[NUMBUFLEN];
10384 char_u *mode_str;
10385 int i;
10386 int mask;
10387 int mode = 0;
10388
10389 rettv->vval.v_number = 0;
10390 fname = get_tv_string_chk(&argvars[0]);
10391 if (fname == NULL)
10392 return;
10393 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10394 if (mode_str == NULL)
10395 return;
10396 if (STRLEN(mode_str) != 9)
10397 {
10398 EMSG2(_(e_invarg2), mode_str);
10399 return;
10400 }
10401
10402 mask = 1;
10403 for (i = 8; i >= 0; --i)
10404 {
10405 if (mode_str[i] != '-')
10406 mode |= mask;
10407 mask = mask << 1;
10408 }
10409 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10410}
10411
10412/*
10413 * "setline()" function
10414 */
10415 static void
10416f_setline(typval_T *argvars, typval_T *rettv)
10417{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010418 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010419
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010420 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010421}
10422
Bram Moolenaard823fa92016-08-12 16:29:27 +020010423static 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 +020010424
10425/*
10426 * Used by "setqflist()" and "setloclist()" functions
10427 */
10428 static void
10429set_qf_ll_list(
10430 win_T *wp UNUSED,
10431 typval_T *list_arg UNUSED,
10432 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010433 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010434 typval_T *rettv)
10435{
10436#ifdef FEAT_QUICKFIX
10437 static char *e_invact = N_("E927: Invalid action: '%s'");
10438 char_u *act;
10439 int action = 0;
10440#endif
10441
10442 rettv->vval.v_number = -1;
10443
10444#ifdef FEAT_QUICKFIX
10445 if (list_arg->v_type != VAR_LIST)
10446 EMSG(_(e_listreq));
10447 else
10448 {
10449 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010450 dict_T *d = NULL;
10451 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010452
10453 if (action_arg->v_type == VAR_STRING)
10454 {
10455 act = get_tv_string_chk(action_arg);
10456 if (act == NULL)
10457 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010458 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10459 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010460 action = *act;
10461 else
10462 EMSG2(_(e_invact), act);
10463 }
10464 else if (action_arg->v_type == VAR_UNKNOWN)
10465 action = ' ';
10466 else
10467 EMSG(_(e_stringreq));
10468
Bram Moolenaard823fa92016-08-12 16:29:27 +020010469 if (action_arg->v_type != VAR_UNKNOWN
10470 && what_arg->v_type != VAR_UNKNOWN)
10471 {
10472 if (what_arg->v_type == VAR_DICT)
10473 d = what_arg->vval.v_dict;
10474 else
10475 {
10476 EMSG(_(e_dictreq));
10477 valid_dict = FALSE;
10478 }
10479 }
10480
10481 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10482 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010483 rettv->vval.v_number = 0;
10484 }
10485#endif
10486}
10487
10488/*
10489 * "setloclist()" function
10490 */
10491 static void
10492f_setloclist(typval_T *argvars, typval_T *rettv)
10493{
10494 win_T *win;
10495
10496 rettv->vval.v_number = -1;
10497
10498 win = find_win_by_nr(&argvars[0], NULL);
10499 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010500 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010501}
10502
10503/*
10504 * "setmatches()" function
10505 */
10506 static void
10507f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10508{
10509#ifdef FEAT_SEARCH_EXTRA
10510 list_T *l;
10511 listitem_T *li;
10512 dict_T *d;
10513 list_T *s = NULL;
10514
10515 rettv->vval.v_number = -1;
10516 if (argvars[0].v_type != VAR_LIST)
10517 {
10518 EMSG(_(e_listreq));
10519 return;
10520 }
10521 if ((l = argvars[0].vval.v_list) != NULL)
10522 {
10523
10524 /* To some extent make sure that we are dealing with a list from
10525 * "getmatches()". */
10526 li = l->lv_first;
10527 while (li != NULL)
10528 {
10529 if (li->li_tv.v_type != VAR_DICT
10530 || (d = li->li_tv.vval.v_dict) == NULL)
10531 {
10532 EMSG(_(e_invarg));
10533 return;
10534 }
10535 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10536 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10537 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10538 && dict_find(d, (char_u *)"priority", -1) != NULL
10539 && dict_find(d, (char_u *)"id", -1) != NULL))
10540 {
10541 EMSG(_(e_invarg));
10542 return;
10543 }
10544 li = li->li_next;
10545 }
10546
10547 clear_matches(curwin);
10548 li = l->lv_first;
10549 while (li != NULL)
10550 {
10551 int i = 0;
10552 char_u buf[5];
10553 dictitem_T *di;
10554 char_u *group;
10555 int priority;
10556 int id;
10557 char_u *conceal;
10558
10559 d = li->li_tv.vval.v_dict;
10560 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10561 {
10562 if (s == NULL)
10563 {
10564 s = list_alloc();
10565 if (s == NULL)
10566 return;
10567 }
10568
10569 /* match from matchaddpos() */
10570 for (i = 1; i < 9; i++)
10571 {
10572 sprintf((char *)buf, (char *)"pos%d", i);
10573 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10574 {
10575 if (di->di_tv.v_type != VAR_LIST)
10576 return;
10577
10578 list_append_tv(s, &di->di_tv);
10579 s->lv_refcount++;
10580 }
10581 else
10582 break;
10583 }
10584 }
10585
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010586 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010587 priority = (int)get_dict_number(d, (char_u *)"priority");
10588 id = (int)get_dict_number(d, (char_u *)"id");
10589 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010590 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010591 : NULL;
10592 if (i == 0)
10593 {
10594 match_add(curwin, group,
10595 get_dict_string(d, (char_u *)"pattern", FALSE),
10596 priority, id, NULL, conceal);
10597 }
10598 else
10599 {
10600 match_add(curwin, group, NULL, priority, id, s, conceal);
10601 list_unref(s);
10602 s = NULL;
10603 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010604 vim_free(group);
10605 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010606
10607 li = li->li_next;
10608 }
10609 rettv->vval.v_number = 0;
10610 }
10611#endif
10612}
10613
10614/*
10615 * "setpos()" function
10616 */
10617 static void
10618f_setpos(typval_T *argvars, typval_T *rettv)
10619{
10620 pos_T pos;
10621 int fnum;
10622 char_u *name;
10623 colnr_T curswant = -1;
10624
10625 rettv->vval.v_number = -1;
10626 name = get_tv_string_chk(argvars);
10627 if (name != NULL)
10628 {
10629 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10630 {
10631 if (--pos.col < 0)
10632 pos.col = 0;
10633 if (name[0] == '.' && name[1] == NUL)
10634 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010635 /* set cursor; "fnum" is ignored */
10636 curwin->w_cursor = pos;
10637 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010638 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010639 curwin->w_curswant = curswant - 1;
10640 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010641 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010642 check_cursor();
10643 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 }
10645 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10646 {
10647 /* set mark */
10648 if (setmark_pos(name[1], &pos, fnum) == OK)
10649 rettv->vval.v_number = 0;
10650 }
10651 else
10652 EMSG(_(e_invarg));
10653 }
10654 }
10655}
10656
10657/*
10658 * "setqflist()" function
10659 */
10660 static void
10661f_setqflist(typval_T *argvars, typval_T *rettv)
10662{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010663 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010664}
10665
10666/*
10667 * "setreg()" function
10668 */
10669 static void
10670f_setreg(typval_T *argvars, typval_T *rettv)
10671{
10672 int regname;
10673 char_u *strregname;
10674 char_u *stropt;
10675 char_u *strval;
10676 int append;
10677 char_u yank_type;
10678 long block_len;
10679
10680 block_len = -1;
10681 yank_type = MAUTO;
10682 append = FALSE;
10683
10684 strregname = get_tv_string_chk(argvars);
10685 rettv->vval.v_number = 1; /* FAIL is default */
10686
10687 if (strregname == NULL)
10688 return; /* type error; errmsg already given */
10689 regname = *strregname;
10690 if (regname == 0 || regname == '@')
10691 regname = '"';
10692
10693 if (argvars[2].v_type != VAR_UNKNOWN)
10694 {
10695 stropt = get_tv_string_chk(&argvars[2]);
10696 if (stropt == NULL)
10697 return; /* type error */
10698 for (; *stropt != NUL; ++stropt)
10699 switch (*stropt)
10700 {
10701 case 'a': case 'A': /* append */
10702 append = TRUE;
10703 break;
10704 case 'v': case 'c': /* character-wise selection */
10705 yank_type = MCHAR;
10706 break;
10707 case 'V': case 'l': /* line-wise selection */
10708 yank_type = MLINE;
10709 break;
10710 case 'b': case Ctrl_V: /* block-wise selection */
10711 yank_type = MBLOCK;
10712 if (VIM_ISDIGIT(stropt[1]))
10713 {
10714 ++stropt;
10715 block_len = getdigits(&stropt) - 1;
10716 --stropt;
10717 }
10718 break;
10719 }
10720 }
10721
10722 if (argvars[1].v_type == VAR_LIST)
10723 {
10724 char_u **lstval;
10725 char_u **allocval;
10726 char_u buf[NUMBUFLEN];
10727 char_u **curval;
10728 char_u **curallocval;
10729 list_T *ll = argvars[1].vval.v_list;
10730 listitem_T *li;
10731 int len;
10732
10733 /* If the list is NULL handle like an empty list. */
10734 len = ll == NULL ? 0 : ll->lv_len;
10735
10736 /* First half: use for pointers to result lines; second half: use for
10737 * pointers to allocated copies. */
10738 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10739 if (lstval == NULL)
10740 return;
10741 curval = lstval;
10742 allocval = lstval + len + 2;
10743 curallocval = allocval;
10744
10745 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10746 li = li->li_next)
10747 {
10748 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10749 if (strval == NULL)
10750 goto free_lstval;
10751 if (strval == buf)
10752 {
10753 /* Need to make a copy, next get_tv_string_buf_chk() will
10754 * overwrite the string. */
10755 strval = vim_strsave(buf);
10756 if (strval == NULL)
10757 goto free_lstval;
10758 *curallocval++ = strval;
10759 }
10760 *curval++ = strval;
10761 }
10762 *curval++ = NULL;
10763
10764 write_reg_contents_lst(regname, lstval, -1,
10765 append, yank_type, block_len);
10766free_lstval:
10767 while (curallocval > allocval)
10768 vim_free(*--curallocval);
10769 vim_free(lstval);
10770 }
10771 else
10772 {
10773 strval = get_tv_string_chk(&argvars[1]);
10774 if (strval == NULL)
10775 return;
10776 write_reg_contents_ex(regname, strval, -1,
10777 append, yank_type, block_len);
10778 }
10779 rettv->vval.v_number = 0;
10780}
10781
10782/*
10783 * "settabvar()" function
10784 */
10785 static void
10786f_settabvar(typval_T *argvars, typval_T *rettv)
10787{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010788 tabpage_T *save_curtab;
10789 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010790 char_u *varname, *tabvarname;
10791 typval_T *varp;
10792
10793 rettv->vval.v_number = 0;
10794
10795 if (check_restricted() || check_secure())
10796 return;
10797
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010798 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010799 varname = get_tv_string_chk(&argvars[1]);
10800 varp = &argvars[2];
10801
Bram Moolenaar4033c552017-09-16 20:54:51 +020010802 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010803 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010804 save_curtab = curtab;
10805 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010806
10807 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10808 if (tabvarname != NULL)
10809 {
10810 STRCPY(tabvarname, "t:");
10811 STRCPY(tabvarname + 2, varname);
10812 set_var(tabvarname, varp, TRUE);
10813 vim_free(tabvarname);
10814 }
10815
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010816 /* Restore current tabpage */
10817 if (valid_tabpage(save_curtab))
10818 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010819 }
10820}
10821
10822/*
10823 * "settabwinvar()" function
10824 */
10825 static void
10826f_settabwinvar(typval_T *argvars, typval_T *rettv)
10827{
10828 setwinvar(argvars, rettv, 1);
10829}
10830
10831/*
10832 * "setwinvar()" function
10833 */
10834 static void
10835f_setwinvar(typval_T *argvars, typval_T *rettv)
10836{
10837 setwinvar(argvars, rettv, 0);
10838}
10839
10840#ifdef FEAT_CRYPT
10841/*
10842 * "sha256({string})" function
10843 */
10844 static void
10845f_sha256(typval_T *argvars, typval_T *rettv)
10846{
10847 char_u *p;
10848
10849 p = get_tv_string(&argvars[0]);
10850 rettv->vval.v_string = vim_strsave(
10851 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10852 rettv->v_type = VAR_STRING;
10853}
10854#endif /* FEAT_CRYPT */
10855
10856/*
10857 * "shellescape({string})" function
10858 */
10859 static void
10860f_shellescape(typval_T *argvars, typval_T *rettv)
10861{
Bram Moolenaar20615522017-06-05 18:46:26 +020010862 int do_special = non_zero_arg(&argvars[1]);
10863
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010864 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010865 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010866 rettv->v_type = VAR_STRING;
10867}
10868
10869/*
10870 * shiftwidth() function
10871 */
10872 static void
10873f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10874{
10875 rettv->vval.v_number = get_sw_value(curbuf);
10876}
10877
10878/*
10879 * "simplify()" function
10880 */
10881 static void
10882f_simplify(typval_T *argvars, typval_T *rettv)
10883{
10884 char_u *p;
10885
10886 p = get_tv_string(&argvars[0]);
10887 rettv->vval.v_string = vim_strsave(p);
10888 simplify_filename(rettv->vval.v_string); /* simplify in place */
10889 rettv->v_type = VAR_STRING;
10890}
10891
10892#ifdef FEAT_FLOAT
10893/*
10894 * "sin()" function
10895 */
10896 static void
10897f_sin(typval_T *argvars, typval_T *rettv)
10898{
10899 float_T f = 0.0;
10900
10901 rettv->v_type = VAR_FLOAT;
10902 if (get_float_arg(argvars, &f) == OK)
10903 rettv->vval.v_float = sin(f);
10904 else
10905 rettv->vval.v_float = 0.0;
10906}
10907
10908/*
10909 * "sinh()" function
10910 */
10911 static void
10912f_sinh(typval_T *argvars, typval_T *rettv)
10913{
10914 float_T f = 0.0;
10915
10916 rettv->v_type = VAR_FLOAT;
10917 if (get_float_arg(argvars, &f) == OK)
10918 rettv->vval.v_float = sinh(f);
10919 else
10920 rettv->vval.v_float = 0.0;
10921}
10922#endif
10923
10924static int
10925#ifdef __BORLANDC__
10926 _RTLENTRYF
10927#endif
10928 item_compare(const void *s1, const void *s2);
10929static int
10930#ifdef __BORLANDC__
10931 _RTLENTRYF
10932#endif
10933 item_compare2(const void *s1, const void *s2);
10934
10935/* struct used in the array that's given to qsort() */
10936typedef struct
10937{
10938 listitem_T *item;
10939 int idx;
10940} sortItem_T;
10941
10942/* struct storing information about current sort */
10943typedef struct
10944{
10945 int item_compare_ic;
10946 int item_compare_numeric;
10947 int item_compare_numbers;
10948#ifdef FEAT_FLOAT
10949 int item_compare_float;
10950#endif
10951 char_u *item_compare_func;
10952 partial_T *item_compare_partial;
10953 dict_T *item_compare_selfdict;
10954 int item_compare_func_err;
10955 int item_compare_keep_zero;
10956} sortinfo_T;
10957static sortinfo_T *sortinfo = NULL;
10958static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10959#define ITEM_COMPARE_FAIL 999
10960
10961/*
10962 * Compare functions for f_sort() and f_uniq() below.
10963 */
10964 static int
10965#ifdef __BORLANDC__
10966_RTLENTRYF
10967#endif
10968item_compare(const void *s1, const void *s2)
10969{
10970 sortItem_T *si1, *si2;
10971 typval_T *tv1, *tv2;
10972 char_u *p1, *p2;
10973 char_u *tofree1 = NULL, *tofree2 = NULL;
10974 int res;
10975 char_u numbuf1[NUMBUFLEN];
10976 char_u numbuf2[NUMBUFLEN];
10977
10978 si1 = (sortItem_T *)s1;
10979 si2 = (sortItem_T *)s2;
10980 tv1 = &si1->item->li_tv;
10981 tv2 = &si2->item->li_tv;
10982
10983 if (sortinfo->item_compare_numbers)
10984 {
10985 varnumber_T v1 = get_tv_number(tv1);
10986 varnumber_T v2 = get_tv_number(tv2);
10987
10988 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10989 }
10990
10991#ifdef FEAT_FLOAT
10992 if (sortinfo->item_compare_float)
10993 {
10994 float_T v1 = get_tv_float(tv1);
10995 float_T v2 = get_tv_float(tv2);
10996
10997 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10998 }
10999#endif
11000
11001 /* tv2string() puts quotes around a string and allocates memory. Don't do
11002 * that for string variables. Use a single quote when comparing with a
11003 * non-string to do what the docs promise. */
11004 if (tv1->v_type == VAR_STRING)
11005 {
11006 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11007 p1 = (char_u *)"'";
11008 else
11009 p1 = tv1->vval.v_string;
11010 }
11011 else
11012 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11013 if (tv2->v_type == VAR_STRING)
11014 {
11015 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11016 p2 = (char_u *)"'";
11017 else
11018 p2 = tv2->vval.v_string;
11019 }
11020 else
11021 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11022 if (p1 == NULL)
11023 p1 = (char_u *)"";
11024 if (p2 == NULL)
11025 p2 = (char_u *)"";
11026 if (!sortinfo->item_compare_numeric)
11027 {
11028 if (sortinfo->item_compare_ic)
11029 res = STRICMP(p1, p2);
11030 else
11031 res = STRCMP(p1, p2);
11032 }
11033 else
11034 {
11035 double n1, n2;
11036 n1 = strtod((char *)p1, (char **)&p1);
11037 n2 = strtod((char *)p2, (char **)&p2);
11038 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11039 }
11040
11041 /* When the result would be zero, compare the item indexes. Makes the
11042 * sort stable. */
11043 if (res == 0 && !sortinfo->item_compare_keep_zero)
11044 res = si1->idx > si2->idx ? 1 : -1;
11045
11046 vim_free(tofree1);
11047 vim_free(tofree2);
11048 return res;
11049}
11050
11051 static int
11052#ifdef __BORLANDC__
11053_RTLENTRYF
11054#endif
11055item_compare2(const void *s1, const void *s2)
11056{
11057 sortItem_T *si1, *si2;
11058 int res;
11059 typval_T rettv;
11060 typval_T argv[3];
11061 int dummy;
11062 char_u *func_name;
11063 partial_T *partial = sortinfo->item_compare_partial;
11064
11065 /* shortcut after failure in previous call; compare all items equal */
11066 if (sortinfo->item_compare_func_err)
11067 return 0;
11068
11069 si1 = (sortItem_T *)s1;
11070 si2 = (sortItem_T *)s2;
11071
11072 if (partial == NULL)
11073 func_name = sortinfo->item_compare_func;
11074 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011075 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011076
11077 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11078 * in the copy without changing the original list items. */
11079 copy_tv(&si1->item->li_tv, &argv[0]);
11080 copy_tv(&si2->item->li_tv, &argv[1]);
11081
11082 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11083 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011084 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011085 partial, sortinfo->item_compare_selfdict);
11086 clear_tv(&argv[0]);
11087 clear_tv(&argv[1]);
11088
11089 if (res == FAIL)
11090 res = ITEM_COMPARE_FAIL;
11091 else
11092 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11093 if (sortinfo->item_compare_func_err)
11094 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11095 clear_tv(&rettv);
11096
11097 /* When the result would be zero, compare the pointers themselves. Makes
11098 * the sort stable. */
11099 if (res == 0 && !sortinfo->item_compare_keep_zero)
11100 res = si1->idx > si2->idx ? 1 : -1;
11101
11102 return res;
11103}
11104
11105/*
11106 * "sort({list})" function
11107 */
11108 static void
11109do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11110{
11111 list_T *l;
11112 listitem_T *li;
11113 sortItem_T *ptrs;
11114 sortinfo_T *old_sortinfo;
11115 sortinfo_T info;
11116 long len;
11117 long i;
11118
11119 /* Pointer to current info struct used in compare function. Save and
11120 * restore the current one for nested calls. */
11121 old_sortinfo = sortinfo;
11122 sortinfo = &info;
11123
11124 if (argvars[0].v_type != VAR_LIST)
11125 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11126 else
11127 {
11128 l = argvars[0].vval.v_list;
11129 if (l == NULL || tv_check_lock(l->lv_lock,
11130 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11131 TRUE))
11132 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011133 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011134
11135 len = list_len(l);
11136 if (len <= 1)
11137 goto theend; /* short list sorts pretty quickly */
11138
11139 info.item_compare_ic = FALSE;
11140 info.item_compare_numeric = FALSE;
11141 info.item_compare_numbers = FALSE;
11142#ifdef FEAT_FLOAT
11143 info.item_compare_float = FALSE;
11144#endif
11145 info.item_compare_func = NULL;
11146 info.item_compare_partial = NULL;
11147 info.item_compare_selfdict = NULL;
11148 if (argvars[1].v_type != VAR_UNKNOWN)
11149 {
11150 /* optional second argument: {func} */
11151 if (argvars[1].v_type == VAR_FUNC)
11152 info.item_compare_func = argvars[1].vval.v_string;
11153 else if (argvars[1].v_type == VAR_PARTIAL)
11154 info.item_compare_partial = argvars[1].vval.v_partial;
11155 else
11156 {
11157 int error = FALSE;
11158
11159 i = (long)get_tv_number_chk(&argvars[1], &error);
11160 if (error)
11161 goto theend; /* type error; errmsg already given */
11162 if (i == 1)
11163 info.item_compare_ic = TRUE;
11164 else if (argvars[1].v_type != VAR_NUMBER)
11165 info.item_compare_func = get_tv_string(&argvars[1]);
11166 else if (i != 0)
11167 {
11168 EMSG(_(e_invarg));
11169 goto theend;
11170 }
11171 if (info.item_compare_func != NULL)
11172 {
11173 if (*info.item_compare_func == NUL)
11174 {
11175 /* empty string means default sort */
11176 info.item_compare_func = NULL;
11177 }
11178 else if (STRCMP(info.item_compare_func, "n") == 0)
11179 {
11180 info.item_compare_func = NULL;
11181 info.item_compare_numeric = TRUE;
11182 }
11183 else if (STRCMP(info.item_compare_func, "N") == 0)
11184 {
11185 info.item_compare_func = NULL;
11186 info.item_compare_numbers = TRUE;
11187 }
11188#ifdef FEAT_FLOAT
11189 else if (STRCMP(info.item_compare_func, "f") == 0)
11190 {
11191 info.item_compare_func = NULL;
11192 info.item_compare_float = TRUE;
11193 }
11194#endif
11195 else if (STRCMP(info.item_compare_func, "i") == 0)
11196 {
11197 info.item_compare_func = NULL;
11198 info.item_compare_ic = TRUE;
11199 }
11200 }
11201 }
11202
11203 if (argvars[2].v_type != VAR_UNKNOWN)
11204 {
11205 /* optional third argument: {dict} */
11206 if (argvars[2].v_type != VAR_DICT)
11207 {
11208 EMSG(_(e_dictreq));
11209 goto theend;
11210 }
11211 info.item_compare_selfdict = argvars[2].vval.v_dict;
11212 }
11213 }
11214
11215 /* Make an array with each entry pointing to an item in the List. */
11216 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11217 if (ptrs == NULL)
11218 goto theend;
11219
11220 i = 0;
11221 if (sort)
11222 {
11223 /* sort(): ptrs will be the list to sort */
11224 for (li = l->lv_first; li != NULL; li = li->li_next)
11225 {
11226 ptrs[i].item = li;
11227 ptrs[i].idx = i;
11228 ++i;
11229 }
11230
11231 info.item_compare_func_err = FALSE;
11232 info.item_compare_keep_zero = FALSE;
11233 /* test the compare function */
11234 if ((info.item_compare_func != NULL
11235 || info.item_compare_partial != NULL)
11236 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11237 == ITEM_COMPARE_FAIL)
11238 EMSG(_("E702: Sort compare function failed"));
11239 else
11240 {
11241 /* Sort the array with item pointers. */
11242 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11243 info.item_compare_func == NULL
11244 && info.item_compare_partial == NULL
11245 ? item_compare : item_compare2);
11246
11247 if (!info.item_compare_func_err)
11248 {
11249 /* Clear the List and append the items in sorted order. */
11250 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11251 l->lv_len = 0;
11252 for (i = 0; i < len; ++i)
11253 list_append(l, ptrs[i].item);
11254 }
11255 }
11256 }
11257 else
11258 {
11259 int (*item_compare_func_ptr)(const void *, const void *);
11260
11261 /* f_uniq(): ptrs will be a stack of items to remove */
11262 info.item_compare_func_err = FALSE;
11263 info.item_compare_keep_zero = TRUE;
11264 item_compare_func_ptr = info.item_compare_func != NULL
11265 || info.item_compare_partial != NULL
11266 ? item_compare2 : item_compare;
11267
11268 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11269 li = li->li_next)
11270 {
11271 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11272 == 0)
11273 ptrs[i++].item = li;
11274 if (info.item_compare_func_err)
11275 {
11276 EMSG(_("E882: Uniq compare function failed"));
11277 break;
11278 }
11279 }
11280
11281 if (!info.item_compare_func_err)
11282 {
11283 while (--i >= 0)
11284 {
11285 li = ptrs[i].item->li_next;
11286 ptrs[i].item->li_next = li->li_next;
11287 if (li->li_next != NULL)
11288 li->li_next->li_prev = ptrs[i].item;
11289 else
11290 l->lv_last = ptrs[i].item;
11291 list_fix_watch(l, li);
11292 listitem_free(li);
11293 l->lv_len--;
11294 }
11295 }
11296 }
11297
11298 vim_free(ptrs);
11299 }
11300theend:
11301 sortinfo = old_sortinfo;
11302}
11303
11304/*
11305 * "sort({list})" function
11306 */
11307 static void
11308f_sort(typval_T *argvars, typval_T *rettv)
11309{
11310 do_sort_uniq(argvars, rettv, TRUE);
11311}
11312
11313/*
11314 * "uniq({list})" function
11315 */
11316 static void
11317f_uniq(typval_T *argvars, typval_T *rettv)
11318{
11319 do_sort_uniq(argvars, rettv, FALSE);
11320}
11321
11322/*
11323 * "soundfold({word})" function
11324 */
11325 static void
11326f_soundfold(typval_T *argvars, typval_T *rettv)
11327{
11328 char_u *s;
11329
11330 rettv->v_type = VAR_STRING;
11331 s = get_tv_string(&argvars[0]);
11332#ifdef FEAT_SPELL
11333 rettv->vval.v_string = eval_soundfold(s);
11334#else
11335 rettv->vval.v_string = vim_strsave(s);
11336#endif
11337}
11338
11339/*
11340 * "spellbadword()" function
11341 */
11342 static void
11343f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11344{
11345 char_u *word = (char_u *)"";
11346 hlf_T attr = HLF_COUNT;
11347 int len = 0;
11348
11349 if (rettv_list_alloc(rettv) == FAIL)
11350 return;
11351
11352#ifdef FEAT_SPELL
11353 if (argvars[0].v_type == VAR_UNKNOWN)
11354 {
11355 /* Find the start and length of the badly spelled word. */
11356 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11357 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011358 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011359 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011360 curwin->w_set_curswant = TRUE;
11361 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011362 }
11363 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11364 {
11365 char_u *str = get_tv_string_chk(&argvars[0]);
11366 int capcol = -1;
11367
11368 if (str != NULL)
11369 {
11370 /* Check the argument for spelling. */
11371 while (*str != NUL)
11372 {
11373 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11374 if (attr != HLF_COUNT)
11375 {
11376 word = str;
11377 break;
11378 }
11379 str += len;
11380 }
11381 }
11382 }
11383#endif
11384
11385 list_append_string(rettv->vval.v_list, word, len);
11386 list_append_string(rettv->vval.v_list, (char_u *)(
11387 attr == HLF_SPB ? "bad" :
11388 attr == HLF_SPR ? "rare" :
11389 attr == HLF_SPL ? "local" :
11390 attr == HLF_SPC ? "caps" :
11391 ""), -1);
11392}
11393
11394/*
11395 * "spellsuggest()" function
11396 */
11397 static void
11398f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11399{
11400#ifdef FEAT_SPELL
11401 char_u *str;
11402 int typeerr = FALSE;
11403 int maxcount;
11404 garray_T ga;
11405 int i;
11406 listitem_T *li;
11407 int need_capital = FALSE;
11408#endif
11409
11410 if (rettv_list_alloc(rettv) == FAIL)
11411 return;
11412
11413#ifdef FEAT_SPELL
11414 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11415 {
11416 str = get_tv_string(&argvars[0]);
11417 if (argvars[1].v_type != VAR_UNKNOWN)
11418 {
11419 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11420 if (maxcount <= 0)
11421 return;
11422 if (argvars[2].v_type != VAR_UNKNOWN)
11423 {
11424 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11425 if (typeerr)
11426 return;
11427 }
11428 }
11429 else
11430 maxcount = 25;
11431
11432 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11433
11434 for (i = 0; i < ga.ga_len; ++i)
11435 {
11436 str = ((char_u **)ga.ga_data)[i];
11437
11438 li = listitem_alloc();
11439 if (li == NULL)
11440 vim_free(str);
11441 else
11442 {
11443 li->li_tv.v_type = VAR_STRING;
11444 li->li_tv.v_lock = 0;
11445 li->li_tv.vval.v_string = str;
11446 list_append(rettv->vval.v_list, li);
11447 }
11448 }
11449 ga_clear(&ga);
11450 }
11451#endif
11452}
11453
11454 static void
11455f_split(typval_T *argvars, typval_T *rettv)
11456{
11457 char_u *str;
11458 char_u *end;
11459 char_u *pat = NULL;
11460 regmatch_T regmatch;
11461 char_u patbuf[NUMBUFLEN];
11462 char_u *save_cpo;
11463 int match;
11464 colnr_T col = 0;
11465 int keepempty = FALSE;
11466 int typeerr = FALSE;
11467
11468 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11469 save_cpo = p_cpo;
11470 p_cpo = (char_u *)"";
11471
11472 str = get_tv_string(&argvars[0]);
11473 if (argvars[1].v_type != VAR_UNKNOWN)
11474 {
11475 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11476 if (pat == NULL)
11477 typeerr = TRUE;
11478 if (argvars[2].v_type != VAR_UNKNOWN)
11479 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11480 }
11481 if (pat == NULL || *pat == NUL)
11482 pat = (char_u *)"[\\x01- ]\\+";
11483
11484 if (rettv_list_alloc(rettv) == FAIL)
11485 return;
11486 if (typeerr)
11487 return;
11488
11489 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11490 if (regmatch.regprog != NULL)
11491 {
11492 regmatch.rm_ic = FALSE;
11493 while (*str != NUL || keepempty)
11494 {
11495 if (*str == NUL)
11496 match = FALSE; /* empty item at the end */
11497 else
11498 match = vim_regexec_nl(&regmatch, str, col);
11499 if (match)
11500 end = regmatch.startp[0];
11501 else
11502 end = str + STRLEN(str);
11503 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11504 && *str != NUL && match && end < regmatch.endp[0]))
11505 {
11506 if (list_append_string(rettv->vval.v_list, str,
11507 (int)(end - str)) == FAIL)
11508 break;
11509 }
11510 if (!match)
11511 break;
11512 /* Advance to just after the match. */
11513 if (regmatch.endp[0] > str)
11514 col = 0;
11515 else
11516 {
11517 /* Don't get stuck at the same match. */
11518#ifdef FEAT_MBYTE
11519 col = (*mb_ptr2len)(regmatch.endp[0]);
11520#else
11521 col = 1;
11522#endif
11523 }
11524 str = regmatch.endp[0];
11525 }
11526
11527 vim_regfree(regmatch.regprog);
11528 }
11529
11530 p_cpo = save_cpo;
11531}
11532
11533#ifdef FEAT_FLOAT
11534/*
11535 * "sqrt()" function
11536 */
11537 static void
11538f_sqrt(typval_T *argvars, typval_T *rettv)
11539{
11540 float_T f = 0.0;
11541
11542 rettv->v_type = VAR_FLOAT;
11543 if (get_float_arg(argvars, &f) == OK)
11544 rettv->vval.v_float = sqrt(f);
11545 else
11546 rettv->vval.v_float = 0.0;
11547}
11548
11549/*
11550 * "str2float()" function
11551 */
11552 static void
11553f_str2float(typval_T *argvars, typval_T *rettv)
11554{
11555 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011556 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011557
Bram Moolenaar08243d22017-01-10 16:12:29 +010011558 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011559 p = skipwhite(p + 1);
11560 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011561 if (isneg)
11562 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011563 rettv->v_type = VAR_FLOAT;
11564}
11565#endif
11566
11567/*
11568 * "str2nr()" function
11569 */
11570 static void
11571f_str2nr(typval_T *argvars, typval_T *rettv)
11572{
11573 int base = 10;
11574 char_u *p;
11575 varnumber_T n;
11576 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011577 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011578
11579 if (argvars[1].v_type != VAR_UNKNOWN)
11580 {
11581 base = (int)get_tv_number(&argvars[1]);
11582 if (base != 2 && base != 8 && base != 10 && base != 16)
11583 {
11584 EMSG(_(e_invarg));
11585 return;
11586 }
11587 }
11588
11589 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011590 isneg = (*p == '-');
11591 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011592 p = skipwhite(p + 1);
11593 switch (base)
11594 {
11595 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11596 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11597 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11598 default: what = 0;
11599 }
11600 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011601 if (isneg)
11602 rettv->vval.v_number = -n;
11603 else
11604 rettv->vval.v_number = n;
11605
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011606}
11607
11608#ifdef HAVE_STRFTIME
11609/*
11610 * "strftime({format}[, {time}])" function
11611 */
11612 static void
11613f_strftime(typval_T *argvars, typval_T *rettv)
11614{
11615 char_u result_buf[256];
11616 struct tm *curtime;
11617 time_t seconds;
11618 char_u *p;
11619
11620 rettv->v_type = VAR_STRING;
11621
11622 p = get_tv_string(&argvars[0]);
11623 if (argvars[1].v_type == VAR_UNKNOWN)
11624 seconds = time(NULL);
11625 else
11626 seconds = (time_t)get_tv_number(&argvars[1]);
11627 curtime = localtime(&seconds);
11628 /* MSVC returns NULL for an invalid value of seconds. */
11629 if (curtime == NULL)
11630 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11631 else
11632 {
11633# ifdef FEAT_MBYTE
11634 vimconv_T conv;
11635 char_u *enc;
11636
11637 conv.vc_type = CONV_NONE;
11638 enc = enc_locale();
11639 convert_setup(&conv, p_enc, enc);
11640 if (conv.vc_type != CONV_NONE)
11641 p = string_convert(&conv, p, NULL);
11642# endif
11643 if (p != NULL)
11644 (void)strftime((char *)result_buf, sizeof(result_buf),
11645 (char *)p, curtime);
11646 else
11647 result_buf[0] = NUL;
11648
11649# ifdef FEAT_MBYTE
11650 if (conv.vc_type != CONV_NONE)
11651 vim_free(p);
11652 convert_setup(&conv, enc, p_enc);
11653 if (conv.vc_type != CONV_NONE)
11654 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11655 else
11656# endif
11657 rettv->vval.v_string = vim_strsave(result_buf);
11658
11659# ifdef FEAT_MBYTE
11660 /* Release conversion descriptors */
11661 convert_setup(&conv, NULL, NULL);
11662 vim_free(enc);
11663# endif
11664 }
11665}
11666#endif
11667
11668/*
11669 * "strgetchar()" function
11670 */
11671 static void
11672f_strgetchar(typval_T *argvars, typval_T *rettv)
11673{
11674 char_u *str;
11675 int len;
11676 int error = FALSE;
11677 int charidx;
11678
11679 rettv->vval.v_number = -1;
11680 str = get_tv_string_chk(&argvars[0]);
11681 if (str == NULL)
11682 return;
11683 len = (int)STRLEN(str);
11684 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11685 if (error)
11686 return;
11687#ifdef FEAT_MBYTE
11688 {
11689 int byteidx = 0;
11690
11691 while (charidx >= 0 && byteidx < len)
11692 {
11693 if (charidx == 0)
11694 {
11695 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11696 break;
11697 }
11698 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011699 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011700 }
11701 }
11702#else
11703 if (charidx < len)
11704 rettv->vval.v_number = str[charidx];
11705#endif
11706}
11707
11708/*
11709 * "stridx()" function
11710 */
11711 static void
11712f_stridx(typval_T *argvars, typval_T *rettv)
11713{
11714 char_u buf[NUMBUFLEN];
11715 char_u *needle;
11716 char_u *haystack;
11717 char_u *save_haystack;
11718 char_u *pos;
11719 int start_idx;
11720
11721 needle = get_tv_string_chk(&argvars[1]);
11722 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11723 rettv->vval.v_number = -1;
11724 if (needle == NULL || haystack == NULL)
11725 return; /* type error; errmsg already given */
11726
11727 if (argvars[2].v_type != VAR_UNKNOWN)
11728 {
11729 int error = FALSE;
11730
11731 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11732 if (error || start_idx >= (int)STRLEN(haystack))
11733 return;
11734 if (start_idx >= 0)
11735 haystack += start_idx;
11736 }
11737
11738 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11739 if (pos != NULL)
11740 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11741}
11742
11743/*
11744 * "string()" function
11745 */
11746 static void
11747f_string(typval_T *argvars, typval_T *rettv)
11748{
11749 char_u *tofree;
11750 char_u numbuf[NUMBUFLEN];
11751
11752 rettv->v_type = VAR_STRING;
11753 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11754 get_copyID());
11755 /* Make a copy if we have a value but it's not in allocated memory. */
11756 if (rettv->vval.v_string != NULL && tofree == NULL)
11757 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11758}
11759
11760/*
11761 * "strlen()" function
11762 */
11763 static void
11764f_strlen(typval_T *argvars, typval_T *rettv)
11765{
11766 rettv->vval.v_number = (varnumber_T)(STRLEN(
11767 get_tv_string(&argvars[0])));
11768}
11769
11770/*
11771 * "strchars()" function
11772 */
11773 static void
11774f_strchars(typval_T *argvars, typval_T *rettv)
11775{
11776 char_u *s = get_tv_string(&argvars[0]);
11777 int skipcc = 0;
11778#ifdef FEAT_MBYTE
11779 varnumber_T len = 0;
11780 int (*func_mb_ptr2char_adv)(char_u **pp);
11781#endif
11782
11783 if (argvars[1].v_type != VAR_UNKNOWN)
11784 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11785 if (skipcc < 0 || skipcc > 1)
11786 EMSG(_(e_invarg));
11787 else
11788 {
11789#ifdef FEAT_MBYTE
11790 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11791 while (*s != NUL)
11792 {
11793 func_mb_ptr2char_adv(&s);
11794 ++len;
11795 }
11796 rettv->vval.v_number = len;
11797#else
11798 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11799#endif
11800 }
11801}
11802
11803/*
11804 * "strdisplaywidth()" function
11805 */
11806 static void
11807f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11808{
11809 char_u *s = get_tv_string(&argvars[0]);
11810 int col = 0;
11811
11812 if (argvars[1].v_type != VAR_UNKNOWN)
11813 col = (int)get_tv_number(&argvars[1]);
11814
11815 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11816}
11817
11818/*
11819 * "strwidth()" function
11820 */
11821 static void
11822f_strwidth(typval_T *argvars, typval_T *rettv)
11823{
11824 char_u *s = get_tv_string(&argvars[0]);
11825
11826 rettv->vval.v_number = (varnumber_T)(
11827#ifdef FEAT_MBYTE
11828 mb_string2cells(s, -1)
11829#else
11830 STRLEN(s)
11831#endif
11832 );
11833}
11834
11835/*
11836 * "strcharpart()" function
11837 */
11838 static void
11839f_strcharpart(typval_T *argvars, typval_T *rettv)
11840{
11841#ifdef FEAT_MBYTE
11842 char_u *p;
11843 int nchar;
11844 int nbyte = 0;
11845 int charlen;
11846 int len = 0;
11847 int slen;
11848 int error = FALSE;
11849
11850 p = get_tv_string(&argvars[0]);
11851 slen = (int)STRLEN(p);
11852
11853 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11854 if (!error)
11855 {
11856 if (nchar > 0)
11857 while (nchar > 0 && nbyte < slen)
11858 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011859 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011860 --nchar;
11861 }
11862 else
11863 nbyte = nchar;
11864 if (argvars[2].v_type != VAR_UNKNOWN)
11865 {
11866 charlen = (int)get_tv_number(&argvars[2]);
11867 while (charlen > 0 && nbyte + len < slen)
11868 {
11869 int off = nbyte + len;
11870
11871 if (off < 0)
11872 len += 1;
11873 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011874 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011875 --charlen;
11876 }
11877 }
11878 else
11879 len = slen - nbyte; /* default: all bytes that are available. */
11880 }
11881
11882 /*
11883 * Only return the overlap between the specified part and the actual
11884 * string.
11885 */
11886 if (nbyte < 0)
11887 {
11888 len += nbyte;
11889 nbyte = 0;
11890 }
11891 else if (nbyte > slen)
11892 nbyte = slen;
11893 if (len < 0)
11894 len = 0;
11895 else if (nbyte + len > slen)
11896 len = slen - nbyte;
11897
11898 rettv->v_type = VAR_STRING;
11899 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11900#else
11901 f_strpart(argvars, rettv);
11902#endif
11903}
11904
11905/*
11906 * "strpart()" function
11907 */
11908 static void
11909f_strpart(typval_T *argvars, typval_T *rettv)
11910{
11911 char_u *p;
11912 int n;
11913 int len;
11914 int slen;
11915 int error = FALSE;
11916
11917 p = get_tv_string(&argvars[0]);
11918 slen = (int)STRLEN(p);
11919
11920 n = (int)get_tv_number_chk(&argvars[1], &error);
11921 if (error)
11922 len = 0;
11923 else if (argvars[2].v_type != VAR_UNKNOWN)
11924 len = (int)get_tv_number(&argvars[2]);
11925 else
11926 len = slen - n; /* default len: all bytes that are available. */
11927
11928 /*
11929 * Only return the overlap between the specified part and the actual
11930 * string.
11931 */
11932 if (n < 0)
11933 {
11934 len += n;
11935 n = 0;
11936 }
11937 else if (n > slen)
11938 n = slen;
11939 if (len < 0)
11940 len = 0;
11941 else if (n + len > slen)
11942 len = slen - n;
11943
11944 rettv->v_type = VAR_STRING;
11945 rettv->vval.v_string = vim_strnsave(p + n, len);
11946}
11947
11948/*
11949 * "strridx()" function
11950 */
11951 static void
11952f_strridx(typval_T *argvars, typval_T *rettv)
11953{
11954 char_u buf[NUMBUFLEN];
11955 char_u *needle;
11956 char_u *haystack;
11957 char_u *rest;
11958 char_u *lastmatch = NULL;
11959 int haystack_len, end_idx;
11960
11961 needle = get_tv_string_chk(&argvars[1]);
11962 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11963
11964 rettv->vval.v_number = -1;
11965 if (needle == NULL || haystack == NULL)
11966 return; /* type error; errmsg already given */
11967
11968 haystack_len = (int)STRLEN(haystack);
11969 if (argvars[2].v_type != VAR_UNKNOWN)
11970 {
11971 /* Third argument: upper limit for index */
11972 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11973 if (end_idx < 0)
11974 return; /* can never find a match */
11975 }
11976 else
11977 end_idx = haystack_len;
11978
11979 if (*needle == NUL)
11980 {
11981 /* Empty string matches past the end. */
11982 lastmatch = haystack + end_idx;
11983 }
11984 else
11985 {
11986 for (rest = haystack; *rest != '\0'; ++rest)
11987 {
11988 rest = (char_u *)strstr((char *)rest, (char *)needle);
11989 if (rest == NULL || rest > haystack + end_idx)
11990 break;
11991 lastmatch = rest;
11992 }
11993 }
11994
11995 if (lastmatch == NULL)
11996 rettv->vval.v_number = -1;
11997 else
11998 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11999}
12000
12001/*
12002 * "strtrans()" function
12003 */
12004 static void
12005f_strtrans(typval_T *argvars, typval_T *rettv)
12006{
12007 rettv->v_type = VAR_STRING;
12008 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12009}
12010
12011/*
12012 * "submatch()" function
12013 */
12014 static void
12015f_submatch(typval_T *argvars, typval_T *rettv)
12016{
12017 int error = FALSE;
12018 int no;
12019 int retList = 0;
12020
12021 no = (int)get_tv_number_chk(&argvars[0], &error);
12022 if (error)
12023 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012024 if (no < 0 || no >= NSUBEXP)
12025 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012026 EMSGN(_("E935: invalid submatch number: %d"), no);
12027 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012028 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012029 if (argvars[1].v_type != VAR_UNKNOWN)
12030 retList = (int)get_tv_number_chk(&argvars[1], &error);
12031 if (error)
12032 return;
12033
12034 if (retList == 0)
12035 {
12036 rettv->v_type = VAR_STRING;
12037 rettv->vval.v_string = reg_submatch(no);
12038 }
12039 else
12040 {
12041 rettv->v_type = VAR_LIST;
12042 rettv->vval.v_list = reg_submatch_list(no);
12043 }
12044}
12045
12046/*
12047 * "substitute()" function
12048 */
12049 static void
12050f_substitute(typval_T *argvars, typval_T *rettv)
12051{
12052 char_u patbuf[NUMBUFLEN];
12053 char_u subbuf[NUMBUFLEN];
12054 char_u flagsbuf[NUMBUFLEN];
12055
12056 char_u *str = get_tv_string_chk(&argvars[0]);
12057 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012058 char_u *sub = NULL;
12059 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012060 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12061
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012062 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12063 expr = &argvars[2];
12064 else
12065 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12066
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012067 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012068 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12069 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012070 rettv->vval.v_string = NULL;
12071 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012072 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012073}
12074
12075/*
12076 * "synID(lnum, col, trans)" function
12077 */
12078 static void
12079f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12080{
12081 int id = 0;
12082#ifdef FEAT_SYN_HL
12083 linenr_T lnum;
12084 colnr_T col;
12085 int trans;
12086 int transerr = FALSE;
12087
12088 lnum = get_tv_lnum(argvars); /* -1 on type error */
12089 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12090 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12091
12092 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12093 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12094 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12095#endif
12096
12097 rettv->vval.v_number = id;
12098}
12099
12100/*
12101 * "synIDattr(id, what [, mode])" function
12102 */
12103 static void
12104f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12105{
12106 char_u *p = NULL;
12107#ifdef FEAT_SYN_HL
12108 int id;
12109 char_u *what;
12110 char_u *mode;
12111 char_u modebuf[NUMBUFLEN];
12112 int modec;
12113
12114 id = (int)get_tv_number(&argvars[0]);
12115 what = get_tv_string(&argvars[1]);
12116 if (argvars[2].v_type != VAR_UNKNOWN)
12117 {
12118 mode = get_tv_string_buf(&argvars[2], modebuf);
12119 modec = TOLOWER_ASC(mode[0]);
12120 if (modec != 't' && modec != 'c' && modec != 'g')
12121 modec = 0; /* replace invalid with current */
12122 }
12123 else
12124 {
12125#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12126 if (USE_24BIT)
12127 modec = 'g';
12128 else
12129#endif
12130 if (t_colors > 1)
12131 modec = 'c';
12132 else
12133 modec = 't';
12134 }
12135
12136
12137 switch (TOLOWER_ASC(what[0]))
12138 {
12139 case 'b':
12140 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12141 p = highlight_color(id, what, modec);
12142 else /* bold */
12143 p = highlight_has_attr(id, HL_BOLD, modec);
12144 break;
12145
12146 case 'f': /* fg[#] or font */
12147 p = highlight_color(id, what, modec);
12148 break;
12149
12150 case 'i':
12151 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12152 p = highlight_has_attr(id, HL_INVERSE, modec);
12153 else /* italic */
12154 p = highlight_has_attr(id, HL_ITALIC, modec);
12155 break;
12156
12157 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012158 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012159 break;
12160
12161 case 'r': /* reverse */
12162 p = highlight_has_attr(id, HL_INVERSE, modec);
12163 break;
12164
12165 case 's':
12166 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12167 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012168 /* strikeout */
12169 else if (TOLOWER_ASC(what[1]) == 't' &&
12170 TOLOWER_ASC(what[2]) == 'r')
12171 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012172 else /* standout */
12173 p = highlight_has_attr(id, HL_STANDOUT, modec);
12174 break;
12175
12176 case 'u':
12177 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12178 /* underline */
12179 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12180 else
12181 /* undercurl */
12182 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12183 break;
12184 }
12185
12186 if (p != NULL)
12187 p = vim_strsave(p);
12188#endif
12189 rettv->v_type = VAR_STRING;
12190 rettv->vval.v_string = p;
12191}
12192
12193/*
12194 * "synIDtrans(id)" function
12195 */
12196 static void
12197f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12198{
12199 int id;
12200
12201#ifdef FEAT_SYN_HL
12202 id = (int)get_tv_number(&argvars[0]);
12203
12204 if (id > 0)
12205 id = syn_get_final_id(id);
12206 else
12207#endif
12208 id = 0;
12209
12210 rettv->vval.v_number = id;
12211}
12212
12213/*
12214 * "synconcealed(lnum, col)" function
12215 */
12216 static void
12217f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12218{
12219#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12220 linenr_T lnum;
12221 colnr_T col;
12222 int syntax_flags = 0;
12223 int cchar;
12224 int matchid = 0;
12225 char_u str[NUMBUFLEN];
12226#endif
12227
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012228 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012229
12230#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12231 lnum = get_tv_lnum(argvars); /* -1 on type error */
12232 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12233
12234 vim_memset(str, NUL, sizeof(str));
12235
12236 if (rettv_list_alloc(rettv) != FAIL)
12237 {
12238 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12239 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12240 && curwin->w_p_cole > 0)
12241 {
12242 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12243 syntax_flags = get_syntax_info(&matchid);
12244
12245 /* get the conceal character */
12246 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12247 {
12248 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012249 if (cchar == NUL && curwin->w_p_cole == 1)
12250 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012251 if (cchar != NUL)
12252 {
12253# ifdef FEAT_MBYTE
12254 if (has_mbyte)
12255 (*mb_char2bytes)(cchar, str);
12256 else
12257# endif
12258 str[0] = cchar;
12259 }
12260 }
12261 }
12262
12263 list_append_number(rettv->vval.v_list,
12264 (syntax_flags & HL_CONCEAL) != 0);
12265 /* -1 to auto-determine strlen */
12266 list_append_string(rettv->vval.v_list, str, -1);
12267 list_append_number(rettv->vval.v_list, matchid);
12268 }
12269#endif
12270}
12271
12272/*
12273 * "synstack(lnum, col)" function
12274 */
12275 static void
12276f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12277{
12278#ifdef FEAT_SYN_HL
12279 linenr_T lnum;
12280 colnr_T col;
12281 int i;
12282 int id;
12283#endif
12284
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012285 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012286
12287#ifdef FEAT_SYN_HL
12288 lnum = get_tv_lnum(argvars); /* -1 on type error */
12289 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12290
12291 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12292 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12293 && rettv_list_alloc(rettv) != FAIL)
12294 {
12295 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12296 for (i = 0; ; ++i)
12297 {
12298 id = syn_get_stack_item(i);
12299 if (id < 0)
12300 break;
12301 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12302 break;
12303 }
12304 }
12305#endif
12306}
12307
12308 static void
12309get_cmd_output_as_rettv(
12310 typval_T *argvars,
12311 typval_T *rettv,
12312 int retlist)
12313{
12314 char_u *res = NULL;
12315 char_u *p;
12316 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012317 int err = FALSE;
12318 FILE *fd;
12319 list_T *list = NULL;
12320 int flags = SHELL_SILENT;
12321
12322 rettv->v_type = VAR_STRING;
12323 rettv->vval.v_string = NULL;
12324 if (check_restricted() || check_secure())
12325 goto errret;
12326
12327 if (argvars[1].v_type != VAR_UNKNOWN)
12328 {
12329 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012330 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012331 * command.
12332 */
12333 if ((infile = vim_tempname('i', TRUE)) == NULL)
12334 {
12335 EMSG(_(e_notmp));
12336 goto errret;
12337 }
12338
12339 fd = mch_fopen((char *)infile, WRITEBIN);
12340 if (fd == NULL)
12341 {
12342 EMSG2(_(e_notopen), infile);
12343 goto errret;
12344 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012345 if (argvars[1].v_type == VAR_NUMBER)
12346 {
12347 linenr_T lnum;
12348 buf_T *buf;
12349
12350 buf = buflist_findnr(argvars[1].vval.v_number);
12351 if (buf == NULL)
12352 {
12353 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012354 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012355 goto errret;
12356 }
12357
12358 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12359 {
12360 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12361 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12362 {
12363 err = TRUE;
12364 break;
12365 }
12366 if (putc(NL, fd) == EOF)
12367 {
12368 err = TRUE;
12369 break;
12370 }
12371 }
12372 }
12373 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012374 {
12375 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12376 err = TRUE;
12377 }
12378 else
12379 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012380 size_t len;
12381 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012382
12383 p = get_tv_string_buf_chk(&argvars[1], buf);
12384 if (p == NULL)
12385 {
12386 fclose(fd);
12387 goto errret; /* type error; errmsg already given */
12388 }
12389 len = STRLEN(p);
12390 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12391 err = TRUE;
12392 }
12393 if (fclose(fd) != 0)
12394 err = TRUE;
12395 if (err)
12396 {
12397 EMSG(_("E677: Error writing temp file"));
12398 goto errret;
12399 }
12400 }
12401
12402 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12403 * echoes typeahead, that messes up the display. */
12404 if (!msg_silent)
12405 flags += SHELL_COOKED;
12406
12407 if (retlist)
12408 {
12409 int len;
12410 listitem_T *li;
12411 char_u *s = NULL;
12412 char_u *start;
12413 char_u *end;
12414 int i;
12415
12416 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12417 if (res == NULL)
12418 goto errret;
12419
12420 list = list_alloc();
12421 if (list == NULL)
12422 goto errret;
12423
12424 for (i = 0; i < len; ++i)
12425 {
12426 start = res + i;
12427 while (i < len && res[i] != NL)
12428 ++i;
12429 end = res + i;
12430
12431 s = alloc((unsigned)(end - start + 1));
12432 if (s == NULL)
12433 goto errret;
12434
12435 for (p = s; start < end; ++p, ++start)
12436 *p = *start == NUL ? NL : *start;
12437 *p = NUL;
12438
12439 li = listitem_alloc();
12440 if (li == NULL)
12441 {
12442 vim_free(s);
12443 goto errret;
12444 }
12445 li->li_tv.v_type = VAR_STRING;
12446 li->li_tv.v_lock = 0;
12447 li->li_tv.vval.v_string = s;
12448 list_append(list, li);
12449 }
12450
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012451 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012452 list = NULL;
12453 }
12454 else
12455 {
12456 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12457#ifdef USE_CR
12458 /* translate <CR> into <NL> */
12459 if (res != NULL)
12460 {
12461 char_u *s;
12462
12463 for (s = res; *s; ++s)
12464 {
12465 if (*s == CAR)
12466 *s = NL;
12467 }
12468 }
12469#else
12470# ifdef USE_CRNL
12471 /* translate <CR><NL> into <NL> */
12472 if (res != NULL)
12473 {
12474 char_u *s, *d;
12475
12476 d = res;
12477 for (s = res; *s; ++s)
12478 {
12479 if (s[0] == CAR && s[1] == NL)
12480 ++s;
12481 *d++ = *s;
12482 }
12483 *d = NUL;
12484 }
12485# endif
12486#endif
12487 rettv->vval.v_string = res;
12488 res = NULL;
12489 }
12490
12491errret:
12492 if (infile != NULL)
12493 {
12494 mch_remove(infile);
12495 vim_free(infile);
12496 }
12497 if (res != NULL)
12498 vim_free(res);
12499 if (list != NULL)
12500 list_free(list);
12501}
12502
12503/*
12504 * "system()" function
12505 */
12506 static void
12507f_system(typval_T *argvars, typval_T *rettv)
12508{
12509 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12510}
12511
12512/*
12513 * "systemlist()" function
12514 */
12515 static void
12516f_systemlist(typval_T *argvars, typval_T *rettv)
12517{
12518 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12519}
12520
12521/*
12522 * "tabpagebuflist()" function
12523 */
12524 static void
12525f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12526{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012527 tabpage_T *tp;
12528 win_T *wp = NULL;
12529
12530 if (argvars[0].v_type == VAR_UNKNOWN)
12531 wp = firstwin;
12532 else
12533 {
12534 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12535 if (tp != NULL)
12536 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12537 }
12538 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12539 {
12540 for (; wp != NULL; wp = wp->w_next)
12541 if (list_append_number(rettv->vval.v_list,
12542 wp->w_buffer->b_fnum) == FAIL)
12543 break;
12544 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012545}
12546
12547
12548/*
12549 * "tabpagenr()" function
12550 */
12551 static void
12552f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12553{
12554 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012555 char_u *arg;
12556
12557 if (argvars[0].v_type != VAR_UNKNOWN)
12558 {
12559 arg = get_tv_string_chk(&argvars[0]);
12560 nr = 0;
12561 if (arg != NULL)
12562 {
12563 if (STRCMP(arg, "$") == 0)
12564 nr = tabpage_index(NULL) - 1;
12565 else
12566 EMSG2(_(e_invexpr2), arg);
12567 }
12568 }
12569 else
12570 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012571 rettv->vval.v_number = nr;
12572}
12573
12574
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575static int get_winnr(tabpage_T *tp, typval_T *argvar);
12576
12577/*
12578 * Common code for tabpagewinnr() and winnr().
12579 */
12580 static int
12581get_winnr(tabpage_T *tp, typval_T *argvar)
12582{
12583 win_T *twin;
12584 int nr = 1;
12585 win_T *wp;
12586 char_u *arg;
12587
12588 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12589 if (argvar->v_type != VAR_UNKNOWN)
12590 {
12591 arg = get_tv_string_chk(argvar);
12592 if (arg == NULL)
12593 nr = 0; /* type error; errmsg already given */
12594 else if (STRCMP(arg, "$") == 0)
12595 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12596 else if (STRCMP(arg, "#") == 0)
12597 {
12598 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12599 if (twin == NULL)
12600 nr = 0;
12601 }
12602 else
12603 {
12604 EMSG2(_(e_invexpr2), arg);
12605 nr = 0;
12606 }
12607 }
12608
12609 if (nr > 0)
12610 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12611 wp != twin; wp = wp->w_next)
12612 {
12613 if (wp == NULL)
12614 {
12615 /* didn't find it in this tabpage */
12616 nr = 0;
12617 break;
12618 }
12619 ++nr;
12620 }
12621 return nr;
12622}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012623
12624/*
12625 * "tabpagewinnr()" function
12626 */
12627 static void
12628f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12629{
12630 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012631 tabpage_T *tp;
12632
12633 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12634 if (tp == NULL)
12635 nr = 0;
12636 else
12637 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012638 rettv->vval.v_number = nr;
12639}
12640
12641
12642/*
12643 * "tagfiles()" function
12644 */
12645 static void
12646f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12647{
12648 char_u *fname;
12649 tagname_T tn;
12650 int first;
12651
12652 if (rettv_list_alloc(rettv) == FAIL)
12653 return;
12654 fname = alloc(MAXPATHL);
12655 if (fname == NULL)
12656 return;
12657
12658 for (first = TRUE; ; first = FALSE)
12659 if (get_tagfname(&tn, first, fname) == FAIL
12660 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12661 break;
12662 tagname_free(&tn);
12663 vim_free(fname);
12664}
12665
12666/*
12667 * "taglist()" function
12668 */
12669 static void
12670f_taglist(typval_T *argvars, typval_T *rettv)
12671{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012672 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012673 char_u *tag_pattern;
12674
12675 tag_pattern = get_tv_string(&argvars[0]);
12676
12677 rettv->vval.v_number = FALSE;
12678 if (*tag_pattern == NUL)
12679 return;
12680
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012681 if (argvars[1].v_type != VAR_UNKNOWN)
12682 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012683 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012684 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012685}
12686
12687/*
12688 * "tempname()" function
12689 */
12690 static void
12691f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12692{
12693 static int x = 'A';
12694
12695 rettv->v_type = VAR_STRING;
12696 rettv->vval.v_string = vim_tempname(x, FALSE);
12697
12698 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12699 * names. Skip 'I' and 'O', they are used for shell redirection. */
12700 do
12701 {
12702 if (x == 'Z')
12703 x = '0';
12704 else if (x == '9')
12705 x = 'A';
12706 else
12707 {
12708#ifdef EBCDIC
12709 if (x == 'I')
12710 x = 'J';
12711 else if (x == 'R')
12712 x = 'S';
12713 else
12714#endif
12715 ++x;
12716 }
12717 } while (x == 'I' || x == 'O');
12718}
12719
12720#ifdef FEAT_FLOAT
12721/*
12722 * "tan()" function
12723 */
12724 static void
12725f_tan(typval_T *argvars, typval_T *rettv)
12726{
12727 float_T f = 0.0;
12728
12729 rettv->v_type = VAR_FLOAT;
12730 if (get_float_arg(argvars, &f) == OK)
12731 rettv->vval.v_float = tan(f);
12732 else
12733 rettv->vval.v_float = 0.0;
12734}
12735
12736/*
12737 * "tanh()" function
12738 */
12739 static void
12740f_tanh(typval_T *argvars, typval_T *rettv)
12741{
12742 float_T f = 0.0;
12743
12744 rettv->v_type = VAR_FLOAT;
12745 if (get_float_arg(argvars, &f) == OK)
12746 rettv->vval.v_float = tanh(f);
12747 else
12748 rettv->vval.v_float = 0.0;
12749}
12750#endif
12751
12752/*
12753 * "test_alloc_fail(id, countdown, repeat)" function
12754 */
12755 static void
12756f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12757{
12758 if (argvars[0].v_type != VAR_NUMBER
12759 || argvars[0].vval.v_number <= 0
12760 || argvars[1].v_type != VAR_NUMBER
12761 || argvars[1].vval.v_number < 0
12762 || argvars[2].v_type != VAR_NUMBER)
12763 EMSG(_(e_invarg));
12764 else
12765 {
12766 alloc_fail_id = argvars[0].vval.v_number;
12767 if (alloc_fail_id >= aid_last)
12768 EMSG(_(e_invarg));
12769 alloc_fail_countdown = argvars[1].vval.v_number;
12770 alloc_fail_repeat = argvars[2].vval.v_number;
12771 did_outofmem_msg = FALSE;
12772 }
12773}
12774
12775/*
12776 * "test_autochdir()"
12777 */
12778 static void
12779f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12780{
12781#if defined(FEAT_AUTOCHDIR)
12782 test_autochdir = TRUE;
12783#endif
12784}
12785
12786/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012787 * "test_feedinput()"
12788 */
12789 static void
12790f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12791{
12792#ifdef USE_INPUT_BUF
12793 char_u *val = get_tv_string_chk(&argvars[0]);
12794
12795 if (val != NULL)
12796 {
12797 trash_input_buf();
12798 add_to_input_buf_csi(val, (int)STRLEN(val));
12799 }
12800#endif
12801}
12802
12803/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012804 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012805 */
12806 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012807f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012808{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012809 char_u *name = (char_u *)"";
12810 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012811 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012812
12813 if (argvars[0].v_type != VAR_STRING
12814 || (argvars[1].v_type) != VAR_NUMBER)
12815 EMSG(_(e_invarg));
12816 else
12817 {
12818 name = get_tv_string_chk(&argvars[0]);
12819 val = (int)get_tv_number(&argvars[1]);
12820
12821 if (STRCMP(name, (char_u *)"redraw") == 0)
12822 disable_redraw_for_testing = val;
12823 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12824 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012825 else if (STRCMP(name, (char_u *)"starting") == 0)
12826 {
12827 if (val)
12828 {
12829 if (save_starting < 0)
12830 save_starting = starting;
12831 starting = 0;
12832 }
12833 else
12834 {
12835 starting = save_starting;
12836 save_starting = -1;
12837 }
12838 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012839 else if (STRCMP(name, (char_u *)"ALL") == 0)
12840 {
12841 disable_char_avail_for_testing = FALSE;
12842 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012843 if (save_starting >= 0)
12844 {
12845 starting = save_starting;
12846 save_starting = -1;
12847 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012848 }
12849 else
12850 EMSG2(_(e_invarg2), name);
12851 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012852}
12853
12854/*
12855 * "test_garbagecollect_now()" function
12856 */
12857 static void
12858f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12859{
12860 /* This is dangerous, any Lists and Dicts used internally may be freed
12861 * while still in use. */
12862 garbage_collect(TRUE);
12863}
12864
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012865/*
12866 * "test_ignore_error()" function
12867 */
12868 static void
12869f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12870{
12871 ignore_error_for_testing(get_tv_string(&argvars[0]));
12872}
12873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012874#ifdef FEAT_JOB_CHANNEL
12875 static void
12876f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12877{
12878 rettv->v_type = VAR_CHANNEL;
12879 rettv->vval.v_channel = NULL;
12880}
12881#endif
12882
12883 static void
12884f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12885{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012886 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012887}
12888
12889#ifdef FEAT_JOB_CHANNEL
12890 static void
12891f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12892{
12893 rettv->v_type = VAR_JOB;
12894 rettv->vval.v_job = NULL;
12895}
12896#endif
12897
12898 static void
12899f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12900{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012901 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012902}
12903
12904 static void
12905f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12906{
12907 rettv->v_type = VAR_PARTIAL;
12908 rettv->vval.v_partial = NULL;
12909}
12910
12911 static void
12912f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12913{
12914 rettv->v_type = VAR_STRING;
12915 rettv->vval.v_string = NULL;
12916}
12917
12918 static void
12919f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12920{
12921 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12922}
12923
12924#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12925/*
12926 * Get a callback from "arg". It can be a Funcref or a function name.
12927 * When "arg" is zero return an empty string.
12928 * Return NULL for an invalid argument.
12929 */
12930 char_u *
12931get_callback(typval_T *arg, partial_T **pp)
12932{
12933 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12934 {
12935 *pp = arg->vval.v_partial;
12936 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012937 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012938 }
12939 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012940 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012941 {
12942 func_ref(arg->vval.v_string);
12943 return arg->vval.v_string;
12944 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012945 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12946 return (char_u *)"";
12947 EMSG(_("E921: Invalid callback argument"));
12948 return NULL;
12949}
12950
12951/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020012952 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012953 */
12954 void
12955free_callback(char_u *callback, partial_T *partial)
12956{
12957 if (partial != NULL)
12958 partial_unref(partial);
12959 else if (callback != NULL)
12960 {
12961 func_unref(callback);
12962 vim_free(callback);
12963 }
12964}
12965#endif
12966
12967#ifdef FEAT_TIMERS
12968/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012969 * "timer_info([timer])" function
12970 */
12971 static void
12972f_timer_info(typval_T *argvars, typval_T *rettv)
12973{
12974 timer_T *timer = NULL;
12975
12976 if (rettv_list_alloc(rettv) != OK)
12977 return;
12978 if (argvars[0].v_type != VAR_UNKNOWN)
12979 {
12980 if (argvars[0].v_type != VAR_NUMBER)
12981 EMSG(_(e_number_exp));
12982 else
12983 {
12984 timer = find_timer((int)get_tv_number(&argvars[0]));
12985 if (timer != NULL)
12986 add_timer_info(rettv, timer);
12987 }
12988 }
12989 else
12990 add_timer_info_all(rettv);
12991}
12992
12993/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012994 * "timer_pause(timer, paused)" function
12995 */
12996 static void
12997f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12998{
12999 timer_T *timer = NULL;
13000 int paused = (int)get_tv_number(&argvars[1]);
13001
13002 if (argvars[0].v_type != VAR_NUMBER)
13003 EMSG(_(e_number_exp));
13004 else
13005 {
13006 timer = find_timer((int)get_tv_number(&argvars[0]));
13007 if (timer != NULL)
13008 timer->tr_paused = paused;
13009 }
13010}
13011
13012/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013013 * "timer_start(time, callback [, options])" function
13014 */
13015 static void
13016f_timer_start(typval_T *argvars, typval_T *rettv)
13017{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013018 long msec = (long)get_tv_number(&argvars[0]);
13019 timer_T *timer;
13020 int repeat = 0;
13021 char_u *callback;
13022 dict_T *dict;
13023 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013024
Bram Moolenaar75537a92016-09-05 22:45:28 +020013025 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013026 if (check_secure())
13027 return;
13028 if (argvars[2].v_type != VAR_UNKNOWN)
13029 {
13030 if (argvars[2].v_type != VAR_DICT
13031 || (dict = argvars[2].vval.v_dict) == NULL)
13032 {
13033 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13034 return;
13035 }
13036 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13037 repeat = get_dict_number(dict, (char_u *)"repeat");
13038 }
13039
Bram Moolenaar75537a92016-09-05 22:45:28 +020013040 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013041 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013042 return;
13043
13044 timer = create_timer(msec, repeat);
13045 if (timer == NULL)
13046 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013047 else
13048 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013049 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013050 timer->tr_callback = vim_strsave(callback);
13051 else
13052 /* pointer into the partial */
13053 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013054 timer->tr_partial = partial;
13055 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013056 }
13057}
13058
13059/*
13060 * "timer_stop(timer)" function
13061 */
13062 static void
13063f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13064{
13065 timer_T *timer;
13066
13067 if (argvars[0].v_type != VAR_NUMBER)
13068 {
13069 EMSG(_(e_number_exp));
13070 return;
13071 }
13072 timer = find_timer((int)get_tv_number(&argvars[0]));
13073 if (timer != NULL)
13074 stop_timer(timer);
13075}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013076
13077/*
13078 * "timer_stopall()" function
13079 */
13080 static void
13081f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13082{
13083 stop_all_timers();
13084}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013085#endif
13086
13087/*
13088 * "tolower(string)" function
13089 */
13090 static void
13091f_tolower(typval_T *argvars, typval_T *rettv)
13092{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013093 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013094 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013095}
13096
13097/*
13098 * "toupper(string)" function
13099 */
13100 static void
13101f_toupper(typval_T *argvars, typval_T *rettv)
13102{
13103 rettv->v_type = VAR_STRING;
13104 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13105}
13106
13107/*
13108 * "tr(string, fromstr, tostr)" function
13109 */
13110 static void
13111f_tr(typval_T *argvars, typval_T *rettv)
13112{
13113 char_u *in_str;
13114 char_u *fromstr;
13115 char_u *tostr;
13116 char_u *p;
13117#ifdef FEAT_MBYTE
13118 int inlen;
13119 int fromlen;
13120 int tolen;
13121 int idx;
13122 char_u *cpstr;
13123 int cplen;
13124 int first = TRUE;
13125#endif
13126 char_u buf[NUMBUFLEN];
13127 char_u buf2[NUMBUFLEN];
13128 garray_T ga;
13129
13130 in_str = get_tv_string(&argvars[0]);
13131 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13132 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13133
13134 /* Default return value: empty string. */
13135 rettv->v_type = VAR_STRING;
13136 rettv->vval.v_string = NULL;
13137 if (fromstr == NULL || tostr == NULL)
13138 return; /* type error; errmsg already given */
13139 ga_init2(&ga, (int)sizeof(char), 80);
13140
13141#ifdef FEAT_MBYTE
13142 if (!has_mbyte)
13143#endif
13144 /* not multi-byte: fromstr and tostr must be the same length */
13145 if (STRLEN(fromstr) != STRLEN(tostr))
13146 {
13147#ifdef FEAT_MBYTE
13148error:
13149#endif
13150 EMSG2(_(e_invarg2), fromstr);
13151 ga_clear(&ga);
13152 return;
13153 }
13154
13155 /* fromstr and tostr have to contain the same number of chars */
13156 while (*in_str != NUL)
13157 {
13158#ifdef FEAT_MBYTE
13159 if (has_mbyte)
13160 {
13161 inlen = (*mb_ptr2len)(in_str);
13162 cpstr = in_str;
13163 cplen = inlen;
13164 idx = 0;
13165 for (p = fromstr; *p != NUL; p += fromlen)
13166 {
13167 fromlen = (*mb_ptr2len)(p);
13168 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13169 {
13170 for (p = tostr; *p != NUL; p += tolen)
13171 {
13172 tolen = (*mb_ptr2len)(p);
13173 if (idx-- == 0)
13174 {
13175 cplen = tolen;
13176 cpstr = p;
13177 break;
13178 }
13179 }
13180 if (*p == NUL) /* tostr is shorter than fromstr */
13181 goto error;
13182 break;
13183 }
13184 ++idx;
13185 }
13186
13187 if (first && cpstr == in_str)
13188 {
13189 /* Check that fromstr and tostr have the same number of
13190 * (multi-byte) characters. Done only once when a character
13191 * of in_str doesn't appear in fromstr. */
13192 first = FALSE;
13193 for (p = tostr; *p != NUL; p += tolen)
13194 {
13195 tolen = (*mb_ptr2len)(p);
13196 --idx;
13197 }
13198 if (idx != 0)
13199 goto error;
13200 }
13201
13202 (void)ga_grow(&ga, cplen);
13203 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13204 ga.ga_len += cplen;
13205
13206 in_str += inlen;
13207 }
13208 else
13209#endif
13210 {
13211 /* When not using multi-byte chars we can do it faster. */
13212 p = vim_strchr(fromstr, *in_str);
13213 if (p != NULL)
13214 ga_append(&ga, tostr[p - fromstr]);
13215 else
13216 ga_append(&ga, *in_str);
13217 ++in_str;
13218 }
13219 }
13220
13221 /* add a terminating NUL */
13222 (void)ga_grow(&ga, 1);
13223 ga_append(&ga, NUL);
13224
13225 rettv->vval.v_string = ga.ga_data;
13226}
13227
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013228/*
13229 * "trim({expr})" function
13230 */
13231 static void
13232f_trim(typval_T *argvars, typval_T *rettv)
13233{
13234 char_u buf1[NUMBUFLEN];
13235 char_u buf2[NUMBUFLEN];
13236 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13237 char_u *mask = NULL;
13238 char_u *tail;
13239 char_u *prev;
13240 char_u *p;
13241 int c1;
13242
13243 rettv->v_type = VAR_STRING;
13244 if (head == NULL)
13245 {
13246 rettv->vval.v_string = NULL;
13247 return;
13248 }
13249
13250 if (argvars[1].v_type == VAR_STRING)
13251 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13252
13253 while (*head != NUL)
13254 {
13255 c1 = PTR2CHAR(head);
13256 if (mask == NULL)
13257 {
13258 if (c1 > ' ' && c1 != 0xa0)
13259 break;
13260 }
13261 else
13262 {
13263 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13264 if (c1 == PTR2CHAR(p))
13265 break;
13266 if (*p == NUL)
13267 break;
13268 }
13269 MB_PTR_ADV(head);
13270 }
13271
13272 for (tail = head + STRLEN(head); tail > head; tail = prev)
13273 {
13274 prev = tail;
13275 MB_PTR_BACK(head, prev);
13276 c1 = PTR2CHAR(prev);
13277 if (mask == NULL)
13278 {
13279 if (c1 > ' ' && c1 != 0xa0)
13280 break;
13281 }
13282 else
13283 {
13284 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13285 if (c1 == PTR2CHAR(p))
13286 break;
13287 if (*p == NUL)
13288 break;
13289 }
13290 }
13291 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13292}
13293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013294#ifdef FEAT_FLOAT
13295/*
13296 * "trunc({float})" function
13297 */
13298 static void
13299f_trunc(typval_T *argvars, typval_T *rettv)
13300{
13301 float_T f = 0.0;
13302
13303 rettv->v_type = VAR_FLOAT;
13304 if (get_float_arg(argvars, &f) == OK)
13305 /* trunc() is not in C90, use floor() or ceil() instead. */
13306 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13307 else
13308 rettv->vval.v_float = 0.0;
13309}
13310#endif
13311
13312/*
13313 * "type(expr)" function
13314 */
13315 static void
13316f_type(typval_T *argvars, typval_T *rettv)
13317{
13318 int n = -1;
13319
13320 switch (argvars[0].v_type)
13321 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013322 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13323 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013324 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013325 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13326 case VAR_LIST: n = VAR_TYPE_LIST; break;
13327 case VAR_DICT: n = VAR_TYPE_DICT; break;
13328 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013329 case VAR_SPECIAL:
13330 if (argvars[0].vval.v_number == VVAL_FALSE
13331 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013332 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013333 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013334 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013335 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013336 case VAR_JOB: n = VAR_TYPE_JOB; break;
13337 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013338 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013339 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013340 n = -1;
13341 break;
13342 }
13343 rettv->vval.v_number = n;
13344}
13345
13346/*
13347 * "undofile(name)" function
13348 */
13349 static void
13350f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13351{
13352 rettv->v_type = VAR_STRING;
13353#ifdef FEAT_PERSISTENT_UNDO
13354 {
13355 char_u *fname = get_tv_string(&argvars[0]);
13356
13357 if (*fname == NUL)
13358 {
13359 /* If there is no file name there will be no undo file. */
13360 rettv->vval.v_string = NULL;
13361 }
13362 else
13363 {
13364 char_u *ffname = FullName_save(fname, FALSE);
13365
13366 if (ffname != NULL)
13367 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13368 vim_free(ffname);
13369 }
13370 }
13371#else
13372 rettv->vval.v_string = NULL;
13373#endif
13374}
13375
13376/*
13377 * "undotree()" function
13378 */
13379 static void
13380f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13381{
13382 if (rettv_dict_alloc(rettv) == OK)
13383 {
13384 dict_T *dict = rettv->vval.v_dict;
13385 list_T *list;
13386
13387 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13388 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13389 dict_add_nr_str(dict, "save_last",
13390 (long)curbuf->b_u_save_nr_last, NULL);
13391 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13392 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13393 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13394
13395 list = list_alloc();
13396 if (list != NULL)
13397 {
13398 u_eval_tree(curbuf->b_u_oldhead, list);
13399 dict_add_list(dict, "entries", list);
13400 }
13401 }
13402}
13403
13404/*
13405 * "values(dict)" function
13406 */
13407 static void
13408f_values(typval_T *argvars, typval_T *rettv)
13409{
13410 dict_list(argvars, rettv, 1);
13411}
13412
13413/*
13414 * "virtcol(string)" function
13415 */
13416 static void
13417f_virtcol(typval_T *argvars, typval_T *rettv)
13418{
13419 colnr_T vcol = 0;
13420 pos_T *fp;
13421 int fnum = curbuf->b_fnum;
13422
13423 fp = var2fpos(&argvars[0], FALSE, &fnum);
13424 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13425 && fnum == curbuf->b_fnum)
13426 {
13427 getvvcol(curwin, fp, NULL, NULL, &vcol);
13428 ++vcol;
13429 }
13430
13431 rettv->vval.v_number = vcol;
13432}
13433
13434/*
13435 * "visualmode()" function
13436 */
13437 static void
13438f_visualmode(typval_T *argvars, typval_T *rettv)
13439{
13440 char_u str[2];
13441
13442 rettv->v_type = VAR_STRING;
13443 str[0] = curbuf->b_visual_mode_eval;
13444 str[1] = NUL;
13445 rettv->vval.v_string = vim_strsave(str);
13446
13447 /* A non-zero number or non-empty string argument: reset mode. */
13448 if (non_zero_arg(&argvars[0]))
13449 curbuf->b_visual_mode_eval = NUL;
13450}
13451
13452/*
13453 * "wildmenumode()" function
13454 */
13455 static void
13456f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13457{
13458#ifdef FEAT_WILDMENU
13459 if (wild_menu_showing)
13460 rettv->vval.v_number = 1;
13461#endif
13462}
13463
13464/*
13465 * "winbufnr(nr)" function
13466 */
13467 static void
13468f_winbufnr(typval_T *argvars, typval_T *rettv)
13469{
13470 win_T *wp;
13471
13472 wp = find_win_by_nr(&argvars[0], NULL);
13473 if (wp == NULL)
13474 rettv->vval.v_number = -1;
13475 else
13476 rettv->vval.v_number = wp->w_buffer->b_fnum;
13477}
13478
13479/*
13480 * "wincol()" function
13481 */
13482 static void
13483f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13484{
13485 validate_cursor();
13486 rettv->vval.v_number = curwin->w_wcol + 1;
13487}
13488
13489/*
13490 * "winheight(nr)" function
13491 */
13492 static void
13493f_winheight(typval_T *argvars, typval_T *rettv)
13494{
13495 win_T *wp;
13496
13497 wp = find_win_by_nr(&argvars[0], NULL);
13498 if (wp == NULL)
13499 rettv->vval.v_number = -1;
13500 else
13501 rettv->vval.v_number = wp->w_height;
13502}
13503
13504/*
13505 * "winline()" function
13506 */
13507 static void
13508f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13509{
13510 validate_cursor();
13511 rettv->vval.v_number = curwin->w_wrow + 1;
13512}
13513
13514/*
13515 * "winnr()" function
13516 */
13517 static void
13518f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13519{
13520 int nr = 1;
13521
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013522 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013523 rettv->vval.v_number = nr;
13524}
13525
13526/*
13527 * "winrestcmd()" function
13528 */
13529 static void
13530f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13531{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013532 win_T *wp;
13533 int winnr = 1;
13534 garray_T ga;
13535 char_u buf[50];
13536
13537 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013538 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013539 {
13540 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13541 ga_concat(&ga, buf);
13542 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13543 ga_concat(&ga, buf);
13544 ++winnr;
13545 }
13546 ga_append(&ga, NUL);
13547
13548 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013549 rettv->v_type = VAR_STRING;
13550}
13551
13552/*
13553 * "winrestview()" function
13554 */
13555 static void
13556f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13557{
13558 dict_T *dict;
13559
13560 if (argvars[0].v_type != VAR_DICT
13561 || (dict = argvars[0].vval.v_dict) == NULL)
13562 EMSG(_(e_invarg));
13563 else
13564 {
13565 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13566 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13567 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13568 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13569#ifdef FEAT_VIRTUALEDIT
13570 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13571 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13572#endif
13573 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13574 {
13575 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13576 curwin->w_set_curswant = FALSE;
13577 }
13578
13579 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13580 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13581#ifdef FEAT_DIFF
13582 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13583 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13584#endif
13585 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13586 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13587 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13588 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13589
13590 check_cursor();
13591 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013592 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013593 changed_window_setting();
13594
13595 if (curwin->w_topline <= 0)
13596 curwin->w_topline = 1;
13597 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13598 curwin->w_topline = curbuf->b_ml.ml_line_count;
13599#ifdef FEAT_DIFF
13600 check_topfill(curwin, TRUE);
13601#endif
13602 }
13603}
13604
13605/*
13606 * "winsaveview()" function
13607 */
13608 static void
13609f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13610{
13611 dict_T *dict;
13612
13613 if (rettv_dict_alloc(rettv) == FAIL)
13614 return;
13615 dict = rettv->vval.v_dict;
13616
13617 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13618 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13619#ifdef FEAT_VIRTUALEDIT
13620 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13621#endif
13622 update_curswant();
13623 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13624
13625 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13626#ifdef FEAT_DIFF
13627 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13628#endif
13629 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13630 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13631}
13632
13633/*
13634 * "winwidth(nr)" function
13635 */
13636 static void
13637f_winwidth(typval_T *argvars, typval_T *rettv)
13638{
13639 win_T *wp;
13640
13641 wp = find_win_by_nr(&argvars[0], NULL);
13642 if (wp == NULL)
13643 rettv->vval.v_number = -1;
13644 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013645 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013646}
13647
13648/*
13649 * "wordcount()" function
13650 */
13651 static void
13652f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13653{
13654 if (rettv_dict_alloc(rettv) == FAIL)
13655 return;
13656 cursor_pos_info(rettv->vval.v_dict);
13657}
13658
13659/*
13660 * "writefile()" function
13661 */
13662 static void
13663f_writefile(typval_T *argvars, typval_T *rettv)
13664{
13665 int binary = FALSE;
13666 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013667#ifdef HAVE_FSYNC
13668 int do_fsync = p_fs;
13669#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013670 char_u *fname;
13671 FILE *fd;
13672 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013673 listitem_T *li;
13674 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013675
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013676 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013677 if (check_restricted() || check_secure())
13678 return;
13679
13680 if (argvars[0].v_type != VAR_LIST)
13681 {
13682 EMSG2(_(e_listarg), "writefile()");
13683 return;
13684 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013685 list = argvars[0].vval.v_list;
13686 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013687 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013688 for (li = list->lv_first; li != NULL; li = li->li_next)
13689 if (get_tv_string_chk(&li->li_tv) == NULL)
13690 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013691
13692 if (argvars[2].v_type != VAR_UNKNOWN)
13693 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013694 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13695
13696 if (arg2 == NULL)
13697 return;
13698 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013699 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013700 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013701 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013702#ifdef HAVE_FSYNC
13703 if (vim_strchr(arg2, 's') != NULL)
13704 do_fsync = TRUE;
13705 else if (vim_strchr(arg2, 'S') != NULL)
13706 do_fsync = FALSE;
13707#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013708 }
13709
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013710 fname = get_tv_string_chk(&argvars[1]);
13711 if (fname == NULL)
13712 return;
13713
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013714 /* Always open the file in binary mode, library functions have a mind of
13715 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013716 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13717 append ? APPENDBIN : WRITEBIN)) == NULL)
13718 {
13719 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13720 ret = -1;
13721 }
13722 else
13723 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013724 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013725 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013726#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013727 else if (do_fsync)
13728 /* Ignore the error, the user wouldn't know what to do about it.
13729 * May happen for a device. */
13730 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013731#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013732 fclose(fd);
13733 }
13734
13735 rettv->vval.v_number = ret;
13736}
13737
13738/*
13739 * "xor(expr, expr)" function
13740 */
13741 static void
13742f_xor(typval_T *argvars, typval_T *rettv)
13743{
13744 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13745 ^ get_tv_number_chk(&argvars[1], NULL);
13746}
13747
13748
13749#endif /* FEAT_EVAL */