blob: 90aa2efd50e1b08683d8ea62b27a2e4e0dd001a8 [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);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200309static void f_reg_executing(typval_T *argvars, typval_T *rettv);
310static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200311static void f_reltime(typval_T *argvars, typval_T *rettv);
312#ifdef FEAT_FLOAT
313static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
314#endif
315static void f_reltimestr(typval_T *argvars, typval_T *rettv);
316static void f_remote_expr(typval_T *argvars, typval_T *rettv);
317static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
318static void f_remote_peek(typval_T *argvars, typval_T *rettv);
319static void f_remote_read(typval_T *argvars, typval_T *rettv);
320static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100321static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200322static void f_remove(typval_T *argvars, typval_T *rettv);
323static void f_rename(typval_T *argvars, typval_T *rettv);
324static void f_repeat(typval_T *argvars, typval_T *rettv);
325static void f_resolve(typval_T *argvars, typval_T *rettv);
326static void f_reverse(typval_T *argvars, typval_T *rettv);
327#ifdef FEAT_FLOAT
328static void f_round(typval_T *argvars, typval_T *rettv);
329#endif
330static void f_screenattr(typval_T *argvars, typval_T *rettv);
331static void f_screenchar(typval_T *argvars, typval_T *rettv);
332static void f_screencol(typval_T *argvars, typval_T *rettv);
333static void f_screenrow(typval_T *argvars, typval_T *rettv);
334static void f_search(typval_T *argvars, typval_T *rettv);
335static void f_searchdecl(typval_T *argvars, typval_T *rettv);
336static void f_searchpair(typval_T *argvars, typval_T *rettv);
337static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
338static void f_searchpos(typval_T *argvars, typval_T *rettv);
339static void f_server2client(typval_T *argvars, typval_T *rettv);
340static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200341static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200342static void f_setbufvar(typval_T *argvars, typval_T *rettv);
343static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
344static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
345static void f_setfperm(typval_T *argvars, typval_T *rettv);
346static void f_setline(typval_T *argvars, typval_T *rettv);
347static void f_setloclist(typval_T *argvars, typval_T *rettv);
348static void f_setmatches(typval_T *argvars, typval_T *rettv);
349static void f_setpos(typval_T *argvars, typval_T *rettv);
350static void f_setqflist(typval_T *argvars, typval_T *rettv);
351static void f_setreg(typval_T *argvars, typval_T *rettv);
352static void f_settabvar(typval_T *argvars, typval_T *rettv);
353static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
354static void f_setwinvar(typval_T *argvars, typval_T *rettv);
355#ifdef FEAT_CRYPT
356static void f_sha256(typval_T *argvars, typval_T *rettv);
357#endif /* FEAT_CRYPT */
358static void f_shellescape(typval_T *argvars, typval_T *rettv);
359static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
360static void f_simplify(typval_T *argvars, typval_T *rettv);
361#ifdef FEAT_FLOAT
362static void f_sin(typval_T *argvars, typval_T *rettv);
363static void f_sinh(typval_T *argvars, typval_T *rettv);
364#endif
365static void f_sort(typval_T *argvars, typval_T *rettv);
366static void f_soundfold(typval_T *argvars, typval_T *rettv);
367static void f_spellbadword(typval_T *argvars, typval_T *rettv);
368static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
369static void f_split(typval_T *argvars, typval_T *rettv);
370#ifdef FEAT_FLOAT
371static void f_sqrt(typval_T *argvars, typval_T *rettv);
372static void f_str2float(typval_T *argvars, typval_T *rettv);
373#endif
374static void f_str2nr(typval_T *argvars, typval_T *rettv);
375static void f_strchars(typval_T *argvars, typval_T *rettv);
376#ifdef HAVE_STRFTIME
377static void f_strftime(typval_T *argvars, typval_T *rettv);
378#endif
379static void f_strgetchar(typval_T *argvars, typval_T *rettv);
380static void f_stridx(typval_T *argvars, typval_T *rettv);
381static void f_string(typval_T *argvars, typval_T *rettv);
382static void f_strlen(typval_T *argvars, typval_T *rettv);
383static void f_strcharpart(typval_T *argvars, typval_T *rettv);
384static void f_strpart(typval_T *argvars, typval_T *rettv);
385static void f_strridx(typval_T *argvars, typval_T *rettv);
386static void f_strtrans(typval_T *argvars, typval_T *rettv);
387static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
388static void f_strwidth(typval_T *argvars, typval_T *rettv);
389static void f_submatch(typval_T *argvars, typval_T *rettv);
390static void f_substitute(typval_T *argvars, typval_T *rettv);
391static void f_synID(typval_T *argvars, typval_T *rettv);
392static void f_synIDattr(typval_T *argvars, typval_T *rettv);
393static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
394static void f_synstack(typval_T *argvars, typval_T *rettv);
395static void f_synconcealed(typval_T *argvars, typval_T *rettv);
396static void f_system(typval_T *argvars, typval_T *rettv);
397static void f_systemlist(typval_T *argvars, typval_T *rettv);
398static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
399static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
400static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
401static void f_taglist(typval_T *argvars, typval_T *rettv);
402static void f_tagfiles(typval_T *argvars, typval_T *rettv);
403static void f_tempname(typval_T *argvars, typval_T *rettv);
404static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
405static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200406static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100407static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200408static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100409static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200410#ifdef FEAT_JOB_CHANNEL
411static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
412#endif
413static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
414#ifdef FEAT_JOB_CHANNEL
415static void f_test_null_job(typval_T *argvars, typval_T *rettv);
416#endif
417static void f_test_null_list(typval_T *argvars, typval_T *rettv);
418static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
419static void f_test_null_string(typval_T *argvars, typval_T *rettv);
420static void f_test_settime(typval_T *argvars, typval_T *rettv);
421#ifdef FEAT_FLOAT
422static void f_tan(typval_T *argvars, typval_T *rettv);
423static void f_tanh(typval_T *argvars, typval_T *rettv);
424#endif
425#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200426static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200427static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200428static void f_timer_start(typval_T *argvars, typval_T *rettv);
429static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200430static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200431#endif
432static void f_tolower(typval_T *argvars, typval_T *rettv);
433static void f_toupper(typval_T *argvars, typval_T *rettv);
434static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100435static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#ifdef FEAT_FLOAT
437static void f_trunc(typval_T *argvars, typval_T *rettv);
438#endif
439static void f_type(typval_T *argvars, typval_T *rettv);
440static void f_undofile(typval_T *argvars, typval_T *rettv);
441static void f_undotree(typval_T *argvars, typval_T *rettv);
442static void f_uniq(typval_T *argvars, typval_T *rettv);
443static void f_values(typval_T *argvars, typval_T *rettv);
444static void f_virtcol(typval_T *argvars, typval_T *rettv);
445static void f_visualmode(typval_T *argvars, typval_T *rettv);
446static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
447static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
448static void f_win_getid(typval_T *argvars, typval_T *rettv);
449static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
450static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
451static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100452static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200453static void f_winbufnr(typval_T *argvars, typval_T *rettv);
454static void f_wincol(typval_T *argvars, typval_T *rettv);
455static void f_winheight(typval_T *argvars, typval_T *rettv);
456static void f_winline(typval_T *argvars, typval_T *rettv);
457static void f_winnr(typval_T *argvars, typval_T *rettv);
458static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
459static void f_winrestview(typval_T *argvars, typval_T *rettv);
460static void f_winsaveview(typval_T *argvars, typval_T *rettv);
461static void f_winwidth(typval_T *argvars, typval_T *rettv);
462static void f_writefile(typval_T *argvars, typval_T *rettv);
463static void f_wordcount(typval_T *argvars, typval_T *rettv);
464static void f_xor(typval_T *argvars, typval_T *rettv);
465
466/*
467 * Array with names and number of arguments of all internal functions
468 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
469 */
470static struct fst
471{
472 char *f_name; /* function name */
473 char f_min_argc; /* minimal number of arguments */
474 char f_max_argc; /* maximal number of arguments */
475 void (*f_func)(typval_T *args, typval_T *rvar);
476 /* implementation of function */
477} functions[] =
478{
479#ifdef FEAT_FLOAT
480 {"abs", 1, 1, f_abs},
481 {"acos", 1, 1, f_acos}, /* WJMc */
482#endif
483 {"add", 2, 2, f_add},
484 {"and", 2, 2, f_and},
485 {"append", 2, 2, f_append},
486 {"argc", 0, 0, f_argc},
487 {"argidx", 0, 0, f_argidx},
488 {"arglistid", 0, 2, f_arglistid},
489 {"argv", 0, 1, f_argv},
490#ifdef FEAT_FLOAT
491 {"asin", 1, 1, f_asin}, /* WJMc */
492#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100493 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200494 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100495 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200496 {"assert_exception", 1, 2, f_assert_exception},
497 {"assert_fails", 1, 2, f_assert_fails},
498 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100499 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200500 {"assert_match", 2, 3, f_assert_match},
501 {"assert_notequal", 2, 3, f_assert_notequal},
502 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100503 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200504 {"assert_true", 1, 2, f_assert_true},
505#ifdef FEAT_FLOAT
506 {"atan", 1, 1, f_atan},
507 {"atan2", 2, 2, f_atan2},
508#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100509#ifdef FEAT_BEVAL
510 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100511# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100512 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100513# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100514#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200515 {"browse", 4, 4, f_browse},
516 {"browsedir", 2, 2, f_browsedir},
517 {"bufexists", 1, 1, f_bufexists},
518 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
519 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
520 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
521 {"buflisted", 1, 1, f_buflisted},
522 {"bufloaded", 1, 1, f_bufloaded},
523 {"bufname", 1, 1, f_bufname},
524 {"bufnr", 1, 2, f_bufnr},
525 {"bufwinid", 1, 1, f_bufwinid},
526 {"bufwinnr", 1, 1, f_bufwinnr},
527 {"byte2line", 1, 1, f_byte2line},
528 {"byteidx", 2, 2, f_byteidx},
529 {"byteidxcomp", 2, 2, f_byteidxcomp},
530 {"call", 2, 3, f_call},
531#ifdef FEAT_FLOAT
532 {"ceil", 1, 1, f_ceil},
533#endif
534#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100535 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200537 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200538 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
539 {"ch_evalraw", 2, 3, f_ch_evalraw},
540 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
541 {"ch_getjob", 1, 1, f_ch_getjob},
542 {"ch_info", 1, 1, f_ch_info},
543 {"ch_log", 1, 2, f_ch_log},
544 {"ch_logfile", 1, 2, f_ch_logfile},
545 {"ch_open", 1, 2, f_ch_open},
546 {"ch_read", 1, 2, f_ch_read},
547 {"ch_readraw", 1, 2, f_ch_readraw},
548 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
549 {"ch_sendraw", 2, 3, f_ch_sendraw},
550 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200551 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200552#endif
553 {"changenr", 0, 0, f_changenr},
554 {"char2nr", 1, 2, f_char2nr},
555 {"cindent", 1, 1, f_cindent},
556 {"clearmatches", 0, 0, f_clearmatches},
557 {"col", 1, 1, f_col},
558#if defined(FEAT_INS_EXPAND)
559 {"complete", 2, 2, f_complete},
560 {"complete_add", 1, 1, f_complete_add},
561 {"complete_check", 0, 0, f_complete_check},
562#endif
563 {"confirm", 1, 4, f_confirm},
564 {"copy", 1, 1, f_copy},
565#ifdef FEAT_FLOAT
566 {"cos", 1, 1, f_cos},
567 {"cosh", 1, 1, f_cosh},
568#endif
569 {"count", 2, 4, f_count},
570 {"cscope_connection",0,3, f_cscope_connection},
571 {"cursor", 1, 3, f_cursor},
572 {"deepcopy", 1, 2, f_deepcopy},
573 {"delete", 1, 2, f_delete},
574 {"did_filetype", 0, 0, f_did_filetype},
575 {"diff_filler", 1, 1, f_diff_filler},
576 {"diff_hlID", 2, 2, f_diff_hlID},
577 {"empty", 1, 1, f_empty},
578 {"escape", 2, 2, f_escape},
579 {"eval", 1, 1, f_eval},
580 {"eventhandler", 0, 0, f_eventhandler},
581 {"executable", 1, 1, f_executable},
582 {"execute", 1, 2, f_execute},
583 {"exepath", 1, 1, f_exepath},
584 {"exists", 1, 1, f_exists},
585#ifdef FEAT_FLOAT
586 {"exp", 1, 1, f_exp},
587#endif
588 {"expand", 1, 3, f_expand},
589 {"extend", 2, 3, f_extend},
590 {"feedkeys", 1, 2, f_feedkeys},
591 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
592 {"filereadable", 1, 1, f_filereadable},
593 {"filewritable", 1, 1, f_filewritable},
594 {"filter", 2, 2, f_filter},
595 {"finddir", 1, 3, f_finddir},
596 {"findfile", 1, 3, f_findfile},
597#ifdef FEAT_FLOAT
598 {"float2nr", 1, 1, f_float2nr},
599 {"floor", 1, 1, f_floor},
600 {"fmod", 2, 2, f_fmod},
601#endif
602 {"fnameescape", 1, 1, f_fnameescape},
603 {"fnamemodify", 2, 2, f_fnamemodify},
604 {"foldclosed", 1, 1, f_foldclosed},
605 {"foldclosedend", 1, 1, f_foldclosedend},
606 {"foldlevel", 1, 1, f_foldlevel},
607 {"foldtext", 0, 0, f_foldtext},
608 {"foldtextresult", 1, 1, f_foldtextresult},
609 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200610 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200611 {"function", 1, 3, f_function},
612 {"garbagecollect", 0, 1, f_garbagecollect},
613 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200614 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200615 {"getbufline", 2, 3, f_getbufline},
616 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100617 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200618 {"getchar", 0, 1, f_getchar},
619 {"getcharmod", 0, 0, f_getcharmod},
620 {"getcharsearch", 0, 0, f_getcharsearch},
621 {"getcmdline", 0, 0, f_getcmdline},
622 {"getcmdpos", 0, 0, f_getcmdpos},
623 {"getcmdtype", 0, 0, f_getcmdtype},
624 {"getcmdwintype", 0, 0, f_getcmdwintype},
625#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200626 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627#endif
628 {"getcurpos", 0, 0, f_getcurpos},
629 {"getcwd", 0, 2, f_getcwd},
630 {"getfontname", 0, 1, f_getfontname},
631 {"getfperm", 1, 1, f_getfperm},
632 {"getfsize", 1, 1, f_getfsize},
633 {"getftime", 1, 1, f_getftime},
634 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100635 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200637 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200638 {"getmatches", 0, 0, f_getmatches},
639 {"getpid", 0, 0, f_getpid},
640 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200641 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200642 {"getreg", 0, 3, f_getreg},
643 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200644 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200645 {"gettabvar", 2, 3, f_gettabvar},
646 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200647 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100648 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649 {"getwinposx", 0, 0, f_getwinposx},
650 {"getwinposy", 0, 0, f_getwinposy},
651 {"getwinvar", 2, 3, f_getwinvar},
652 {"glob", 1, 4, f_glob},
653 {"glob2regpat", 1, 1, f_glob2regpat},
654 {"globpath", 2, 5, f_globpath},
655 {"has", 1, 1, f_has},
656 {"has_key", 2, 2, f_has_key},
657 {"haslocaldir", 0, 2, f_haslocaldir},
658 {"hasmapto", 1, 3, f_hasmapto},
659 {"highlightID", 1, 1, f_hlID}, /* obsolete */
660 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
661 {"histadd", 2, 2, f_histadd},
662 {"histdel", 1, 2, f_histdel},
663 {"histget", 1, 2, f_histget},
664 {"histnr", 1, 1, f_histnr},
665 {"hlID", 1, 1, f_hlID},
666 {"hlexists", 1, 1, f_hlexists},
667 {"hostname", 0, 0, f_hostname},
668 {"iconv", 3, 3, f_iconv},
669 {"indent", 1, 1, f_indent},
670 {"index", 2, 4, f_index},
671 {"input", 1, 3, f_input},
672 {"inputdialog", 1, 3, f_inputdialog},
673 {"inputlist", 1, 1, f_inputlist},
674 {"inputrestore", 0, 0, f_inputrestore},
675 {"inputsave", 0, 0, f_inputsave},
676 {"inputsecret", 1, 2, f_inputsecret},
677 {"insert", 2, 3, f_insert},
678 {"invert", 1, 1, f_invert},
679 {"isdirectory", 1, 1, f_isdirectory},
680 {"islocked", 1, 1, f_islocked},
681#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
682 {"isnan", 1, 1, f_isnan},
683#endif
684 {"items", 1, 1, f_items},
685#ifdef FEAT_JOB_CHANNEL
686 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200687 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688 {"job_setoptions", 2, 2, f_job_setoptions},
689 {"job_start", 1, 2, f_job_start},
690 {"job_status", 1, 1, f_job_status},
691 {"job_stop", 1, 2, f_job_stop},
692#endif
693 {"join", 1, 2, f_join},
694 {"js_decode", 1, 1, f_js_decode},
695 {"js_encode", 1, 1, f_js_encode},
696 {"json_decode", 1, 1, f_json_decode},
697 {"json_encode", 1, 1, f_json_encode},
698 {"keys", 1, 1, f_keys},
699 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
700 {"len", 1, 1, f_len},
701 {"libcall", 3, 3, f_libcall},
702 {"libcallnr", 3, 3, f_libcallnr},
703 {"line", 1, 1, f_line},
704 {"line2byte", 1, 1, f_line2byte},
705 {"lispindent", 1, 1, f_lispindent},
706 {"localtime", 0, 0, f_localtime},
707#ifdef FEAT_FLOAT
708 {"log", 1, 1, f_log},
709 {"log10", 1, 1, f_log10},
710#endif
711#ifdef FEAT_LUA
712 {"luaeval", 1, 2, f_luaeval},
713#endif
714 {"map", 2, 2, f_map},
715 {"maparg", 1, 4, f_maparg},
716 {"mapcheck", 1, 3, f_mapcheck},
717 {"match", 2, 4, f_match},
718 {"matchadd", 2, 5, f_matchadd},
719 {"matchaddpos", 2, 5, f_matchaddpos},
720 {"matcharg", 1, 1, f_matcharg},
721 {"matchdelete", 1, 1, f_matchdelete},
722 {"matchend", 2, 4, f_matchend},
723 {"matchlist", 2, 4, f_matchlist},
724 {"matchstr", 2, 4, f_matchstr},
725 {"matchstrpos", 2, 4, f_matchstrpos},
726 {"max", 1, 1, f_max},
727 {"min", 1, 1, f_min},
728#ifdef vim_mkdir
729 {"mkdir", 1, 3, f_mkdir},
730#endif
731 {"mode", 0, 1, f_mode},
732#ifdef FEAT_MZSCHEME
733 {"mzeval", 1, 1, f_mzeval},
734#endif
735 {"nextnonblank", 1, 1, f_nextnonblank},
736 {"nr2char", 1, 2, f_nr2char},
737 {"or", 2, 2, f_or},
738 {"pathshorten", 1, 1, f_pathshorten},
739#ifdef FEAT_PERL
740 {"perleval", 1, 1, f_perleval},
741#endif
742#ifdef FEAT_FLOAT
743 {"pow", 2, 2, f_pow},
744#endif
745 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100746 {"printf", 1, 19, f_printf},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747 {"pumvisible", 0, 0, f_pumvisible},
748#ifdef FEAT_PYTHON3
749 {"py3eval", 1, 1, f_py3eval},
750#endif
751#ifdef FEAT_PYTHON
752 {"pyeval", 1, 1, f_pyeval},
753#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100754#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
755 {"pyxeval", 1, 1, f_pyxeval},
756#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757 {"range", 1, 3, f_range},
758 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200759 {"reg_executing", 0, 0, f_reg_executing},
760 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200761 {"reltime", 0, 2, f_reltime},
762#ifdef FEAT_FLOAT
763 {"reltimefloat", 1, 1, f_reltimefloat},
764#endif
765 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100766 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200767 {"remote_foreground", 1, 1, f_remote_foreground},
768 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100769 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200770 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100771 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772 {"remove", 2, 3, f_remove},
773 {"rename", 2, 2, f_rename},
774 {"repeat", 2, 2, f_repeat},
775 {"resolve", 1, 1, f_resolve},
776 {"reverse", 1, 1, f_reverse},
777#ifdef FEAT_FLOAT
778 {"round", 1, 1, f_round},
779#endif
780 {"screenattr", 2, 2, f_screenattr},
781 {"screenchar", 2, 2, f_screenchar},
782 {"screencol", 0, 0, f_screencol},
783 {"screenrow", 0, 0, f_screenrow},
784 {"search", 1, 4, f_search},
785 {"searchdecl", 1, 3, f_searchdecl},
786 {"searchpair", 3, 7, f_searchpair},
787 {"searchpairpos", 3, 7, f_searchpairpos},
788 {"searchpos", 1, 4, f_searchpos},
789 {"server2client", 2, 2, f_server2client},
790 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200791 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200792 {"setbufvar", 3, 3, f_setbufvar},
793 {"setcharsearch", 1, 1, f_setcharsearch},
794 {"setcmdpos", 1, 1, f_setcmdpos},
795 {"setfperm", 2, 2, f_setfperm},
796 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200797 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200798 {"setmatches", 1, 1, f_setmatches},
799 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200800 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200801 {"setreg", 2, 3, f_setreg},
802 {"settabvar", 3, 3, f_settabvar},
803 {"settabwinvar", 4, 4, f_settabwinvar},
804 {"setwinvar", 3, 3, f_setwinvar},
805#ifdef FEAT_CRYPT
806 {"sha256", 1, 1, f_sha256},
807#endif
808 {"shellescape", 1, 2, f_shellescape},
809 {"shiftwidth", 0, 0, f_shiftwidth},
810 {"simplify", 1, 1, f_simplify},
811#ifdef FEAT_FLOAT
812 {"sin", 1, 1, f_sin},
813 {"sinh", 1, 1, f_sinh},
814#endif
815 {"sort", 1, 3, f_sort},
816 {"soundfold", 1, 1, f_soundfold},
817 {"spellbadword", 0, 1, f_spellbadword},
818 {"spellsuggest", 1, 3, f_spellsuggest},
819 {"split", 1, 3, f_split},
820#ifdef FEAT_FLOAT
821 {"sqrt", 1, 1, f_sqrt},
822 {"str2float", 1, 1, f_str2float},
823#endif
824 {"str2nr", 1, 2, f_str2nr},
825 {"strcharpart", 2, 3, f_strcharpart},
826 {"strchars", 1, 2, f_strchars},
827 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
828#ifdef HAVE_STRFTIME
829 {"strftime", 1, 2, f_strftime},
830#endif
831 {"strgetchar", 2, 2, f_strgetchar},
832 {"stridx", 2, 3, f_stridx},
833 {"string", 1, 1, f_string},
834 {"strlen", 1, 1, f_strlen},
835 {"strpart", 2, 3, f_strpart},
836 {"strridx", 2, 3, f_strridx},
837 {"strtrans", 1, 1, f_strtrans},
838 {"strwidth", 1, 1, f_strwidth},
839 {"submatch", 1, 2, f_submatch},
840 {"substitute", 4, 4, f_substitute},
841 {"synID", 3, 3, f_synID},
842 {"synIDattr", 2, 3, f_synIDattr},
843 {"synIDtrans", 1, 1, f_synIDtrans},
844 {"synconcealed", 2, 2, f_synconcealed},
845 {"synstack", 2, 2, f_synstack},
846 {"system", 1, 2, f_system},
847 {"systemlist", 1, 2, f_systemlist},
848 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
849 {"tabpagenr", 0, 1, f_tabpagenr},
850 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
851 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100852 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853#ifdef FEAT_FLOAT
854 {"tan", 1, 1, f_tan},
855 {"tanh", 1, 1, f_tanh},
856#endif
857 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200858#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100859 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
860 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100861 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200862 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200863# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
864 {"term_getansicolors", 1, 1, f_term_getansicolors},
865# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200866 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200867 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200868 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200869 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200870 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200871 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200872 {"term_getstatus", 1, 1, f_term_getstatus},
873 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200874 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200875 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200876 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200877 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200878# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
879 {"term_setansicolors", 2, 2, f_term_setansicolors},
880# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100881 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100882 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200883 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200884 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200885 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200886#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
888 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200889 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100891 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200892#ifdef FEAT_JOB_CHANNEL
893 {"test_null_channel", 0, 0, f_test_null_channel},
894#endif
895 {"test_null_dict", 0, 0, f_test_null_dict},
896#ifdef FEAT_JOB_CHANNEL
897 {"test_null_job", 0, 0, f_test_null_job},
898#endif
899 {"test_null_list", 0, 0, f_test_null_list},
900 {"test_null_partial", 0, 0, f_test_null_partial},
901 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100902 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200903 {"test_settime", 1, 1, f_test_settime},
904#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200905 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200906 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200907 {"timer_start", 2, 3, f_timer_start},
908 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200909 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200910#endif
911 {"tolower", 1, 1, f_tolower},
912 {"toupper", 1, 1, f_toupper},
913 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100914 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200915#ifdef FEAT_FLOAT
916 {"trunc", 1, 1, f_trunc},
917#endif
918 {"type", 1, 1, f_type},
919 {"undofile", 1, 1, f_undofile},
920 {"undotree", 0, 0, f_undotree},
921 {"uniq", 1, 3, f_uniq},
922 {"values", 1, 1, f_values},
923 {"virtcol", 1, 1, f_virtcol},
924 {"visualmode", 0, 1, f_visualmode},
925 {"wildmenumode", 0, 0, f_wildmenumode},
926 {"win_findbuf", 1, 1, f_win_findbuf},
927 {"win_getid", 0, 2, f_win_getid},
928 {"win_gotoid", 1, 1, f_win_gotoid},
929 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
930 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100931 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200932 {"winbufnr", 1, 1, f_winbufnr},
933 {"wincol", 0, 0, f_wincol},
934 {"winheight", 1, 1, f_winheight},
935 {"winline", 0, 0, f_winline},
936 {"winnr", 0, 1, f_winnr},
937 {"winrestcmd", 0, 0, f_winrestcmd},
938 {"winrestview", 1, 1, f_winrestview},
939 {"winsaveview", 0, 0, f_winsaveview},
940 {"winwidth", 1, 1, f_winwidth},
941 {"wordcount", 0, 0, f_wordcount},
942 {"writefile", 2, 3, f_writefile},
943 {"xor", 2, 2, f_xor},
944};
945
946#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
947
948/*
949 * Function given to ExpandGeneric() to obtain the list of internal
950 * or user defined function names.
951 */
952 char_u *
953get_function_name(expand_T *xp, int idx)
954{
955 static int intidx = -1;
956 char_u *name;
957
958 if (idx == 0)
959 intidx = -1;
960 if (intidx < 0)
961 {
962 name = get_user_func_name(xp, idx);
963 if (name != NULL)
964 return name;
965 }
966 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
967 {
968 STRCPY(IObuff, functions[intidx].f_name);
969 STRCAT(IObuff, "(");
970 if (functions[intidx].f_max_argc == 0)
971 STRCAT(IObuff, ")");
972 return IObuff;
973 }
974
975 return NULL;
976}
977
978/*
979 * Function given to ExpandGeneric() to obtain the list of internal or
980 * user defined variable or function names.
981 */
982 char_u *
983get_expr_name(expand_T *xp, int idx)
984{
985 static int intidx = -1;
986 char_u *name;
987
988 if (idx == 0)
989 intidx = -1;
990 if (intidx < 0)
991 {
992 name = get_function_name(xp, idx);
993 if (name != NULL)
994 return name;
995 }
996 return get_user_var_name(xp, ++intidx);
997}
998
999#endif /* FEAT_CMDL_COMPL */
1000
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001001/*
1002 * Find internal function in table above.
1003 * Return index, or -1 if not found
1004 */
1005 int
1006find_internal_func(
1007 char_u *name) /* name of the function */
1008{
1009 int first = 0;
1010 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1011 int cmp;
1012 int x;
1013
1014 /*
1015 * Find the function name in the table. Binary search.
1016 */
1017 while (first <= last)
1018 {
1019 x = first + ((unsigned)(last - first) >> 1);
1020 cmp = STRCMP(name, functions[x].f_name);
1021 if (cmp < 0)
1022 last = x - 1;
1023 else if (cmp > 0)
1024 first = x + 1;
1025 else
1026 return x;
1027 }
1028 return -1;
1029}
1030
1031 int
1032call_internal_func(
1033 char_u *name,
1034 int argcount,
1035 typval_T *argvars,
1036 typval_T *rettv)
1037{
1038 int i;
1039
1040 i = find_internal_func(name);
1041 if (i < 0)
1042 return ERROR_UNKNOWN;
1043 if (argcount < functions[i].f_min_argc)
1044 return ERROR_TOOFEW;
1045 if (argcount > functions[i].f_max_argc)
1046 return ERROR_TOOMANY;
1047 argvars[argcount].v_type = VAR_UNKNOWN;
1048 functions[i].f_func(argvars, rettv);
1049 return ERROR_NONE;
1050}
1051
1052/*
1053 * Return TRUE for a non-zero Number and a non-empty String.
1054 */
1055 static int
1056non_zero_arg(typval_T *argvars)
1057{
1058 return ((argvars[0].v_type == VAR_NUMBER
1059 && argvars[0].vval.v_number != 0)
1060 || (argvars[0].v_type == VAR_SPECIAL
1061 && argvars[0].vval.v_number == VVAL_TRUE)
1062 || (argvars[0].v_type == VAR_STRING
1063 && argvars[0].vval.v_string != NULL
1064 && *argvars[0].vval.v_string != NUL));
1065}
1066
1067/*
1068 * Get the lnum from the first argument.
1069 * Also accepts ".", "$", etc., but that only works for the current buffer.
1070 * Returns -1 on error.
1071 */
1072 static linenr_T
1073get_tv_lnum(typval_T *argvars)
1074{
1075 typval_T rettv;
1076 linenr_T lnum;
1077
1078 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1079 if (lnum == 0) /* no valid number, try using line() */
1080 {
1081 rettv.v_type = VAR_NUMBER;
1082 f_line(argvars, &rettv);
1083 lnum = (linenr_T)rettv.vval.v_number;
1084 clear_tv(&rettv);
1085 }
1086 return lnum;
1087}
1088
1089#ifdef FEAT_FLOAT
1090static int get_float_arg(typval_T *argvars, float_T *f);
1091
1092/*
1093 * Get the float value of "argvars[0]" into "f".
1094 * Returns FAIL when the argument is not a Number or Float.
1095 */
1096 static int
1097get_float_arg(typval_T *argvars, float_T *f)
1098{
1099 if (argvars[0].v_type == VAR_FLOAT)
1100 {
1101 *f = argvars[0].vval.v_float;
1102 return OK;
1103 }
1104 if (argvars[0].v_type == VAR_NUMBER)
1105 {
1106 *f = (float_T)argvars[0].vval.v_number;
1107 return OK;
1108 }
1109 EMSG(_("E808: Number or Float required"));
1110 return FAIL;
1111}
1112
1113/*
1114 * "abs(expr)" function
1115 */
1116 static void
1117f_abs(typval_T *argvars, typval_T *rettv)
1118{
1119 if (argvars[0].v_type == VAR_FLOAT)
1120 {
1121 rettv->v_type = VAR_FLOAT;
1122 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1123 }
1124 else
1125 {
1126 varnumber_T n;
1127 int error = FALSE;
1128
1129 n = get_tv_number_chk(&argvars[0], &error);
1130 if (error)
1131 rettv->vval.v_number = -1;
1132 else if (n > 0)
1133 rettv->vval.v_number = n;
1134 else
1135 rettv->vval.v_number = -n;
1136 }
1137}
1138
1139/*
1140 * "acos()" function
1141 */
1142 static void
1143f_acos(typval_T *argvars, typval_T *rettv)
1144{
1145 float_T f = 0.0;
1146
1147 rettv->v_type = VAR_FLOAT;
1148 if (get_float_arg(argvars, &f) == OK)
1149 rettv->vval.v_float = acos(f);
1150 else
1151 rettv->vval.v_float = 0.0;
1152}
1153#endif
1154
1155/*
1156 * "add(list, item)" function
1157 */
1158 static void
1159f_add(typval_T *argvars, typval_T *rettv)
1160{
1161 list_T *l;
1162
1163 rettv->vval.v_number = 1; /* Default: Failed */
1164 if (argvars[0].v_type == VAR_LIST)
1165 {
1166 if ((l = argvars[0].vval.v_list) != NULL
1167 && !tv_check_lock(l->lv_lock,
1168 (char_u *)N_("add() argument"), TRUE)
1169 && list_append_tv(l, &argvars[1]) == OK)
1170 copy_tv(&argvars[0], rettv);
1171 }
1172 else
1173 EMSG(_(e_listreq));
1174}
1175
1176/*
1177 * "and(expr, expr)" function
1178 */
1179 static void
1180f_and(typval_T *argvars, typval_T *rettv)
1181{
1182 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1183 & get_tv_number_chk(&argvars[1], NULL);
1184}
1185
1186/*
1187 * "append(lnum, string/list)" function
1188 */
1189 static void
1190f_append(typval_T *argvars, typval_T *rettv)
1191{
1192 long lnum;
1193 char_u *line;
1194 list_T *l = NULL;
1195 listitem_T *li = NULL;
1196 typval_T *tv;
1197 long added = 0;
1198
1199 /* When coming here from Insert mode, sync undo, so that this can be
1200 * undone separately from what was previously inserted. */
1201 if (u_sync_once == 2)
1202 {
1203 u_sync_once = 1; /* notify that u_sync() was called */
1204 u_sync(TRUE);
1205 }
1206
1207 lnum = get_tv_lnum(argvars);
1208 if (lnum >= 0
1209 && lnum <= curbuf->b_ml.ml_line_count
1210 && u_save(lnum, lnum + 1) == OK)
1211 {
1212 if (argvars[1].v_type == VAR_LIST)
1213 {
1214 l = argvars[1].vval.v_list;
1215 if (l == NULL)
1216 return;
1217 li = l->lv_first;
1218 }
1219 for (;;)
1220 {
1221 if (l == NULL)
1222 tv = &argvars[1]; /* append a string */
1223 else if (li == NULL)
1224 break; /* end of list */
1225 else
1226 tv = &li->li_tv; /* append item from list */
1227 line = get_tv_string_chk(tv);
1228 if (line == NULL) /* type error */
1229 {
1230 rettv->vval.v_number = 1; /* Failed */
1231 break;
1232 }
1233 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1234 ++added;
1235 if (l == NULL)
1236 break;
1237 li = li->li_next;
1238 }
1239
1240 appended_lines_mark(lnum, added);
1241 if (curwin->w_cursor.lnum > lnum)
1242 curwin->w_cursor.lnum += added;
1243 }
1244 else
1245 rettv->vval.v_number = 1; /* Failed */
1246}
1247
1248/*
1249 * "argc()" function
1250 */
1251 static void
1252f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1253{
1254 rettv->vval.v_number = ARGCOUNT;
1255}
1256
1257/*
1258 * "argidx()" function
1259 */
1260 static void
1261f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1262{
1263 rettv->vval.v_number = curwin->w_arg_idx;
1264}
1265
1266/*
1267 * "arglistid()" function
1268 */
1269 static void
1270f_arglistid(typval_T *argvars, typval_T *rettv)
1271{
1272 win_T *wp;
1273
1274 rettv->vval.v_number = -1;
1275 wp = find_tabwin(&argvars[0], &argvars[1]);
1276 if (wp != NULL)
1277 rettv->vval.v_number = wp->w_alist->id;
1278}
1279
1280/*
1281 * "argv(nr)" function
1282 */
1283 static void
1284f_argv(typval_T *argvars, typval_T *rettv)
1285{
1286 int idx;
1287
1288 if (argvars[0].v_type != VAR_UNKNOWN)
1289 {
1290 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1291 if (idx >= 0 && idx < ARGCOUNT)
1292 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1293 else
1294 rettv->vval.v_string = NULL;
1295 rettv->v_type = VAR_STRING;
1296 }
1297 else if (rettv_list_alloc(rettv) == OK)
1298 for (idx = 0; idx < ARGCOUNT; ++idx)
1299 list_append_string(rettv->vval.v_list,
1300 alist_name(&ARGLIST[idx]), -1);
1301}
1302
1303/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001304 * "assert_beeps(cmd [, error])" function
1305 */
1306 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001307f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001308{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001309 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001310}
1311
1312/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313 * "assert_equal(expected, actual[, msg])" function
1314 */
1315 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001316f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001317{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001318 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001319}
1320
1321/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001322 * "assert_equalfile(fname-one, fname-two)" function
1323 */
1324 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001325f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001326{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001327 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001328}
1329
1330/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001331 * "assert_notequal(expected, actual[, msg])" function
1332 */
1333 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001334f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001335{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001336 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001337}
1338
1339/*
1340 * "assert_exception(string[, msg])" function
1341 */
1342 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001343f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001345 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001346}
1347
1348/*
1349 * "assert_fails(cmd [, error])" function
1350 */
1351 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001352f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001354 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001355}
1356
1357/*
1358 * "assert_false(actual[, msg])" function
1359 */
1360 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001361f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001363 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364}
1365
1366/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001367 * "assert_inrange(lower, upper[, msg])" function
1368 */
1369 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001370f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001371{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001372 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001373}
1374
1375/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376 * "assert_match(pattern, actual[, msg])" function
1377 */
1378 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001379f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001380{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001381 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382}
1383
1384/*
1385 * "assert_notmatch(pattern, actual[, msg])" function
1386 */
1387 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001388f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001389{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001390 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001391}
1392
1393/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001394 * "assert_report(msg)" function
1395 */
1396 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001397f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001398{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001399 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001400}
1401
1402/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001403 * "assert_true(actual[, msg])" function
1404 */
1405 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001406f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001407{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001408 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001409}
1410
1411#ifdef FEAT_FLOAT
1412/*
1413 * "asin()" function
1414 */
1415 static void
1416f_asin(typval_T *argvars, typval_T *rettv)
1417{
1418 float_T f = 0.0;
1419
1420 rettv->v_type = VAR_FLOAT;
1421 if (get_float_arg(argvars, &f) == OK)
1422 rettv->vval.v_float = asin(f);
1423 else
1424 rettv->vval.v_float = 0.0;
1425}
1426
1427/*
1428 * "atan()" function
1429 */
1430 static void
1431f_atan(typval_T *argvars, typval_T *rettv)
1432{
1433 float_T f = 0.0;
1434
1435 rettv->v_type = VAR_FLOAT;
1436 if (get_float_arg(argvars, &f) == OK)
1437 rettv->vval.v_float = atan(f);
1438 else
1439 rettv->vval.v_float = 0.0;
1440}
1441
1442/*
1443 * "atan2()" function
1444 */
1445 static void
1446f_atan2(typval_T *argvars, typval_T *rettv)
1447{
1448 float_T fx = 0.0, fy = 0.0;
1449
1450 rettv->v_type = VAR_FLOAT;
1451 if (get_float_arg(argvars, &fx) == OK
1452 && get_float_arg(&argvars[1], &fy) == OK)
1453 rettv->vval.v_float = atan2(fx, fy);
1454 else
1455 rettv->vval.v_float = 0.0;
1456}
1457#endif
1458
1459/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001460 * "balloon_show()" function
1461 */
1462#ifdef FEAT_BEVAL
1463 static void
1464f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1465{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001466 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001467 {
1468 if (argvars[0].v_type == VAR_LIST
1469# ifdef FEAT_GUI
1470 && !gui.in_use
1471# endif
1472 )
1473 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1474 else
1475 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1476 }
1477}
1478
Bram Moolenaar669a8282017-11-19 20:13:05 +01001479# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001480 static void
1481f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1482{
1483 if (rettv_list_alloc(rettv) == OK)
1484 {
1485 char_u *msg = get_tv_string_chk(&argvars[0]);
1486
1487 if (msg != NULL)
1488 {
1489 pumitem_T *array;
1490 int size = split_message(msg, &array);
1491 int i;
1492
1493 /* Skip the first and last item, they are always empty. */
1494 for (i = 1; i < size - 1; ++i)
1495 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001496 while (size > 0)
1497 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001498 vim_free(array);
1499 }
1500 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001501}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001502# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001503#endif
1504
1505/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506 * "browse(save, title, initdir, default)" function
1507 */
1508 static void
1509f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1510{
1511#ifdef FEAT_BROWSE
1512 int save;
1513 char_u *title;
1514 char_u *initdir;
1515 char_u *defname;
1516 char_u buf[NUMBUFLEN];
1517 char_u buf2[NUMBUFLEN];
1518 int error = FALSE;
1519
1520 save = (int)get_tv_number_chk(&argvars[0], &error);
1521 title = get_tv_string_chk(&argvars[1]);
1522 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1523 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1524
1525 if (error || title == NULL || initdir == NULL || defname == NULL)
1526 rettv->vval.v_string = NULL;
1527 else
1528 rettv->vval.v_string =
1529 do_browse(save ? BROWSE_SAVE : 0,
1530 title, defname, NULL, initdir, NULL, curbuf);
1531#else
1532 rettv->vval.v_string = NULL;
1533#endif
1534 rettv->v_type = VAR_STRING;
1535}
1536
1537/*
1538 * "browsedir(title, initdir)" function
1539 */
1540 static void
1541f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1542{
1543#ifdef FEAT_BROWSE
1544 char_u *title;
1545 char_u *initdir;
1546 char_u buf[NUMBUFLEN];
1547
1548 title = get_tv_string_chk(&argvars[0]);
1549 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1550
1551 if (title == NULL || initdir == NULL)
1552 rettv->vval.v_string = NULL;
1553 else
1554 rettv->vval.v_string = do_browse(BROWSE_DIR,
1555 title, NULL, NULL, initdir, NULL, curbuf);
1556#else
1557 rettv->vval.v_string = NULL;
1558#endif
1559 rettv->v_type = VAR_STRING;
1560}
1561
1562static buf_T *find_buffer(typval_T *avar);
1563
1564/*
1565 * Find a buffer by number or exact name.
1566 */
1567 static buf_T *
1568find_buffer(typval_T *avar)
1569{
1570 buf_T *buf = NULL;
1571
1572 if (avar->v_type == VAR_NUMBER)
1573 buf = buflist_findnr((int)avar->vval.v_number);
1574 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1575 {
1576 buf = buflist_findname_exp(avar->vval.v_string);
1577 if (buf == NULL)
1578 {
1579 /* No full path name match, try a match with a URL or a "nofile"
1580 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001581 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001582 if (buf->b_fname != NULL
1583 && (path_with_url(buf->b_fname)
1584#ifdef FEAT_QUICKFIX
1585 || bt_nofile(buf)
1586#endif
1587 )
1588 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1589 break;
1590 }
1591 }
1592 return buf;
1593}
1594
1595/*
1596 * "bufexists(expr)" function
1597 */
1598 static void
1599f_bufexists(typval_T *argvars, typval_T *rettv)
1600{
1601 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1602}
1603
1604/*
1605 * "buflisted(expr)" function
1606 */
1607 static void
1608f_buflisted(typval_T *argvars, typval_T *rettv)
1609{
1610 buf_T *buf;
1611
1612 buf = find_buffer(&argvars[0]);
1613 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1614}
1615
1616/*
1617 * "bufloaded(expr)" function
1618 */
1619 static void
1620f_bufloaded(typval_T *argvars, typval_T *rettv)
1621{
1622 buf_T *buf;
1623
1624 buf = find_buffer(&argvars[0]);
1625 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1626}
1627
1628 buf_T *
1629buflist_find_by_name(char_u *name, int curtab_only)
1630{
1631 int save_magic;
1632 char_u *save_cpo;
1633 buf_T *buf;
1634
1635 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1636 save_magic = p_magic;
1637 p_magic = TRUE;
1638 save_cpo = p_cpo;
1639 p_cpo = (char_u *)"";
1640
1641 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1642 TRUE, FALSE, curtab_only));
1643
1644 p_magic = save_magic;
1645 p_cpo = save_cpo;
1646 return buf;
1647}
1648
1649/*
1650 * Get buffer by number or pattern.
1651 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001652 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001653get_buf_tv(typval_T *tv, int curtab_only)
1654{
1655 char_u *name = tv->vval.v_string;
1656 buf_T *buf;
1657
1658 if (tv->v_type == VAR_NUMBER)
1659 return buflist_findnr((int)tv->vval.v_number);
1660 if (tv->v_type != VAR_STRING)
1661 return NULL;
1662 if (name == NULL || *name == NUL)
1663 return curbuf;
1664 if (name[0] == '$' && name[1] == NUL)
1665 return lastbuf;
1666
1667 buf = buflist_find_by_name(name, curtab_only);
1668
1669 /* If not found, try expanding the name, like done for bufexists(). */
1670 if (buf == NULL)
1671 buf = find_buffer(tv);
1672
1673 return buf;
1674}
1675
1676/*
1677 * "bufname(expr)" function
1678 */
1679 static void
1680f_bufname(typval_T *argvars, typval_T *rettv)
1681{
1682 buf_T *buf;
1683
1684 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1685 ++emsg_off;
1686 buf = get_buf_tv(&argvars[0], FALSE);
1687 rettv->v_type = VAR_STRING;
1688 if (buf != NULL && buf->b_fname != NULL)
1689 rettv->vval.v_string = vim_strsave(buf->b_fname);
1690 else
1691 rettv->vval.v_string = NULL;
1692 --emsg_off;
1693}
1694
1695/*
1696 * "bufnr(expr)" function
1697 */
1698 static void
1699f_bufnr(typval_T *argvars, typval_T *rettv)
1700{
1701 buf_T *buf;
1702 int error = FALSE;
1703 char_u *name;
1704
1705 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1706 ++emsg_off;
1707 buf = get_buf_tv(&argvars[0], FALSE);
1708 --emsg_off;
1709
1710 /* If the buffer isn't found and the second argument is not zero create a
1711 * new buffer. */
1712 if (buf == NULL
1713 && argvars[1].v_type != VAR_UNKNOWN
1714 && get_tv_number_chk(&argvars[1], &error) != 0
1715 && !error
1716 && (name = get_tv_string_chk(&argvars[0])) != NULL
1717 && !error)
1718 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1719
1720 if (buf != NULL)
1721 rettv->vval.v_number = buf->b_fnum;
1722 else
1723 rettv->vval.v_number = -1;
1724}
1725
1726 static void
1727buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1728{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001729 win_T *wp;
1730 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001731 buf_T *buf;
1732
1733 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1734 ++emsg_off;
1735 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001736 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001737 {
1738 ++winnr;
1739 if (wp->w_buffer == buf)
1740 break;
1741 }
1742 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001743 --emsg_off;
1744}
1745
1746/*
1747 * "bufwinid(nr)" function
1748 */
1749 static void
1750f_bufwinid(typval_T *argvars, typval_T *rettv)
1751{
1752 buf_win_common(argvars, rettv, FALSE);
1753}
1754
1755/*
1756 * "bufwinnr(nr)" function
1757 */
1758 static void
1759f_bufwinnr(typval_T *argvars, typval_T *rettv)
1760{
1761 buf_win_common(argvars, rettv, TRUE);
1762}
1763
1764/*
1765 * "byte2line(byte)" function
1766 */
1767 static void
1768f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1769{
1770#ifndef FEAT_BYTEOFF
1771 rettv->vval.v_number = -1;
1772#else
1773 long boff = 0;
1774
1775 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1776 if (boff < 0)
1777 rettv->vval.v_number = -1;
1778 else
1779 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1780 (linenr_T)0, &boff);
1781#endif
1782}
1783
1784 static void
1785byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1786{
1787#ifdef FEAT_MBYTE
1788 char_u *t;
1789#endif
1790 char_u *str;
1791 varnumber_T idx;
1792
1793 str = get_tv_string_chk(&argvars[0]);
1794 idx = get_tv_number_chk(&argvars[1], NULL);
1795 rettv->vval.v_number = -1;
1796 if (str == NULL || idx < 0)
1797 return;
1798
1799#ifdef FEAT_MBYTE
1800 t = str;
1801 for ( ; idx > 0; idx--)
1802 {
1803 if (*t == NUL) /* EOL reached */
1804 return;
1805 if (enc_utf8 && comp)
1806 t += utf_ptr2len(t);
1807 else
1808 t += (*mb_ptr2len)(t);
1809 }
1810 rettv->vval.v_number = (varnumber_T)(t - str);
1811#else
1812 if ((size_t)idx <= STRLEN(str))
1813 rettv->vval.v_number = idx;
1814#endif
1815}
1816
1817/*
1818 * "byteidx()" function
1819 */
1820 static void
1821f_byteidx(typval_T *argvars, typval_T *rettv)
1822{
1823 byteidx(argvars, rettv, FALSE);
1824}
1825
1826/*
1827 * "byteidxcomp()" function
1828 */
1829 static void
1830f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1831{
1832 byteidx(argvars, rettv, TRUE);
1833}
1834
1835/*
1836 * "call(func, arglist [, dict])" function
1837 */
1838 static void
1839f_call(typval_T *argvars, typval_T *rettv)
1840{
1841 char_u *func;
1842 partial_T *partial = NULL;
1843 dict_T *selfdict = NULL;
1844
1845 if (argvars[1].v_type != VAR_LIST)
1846 {
1847 EMSG(_(e_listreq));
1848 return;
1849 }
1850 if (argvars[1].vval.v_list == NULL)
1851 return;
1852
1853 if (argvars[0].v_type == VAR_FUNC)
1854 func = argvars[0].vval.v_string;
1855 else if (argvars[0].v_type == VAR_PARTIAL)
1856 {
1857 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001858 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001859 }
1860 else
1861 func = get_tv_string(&argvars[0]);
1862 if (*func == NUL)
1863 return; /* type error or empty name */
1864
1865 if (argvars[2].v_type != VAR_UNKNOWN)
1866 {
1867 if (argvars[2].v_type != VAR_DICT)
1868 {
1869 EMSG(_(e_dictreq));
1870 return;
1871 }
1872 selfdict = argvars[2].vval.v_dict;
1873 }
1874
1875 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1876}
1877
1878#ifdef FEAT_FLOAT
1879/*
1880 * "ceil({float})" function
1881 */
1882 static void
1883f_ceil(typval_T *argvars, typval_T *rettv)
1884{
1885 float_T f = 0.0;
1886
1887 rettv->v_type = VAR_FLOAT;
1888 if (get_float_arg(argvars, &f) == OK)
1889 rettv->vval.v_float = ceil(f);
1890 else
1891 rettv->vval.v_float = 0.0;
1892}
1893#endif
1894
1895#ifdef FEAT_JOB_CHANNEL
1896/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001897 * "ch_canread()" function
1898 */
1899 static void
1900f_ch_canread(typval_T *argvars, typval_T *rettv)
1901{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001902 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001903
1904 rettv->vval.v_number = 0;
1905 if (channel != NULL)
1906 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1907 || channel_has_readahead(channel, PART_OUT)
1908 || channel_has_readahead(channel, PART_ERR);
1909}
1910
1911/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001912 * "ch_close()" function
1913 */
1914 static void
1915f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1916{
1917 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1918
1919 if (channel != NULL)
1920 {
1921 channel_close(channel, FALSE);
1922 channel_clear(channel);
1923 }
1924}
1925
1926/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001927 * "ch_close()" function
1928 */
1929 static void
1930f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1931{
1932 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1933
1934 if (channel != NULL)
1935 channel_close_in(channel);
1936}
1937
1938/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001939 * "ch_getbufnr()" function
1940 */
1941 static void
1942f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1943{
1944 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1945
1946 rettv->vval.v_number = -1;
1947 if (channel != NULL)
1948 {
1949 char_u *what = get_tv_string(&argvars[1]);
1950 int part;
1951
1952 if (STRCMP(what, "err") == 0)
1953 part = PART_ERR;
1954 else if (STRCMP(what, "out") == 0)
1955 part = PART_OUT;
1956 else if (STRCMP(what, "in") == 0)
1957 part = PART_IN;
1958 else
1959 part = PART_SOCK;
1960 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1961 rettv->vval.v_number =
1962 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1963 }
1964}
1965
1966/*
1967 * "ch_getjob()" function
1968 */
1969 static void
1970f_ch_getjob(typval_T *argvars, typval_T *rettv)
1971{
1972 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1973
1974 if (channel != NULL)
1975 {
1976 rettv->v_type = VAR_JOB;
1977 rettv->vval.v_job = channel->ch_job;
1978 if (channel->ch_job != NULL)
1979 ++channel->ch_job->jv_refcount;
1980 }
1981}
1982
1983/*
1984 * "ch_info()" function
1985 */
1986 static void
1987f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1988{
1989 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1990
1991 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1992 channel_info(channel, rettv->vval.v_dict);
1993}
1994
1995/*
1996 * "ch_log()" function
1997 */
1998 static void
1999f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2000{
2001 char_u *msg = get_tv_string(&argvars[0]);
2002 channel_T *channel = NULL;
2003
2004 if (argvars[1].v_type != VAR_UNKNOWN)
2005 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2006
Bram Moolenaard5359b22018-04-05 22:44:39 +02002007 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002008}
2009
2010/*
2011 * "ch_logfile()" function
2012 */
2013 static void
2014f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2015{
2016 char_u *fname;
2017 char_u *opt = (char_u *)"";
2018 char_u buf[NUMBUFLEN];
2019
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002020 /* Don't open a file in restricted mode. */
2021 if (check_restricted() || check_secure())
2022 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023 fname = get_tv_string(&argvars[0]);
2024 if (argvars[1].v_type == VAR_STRING)
2025 opt = get_tv_string_buf(&argvars[1], buf);
2026 ch_logfile(fname, opt);
2027}
2028
2029/*
2030 * "ch_open()" function
2031 */
2032 static void
2033f_ch_open(typval_T *argvars, typval_T *rettv)
2034{
2035 rettv->v_type = VAR_CHANNEL;
2036 if (check_restricted() || check_secure())
2037 return;
2038 rettv->vval.v_channel = channel_open_func(argvars);
2039}
2040
2041/*
2042 * "ch_read()" function
2043 */
2044 static void
2045f_ch_read(typval_T *argvars, typval_T *rettv)
2046{
2047 common_channel_read(argvars, rettv, FALSE);
2048}
2049
2050/*
2051 * "ch_readraw()" function
2052 */
2053 static void
2054f_ch_readraw(typval_T *argvars, typval_T *rettv)
2055{
2056 common_channel_read(argvars, rettv, TRUE);
2057}
2058
2059/*
2060 * "ch_evalexpr()" function
2061 */
2062 static void
2063f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2064{
2065 ch_expr_common(argvars, rettv, TRUE);
2066}
2067
2068/*
2069 * "ch_sendexpr()" function
2070 */
2071 static void
2072f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2073{
2074 ch_expr_common(argvars, rettv, FALSE);
2075}
2076
2077/*
2078 * "ch_evalraw()" function
2079 */
2080 static void
2081f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2082{
2083 ch_raw_common(argvars, rettv, TRUE);
2084}
2085
2086/*
2087 * "ch_sendraw()" function
2088 */
2089 static void
2090f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2091{
2092 ch_raw_common(argvars, rettv, FALSE);
2093}
2094
2095/*
2096 * "ch_setoptions()" function
2097 */
2098 static void
2099f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2100{
2101 channel_T *channel;
2102 jobopt_T opt;
2103
2104 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2105 if (channel == NULL)
2106 return;
2107 clear_job_options(&opt);
2108 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002109 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002110 channel_set_options(channel, &opt);
2111 free_job_options(&opt);
2112}
2113
2114/*
2115 * "ch_status()" function
2116 */
2117 static void
2118f_ch_status(typval_T *argvars, typval_T *rettv)
2119{
2120 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002121 jobopt_T opt;
2122 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002123
2124 /* return an empty string by default */
2125 rettv->v_type = VAR_STRING;
2126 rettv->vval.v_string = NULL;
2127
2128 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002129
2130 if (argvars[1].v_type != VAR_UNKNOWN)
2131 {
2132 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002133 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002134 && (opt.jo_set & JO_PART))
2135 part = opt.jo_part;
2136 }
2137
2138 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002139}
2140#endif
2141
2142/*
2143 * "changenr()" function
2144 */
2145 static void
2146f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2147{
2148 rettv->vval.v_number = curbuf->b_u_seq_cur;
2149}
2150
2151/*
2152 * "char2nr(string)" function
2153 */
2154 static void
2155f_char2nr(typval_T *argvars, typval_T *rettv)
2156{
2157#ifdef FEAT_MBYTE
2158 if (has_mbyte)
2159 {
2160 int utf8 = 0;
2161
2162 if (argvars[1].v_type != VAR_UNKNOWN)
2163 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2164
2165 if (utf8)
2166 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2167 else
2168 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2169 }
2170 else
2171#endif
2172 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2173}
2174
2175/*
2176 * "cindent(lnum)" function
2177 */
2178 static void
2179f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2180{
2181#ifdef FEAT_CINDENT
2182 pos_T pos;
2183 linenr_T lnum;
2184
2185 pos = curwin->w_cursor;
2186 lnum = get_tv_lnum(argvars);
2187 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2188 {
2189 curwin->w_cursor.lnum = lnum;
2190 rettv->vval.v_number = get_c_indent();
2191 curwin->w_cursor = pos;
2192 }
2193 else
2194#endif
2195 rettv->vval.v_number = -1;
2196}
2197
2198/*
2199 * "clearmatches()" function
2200 */
2201 static void
2202f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2203{
2204#ifdef FEAT_SEARCH_EXTRA
2205 clear_matches(curwin);
2206#endif
2207}
2208
2209/*
2210 * "col(string)" function
2211 */
2212 static void
2213f_col(typval_T *argvars, typval_T *rettv)
2214{
2215 colnr_T col = 0;
2216 pos_T *fp;
2217 int fnum = curbuf->b_fnum;
2218
2219 fp = var2fpos(&argvars[0], FALSE, &fnum);
2220 if (fp != NULL && fnum == curbuf->b_fnum)
2221 {
2222 if (fp->col == MAXCOL)
2223 {
2224 /* '> can be MAXCOL, get the length of the line then */
2225 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2226 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2227 else
2228 col = MAXCOL;
2229 }
2230 else
2231 {
2232 col = fp->col + 1;
2233#ifdef FEAT_VIRTUALEDIT
2234 /* col(".") when the cursor is on the NUL at the end of the line
2235 * because of "coladd" can be seen as an extra column. */
2236 if (virtual_active() && fp == &curwin->w_cursor)
2237 {
2238 char_u *p = ml_get_cursor();
2239
2240 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2241 curwin->w_virtcol - curwin->w_cursor.coladd))
2242 {
2243# ifdef FEAT_MBYTE
2244 int l;
2245
2246 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2247 col += l;
2248# else
2249 if (*p != NUL && p[1] == NUL)
2250 ++col;
2251# endif
2252 }
2253 }
2254#endif
2255 }
2256 }
2257 rettv->vval.v_number = col;
2258}
2259
2260#if defined(FEAT_INS_EXPAND)
2261/*
2262 * "complete()" function
2263 */
2264 static void
2265f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2266{
2267 int startcol;
2268
2269 if ((State & INSERT) == 0)
2270 {
2271 EMSG(_("E785: complete() can only be used in Insert mode"));
2272 return;
2273 }
2274
2275 /* Check for undo allowed here, because if something was already inserted
2276 * the line was already saved for undo and this check isn't done. */
2277 if (!undo_allowed())
2278 return;
2279
2280 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2281 {
2282 EMSG(_(e_invarg));
2283 return;
2284 }
2285
2286 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2287 if (startcol <= 0)
2288 return;
2289
2290 set_completion(startcol - 1, argvars[1].vval.v_list);
2291}
2292
2293/*
2294 * "complete_add()" function
2295 */
2296 static void
2297f_complete_add(typval_T *argvars, typval_T *rettv)
2298{
2299 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2300}
2301
2302/*
2303 * "complete_check()" function
2304 */
2305 static void
2306f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2307{
2308 int saved = RedrawingDisabled;
2309
2310 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002311 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002312 rettv->vval.v_number = compl_interrupted;
2313 RedrawingDisabled = saved;
2314}
2315#endif
2316
2317/*
2318 * "confirm(message, buttons[, default [, type]])" function
2319 */
2320 static void
2321f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2322{
2323#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2324 char_u *message;
2325 char_u *buttons = NULL;
2326 char_u buf[NUMBUFLEN];
2327 char_u buf2[NUMBUFLEN];
2328 int def = 1;
2329 int type = VIM_GENERIC;
2330 char_u *typestr;
2331 int error = FALSE;
2332
2333 message = get_tv_string_chk(&argvars[0]);
2334 if (message == NULL)
2335 error = TRUE;
2336 if (argvars[1].v_type != VAR_UNKNOWN)
2337 {
2338 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2339 if (buttons == NULL)
2340 error = TRUE;
2341 if (argvars[2].v_type != VAR_UNKNOWN)
2342 {
2343 def = (int)get_tv_number_chk(&argvars[2], &error);
2344 if (argvars[3].v_type != VAR_UNKNOWN)
2345 {
2346 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2347 if (typestr == NULL)
2348 error = TRUE;
2349 else
2350 {
2351 switch (TOUPPER_ASC(*typestr))
2352 {
2353 case 'E': type = VIM_ERROR; break;
2354 case 'Q': type = VIM_QUESTION; break;
2355 case 'I': type = VIM_INFO; break;
2356 case 'W': type = VIM_WARNING; break;
2357 case 'G': type = VIM_GENERIC; break;
2358 }
2359 }
2360 }
2361 }
2362 }
2363
2364 if (buttons == NULL || *buttons == NUL)
2365 buttons = (char_u *)_("&Ok");
2366
2367 if (!error)
2368 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2369 def, NULL, FALSE);
2370#endif
2371}
2372
2373/*
2374 * "copy()" function
2375 */
2376 static void
2377f_copy(typval_T *argvars, typval_T *rettv)
2378{
2379 item_copy(&argvars[0], rettv, FALSE, 0);
2380}
2381
2382#ifdef FEAT_FLOAT
2383/*
2384 * "cos()" function
2385 */
2386 static void
2387f_cos(typval_T *argvars, typval_T *rettv)
2388{
2389 float_T f = 0.0;
2390
2391 rettv->v_type = VAR_FLOAT;
2392 if (get_float_arg(argvars, &f) == OK)
2393 rettv->vval.v_float = cos(f);
2394 else
2395 rettv->vval.v_float = 0.0;
2396}
2397
2398/*
2399 * "cosh()" function
2400 */
2401 static void
2402f_cosh(typval_T *argvars, typval_T *rettv)
2403{
2404 float_T f = 0.0;
2405
2406 rettv->v_type = VAR_FLOAT;
2407 if (get_float_arg(argvars, &f) == OK)
2408 rettv->vval.v_float = cosh(f);
2409 else
2410 rettv->vval.v_float = 0.0;
2411}
2412#endif
2413
2414/*
2415 * "count()" function
2416 */
2417 static void
2418f_count(typval_T *argvars, typval_T *rettv)
2419{
2420 long n = 0;
2421 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002422 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002423
Bram Moolenaar9966b212017-07-28 16:46:57 +02002424 if (argvars[2].v_type != VAR_UNKNOWN)
2425 ic = (int)get_tv_number_chk(&argvars[2], &error);
2426
2427 if (argvars[0].v_type == VAR_STRING)
2428 {
2429 char_u *expr = get_tv_string_chk(&argvars[1]);
2430 char_u *p = argvars[0].vval.v_string;
2431 char_u *next;
2432
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002433 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002434 {
2435 if (ic)
2436 {
2437 size_t len = STRLEN(expr);
2438
2439 while (*p != NUL)
2440 {
2441 if (MB_STRNICMP(p, expr, len) == 0)
2442 {
2443 ++n;
2444 p += len;
2445 }
2446 else
2447 MB_PTR_ADV(p);
2448 }
2449 }
2450 else
2451 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2452 != NULL)
2453 {
2454 ++n;
2455 p = next + STRLEN(expr);
2456 }
2457 }
2458
2459 }
2460 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 {
2462 listitem_T *li;
2463 list_T *l;
2464 long idx;
2465
2466 if ((l = argvars[0].vval.v_list) != NULL)
2467 {
2468 li = l->lv_first;
2469 if (argvars[2].v_type != VAR_UNKNOWN)
2470 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002471 if (argvars[3].v_type != VAR_UNKNOWN)
2472 {
2473 idx = (long)get_tv_number_chk(&argvars[3], &error);
2474 if (!error)
2475 {
2476 li = list_find(l, idx);
2477 if (li == NULL)
2478 EMSGN(_(e_listidx), idx);
2479 }
2480 }
2481 if (error)
2482 li = NULL;
2483 }
2484
2485 for ( ; li != NULL; li = li->li_next)
2486 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2487 ++n;
2488 }
2489 }
2490 else if (argvars[0].v_type == VAR_DICT)
2491 {
2492 int todo;
2493 dict_T *d;
2494 hashitem_T *hi;
2495
2496 if ((d = argvars[0].vval.v_dict) != NULL)
2497 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002498 if (argvars[2].v_type != VAR_UNKNOWN)
2499 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002500 if (argvars[3].v_type != VAR_UNKNOWN)
2501 EMSG(_(e_invarg));
2502 }
2503
2504 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2505 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2506 {
2507 if (!HASHITEM_EMPTY(hi))
2508 {
2509 --todo;
2510 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2511 ++n;
2512 }
2513 }
2514 }
2515 }
2516 else
2517 EMSG2(_(e_listdictarg), "count()");
2518 rettv->vval.v_number = n;
2519}
2520
2521/*
2522 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2523 *
2524 * Checks the existence of a cscope connection.
2525 */
2526 static void
2527f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2528{
2529#ifdef FEAT_CSCOPE
2530 int num = 0;
2531 char_u *dbpath = NULL;
2532 char_u *prepend = NULL;
2533 char_u buf[NUMBUFLEN];
2534
2535 if (argvars[0].v_type != VAR_UNKNOWN
2536 && argvars[1].v_type != VAR_UNKNOWN)
2537 {
2538 num = (int)get_tv_number(&argvars[0]);
2539 dbpath = get_tv_string(&argvars[1]);
2540 if (argvars[2].v_type != VAR_UNKNOWN)
2541 prepend = get_tv_string_buf(&argvars[2], buf);
2542 }
2543
2544 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2545#endif
2546}
2547
2548/*
2549 * "cursor(lnum, col)" function, or
2550 * "cursor(list)"
2551 *
2552 * Moves the cursor to the specified line and column.
2553 * Returns 0 when the position could be set, -1 otherwise.
2554 */
2555 static void
2556f_cursor(typval_T *argvars, typval_T *rettv)
2557{
2558 long line, col;
2559#ifdef FEAT_VIRTUALEDIT
2560 long coladd = 0;
2561#endif
2562 int set_curswant = TRUE;
2563
2564 rettv->vval.v_number = -1;
2565 if (argvars[1].v_type == VAR_UNKNOWN)
2566 {
2567 pos_T pos;
2568 colnr_T curswant = -1;
2569
2570 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2571 {
2572 EMSG(_(e_invarg));
2573 return;
2574 }
2575 line = pos.lnum;
2576 col = pos.col;
2577#ifdef FEAT_VIRTUALEDIT
2578 coladd = pos.coladd;
2579#endif
2580 if (curswant >= 0)
2581 {
2582 curwin->w_curswant = curswant - 1;
2583 set_curswant = FALSE;
2584 }
2585 }
2586 else
2587 {
2588 line = get_tv_lnum(argvars);
2589 col = (long)get_tv_number_chk(&argvars[1], NULL);
2590#ifdef FEAT_VIRTUALEDIT
2591 if (argvars[2].v_type != VAR_UNKNOWN)
2592 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2593#endif
2594 }
2595 if (line < 0 || col < 0
2596#ifdef FEAT_VIRTUALEDIT
2597 || coladd < 0
2598#endif
2599 )
2600 return; /* type error; errmsg already given */
2601 if (line > 0)
2602 curwin->w_cursor.lnum = line;
2603 if (col > 0)
2604 curwin->w_cursor.col = col - 1;
2605#ifdef FEAT_VIRTUALEDIT
2606 curwin->w_cursor.coladd = coladd;
2607#endif
2608
2609 /* Make sure the cursor is in a valid position. */
2610 check_cursor();
2611#ifdef FEAT_MBYTE
2612 /* Correct cursor for multi-byte character. */
2613 if (has_mbyte)
2614 mb_adjust_cursor();
2615#endif
2616
2617 curwin->w_set_curswant = set_curswant;
2618 rettv->vval.v_number = 0;
2619}
2620
2621/*
2622 * "deepcopy()" function
2623 */
2624 static void
2625f_deepcopy(typval_T *argvars, typval_T *rettv)
2626{
2627 int noref = 0;
2628 int copyID;
2629
2630 if (argvars[1].v_type != VAR_UNKNOWN)
2631 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2632 if (noref < 0 || noref > 1)
2633 EMSG(_(e_invarg));
2634 else
2635 {
2636 copyID = get_copyID();
2637 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2638 }
2639}
2640
2641/*
2642 * "delete()" function
2643 */
2644 static void
2645f_delete(typval_T *argvars, typval_T *rettv)
2646{
2647 char_u nbuf[NUMBUFLEN];
2648 char_u *name;
2649 char_u *flags;
2650
2651 rettv->vval.v_number = -1;
2652 if (check_restricted() || check_secure())
2653 return;
2654
2655 name = get_tv_string(&argvars[0]);
2656 if (name == NULL || *name == NUL)
2657 {
2658 EMSG(_(e_invarg));
2659 return;
2660 }
2661
2662 if (argvars[1].v_type != VAR_UNKNOWN)
2663 flags = get_tv_string_buf(&argvars[1], nbuf);
2664 else
2665 flags = (char_u *)"";
2666
2667 if (*flags == NUL)
2668 /* delete a file */
2669 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2670 else if (STRCMP(flags, "d") == 0)
2671 /* delete an empty directory */
2672 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2673 else if (STRCMP(flags, "rf") == 0)
2674 /* delete a directory recursively */
2675 rettv->vval.v_number = delete_recursive(name);
2676 else
2677 EMSG2(_(e_invexpr2), flags);
2678}
2679
2680/*
2681 * "did_filetype()" function
2682 */
2683 static void
2684f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2685{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002686 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002687}
2688
2689/*
2690 * "diff_filler()" function
2691 */
2692 static void
2693f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2694{
2695#ifdef FEAT_DIFF
2696 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2697#endif
2698}
2699
2700/*
2701 * "diff_hlID()" function
2702 */
2703 static void
2704f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2705{
2706#ifdef FEAT_DIFF
2707 linenr_T lnum = get_tv_lnum(argvars);
2708 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002709 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002710 static int fnum = 0;
2711 static int change_start = 0;
2712 static int change_end = 0;
2713 static hlf_T hlID = (hlf_T)0;
2714 int filler_lines;
2715 int col;
2716
2717 if (lnum < 0) /* ignore type error in {lnum} arg */
2718 lnum = 0;
2719 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002720 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002721 || fnum != curbuf->b_fnum)
2722 {
2723 /* New line, buffer, change: need to get the values. */
2724 filler_lines = diff_check(curwin, lnum);
2725 if (filler_lines < 0)
2726 {
2727 if (filler_lines == -1)
2728 {
2729 change_start = MAXCOL;
2730 change_end = -1;
2731 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2732 hlID = HLF_ADD; /* added line */
2733 else
2734 hlID = HLF_CHD; /* changed line */
2735 }
2736 else
2737 hlID = HLF_ADD; /* added line */
2738 }
2739 else
2740 hlID = (hlf_T)0;
2741 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002742 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002743 fnum = curbuf->b_fnum;
2744 }
2745
2746 if (hlID == HLF_CHD || hlID == HLF_TXD)
2747 {
2748 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2749 if (col >= change_start && col <= change_end)
2750 hlID = HLF_TXD; /* changed text */
2751 else
2752 hlID = HLF_CHD; /* changed line */
2753 }
2754 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2755#endif
2756}
2757
2758/*
2759 * "empty({expr})" function
2760 */
2761 static void
2762f_empty(typval_T *argvars, typval_T *rettv)
2763{
2764 int n = FALSE;
2765
2766 switch (argvars[0].v_type)
2767 {
2768 case VAR_STRING:
2769 case VAR_FUNC:
2770 n = argvars[0].vval.v_string == NULL
2771 || *argvars[0].vval.v_string == NUL;
2772 break;
2773 case VAR_PARTIAL:
2774 n = FALSE;
2775 break;
2776 case VAR_NUMBER:
2777 n = argvars[0].vval.v_number == 0;
2778 break;
2779 case VAR_FLOAT:
2780#ifdef FEAT_FLOAT
2781 n = argvars[0].vval.v_float == 0.0;
2782 break;
2783#endif
2784 case VAR_LIST:
2785 n = argvars[0].vval.v_list == NULL
2786 || argvars[0].vval.v_list->lv_first == NULL;
2787 break;
2788 case VAR_DICT:
2789 n = argvars[0].vval.v_dict == NULL
2790 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2791 break;
2792 case VAR_SPECIAL:
2793 n = argvars[0].vval.v_number != VVAL_TRUE;
2794 break;
2795
2796 case VAR_JOB:
2797#ifdef FEAT_JOB_CHANNEL
2798 n = argvars[0].vval.v_job == NULL
2799 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2800 break;
2801#endif
2802 case VAR_CHANNEL:
2803#ifdef FEAT_JOB_CHANNEL
2804 n = argvars[0].vval.v_channel == NULL
2805 || !channel_is_open(argvars[0].vval.v_channel);
2806 break;
2807#endif
2808 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002809 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002810 n = TRUE;
2811 break;
2812 }
2813
2814 rettv->vval.v_number = n;
2815}
2816
2817/*
2818 * "escape({string}, {chars})" function
2819 */
2820 static void
2821f_escape(typval_T *argvars, typval_T *rettv)
2822{
2823 char_u buf[NUMBUFLEN];
2824
2825 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2826 get_tv_string_buf(&argvars[1], buf));
2827 rettv->v_type = VAR_STRING;
2828}
2829
2830/*
2831 * "eval()" function
2832 */
2833 static void
2834f_eval(typval_T *argvars, typval_T *rettv)
2835{
2836 char_u *s, *p;
2837
2838 s = get_tv_string_chk(&argvars[0]);
2839 if (s != NULL)
2840 s = skipwhite(s);
2841
2842 p = s;
2843 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2844 {
2845 if (p != NULL && !aborting())
2846 EMSG2(_(e_invexpr2), p);
2847 need_clr_eos = FALSE;
2848 rettv->v_type = VAR_NUMBER;
2849 rettv->vval.v_number = 0;
2850 }
2851 else if (*s != NUL)
2852 EMSG(_(e_trailing));
2853}
2854
2855/*
2856 * "eventhandler()" function
2857 */
2858 static void
2859f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2860{
2861 rettv->vval.v_number = vgetc_busy;
2862}
2863
2864/*
2865 * "executable()" function
2866 */
2867 static void
2868f_executable(typval_T *argvars, typval_T *rettv)
2869{
2870 char_u *name = get_tv_string(&argvars[0]);
2871
2872 /* Check in $PATH and also check directly if there is a directory name. */
2873 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2874 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2875}
2876
2877static garray_T redir_execute_ga;
2878
2879/*
2880 * Append "value[value_len]" to the execute() output.
2881 */
2882 void
2883execute_redir_str(char_u *value, int value_len)
2884{
2885 int len;
2886
2887 if (value_len == -1)
2888 len = (int)STRLEN(value); /* Append the entire string */
2889 else
2890 len = value_len; /* Append only "value_len" characters */
2891 if (ga_grow(&redir_execute_ga, len) == OK)
2892 {
2893 mch_memmove((char *)redir_execute_ga.ga_data
2894 + redir_execute_ga.ga_len, value, len);
2895 redir_execute_ga.ga_len += len;
2896 }
2897}
2898
2899/*
2900 * Get next line from a list.
2901 * Called by do_cmdline() to get the next line.
2902 * Returns allocated string, or NULL for end of function.
2903 */
2904
2905 static char_u *
2906get_list_line(
2907 int c UNUSED,
2908 void *cookie,
2909 int indent UNUSED)
2910{
2911 listitem_T **p = (listitem_T **)cookie;
2912 listitem_T *item = *p;
2913 char_u buf[NUMBUFLEN];
2914 char_u *s;
2915
2916 if (item == NULL)
2917 return NULL;
2918 s = get_tv_string_buf_chk(&item->li_tv, buf);
2919 *p = item->li_next;
2920 return s == NULL ? NULL : vim_strsave(s);
2921}
2922
2923/*
2924 * "execute()" function
2925 */
2926 static void
2927f_execute(typval_T *argvars, typval_T *rettv)
2928{
2929 char_u *cmd = NULL;
2930 list_T *list = NULL;
2931 int save_msg_silent = msg_silent;
2932 int save_emsg_silent = emsg_silent;
2933 int save_emsg_noredir = emsg_noredir;
2934 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002935 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002936 garray_T save_ga;
2937
2938 rettv->vval.v_string = NULL;
2939 rettv->v_type = VAR_STRING;
2940
2941 if (argvars[0].v_type == VAR_LIST)
2942 {
2943 list = argvars[0].vval.v_list;
2944 if (list == NULL || list->lv_first == NULL)
2945 /* empty list, no commands, empty output */
2946 return;
2947 ++list->lv_refcount;
2948 }
2949 else
2950 {
2951 cmd = get_tv_string_chk(&argvars[0]);
2952 if (cmd == NULL)
2953 return;
2954 }
2955
2956 if (argvars[1].v_type != VAR_UNKNOWN)
2957 {
2958 char_u buf[NUMBUFLEN];
2959 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2960
2961 if (s == NULL)
2962 return;
2963 if (STRNCMP(s, "silent", 6) == 0)
2964 ++msg_silent;
2965 if (STRCMP(s, "silent!") == 0)
2966 {
2967 emsg_silent = TRUE;
2968 emsg_noredir = TRUE;
2969 }
2970 }
2971 else
2972 ++msg_silent;
2973
2974 if (redir_execute)
2975 save_ga = redir_execute_ga;
2976 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2977 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002978 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002979
2980 if (cmd != NULL)
2981 do_cmdline_cmd(cmd);
2982 else
2983 {
2984 listitem_T *item = list->lv_first;
2985
2986 do_cmdline(NULL, get_list_line, (void *)&item,
2987 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2988 --list->lv_refcount;
2989 }
2990
Bram Moolenaard297f352017-01-29 20:31:21 +01002991 /* Need to append a NUL to the result. */
2992 if (ga_grow(&redir_execute_ga, 1) == OK)
2993 {
2994 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2995 rettv->vval.v_string = redir_execute_ga.ga_data;
2996 }
2997 else
2998 {
2999 ga_clear(&redir_execute_ga);
3000 rettv->vval.v_string = NULL;
3001 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003002 msg_silent = save_msg_silent;
3003 emsg_silent = save_emsg_silent;
3004 emsg_noredir = save_emsg_noredir;
3005
3006 redir_execute = save_redir_execute;
3007 if (redir_execute)
3008 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003009 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003010
3011 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3012 * line. Put it back in the first column. */
3013 msg_col = 0;
3014}
3015
3016/*
3017 * "exepath()" function
3018 */
3019 static void
3020f_exepath(typval_T *argvars, typval_T *rettv)
3021{
3022 char_u *p = NULL;
3023
3024 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3025 rettv->v_type = VAR_STRING;
3026 rettv->vval.v_string = p;
3027}
3028
3029/*
3030 * "exists()" function
3031 */
3032 static void
3033f_exists(typval_T *argvars, typval_T *rettv)
3034{
3035 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003037
3038 p = get_tv_string(&argvars[0]);
3039 if (*p == '$') /* environment variable */
3040 {
3041 /* first try "normal" environment variables (fast) */
3042 if (mch_getenv(p + 1) != NULL)
3043 n = TRUE;
3044 else
3045 {
3046 /* try expanding things like $VIM and ${HOME} */
3047 p = expand_env_save(p);
3048 if (p != NULL && *p != '$')
3049 n = TRUE;
3050 vim_free(p);
3051 }
3052 }
3053 else if (*p == '&' || *p == '+') /* option */
3054 {
3055 n = (get_option_tv(&p, NULL, TRUE) == OK);
3056 if (*skipwhite(p) != NUL)
3057 n = FALSE; /* trailing garbage */
3058 }
3059 else if (*p == '*') /* internal or user defined function */
3060 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003061 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062 }
3063 else if (*p == ':')
3064 {
3065 n = cmd_exists(p + 1);
3066 }
3067 else if (*p == '#')
3068 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003069 if (p[1] == '#')
3070 n = autocmd_supported(p + 2);
3071 else
3072 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 }
3074 else /* internal variable */
3075 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003076 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 }
3078
3079 rettv->vval.v_number = n;
3080}
3081
3082#ifdef FEAT_FLOAT
3083/*
3084 * "exp()" function
3085 */
3086 static void
3087f_exp(typval_T *argvars, typval_T *rettv)
3088{
3089 float_T f = 0.0;
3090
3091 rettv->v_type = VAR_FLOAT;
3092 if (get_float_arg(argvars, &f) == OK)
3093 rettv->vval.v_float = exp(f);
3094 else
3095 rettv->vval.v_float = 0.0;
3096}
3097#endif
3098
3099/*
3100 * "expand()" function
3101 */
3102 static void
3103f_expand(typval_T *argvars, typval_T *rettv)
3104{
3105 char_u *s;
3106 int len;
3107 char_u *errormsg;
3108 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3109 expand_T xpc;
3110 int error = FALSE;
3111 char_u *result;
3112
3113 rettv->v_type = VAR_STRING;
3114 if (argvars[1].v_type != VAR_UNKNOWN
3115 && argvars[2].v_type != VAR_UNKNOWN
3116 && get_tv_number_chk(&argvars[2], &error)
3117 && !error)
3118 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003119 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003120 }
3121
3122 s = get_tv_string(&argvars[0]);
3123 if (*s == '%' || *s == '#' || *s == '<')
3124 {
3125 ++emsg_off;
3126 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3127 --emsg_off;
3128 if (rettv->v_type == VAR_LIST)
3129 {
3130 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3131 list_append_string(rettv->vval.v_list, result, -1);
3132 else
3133 vim_free(result);
3134 }
3135 else
3136 rettv->vval.v_string = result;
3137 }
3138 else
3139 {
3140 /* When the optional second argument is non-zero, don't remove matches
3141 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3142 if (argvars[1].v_type != VAR_UNKNOWN
3143 && get_tv_number_chk(&argvars[1], &error))
3144 options |= WILD_KEEP_ALL;
3145 if (!error)
3146 {
3147 ExpandInit(&xpc);
3148 xpc.xp_context = EXPAND_FILES;
3149 if (p_wic)
3150 options += WILD_ICASE;
3151 if (rettv->v_type == VAR_STRING)
3152 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3153 options, WILD_ALL);
3154 else if (rettv_list_alloc(rettv) != FAIL)
3155 {
3156 int i;
3157
3158 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3159 for (i = 0; i < xpc.xp_numfiles; i++)
3160 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3161 ExpandCleanup(&xpc);
3162 }
3163 }
3164 else
3165 rettv->vval.v_string = NULL;
3166 }
3167}
3168
3169/*
3170 * "extend(list, list [, idx])" function
3171 * "extend(dict, dict [, action])" function
3172 */
3173 static void
3174f_extend(typval_T *argvars, typval_T *rettv)
3175{
3176 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3177
3178 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3179 {
3180 list_T *l1, *l2;
3181 listitem_T *item;
3182 long before;
3183 int error = FALSE;
3184
3185 l1 = argvars[0].vval.v_list;
3186 l2 = argvars[1].vval.v_list;
3187 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3188 && l2 != NULL)
3189 {
3190 if (argvars[2].v_type != VAR_UNKNOWN)
3191 {
3192 before = (long)get_tv_number_chk(&argvars[2], &error);
3193 if (error)
3194 return; /* type error; errmsg already given */
3195
3196 if (before == l1->lv_len)
3197 item = NULL;
3198 else
3199 {
3200 item = list_find(l1, before);
3201 if (item == NULL)
3202 {
3203 EMSGN(_(e_listidx), before);
3204 return;
3205 }
3206 }
3207 }
3208 else
3209 item = NULL;
3210 list_extend(l1, l2, item);
3211
3212 copy_tv(&argvars[0], rettv);
3213 }
3214 }
3215 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3216 {
3217 dict_T *d1, *d2;
3218 char_u *action;
3219 int i;
3220
3221 d1 = argvars[0].vval.v_dict;
3222 d2 = argvars[1].vval.v_dict;
3223 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3224 && d2 != NULL)
3225 {
3226 /* Check the third argument. */
3227 if (argvars[2].v_type != VAR_UNKNOWN)
3228 {
3229 static char *(av[]) = {"keep", "force", "error"};
3230
3231 action = get_tv_string_chk(&argvars[2]);
3232 if (action == NULL)
3233 return; /* type error; errmsg already given */
3234 for (i = 0; i < 3; ++i)
3235 if (STRCMP(action, av[i]) == 0)
3236 break;
3237 if (i == 3)
3238 {
3239 EMSG2(_(e_invarg2), action);
3240 return;
3241 }
3242 }
3243 else
3244 action = (char_u *)"force";
3245
3246 dict_extend(d1, d2, action);
3247
3248 copy_tv(&argvars[0], rettv);
3249 }
3250 }
3251 else
3252 EMSG2(_(e_listdictarg), "extend()");
3253}
3254
3255/*
3256 * "feedkeys()" function
3257 */
3258 static void
3259f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3260{
3261 int remap = TRUE;
3262 int insert = FALSE;
3263 char_u *keys, *flags;
3264 char_u nbuf[NUMBUFLEN];
3265 int typed = FALSE;
3266 int execute = FALSE;
3267 int dangerous = FALSE;
3268 char_u *keys_esc;
3269
3270 /* This is not allowed in the sandbox. If the commands would still be
3271 * executed in the sandbox it would be OK, but it probably happens later,
3272 * when "sandbox" is no longer set. */
3273 if (check_secure())
3274 return;
3275
3276 keys = get_tv_string(&argvars[0]);
3277
3278 if (argvars[1].v_type != VAR_UNKNOWN)
3279 {
3280 flags = get_tv_string_buf(&argvars[1], nbuf);
3281 for ( ; *flags != NUL; ++flags)
3282 {
3283 switch (*flags)
3284 {
3285 case 'n': remap = FALSE; break;
3286 case 'm': remap = TRUE; break;
3287 case 't': typed = TRUE; break;
3288 case 'i': insert = TRUE; break;
3289 case 'x': execute = TRUE; break;
3290 case '!': dangerous = TRUE; break;
3291 }
3292 }
3293 }
3294
3295 if (*keys != NUL || execute)
3296 {
3297 /* Need to escape K_SPECIAL and CSI before putting the string in the
3298 * typeahead buffer. */
3299 keys_esc = vim_strsave_escape_csi(keys);
3300 if (keys_esc != NULL)
3301 {
3302 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3303 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3304 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003305 if (vgetc_busy
3306#ifdef FEAT_TIMERS
3307 || timer_busy
3308#endif
3309 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003310 typebuf_was_filled = TRUE;
3311 if (execute)
3312 {
3313 int save_msg_scroll = msg_scroll;
3314
3315 /* Avoid a 1 second delay when the keys start Insert mode. */
3316 msg_scroll = FALSE;
3317
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003318 if (!dangerous)
3319 ++ex_normal_busy;
Bram Moolenaar655a82a2018-05-08 22:01:07 +02003320 exec_normal(TRUE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003321 if (!dangerous)
3322 --ex_normal_busy;
3323
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003324 msg_scroll |= save_msg_scroll;
3325 }
3326 }
3327 }
3328}
3329
3330/*
3331 * "filereadable()" function
3332 */
3333 static void
3334f_filereadable(typval_T *argvars, typval_T *rettv)
3335{
3336 int fd;
3337 char_u *p;
3338 int n;
3339
3340#ifndef O_NONBLOCK
3341# define O_NONBLOCK 0
3342#endif
3343 p = get_tv_string(&argvars[0]);
3344 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3345 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3346 {
3347 n = TRUE;
3348 close(fd);
3349 }
3350 else
3351 n = FALSE;
3352
3353 rettv->vval.v_number = n;
3354}
3355
3356/*
3357 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3358 * rights to write into.
3359 */
3360 static void
3361f_filewritable(typval_T *argvars, typval_T *rettv)
3362{
3363 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3364}
3365
3366 static void
3367findfilendir(
3368 typval_T *argvars UNUSED,
3369 typval_T *rettv,
3370 int find_what UNUSED)
3371{
3372#ifdef FEAT_SEARCHPATH
3373 char_u *fname;
3374 char_u *fresult = NULL;
3375 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3376 char_u *p;
3377 char_u pathbuf[NUMBUFLEN];
3378 int count = 1;
3379 int first = TRUE;
3380 int error = FALSE;
3381#endif
3382
3383 rettv->vval.v_string = NULL;
3384 rettv->v_type = VAR_STRING;
3385
3386#ifdef FEAT_SEARCHPATH
3387 fname = get_tv_string(&argvars[0]);
3388
3389 if (argvars[1].v_type != VAR_UNKNOWN)
3390 {
3391 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3392 if (p == NULL)
3393 error = TRUE;
3394 else
3395 {
3396 if (*p != NUL)
3397 path = p;
3398
3399 if (argvars[2].v_type != VAR_UNKNOWN)
3400 count = (int)get_tv_number_chk(&argvars[2], &error);
3401 }
3402 }
3403
3404 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3405 error = TRUE;
3406
3407 if (*fname != NUL && !error)
3408 {
3409 do
3410 {
3411 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3412 vim_free(fresult);
3413 fresult = find_file_in_path_option(first ? fname : NULL,
3414 first ? (int)STRLEN(fname) : 0,
3415 0, first, path,
3416 find_what,
3417 curbuf->b_ffname,
3418 find_what == FINDFILE_DIR
3419 ? (char_u *)"" : curbuf->b_p_sua);
3420 first = FALSE;
3421
3422 if (fresult != NULL && rettv->v_type == VAR_LIST)
3423 list_append_string(rettv->vval.v_list, fresult, -1);
3424
3425 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3426 }
3427
3428 if (rettv->v_type == VAR_STRING)
3429 rettv->vval.v_string = fresult;
3430#endif
3431}
3432
3433/*
3434 * "filter()" function
3435 */
3436 static void
3437f_filter(typval_T *argvars, typval_T *rettv)
3438{
3439 filter_map(argvars, rettv, FALSE);
3440}
3441
3442/*
3443 * "finddir({fname}[, {path}[, {count}]])" function
3444 */
3445 static void
3446f_finddir(typval_T *argvars, typval_T *rettv)
3447{
3448 findfilendir(argvars, rettv, FINDFILE_DIR);
3449}
3450
3451/*
3452 * "findfile({fname}[, {path}[, {count}]])" function
3453 */
3454 static void
3455f_findfile(typval_T *argvars, typval_T *rettv)
3456{
3457 findfilendir(argvars, rettv, FINDFILE_FILE);
3458}
3459
3460#ifdef FEAT_FLOAT
3461/*
3462 * "float2nr({float})" function
3463 */
3464 static void
3465f_float2nr(typval_T *argvars, typval_T *rettv)
3466{
3467 float_T f = 0.0;
3468
3469 if (get_float_arg(argvars, &f) == OK)
3470 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003471 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003472 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003473 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003474 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475 else
3476 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003477 }
3478}
3479
3480/*
3481 * "floor({float})" function
3482 */
3483 static void
3484f_floor(typval_T *argvars, typval_T *rettv)
3485{
3486 float_T f = 0.0;
3487
3488 rettv->v_type = VAR_FLOAT;
3489 if (get_float_arg(argvars, &f) == OK)
3490 rettv->vval.v_float = floor(f);
3491 else
3492 rettv->vval.v_float = 0.0;
3493}
3494
3495/*
3496 * "fmod()" function
3497 */
3498 static void
3499f_fmod(typval_T *argvars, typval_T *rettv)
3500{
3501 float_T fx = 0.0, fy = 0.0;
3502
3503 rettv->v_type = VAR_FLOAT;
3504 if (get_float_arg(argvars, &fx) == OK
3505 && get_float_arg(&argvars[1], &fy) == OK)
3506 rettv->vval.v_float = fmod(fx, fy);
3507 else
3508 rettv->vval.v_float = 0.0;
3509}
3510#endif
3511
3512/*
3513 * "fnameescape({string})" function
3514 */
3515 static void
3516f_fnameescape(typval_T *argvars, typval_T *rettv)
3517{
3518 rettv->vval.v_string = vim_strsave_fnameescape(
3519 get_tv_string(&argvars[0]), FALSE);
3520 rettv->v_type = VAR_STRING;
3521}
3522
3523/*
3524 * "fnamemodify({fname}, {mods})" function
3525 */
3526 static void
3527f_fnamemodify(typval_T *argvars, typval_T *rettv)
3528{
3529 char_u *fname;
3530 char_u *mods;
3531 int usedlen = 0;
3532 int len;
3533 char_u *fbuf = NULL;
3534 char_u buf[NUMBUFLEN];
3535
3536 fname = get_tv_string_chk(&argvars[0]);
3537 mods = get_tv_string_buf_chk(&argvars[1], buf);
3538 if (fname == NULL || mods == NULL)
3539 fname = NULL;
3540 else
3541 {
3542 len = (int)STRLEN(fname);
3543 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3544 }
3545
3546 rettv->v_type = VAR_STRING;
3547 if (fname == NULL)
3548 rettv->vval.v_string = NULL;
3549 else
3550 rettv->vval.v_string = vim_strnsave(fname, len);
3551 vim_free(fbuf);
3552}
3553
3554static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3555
3556/*
3557 * "foldclosed()" function
3558 */
3559 static void
3560foldclosed_both(
3561 typval_T *argvars UNUSED,
3562 typval_T *rettv,
3563 int end UNUSED)
3564{
3565#ifdef FEAT_FOLDING
3566 linenr_T lnum;
3567 linenr_T first, last;
3568
3569 lnum = get_tv_lnum(argvars);
3570 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3571 {
3572 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3573 {
3574 if (end)
3575 rettv->vval.v_number = (varnumber_T)last;
3576 else
3577 rettv->vval.v_number = (varnumber_T)first;
3578 return;
3579 }
3580 }
3581#endif
3582 rettv->vval.v_number = -1;
3583}
3584
3585/*
3586 * "foldclosed()" function
3587 */
3588 static void
3589f_foldclosed(typval_T *argvars, typval_T *rettv)
3590{
3591 foldclosed_both(argvars, rettv, FALSE);
3592}
3593
3594/*
3595 * "foldclosedend()" function
3596 */
3597 static void
3598f_foldclosedend(typval_T *argvars, typval_T *rettv)
3599{
3600 foldclosed_both(argvars, rettv, TRUE);
3601}
3602
3603/*
3604 * "foldlevel()" function
3605 */
3606 static void
3607f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3608{
3609#ifdef FEAT_FOLDING
3610 linenr_T lnum;
3611
3612 lnum = get_tv_lnum(argvars);
3613 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3614 rettv->vval.v_number = foldLevel(lnum);
3615#endif
3616}
3617
3618/*
3619 * "foldtext()" function
3620 */
3621 static void
3622f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3623{
3624#ifdef FEAT_FOLDING
3625 linenr_T foldstart;
3626 linenr_T foldend;
3627 char_u *dashes;
3628 linenr_T lnum;
3629 char_u *s;
3630 char_u *r;
3631 int len;
3632 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003633 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634#endif
3635
3636 rettv->v_type = VAR_STRING;
3637 rettv->vval.v_string = NULL;
3638#ifdef FEAT_FOLDING
3639 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3640 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3641 dashes = get_vim_var_str(VV_FOLDDASHES);
3642 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3643 && dashes != NULL)
3644 {
3645 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003646 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647 if (!linewhite(lnum))
3648 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649
3650 /* Find interesting text in this line. */
3651 s = skipwhite(ml_get(lnum));
3652 /* skip C comment-start */
3653 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3654 {
3655 s = skipwhite(s + 2);
3656 if (*skipwhite(s) == NUL
3657 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3658 {
3659 s = skipwhite(ml_get(lnum + 1));
3660 if (*s == '*')
3661 s = skipwhite(s + 1);
3662 }
3663 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003664 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003665 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003666 r = alloc((unsigned)(STRLEN(txt)
3667 + STRLEN(dashes) /* for %s */
3668 + 20 /* for %3ld */
3669 + STRLEN(s))); /* concatenated */
3670 if (r != NULL)
3671 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003672 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003673 len = (int)STRLEN(r);
3674 STRCAT(r, s);
3675 /* remove 'foldmarker' and 'commentstring' */
3676 foldtext_cleanup(r + len);
3677 rettv->vval.v_string = r;
3678 }
3679 }
3680#endif
3681}
3682
3683/*
3684 * "foldtextresult(lnum)" function
3685 */
3686 static void
3687f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3688{
3689#ifdef FEAT_FOLDING
3690 linenr_T lnum;
3691 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003692 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003693 foldinfo_T foldinfo;
3694 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003695 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003696#endif
3697
3698 rettv->v_type = VAR_STRING;
3699 rettv->vval.v_string = NULL;
3700#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003701 if (entered)
3702 return; /* reject recursive use */
3703 entered = TRUE;
3704
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003705 lnum = get_tv_lnum(argvars);
3706 /* treat illegal types and illegal string values for {lnum} the same */
3707 if (lnum < 0)
3708 lnum = 0;
3709 fold_count = foldedCount(curwin, lnum, &foldinfo);
3710 if (fold_count > 0)
3711 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003712 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3713 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714 if (text == buf)
3715 text = vim_strsave(text);
3716 rettv->vval.v_string = text;
3717 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003718
3719 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720#endif
3721}
3722
3723/*
3724 * "foreground()" function
3725 */
3726 static void
3727f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3728{
3729#ifdef FEAT_GUI
3730 if (gui.in_use)
3731 gui_mch_set_foreground();
3732#else
3733# ifdef WIN32
3734 win32_set_foreground();
3735# endif
3736#endif
3737}
3738
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003739 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003740common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003741{
3742 char_u *s;
3743 char_u *name;
3744 int use_string = FALSE;
3745 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003746 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747
3748 if (argvars[0].v_type == VAR_FUNC)
3749 {
3750 /* function(MyFunc, [arg], dict) */
3751 s = argvars[0].vval.v_string;
3752 }
3753 else if (argvars[0].v_type == VAR_PARTIAL
3754 && argvars[0].vval.v_partial != NULL)
3755 {
3756 /* function(dict.MyFunc, [arg]) */
3757 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003758 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003759 }
3760 else
3761 {
3762 /* function('MyFunc', [arg], dict) */
3763 s = get_tv_string(&argvars[0]);
3764 use_string = TRUE;
3765 }
3766
Bram Moolenaar843b8842016-08-21 14:36:15 +02003767 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003768 {
3769 name = s;
3770 trans_name = trans_function_name(&name, FALSE,
3771 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3772 if (*name != NUL)
3773 s = NULL;
3774 }
3775
Bram Moolenaar843b8842016-08-21 14:36:15 +02003776 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3777 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003778 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003779 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003780 else if (trans_name != NULL && (is_funcref
3781 ? find_func(trans_name) == NULL
3782 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003783 EMSG2(_("E700: Unknown function: %s"), s);
3784 else
3785 {
3786 int dict_idx = 0;
3787 int arg_idx = 0;
3788 list_T *list = NULL;
3789
3790 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3791 {
3792 char sid_buf[25];
3793 int off = *s == 's' ? 2 : 5;
3794
3795 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3796 * also be called from another script. Using trans_function_name()
3797 * would also work, but some plugins depend on the name being
3798 * printable text. */
3799 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3800 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3801 if (name != NULL)
3802 {
3803 STRCPY(name, sid_buf);
3804 STRCAT(name, s + off);
3805 }
3806 }
3807 else
3808 name = vim_strsave(s);
3809
3810 if (argvars[1].v_type != VAR_UNKNOWN)
3811 {
3812 if (argvars[2].v_type != VAR_UNKNOWN)
3813 {
3814 /* function(name, [args], dict) */
3815 arg_idx = 1;
3816 dict_idx = 2;
3817 }
3818 else if (argvars[1].v_type == VAR_DICT)
3819 /* function(name, dict) */
3820 dict_idx = 1;
3821 else
3822 /* function(name, [args]) */
3823 arg_idx = 1;
3824 if (dict_idx > 0)
3825 {
3826 if (argvars[dict_idx].v_type != VAR_DICT)
3827 {
3828 EMSG(_("E922: expected a dict"));
3829 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003830 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831 }
3832 if (argvars[dict_idx].vval.v_dict == NULL)
3833 dict_idx = 0;
3834 }
3835 if (arg_idx > 0)
3836 {
3837 if (argvars[arg_idx].v_type != VAR_LIST)
3838 {
3839 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3840 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003841 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003842 }
3843 list = argvars[arg_idx].vval.v_list;
3844 if (list == NULL || list->lv_len == 0)
3845 arg_idx = 0;
3846 }
3847 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003848 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003849 {
3850 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3851
3852 /* result is a VAR_PARTIAL */
3853 if (pt == NULL)
3854 vim_free(name);
3855 else
3856 {
3857 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3858 {
3859 listitem_T *li;
3860 int i = 0;
3861 int arg_len = 0;
3862 int lv_len = 0;
3863
3864 if (arg_pt != NULL)
3865 arg_len = arg_pt->pt_argc;
3866 if (list != NULL)
3867 lv_len = list->lv_len;
3868 pt->pt_argc = arg_len + lv_len;
3869 pt->pt_argv = (typval_T *)alloc(
3870 sizeof(typval_T) * pt->pt_argc);
3871 if (pt->pt_argv == NULL)
3872 {
3873 vim_free(pt);
3874 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003875 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003876 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003877 for (i = 0; i < arg_len; i++)
3878 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3879 if (lv_len > 0)
3880 for (li = list->lv_first; li != NULL;
3881 li = li->li_next)
3882 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003883 }
3884
3885 /* For "function(dict.func, [], dict)" and "func" is a partial
3886 * use "dict". That is backwards compatible. */
3887 if (dict_idx > 0)
3888 {
3889 /* The dict is bound explicitly, pt_auto is FALSE. */
3890 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3891 ++pt->pt_dict->dv_refcount;
3892 }
3893 else if (arg_pt != NULL)
3894 {
3895 /* If the dict was bound automatically the result is also
3896 * bound automatically. */
3897 pt->pt_dict = arg_pt->pt_dict;
3898 pt->pt_auto = arg_pt->pt_auto;
3899 if (pt->pt_dict != NULL)
3900 ++pt->pt_dict->dv_refcount;
3901 }
3902
3903 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003904 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3905 {
3906 pt->pt_func = arg_pt->pt_func;
3907 func_ptr_ref(pt->pt_func);
3908 vim_free(name);
3909 }
3910 else if (is_funcref)
3911 {
3912 pt->pt_func = find_func(trans_name);
3913 func_ptr_ref(pt->pt_func);
3914 vim_free(name);
3915 }
3916 else
3917 {
3918 pt->pt_name = name;
3919 func_ref(name);
3920 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 }
3922 rettv->v_type = VAR_PARTIAL;
3923 rettv->vval.v_partial = pt;
3924 }
3925 else
3926 {
3927 /* result is a VAR_FUNC */
3928 rettv->v_type = VAR_FUNC;
3929 rettv->vval.v_string = name;
3930 func_ref(name);
3931 }
3932 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003933theend:
3934 vim_free(trans_name);
3935}
3936
3937/*
3938 * "funcref()" function
3939 */
3940 static void
3941f_funcref(typval_T *argvars, typval_T *rettv)
3942{
3943 common_function(argvars, rettv, TRUE);
3944}
3945
3946/*
3947 * "function()" function
3948 */
3949 static void
3950f_function(typval_T *argvars, typval_T *rettv)
3951{
3952 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953}
3954
3955/*
3956 * "garbagecollect()" function
3957 */
3958 static void
3959f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3960{
3961 /* This is postponed until we are back at the toplevel, because we may be
3962 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3963 want_garbage_collect = TRUE;
3964
3965 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3966 garbage_collect_at_exit = TRUE;
3967}
3968
3969/*
3970 * "get()" function
3971 */
3972 static void
3973f_get(typval_T *argvars, typval_T *rettv)
3974{
3975 listitem_T *li;
3976 list_T *l;
3977 dictitem_T *di;
3978 dict_T *d;
3979 typval_T *tv = NULL;
3980
3981 if (argvars[0].v_type == VAR_LIST)
3982 {
3983 if ((l = argvars[0].vval.v_list) != NULL)
3984 {
3985 int error = FALSE;
3986
3987 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3988 if (!error && li != NULL)
3989 tv = &li->li_tv;
3990 }
3991 }
3992 else if (argvars[0].v_type == VAR_DICT)
3993 {
3994 if ((d = argvars[0].vval.v_dict) != NULL)
3995 {
3996 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3997 if (di != NULL)
3998 tv = &di->di_tv;
3999 }
4000 }
4001 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4002 {
4003 partial_T *pt;
4004 partial_T fref_pt;
4005
4006 if (argvars[0].v_type == VAR_PARTIAL)
4007 pt = argvars[0].vval.v_partial;
4008 else
4009 {
4010 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4011 fref_pt.pt_name = argvars[0].vval.v_string;
4012 pt = &fref_pt;
4013 }
4014
4015 if (pt != NULL)
4016 {
4017 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004018 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004019
4020 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4021 {
4022 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004023 n = partial_name(pt);
4024 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004025 rettv->vval.v_string = NULL;
4026 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004027 {
4028 rettv->vval.v_string = vim_strsave(n);
4029 if (rettv->v_type == VAR_FUNC)
4030 func_ref(rettv->vval.v_string);
4031 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004032 }
4033 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004034 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004035 else if (STRCMP(what, "args") == 0)
4036 {
4037 rettv->v_type = VAR_LIST;
4038 if (rettv_list_alloc(rettv) == OK)
4039 {
4040 int i;
4041
4042 for (i = 0; i < pt->pt_argc; ++i)
4043 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4044 }
4045 }
4046 else
4047 EMSG2(_(e_invarg2), what);
4048 return;
4049 }
4050 }
4051 else
4052 EMSG2(_(e_listdictarg), "get()");
4053
4054 if (tv == NULL)
4055 {
4056 if (argvars[2].v_type != VAR_UNKNOWN)
4057 copy_tv(&argvars[2], rettv);
4058 }
4059 else
4060 copy_tv(tv, rettv);
4061}
4062
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004063#ifdef FEAT_SIGNS
4064/*
4065 * Returns information about signs placed in a buffer as list of dicts.
4066 */
4067 static void
4068get_buffer_signs(buf_T *buf, list_T *l)
4069{
4070 signlist_T *sign;
4071
4072 for (sign = buf->b_signlist; sign; sign = sign->next)
4073 {
4074 dict_T *d = dict_alloc();
4075
4076 if (d != NULL)
4077 {
4078 dict_add_nr_str(d, "id", sign->id, NULL);
4079 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004080 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004081
4082 list_append_dict(l, d);
4083 }
4084 }
4085}
4086#endif
4087
4088/*
4089 * Returns buffer options, variables and other attributes in a dictionary.
4090 */
4091 static dict_T *
4092get_buffer_info(buf_T *buf)
4093{
4094 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004095 tabpage_T *tp;
4096 win_T *wp;
4097 list_T *windows;
4098
4099 dict = dict_alloc();
4100 if (dict == NULL)
4101 return NULL;
4102
Bram Moolenaar33928832016-08-18 21:22:04 +02004103 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004104 dict_add_nr_str(dict, "name", 0L,
4105 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004106 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4107 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004108 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4109 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4110 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004111 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004112 dict_add_nr_str(dict, "hidden",
4113 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4114 NULL);
4115
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004116 /* Get a reference to buffer variables */
4117 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004118
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004119 /* List of windows displaying this buffer */
4120 windows = list_alloc();
4121 if (windows != NULL)
4122 {
4123 FOR_ALL_TAB_WINDOWS(tp, wp)
4124 if (wp->w_buffer == buf)
4125 list_append_number(windows, (varnumber_T)wp->w_id);
4126 dict_add_list(dict, "windows", windows);
4127 }
4128
4129#ifdef FEAT_SIGNS
4130 if (buf->b_signlist != NULL)
4131 {
4132 /* List of signs placed in this buffer */
4133 list_T *signs = list_alloc();
4134 if (signs != NULL)
4135 {
4136 get_buffer_signs(buf, signs);
4137 dict_add_list(dict, "signs", signs);
4138 }
4139 }
4140#endif
4141
4142 return dict;
4143}
4144
4145/*
4146 * "getbufinfo()" function
4147 */
4148 static void
4149f_getbufinfo(typval_T *argvars, typval_T *rettv)
4150{
4151 buf_T *buf = NULL;
4152 buf_T *argbuf = NULL;
4153 dict_T *d;
4154 int filtered = FALSE;
4155 int sel_buflisted = FALSE;
4156 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004157 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004158
4159 if (rettv_list_alloc(rettv) != OK)
4160 return;
4161
4162 /* List of all the buffers or selected buffers */
4163 if (argvars[0].v_type == VAR_DICT)
4164 {
4165 dict_T *sel_d = argvars[0].vval.v_dict;
4166
4167 if (sel_d != NULL)
4168 {
4169 dictitem_T *di;
4170
4171 filtered = TRUE;
4172
4173 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4174 if (di != NULL && get_tv_number(&di->di_tv))
4175 sel_buflisted = TRUE;
4176
4177 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4178 if (di != NULL && get_tv_number(&di->di_tv))
4179 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004180
4181 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4182 if (di != NULL && get_tv_number(&di->di_tv))
4183 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004184 }
4185 }
4186 else if (argvars[0].v_type != VAR_UNKNOWN)
4187 {
4188 /* Information about one buffer. Argument specifies the buffer */
4189 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4190 ++emsg_off;
4191 argbuf = get_buf_tv(&argvars[0], FALSE);
4192 --emsg_off;
4193 if (argbuf == NULL)
4194 return;
4195 }
4196
4197 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004198 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004199 {
4200 if (argbuf != NULL && argbuf != buf)
4201 continue;
4202 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004203 || (sel_buflisted && !buf->b_p_bl)
4204 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004205 continue;
4206
4207 d = get_buffer_info(buf);
4208 if (d != NULL)
4209 list_append_dict(rettv->vval.v_list, d);
4210 if (argbuf != NULL)
4211 return;
4212 }
4213}
4214
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004215static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4216
4217/*
4218 * Get line or list of lines from buffer "buf" into "rettv".
4219 * Return a range (from start to end) of lines in rettv from the specified
4220 * buffer.
4221 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4222 */
4223 static void
4224get_buffer_lines(
4225 buf_T *buf,
4226 linenr_T start,
4227 linenr_T end,
4228 int retlist,
4229 typval_T *rettv)
4230{
4231 char_u *p;
4232
4233 rettv->v_type = VAR_STRING;
4234 rettv->vval.v_string = NULL;
4235 if (retlist && rettv_list_alloc(rettv) == FAIL)
4236 return;
4237
4238 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4239 return;
4240
4241 if (!retlist)
4242 {
4243 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4244 p = ml_get_buf(buf, start, FALSE);
4245 else
4246 p = (char_u *)"";
4247 rettv->vval.v_string = vim_strsave(p);
4248 }
4249 else
4250 {
4251 if (end < start)
4252 return;
4253
4254 if (start < 1)
4255 start = 1;
4256 if (end > buf->b_ml.ml_line_count)
4257 end = buf->b_ml.ml_line_count;
4258 while (start <= end)
4259 if (list_append_string(rettv->vval.v_list,
4260 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4261 break;
4262 }
4263}
4264
4265/*
4266 * Get the lnum from the first argument.
4267 * Also accepts "$", then "buf" is used.
4268 * Returns 0 on error.
4269 */
4270 static linenr_T
4271get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4272{
4273 if (argvars[0].v_type == VAR_STRING
4274 && argvars[0].vval.v_string != NULL
4275 && argvars[0].vval.v_string[0] == '$'
4276 && buf != NULL)
4277 return buf->b_ml.ml_line_count;
4278 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4279}
4280
4281/*
4282 * "getbufline()" function
4283 */
4284 static void
4285f_getbufline(typval_T *argvars, typval_T *rettv)
4286{
4287 linenr_T lnum;
4288 linenr_T end;
4289 buf_T *buf;
4290
4291 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4292 ++emsg_off;
4293 buf = get_buf_tv(&argvars[0], FALSE);
4294 --emsg_off;
4295
4296 lnum = get_tv_lnum_buf(&argvars[1], buf);
4297 if (argvars[2].v_type == VAR_UNKNOWN)
4298 end = lnum;
4299 else
4300 end = get_tv_lnum_buf(&argvars[2], buf);
4301
4302 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4303}
4304
4305/*
4306 * "getbufvar()" function
4307 */
4308 static void
4309f_getbufvar(typval_T *argvars, typval_T *rettv)
4310{
4311 buf_T *buf;
4312 buf_T *save_curbuf;
4313 char_u *varname;
4314 dictitem_T *v;
4315 int done = FALSE;
4316
4317 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4318 varname = get_tv_string_chk(&argvars[1]);
4319 ++emsg_off;
4320 buf = get_buf_tv(&argvars[0], FALSE);
4321
4322 rettv->v_type = VAR_STRING;
4323 rettv->vval.v_string = NULL;
4324
4325 if (buf != NULL && varname != NULL)
4326 {
4327 /* set curbuf to be our buf, temporarily */
4328 save_curbuf = curbuf;
4329 curbuf = buf;
4330
Bram Moolenaar30567352016-08-27 21:25:44 +02004331 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004332 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004333 if (varname[1] == NUL)
4334 {
4335 /* get all buffer-local options in a dict */
4336 dict_T *opts = get_winbuf_options(TRUE);
4337
4338 if (opts != NULL)
4339 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004340 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004341 done = TRUE;
4342 }
4343 }
4344 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4345 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004346 done = TRUE;
4347 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004348 else
4349 {
4350 /* Look up the variable. */
4351 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4352 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4353 'b', varname, FALSE);
4354 if (v != NULL)
4355 {
4356 copy_tv(&v->di_tv, rettv);
4357 done = TRUE;
4358 }
4359 }
4360
4361 /* restore previous notion of curbuf */
4362 curbuf = save_curbuf;
4363 }
4364
4365 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4366 /* use the default value */
4367 copy_tv(&argvars[2], rettv);
4368
4369 --emsg_off;
4370}
4371
4372/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004373 * "getchangelist()" function
4374 */
4375 static void
4376f_getchangelist(typval_T *argvars, typval_T *rettv)
4377{
4378#ifdef FEAT_JUMPLIST
4379 buf_T *buf;
4380 int i;
4381 list_T *l;
4382 dict_T *d;
4383#endif
4384
4385 if (rettv_list_alloc(rettv) != OK)
4386 return;
4387
4388#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004389 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4390 ++emsg_off;
4391 buf = get_buf_tv(&argvars[0], FALSE);
4392 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004393 if (buf == NULL)
4394 return;
4395
4396 l = list_alloc();
4397 if (l == NULL)
4398 return;
4399
4400 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4401 return;
4402 /*
4403 * The current window change list index tracks only the position in the
4404 * current buffer change list. For other buffers, use the change list
4405 * length as the current index.
4406 */
4407 list_append_number(rettv->vval.v_list,
4408 (varnumber_T)((buf == curwin->w_buffer)
4409 ? curwin->w_changelistidx : buf->b_changelistlen));
4410
4411 for (i = 0; i < buf->b_changelistlen; ++i)
4412 {
4413 if (buf->b_changelist[i].lnum == 0)
4414 continue;
4415 if ((d = dict_alloc()) == NULL)
4416 return;
4417 if (list_append_dict(l, d) == FAIL)
4418 return;
4419 dict_add_nr_str(d, "lnum", (long)buf->b_changelist[i].lnum, NULL);
4420 dict_add_nr_str(d, "col", (long)buf->b_changelist[i].col, NULL);
4421# ifdef FEAT_VIRTUALEDIT
4422 dict_add_nr_str(d, "coladd", (long)buf->b_changelist[i].coladd, NULL);
4423# endif
4424 }
4425#endif
4426}
4427/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004428 * "getchar()" function
4429 */
4430 static void
4431f_getchar(typval_T *argvars, typval_T *rettv)
4432{
4433 varnumber_T n;
4434 int error = FALSE;
4435
4436 /* Position the cursor. Needed after a message that ends in a space. */
4437 windgoto(msg_row, msg_col);
4438
4439 ++no_mapping;
4440 ++allow_keys;
4441 for (;;)
4442 {
4443 if (argvars[0].v_type == VAR_UNKNOWN)
4444 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004445 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004446 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4447 /* getchar(1): only check if char avail */
4448 n = vpeekc_any();
4449 else if (error || vpeekc_any() == NUL)
4450 /* illegal argument or getchar(0) and no char avail: return zero */
4451 n = 0;
4452 else
4453 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004454 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004455
4456 if (n == K_IGNORE)
4457 continue;
4458 break;
4459 }
4460 --no_mapping;
4461 --allow_keys;
4462
4463 set_vim_var_nr(VV_MOUSE_WIN, 0);
4464 set_vim_var_nr(VV_MOUSE_WINID, 0);
4465 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4466 set_vim_var_nr(VV_MOUSE_COL, 0);
4467
4468 rettv->vval.v_number = n;
4469 if (IS_SPECIAL(n) || mod_mask != 0)
4470 {
4471 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4472 int i = 0;
4473
4474 /* Turn a special key into three bytes, plus modifier. */
4475 if (mod_mask != 0)
4476 {
4477 temp[i++] = K_SPECIAL;
4478 temp[i++] = KS_MODIFIER;
4479 temp[i++] = mod_mask;
4480 }
4481 if (IS_SPECIAL(n))
4482 {
4483 temp[i++] = K_SPECIAL;
4484 temp[i++] = K_SECOND(n);
4485 temp[i++] = K_THIRD(n);
4486 }
4487#ifdef FEAT_MBYTE
4488 else if (has_mbyte)
4489 i += (*mb_char2bytes)(n, temp + i);
4490#endif
4491 else
4492 temp[i++] = n;
4493 temp[i++] = NUL;
4494 rettv->v_type = VAR_STRING;
4495 rettv->vval.v_string = vim_strsave(temp);
4496
4497#ifdef FEAT_MOUSE
4498 if (is_mouse_key(n))
4499 {
4500 int row = mouse_row;
4501 int col = mouse_col;
4502 win_T *win;
4503 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004504 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004505 int winnr = 1;
4506
4507 if (row >= 0 && col >= 0)
4508 {
4509 /* Find the window at the mouse coordinates and compute the
4510 * text position. */
4511 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004512 if (win == NULL)
4513 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004514 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004515 for (wp = firstwin; wp != win; wp = wp->w_next)
4516 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4518 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4519 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4520 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4521 }
4522 }
4523#endif
4524 }
4525}
4526
4527/*
4528 * "getcharmod()" function
4529 */
4530 static void
4531f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4532{
4533 rettv->vval.v_number = mod_mask;
4534}
4535
4536/*
4537 * "getcharsearch()" function
4538 */
4539 static void
4540f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4541{
4542 if (rettv_dict_alloc(rettv) != FAIL)
4543 {
4544 dict_T *dict = rettv->vval.v_dict;
4545
4546 dict_add_nr_str(dict, "char", 0L, last_csearch());
4547 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4548 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4549 }
4550}
4551
4552/*
4553 * "getcmdline()" function
4554 */
4555 static void
4556f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4557{
4558 rettv->v_type = VAR_STRING;
4559 rettv->vval.v_string = get_cmdline_str();
4560}
4561
4562/*
4563 * "getcmdpos()" function
4564 */
4565 static void
4566f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4567{
4568 rettv->vval.v_number = get_cmdline_pos() + 1;
4569}
4570
4571/*
4572 * "getcmdtype()" function
4573 */
4574 static void
4575f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4576{
4577 rettv->v_type = VAR_STRING;
4578 rettv->vval.v_string = alloc(2);
4579 if (rettv->vval.v_string != NULL)
4580 {
4581 rettv->vval.v_string[0] = get_cmdline_type();
4582 rettv->vval.v_string[1] = NUL;
4583 }
4584}
4585
4586/*
4587 * "getcmdwintype()" function
4588 */
4589 static void
4590f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4591{
4592 rettv->v_type = VAR_STRING;
4593 rettv->vval.v_string = NULL;
4594#ifdef FEAT_CMDWIN
4595 rettv->vval.v_string = alloc(2);
4596 if (rettv->vval.v_string != NULL)
4597 {
4598 rettv->vval.v_string[0] = cmdwin_type;
4599 rettv->vval.v_string[1] = NUL;
4600 }
4601#endif
4602}
4603
4604#if defined(FEAT_CMDL_COMPL)
4605/*
4606 * "getcompletion()" function
4607 */
4608 static void
4609f_getcompletion(typval_T *argvars, typval_T *rettv)
4610{
4611 char_u *pat;
4612 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004613 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004614 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4615 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004616
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004617 if (argvars[2].v_type != VAR_UNKNOWN)
4618 filtered = get_tv_number_chk(&argvars[2], NULL);
4619
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004620 if (p_wic)
4621 options |= WILD_ICASE;
4622
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004623 /* For filtered results, 'wildignore' is used */
4624 if (!filtered)
4625 options |= WILD_KEEP_ALL;
4626
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004627 ExpandInit(&xpc);
4628 xpc.xp_pattern = get_tv_string(&argvars[0]);
4629 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4630 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4631 if (xpc.xp_context == EXPAND_NOTHING)
4632 {
4633 if (argvars[1].v_type == VAR_STRING)
4634 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4635 else
4636 EMSG(_(e_invarg));
4637 return;
4638 }
4639
4640# if defined(FEAT_MENU)
4641 if (xpc.xp_context == EXPAND_MENUS)
4642 {
4643 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4644 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4645 }
4646# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004647#ifdef FEAT_CSCOPE
4648 if (xpc.xp_context == EXPAND_CSCOPE)
4649 {
4650 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4651 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4652 }
4653#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004654#ifdef FEAT_SIGNS
4655 if (xpc.xp_context == EXPAND_SIGN)
4656 {
4657 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4658 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4659 }
4660#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661
4662 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4663 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4664 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004665 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004666
4667 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4668
4669 for (i = 0; i < xpc.xp_numfiles; i++)
4670 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4671 }
4672 vim_free(pat);
4673 ExpandCleanup(&xpc);
4674}
4675#endif
4676
4677/*
4678 * "getcwd()" function
4679 */
4680 static void
4681f_getcwd(typval_T *argvars, typval_T *rettv)
4682{
4683 win_T *wp = NULL;
4684 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004685 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686
4687 rettv->v_type = VAR_STRING;
4688 rettv->vval.v_string = NULL;
4689
Bram Moolenaar54591292018-02-09 20:53:59 +01004690 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4691 global = TRUE;
4692 else
4693 wp = find_tabwin(&argvars[0], &argvars[1]);
4694
4695 if (wp != NULL && wp->w_localdir != NULL)
4696 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4697 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004698 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004699 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 rettv->vval.v_string = vim_strsave(globaldir);
4701 else
4702 {
4703 cwd = alloc(MAXPATHL);
4704 if (cwd != NULL)
4705 {
4706 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4707 rettv->vval.v_string = vim_strsave(cwd);
4708 vim_free(cwd);
4709 }
4710 }
4711#ifdef BACKSLASH_IN_FILENAME
4712 if (rettv->vval.v_string != NULL)
4713 slash_adjust(rettv->vval.v_string);
4714#endif
4715 }
4716}
4717
4718/*
4719 * "getfontname()" function
4720 */
4721 static void
4722f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4723{
4724 rettv->v_type = VAR_STRING;
4725 rettv->vval.v_string = NULL;
4726#ifdef FEAT_GUI
4727 if (gui.in_use)
4728 {
4729 GuiFont font;
4730 char_u *name = NULL;
4731
4732 if (argvars[0].v_type == VAR_UNKNOWN)
4733 {
4734 /* Get the "Normal" font. Either the name saved by
4735 * hl_set_font_name() or from the font ID. */
4736 font = gui.norm_font;
4737 name = hl_get_font_name();
4738 }
4739 else
4740 {
4741 name = get_tv_string(&argvars[0]);
4742 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4743 return;
4744 font = gui_mch_get_font(name, FALSE);
4745 if (font == NOFONT)
4746 return; /* Invalid font name, return empty string. */
4747 }
4748 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4749 if (argvars[0].v_type != VAR_UNKNOWN)
4750 gui_mch_free_font(font);
4751 }
4752#endif
4753}
4754
4755/*
4756 * "getfperm({fname})" function
4757 */
4758 static void
4759f_getfperm(typval_T *argvars, typval_T *rettv)
4760{
4761 char_u *fname;
4762 stat_T st;
4763 char_u *perm = NULL;
4764 char_u flags[] = "rwx";
4765 int i;
4766
4767 fname = get_tv_string(&argvars[0]);
4768
4769 rettv->v_type = VAR_STRING;
4770 if (mch_stat((char *)fname, &st) >= 0)
4771 {
4772 perm = vim_strsave((char_u *)"---------");
4773 if (perm != NULL)
4774 {
4775 for (i = 0; i < 9; i++)
4776 {
4777 if (st.st_mode & (1 << (8 - i)))
4778 perm[i] = flags[i % 3];
4779 }
4780 }
4781 }
4782 rettv->vval.v_string = perm;
4783}
4784
4785/*
4786 * "getfsize({fname})" function
4787 */
4788 static void
4789f_getfsize(typval_T *argvars, typval_T *rettv)
4790{
4791 char_u *fname;
4792 stat_T st;
4793
4794 fname = get_tv_string(&argvars[0]);
4795
4796 rettv->v_type = VAR_NUMBER;
4797
4798 if (mch_stat((char *)fname, &st) >= 0)
4799 {
4800 if (mch_isdir(fname))
4801 rettv->vval.v_number = 0;
4802 else
4803 {
4804 rettv->vval.v_number = (varnumber_T)st.st_size;
4805
4806 /* non-perfect check for overflow */
4807 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4808 rettv->vval.v_number = -2;
4809 }
4810 }
4811 else
4812 rettv->vval.v_number = -1;
4813}
4814
4815/*
4816 * "getftime({fname})" function
4817 */
4818 static void
4819f_getftime(typval_T *argvars, typval_T *rettv)
4820{
4821 char_u *fname;
4822 stat_T st;
4823
4824 fname = get_tv_string(&argvars[0]);
4825
4826 if (mch_stat((char *)fname, &st) >= 0)
4827 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4828 else
4829 rettv->vval.v_number = -1;
4830}
4831
4832/*
4833 * "getftype({fname})" function
4834 */
4835 static void
4836f_getftype(typval_T *argvars, typval_T *rettv)
4837{
4838 char_u *fname;
4839 stat_T st;
4840 char_u *type = NULL;
4841 char *t;
4842
4843 fname = get_tv_string(&argvars[0]);
4844
4845 rettv->v_type = VAR_STRING;
4846 if (mch_lstat((char *)fname, &st) >= 0)
4847 {
4848#ifdef S_ISREG
4849 if (S_ISREG(st.st_mode))
4850 t = "file";
4851 else if (S_ISDIR(st.st_mode))
4852 t = "dir";
4853# ifdef S_ISLNK
4854 else if (S_ISLNK(st.st_mode))
4855 t = "link";
4856# endif
4857# ifdef S_ISBLK
4858 else if (S_ISBLK(st.st_mode))
4859 t = "bdev";
4860# endif
4861# ifdef S_ISCHR
4862 else if (S_ISCHR(st.st_mode))
4863 t = "cdev";
4864# endif
4865# ifdef S_ISFIFO
4866 else if (S_ISFIFO(st.st_mode))
4867 t = "fifo";
4868# endif
4869# ifdef S_ISSOCK
4870 else if (S_ISSOCK(st.st_mode))
4871 t = "fifo";
4872# endif
4873 else
4874 t = "other";
4875#else
4876# ifdef S_IFMT
4877 switch (st.st_mode & S_IFMT)
4878 {
4879 case S_IFREG: t = "file"; break;
4880 case S_IFDIR: t = "dir"; break;
4881# ifdef S_IFLNK
4882 case S_IFLNK: t = "link"; break;
4883# endif
4884# ifdef S_IFBLK
4885 case S_IFBLK: t = "bdev"; break;
4886# endif
4887# ifdef S_IFCHR
4888 case S_IFCHR: t = "cdev"; break;
4889# endif
4890# ifdef S_IFIFO
4891 case S_IFIFO: t = "fifo"; break;
4892# endif
4893# ifdef S_IFSOCK
4894 case S_IFSOCK: t = "socket"; break;
4895# endif
4896 default: t = "other";
4897 }
4898# else
4899 if (mch_isdir(fname))
4900 t = "dir";
4901 else
4902 t = "file";
4903# endif
4904#endif
4905 type = vim_strsave((char_u *)t);
4906 }
4907 rettv->vval.v_string = type;
4908}
4909
4910/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004911 * "getjumplist()" function
4912 */
4913 static void
4914f_getjumplist(typval_T *argvars, typval_T *rettv)
4915{
4916#ifdef FEAT_JUMPLIST
4917 win_T *wp;
4918 int i;
4919 list_T *l;
4920 dict_T *d;
4921#endif
4922
4923 if (rettv_list_alloc(rettv) != OK)
4924 return;
4925
4926#ifdef FEAT_JUMPLIST
4927 wp = find_tabwin(&argvars[0], &argvars[1]);
4928 if (wp == NULL)
4929 return;
4930
4931 l = list_alloc();
4932 if (l == NULL)
4933 return;
4934
4935 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4936 return;
4937 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4938
Bram Moolenaar48679742018-02-13 13:33:29 +01004939 cleanup_jumplist(wp, TRUE);
4940
Bram Moolenaar4f505882018-02-10 21:06:32 +01004941 for (i = 0; i < wp->w_jumplistlen; ++i)
4942 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004943 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4944 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004945 if ((d = dict_alloc()) == NULL)
4946 return;
4947 if (list_append_dict(l, d) == FAIL)
4948 return;
4949 dict_add_nr_str(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum,
4950 NULL);
4951 dict_add_nr_str(d, "col", (long)wp->w_jumplist[i].fmark.mark.col,
4952 NULL);
4953# ifdef FEAT_VIRTUALEDIT
4954 dict_add_nr_str(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd,
4955 NULL);
4956# endif
4957 dict_add_nr_str(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum, NULL);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004958 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaar4f505882018-02-10 21:06:32 +01004959 dict_add_nr_str(d, "filename", 0L, wp->w_jumplist[i].fname);
4960 }
4961#endif
4962}
4963
4964/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965 * "getline(lnum, [end])" function
4966 */
4967 static void
4968f_getline(typval_T *argvars, typval_T *rettv)
4969{
4970 linenr_T lnum;
4971 linenr_T end;
4972 int retlist;
4973
4974 lnum = get_tv_lnum(argvars);
4975 if (argvars[1].v_type == VAR_UNKNOWN)
4976 {
4977 end = 0;
4978 retlist = FALSE;
4979 }
4980 else
4981 {
4982 end = get_tv_lnum(&argvars[1]);
4983 retlist = TRUE;
4984 }
4985
4986 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4987}
4988
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004989#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004990 static void
4991get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4992{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004993 if (what_arg->v_type == VAR_UNKNOWN)
4994 {
4995 if (rettv_list_alloc(rettv) == OK)
4996 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004997 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004998 }
4999 else
5000 {
5001 if (rettv_dict_alloc(rettv) == OK)
5002 if (is_qf || (wp != NULL))
5003 {
5004 if (what_arg->v_type == VAR_DICT)
5005 {
5006 dict_T *d = what_arg->vval.v_dict;
5007
5008 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005009 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005010 }
5011 else
5012 EMSG(_(e_dictreq));
5013 }
5014 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005015}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005016#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005017
5018/*
5019 * "getloclist()" function
5020 */
5021 static void
5022f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5023{
5024#ifdef FEAT_QUICKFIX
5025 win_T *wp;
5026
5027 wp = find_win_by_nr(&argvars[0], NULL);
5028 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5029#endif
5030}
5031
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005032/*
5033 * "getmatches()" function
5034 */
5035 static void
5036f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5037{
5038#ifdef FEAT_SEARCH_EXTRA
5039 dict_T *dict;
5040 matchitem_T *cur = curwin->w_match_head;
5041 int i;
5042
5043 if (rettv_list_alloc(rettv) == OK)
5044 {
5045 while (cur != NULL)
5046 {
5047 dict = dict_alloc();
5048 if (dict == NULL)
5049 return;
5050 if (cur->match.regprog == NULL)
5051 {
5052 /* match added with matchaddpos() */
5053 for (i = 0; i < MAXPOSMATCH; ++i)
5054 {
5055 llpos_T *llpos;
5056 char buf[6];
5057 list_T *l;
5058
5059 llpos = &cur->pos.pos[i];
5060 if (llpos->lnum == 0)
5061 break;
5062 l = list_alloc();
5063 if (l == NULL)
5064 break;
5065 list_append_number(l, (varnumber_T)llpos->lnum);
5066 if (llpos->col > 0)
5067 {
5068 list_append_number(l, (varnumber_T)llpos->col);
5069 list_append_number(l, (varnumber_T)llpos->len);
5070 }
5071 sprintf(buf, "pos%d", i + 1);
5072 dict_add_list(dict, buf, l);
5073 }
5074 }
5075 else
5076 {
5077 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
5078 }
5079 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
5080 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
5081 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
5082# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5083 if (cur->conceal_char)
5084 {
5085 char_u buf[MB_MAXBYTES + 1];
5086
5087 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5088 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
5089 }
5090# endif
5091 list_append_dict(rettv->vval.v_list, dict);
5092 cur = cur->next;
5093 }
5094 }
5095#endif
5096}
5097
5098/*
5099 * "getpid()" function
5100 */
5101 static void
5102f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5103{
5104 rettv->vval.v_number = mch_get_pid();
5105}
5106
5107 static void
5108getpos_both(
5109 typval_T *argvars,
5110 typval_T *rettv,
5111 int getcurpos)
5112{
5113 pos_T *fp;
5114 list_T *l;
5115 int fnum = -1;
5116
5117 if (rettv_list_alloc(rettv) == OK)
5118 {
5119 l = rettv->vval.v_list;
5120 if (getcurpos)
5121 fp = &curwin->w_cursor;
5122 else
5123 fp = var2fpos(&argvars[0], TRUE, &fnum);
5124 if (fnum != -1)
5125 list_append_number(l, (varnumber_T)fnum);
5126 else
5127 list_append_number(l, (varnumber_T)0);
5128 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5129 : (varnumber_T)0);
5130 list_append_number(l, (fp != NULL)
5131 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5132 : (varnumber_T)0);
5133 list_append_number(l,
5134#ifdef FEAT_VIRTUALEDIT
5135 (fp != NULL) ? (varnumber_T)fp->coladd :
5136#endif
5137 (varnumber_T)0);
5138 if (getcurpos)
5139 {
5140 update_curswant();
5141 list_append_number(l, curwin->w_curswant == MAXCOL ?
5142 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5143 }
5144 }
5145 else
5146 rettv->vval.v_number = FALSE;
5147}
5148
5149
5150/*
5151 * "getcurpos()" function
5152 */
5153 static void
5154f_getcurpos(typval_T *argvars, typval_T *rettv)
5155{
5156 getpos_both(argvars, rettv, TRUE);
5157}
5158
5159/*
5160 * "getpos(string)" function
5161 */
5162 static void
5163f_getpos(typval_T *argvars, typval_T *rettv)
5164{
5165 getpos_both(argvars, rettv, FALSE);
5166}
5167
5168/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005169 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005170 */
5171 static void
5172f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5173{
5174#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005175 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005176#endif
5177}
5178
5179/*
5180 * "getreg()" function
5181 */
5182 static void
5183f_getreg(typval_T *argvars, typval_T *rettv)
5184{
5185 char_u *strregname;
5186 int regname;
5187 int arg2 = FALSE;
5188 int return_list = FALSE;
5189 int error = FALSE;
5190
5191 if (argvars[0].v_type != VAR_UNKNOWN)
5192 {
5193 strregname = get_tv_string_chk(&argvars[0]);
5194 error = strregname == NULL;
5195 if (argvars[1].v_type != VAR_UNKNOWN)
5196 {
5197 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5198 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5199 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5200 }
5201 }
5202 else
5203 strregname = get_vim_var_str(VV_REG);
5204
5205 if (error)
5206 return;
5207
5208 regname = (strregname == NULL ? '"' : *strregname);
5209 if (regname == 0)
5210 regname = '"';
5211
5212 if (return_list)
5213 {
5214 rettv->v_type = VAR_LIST;
5215 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5216 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5217 if (rettv->vval.v_list == NULL)
5218 (void)rettv_list_alloc(rettv);
5219 else
5220 ++rettv->vval.v_list->lv_refcount;
5221 }
5222 else
5223 {
5224 rettv->v_type = VAR_STRING;
5225 rettv->vval.v_string = get_reg_contents(regname,
5226 arg2 ? GREG_EXPR_SRC : 0);
5227 }
5228}
5229
5230/*
5231 * "getregtype()" function
5232 */
5233 static void
5234f_getregtype(typval_T *argvars, typval_T *rettv)
5235{
5236 char_u *strregname;
5237 int regname;
5238 char_u buf[NUMBUFLEN + 2];
5239 long reglen = 0;
5240
5241 if (argvars[0].v_type != VAR_UNKNOWN)
5242 {
5243 strregname = get_tv_string_chk(&argvars[0]);
5244 if (strregname == NULL) /* type error; errmsg already given */
5245 {
5246 rettv->v_type = VAR_STRING;
5247 rettv->vval.v_string = NULL;
5248 return;
5249 }
5250 }
5251 else
5252 /* Default to v:register */
5253 strregname = get_vim_var_str(VV_REG);
5254
5255 regname = (strregname == NULL ? '"' : *strregname);
5256 if (regname == 0)
5257 regname = '"';
5258
5259 buf[0] = NUL;
5260 buf[1] = NUL;
5261 switch (get_reg_type(regname, &reglen))
5262 {
5263 case MLINE: buf[0] = 'V'; break;
5264 case MCHAR: buf[0] = 'v'; break;
5265 case MBLOCK:
5266 buf[0] = Ctrl_V;
5267 sprintf((char *)buf + 1, "%ld", reglen + 1);
5268 break;
5269 }
5270 rettv->v_type = VAR_STRING;
5271 rettv->vval.v_string = vim_strsave(buf);
5272}
5273
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005274/*
5275 * Returns information (variables, options, etc.) about a tab page
5276 * as a dictionary.
5277 */
5278 static dict_T *
5279get_tabpage_info(tabpage_T *tp, int tp_idx)
5280{
5281 win_T *wp;
5282 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005283 list_T *l;
5284
5285 dict = dict_alloc();
5286 if (dict == NULL)
5287 return NULL;
5288
Bram Moolenaar33928832016-08-18 21:22:04 +02005289 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005290
5291 l = list_alloc();
5292 if (l != NULL)
5293 {
5294 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5295 wp; wp = wp->w_next)
5296 list_append_number(l, (varnumber_T)wp->w_id);
5297 dict_add_list(dict, "windows", l);
5298 }
5299
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005300 /* Make a reference to tabpage variables */
5301 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005302
5303 return dict;
5304}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005305
5306/*
5307 * "gettabinfo()" function
5308 */
5309 static void
5310f_gettabinfo(typval_T *argvars, typval_T *rettv)
5311{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005312 tabpage_T *tp, *tparg = NULL;
5313 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005314 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005315
5316 if (rettv_list_alloc(rettv) != OK)
5317 return;
5318
5319 if (argvars[0].v_type != VAR_UNKNOWN)
5320 {
5321 /* Information about one tab page */
5322 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5323 if (tparg == NULL)
5324 return;
5325 }
5326
5327 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005328 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005329 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005330 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005331 if (tparg != NULL && tp != tparg)
5332 continue;
5333 d = get_tabpage_info(tp, tpnr);
5334 if (d != NULL)
5335 list_append_dict(rettv->vval.v_list, d);
5336 if (tparg != NULL)
5337 return;
5338 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005339}
5340
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005341/*
5342 * "gettabvar()" function
5343 */
5344 static void
5345f_gettabvar(typval_T *argvars, typval_T *rettv)
5346{
5347 win_T *oldcurwin;
5348 tabpage_T *tp, *oldtabpage;
5349 dictitem_T *v;
5350 char_u *varname;
5351 int done = FALSE;
5352
5353 rettv->v_type = VAR_STRING;
5354 rettv->vval.v_string = NULL;
5355
5356 varname = get_tv_string_chk(&argvars[1]);
5357 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5358 if (tp != NULL && varname != NULL)
5359 {
5360 /* Set tp to be our tabpage, temporarily. Also set the window to the
5361 * first window in the tabpage, otherwise the window is not valid. */
5362 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005363 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5364 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005365 {
5366 /* look up the variable */
5367 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5368 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5369 if (v != NULL)
5370 {
5371 copy_tv(&v->di_tv, rettv);
5372 done = TRUE;
5373 }
5374 }
5375
5376 /* restore previous notion of curwin */
5377 restore_win(oldcurwin, oldtabpage, TRUE);
5378 }
5379
5380 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5381 copy_tv(&argvars[2], rettv);
5382}
5383
5384/*
5385 * "gettabwinvar()" function
5386 */
5387 static void
5388f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5389{
5390 getwinvar(argvars, rettv, 1);
5391}
5392
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005393/*
5394 * Returns information about a window as a dictionary.
5395 */
5396 static dict_T *
5397get_win_info(win_T *wp, short tpnr, short winnr)
5398{
5399 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005400
5401 dict = dict_alloc();
5402 if (dict == NULL)
5403 return NULL;
5404
Bram Moolenaar33928832016-08-18 21:22:04 +02005405 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5406 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005407 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5408 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005409#ifdef FEAT_MENU
5410 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5411#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005412 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005413 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005414
Bram Moolenaar69905d12017-08-13 18:14:47 +02005415#ifdef FEAT_TERMINAL
5416 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5417#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005418#ifdef FEAT_QUICKFIX
5419 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5420 dict_add_nr_str(dict, "loclist",
5421 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5422#endif
5423
Bram Moolenaar30567352016-08-27 21:25:44 +02005424 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005425 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005426
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005427 return dict;
5428}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005429
5430/*
5431 * "getwininfo()" function
5432 */
5433 static void
5434f_getwininfo(typval_T *argvars, typval_T *rettv)
5435{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005436 tabpage_T *tp;
5437 win_T *wp = NULL, *wparg = NULL;
5438 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005439 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005440
5441 if (rettv_list_alloc(rettv) != OK)
5442 return;
5443
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005444 if (argvars[0].v_type != VAR_UNKNOWN)
5445 {
5446 wparg = win_id2wp(argvars);
5447 if (wparg == NULL)
5448 return;
5449 }
5450
5451 /* Collect information about either all the windows across all the tab
5452 * pages or one particular window.
5453 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005454 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005455 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005456 tabnr++;
5457 winnr = 0;
5458 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005459 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005460 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005461 if (wparg != NULL && wp != wparg)
5462 continue;
5463 d = get_win_info(wp, tabnr, winnr);
5464 if (d != NULL)
5465 list_append_dict(rettv->vval.v_list, d);
5466 if (wparg != NULL)
5467 /* found information about a specific window */
5468 return;
5469 }
5470 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005471}
5472
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005474 * "win_findbuf()" function
5475 */
5476 static void
5477f_win_findbuf(typval_T *argvars, typval_T *rettv)
5478{
5479 if (rettv_list_alloc(rettv) != FAIL)
5480 win_findbuf(argvars, rettv->vval.v_list);
5481}
5482
5483/*
5484 * "win_getid()" function
5485 */
5486 static void
5487f_win_getid(typval_T *argvars, typval_T *rettv)
5488{
5489 rettv->vval.v_number = win_getid(argvars);
5490}
5491
5492/*
5493 * "win_gotoid()" function
5494 */
5495 static void
5496f_win_gotoid(typval_T *argvars, typval_T *rettv)
5497{
5498 rettv->vval.v_number = win_gotoid(argvars);
5499}
5500
5501/*
5502 * "win_id2tabwin()" function
5503 */
5504 static void
5505f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5506{
5507 if (rettv_list_alloc(rettv) != FAIL)
5508 win_id2tabwin(argvars, rettv->vval.v_list);
5509}
5510
5511/*
5512 * "win_id2win()" function
5513 */
5514 static void
5515f_win_id2win(typval_T *argvars, typval_T *rettv)
5516{
5517 rettv->vval.v_number = win_id2win(argvars);
5518}
5519
5520/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005521 * "win_screenpos()" function
5522 */
5523 static void
5524f_win_screenpos(typval_T *argvars, typval_T *rettv)
5525{
5526 win_T *wp;
5527
5528 if (rettv_list_alloc(rettv) == FAIL)
5529 return;
5530
5531 wp = find_win_by_nr(&argvars[0], NULL);
5532 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5533 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5534}
5535
5536/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005537 * "getwinpos({timeout})" function
5538 */
5539 static void
5540f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5541{
5542 int x = -1;
5543 int y = -1;
5544
5545 if (rettv_list_alloc(rettv) == FAIL)
5546 return;
5547#ifdef FEAT_GUI
5548 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005549 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005550# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5551 else
5552# endif
5553#endif
5554#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5555 {
5556 varnumber_T timeout = 100;
5557
5558 if (argvars[0].v_type != VAR_UNKNOWN)
5559 timeout = get_tv_number(&argvars[0]);
5560 term_get_winpos(&x, &y, timeout);
5561 }
5562#endif
5563 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5564 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5565}
5566
5567
5568/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005569 * "getwinposx()" function
5570 */
5571 static void
5572f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5573{
5574 rettv->vval.v_number = -1;
5575#ifdef FEAT_GUI
5576 if (gui.in_use)
5577 {
5578 int x, y;
5579
5580 if (gui_mch_get_winpos(&x, &y) == OK)
5581 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005582 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005583 }
5584#endif
5585#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5586 {
5587 int x, y;
5588
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005589 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005590 rettv->vval.v_number = x;
5591 }
5592#endif
5593}
5594
5595/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596 * "getwinposy()" function
5597 */
5598 static void
5599f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5600{
5601 rettv->vval.v_number = -1;
5602#ifdef FEAT_GUI
5603 if (gui.in_use)
5604 {
5605 int x, y;
5606
5607 if (gui_mch_get_winpos(&x, &y) == OK)
5608 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005609 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005610 }
5611#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005612#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5613 {
5614 int x, y;
5615
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005616 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005617 rettv->vval.v_number = y;
5618 }
5619#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005620}
5621
5622/*
5623 * "getwinvar()" function
5624 */
5625 static void
5626f_getwinvar(typval_T *argvars, typval_T *rettv)
5627{
5628 getwinvar(argvars, rettv, 0);
5629}
5630
5631/*
5632 * "glob()" function
5633 */
5634 static void
5635f_glob(typval_T *argvars, typval_T *rettv)
5636{
5637 int options = WILD_SILENT|WILD_USE_NL;
5638 expand_T xpc;
5639 int error = FALSE;
5640
5641 /* When the optional second argument is non-zero, don't remove matches
5642 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5643 rettv->v_type = VAR_STRING;
5644 if (argvars[1].v_type != VAR_UNKNOWN)
5645 {
5646 if (get_tv_number_chk(&argvars[1], &error))
5647 options |= WILD_KEEP_ALL;
5648 if (argvars[2].v_type != VAR_UNKNOWN)
5649 {
5650 if (get_tv_number_chk(&argvars[2], &error))
5651 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005652 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005653 }
5654 if (argvars[3].v_type != VAR_UNKNOWN
5655 && get_tv_number_chk(&argvars[3], &error))
5656 options |= WILD_ALLLINKS;
5657 }
5658 }
5659 if (!error)
5660 {
5661 ExpandInit(&xpc);
5662 xpc.xp_context = EXPAND_FILES;
5663 if (p_wic)
5664 options += WILD_ICASE;
5665 if (rettv->v_type == VAR_STRING)
5666 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5667 NULL, options, WILD_ALL);
5668 else if (rettv_list_alloc(rettv) != FAIL)
5669 {
5670 int i;
5671
5672 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5673 NULL, options, WILD_ALL_KEEP);
5674 for (i = 0; i < xpc.xp_numfiles; i++)
5675 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5676
5677 ExpandCleanup(&xpc);
5678 }
5679 }
5680 else
5681 rettv->vval.v_string = NULL;
5682}
5683
5684/*
5685 * "globpath()" function
5686 */
5687 static void
5688f_globpath(typval_T *argvars, typval_T *rettv)
5689{
5690 int flags = 0;
5691 char_u buf1[NUMBUFLEN];
5692 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5693 int error = FALSE;
5694 garray_T ga;
5695 int i;
5696
5697 /* When the optional second argument is non-zero, don't remove matches
5698 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5699 rettv->v_type = VAR_STRING;
5700 if (argvars[2].v_type != VAR_UNKNOWN)
5701 {
5702 if (get_tv_number_chk(&argvars[2], &error))
5703 flags |= WILD_KEEP_ALL;
5704 if (argvars[3].v_type != VAR_UNKNOWN)
5705 {
5706 if (get_tv_number_chk(&argvars[3], &error))
5707 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005708 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005709 }
5710 if (argvars[4].v_type != VAR_UNKNOWN
5711 && get_tv_number_chk(&argvars[4], &error))
5712 flags |= WILD_ALLLINKS;
5713 }
5714 }
5715 if (file != NULL && !error)
5716 {
5717 ga_init2(&ga, (int)sizeof(char_u *), 10);
5718 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5719 if (rettv->v_type == VAR_STRING)
5720 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5721 else if (rettv_list_alloc(rettv) != FAIL)
5722 for (i = 0; i < ga.ga_len; ++i)
5723 list_append_string(rettv->vval.v_list,
5724 ((char_u **)(ga.ga_data))[i], -1);
5725 ga_clear_strings(&ga);
5726 }
5727 else
5728 rettv->vval.v_string = NULL;
5729}
5730
5731/*
5732 * "glob2regpat()" function
5733 */
5734 static void
5735f_glob2regpat(typval_T *argvars, typval_T *rettv)
5736{
5737 char_u *pat = get_tv_string_chk(&argvars[0]);
5738
5739 rettv->v_type = VAR_STRING;
5740 rettv->vval.v_string = (pat == NULL)
5741 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5742}
5743
5744/* for VIM_VERSION_ defines */
5745#include "version.h"
5746
5747/*
5748 * "has()" function
5749 */
5750 static void
5751f_has(typval_T *argvars, typval_T *rettv)
5752{
5753 int i;
5754 char_u *name;
5755 int n = FALSE;
5756 static char *(has_list[]) =
5757 {
5758#ifdef AMIGA
5759 "amiga",
5760# ifdef FEAT_ARP
5761 "arp",
5762# endif
5763#endif
5764#ifdef __BEOS__
5765 "beos",
5766#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005767#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005768 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5769 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005770# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005771 "macunix", /* Mac OS X, with the darwin feature */
5772 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005773# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005774#endif
5775#ifdef __QNX__
5776 "qnx",
5777#endif
5778#ifdef UNIX
5779 "unix",
5780#endif
5781#ifdef VMS
5782 "vms",
5783#endif
5784#ifdef WIN32
5785 "win32",
5786#endif
5787#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5788 "win32unix",
5789#endif
5790#if defined(WIN64) || defined(_WIN64)
5791 "win64",
5792#endif
5793#ifdef EBCDIC
5794 "ebcdic",
5795#endif
5796#ifndef CASE_INSENSITIVE_FILENAME
5797 "fname_case",
5798#endif
5799#ifdef HAVE_ACL
5800 "acl",
5801#endif
5802#ifdef FEAT_ARABIC
5803 "arabic",
5804#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005805 "autocmd",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005806#ifdef FEAT_AUTOSERVERNAME
5807 "autoservername",
5808#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005809#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005810 "balloon_eval",
5811# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5812 "balloon_multiline",
5813# endif
5814#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005815#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005816 "balloon_eval_term",
5817#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005818#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5819 "builtin_terms",
5820# ifdef ALL_BUILTIN_TCAPS
5821 "all_builtin_terms",
5822# endif
5823#endif
5824#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5825 || defined(FEAT_GUI_W32) \
5826 || defined(FEAT_GUI_MOTIF))
5827 "browsefilter",
5828#endif
5829#ifdef FEAT_BYTEOFF
5830 "byte_offset",
5831#endif
5832#ifdef FEAT_JOB_CHANNEL
5833 "channel",
5834#endif
5835#ifdef FEAT_CINDENT
5836 "cindent",
5837#endif
5838#ifdef FEAT_CLIENTSERVER
5839 "clientserver",
5840#endif
5841#ifdef FEAT_CLIPBOARD
5842 "clipboard",
5843#endif
5844#ifdef FEAT_CMDL_COMPL
5845 "cmdline_compl",
5846#endif
5847#ifdef FEAT_CMDHIST
5848 "cmdline_hist",
5849#endif
5850#ifdef FEAT_COMMENTS
5851 "comments",
5852#endif
5853#ifdef FEAT_CONCEAL
5854 "conceal",
5855#endif
5856#ifdef FEAT_CRYPT
5857 "cryptv",
5858 "crypt-blowfish",
5859 "crypt-blowfish2",
5860#endif
5861#ifdef FEAT_CSCOPE
5862 "cscope",
5863#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005864 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005865#ifdef CURSOR_SHAPE
5866 "cursorshape",
5867#endif
5868#ifdef DEBUG
5869 "debug",
5870#endif
5871#ifdef FEAT_CON_DIALOG
5872 "dialog_con",
5873#endif
5874#ifdef FEAT_GUI_DIALOG
5875 "dialog_gui",
5876#endif
5877#ifdef FEAT_DIFF
5878 "diff",
5879#endif
5880#ifdef FEAT_DIGRAPHS
5881 "digraphs",
5882#endif
5883#ifdef FEAT_DIRECTX
5884 "directx",
5885#endif
5886#ifdef FEAT_DND
5887 "dnd",
5888#endif
5889#ifdef FEAT_EMACS_TAGS
5890 "emacs_tags",
5891#endif
5892 "eval", /* always present, of course! */
5893 "ex_extra", /* graduated feature */
5894#ifdef FEAT_SEARCH_EXTRA
5895 "extra_search",
5896#endif
5897#ifdef FEAT_FKMAP
5898 "farsi",
5899#endif
5900#ifdef FEAT_SEARCHPATH
5901 "file_in_path",
5902#endif
5903#ifdef FEAT_FILTERPIPE
5904 "filterpipe",
5905#endif
5906#ifdef FEAT_FIND_ID
5907 "find_in_path",
5908#endif
5909#ifdef FEAT_FLOAT
5910 "float",
5911#endif
5912#ifdef FEAT_FOLDING
5913 "folding",
5914#endif
5915#ifdef FEAT_FOOTER
5916 "footer",
5917#endif
5918#if !defined(USE_SYSTEM) && defined(UNIX)
5919 "fork",
5920#endif
5921#ifdef FEAT_GETTEXT
5922 "gettext",
5923#endif
5924#ifdef FEAT_GUI
5925 "gui",
5926#endif
5927#ifdef FEAT_GUI_ATHENA
5928# ifdef FEAT_GUI_NEXTAW
5929 "gui_neXtaw",
5930# else
5931 "gui_athena",
5932# endif
5933#endif
5934#ifdef FEAT_GUI_GTK
5935 "gui_gtk",
5936# ifdef USE_GTK3
5937 "gui_gtk3",
5938# else
5939 "gui_gtk2",
5940# endif
5941#endif
5942#ifdef FEAT_GUI_GNOME
5943 "gui_gnome",
5944#endif
5945#ifdef FEAT_GUI_MAC
5946 "gui_mac",
5947#endif
5948#ifdef FEAT_GUI_MOTIF
5949 "gui_motif",
5950#endif
5951#ifdef FEAT_GUI_PHOTON
5952 "gui_photon",
5953#endif
5954#ifdef FEAT_GUI_W32
5955 "gui_win32",
5956#endif
5957#ifdef FEAT_HANGULIN
5958 "hangul_input",
5959#endif
5960#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5961 "iconv",
5962#endif
5963#ifdef FEAT_INS_EXPAND
5964 "insert_expand",
5965#endif
5966#ifdef FEAT_JOB_CHANNEL
5967 "job",
5968#endif
5969#ifdef FEAT_JUMPLIST
5970 "jumplist",
5971#endif
5972#ifdef FEAT_KEYMAP
5973 "keymap",
5974#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005975 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976#ifdef FEAT_LANGMAP
5977 "langmap",
5978#endif
5979#ifdef FEAT_LIBCALL
5980 "libcall",
5981#endif
5982#ifdef FEAT_LINEBREAK
5983 "linebreak",
5984#endif
5985#ifdef FEAT_LISP
5986 "lispindent",
5987#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005988 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005989#ifdef FEAT_LOCALMAP
5990 "localmap",
5991#endif
5992#ifdef FEAT_LUA
5993# ifndef DYNAMIC_LUA
5994 "lua",
5995# endif
5996#endif
5997#ifdef FEAT_MENU
5998 "menu",
5999#endif
6000#ifdef FEAT_SESSION
6001 "mksession",
6002#endif
6003#ifdef FEAT_MODIFY_FNAME
6004 "modify_fname",
6005#endif
6006#ifdef FEAT_MOUSE
6007 "mouse",
6008#endif
6009#ifdef FEAT_MOUSESHAPE
6010 "mouseshape",
6011#endif
6012#if defined(UNIX) || defined(VMS)
6013# ifdef FEAT_MOUSE_DEC
6014 "mouse_dec",
6015# endif
6016# ifdef FEAT_MOUSE_GPM
6017 "mouse_gpm",
6018# endif
6019# ifdef FEAT_MOUSE_JSB
6020 "mouse_jsbterm",
6021# endif
6022# ifdef FEAT_MOUSE_NET
6023 "mouse_netterm",
6024# endif
6025# ifdef FEAT_MOUSE_PTERM
6026 "mouse_pterm",
6027# endif
6028# ifdef FEAT_MOUSE_SGR
6029 "mouse_sgr",
6030# endif
6031# ifdef FEAT_SYSMOUSE
6032 "mouse_sysmouse",
6033# endif
6034# ifdef FEAT_MOUSE_URXVT
6035 "mouse_urxvt",
6036# endif
6037# ifdef FEAT_MOUSE_XTERM
6038 "mouse_xterm",
6039# endif
6040#endif
6041#ifdef FEAT_MBYTE
6042 "multi_byte",
6043#endif
6044#ifdef FEAT_MBYTE_IME
6045 "multi_byte_ime",
6046#endif
6047#ifdef FEAT_MULTI_LANG
6048 "multi_lang",
6049#endif
6050#ifdef FEAT_MZSCHEME
6051#ifndef DYNAMIC_MZSCHEME
6052 "mzscheme",
6053#endif
6054#endif
6055#ifdef FEAT_NUM64
6056 "num64",
6057#endif
6058#ifdef FEAT_OLE
6059 "ole",
6060#endif
6061 "packages",
6062#ifdef FEAT_PATH_EXTRA
6063 "path_extra",
6064#endif
6065#ifdef FEAT_PERL
6066#ifndef DYNAMIC_PERL
6067 "perl",
6068#endif
6069#endif
6070#ifdef FEAT_PERSISTENT_UNDO
6071 "persistent_undo",
6072#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006073#if defined(FEAT_PYTHON)
6074 "python_compiled",
6075# if defined(DYNAMIC_PYTHON)
6076 "python_dynamic",
6077# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006078 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006079 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006080# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006082#if defined(FEAT_PYTHON3)
6083 "python3_compiled",
6084# if defined(DYNAMIC_PYTHON3)
6085 "python3_dynamic",
6086# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006088 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006089# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090#endif
6091#ifdef FEAT_POSTSCRIPT
6092 "postscript",
6093#endif
6094#ifdef FEAT_PRINTER
6095 "printer",
6096#endif
6097#ifdef FEAT_PROFILE
6098 "profile",
6099#endif
6100#ifdef FEAT_RELTIME
6101 "reltime",
6102#endif
6103#ifdef FEAT_QUICKFIX
6104 "quickfix",
6105#endif
6106#ifdef FEAT_RIGHTLEFT
6107 "rightleft",
6108#endif
6109#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6110 "ruby",
6111#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006112 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006113#ifdef FEAT_CMDL_INFO
6114 "showcmd",
6115 "cmdline_info",
6116#endif
6117#ifdef FEAT_SIGNS
6118 "signs",
6119#endif
6120#ifdef FEAT_SMARTINDENT
6121 "smartindent",
6122#endif
6123#ifdef STARTUPTIME
6124 "startuptime",
6125#endif
6126#ifdef FEAT_STL_OPT
6127 "statusline",
6128#endif
6129#ifdef FEAT_SUN_WORKSHOP
6130 "sun_workshop",
6131#endif
6132#ifdef FEAT_NETBEANS_INTG
6133 "netbeans_intg",
6134#endif
6135#ifdef FEAT_SPELL
6136 "spell",
6137#endif
6138#ifdef FEAT_SYN_HL
6139 "syntax",
6140#endif
6141#if defined(USE_SYSTEM) || !defined(UNIX)
6142 "system",
6143#endif
6144#ifdef FEAT_TAG_BINS
6145 "tag_binary",
6146#endif
6147#ifdef FEAT_TAG_OLDSTATIC
6148 "tag_old_static",
6149#endif
6150#ifdef FEAT_TAG_ANYWHITE
6151 "tag_any_white",
6152#endif
6153#ifdef FEAT_TCL
6154# ifndef DYNAMIC_TCL
6155 "tcl",
6156# endif
6157#endif
6158#ifdef FEAT_TERMGUICOLORS
6159 "termguicolors",
6160#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006161#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006162 "terminal",
6163#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006164#ifdef TERMINFO
6165 "terminfo",
6166#endif
6167#ifdef FEAT_TERMRESPONSE
6168 "termresponse",
6169#endif
6170#ifdef FEAT_TEXTOBJ
6171 "textobjects",
6172#endif
6173#ifdef HAVE_TGETENT
6174 "tgetent",
6175#endif
6176#ifdef FEAT_TIMERS
6177 "timers",
6178#endif
6179#ifdef FEAT_TITLE
6180 "title",
6181#endif
6182#ifdef FEAT_TOOLBAR
6183 "toolbar",
6184#endif
6185#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6186 "unnamedplus",
6187#endif
6188#ifdef FEAT_USR_CMDS
6189 "user-commands", /* was accidentally included in 5.4 */
6190 "user_commands",
6191#endif
6192#ifdef FEAT_VIMINFO
6193 "viminfo",
6194#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196#ifdef FEAT_VIRTUALEDIT
6197 "virtualedit",
6198#endif
6199 "visual",
6200#ifdef FEAT_VISUALEXTRA
6201 "visualextra",
6202#endif
6203#ifdef FEAT_VREPLACE
6204 "vreplace",
6205#endif
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006206#ifdef FEAT_VTP
6207 "vtp",
6208#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006209#ifdef FEAT_WILDIGN
6210 "wildignore",
6211#endif
6212#ifdef FEAT_WILDMENU
6213 "wildmenu",
6214#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006216#ifdef FEAT_WAK
6217 "winaltkeys",
6218#endif
6219#ifdef FEAT_WRITEBACKUP
6220 "writebackup",
6221#endif
6222#ifdef FEAT_XIM
6223 "xim",
6224#endif
6225#ifdef FEAT_XFONTSET
6226 "xfontset",
6227#endif
6228#ifdef FEAT_XPM_W32
6229 "xpm",
6230 "xpm_w32", /* for backward compatibility */
6231#else
6232# if defined(HAVE_XPM)
6233 "xpm",
6234# endif
6235#endif
6236#ifdef USE_XSMP
6237 "xsmp",
6238#endif
6239#ifdef USE_XSMP_INTERACT
6240 "xsmp_interact",
6241#endif
6242#ifdef FEAT_XCLIPBOARD
6243 "xterm_clipboard",
6244#endif
6245#ifdef FEAT_XTERM_SAVE
6246 "xterm_save",
6247#endif
6248#if defined(UNIX) && defined(FEAT_X11)
6249 "X11",
6250#endif
6251 NULL
6252 };
6253
6254 name = get_tv_string(&argvars[0]);
6255 for (i = 0; has_list[i] != NULL; ++i)
6256 if (STRICMP(name, has_list[i]) == 0)
6257 {
6258 n = TRUE;
6259 break;
6260 }
6261
6262 if (n == FALSE)
6263 {
6264 if (STRNICMP(name, "patch", 5) == 0)
6265 {
6266 if (name[5] == '-'
6267 && STRLEN(name) >= 11
6268 && vim_isdigit(name[6])
6269 && vim_isdigit(name[8])
6270 && vim_isdigit(name[10]))
6271 {
6272 int major = atoi((char *)name + 6);
6273 int minor = atoi((char *)name + 8);
6274
6275 /* Expect "patch-9.9.01234". */
6276 n = (major < VIM_VERSION_MAJOR
6277 || (major == VIM_VERSION_MAJOR
6278 && (minor < VIM_VERSION_MINOR
6279 || (minor == VIM_VERSION_MINOR
6280 && has_patch(atoi((char *)name + 10))))));
6281 }
6282 else
6283 n = has_patch(atoi((char *)name + 5));
6284 }
6285 else if (STRICMP(name, "vim_starting") == 0)
6286 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006287 else if (STRICMP(name, "ttyin") == 0)
6288 n = mch_input_isatty();
6289 else if (STRICMP(name, "ttyout") == 0)
6290 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291#ifdef FEAT_MBYTE
6292 else if (STRICMP(name, "multi_byte_encoding") == 0)
6293 n = has_mbyte;
6294#endif
6295#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6296 else if (STRICMP(name, "balloon_multiline") == 0)
6297 n = multiline_balloon_available();
6298#endif
6299#ifdef DYNAMIC_TCL
6300 else if (STRICMP(name, "tcl") == 0)
6301 n = tcl_enabled(FALSE);
6302#endif
6303#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6304 else if (STRICMP(name, "iconv") == 0)
6305 n = iconv_enabled(FALSE);
6306#endif
6307#ifdef DYNAMIC_LUA
6308 else if (STRICMP(name, "lua") == 0)
6309 n = lua_enabled(FALSE);
6310#endif
6311#ifdef DYNAMIC_MZSCHEME
6312 else if (STRICMP(name, "mzscheme") == 0)
6313 n = mzscheme_enabled(FALSE);
6314#endif
6315#ifdef DYNAMIC_RUBY
6316 else if (STRICMP(name, "ruby") == 0)
6317 n = ruby_enabled(FALSE);
6318#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006319#ifdef DYNAMIC_PYTHON
6320 else if (STRICMP(name, "python") == 0)
6321 n = python_enabled(FALSE);
6322#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323#ifdef DYNAMIC_PYTHON3
6324 else if (STRICMP(name, "python3") == 0)
6325 n = python3_enabled(FALSE);
6326#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006327#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6328 else if (STRICMP(name, "pythonx") == 0)
6329 {
6330# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6331 if (p_pyx == 0)
6332 n = python3_enabled(FALSE) || python_enabled(FALSE);
6333 else if (p_pyx == 3)
6334 n = python3_enabled(FALSE);
6335 else if (p_pyx == 2)
6336 n = python_enabled(FALSE);
6337# elif defined(DYNAMIC_PYTHON)
6338 n = python_enabled(FALSE);
6339# elif defined(DYNAMIC_PYTHON3)
6340 n = python3_enabled(FALSE);
6341# endif
6342 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343#endif
6344#ifdef DYNAMIC_PERL
6345 else if (STRICMP(name, "perl") == 0)
6346 n = perl_enabled(FALSE);
6347#endif
6348#ifdef FEAT_GUI
6349 else if (STRICMP(name, "gui_running") == 0)
6350 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351# ifdef FEAT_BROWSE
6352 else if (STRICMP(name, "browse") == 0)
6353 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6354# endif
6355#endif
6356#ifdef FEAT_SYN_HL
6357 else if (STRICMP(name, "syntax_items") == 0)
6358 n = syntax_present(curwin);
6359#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006360#ifdef FEAT_VTP
6361 else if (STRICMP(name, "vcon") == 0)
6362 n = has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363#endif
6364#ifdef FEAT_NETBEANS_INTG
6365 else if (STRICMP(name, "netbeans_enabled") == 0)
6366 n = netbeans_active();
6367#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006368#if defined(FEAT_TERMINAL) && defined(WIN3264)
6369 else if (STRICMP(name, "terminal") == 0)
6370 n = terminal_enabled();
6371#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372 }
6373
6374 rettv->vval.v_number = n;
6375}
6376
6377/*
6378 * "has_key()" function
6379 */
6380 static void
6381f_has_key(typval_T *argvars, typval_T *rettv)
6382{
6383 if (argvars[0].v_type != VAR_DICT)
6384 {
6385 EMSG(_(e_dictreq));
6386 return;
6387 }
6388 if (argvars[0].vval.v_dict == NULL)
6389 return;
6390
6391 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6392 get_tv_string(&argvars[1]), -1) != NULL;
6393}
6394
6395/*
6396 * "haslocaldir()" function
6397 */
6398 static void
6399f_haslocaldir(typval_T *argvars, typval_T *rettv)
6400{
6401 win_T *wp = NULL;
6402
6403 wp = find_tabwin(&argvars[0], &argvars[1]);
6404 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6405}
6406
6407/*
6408 * "hasmapto()" function
6409 */
6410 static void
6411f_hasmapto(typval_T *argvars, typval_T *rettv)
6412{
6413 char_u *name;
6414 char_u *mode;
6415 char_u buf[NUMBUFLEN];
6416 int abbr = FALSE;
6417
6418 name = get_tv_string(&argvars[0]);
6419 if (argvars[1].v_type == VAR_UNKNOWN)
6420 mode = (char_u *)"nvo";
6421 else
6422 {
6423 mode = get_tv_string_buf(&argvars[1], buf);
6424 if (argvars[2].v_type != VAR_UNKNOWN)
6425 abbr = (int)get_tv_number(&argvars[2]);
6426 }
6427
6428 if (map_to_exists(name, mode, abbr))
6429 rettv->vval.v_number = TRUE;
6430 else
6431 rettv->vval.v_number = FALSE;
6432}
6433
6434/*
6435 * "histadd()" function
6436 */
6437 static void
6438f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6439{
6440#ifdef FEAT_CMDHIST
6441 int histype;
6442 char_u *str;
6443 char_u buf[NUMBUFLEN];
6444#endif
6445
6446 rettv->vval.v_number = FALSE;
6447 if (check_restricted() || check_secure())
6448 return;
6449#ifdef FEAT_CMDHIST
6450 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6451 histype = str != NULL ? get_histtype(str) : -1;
6452 if (histype >= 0)
6453 {
6454 str = get_tv_string_buf(&argvars[1], buf);
6455 if (*str != NUL)
6456 {
6457 init_history();
6458 add_to_history(histype, str, FALSE, NUL);
6459 rettv->vval.v_number = TRUE;
6460 return;
6461 }
6462 }
6463#endif
6464}
6465
6466/*
6467 * "histdel()" function
6468 */
6469 static void
6470f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6471{
6472#ifdef FEAT_CMDHIST
6473 int n;
6474 char_u buf[NUMBUFLEN];
6475 char_u *str;
6476
6477 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6478 if (str == NULL)
6479 n = 0;
6480 else if (argvars[1].v_type == VAR_UNKNOWN)
6481 /* only one argument: clear entire history */
6482 n = clr_history(get_histtype(str));
6483 else if (argvars[1].v_type == VAR_NUMBER)
6484 /* index given: remove that entry */
6485 n = del_history_idx(get_histtype(str),
6486 (int)get_tv_number(&argvars[1]));
6487 else
6488 /* string given: remove all matching entries */
6489 n = del_history_entry(get_histtype(str),
6490 get_tv_string_buf(&argvars[1], buf));
6491 rettv->vval.v_number = n;
6492#endif
6493}
6494
6495/*
6496 * "histget()" function
6497 */
6498 static void
6499f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6500{
6501#ifdef FEAT_CMDHIST
6502 int type;
6503 int idx;
6504 char_u *str;
6505
6506 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6507 if (str == NULL)
6508 rettv->vval.v_string = NULL;
6509 else
6510 {
6511 type = get_histtype(str);
6512 if (argvars[1].v_type == VAR_UNKNOWN)
6513 idx = get_history_idx(type);
6514 else
6515 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6516 /* -1 on type error */
6517 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6518 }
6519#else
6520 rettv->vval.v_string = NULL;
6521#endif
6522 rettv->v_type = VAR_STRING;
6523}
6524
6525/*
6526 * "histnr()" function
6527 */
6528 static void
6529f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6530{
6531 int i;
6532
6533#ifdef FEAT_CMDHIST
6534 char_u *history = get_tv_string_chk(&argvars[0]);
6535
6536 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6537 if (i >= HIST_CMD && i < HIST_COUNT)
6538 i = get_history_idx(i);
6539 else
6540#endif
6541 i = -1;
6542 rettv->vval.v_number = i;
6543}
6544
6545/*
6546 * "highlightID(name)" function
6547 */
6548 static void
6549f_hlID(typval_T *argvars, typval_T *rettv)
6550{
6551 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6552}
6553
6554/*
6555 * "highlight_exists()" function
6556 */
6557 static void
6558f_hlexists(typval_T *argvars, typval_T *rettv)
6559{
6560 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6561}
6562
6563/*
6564 * "hostname()" function
6565 */
6566 static void
6567f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6568{
6569 char_u hostname[256];
6570
6571 mch_get_host_name(hostname, 256);
6572 rettv->v_type = VAR_STRING;
6573 rettv->vval.v_string = vim_strsave(hostname);
6574}
6575
6576/*
6577 * iconv() function
6578 */
6579 static void
6580f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6581{
6582#ifdef FEAT_MBYTE
6583 char_u buf1[NUMBUFLEN];
6584 char_u buf2[NUMBUFLEN];
6585 char_u *from, *to, *str;
6586 vimconv_T vimconv;
6587#endif
6588
6589 rettv->v_type = VAR_STRING;
6590 rettv->vval.v_string = NULL;
6591
6592#ifdef FEAT_MBYTE
6593 str = get_tv_string(&argvars[0]);
6594 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6595 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6596 vimconv.vc_type = CONV_NONE;
6597 convert_setup(&vimconv, from, to);
6598
6599 /* If the encodings are equal, no conversion needed. */
6600 if (vimconv.vc_type == CONV_NONE)
6601 rettv->vval.v_string = vim_strsave(str);
6602 else
6603 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6604
6605 convert_setup(&vimconv, NULL, NULL);
6606 vim_free(from);
6607 vim_free(to);
6608#endif
6609}
6610
6611/*
6612 * "indent()" function
6613 */
6614 static void
6615f_indent(typval_T *argvars, typval_T *rettv)
6616{
6617 linenr_T lnum;
6618
6619 lnum = get_tv_lnum(argvars);
6620 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6621 rettv->vval.v_number = get_indent_lnum(lnum);
6622 else
6623 rettv->vval.v_number = -1;
6624}
6625
6626/*
6627 * "index()" function
6628 */
6629 static void
6630f_index(typval_T *argvars, typval_T *rettv)
6631{
6632 list_T *l;
6633 listitem_T *item;
6634 long idx = 0;
6635 int ic = FALSE;
6636
6637 rettv->vval.v_number = -1;
6638 if (argvars[0].v_type != VAR_LIST)
6639 {
6640 EMSG(_(e_listreq));
6641 return;
6642 }
6643 l = argvars[0].vval.v_list;
6644 if (l != NULL)
6645 {
6646 item = l->lv_first;
6647 if (argvars[2].v_type != VAR_UNKNOWN)
6648 {
6649 int error = FALSE;
6650
6651 /* Start at specified item. Use the cached index that list_find()
6652 * sets, so that a negative number also works. */
6653 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6654 idx = l->lv_idx;
6655 if (argvars[3].v_type != VAR_UNKNOWN)
6656 ic = (int)get_tv_number_chk(&argvars[3], &error);
6657 if (error)
6658 item = NULL;
6659 }
6660
6661 for ( ; item != NULL; item = item->li_next, ++idx)
6662 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6663 {
6664 rettv->vval.v_number = idx;
6665 break;
6666 }
6667 }
6668}
6669
6670static int inputsecret_flag = 0;
6671
6672/*
6673 * "input()" function
6674 * Also handles inputsecret() when inputsecret is set.
6675 */
6676 static void
6677f_input(typval_T *argvars, typval_T *rettv)
6678{
6679 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6680}
6681
6682/*
6683 * "inputdialog()" function
6684 */
6685 static void
6686f_inputdialog(typval_T *argvars, typval_T *rettv)
6687{
6688#if defined(FEAT_GUI_TEXTDIALOG)
6689 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6690 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6691 {
6692 char_u *message;
6693 char_u buf[NUMBUFLEN];
6694 char_u *defstr = (char_u *)"";
6695
6696 message = get_tv_string_chk(&argvars[0]);
6697 if (argvars[1].v_type != VAR_UNKNOWN
6698 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6699 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6700 else
6701 IObuff[0] = NUL;
6702 if (message != NULL && defstr != NULL
6703 && do_dialog(VIM_QUESTION, NULL, message,
6704 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6705 rettv->vval.v_string = vim_strsave(IObuff);
6706 else
6707 {
6708 if (message != NULL && defstr != NULL
6709 && argvars[1].v_type != VAR_UNKNOWN
6710 && argvars[2].v_type != VAR_UNKNOWN)
6711 rettv->vval.v_string = vim_strsave(
6712 get_tv_string_buf(&argvars[2], buf));
6713 else
6714 rettv->vval.v_string = NULL;
6715 }
6716 rettv->v_type = VAR_STRING;
6717 }
6718 else
6719#endif
6720 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6721}
6722
6723/*
6724 * "inputlist()" function
6725 */
6726 static void
6727f_inputlist(typval_T *argvars, typval_T *rettv)
6728{
6729 listitem_T *li;
6730 int selected;
6731 int mouse_used;
6732
6733#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006734 /* While starting up, there is no place to enter text. When running tests
6735 * with --not-a-term we assume feedkeys() will be used. */
6736 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 return;
6738#endif
6739 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6740 {
6741 EMSG2(_(e_listarg), "inputlist()");
6742 return;
6743 }
6744
6745 msg_start();
6746 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6747 lines_left = Rows; /* avoid more prompt */
6748 msg_scroll = TRUE;
6749 msg_clr_eos();
6750
6751 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6752 {
6753 msg_puts(get_tv_string(&li->li_tv));
6754 msg_putchar('\n');
6755 }
6756
6757 /* Ask for choice. */
6758 selected = prompt_for_number(&mouse_used);
6759 if (mouse_used)
6760 selected -= lines_left;
6761
6762 rettv->vval.v_number = selected;
6763}
6764
6765
6766static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6767
6768/*
6769 * "inputrestore()" function
6770 */
6771 static void
6772f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6773{
6774 if (ga_userinput.ga_len > 0)
6775 {
6776 --ga_userinput.ga_len;
6777 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6778 + ga_userinput.ga_len);
6779 /* default return is zero == OK */
6780 }
6781 else if (p_verbose > 1)
6782 {
6783 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6784 rettv->vval.v_number = 1; /* Failed */
6785 }
6786}
6787
6788/*
6789 * "inputsave()" function
6790 */
6791 static void
6792f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6793{
6794 /* Add an entry to the stack of typeahead storage. */
6795 if (ga_grow(&ga_userinput, 1) == OK)
6796 {
6797 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6798 + ga_userinput.ga_len);
6799 ++ga_userinput.ga_len;
6800 /* default return is zero == OK */
6801 }
6802 else
6803 rettv->vval.v_number = 1; /* Failed */
6804}
6805
6806/*
6807 * "inputsecret()" function
6808 */
6809 static void
6810f_inputsecret(typval_T *argvars, typval_T *rettv)
6811{
6812 ++cmdline_star;
6813 ++inputsecret_flag;
6814 f_input(argvars, rettv);
6815 --cmdline_star;
6816 --inputsecret_flag;
6817}
6818
6819/*
6820 * "insert()" function
6821 */
6822 static void
6823f_insert(typval_T *argvars, typval_T *rettv)
6824{
6825 long before = 0;
6826 listitem_T *item;
6827 list_T *l;
6828 int error = FALSE;
6829
6830 if (argvars[0].v_type != VAR_LIST)
6831 EMSG2(_(e_listarg), "insert()");
6832 else if ((l = argvars[0].vval.v_list) != NULL
6833 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6834 {
6835 if (argvars[2].v_type != VAR_UNKNOWN)
6836 before = (long)get_tv_number_chk(&argvars[2], &error);
6837 if (error)
6838 return; /* type error; errmsg already given */
6839
6840 if (before == l->lv_len)
6841 item = NULL;
6842 else
6843 {
6844 item = list_find(l, before);
6845 if (item == NULL)
6846 {
6847 EMSGN(_(e_listidx), before);
6848 l = NULL;
6849 }
6850 }
6851 if (l != NULL)
6852 {
6853 list_insert_tv(l, &argvars[1], item);
6854 copy_tv(&argvars[0], rettv);
6855 }
6856 }
6857}
6858
6859/*
6860 * "invert(expr)" function
6861 */
6862 static void
6863f_invert(typval_T *argvars, typval_T *rettv)
6864{
6865 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6866}
6867
6868/*
6869 * "isdirectory()" function
6870 */
6871 static void
6872f_isdirectory(typval_T *argvars, typval_T *rettv)
6873{
6874 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6875}
6876
6877/*
6878 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6879 * or it refers to a List or Dictionary that is locked.
6880 */
6881 static int
6882tv_islocked(typval_T *tv)
6883{
6884 return (tv->v_lock & VAR_LOCKED)
6885 || (tv->v_type == VAR_LIST
6886 && tv->vval.v_list != NULL
6887 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6888 || (tv->v_type == VAR_DICT
6889 && tv->vval.v_dict != NULL
6890 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6891}
6892
6893/*
6894 * "islocked()" function
6895 */
6896 static void
6897f_islocked(typval_T *argvars, typval_T *rettv)
6898{
6899 lval_T lv;
6900 char_u *end;
6901 dictitem_T *di;
6902
6903 rettv->vval.v_number = -1;
6904 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006905 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 if (end != NULL && lv.ll_name != NULL)
6907 {
6908 if (*end != NUL)
6909 EMSG(_(e_trailing));
6910 else
6911 {
6912 if (lv.ll_tv == NULL)
6913 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006914 di = find_var(lv.ll_name, NULL, TRUE);
6915 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006917 /* Consider a variable locked when:
6918 * 1. the variable itself is locked
6919 * 2. the value of the variable is locked.
6920 * 3. the List or Dict value is locked.
6921 */
6922 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6923 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006924 }
6925 }
6926 else if (lv.ll_range)
6927 EMSG(_("E786: Range not allowed"));
6928 else if (lv.ll_newkey != NULL)
6929 EMSG2(_(e_dictkey), lv.ll_newkey);
6930 else if (lv.ll_list != NULL)
6931 /* List item. */
6932 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6933 else
6934 /* Dictionary item. */
6935 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6936 }
6937 }
6938
6939 clear_lval(&lv);
6940}
6941
6942#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6943/*
6944 * "isnan()" function
6945 */
6946 static void
6947f_isnan(typval_T *argvars, typval_T *rettv)
6948{
6949 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6950 && isnan(argvars[0].vval.v_float);
6951}
6952#endif
6953
6954/*
6955 * "items(dict)" function
6956 */
6957 static void
6958f_items(typval_T *argvars, typval_T *rettv)
6959{
6960 dict_list(argvars, rettv, 2);
6961}
6962
6963#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6964/*
6965 * Get the job from the argument.
6966 * Returns NULL if the job is invalid.
6967 */
6968 static job_T *
6969get_job_arg(typval_T *tv)
6970{
6971 job_T *job;
6972
6973 if (tv->v_type != VAR_JOB)
6974 {
6975 EMSG2(_(e_invarg2), get_tv_string(tv));
6976 return NULL;
6977 }
6978 job = tv->vval.v_job;
6979
6980 if (job == NULL)
6981 EMSG(_("E916: not a valid job"));
6982 return job;
6983}
6984
6985/*
6986 * "job_getchannel()" function
6987 */
6988 static void
6989f_job_getchannel(typval_T *argvars, typval_T *rettv)
6990{
6991 job_T *job = get_job_arg(&argvars[0]);
6992
6993 if (job != NULL)
6994 {
6995 rettv->v_type = VAR_CHANNEL;
6996 rettv->vval.v_channel = job->jv_channel;
6997 if (job->jv_channel != NULL)
6998 ++job->jv_channel->ch_refcount;
6999 }
7000}
7001
7002/*
7003 * "job_info()" function
7004 */
7005 static void
7006f_job_info(typval_T *argvars, typval_T *rettv)
7007{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007008 if (argvars[0].v_type != VAR_UNKNOWN)
7009 {
7010 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007011
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007012 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7013 job_info(job, rettv->vval.v_dict);
7014 }
7015 else if (rettv_list_alloc(rettv) == OK)
7016 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007017}
7018
7019/*
7020 * "job_setoptions()" function
7021 */
7022 static void
7023f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7024{
7025 job_T *job = get_job_arg(&argvars[0]);
7026 jobopt_T opt;
7027
7028 if (job == NULL)
7029 return;
7030 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007031 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007032 job_set_options(job, &opt);
7033 free_job_options(&opt);
7034}
7035
7036/*
7037 * "job_start()" function
7038 */
7039 static void
7040f_job_start(typval_T *argvars, typval_T *rettv)
7041{
7042 rettv->v_type = VAR_JOB;
7043 if (check_restricted() || check_secure())
7044 return;
Bram Moolenaar13568252018-03-16 20:46:58 +01007045 rettv->vval.v_job = job_start(argvars, NULL, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007046}
7047
7048/*
7049 * "job_status()" function
7050 */
7051 static void
7052f_job_status(typval_T *argvars, typval_T *rettv)
7053{
7054 job_T *job = get_job_arg(&argvars[0]);
7055
7056 if (job != NULL)
7057 {
7058 rettv->v_type = VAR_STRING;
7059 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7060 }
7061}
7062
7063/*
7064 * "job_stop()" function
7065 */
7066 static void
7067f_job_stop(typval_T *argvars, typval_T *rettv)
7068{
7069 job_T *job = get_job_arg(&argvars[0]);
7070
7071 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007072 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007073}
7074#endif
7075
7076/*
7077 * "join()" function
7078 */
7079 static void
7080f_join(typval_T *argvars, typval_T *rettv)
7081{
7082 garray_T ga;
7083 char_u *sep;
7084
7085 if (argvars[0].v_type != VAR_LIST)
7086 {
7087 EMSG(_(e_listreq));
7088 return;
7089 }
7090 if (argvars[0].vval.v_list == NULL)
7091 return;
7092 if (argvars[1].v_type == VAR_UNKNOWN)
7093 sep = (char_u *)" ";
7094 else
7095 sep = get_tv_string_chk(&argvars[1]);
7096
7097 rettv->v_type = VAR_STRING;
7098
7099 if (sep != NULL)
7100 {
7101 ga_init2(&ga, (int)sizeof(char), 80);
7102 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7103 ga_append(&ga, NUL);
7104 rettv->vval.v_string = (char_u *)ga.ga_data;
7105 }
7106 else
7107 rettv->vval.v_string = NULL;
7108}
7109
7110/*
7111 * "js_decode()" function
7112 */
7113 static void
7114f_js_decode(typval_T *argvars, typval_T *rettv)
7115{
7116 js_read_T reader;
7117
7118 reader.js_buf = get_tv_string(&argvars[0]);
7119 reader.js_fill = NULL;
7120 reader.js_used = 0;
7121 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7122 EMSG(_(e_invarg));
7123}
7124
7125/*
7126 * "js_encode()" function
7127 */
7128 static void
7129f_js_encode(typval_T *argvars, typval_T *rettv)
7130{
7131 rettv->v_type = VAR_STRING;
7132 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7133}
7134
7135/*
7136 * "json_decode()" function
7137 */
7138 static void
7139f_json_decode(typval_T *argvars, typval_T *rettv)
7140{
7141 js_read_T reader;
7142
7143 reader.js_buf = get_tv_string(&argvars[0]);
7144 reader.js_fill = NULL;
7145 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007146 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007147}
7148
7149/*
7150 * "json_encode()" function
7151 */
7152 static void
7153f_json_encode(typval_T *argvars, typval_T *rettv)
7154{
7155 rettv->v_type = VAR_STRING;
7156 rettv->vval.v_string = json_encode(&argvars[0], 0);
7157}
7158
7159/*
7160 * "keys()" function
7161 */
7162 static void
7163f_keys(typval_T *argvars, typval_T *rettv)
7164{
7165 dict_list(argvars, rettv, 0);
7166}
7167
7168/*
7169 * "last_buffer_nr()" function.
7170 */
7171 static void
7172f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7173{
7174 int n = 0;
7175 buf_T *buf;
7176
Bram Moolenaar29323592016-07-24 22:04:11 +02007177 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007178 if (n < buf->b_fnum)
7179 n = buf->b_fnum;
7180
7181 rettv->vval.v_number = n;
7182}
7183
7184/*
7185 * "len()" function
7186 */
7187 static void
7188f_len(typval_T *argvars, typval_T *rettv)
7189{
7190 switch (argvars[0].v_type)
7191 {
7192 case VAR_STRING:
7193 case VAR_NUMBER:
7194 rettv->vval.v_number = (varnumber_T)STRLEN(
7195 get_tv_string(&argvars[0]));
7196 break;
7197 case VAR_LIST:
7198 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7199 break;
7200 case VAR_DICT:
7201 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7202 break;
7203 case VAR_UNKNOWN:
7204 case VAR_SPECIAL:
7205 case VAR_FLOAT:
7206 case VAR_FUNC:
7207 case VAR_PARTIAL:
7208 case VAR_JOB:
7209 case VAR_CHANNEL:
7210 EMSG(_("E701: Invalid type for len()"));
7211 break;
7212 }
7213}
7214
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007215 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007216libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007217{
7218#ifdef FEAT_LIBCALL
7219 char_u *string_in;
7220 char_u **string_result;
7221 int nr_result;
7222#endif
7223
7224 rettv->v_type = type;
7225 if (type != VAR_NUMBER)
7226 rettv->vval.v_string = NULL;
7227
7228 if (check_restricted() || check_secure())
7229 return;
7230
7231#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007232 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7234 {
7235 string_in = NULL;
7236 if (argvars[2].v_type == VAR_STRING)
7237 string_in = argvars[2].vval.v_string;
7238 if (type == VAR_NUMBER)
7239 string_result = NULL;
7240 else
7241 string_result = &rettv->vval.v_string;
7242 if (mch_libcall(argvars[0].vval.v_string,
7243 argvars[1].vval.v_string,
7244 string_in,
7245 argvars[2].vval.v_number,
7246 string_result,
7247 &nr_result) == OK
7248 && type == VAR_NUMBER)
7249 rettv->vval.v_number = nr_result;
7250 }
7251#endif
7252}
7253
7254/*
7255 * "libcall()" function
7256 */
7257 static void
7258f_libcall(typval_T *argvars, typval_T *rettv)
7259{
7260 libcall_common(argvars, rettv, VAR_STRING);
7261}
7262
7263/*
7264 * "libcallnr()" function
7265 */
7266 static void
7267f_libcallnr(typval_T *argvars, typval_T *rettv)
7268{
7269 libcall_common(argvars, rettv, VAR_NUMBER);
7270}
7271
7272/*
7273 * "line(string)" function
7274 */
7275 static void
7276f_line(typval_T *argvars, typval_T *rettv)
7277{
7278 linenr_T lnum = 0;
7279 pos_T *fp;
7280 int fnum;
7281
7282 fp = var2fpos(&argvars[0], TRUE, &fnum);
7283 if (fp != NULL)
7284 lnum = fp->lnum;
7285 rettv->vval.v_number = lnum;
7286}
7287
7288/*
7289 * "line2byte(lnum)" function
7290 */
7291 static void
7292f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7293{
7294#ifndef FEAT_BYTEOFF
7295 rettv->vval.v_number = -1;
7296#else
7297 linenr_T lnum;
7298
7299 lnum = get_tv_lnum(argvars);
7300 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7301 rettv->vval.v_number = -1;
7302 else
7303 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7304 if (rettv->vval.v_number >= 0)
7305 ++rettv->vval.v_number;
7306#endif
7307}
7308
7309/*
7310 * "lispindent(lnum)" function
7311 */
7312 static void
7313f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7314{
7315#ifdef FEAT_LISP
7316 pos_T pos;
7317 linenr_T lnum;
7318
7319 pos = curwin->w_cursor;
7320 lnum = get_tv_lnum(argvars);
7321 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7322 {
7323 curwin->w_cursor.lnum = lnum;
7324 rettv->vval.v_number = get_lisp_indent();
7325 curwin->w_cursor = pos;
7326 }
7327 else
7328#endif
7329 rettv->vval.v_number = -1;
7330}
7331
7332/*
7333 * "localtime()" function
7334 */
7335 static void
7336f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7337{
7338 rettv->vval.v_number = (varnumber_T)time(NULL);
7339}
7340
7341static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7342
7343 static void
7344get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7345{
7346 char_u *keys;
7347 char_u *which;
7348 char_u buf[NUMBUFLEN];
7349 char_u *keys_buf = NULL;
7350 char_u *rhs;
7351 int mode;
7352 int abbr = FALSE;
7353 int get_dict = FALSE;
7354 mapblock_T *mp;
7355 int buffer_local;
7356
7357 /* return empty string for failure */
7358 rettv->v_type = VAR_STRING;
7359 rettv->vval.v_string = NULL;
7360
7361 keys = get_tv_string(&argvars[0]);
7362 if (*keys == NUL)
7363 return;
7364
7365 if (argvars[1].v_type != VAR_UNKNOWN)
7366 {
7367 which = get_tv_string_buf_chk(&argvars[1], buf);
7368 if (argvars[2].v_type != VAR_UNKNOWN)
7369 {
7370 abbr = (int)get_tv_number(&argvars[2]);
7371 if (argvars[3].v_type != VAR_UNKNOWN)
7372 get_dict = (int)get_tv_number(&argvars[3]);
7373 }
7374 }
7375 else
7376 which = (char_u *)"";
7377 if (which == NULL)
7378 return;
7379
7380 mode = get_map_mode(&which, 0);
7381
7382 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7383 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7384 vim_free(keys_buf);
7385
7386 if (!get_dict)
7387 {
7388 /* Return a string. */
7389 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007390 {
7391 if (*rhs == NUL)
7392 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7393 else
7394 rettv->vval.v_string = str2special_save(rhs, FALSE);
7395 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396
7397 }
7398 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7399 {
7400 /* Return a dictionary. */
7401 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7402 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7403 dict_T *dict = rettv->vval.v_dict;
7404
7405 dict_add_nr_str(dict, "lhs", 0L, lhs);
7406 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7407 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7408 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7409 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7410 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7411 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7412 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7413 dict_add_nr_str(dict, "mode", 0L, mapmode);
7414
7415 vim_free(lhs);
7416 vim_free(mapmode);
7417 }
7418}
7419
7420#ifdef FEAT_FLOAT
7421/*
7422 * "log()" function
7423 */
7424 static void
7425f_log(typval_T *argvars, typval_T *rettv)
7426{
7427 float_T f = 0.0;
7428
7429 rettv->v_type = VAR_FLOAT;
7430 if (get_float_arg(argvars, &f) == OK)
7431 rettv->vval.v_float = log(f);
7432 else
7433 rettv->vval.v_float = 0.0;
7434}
7435
7436/*
7437 * "log10()" function
7438 */
7439 static void
7440f_log10(typval_T *argvars, typval_T *rettv)
7441{
7442 float_T f = 0.0;
7443
7444 rettv->v_type = VAR_FLOAT;
7445 if (get_float_arg(argvars, &f) == OK)
7446 rettv->vval.v_float = log10(f);
7447 else
7448 rettv->vval.v_float = 0.0;
7449}
7450#endif
7451
7452#ifdef FEAT_LUA
7453/*
7454 * "luaeval()" function
7455 */
7456 static void
7457f_luaeval(typval_T *argvars, typval_T *rettv)
7458{
7459 char_u *str;
7460 char_u buf[NUMBUFLEN];
7461
7462 str = get_tv_string_buf(&argvars[0], buf);
7463 do_luaeval(str, argvars + 1, rettv);
7464}
7465#endif
7466
7467/*
7468 * "map()" function
7469 */
7470 static void
7471f_map(typval_T *argvars, typval_T *rettv)
7472{
7473 filter_map(argvars, rettv, TRUE);
7474}
7475
7476/*
7477 * "maparg()" function
7478 */
7479 static void
7480f_maparg(typval_T *argvars, typval_T *rettv)
7481{
7482 get_maparg(argvars, rettv, TRUE);
7483}
7484
7485/*
7486 * "mapcheck()" function
7487 */
7488 static void
7489f_mapcheck(typval_T *argvars, typval_T *rettv)
7490{
7491 get_maparg(argvars, rettv, FALSE);
7492}
7493
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007494typedef enum
7495{
7496 MATCH_END, /* matchend() */
7497 MATCH_MATCH, /* match() */
7498 MATCH_STR, /* matchstr() */
7499 MATCH_LIST, /* matchlist() */
7500 MATCH_POS /* matchstrpos() */
7501} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502
7503 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007504find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007505{
7506 char_u *str = NULL;
7507 long len = 0;
7508 char_u *expr = NULL;
7509 char_u *pat;
7510 regmatch_T regmatch;
7511 char_u patbuf[NUMBUFLEN];
7512 char_u strbuf[NUMBUFLEN];
7513 char_u *save_cpo;
7514 long start = 0;
7515 long nth = 1;
7516 colnr_T startcol = 0;
7517 int match = 0;
7518 list_T *l = NULL;
7519 listitem_T *li = NULL;
7520 long idx = 0;
7521 char_u *tofree = NULL;
7522
7523 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7524 save_cpo = p_cpo;
7525 p_cpo = (char_u *)"";
7526
7527 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007528 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007530 /* type MATCH_LIST: return empty list when there are no matches.
7531 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 if (rettv_list_alloc(rettv) == FAIL)
7533 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007534 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007535 && (list_append_string(rettv->vval.v_list,
7536 (char_u *)"", 0) == FAIL
7537 || list_append_number(rettv->vval.v_list,
7538 (varnumber_T)-1) == FAIL
7539 || list_append_number(rettv->vval.v_list,
7540 (varnumber_T)-1) == FAIL
7541 || list_append_number(rettv->vval.v_list,
7542 (varnumber_T)-1) == FAIL))
7543 {
7544 list_free(rettv->vval.v_list);
7545 rettv->vval.v_list = NULL;
7546 goto theend;
7547 }
7548 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007549 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007550 {
7551 rettv->v_type = VAR_STRING;
7552 rettv->vval.v_string = NULL;
7553 }
7554
7555 if (argvars[0].v_type == VAR_LIST)
7556 {
7557 if ((l = argvars[0].vval.v_list) == NULL)
7558 goto theend;
7559 li = l->lv_first;
7560 }
7561 else
7562 {
7563 expr = str = get_tv_string(&argvars[0]);
7564 len = (long)STRLEN(str);
7565 }
7566
7567 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7568 if (pat == NULL)
7569 goto theend;
7570
7571 if (argvars[2].v_type != VAR_UNKNOWN)
7572 {
7573 int error = FALSE;
7574
7575 start = (long)get_tv_number_chk(&argvars[2], &error);
7576 if (error)
7577 goto theend;
7578 if (l != NULL)
7579 {
7580 li = list_find(l, start);
7581 if (li == NULL)
7582 goto theend;
7583 idx = l->lv_idx; /* use the cached index */
7584 }
7585 else
7586 {
7587 if (start < 0)
7588 start = 0;
7589 if (start > len)
7590 goto theend;
7591 /* When "count" argument is there ignore matches before "start",
7592 * otherwise skip part of the string. Differs when pattern is "^"
7593 * or "\<". */
7594 if (argvars[3].v_type != VAR_UNKNOWN)
7595 startcol = start;
7596 else
7597 {
7598 str += start;
7599 len -= start;
7600 }
7601 }
7602
7603 if (argvars[3].v_type != VAR_UNKNOWN)
7604 nth = (long)get_tv_number_chk(&argvars[3], &error);
7605 if (error)
7606 goto theend;
7607 }
7608
7609 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7610 if (regmatch.regprog != NULL)
7611 {
7612 regmatch.rm_ic = p_ic;
7613
7614 for (;;)
7615 {
7616 if (l != NULL)
7617 {
7618 if (li == NULL)
7619 {
7620 match = FALSE;
7621 break;
7622 }
7623 vim_free(tofree);
7624 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7625 if (str == NULL)
7626 break;
7627 }
7628
7629 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7630
7631 if (match && --nth <= 0)
7632 break;
7633 if (l == NULL && !match)
7634 break;
7635
7636 /* Advance to just after the match. */
7637 if (l != NULL)
7638 {
7639 li = li->li_next;
7640 ++idx;
7641 }
7642 else
7643 {
7644#ifdef FEAT_MBYTE
7645 startcol = (colnr_T)(regmatch.startp[0]
7646 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7647#else
7648 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7649#endif
7650 if (startcol > (colnr_T)len
7651 || str + startcol <= regmatch.startp[0])
7652 {
7653 match = FALSE;
7654 break;
7655 }
7656 }
7657 }
7658
7659 if (match)
7660 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007661 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007662 {
7663 listitem_T *li1 = rettv->vval.v_list->lv_first;
7664 listitem_T *li2 = li1->li_next;
7665 listitem_T *li3 = li2->li_next;
7666 listitem_T *li4 = li3->li_next;
7667
7668 vim_free(li1->li_tv.vval.v_string);
7669 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7670 (int)(regmatch.endp[0] - regmatch.startp[0]));
7671 li3->li_tv.vval.v_number =
7672 (varnumber_T)(regmatch.startp[0] - expr);
7673 li4->li_tv.vval.v_number =
7674 (varnumber_T)(regmatch.endp[0] - expr);
7675 if (l != NULL)
7676 li2->li_tv.vval.v_number = (varnumber_T)idx;
7677 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007678 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007679 {
7680 int i;
7681
7682 /* return list with matched string and submatches */
7683 for (i = 0; i < NSUBEXP; ++i)
7684 {
7685 if (regmatch.endp[i] == NULL)
7686 {
7687 if (list_append_string(rettv->vval.v_list,
7688 (char_u *)"", 0) == FAIL)
7689 break;
7690 }
7691 else if (list_append_string(rettv->vval.v_list,
7692 regmatch.startp[i],
7693 (int)(regmatch.endp[i] - regmatch.startp[i]))
7694 == FAIL)
7695 break;
7696 }
7697 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007698 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007699 {
7700 /* return matched string */
7701 if (l != NULL)
7702 copy_tv(&li->li_tv, rettv);
7703 else
7704 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7705 (int)(regmatch.endp[0] - regmatch.startp[0]));
7706 }
7707 else if (l != NULL)
7708 rettv->vval.v_number = idx;
7709 else
7710 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007711 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007712 rettv->vval.v_number =
7713 (varnumber_T)(regmatch.startp[0] - str);
7714 else
7715 rettv->vval.v_number =
7716 (varnumber_T)(regmatch.endp[0] - str);
7717 rettv->vval.v_number += (varnumber_T)(str - expr);
7718 }
7719 }
7720 vim_regfree(regmatch.regprog);
7721 }
7722
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007723theend:
7724 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725 /* matchstrpos() without a list: drop the second item. */
7726 listitem_remove(rettv->vval.v_list,
7727 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728 vim_free(tofree);
7729 p_cpo = save_cpo;
7730}
7731
7732/*
7733 * "match()" function
7734 */
7735 static void
7736f_match(typval_T *argvars, typval_T *rettv)
7737{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007738 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007739}
7740
7741/*
7742 * "matchadd()" function
7743 */
7744 static void
7745f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7746{
7747#ifdef FEAT_SEARCH_EXTRA
7748 char_u buf[NUMBUFLEN];
7749 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7750 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7751 int prio = 10; /* default priority */
7752 int id = -1;
7753 int error = FALSE;
7754 char_u *conceal_char = NULL;
7755
7756 rettv->vval.v_number = -1;
7757
7758 if (grp == NULL || pat == NULL)
7759 return;
7760 if (argvars[2].v_type != VAR_UNKNOWN)
7761 {
7762 prio = (int)get_tv_number_chk(&argvars[2], &error);
7763 if (argvars[3].v_type != VAR_UNKNOWN)
7764 {
7765 id = (int)get_tv_number_chk(&argvars[3], &error);
7766 if (argvars[4].v_type != VAR_UNKNOWN)
7767 {
7768 if (argvars[4].v_type != VAR_DICT)
7769 {
7770 EMSG(_(e_dictreq));
7771 return;
7772 }
7773 if (dict_find(argvars[4].vval.v_dict,
7774 (char_u *)"conceal", -1) != NULL)
7775 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7776 (char_u *)"conceal", FALSE);
7777 }
7778 }
7779 }
7780 if (error == TRUE)
7781 return;
7782 if (id >= 1 && id <= 3)
7783 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007784 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007785 return;
7786 }
7787
7788 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7789 conceal_char);
7790#endif
7791}
7792
7793/*
7794 * "matchaddpos()" function
7795 */
7796 static void
7797f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7798{
7799#ifdef FEAT_SEARCH_EXTRA
7800 char_u buf[NUMBUFLEN];
7801 char_u *group;
7802 int prio = 10;
7803 int id = -1;
7804 int error = FALSE;
7805 list_T *l;
7806 char_u *conceal_char = NULL;
7807
7808 rettv->vval.v_number = -1;
7809
7810 group = get_tv_string_buf_chk(&argvars[0], buf);
7811 if (group == NULL)
7812 return;
7813
7814 if (argvars[1].v_type != VAR_LIST)
7815 {
7816 EMSG2(_(e_listarg), "matchaddpos()");
7817 return;
7818 }
7819 l = argvars[1].vval.v_list;
7820 if (l == NULL)
7821 return;
7822
7823 if (argvars[2].v_type != VAR_UNKNOWN)
7824 {
7825 prio = (int)get_tv_number_chk(&argvars[2], &error);
7826 if (argvars[3].v_type != VAR_UNKNOWN)
7827 {
7828 id = (int)get_tv_number_chk(&argvars[3], &error);
7829 if (argvars[4].v_type != VAR_UNKNOWN)
7830 {
7831 if (argvars[4].v_type != VAR_DICT)
7832 {
7833 EMSG(_(e_dictreq));
7834 return;
7835 }
7836 if (dict_find(argvars[4].vval.v_dict,
7837 (char_u *)"conceal", -1) != NULL)
7838 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7839 (char_u *)"conceal", FALSE);
7840 }
7841 }
7842 }
7843 if (error == TRUE)
7844 return;
7845
7846 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7847 if (id == 1 || id == 2)
7848 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007849 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007850 return;
7851 }
7852
7853 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7854 conceal_char);
7855#endif
7856}
7857
7858/*
7859 * "matcharg()" function
7860 */
7861 static void
7862f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7863{
7864 if (rettv_list_alloc(rettv) == OK)
7865 {
7866#ifdef FEAT_SEARCH_EXTRA
7867 int id = (int)get_tv_number(&argvars[0]);
7868 matchitem_T *m;
7869
7870 if (id >= 1 && id <= 3)
7871 {
7872 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7873 {
7874 list_append_string(rettv->vval.v_list,
7875 syn_id2name(m->hlg_id), -1);
7876 list_append_string(rettv->vval.v_list, m->pattern, -1);
7877 }
7878 else
7879 {
7880 list_append_string(rettv->vval.v_list, NULL, -1);
7881 list_append_string(rettv->vval.v_list, NULL, -1);
7882 }
7883 }
7884#endif
7885 }
7886}
7887
7888/*
7889 * "matchdelete()" function
7890 */
7891 static void
7892f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7893{
7894#ifdef FEAT_SEARCH_EXTRA
7895 rettv->vval.v_number = match_delete(curwin,
7896 (int)get_tv_number(&argvars[0]), TRUE);
7897#endif
7898}
7899
7900/*
7901 * "matchend()" function
7902 */
7903 static void
7904f_matchend(typval_T *argvars, typval_T *rettv)
7905{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007906 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007907}
7908
7909/*
7910 * "matchlist()" function
7911 */
7912 static void
7913f_matchlist(typval_T *argvars, typval_T *rettv)
7914{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007915 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007916}
7917
7918/*
7919 * "matchstr()" function
7920 */
7921 static void
7922f_matchstr(typval_T *argvars, typval_T *rettv)
7923{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007924 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007925}
7926
7927/*
7928 * "matchstrpos()" function
7929 */
7930 static void
7931f_matchstrpos(typval_T *argvars, typval_T *rettv)
7932{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007933 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007934}
7935
7936static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7937
7938 static void
7939max_min(typval_T *argvars, typval_T *rettv, int domax)
7940{
7941 varnumber_T n = 0;
7942 varnumber_T i;
7943 int error = FALSE;
7944
7945 if (argvars[0].v_type == VAR_LIST)
7946 {
7947 list_T *l;
7948 listitem_T *li;
7949
7950 l = argvars[0].vval.v_list;
7951 if (l != NULL)
7952 {
7953 li = l->lv_first;
7954 if (li != NULL)
7955 {
7956 n = get_tv_number_chk(&li->li_tv, &error);
7957 for (;;)
7958 {
7959 li = li->li_next;
7960 if (li == NULL)
7961 break;
7962 i = get_tv_number_chk(&li->li_tv, &error);
7963 if (domax ? i > n : i < n)
7964 n = i;
7965 }
7966 }
7967 }
7968 }
7969 else if (argvars[0].v_type == VAR_DICT)
7970 {
7971 dict_T *d;
7972 int first = TRUE;
7973 hashitem_T *hi;
7974 int todo;
7975
7976 d = argvars[0].vval.v_dict;
7977 if (d != NULL)
7978 {
7979 todo = (int)d->dv_hashtab.ht_used;
7980 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7981 {
7982 if (!HASHITEM_EMPTY(hi))
7983 {
7984 --todo;
7985 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7986 if (first)
7987 {
7988 n = i;
7989 first = FALSE;
7990 }
7991 else if (domax ? i > n : i < n)
7992 n = i;
7993 }
7994 }
7995 }
7996 }
7997 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007998 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007999 rettv->vval.v_number = error ? 0 : n;
8000}
8001
8002/*
8003 * "max()" function
8004 */
8005 static void
8006f_max(typval_T *argvars, typval_T *rettv)
8007{
8008 max_min(argvars, rettv, TRUE);
8009}
8010
8011/*
8012 * "min()" function
8013 */
8014 static void
8015f_min(typval_T *argvars, typval_T *rettv)
8016{
8017 max_min(argvars, rettv, FALSE);
8018}
8019
8020static int mkdir_recurse(char_u *dir, int prot);
8021
8022/*
8023 * Create the directory in which "dir" is located, and higher levels when
8024 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008025 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008026 */
8027 static int
8028mkdir_recurse(char_u *dir, int prot)
8029{
8030 char_u *p;
8031 char_u *updir;
8032 int r = FAIL;
8033
8034 /* Get end of directory name in "dir".
8035 * We're done when it's "/" or "c:/". */
8036 p = gettail_sep(dir);
8037 if (p <= get_past_head(dir))
8038 return OK;
8039
8040 /* If the directory exists we're done. Otherwise: create it.*/
8041 updir = vim_strnsave(dir, (int)(p - dir));
8042 if (updir == NULL)
8043 return FAIL;
8044 if (mch_isdir(updir))
8045 r = OK;
8046 else if (mkdir_recurse(updir, prot) == OK)
8047 r = vim_mkdir_emsg(updir, prot);
8048 vim_free(updir);
8049 return r;
8050}
8051
8052#ifdef vim_mkdir
8053/*
8054 * "mkdir()" function
8055 */
8056 static void
8057f_mkdir(typval_T *argvars, typval_T *rettv)
8058{
8059 char_u *dir;
8060 char_u buf[NUMBUFLEN];
8061 int prot = 0755;
8062
8063 rettv->vval.v_number = FAIL;
8064 if (check_restricted() || check_secure())
8065 return;
8066
8067 dir = get_tv_string_buf(&argvars[0], buf);
8068 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008069 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008071 if (*gettail(dir) == NUL)
8072 /* remove trailing slashes */
8073 *gettail_sep(dir) = NUL;
8074
8075 if (argvars[1].v_type != VAR_UNKNOWN)
8076 {
8077 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008079 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8080 if (prot == -1)
8081 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008083 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8084 {
8085 if (mch_isdir(dir))
8086 {
8087 /* With the "p" flag it's OK if the dir already exists. */
8088 rettv->vval.v_number = OK;
8089 return;
8090 }
8091 mkdir_recurse(dir, prot);
8092 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008093 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008094 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095}
8096#endif
8097
8098/*
8099 * "mode()" function
8100 */
8101 static void
8102f_mode(typval_T *argvars, typval_T *rettv)
8103{
8104 char_u buf[3];
8105
8106 buf[1] = NUL;
8107 buf[2] = NUL;
8108
8109 if (time_for_testing == 93784)
8110 {
8111 /* Testing the two-character code. */
8112 buf[0] = 'x';
8113 buf[1] = '!';
8114 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008115#ifdef FEAT_TERMINAL
8116 else if (term_use_loop())
8117 buf[0] = 't';
8118#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119 else if (VIsual_active)
8120 {
8121 if (VIsual_select)
8122 buf[0] = VIsual_mode + 's' - 'v';
8123 else
8124 buf[0] = VIsual_mode;
8125 }
8126 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8127 || State == CONFIRM)
8128 {
8129 buf[0] = 'r';
8130 if (State == ASKMORE)
8131 buf[1] = 'm';
8132 else if (State == CONFIRM)
8133 buf[1] = '?';
8134 }
8135 else if (State == EXTERNCMD)
8136 buf[0] = '!';
8137 else if (State & INSERT)
8138 {
8139#ifdef FEAT_VREPLACE
8140 if (State & VREPLACE_FLAG)
8141 {
8142 buf[0] = 'R';
8143 buf[1] = 'v';
8144 }
8145 else
8146#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01008147 {
8148 if (State & REPLACE_FLAG)
8149 buf[0] = 'R';
8150 else
8151 buf[0] = 'i';
8152#ifdef FEAT_INS_EXPAND
8153 if (ins_compl_active())
8154 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008155 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008156 buf[1] = 'x';
8157#endif
8158 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008160 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161 {
8162 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008163 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008165 else if (exmode_active == EXMODE_NORMAL)
8166 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167 }
8168 else
8169 {
8170 buf[0] = 'n';
8171 if (finish_op)
8172 buf[1] = 'o';
8173 }
8174
8175 /* Clear out the minor mode when the argument is not a non-zero number or
8176 * non-empty string. */
8177 if (!non_zero_arg(&argvars[0]))
8178 buf[1] = NUL;
8179
8180 rettv->vval.v_string = vim_strsave(buf);
8181 rettv->v_type = VAR_STRING;
8182}
8183
8184#if defined(FEAT_MZSCHEME) || defined(PROTO)
8185/*
8186 * "mzeval()" function
8187 */
8188 static void
8189f_mzeval(typval_T *argvars, typval_T *rettv)
8190{
8191 char_u *str;
8192 char_u buf[NUMBUFLEN];
8193
8194 str = get_tv_string_buf(&argvars[0], buf);
8195 do_mzeval(str, rettv);
8196}
8197
8198 void
8199mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8200{
8201 typval_T argvars[3];
8202
8203 argvars[0].v_type = VAR_STRING;
8204 argvars[0].vval.v_string = name;
8205 copy_tv(args, &argvars[1]);
8206 argvars[2].v_type = VAR_UNKNOWN;
8207 f_call(argvars, rettv);
8208 clear_tv(&argvars[1]);
8209}
8210#endif
8211
8212/*
8213 * "nextnonblank()" function
8214 */
8215 static void
8216f_nextnonblank(typval_T *argvars, typval_T *rettv)
8217{
8218 linenr_T lnum;
8219
8220 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8221 {
8222 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8223 {
8224 lnum = 0;
8225 break;
8226 }
8227 if (*skipwhite(ml_get(lnum)) != NUL)
8228 break;
8229 }
8230 rettv->vval.v_number = lnum;
8231}
8232
8233/*
8234 * "nr2char()" function
8235 */
8236 static void
8237f_nr2char(typval_T *argvars, typval_T *rettv)
8238{
8239 char_u buf[NUMBUFLEN];
8240
8241#ifdef FEAT_MBYTE
8242 if (has_mbyte)
8243 {
8244 int utf8 = 0;
8245
8246 if (argvars[1].v_type != VAR_UNKNOWN)
8247 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8248 if (utf8)
8249 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8250 else
8251 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8252 }
8253 else
8254#endif
8255 {
8256 buf[0] = (char_u)get_tv_number(&argvars[0]);
8257 buf[1] = NUL;
8258 }
8259 rettv->v_type = VAR_STRING;
8260 rettv->vval.v_string = vim_strsave(buf);
8261}
8262
8263/*
8264 * "or(expr, expr)" function
8265 */
8266 static void
8267f_or(typval_T *argvars, typval_T *rettv)
8268{
8269 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8270 | get_tv_number_chk(&argvars[1], NULL);
8271}
8272
8273/*
8274 * "pathshorten()" function
8275 */
8276 static void
8277f_pathshorten(typval_T *argvars, typval_T *rettv)
8278{
8279 char_u *p;
8280
8281 rettv->v_type = VAR_STRING;
8282 p = get_tv_string_chk(&argvars[0]);
8283 if (p == NULL)
8284 rettv->vval.v_string = NULL;
8285 else
8286 {
8287 p = vim_strsave(p);
8288 rettv->vval.v_string = p;
8289 if (p != NULL)
8290 shorten_dir(p);
8291 }
8292}
8293
8294#ifdef FEAT_PERL
8295/*
8296 * "perleval()" function
8297 */
8298 static void
8299f_perleval(typval_T *argvars, typval_T *rettv)
8300{
8301 char_u *str;
8302 char_u buf[NUMBUFLEN];
8303
8304 str = get_tv_string_buf(&argvars[0], buf);
8305 do_perleval(str, rettv);
8306}
8307#endif
8308
8309#ifdef FEAT_FLOAT
8310/*
8311 * "pow()" function
8312 */
8313 static void
8314f_pow(typval_T *argvars, typval_T *rettv)
8315{
8316 float_T fx = 0.0, fy = 0.0;
8317
8318 rettv->v_type = VAR_FLOAT;
8319 if (get_float_arg(argvars, &fx) == OK
8320 && get_float_arg(&argvars[1], &fy) == OK)
8321 rettv->vval.v_float = pow(fx, fy);
8322 else
8323 rettv->vval.v_float = 0.0;
8324}
8325#endif
8326
8327/*
8328 * "prevnonblank()" function
8329 */
8330 static void
8331f_prevnonblank(typval_T *argvars, typval_T *rettv)
8332{
8333 linenr_T lnum;
8334
8335 lnum = get_tv_lnum(argvars);
8336 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8337 lnum = 0;
8338 else
8339 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8340 --lnum;
8341 rettv->vval.v_number = lnum;
8342}
8343
8344/* This dummy va_list is here because:
8345 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8346 * - locally in the function results in a "used before set" warning
8347 * - using va_start() to initialize it gives "function with fixed args" error */
8348static va_list ap;
8349
8350/*
8351 * "printf()" function
8352 */
8353 static void
8354f_printf(typval_T *argvars, typval_T *rettv)
8355{
8356 char_u buf[NUMBUFLEN];
8357 int len;
8358 char_u *s;
8359 int saved_did_emsg = did_emsg;
8360 char *fmt;
8361
8362 rettv->v_type = VAR_STRING;
8363 rettv->vval.v_string = NULL;
8364
8365 /* Get the required length, allocate the buffer and do it for real. */
8366 did_emsg = FALSE;
8367 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008368 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 if (!did_emsg)
8370 {
8371 s = alloc(len + 1);
8372 if (s != NULL)
8373 {
8374 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008375 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8376 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008377 }
8378 }
8379 did_emsg |= saved_did_emsg;
8380}
8381
8382/*
8383 * "pumvisible()" function
8384 */
8385 static void
8386f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8387{
8388#ifdef FEAT_INS_EXPAND
8389 if (pum_visible())
8390 rettv->vval.v_number = 1;
8391#endif
8392}
8393
8394#ifdef FEAT_PYTHON3
8395/*
8396 * "py3eval()" function
8397 */
8398 static void
8399f_py3eval(typval_T *argvars, typval_T *rettv)
8400{
8401 char_u *str;
8402 char_u buf[NUMBUFLEN];
8403
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008404 if (p_pyx == 0)
8405 p_pyx = 3;
8406
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008407 str = get_tv_string_buf(&argvars[0], buf);
8408 do_py3eval(str, rettv);
8409}
8410#endif
8411
8412#ifdef FEAT_PYTHON
8413/*
8414 * "pyeval()" function
8415 */
8416 static void
8417f_pyeval(typval_T *argvars, typval_T *rettv)
8418{
8419 char_u *str;
8420 char_u buf[NUMBUFLEN];
8421
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008422 if (p_pyx == 0)
8423 p_pyx = 2;
8424
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008425 str = get_tv_string_buf(&argvars[0], buf);
8426 do_pyeval(str, rettv);
8427}
8428#endif
8429
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008430#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8431/*
8432 * "pyxeval()" function
8433 */
8434 static void
8435f_pyxeval(typval_T *argvars, typval_T *rettv)
8436{
8437# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8438 init_pyxversion();
8439 if (p_pyx == 2)
8440 f_pyeval(argvars, rettv);
8441 else
8442 f_py3eval(argvars, rettv);
8443# elif defined(FEAT_PYTHON)
8444 f_pyeval(argvars, rettv);
8445# elif defined(FEAT_PYTHON3)
8446 f_py3eval(argvars, rettv);
8447# endif
8448}
8449#endif
8450
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008451/*
8452 * "range()" function
8453 */
8454 static void
8455f_range(typval_T *argvars, typval_T *rettv)
8456{
8457 varnumber_T start;
8458 varnumber_T end;
8459 varnumber_T stride = 1;
8460 varnumber_T i;
8461 int error = FALSE;
8462
8463 start = get_tv_number_chk(&argvars[0], &error);
8464 if (argvars[1].v_type == VAR_UNKNOWN)
8465 {
8466 end = start - 1;
8467 start = 0;
8468 }
8469 else
8470 {
8471 end = get_tv_number_chk(&argvars[1], &error);
8472 if (argvars[2].v_type != VAR_UNKNOWN)
8473 stride = get_tv_number_chk(&argvars[2], &error);
8474 }
8475
8476 if (error)
8477 return; /* type error; errmsg already given */
8478 if (stride == 0)
8479 EMSG(_("E726: Stride is zero"));
8480 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8481 EMSG(_("E727: Start past end"));
8482 else
8483 {
8484 if (rettv_list_alloc(rettv) == OK)
8485 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8486 if (list_append_number(rettv->vval.v_list,
8487 (varnumber_T)i) == FAIL)
8488 break;
8489 }
8490}
8491
8492/*
8493 * "readfile()" function
8494 */
8495 static void
8496f_readfile(typval_T *argvars, typval_T *rettv)
8497{
8498 int binary = FALSE;
8499 int failed = FALSE;
8500 char_u *fname;
8501 FILE *fd;
8502 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8503 int io_size = sizeof(buf);
8504 int readlen; /* size of last fread() */
8505 char_u *prev = NULL; /* previously read bytes, if any */
8506 long prevlen = 0; /* length of data in prev */
8507 long prevsize = 0; /* size of prev buffer */
8508 long maxline = MAXLNUM;
8509 long cnt = 0;
8510 char_u *p; /* position in buf */
8511 char_u *start; /* start of current line */
8512
8513 if (argvars[1].v_type != VAR_UNKNOWN)
8514 {
8515 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8516 binary = TRUE;
8517 if (argvars[2].v_type != VAR_UNKNOWN)
8518 maxline = (long)get_tv_number(&argvars[2]);
8519 }
8520
8521 if (rettv_list_alloc(rettv) == FAIL)
8522 return;
8523
8524 /* Always open the file in binary mode, library functions have a mind of
8525 * their own about CR-LF conversion. */
8526 fname = get_tv_string(&argvars[0]);
8527 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8528 {
8529 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8530 return;
8531 }
8532
8533 while (cnt < maxline || maxline < 0)
8534 {
8535 readlen = (int)fread(buf, 1, io_size, fd);
8536
8537 /* This for loop processes what was read, but is also entered at end
8538 * of file so that either:
8539 * - an incomplete line gets written
8540 * - a "binary" file gets an empty line at the end if it ends in a
8541 * newline. */
8542 for (p = buf, start = buf;
8543 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8544 ++p)
8545 {
8546 if (*p == '\n' || readlen <= 0)
8547 {
8548 listitem_T *li;
8549 char_u *s = NULL;
8550 long_u len = p - start;
8551
8552 /* Finished a line. Remove CRs before NL. */
8553 if (readlen > 0 && !binary)
8554 {
8555 while (len > 0 && start[len - 1] == '\r')
8556 --len;
8557 /* removal may cross back to the "prev" string */
8558 if (len == 0)
8559 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8560 --prevlen;
8561 }
8562 if (prevlen == 0)
8563 s = vim_strnsave(start, (int)len);
8564 else
8565 {
8566 /* Change "prev" buffer to be the right size. This way
8567 * the bytes are only copied once, and very long lines are
8568 * allocated only once. */
8569 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8570 {
8571 mch_memmove(s + prevlen, start, len);
8572 s[prevlen + len] = NUL;
8573 prev = NULL; /* the list will own the string */
8574 prevlen = prevsize = 0;
8575 }
8576 }
8577 if (s == NULL)
8578 {
8579 do_outofmem_msg((long_u) prevlen + len + 1);
8580 failed = TRUE;
8581 break;
8582 }
8583
8584 if ((li = listitem_alloc()) == NULL)
8585 {
8586 vim_free(s);
8587 failed = TRUE;
8588 break;
8589 }
8590 li->li_tv.v_type = VAR_STRING;
8591 li->li_tv.v_lock = 0;
8592 li->li_tv.vval.v_string = s;
8593 list_append(rettv->vval.v_list, li);
8594
8595 start = p + 1; /* step over newline */
8596 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8597 break;
8598 }
8599 else if (*p == NUL)
8600 *p = '\n';
8601#ifdef FEAT_MBYTE
8602 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8603 * when finding the BF and check the previous two bytes. */
8604 else if (*p == 0xbf && enc_utf8 && !binary)
8605 {
8606 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8607 * + 1, these may be in the "prev" string. */
8608 char_u back1 = p >= buf + 1 ? p[-1]
8609 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8610 char_u back2 = p >= buf + 2 ? p[-2]
8611 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8612 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8613
8614 if (back2 == 0xef && back1 == 0xbb)
8615 {
8616 char_u *dest = p - 2;
8617
8618 /* Usually a BOM is at the beginning of a file, and so at
8619 * the beginning of a line; then we can just step over it.
8620 */
8621 if (start == dest)
8622 start = p + 1;
8623 else
8624 {
8625 /* have to shuffle buf to close gap */
8626 int adjust_prevlen = 0;
8627
8628 if (dest < buf)
8629 {
8630 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8631 dest = buf;
8632 }
8633 if (readlen > p - buf + 1)
8634 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8635 readlen -= 3 - adjust_prevlen;
8636 prevlen -= adjust_prevlen;
8637 p = dest - 1;
8638 }
8639 }
8640 }
8641#endif
8642 } /* for */
8643
8644 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8645 break;
8646 if (start < p)
8647 {
8648 /* There's part of a line in buf, store it in "prev". */
8649 if (p - start + prevlen >= prevsize)
8650 {
8651 /* need bigger "prev" buffer */
8652 char_u *newprev;
8653
8654 /* A common use case is ordinary text files and "prev" gets a
8655 * fragment of a line, so the first allocation is made
8656 * small, to avoid repeatedly 'allocing' large and
8657 * 'reallocing' small. */
8658 if (prevsize == 0)
8659 prevsize = (long)(p - start);
8660 else
8661 {
8662 long grow50pc = (prevsize * 3) / 2;
8663 long growmin = (long)((p - start) * 2 + prevlen);
8664 prevsize = grow50pc > growmin ? grow50pc : growmin;
8665 }
8666 newprev = prev == NULL ? alloc(prevsize)
8667 : vim_realloc(prev, prevsize);
8668 if (newprev == NULL)
8669 {
8670 do_outofmem_msg((long_u)prevsize);
8671 failed = TRUE;
8672 break;
8673 }
8674 prev = newprev;
8675 }
8676 /* Add the line part to end of "prev". */
8677 mch_memmove(prev + prevlen, start, p - start);
8678 prevlen += (long)(p - start);
8679 }
8680 } /* while */
8681
8682 /*
8683 * For a negative line count use only the lines at the end of the file,
8684 * free the rest.
8685 */
8686 if (!failed && maxline < 0)
8687 while (cnt > -maxline)
8688 {
8689 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8690 --cnt;
8691 }
8692
8693 if (failed)
8694 {
8695 list_free(rettv->vval.v_list);
8696 /* readfile doc says an empty list is returned on error */
8697 rettv->vval.v_list = list_alloc();
8698 }
8699
8700 vim_free(prev);
8701 fclose(fd);
8702}
8703
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008704 static void
8705return_register(int regname, typval_T *rettv)
8706{
8707 char_u buf[2] = {0, 0};
8708
8709 buf[0] = (char_u)regname;
8710 rettv->v_type = VAR_STRING;
8711 rettv->vval.v_string = vim_strsave(buf);
8712}
8713
8714/*
8715 * "reg_executing()" function
8716 */
8717 static void
8718f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8719{
8720 return_register(reg_executing, rettv);
8721}
8722
8723/*
8724 * "reg_recording()" function
8725 */
8726 static void
8727f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8728{
8729 return_register(reg_recording, rettv);
8730}
8731
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008732#if defined(FEAT_RELTIME)
8733static int list2proftime(typval_T *arg, proftime_T *tm);
8734
8735/*
8736 * Convert a List to proftime_T.
8737 * Return FAIL when there is something wrong.
8738 */
8739 static int
8740list2proftime(typval_T *arg, proftime_T *tm)
8741{
8742 long n1, n2;
8743 int error = FALSE;
8744
8745 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8746 || arg->vval.v_list->lv_len != 2)
8747 return FAIL;
8748 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8749 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8750# ifdef WIN3264
8751 tm->HighPart = n1;
8752 tm->LowPart = n2;
8753# else
8754 tm->tv_sec = n1;
8755 tm->tv_usec = n2;
8756# endif
8757 return error ? FAIL : OK;
8758}
8759#endif /* FEAT_RELTIME */
8760
8761/*
8762 * "reltime()" function
8763 */
8764 static void
8765f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8766{
8767#ifdef FEAT_RELTIME
8768 proftime_T res;
8769 proftime_T start;
8770
8771 if (argvars[0].v_type == VAR_UNKNOWN)
8772 {
8773 /* No arguments: get current time. */
8774 profile_start(&res);
8775 }
8776 else if (argvars[1].v_type == VAR_UNKNOWN)
8777 {
8778 if (list2proftime(&argvars[0], &res) == FAIL)
8779 return;
8780 profile_end(&res);
8781 }
8782 else
8783 {
8784 /* Two arguments: compute the difference. */
8785 if (list2proftime(&argvars[0], &start) == FAIL
8786 || list2proftime(&argvars[1], &res) == FAIL)
8787 return;
8788 profile_sub(&res, &start);
8789 }
8790
8791 if (rettv_list_alloc(rettv) == OK)
8792 {
8793 long n1, n2;
8794
8795# ifdef WIN3264
8796 n1 = res.HighPart;
8797 n2 = res.LowPart;
8798# else
8799 n1 = res.tv_sec;
8800 n2 = res.tv_usec;
8801# endif
8802 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8803 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8804 }
8805#endif
8806}
8807
8808#ifdef FEAT_FLOAT
8809/*
8810 * "reltimefloat()" function
8811 */
8812 static void
8813f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8814{
8815# ifdef FEAT_RELTIME
8816 proftime_T tm;
8817# endif
8818
8819 rettv->v_type = VAR_FLOAT;
8820 rettv->vval.v_float = 0;
8821# ifdef FEAT_RELTIME
8822 if (list2proftime(&argvars[0], &tm) == OK)
8823 rettv->vval.v_float = profile_float(&tm);
8824# endif
8825}
8826#endif
8827
8828/*
8829 * "reltimestr()" function
8830 */
8831 static void
8832f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8833{
8834#ifdef FEAT_RELTIME
8835 proftime_T tm;
8836#endif
8837
8838 rettv->v_type = VAR_STRING;
8839 rettv->vval.v_string = NULL;
8840#ifdef FEAT_RELTIME
8841 if (list2proftime(&argvars[0], &tm) == OK)
8842 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8843#endif
8844}
8845
8846#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8847static void make_connection(void);
8848static int check_connection(void);
8849
8850 static void
8851make_connection(void)
8852{
8853 if (X_DISPLAY == NULL
8854# ifdef FEAT_GUI
8855 && !gui.in_use
8856# endif
8857 )
8858 {
8859 x_force_connect = TRUE;
8860 setup_term_clip();
8861 x_force_connect = FALSE;
8862 }
8863}
8864
8865 static int
8866check_connection(void)
8867{
8868 make_connection();
8869 if (X_DISPLAY == NULL)
8870 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008871 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008872 return FAIL;
8873 }
8874 return OK;
8875}
8876#endif
8877
8878#ifdef FEAT_CLIENTSERVER
8879 static void
8880remote_common(typval_T *argvars, typval_T *rettv, int expr)
8881{
8882 char_u *server_name;
8883 char_u *keys;
8884 char_u *r = NULL;
8885 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008886 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008887# ifdef WIN32
8888 HWND w;
8889# else
8890 Window w;
8891# endif
8892
8893 if (check_restricted() || check_secure())
8894 return;
8895
8896# ifdef FEAT_X11
8897 if (check_connection() == FAIL)
8898 return;
8899# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008900 if (argvars[2].v_type != VAR_UNKNOWN
8901 && argvars[3].v_type != VAR_UNKNOWN)
8902 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008903
8904 server_name = get_tv_string_chk(&argvars[0]);
8905 if (server_name == NULL)
8906 return; /* type error; errmsg already given */
8907 keys = get_tv_string_buf(&argvars[1], buf);
8908# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008909 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008910# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008911 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8912 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008913# endif
8914 {
8915 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008916 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008917 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008918 vim_free(r);
8919 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008920 else
8921 EMSG2(_("E241: Unable to send to %s"), server_name);
8922 return;
8923 }
8924
8925 rettv->vval.v_string = r;
8926
8927 if (argvars[2].v_type != VAR_UNKNOWN)
8928 {
8929 dictitem_T v;
8930 char_u str[30];
8931 char_u *idvar;
8932
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008933 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008934 if (idvar != NULL && *idvar != NUL)
8935 {
8936 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8937 v.di_tv.v_type = VAR_STRING;
8938 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008939 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008940 vim_free(v.di_tv.vval.v_string);
8941 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008942 }
8943}
8944#endif
8945
8946/*
8947 * "remote_expr()" function
8948 */
8949 static void
8950f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8951{
8952 rettv->v_type = VAR_STRING;
8953 rettv->vval.v_string = NULL;
8954#ifdef FEAT_CLIENTSERVER
8955 remote_common(argvars, rettv, TRUE);
8956#endif
8957}
8958
8959/*
8960 * "remote_foreground()" function
8961 */
8962 static void
8963f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8964{
8965#ifdef FEAT_CLIENTSERVER
8966# ifdef WIN32
8967 /* On Win32 it's done in this application. */
8968 {
8969 char_u *server_name = get_tv_string_chk(&argvars[0]);
8970
8971 if (server_name != NULL)
8972 serverForeground(server_name);
8973 }
8974# else
8975 /* Send a foreground() expression to the server. */
8976 argvars[1].v_type = VAR_STRING;
8977 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8978 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008979 rettv->v_type = VAR_STRING;
8980 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008981 remote_common(argvars, rettv, TRUE);
8982 vim_free(argvars[1].vval.v_string);
8983# endif
8984#endif
8985}
8986
8987 static void
8988f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8989{
8990#ifdef FEAT_CLIENTSERVER
8991 dictitem_T v;
8992 char_u *s = NULL;
8993# ifdef WIN32
8994 long_u n = 0;
8995# endif
8996 char_u *serverid;
8997
8998 if (check_restricted() || check_secure())
8999 {
9000 rettv->vval.v_number = -1;
9001 return;
9002 }
9003 serverid = get_tv_string_chk(&argvars[0]);
9004 if (serverid == NULL)
9005 {
9006 rettv->vval.v_number = -1;
9007 return; /* type error; errmsg already given */
9008 }
9009# ifdef WIN32
9010 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9011 if (n == 0)
9012 rettv->vval.v_number = -1;
9013 else
9014 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009015 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009016 rettv->vval.v_number = (s != NULL);
9017 }
9018# else
9019 if (check_connection() == FAIL)
9020 return;
9021
9022 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9023 serverStrToWin(serverid), &s);
9024# endif
9025
9026 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9027 {
9028 char_u *retvar;
9029
9030 v.di_tv.v_type = VAR_STRING;
9031 v.di_tv.vval.v_string = vim_strsave(s);
9032 retvar = get_tv_string_chk(&argvars[1]);
9033 if (retvar != NULL)
9034 set_var(retvar, &v.di_tv, FALSE);
9035 vim_free(v.di_tv.vval.v_string);
9036 }
9037#else
9038 rettv->vval.v_number = -1;
9039#endif
9040}
9041
9042 static void
9043f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9044{
9045 char_u *r = NULL;
9046
9047#ifdef FEAT_CLIENTSERVER
9048 char_u *serverid = get_tv_string_chk(&argvars[0]);
9049
9050 if (serverid != NULL && !check_restricted() && !check_secure())
9051 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009052 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009053# ifdef WIN32
9054 /* The server's HWND is encoded in the 'id' parameter */
9055 long_u n = 0;
9056# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009057
9058 if (argvars[1].v_type != VAR_UNKNOWN)
9059 timeout = get_tv_number(&argvars[1]);
9060
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009061# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009062 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9063 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009064 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009065 if (r == NULL)
9066# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009067 if (check_connection() == FAIL
9068 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9069 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009070# endif
9071 EMSG(_("E277: Unable to read a server reply"));
9072 }
9073#endif
9074 rettv->v_type = VAR_STRING;
9075 rettv->vval.v_string = r;
9076}
9077
9078/*
9079 * "remote_send()" function
9080 */
9081 static void
9082f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9083{
9084 rettv->v_type = VAR_STRING;
9085 rettv->vval.v_string = NULL;
9086#ifdef FEAT_CLIENTSERVER
9087 remote_common(argvars, rettv, FALSE);
9088#endif
9089}
9090
9091/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009092 * "remote_startserver()" function
9093 */
9094 static void
9095f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9096{
9097#ifdef FEAT_CLIENTSERVER
9098 char_u *server = get_tv_string_chk(&argvars[0]);
9099
9100 if (server == NULL)
9101 return; /* type error; errmsg already given */
9102 if (serverName != NULL)
9103 EMSG(_("E941: already started a server"));
9104 else
9105 {
9106# ifdef FEAT_X11
9107 if (check_connection() == OK)
9108 serverRegisterName(X_DISPLAY, server);
9109# else
9110 serverSetName(server);
9111# endif
9112 }
9113#else
9114 EMSG(_("E942: +clientserver feature not available"));
9115#endif
9116}
9117
9118/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009119 * "remove()" function
9120 */
9121 static void
9122f_remove(typval_T *argvars, typval_T *rettv)
9123{
9124 list_T *l;
9125 listitem_T *item, *item2;
9126 listitem_T *li;
9127 long idx;
9128 long end;
9129 char_u *key;
9130 dict_T *d;
9131 dictitem_T *di;
9132 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9133
9134 if (argvars[0].v_type == VAR_DICT)
9135 {
9136 if (argvars[2].v_type != VAR_UNKNOWN)
9137 EMSG2(_(e_toomanyarg), "remove()");
9138 else if ((d = argvars[0].vval.v_dict) != NULL
9139 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9140 {
9141 key = get_tv_string_chk(&argvars[1]);
9142 if (key != NULL)
9143 {
9144 di = dict_find(d, key, -1);
9145 if (di == NULL)
9146 EMSG2(_(e_dictkey), key);
9147 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9148 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9149 {
9150 *rettv = di->di_tv;
9151 init_tv(&di->di_tv);
9152 dictitem_remove(d, di);
9153 }
9154 }
9155 }
9156 }
9157 else if (argvars[0].v_type != VAR_LIST)
9158 EMSG2(_(e_listdictarg), "remove()");
9159 else if ((l = argvars[0].vval.v_list) != NULL
9160 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9161 {
9162 int error = FALSE;
9163
9164 idx = (long)get_tv_number_chk(&argvars[1], &error);
9165 if (error)
9166 ; /* type error: do nothing, errmsg already given */
9167 else if ((item = list_find(l, idx)) == NULL)
9168 EMSGN(_(e_listidx), idx);
9169 else
9170 {
9171 if (argvars[2].v_type == VAR_UNKNOWN)
9172 {
9173 /* Remove one item, return its value. */
9174 vimlist_remove(l, item, item);
9175 *rettv = item->li_tv;
9176 vim_free(item);
9177 }
9178 else
9179 {
9180 /* Remove range of items, return list with values. */
9181 end = (long)get_tv_number_chk(&argvars[2], &error);
9182 if (error)
9183 ; /* type error: do nothing */
9184 else if ((item2 = list_find(l, end)) == NULL)
9185 EMSGN(_(e_listidx), end);
9186 else
9187 {
9188 int cnt = 0;
9189
9190 for (li = item; li != NULL; li = li->li_next)
9191 {
9192 ++cnt;
9193 if (li == item2)
9194 break;
9195 }
9196 if (li == NULL) /* didn't find "item2" after "item" */
9197 EMSG(_(e_invrange));
9198 else
9199 {
9200 vimlist_remove(l, item, item2);
9201 if (rettv_list_alloc(rettv) == OK)
9202 {
9203 l = rettv->vval.v_list;
9204 l->lv_first = item;
9205 l->lv_last = item2;
9206 item->li_prev = NULL;
9207 item2->li_next = NULL;
9208 l->lv_len = cnt;
9209 }
9210 }
9211 }
9212 }
9213 }
9214 }
9215}
9216
9217/*
9218 * "rename({from}, {to})" function
9219 */
9220 static void
9221f_rename(typval_T *argvars, typval_T *rettv)
9222{
9223 char_u buf[NUMBUFLEN];
9224
9225 if (check_restricted() || check_secure())
9226 rettv->vval.v_number = -1;
9227 else
9228 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9229 get_tv_string_buf(&argvars[1], buf));
9230}
9231
9232/*
9233 * "repeat()" function
9234 */
9235 static void
9236f_repeat(typval_T *argvars, typval_T *rettv)
9237{
9238 char_u *p;
9239 int n;
9240 int slen;
9241 int len;
9242 char_u *r;
9243 int i;
9244
9245 n = (int)get_tv_number(&argvars[1]);
9246 if (argvars[0].v_type == VAR_LIST)
9247 {
9248 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9249 while (n-- > 0)
9250 if (list_extend(rettv->vval.v_list,
9251 argvars[0].vval.v_list, NULL) == FAIL)
9252 break;
9253 }
9254 else
9255 {
9256 p = get_tv_string(&argvars[0]);
9257 rettv->v_type = VAR_STRING;
9258 rettv->vval.v_string = NULL;
9259
9260 slen = (int)STRLEN(p);
9261 len = slen * n;
9262 if (len <= 0)
9263 return;
9264
9265 r = alloc(len + 1);
9266 if (r != NULL)
9267 {
9268 for (i = 0; i < n; i++)
9269 mch_memmove(r + i * slen, p, (size_t)slen);
9270 r[len] = NUL;
9271 }
9272
9273 rettv->vval.v_string = r;
9274 }
9275}
9276
9277/*
9278 * "resolve()" function
9279 */
9280 static void
9281f_resolve(typval_T *argvars, typval_T *rettv)
9282{
9283 char_u *p;
9284#ifdef HAVE_READLINK
9285 char_u *buf = NULL;
9286#endif
9287
9288 p = get_tv_string(&argvars[0]);
9289#ifdef FEAT_SHORTCUT
9290 {
9291 char_u *v = NULL;
9292
9293 v = mch_resolve_shortcut(p);
9294 if (v != NULL)
9295 rettv->vval.v_string = v;
9296 else
9297 rettv->vval.v_string = vim_strsave(p);
9298 }
9299#else
9300# ifdef HAVE_READLINK
9301 {
9302 char_u *cpy;
9303 int len;
9304 char_u *remain = NULL;
9305 char_u *q;
9306 int is_relative_to_current = FALSE;
9307 int has_trailing_pathsep = FALSE;
9308 int limit = 100;
9309
9310 p = vim_strsave(p);
9311
9312 if (p[0] == '.' && (vim_ispathsep(p[1])
9313 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9314 is_relative_to_current = TRUE;
9315
9316 len = STRLEN(p);
9317 if (len > 0 && after_pathsep(p, p + len))
9318 {
9319 has_trailing_pathsep = TRUE;
9320 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9321 }
9322
9323 q = getnextcomp(p);
9324 if (*q != NUL)
9325 {
9326 /* Separate the first path component in "p", and keep the
9327 * remainder (beginning with the path separator). */
9328 remain = vim_strsave(q - 1);
9329 q[-1] = NUL;
9330 }
9331
9332 buf = alloc(MAXPATHL + 1);
9333 if (buf == NULL)
9334 goto fail;
9335
9336 for (;;)
9337 {
9338 for (;;)
9339 {
9340 len = readlink((char *)p, (char *)buf, MAXPATHL);
9341 if (len <= 0)
9342 break;
9343 buf[len] = NUL;
9344
9345 if (limit-- == 0)
9346 {
9347 vim_free(p);
9348 vim_free(remain);
9349 EMSG(_("E655: Too many symbolic links (cycle?)"));
9350 rettv->vval.v_string = NULL;
9351 goto fail;
9352 }
9353
9354 /* Ensure that the result will have a trailing path separator
9355 * if the argument has one. */
9356 if (remain == NULL && has_trailing_pathsep)
9357 add_pathsep(buf);
9358
9359 /* Separate the first path component in the link value and
9360 * concatenate the remainders. */
9361 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9362 if (*q != NUL)
9363 {
9364 if (remain == NULL)
9365 remain = vim_strsave(q - 1);
9366 else
9367 {
9368 cpy = concat_str(q - 1, remain);
9369 if (cpy != NULL)
9370 {
9371 vim_free(remain);
9372 remain = cpy;
9373 }
9374 }
9375 q[-1] = NUL;
9376 }
9377
9378 q = gettail(p);
9379 if (q > p && *q == NUL)
9380 {
9381 /* Ignore trailing path separator. */
9382 q[-1] = NUL;
9383 q = gettail(p);
9384 }
9385 if (q > p && !mch_isFullName(buf))
9386 {
9387 /* symlink is relative to directory of argument */
9388 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9389 if (cpy != NULL)
9390 {
9391 STRCPY(cpy, p);
9392 STRCPY(gettail(cpy), buf);
9393 vim_free(p);
9394 p = cpy;
9395 }
9396 }
9397 else
9398 {
9399 vim_free(p);
9400 p = vim_strsave(buf);
9401 }
9402 }
9403
9404 if (remain == NULL)
9405 break;
9406
9407 /* Append the first path component of "remain" to "p". */
9408 q = getnextcomp(remain + 1);
9409 len = q - remain - (*q != NUL);
9410 cpy = vim_strnsave(p, STRLEN(p) + len);
9411 if (cpy != NULL)
9412 {
9413 STRNCAT(cpy, remain, len);
9414 vim_free(p);
9415 p = cpy;
9416 }
9417 /* Shorten "remain". */
9418 if (*q != NUL)
9419 STRMOVE(remain, q - 1);
9420 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009421 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009422 }
9423
9424 /* If the result is a relative path name, make it explicitly relative to
9425 * the current directory if and only if the argument had this form. */
9426 if (!vim_ispathsep(*p))
9427 {
9428 if (is_relative_to_current
9429 && *p != NUL
9430 && !(p[0] == '.'
9431 && (p[1] == NUL
9432 || vim_ispathsep(p[1])
9433 || (p[1] == '.'
9434 && (p[2] == NUL
9435 || vim_ispathsep(p[2]))))))
9436 {
9437 /* Prepend "./". */
9438 cpy = concat_str((char_u *)"./", p);
9439 if (cpy != NULL)
9440 {
9441 vim_free(p);
9442 p = cpy;
9443 }
9444 }
9445 else if (!is_relative_to_current)
9446 {
9447 /* Strip leading "./". */
9448 q = p;
9449 while (q[0] == '.' && vim_ispathsep(q[1]))
9450 q += 2;
9451 if (q > p)
9452 STRMOVE(p, p + 2);
9453 }
9454 }
9455
9456 /* Ensure that the result will have no trailing path separator
9457 * if the argument had none. But keep "/" or "//". */
9458 if (!has_trailing_pathsep)
9459 {
9460 q = p + STRLEN(p);
9461 if (after_pathsep(p, q))
9462 *gettail_sep(p) = NUL;
9463 }
9464
9465 rettv->vval.v_string = p;
9466 }
9467# else
9468 rettv->vval.v_string = vim_strsave(p);
9469# endif
9470#endif
9471
9472 simplify_filename(rettv->vval.v_string);
9473
9474#ifdef HAVE_READLINK
9475fail:
9476 vim_free(buf);
9477#endif
9478 rettv->v_type = VAR_STRING;
9479}
9480
9481/*
9482 * "reverse({list})" function
9483 */
9484 static void
9485f_reverse(typval_T *argvars, typval_T *rettv)
9486{
9487 list_T *l;
9488 listitem_T *li, *ni;
9489
9490 if (argvars[0].v_type != VAR_LIST)
9491 EMSG2(_(e_listarg), "reverse()");
9492 else if ((l = argvars[0].vval.v_list) != NULL
9493 && !tv_check_lock(l->lv_lock,
9494 (char_u *)N_("reverse() argument"), TRUE))
9495 {
9496 li = l->lv_last;
9497 l->lv_first = l->lv_last = NULL;
9498 l->lv_len = 0;
9499 while (li != NULL)
9500 {
9501 ni = li->li_prev;
9502 list_append(l, li);
9503 li = ni;
9504 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009505 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009506 l->lv_idx = l->lv_len - l->lv_idx - 1;
9507 }
9508}
9509
9510#define SP_NOMOVE 0x01 /* don't move cursor */
9511#define SP_REPEAT 0x02 /* repeat to find outer pair */
9512#define SP_RETCOUNT 0x04 /* return matchcount */
9513#define SP_SETPCMARK 0x08 /* set previous context mark */
9514#define SP_START 0x10 /* accept match at start position */
9515#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9516#define SP_END 0x40 /* leave cursor at end of match */
9517#define SP_COLUMN 0x80 /* start at cursor column */
9518
9519static int get_search_arg(typval_T *varp, int *flagsp);
9520
9521/*
9522 * Get flags for a search function.
9523 * Possibly sets "p_ws".
9524 * Returns BACKWARD, FORWARD or zero (for an error).
9525 */
9526 static int
9527get_search_arg(typval_T *varp, int *flagsp)
9528{
9529 int dir = FORWARD;
9530 char_u *flags;
9531 char_u nbuf[NUMBUFLEN];
9532 int mask;
9533
9534 if (varp->v_type != VAR_UNKNOWN)
9535 {
9536 flags = get_tv_string_buf_chk(varp, nbuf);
9537 if (flags == NULL)
9538 return 0; /* type error; errmsg already given */
9539 while (*flags != NUL)
9540 {
9541 switch (*flags)
9542 {
9543 case 'b': dir = BACKWARD; break;
9544 case 'w': p_ws = TRUE; break;
9545 case 'W': p_ws = FALSE; break;
9546 default: mask = 0;
9547 if (flagsp != NULL)
9548 switch (*flags)
9549 {
9550 case 'c': mask = SP_START; break;
9551 case 'e': mask = SP_END; break;
9552 case 'm': mask = SP_RETCOUNT; break;
9553 case 'n': mask = SP_NOMOVE; break;
9554 case 'p': mask = SP_SUBPAT; break;
9555 case 'r': mask = SP_REPEAT; break;
9556 case 's': mask = SP_SETPCMARK; break;
9557 case 'z': mask = SP_COLUMN; break;
9558 }
9559 if (mask == 0)
9560 {
9561 EMSG2(_(e_invarg2), flags);
9562 dir = 0;
9563 }
9564 else
9565 *flagsp |= mask;
9566 }
9567 if (dir == 0)
9568 break;
9569 ++flags;
9570 }
9571 }
9572 return dir;
9573}
9574
9575/*
9576 * Shared by search() and searchpos() functions.
9577 */
9578 static int
9579search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9580{
9581 int flags;
9582 char_u *pat;
9583 pos_T pos;
9584 pos_T save_cursor;
9585 int save_p_ws = p_ws;
9586 int dir;
9587 int retval = 0; /* default: FAIL */
9588 long lnum_stop = 0;
9589 proftime_T tm;
9590#ifdef FEAT_RELTIME
9591 long time_limit = 0;
9592#endif
9593 int options = SEARCH_KEEP;
9594 int subpatnum;
9595
9596 pat = get_tv_string(&argvars[0]);
9597 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9598 if (dir == 0)
9599 goto theend;
9600 flags = *flagsp;
9601 if (flags & SP_START)
9602 options |= SEARCH_START;
9603 if (flags & SP_END)
9604 options |= SEARCH_END;
9605 if (flags & SP_COLUMN)
9606 options |= SEARCH_COL;
9607
9608 /* Optional arguments: line number to stop searching and timeout. */
9609 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9610 {
9611 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9612 if (lnum_stop < 0)
9613 goto theend;
9614#ifdef FEAT_RELTIME
9615 if (argvars[3].v_type != VAR_UNKNOWN)
9616 {
9617 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9618 if (time_limit < 0)
9619 goto theend;
9620 }
9621#endif
9622 }
9623
9624#ifdef FEAT_RELTIME
9625 /* Set the time limit, if there is one. */
9626 profile_setlimit(time_limit, &tm);
9627#endif
9628
9629 /*
9630 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9631 * Check to make sure only those flags are set.
9632 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9633 * flags cannot be set. Check for that condition also.
9634 */
9635 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9636 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9637 {
9638 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9639 goto theend;
9640 }
9641
9642 pos = save_cursor = curwin->w_cursor;
9643 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009644 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009645 if (subpatnum != FAIL)
9646 {
9647 if (flags & SP_SUBPAT)
9648 retval = subpatnum;
9649 else
9650 retval = pos.lnum;
9651 if (flags & SP_SETPCMARK)
9652 setpcmark();
9653 curwin->w_cursor = pos;
9654 if (match_pos != NULL)
9655 {
9656 /* Store the match cursor position */
9657 match_pos->lnum = pos.lnum;
9658 match_pos->col = pos.col + 1;
9659 }
9660 /* "/$" will put the cursor after the end of the line, may need to
9661 * correct that here */
9662 check_cursor();
9663 }
9664
9665 /* If 'n' flag is used: restore cursor position. */
9666 if (flags & SP_NOMOVE)
9667 curwin->w_cursor = save_cursor;
9668 else
9669 curwin->w_set_curswant = TRUE;
9670theend:
9671 p_ws = save_p_ws;
9672
9673 return retval;
9674}
9675
9676#ifdef FEAT_FLOAT
9677
9678/*
9679 * round() is not in C90, use ceil() or floor() instead.
9680 */
9681 float_T
9682vim_round(float_T f)
9683{
9684 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9685}
9686
9687/*
9688 * "round({float})" function
9689 */
9690 static void
9691f_round(typval_T *argvars, typval_T *rettv)
9692{
9693 float_T f = 0.0;
9694
9695 rettv->v_type = VAR_FLOAT;
9696 if (get_float_arg(argvars, &f) == OK)
9697 rettv->vval.v_float = vim_round(f);
9698 else
9699 rettv->vval.v_float = 0.0;
9700}
9701#endif
9702
9703/*
9704 * "screenattr()" function
9705 */
9706 static void
9707f_screenattr(typval_T *argvars, typval_T *rettv)
9708{
9709 int row;
9710 int col;
9711 int c;
9712
9713 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9714 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9715 if (row < 0 || row >= screen_Rows
9716 || col < 0 || col >= screen_Columns)
9717 c = -1;
9718 else
9719 c = ScreenAttrs[LineOffset[row] + col];
9720 rettv->vval.v_number = c;
9721}
9722
9723/*
9724 * "screenchar()" function
9725 */
9726 static void
9727f_screenchar(typval_T *argvars, typval_T *rettv)
9728{
9729 int row;
9730 int col;
9731 int off;
9732 int c;
9733
9734 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9735 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9736 if (row < 0 || row >= screen_Rows
9737 || col < 0 || col >= screen_Columns)
9738 c = -1;
9739 else
9740 {
9741 off = LineOffset[row] + col;
9742#ifdef FEAT_MBYTE
9743 if (enc_utf8 && ScreenLinesUC[off] != 0)
9744 c = ScreenLinesUC[off];
9745 else
9746#endif
9747 c = ScreenLines[off];
9748 }
9749 rettv->vval.v_number = c;
9750}
9751
9752/*
9753 * "screencol()" function
9754 *
9755 * First column is 1 to be consistent with virtcol().
9756 */
9757 static void
9758f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9759{
9760 rettv->vval.v_number = screen_screencol() + 1;
9761}
9762
9763/*
9764 * "screenrow()" function
9765 */
9766 static void
9767f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9768{
9769 rettv->vval.v_number = screen_screenrow() + 1;
9770}
9771
9772/*
9773 * "search()" function
9774 */
9775 static void
9776f_search(typval_T *argvars, typval_T *rettv)
9777{
9778 int flags = 0;
9779
9780 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9781}
9782
9783/*
9784 * "searchdecl()" function
9785 */
9786 static void
9787f_searchdecl(typval_T *argvars, typval_T *rettv)
9788{
9789 int locally = 1;
9790 int thisblock = 0;
9791 int error = FALSE;
9792 char_u *name;
9793
9794 rettv->vval.v_number = 1; /* default: FAIL */
9795
9796 name = get_tv_string_chk(&argvars[0]);
9797 if (argvars[1].v_type != VAR_UNKNOWN)
9798 {
9799 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9800 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9801 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9802 }
9803 if (!error && name != NULL)
9804 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9805 locally, thisblock, SEARCH_KEEP) == FAIL;
9806}
9807
9808/*
9809 * Used by searchpair() and searchpairpos()
9810 */
9811 static int
9812searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9813{
9814 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009815 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009816 int save_p_ws = p_ws;
9817 int dir;
9818 int flags = 0;
9819 char_u nbuf1[NUMBUFLEN];
9820 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009821 int retval = 0; /* default: FAIL */
9822 long lnum_stop = 0;
9823 long time_limit = 0;
9824
9825 /* Get the three pattern arguments: start, middle, end. */
9826 spat = get_tv_string_chk(&argvars[0]);
9827 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9828 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9829 if (spat == NULL || mpat == NULL || epat == NULL)
9830 goto theend; /* type error */
9831
9832 /* Handle the optional fourth argument: flags */
9833 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9834 if (dir == 0)
9835 goto theend;
9836
9837 /* Don't accept SP_END or SP_SUBPAT.
9838 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9839 */
9840 if ((flags & (SP_END | SP_SUBPAT)) != 0
9841 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9842 {
9843 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9844 goto theend;
9845 }
9846
9847 /* Using 'r' implies 'W', otherwise it doesn't work. */
9848 if (flags & SP_REPEAT)
9849 p_ws = FALSE;
9850
9851 /* Optional fifth argument: skip expression */
9852 if (argvars[3].v_type == VAR_UNKNOWN
9853 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009854 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009855 else
9856 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009857 skip = &argvars[4];
9858 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9859 && skip->v_type != VAR_STRING)
9860 {
9861 /* Type error */
9862 goto theend;
9863 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009864 if (argvars[5].v_type != VAR_UNKNOWN)
9865 {
9866 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9867 if (lnum_stop < 0)
9868 goto theend;
9869#ifdef FEAT_RELTIME
9870 if (argvars[6].v_type != VAR_UNKNOWN)
9871 {
9872 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9873 if (time_limit < 0)
9874 goto theend;
9875 }
9876#endif
9877 }
9878 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009879
9880 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9881 match_pos, lnum_stop, time_limit);
9882
9883theend:
9884 p_ws = save_p_ws;
9885
9886 return retval;
9887}
9888
9889/*
9890 * "searchpair()" function
9891 */
9892 static void
9893f_searchpair(typval_T *argvars, typval_T *rettv)
9894{
9895 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9896}
9897
9898/*
9899 * "searchpairpos()" function
9900 */
9901 static void
9902f_searchpairpos(typval_T *argvars, typval_T *rettv)
9903{
9904 pos_T match_pos;
9905 int lnum = 0;
9906 int col = 0;
9907
9908 if (rettv_list_alloc(rettv) == FAIL)
9909 return;
9910
9911 if (searchpair_cmn(argvars, &match_pos) > 0)
9912 {
9913 lnum = match_pos.lnum;
9914 col = match_pos.col;
9915 }
9916
9917 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9918 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9919}
9920
9921/*
9922 * Search for a start/middle/end thing.
9923 * Used by searchpair(), see its documentation for the details.
9924 * Returns 0 or -1 for no match,
9925 */
9926 long
9927do_searchpair(
9928 char_u *spat, /* start pattern */
9929 char_u *mpat, /* middle pattern */
9930 char_u *epat, /* end pattern */
9931 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009932 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009933 int flags, /* SP_SETPCMARK and other SP_ values */
9934 pos_T *match_pos,
9935 linenr_T lnum_stop, /* stop at this line if not zero */
9936 long time_limit UNUSED) /* stop after this many msec */
9937{
9938 char_u *save_cpo;
9939 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9940 long retval = 0;
9941 pos_T pos;
9942 pos_T firstpos;
9943 pos_T foundpos;
9944 pos_T save_cursor;
9945 pos_T save_pos;
9946 int n;
9947 int r;
9948 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009949 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009950 int err;
9951 int options = SEARCH_KEEP;
9952 proftime_T tm;
9953
9954 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9955 save_cpo = p_cpo;
9956 p_cpo = empty_option;
9957
9958#ifdef FEAT_RELTIME
9959 /* Set the time limit, if there is one. */
9960 profile_setlimit(time_limit, &tm);
9961#endif
9962
9963 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9964 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009965 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9966 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009967 if (pat2 == NULL || pat3 == NULL)
9968 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009969 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009970 if (*mpat == NUL)
9971 STRCPY(pat3, pat2);
9972 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009973 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009974 spat, epat, mpat);
9975 if (flags & SP_START)
9976 options |= SEARCH_START;
9977
Bram Moolenaar48570482017-10-30 21:48:41 +01009978 if (skip != NULL)
9979 {
9980 /* Empty string means to not use the skip expression. */
9981 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9982 use_skip = skip->vval.v_string != NULL
9983 && *skip->vval.v_string != NUL;
9984 }
9985
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009986 save_cursor = curwin->w_cursor;
9987 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009988 CLEAR_POS(&firstpos);
9989 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009990 pat = pat3;
9991 for (;;)
9992 {
9993 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009994 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009995 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009996 /* didn't find it or found the first match again: FAIL */
9997 break;
9998
9999 if (firstpos.lnum == 0)
10000 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010001 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010002 {
10003 /* Found the same position again. Can happen with a pattern that
10004 * has "\zs" at the end and searching backwards. Advance one
10005 * character and try again. */
10006 if (dir == BACKWARD)
10007 decl(&pos);
10008 else
10009 incl(&pos);
10010 }
10011 foundpos = pos;
10012
10013 /* clear the start flag to avoid getting stuck here */
10014 options &= ~SEARCH_START;
10015
10016 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010017 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010018 {
10019 save_pos = curwin->w_cursor;
10020 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010021 err = FALSE;
10022 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010023 curwin->w_cursor = save_pos;
10024 if (err)
10025 {
10026 /* Evaluating {skip} caused an error, break here. */
10027 curwin->w_cursor = save_cursor;
10028 retval = -1;
10029 break;
10030 }
10031 if (r)
10032 continue;
10033 }
10034
10035 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10036 {
10037 /* Found end when searching backwards or start when searching
10038 * forward: nested pair. */
10039 ++nest;
10040 pat = pat2; /* nested, don't search for middle */
10041 }
10042 else
10043 {
10044 /* Found end when searching forward or start when searching
10045 * backward: end of (nested) pair; or found middle in outer pair. */
10046 if (--nest == 1)
10047 pat = pat3; /* outer level, search for middle */
10048 }
10049
10050 if (nest == 0)
10051 {
10052 /* Found the match: return matchcount or line number. */
10053 if (flags & SP_RETCOUNT)
10054 ++retval;
10055 else
10056 retval = pos.lnum;
10057 if (flags & SP_SETPCMARK)
10058 setpcmark();
10059 curwin->w_cursor = pos;
10060 if (!(flags & SP_REPEAT))
10061 break;
10062 nest = 1; /* search for next unmatched */
10063 }
10064 }
10065
10066 if (match_pos != NULL)
10067 {
10068 /* Store the match cursor position */
10069 match_pos->lnum = curwin->w_cursor.lnum;
10070 match_pos->col = curwin->w_cursor.col + 1;
10071 }
10072
10073 /* If 'n' flag is used or search failed: restore cursor position. */
10074 if ((flags & SP_NOMOVE) || retval == 0)
10075 curwin->w_cursor = save_cursor;
10076
10077theend:
10078 vim_free(pat2);
10079 vim_free(pat3);
10080 if (p_cpo == empty_option)
10081 p_cpo = save_cpo;
10082 else
10083 /* Darn, evaluating the {skip} expression changed the value. */
10084 free_string_option(save_cpo);
10085
10086 return retval;
10087}
10088
10089/*
10090 * "searchpos()" function
10091 */
10092 static void
10093f_searchpos(typval_T *argvars, typval_T *rettv)
10094{
10095 pos_T match_pos;
10096 int lnum = 0;
10097 int col = 0;
10098 int n;
10099 int flags = 0;
10100
10101 if (rettv_list_alloc(rettv) == FAIL)
10102 return;
10103
10104 n = search_cmn(argvars, &match_pos, &flags);
10105 if (n > 0)
10106 {
10107 lnum = match_pos.lnum;
10108 col = match_pos.col;
10109 }
10110
10111 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10112 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10113 if (flags & SP_SUBPAT)
10114 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10115}
10116
10117 static void
10118f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10119{
10120#ifdef FEAT_CLIENTSERVER
10121 char_u buf[NUMBUFLEN];
10122 char_u *server = get_tv_string_chk(&argvars[0]);
10123 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10124
10125 rettv->vval.v_number = -1;
10126 if (server == NULL || reply == NULL)
10127 return;
10128 if (check_restricted() || check_secure())
10129 return;
10130# ifdef FEAT_X11
10131 if (check_connection() == FAIL)
10132 return;
10133# endif
10134
10135 if (serverSendReply(server, reply) < 0)
10136 {
10137 EMSG(_("E258: Unable to send to client"));
10138 return;
10139 }
10140 rettv->vval.v_number = 0;
10141#else
10142 rettv->vval.v_number = -1;
10143#endif
10144}
10145
10146 static void
10147f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10148{
10149 char_u *r = NULL;
10150
10151#ifdef FEAT_CLIENTSERVER
10152# ifdef WIN32
10153 r = serverGetVimNames();
10154# else
10155 make_connection();
10156 if (X_DISPLAY != NULL)
10157 r = serverGetVimNames(X_DISPLAY);
10158# endif
10159#endif
10160 rettv->v_type = VAR_STRING;
10161 rettv->vval.v_string = r;
10162}
10163
10164/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010165 * Set line or list of lines in buffer "buf".
10166 */
10167 static void
10168set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
10169{
10170 char_u *line = NULL;
10171 list_T *l = NULL;
10172 listitem_T *li = NULL;
10173 long added = 0;
10174 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010175 buf_T *curbuf_save = NULL;
10176 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010177 int is_curbuf = buf == curbuf;
10178
Bram Moolenaar9d954202017-09-04 20:34:19 +020010179 /* When using the current buffer ml_mfp will be set if needed. Useful when
10180 * setline() is used on startup. For other buffers the buffer must be
10181 * loaded. */
10182 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010183 {
10184 rettv->vval.v_number = 1; /* FAIL */
10185 return;
10186 }
10187
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010188 if (!is_curbuf)
10189 {
10190 wininfo_T *wip;
10191
10192 curbuf_save = curbuf;
10193 curwin_save = curwin;
10194 curbuf = buf;
10195 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
10196 {
10197 if (wip->wi_win != NULL)
10198 {
10199 curwin = wip->wi_win;
10200 break;
10201 }
10202 }
10203 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010204
10205 lcount = curbuf->b_ml.ml_line_count;
10206
10207 if (lines->v_type == VAR_LIST)
10208 {
10209 l = lines->vval.v_list;
10210 li = l->lv_first;
10211 }
10212 else
10213 line = get_tv_string_chk(lines);
10214
10215 /* default result is zero == OK */
10216 for (;;)
10217 {
10218 if (l != NULL)
10219 {
10220 /* list argument, get next string */
10221 if (li == NULL)
10222 break;
10223 line = get_tv_string_chk(&li->li_tv);
10224 li = li->li_next;
10225 }
10226
10227 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +020010228 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010229 break;
10230
10231 /* When coming here from Insert mode, sync undo, so that this can be
10232 * undone separately from what was previously inserted. */
10233 if (u_sync_once == 2)
10234 {
10235 u_sync_once = 1; /* notify that u_sync() was called */
10236 u_sync(TRUE);
10237 }
10238
10239 if (lnum <= curbuf->b_ml.ml_line_count)
10240 {
10241 /* existing line, replace it */
10242 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10243 {
10244 changed_bytes(lnum, 0);
10245 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10246 check_cursor_col();
10247 rettv->vval.v_number = 0; /* OK */
10248 }
10249 }
10250 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10251 {
10252 /* lnum is one past the last line, append the line */
10253 ++added;
10254 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10255 rettv->vval.v_number = 0; /* OK */
10256 }
10257
10258 if (l == NULL) /* only one string argument */
10259 break;
10260 ++lnum;
10261 }
10262
10263 if (added > 0)
10264 appended_lines_mark(lcount, added);
10265
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010266 if (!is_curbuf)
10267 {
10268 curbuf = curbuf_save;
10269 curwin = curwin_save;
10270 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010271}
10272
10273/*
10274 * "setbufline()" function
10275 */
10276 static void
10277f_setbufline(argvars, rettv)
10278 typval_T *argvars;
10279 typval_T *rettv;
10280{
10281 linenr_T lnum;
10282 buf_T *buf;
10283
10284 buf = get_buf_tv(&argvars[0], FALSE);
10285 if (buf == NULL)
10286 rettv->vval.v_number = 1; /* FAIL */
10287 else
10288 {
10289 lnum = get_tv_lnum_buf(&argvars[1], buf);
10290
10291 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10292 }
10293}
10294
10295/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 * "setbufvar()" function
10297 */
10298 static void
10299f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10300{
10301 buf_T *buf;
10302 char_u *varname, *bufvarname;
10303 typval_T *varp;
10304 char_u nbuf[NUMBUFLEN];
10305
10306 if (check_restricted() || check_secure())
10307 return;
10308 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10309 varname = get_tv_string_chk(&argvars[1]);
10310 buf = get_buf_tv(&argvars[0], FALSE);
10311 varp = &argvars[2];
10312
10313 if (buf != NULL && varname != NULL && varp != NULL)
10314 {
10315 if (*varname == '&')
10316 {
10317 long numval;
10318 char_u *strval;
10319 int error = FALSE;
10320 aco_save_T aco;
10321
10322 /* set curbuf to be our buf, temporarily */
10323 aucmd_prepbuf(&aco, buf);
10324
10325 ++varname;
10326 numval = (long)get_tv_number_chk(varp, &error);
10327 strval = get_tv_string_buf_chk(varp, nbuf);
10328 if (!error && strval != NULL)
10329 set_option_value(varname, numval, strval, OPT_LOCAL);
10330
10331 /* reset notion of buffer */
10332 aucmd_restbuf(&aco);
10333 }
10334 else
10335 {
10336 buf_T *save_curbuf = curbuf;
10337
10338 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10339 if (bufvarname != NULL)
10340 {
10341 curbuf = buf;
10342 STRCPY(bufvarname, "b:");
10343 STRCPY(bufvarname + 2, varname);
10344 set_var(bufvarname, varp, TRUE);
10345 vim_free(bufvarname);
10346 curbuf = save_curbuf;
10347 }
10348 }
10349 }
10350}
10351
10352 static void
10353f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10354{
10355 dict_T *d;
10356 dictitem_T *di;
10357 char_u *csearch;
10358
10359 if (argvars[0].v_type != VAR_DICT)
10360 {
10361 EMSG(_(e_dictreq));
10362 return;
10363 }
10364
10365 if ((d = argvars[0].vval.v_dict) != NULL)
10366 {
10367 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10368 if (csearch != NULL)
10369 {
10370#ifdef FEAT_MBYTE
10371 if (enc_utf8)
10372 {
10373 int pcc[MAX_MCO];
10374 int c = utfc_ptr2char(csearch, pcc);
10375
10376 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10377 }
10378 else
10379#endif
10380 set_last_csearch(PTR2CHAR(csearch),
10381 csearch, MB_PTR2LEN(csearch));
10382 }
10383
10384 di = dict_find(d, (char_u *)"forward", -1);
10385 if (di != NULL)
10386 set_csearch_direction((int)get_tv_number(&di->di_tv)
10387 ? FORWARD : BACKWARD);
10388
10389 di = dict_find(d, (char_u *)"until", -1);
10390 if (di != NULL)
10391 set_csearch_until(!!get_tv_number(&di->di_tv));
10392 }
10393}
10394
10395/*
10396 * "setcmdpos()" function
10397 */
10398 static void
10399f_setcmdpos(typval_T *argvars, typval_T *rettv)
10400{
10401 int pos = (int)get_tv_number(&argvars[0]) - 1;
10402
10403 if (pos >= 0)
10404 rettv->vval.v_number = set_cmdline_pos(pos);
10405}
10406
10407/*
10408 * "setfperm({fname}, {mode})" function
10409 */
10410 static void
10411f_setfperm(typval_T *argvars, typval_T *rettv)
10412{
10413 char_u *fname;
10414 char_u modebuf[NUMBUFLEN];
10415 char_u *mode_str;
10416 int i;
10417 int mask;
10418 int mode = 0;
10419
10420 rettv->vval.v_number = 0;
10421 fname = get_tv_string_chk(&argvars[0]);
10422 if (fname == NULL)
10423 return;
10424 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10425 if (mode_str == NULL)
10426 return;
10427 if (STRLEN(mode_str) != 9)
10428 {
10429 EMSG2(_(e_invarg2), mode_str);
10430 return;
10431 }
10432
10433 mask = 1;
10434 for (i = 8; i >= 0; --i)
10435 {
10436 if (mode_str[i] != '-')
10437 mode |= mask;
10438 mask = mask << 1;
10439 }
10440 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10441}
10442
10443/*
10444 * "setline()" function
10445 */
10446 static void
10447f_setline(typval_T *argvars, typval_T *rettv)
10448{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010449 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010450
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010451 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010452}
10453
Bram Moolenaard823fa92016-08-12 16:29:27 +020010454static 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 +020010455
10456/*
10457 * Used by "setqflist()" and "setloclist()" functions
10458 */
10459 static void
10460set_qf_ll_list(
10461 win_T *wp UNUSED,
10462 typval_T *list_arg UNUSED,
10463 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010464 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010465 typval_T *rettv)
10466{
10467#ifdef FEAT_QUICKFIX
10468 static char *e_invact = N_("E927: Invalid action: '%s'");
10469 char_u *act;
10470 int action = 0;
10471#endif
10472
10473 rettv->vval.v_number = -1;
10474
10475#ifdef FEAT_QUICKFIX
10476 if (list_arg->v_type != VAR_LIST)
10477 EMSG(_(e_listreq));
10478 else
10479 {
10480 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010481 dict_T *d = NULL;
10482 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010483
10484 if (action_arg->v_type == VAR_STRING)
10485 {
10486 act = get_tv_string_chk(action_arg);
10487 if (act == NULL)
10488 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010489 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10490 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010491 action = *act;
10492 else
10493 EMSG2(_(e_invact), act);
10494 }
10495 else if (action_arg->v_type == VAR_UNKNOWN)
10496 action = ' ';
10497 else
10498 EMSG(_(e_stringreq));
10499
Bram Moolenaard823fa92016-08-12 16:29:27 +020010500 if (action_arg->v_type != VAR_UNKNOWN
10501 && what_arg->v_type != VAR_UNKNOWN)
10502 {
10503 if (what_arg->v_type == VAR_DICT)
10504 d = what_arg->vval.v_dict;
10505 else
10506 {
10507 EMSG(_(e_dictreq));
10508 valid_dict = FALSE;
10509 }
10510 }
10511
10512 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar8b62e312018-05-13 15:29:04 +020010513 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010514 rettv->vval.v_number = 0;
10515 }
10516#endif
10517}
10518
10519/*
10520 * "setloclist()" function
10521 */
10522 static void
10523f_setloclist(typval_T *argvars, typval_T *rettv)
10524{
10525 win_T *win;
10526
10527 rettv->vval.v_number = -1;
10528
10529 win = find_win_by_nr(&argvars[0], NULL);
10530 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010531 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010532}
10533
10534/*
10535 * "setmatches()" function
10536 */
10537 static void
10538f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10539{
10540#ifdef FEAT_SEARCH_EXTRA
10541 list_T *l;
10542 listitem_T *li;
10543 dict_T *d;
10544 list_T *s = NULL;
10545
10546 rettv->vval.v_number = -1;
10547 if (argvars[0].v_type != VAR_LIST)
10548 {
10549 EMSG(_(e_listreq));
10550 return;
10551 }
10552 if ((l = argvars[0].vval.v_list) != NULL)
10553 {
10554
10555 /* To some extent make sure that we are dealing with a list from
10556 * "getmatches()". */
10557 li = l->lv_first;
10558 while (li != NULL)
10559 {
10560 if (li->li_tv.v_type != VAR_DICT
10561 || (d = li->li_tv.vval.v_dict) == NULL)
10562 {
10563 EMSG(_(e_invarg));
10564 return;
10565 }
10566 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10567 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10568 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10569 && dict_find(d, (char_u *)"priority", -1) != NULL
10570 && dict_find(d, (char_u *)"id", -1) != NULL))
10571 {
10572 EMSG(_(e_invarg));
10573 return;
10574 }
10575 li = li->li_next;
10576 }
10577
10578 clear_matches(curwin);
10579 li = l->lv_first;
10580 while (li != NULL)
10581 {
10582 int i = 0;
10583 char_u buf[5];
10584 dictitem_T *di;
10585 char_u *group;
10586 int priority;
10587 int id;
10588 char_u *conceal;
10589
10590 d = li->li_tv.vval.v_dict;
10591 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10592 {
10593 if (s == NULL)
10594 {
10595 s = list_alloc();
10596 if (s == NULL)
10597 return;
10598 }
10599
10600 /* match from matchaddpos() */
10601 for (i = 1; i < 9; i++)
10602 {
10603 sprintf((char *)buf, (char *)"pos%d", i);
10604 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10605 {
10606 if (di->di_tv.v_type != VAR_LIST)
10607 return;
10608
10609 list_append_tv(s, &di->di_tv);
10610 s->lv_refcount++;
10611 }
10612 else
10613 break;
10614 }
10615 }
10616
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010617 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010618 priority = (int)get_dict_number(d, (char_u *)"priority");
10619 id = (int)get_dict_number(d, (char_u *)"id");
10620 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010621 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010622 : NULL;
10623 if (i == 0)
10624 {
10625 match_add(curwin, group,
10626 get_dict_string(d, (char_u *)"pattern", FALSE),
10627 priority, id, NULL, conceal);
10628 }
10629 else
10630 {
10631 match_add(curwin, group, NULL, priority, id, s, conceal);
10632 list_unref(s);
10633 s = NULL;
10634 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010635 vim_free(group);
10636 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010637
10638 li = li->li_next;
10639 }
10640 rettv->vval.v_number = 0;
10641 }
10642#endif
10643}
10644
10645/*
10646 * "setpos()" function
10647 */
10648 static void
10649f_setpos(typval_T *argvars, typval_T *rettv)
10650{
10651 pos_T pos;
10652 int fnum;
10653 char_u *name;
10654 colnr_T curswant = -1;
10655
10656 rettv->vval.v_number = -1;
10657 name = get_tv_string_chk(argvars);
10658 if (name != NULL)
10659 {
10660 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10661 {
10662 if (--pos.col < 0)
10663 pos.col = 0;
10664 if (name[0] == '.' && name[1] == NUL)
10665 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010666 /* set cursor; "fnum" is ignored */
10667 curwin->w_cursor = pos;
10668 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010669 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010670 curwin->w_curswant = curswant - 1;
10671 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010672 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010673 check_cursor();
10674 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010675 }
10676 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10677 {
10678 /* set mark */
10679 if (setmark_pos(name[1], &pos, fnum) == OK)
10680 rettv->vval.v_number = 0;
10681 }
10682 else
10683 EMSG(_(e_invarg));
10684 }
10685 }
10686}
10687
10688/*
10689 * "setqflist()" function
10690 */
10691 static void
10692f_setqflist(typval_T *argvars, typval_T *rettv)
10693{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010694 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010695}
10696
10697/*
10698 * "setreg()" function
10699 */
10700 static void
10701f_setreg(typval_T *argvars, typval_T *rettv)
10702{
10703 int regname;
10704 char_u *strregname;
10705 char_u *stropt;
10706 char_u *strval;
10707 int append;
10708 char_u yank_type;
10709 long block_len;
10710
10711 block_len = -1;
10712 yank_type = MAUTO;
10713 append = FALSE;
10714
10715 strregname = get_tv_string_chk(argvars);
10716 rettv->vval.v_number = 1; /* FAIL is default */
10717
10718 if (strregname == NULL)
10719 return; /* type error; errmsg already given */
10720 regname = *strregname;
10721 if (regname == 0 || regname == '@')
10722 regname = '"';
10723
10724 if (argvars[2].v_type != VAR_UNKNOWN)
10725 {
10726 stropt = get_tv_string_chk(&argvars[2]);
10727 if (stropt == NULL)
10728 return; /* type error */
10729 for (; *stropt != NUL; ++stropt)
10730 switch (*stropt)
10731 {
10732 case 'a': case 'A': /* append */
10733 append = TRUE;
10734 break;
10735 case 'v': case 'c': /* character-wise selection */
10736 yank_type = MCHAR;
10737 break;
10738 case 'V': case 'l': /* line-wise selection */
10739 yank_type = MLINE;
10740 break;
10741 case 'b': case Ctrl_V: /* block-wise selection */
10742 yank_type = MBLOCK;
10743 if (VIM_ISDIGIT(stropt[1]))
10744 {
10745 ++stropt;
10746 block_len = getdigits(&stropt) - 1;
10747 --stropt;
10748 }
10749 break;
10750 }
10751 }
10752
10753 if (argvars[1].v_type == VAR_LIST)
10754 {
10755 char_u **lstval;
10756 char_u **allocval;
10757 char_u buf[NUMBUFLEN];
10758 char_u **curval;
10759 char_u **curallocval;
10760 list_T *ll = argvars[1].vval.v_list;
10761 listitem_T *li;
10762 int len;
10763
10764 /* If the list is NULL handle like an empty list. */
10765 len = ll == NULL ? 0 : ll->lv_len;
10766
10767 /* First half: use for pointers to result lines; second half: use for
10768 * pointers to allocated copies. */
10769 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10770 if (lstval == NULL)
10771 return;
10772 curval = lstval;
10773 allocval = lstval + len + 2;
10774 curallocval = allocval;
10775
10776 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10777 li = li->li_next)
10778 {
10779 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10780 if (strval == NULL)
10781 goto free_lstval;
10782 if (strval == buf)
10783 {
10784 /* Need to make a copy, next get_tv_string_buf_chk() will
10785 * overwrite the string. */
10786 strval = vim_strsave(buf);
10787 if (strval == NULL)
10788 goto free_lstval;
10789 *curallocval++ = strval;
10790 }
10791 *curval++ = strval;
10792 }
10793 *curval++ = NULL;
10794
10795 write_reg_contents_lst(regname, lstval, -1,
10796 append, yank_type, block_len);
10797free_lstval:
10798 while (curallocval > allocval)
10799 vim_free(*--curallocval);
10800 vim_free(lstval);
10801 }
10802 else
10803 {
10804 strval = get_tv_string_chk(&argvars[1]);
10805 if (strval == NULL)
10806 return;
10807 write_reg_contents_ex(regname, strval, -1,
10808 append, yank_type, block_len);
10809 }
10810 rettv->vval.v_number = 0;
10811}
10812
10813/*
10814 * "settabvar()" function
10815 */
10816 static void
10817f_settabvar(typval_T *argvars, typval_T *rettv)
10818{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010819 tabpage_T *save_curtab;
10820 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010821 char_u *varname, *tabvarname;
10822 typval_T *varp;
10823
10824 rettv->vval.v_number = 0;
10825
10826 if (check_restricted() || check_secure())
10827 return;
10828
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010829 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830 varname = get_tv_string_chk(&argvars[1]);
10831 varp = &argvars[2];
10832
Bram Moolenaar4033c552017-09-16 20:54:51 +020010833 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010834 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010835 save_curtab = curtab;
10836 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010837
10838 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10839 if (tabvarname != NULL)
10840 {
10841 STRCPY(tabvarname, "t:");
10842 STRCPY(tabvarname + 2, varname);
10843 set_var(tabvarname, varp, TRUE);
10844 vim_free(tabvarname);
10845 }
10846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010847 /* Restore current tabpage */
10848 if (valid_tabpage(save_curtab))
10849 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010850 }
10851}
10852
10853/*
10854 * "settabwinvar()" function
10855 */
10856 static void
10857f_settabwinvar(typval_T *argvars, typval_T *rettv)
10858{
10859 setwinvar(argvars, rettv, 1);
10860}
10861
10862/*
10863 * "setwinvar()" function
10864 */
10865 static void
10866f_setwinvar(typval_T *argvars, typval_T *rettv)
10867{
10868 setwinvar(argvars, rettv, 0);
10869}
10870
10871#ifdef FEAT_CRYPT
10872/*
10873 * "sha256({string})" function
10874 */
10875 static void
10876f_sha256(typval_T *argvars, typval_T *rettv)
10877{
10878 char_u *p;
10879
10880 p = get_tv_string(&argvars[0]);
10881 rettv->vval.v_string = vim_strsave(
10882 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10883 rettv->v_type = VAR_STRING;
10884}
10885#endif /* FEAT_CRYPT */
10886
10887/*
10888 * "shellescape({string})" function
10889 */
10890 static void
10891f_shellescape(typval_T *argvars, typval_T *rettv)
10892{
Bram Moolenaar20615522017-06-05 18:46:26 +020010893 int do_special = non_zero_arg(&argvars[1]);
10894
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010895 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010896 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010897 rettv->v_type = VAR_STRING;
10898}
10899
10900/*
10901 * shiftwidth() function
10902 */
10903 static void
10904f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10905{
10906 rettv->vval.v_number = get_sw_value(curbuf);
10907}
10908
10909/*
10910 * "simplify()" function
10911 */
10912 static void
10913f_simplify(typval_T *argvars, typval_T *rettv)
10914{
10915 char_u *p;
10916
10917 p = get_tv_string(&argvars[0]);
10918 rettv->vval.v_string = vim_strsave(p);
10919 simplify_filename(rettv->vval.v_string); /* simplify in place */
10920 rettv->v_type = VAR_STRING;
10921}
10922
10923#ifdef FEAT_FLOAT
10924/*
10925 * "sin()" function
10926 */
10927 static void
10928f_sin(typval_T *argvars, typval_T *rettv)
10929{
10930 float_T f = 0.0;
10931
10932 rettv->v_type = VAR_FLOAT;
10933 if (get_float_arg(argvars, &f) == OK)
10934 rettv->vval.v_float = sin(f);
10935 else
10936 rettv->vval.v_float = 0.0;
10937}
10938
10939/*
10940 * "sinh()" function
10941 */
10942 static void
10943f_sinh(typval_T *argvars, typval_T *rettv)
10944{
10945 float_T f = 0.0;
10946
10947 rettv->v_type = VAR_FLOAT;
10948 if (get_float_arg(argvars, &f) == OK)
10949 rettv->vval.v_float = sinh(f);
10950 else
10951 rettv->vval.v_float = 0.0;
10952}
10953#endif
10954
10955static int
10956#ifdef __BORLANDC__
10957 _RTLENTRYF
10958#endif
10959 item_compare(const void *s1, const void *s2);
10960static int
10961#ifdef __BORLANDC__
10962 _RTLENTRYF
10963#endif
10964 item_compare2(const void *s1, const void *s2);
10965
10966/* struct used in the array that's given to qsort() */
10967typedef struct
10968{
10969 listitem_T *item;
10970 int idx;
10971} sortItem_T;
10972
10973/* struct storing information about current sort */
10974typedef struct
10975{
10976 int item_compare_ic;
10977 int item_compare_numeric;
10978 int item_compare_numbers;
10979#ifdef FEAT_FLOAT
10980 int item_compare_float;
10981#endif
10982 char_u *item_compare_func;
10983 partial_T *item_compare_partial;
10984 dict_T *item_compare_selfdict;
10985 int item_compare_func_err;
10986 int item_compare_keep_zero;
10987} sortinfo_T;
10988static sortinfo_T *sortinfo = NULL;
10989static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10990#define ITEM_COMPARE_FAIL 999
10991
10992/*
10993 * Compare functions for f_sort() and f_uniq() below.
10994 */
10995 static int
10996#ifdef __BORLANDC__
10997_RTLENTRYF
10998#endif
10999item_compare(const void *s1, const void *s2)
11000{
11001 sortItem_T *si1, *si2;
11002 typval_T *tv1, *tv2;
11003 char_u *p1, *p2;
11004 char_u *tofree1 = NULL, *tofree2 = NULL;
11005 int res;
11006 char_u numbuf1[NUMBUFLEN];
11007 char_u numbuf2[NUMBUFLEN];
11008
11009 si1 = (sortItem_T *)s1;
11010 si2 = (sortItem_T *)s2;
11011 tv1 = &si1->item->li_tv;
11012 tv2 = &si2->item->li_tv;
11013
11014 if (sortinfo->item_compare_numbers)
11015 {
11016 varnumber_T v1 = get_tv_number(tv1);
11017 varnumber_T v2 = get_tv_number(tv2);
11018
11019 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11020 }
11021
11022#ifdef FEAT_FLOAT
11023 if (sortinfo->item_compare_float)
11024 {
11025 float_T v1 = get_tv_float(tv1);
11026 float_T v2 = get_tv_float(tv2);
11027
11028 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11029 }
11030#endif
11031
11032 /* tv2string() puts quotes around a string and allocates memory. Don't do
11033 * that for string variables. Use a single quote when comparing with a
11034 * non-string to do what the docs promise. */
11035 if (tv1->v_type == VAR_STRING)
11036 {
11037 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11038 p1 = (char_u *)"'";
11039 else
11040 p1 = tv1->vval.v_string;
11041 }
11042 else
11043 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11044 if (tv2->v_type == VAR_STRING)
11045 {
11046 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11047 p2 = (char_u *)"'";
11048 else
11049 p2 = tv2->vval.v_string;
11050 }
11051 else
11052 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11053 if (p1 == NULL)
11054 p1 = (char_u *)"";
11055 if (p2 == NULL)
11056 p2 = (char_u *)"";
11057 if (!sortinfo->item_compare_numeric)
11058 {
11059 if (sortinfo->item_compare_ic)
11060 res = STRICMP(p1, p2);
11061 else
11062 res = STRCMP(p1, p2);
11063 }
11064 else
11065 {
11066 double n1, n2;
11067 n1 = strtod((char *)p1, (char **)&p1);
11068 n2 = strtod((char *)p2, (char **)&p2);
11069 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11070 }
11071
11072 /* When the result would be zero, compare the item indexes. Makes the
11073 * sort stable. */
11074 if (res == 0 && !sortinfo->item_compare_keep_zero)
11075 res = si1->idx > si2->idx ? 1 : -1;
11076
11077 vim_free(tofree1);
11078 vim_free(tofree2);
11079 return res;
11080}
11081
11082 static int
11083#ifdef __BORLANDC__
11084_RTLENTRYF
11085#endif
11086item_compare2(const void *s1, const void *s2)
11087{
11088 sortItem_T *si1, *si2;
11089 int res;
11090 typval_T rettv;
11091 typval_T argv[3];
11092 int dummy;
11093 char_u *func_name;
11094 partial_T *partial = sortinfo->item_compare_partial;
11095
11096 /* shortcut after failure in previous call; compare all items equal */
11097 if (sortinfo->item_compare_func_err)
11098 return 0;
11099
11100 si1 = (sortItem_T *)s1;
11101 si2 = (sortItem_T *)s2;
11102
11103 if (partial == NULL)
11104 func_name = sortinfo->item_compare_func;
11105 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011106 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011107
11108 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11109 * in the copy without changing the original list items. */
11110 copy_tv(&si1->item->li_tv, &argv[0]);
11111 copy_tv(&si2->item->li_tv, &argv[1]);
11112
11113 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11114 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011115 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011116 partial, sortinfo->item_compare_selfdict);
11117 clear_tv(&argv[0]);
11118 clear_tv(&argv[1]);
11119
11120 if (res == FAIL)
11121 res = ITEM_COMPARE_FAIL;
11122 else
11123 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11124 if (sortinfo->item_compare_func_err)
11125 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11126 clear_tv(&rettv);
11127
11128 /* When the result would be zero, compare the pointers themselves. Makes
11129 * the sort stable. */
11130 if (res == 0 && !sortinfo->item_compare_keep_zero)
11131 res = si1->idx > si2->idx ? 1 : -1;
11132
11133 return res;
11134}
11135
11136/*
11137 * "sort({list})" function
11138 */
11139 static void
11140do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11141{
11142 list_T *l;
11143 listitem_T *li;
11144 sortItem_T *ptrs;
11145 sortinfo_T *old_sortinfo;
11146 sortinfo_T info;
11147 long len;
11148 long i;
11149
11150 /* Pointer to current info struct used in compare function. Save and
11151 * restore the current one for nested calls. */
11152 old_sortinfo = sortinfo;
11153 sortinfo = &info;
11154
11155 if (argvars[0].v_type != VAR_LIST)
11156 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11157 else
11158 {
11159 l = argvars[0].vval.v_list;
11160 if (l == NULL || tv_check_lock(l->lv_lock,
11161 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11162 TRUE))
11163 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011164 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011165
11166 len = list_len(l);
11167 if (len <= 1)
11168 goto theend; /* short list sorts pretty quickly */
11169
11170 info.item_compare_ic = FALSE;
11171 info.item_compare_numeric = FALSE;
11172 info.item_compare_numbers = FALSE;
11173#ifdef FEAT_FLOAT
11174 info.item_compare_float = FALSE;
11175#endif
11176 info.item_compare_func = NULL;
11177 info.item_compare_partial = NULL;
11178 info.item_compare_selfdict = NULL;
11179 if (argvars[1].v_type != VAR_UNKNOWN)
11180 {
11181 /* optional second argument: {func} */
11182 if (argvars[1].v_type == VAR_FUNC)
11183 info.item_compare_func = argvars[1].vval.v_string;
11184 else if (argvars[1].v_type == VAR_PARTIAL)
11185 info.item_compare_partial = argvars[1].vval.v_partial;
11186 else
11187 {
11188 int error = FALSE;
11189
11190 i = (long)get_tv_number_chk(&argvars[1], &error);
11191 if (error)
11192 goto theend; /* type error; errmsg already given */
11193 if (i == 1)
11194 info.item_compare_ic = TRUE;
11195 else if (argvars[1].v_type != VAR_NUMBER)
11196 info.item_compare_func = get_tv_string(&argvars[1]);
11197 else if (i != 0)
11198 {
11199 EMSG(_(e_invarg));
11200 goto theend;
11201 }
11202 if (info.item_compare_func != NULL)
11203 {
11204 if (*info.item_compare_func == NUL)
11205 {
11206 /* empty string means default sort */
11207 info.item_compare_func = NULL;
11208 }
11209 else if (STRCMP(info.item_compare_func, "n") == 0)
11210 {
11211 info.item_compare_func = NULL;
11212 info.item_compare_numeric = TRUE;
11213 }
11214 else if (STRCMP(info.item_compare_func, "N") == 0)
11215 {
11216 info.item_compare_func = NULL;
11217 info.item_compare_numbers = TRUE;
11218 }
11219#ifdef FEAT_FLOAT
11220 else if (STRCMP(info.item_compare_func, "f") == 0)
11221 {
11222 info.item_compare_func = NULL;
11223 info.item_compare_float = TRUE;
11224 }
11225#endif
11226 else if (STRCMP(info.item_compare_func, "i") == 0)
11227 {
11228 info.item_compare_func = NULL;
11229 info.item_compare_ic = TRUE;
11230 }
11231 }
11232 }
11233
11234 if (argvars[2].v_type != VAR_UNKNOWN)
11235 {
11236 /* optional third argument: {dict} */
11237 if (argvars[2].v_type != VAR_DICT)
11238 {
11239 EMSG(_(e_dictreq));
11240 goto theend;
11241 }
11242 info.item_compare_selfdict = argvars[2].vval.v_dict;
11243 }
11244 }
11245
11246 /* Make an array with each entry pointing to an item in the List. */
11247 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11248 if (ptrs == NULL)
11249 goto theend;
11250
11251 i = 0;
11252 if (sort)
11253 {
11254 /* sort(): ptrs will be the list to sort */
11255 for (li = l->lv_first; li != NULL; li = li->li_next)
11256 {
11257 ptrs[i].item = li;
11258 ptrs[i].idx = i;
11259 ++i;
11260 }
11261
11262 info.item_compare_func_err = FALSE;
11263 info.item_compare_keep_zero = FALSE;
11264 /* test the compare function */
11265 if ((info.item_compare_func != NULL
11266 || info.item_compare_partial != NULL)
11267 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11268 == ITEM_COMPARE_FAIL)
11269 EMSG(_("E702: Sort compare function failed"));
11270 else
11271 {
11272 /* Sort the array with item pointers. */
11273 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11274 info.item_compare_func == NULL
11275 && info.item_compare_partial == NULL
11276 ? item_compare : item_compare2);
11277
11278 if (!info.item_compare_func_err)
11279 {
11280 /* Clear the List and append the items in sorted order. */
11281 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11282 l->lv_len = 0;
11283 for (i = 0; i < len; ++i)
11284 list_append(l, ptrs[i].item);
11285 }
11286 }
11287 }
11288 else
11289 {
11290 int (*item_compare_func_ptr)(const void *, const void *);
11291
11292 /* f_uniq(): ptrs will be a stack of items to remove */
11293 info.item_compare_func_err = FALSE;
11294 info.item_compare_keep_zero = TRUE;
11295 item_compare_func_ptr = info.item_compare_func != NULL
11296 || info.item_compare_partial != NULL
11297 ? item_compare2 : item_compare;
11298
11299 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11300 li = li->li_next)
11301 {
11302 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11303 == 0)
11304 ptrs[i++].item = li;
11305 if (info.item_compare_func_err)
11306 {
11307 EMSG(_("E882: Uniq compare function failed"));
11308 break;
11309 }
11310 }
11311
11312 if (!info.item_compare_func_err)
11313 {
11314 while (--i >= 0)
11315 {
11316 li = ptrs[i].item->li_next;
11317 ptrs[i].item->li_next = li->li_next;
11318 if (li->li_next != NULL)
11319 li->li_next->li_prev = ptrs[i].item;
11320 else
11321 l->lv_last = ptrs[i].item;
11322 list_fix_watch(l, li);
11323 listitem_free(li);
11324 l->lv_len--;
11325 }
11326 }
11327 }
11328
11329 vim_free(ptrs);
11330 }
11331theend:
11332 sortinfo = old_sortinfo;
11333}
11334
11335/*
11336 * "sort({list})" function
11337 */
11338 static void
11339f_sort(typval_T *argvars, typval_T *rettv)
11340{
11341 do_sort_uniq(argvars, rettv, TRUE);
11342}
11343
11344/*
11345 * "uniq({list})" function
11346 */
11347 static void
11348f_uniq(typval_T *argvars, typval_T *rettv)
11349{
11350 do_sort_uniq(argvars, rettv, FALSE);
11351}
11352
11353/*
11354 * "soundfold({word})" function
11355 */
11356 static void
11357f_soundfold(typval_T *argvars, typval_T *rettv)
11358{
11359 char_u *s;
11360
11361 rettv->v_type = VAR_STRING;
11362 s = get_tv_string(&argvars[0]);
11363#ifdef FEAT_SPELL
11364 rettv->vval.v_string = eval_soundfold(s);
11365#else
11366 rettv->vval.v_string = vim_strsave(s);
11367#endif
11368}
11369
11370/*
11371 * "spellbadword()" function
11372 */
11373 static void
11374f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11375{
11376 char_u *word = (char_u *)"";
11377 hlf_T attr = HLF_COUNT;
11378 int len = 0;
11379
11380 if (rettv_list_alloc(rettv) == FAIL)
11381 return;
11382
11383#ifdef FEAT_SPELL
11384 if (argvars[0].v_type == VAR_UNKNOWN)
11385 {
11386 /* Find the start and length of the badly spelled word. */
11387 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11388 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011389 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011390 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011391 curwin->w_set_curswant = TRUE;
11392 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011393 }
11394 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11395 {
11396 char_u *str = get_tv_string_chk(&argvars[0]);
11397 int capcol = -1;
11398
11399 if (str != NULL)
11400 {
11401 /* Check the argument for spelling. */
11402 while (*str != NUL)
11403 {
11404 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11405 if (attr != HLF_COUNT)
11406 {
11407 word = str;
11408 break;
11409 }
11410 str += len;
11411 }
11412 }
11413 }
11414#endif
11415
11416 list_append_string(rettv->vval.v_list, word, len);
11417 list_append_string(rettv->vval.v_list, (char_u *)(
11418 attr == HLF_SPB ? "bad" :
11419 attr == HLF_SPR ? "rare" :
11420 attr == HLF_SPL ? "local" :
11421 attr == HLF_SPC ? "caps" :
11422 ""), -1);
11423}
11424
11425/*
11426 * "spellsuggest()" function
11427 */
11428 static void
11429f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11430{
11431#ifdef FEAT_SPELL
11432 char_u *str;
11433 int typeerr = FALSE;
11434 int maxcount;
11435 garray_T ga;
11436 int i;
11437 listitem_T *li;
11438 int need_capital = FALSE;
11439#endif
11440
11441 if (rettv_list_alloc(rettv) == FAIL)
11442 return;
11443
11444#ifdef FEAT_SPELL
11445 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11446 {
11447 str = get_tv_string(&argvars[0]);
11448 if (argvars[1].v_type != VAR_UNKNOWN)
11449 {
11450 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11451 if (maxcount <= 0)
11452 return;
11453 if (argvars[2].v_type != VAR_UNKNOWN)
11454 {
11455 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11456 if (typeerr)
11457 return;
11458 }
11459 }
11460 else
11461 maxcount = 25;
11462
11463 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11464
11465 for (i = 0; i < ga.ga_len; ++i)
11466 {
11467 str = ((char_u **)ga.ga_data)[i];
11468
11469 li = listitem_alloc();
11470 if (li == NULL)
11471 vim_free(str);
11472 else
11473 {
11474 li->li_tv.v_type = VAR_STRING;
11475 li->li_tv.v_lock = 0;
11476 li->li_tv.vval.v_string = str;
11477 list_append(rettv->vval.v_list, li);
11478 }
11479 }
11480 ga_clear(&ga);
11481 }
11482#endif
11483}
11484
11485 static void
11486f_split(typval_T *argvars, typval_T *rettv)
11487{
11488 char_u *str;
11489 char_u *end;
11490 char_u *pat = NULL;
11491 regmatch_T regmatch;
11492 char_u patbuf[NUMBUFLEN];
11493 char_u *save_cpo;
11494 int match;
11495 colnr_T col = 0;
11496 int keepempty = FALSE;
11497 int typeerr = FALSE;
11498
11499 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11500 save_cpo = p_cpo;
11501 p_cpo = (char_u *)"";
11502
11503 str = get_tv_string(&argvars[0]);
11504 if (argvars[1].v_type != VAR_UNKNOWN)
11505 {
11506 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11507 if (pat == NULL)
11508 typeerr = TRUE;
11509 if (argvars[2].v_type != VAR_UNKNOWN)
11510 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11511 }
11512 if (pat == NULL || *pat == NUL)
11513 pat = (char_u *)"[\\x01- ]\\+";
11514
11515 if (rettv_list_alloc(rettv) == FAIL)
11516 return;
11517 if (typeerr)
11518 return;
11519
11520 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11521 if (regmatch.regprog != NULL)
11522 {
11523 regmatch.rm_ic = FALSE;
11524 while (*str != NUL || keepempty)
11525 {
11526 if (*str == NUL)
11527 match = FALSE; /* empty item at the end */
11528 else
11529 match = vim_regexec_nl(&regmatch, str, col);
11530 if (match)
11531 end = regmatch.startp[0];
11532 else
11533 end = str + STRLEN(str);
11534 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11535 && *str != NUL && match && end < regmatch.endp[0]))
11536 {
11537 if (list_append_string(rettv->vval.v_list, str,
11538 (int)(end - str)) == FAIL)
11539 break;
11540 }
11541 if (!match)
11542 break;
11543 /* Advance to just after the match. */
11544 if (regmatch.endp[0] > str)
11545 col = 0;
11546 else
11547 {
11548 /* Don't get stuck at the same match. */
11549#ifdef FEAT_MBYTE
11550 col = (*mb_ptr2len)(regmatch.endp[0]);
11551#else
11552 col = 1;
11553#endif
11554 }
11555 str = regmatch.endp[0];
11556 }
11557
11558 vim_regfree(regmatch.regprog);
11559 }
11560
11561 p_cpo = save_cpo;
11562}
11563
11564#ifdef FEAT_FLOAT
11565/*
11566 * "sqrt()" function
11567 */
11568 static void
11569f_sqrt(typval_T *argvars, typval_T *rettv)
11570{
11571 float_T f = 0.0;
11572
11573 rettv->v_type = VAR_FLOAT;
11574 if (get_float_arg(argvars, &f) == OK)
11575 rettv->vval.v_float = sqrt(f);
11576 else
11577 rettv->vval.v_float = 0.0;
11578}
11579
11580/*
11581 * "str2float()" function
11582 */
11583 static void
11584f_str2float(typval_T *argvars, typval_T *rettv)
11585{
11586 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011587 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011588
Bram Moolenaar08243d22017-01-10 16:12:29 +010011589 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011590 p = skipwhite(p + 1);
11591 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011592 if (isneg)
11593 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011594 rettv->v_type = VAR_FLOAT;
11595}
11596#endif
11597
11598/*
11599 * "str2nr()" function
11600 */
11601 static void
11602f_str2nr(typval_T *argvars, typval_T *rettv)
11603{
11604 int base = 10;
11605 char_u *p;
11606 varnumber_T n;
11607 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011608 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011609
11610 if (argvars[1].v_type != VAR_UNKNOWN)
11611 {
11612 base = (int)get_tv_number(&argvars[1]);
11613 if (base != 2 && base != 8 && base != 10 && base != 16)
11614 {
11615 EMSG(_(e_invarg));
11616 return;
11617 }
11618 }
11619
11620 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011621 isneg = (*p == '-');
11622 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011623 p = skipwhite(p + 1);
11624 switch (base)
11625 {
11626 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11627 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11628 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11629 default: what = 0;
11630 }
11631 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011632 if (isneg)
11633 rettv->vval.v_number = -n;
11634 else
11635 rettv->vval.v_number = n;
11636
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011637}
11638
11639#ifdef HAVE_STRFTIME
11640/*
11641 * "strftime({format}[, {time}])" function
11642 */
11643 static void
11644f_strftime(typval_T *argvars, typval_T *rettv)
11645{
11646 char_u result_buf[256];
11647 struct tm *curtime;
11648 time_t seconds;
11649 char_u *p;
11650
11651 rettv->v_type = VAR_STRING;
11652
11653 p = get_tv_string(&argvars[0]);
11654 if (argvars[1].v_type == VAR_UNKNOWN)
11655 seconds = time(NULL);
11656 else
11657 seconds = (time_t)get_tv_number(&argvars[1]);
11658 curtime = localtime(&seconds);
11659 /* MSVC returns NULL for an invalid value of seconds. */
11660 if (curtime == NULL)
11661 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11662 else
11663 {
11664# ifdef FEAT_MBYTE
11665 vimconv_T conv;
11666 char_u *enc;
11667
11668 conv.vc_type = CONV_NONE;
11669 enc = enc_locale();
11670 convert_setup(&conv, p_enc, enc);
11671 if (conv.vc_type != CONV_NONE)
11672 p = string_convert(&conv, p, NULL);
11673# endif
11674 if (p != NULL)
11675 (void)strftime((char *)result_buf, sizeof(result_buf),
11676 (char *)p, curtime);
11677 else
11678 result_buf[0] = NUL;
11679
11680# ifdef FEAT_MBYTE
11681 if (conv.vc_type != CONV_NONE)
11682 vim_free(p);
11683 convert_setup(&conv, enc, p_enc);
11684 if (conv.vc_type != CONV_NONE)
11685 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11686 else
11687# endif
11688 rettv->vval.v_string = vim_strsave(result_buf);
11689
11690# ifdef FEAT_MBYTE
11691 /* Release conversion descriptors */
11692 convert_setup(&conv, NULL, NULL);
11693 vim_free(enc);
11694# endif
11695 }
11696}
11697#endif
11698
11699/*
11700 * "strgetchar()" function
11701 */
11702 static void
11703f_strgetchar(typval_T *argvars, typval_T *rettv)
11704{
11705 char_u *str;
11706 int len;
11707 int error = FALSE;
11708 int charidx;
11709
11710 rettv->vval.v_number = -1;
11711 str = get_tv_string_chk(&argvars[0]);
11712 if (str == NULL)
11713 return;
11714 len = (int)STRLEN(str);
11715 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11716 if (error)
11717 return;
11718#ifdef FEAT_MBYTE
11719 {
11720 int byteidx = 0;
11721
11722 while (charidx >= 0 && byteidx < len)
11723 {
11724 if (charidx == 0)
11725 {
11726 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11727 break;
11728 }
11729 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011730 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011731 }
11732 }
11733#else
11734 if (charidx < len)
11735 rettv->vval.v_number = str[charidx];
11736#endif
11737}
11738
11739/*
11740 * "stridx()" function
11741 */
11742 static void
11743f_stridx(typval_T *argvars, typval_T *rettv)
11744{
11745 char_u buf[NUMBUFLEN];
11746 char_u *needle;
11747 char_u *haystack;
11748 char_u *save_haystack;
11749 char_u *pos;
11750 int start_idx;
11751
11752 needle = get_tv_string_chk(&argvars[1]);
11753 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11754 rettv->vval.v_number = -1;
11755 if (needle == NULL || haystack == NULL)
11756 return; /* type error; errmsg already given */
11757
11758 if (argvars[2].v_type != VAR_UNKNOWN)
11759 {
11760 int error = FALSE;
11761
11762 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11763 if (error || start_idx >= (int)STRLEN(haystack))
11764 return;
11765 if (start_idx >= 0)
11766 haystack += start_idx;
11767 }
11768
11769 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11770 if (pos != NULL)
11771 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11772}
11773
11774/*
11775 * "string()" function
11776 */
11777 static void
11778f_string(typval_T *argvars, typval_T *rettv)
11779{
11780 char_u *tofree;
11781 char_u numbuf[NUMBUFLEN];
11782
11783 rettv->v_type = VAR_STRING;
11784 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11785 get_copyID());
11786 /* Make a copy if we have a value but it's not in allocated memory. */
11787 if (rettv->vval.v_string != NULL && tofree == NULL)
11788 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11789}
11790
11791/*
11792 * "strlen()" function
11793 */
11794 static void
11795f_strlen(typval_T *argvars, typval_T *rettv)
11796{
11797 rettv->vval.v_number = (varnumber_T)(STRLEN(
11798 get_tv_string(&argvars[0])));
11799}
11800
11801/*
11802 * "strchars()" function
11803 */
11804 static void
11805f_strchars(typval_T *argvars, typval_T *rettv)
11806{
11807 char_u *s = get_tv_string(&argvars[0]);
11808 int skipcc = 0;
11809#ifdef FEAT_MBYTE
11810 varnumber_T len = 0;
11811 int (*func_mb_ptr2char_adv)(char_u **pp);
11812#endif
11813
11814 if (argvars[1].v_type != VAR_UNKNOWN)
11815 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11816 if (skipcc < 0 || skipcc > 1)
11817 EMSG(_(e_invarg));
11818 else
11819 {
11820#ifdef FEAT_MBYTE
11821 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11822 while (*s != NUL)
11823 {
11824 func_mb_ptr2char_adv(&s);
11825 ++len;
11826 }
11827 rettv->vval.v_number = len;
11828#else
11829 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11830#endif
11831 }
11832}
11833
11834/*
11835 * "strdisplaywidth()" function
11836 */
11837 static void
11838f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11839{
11840 char_u *s = get_tv_string(&argvars[0]);
11841 int col = 0;
11842
11843 if (argvars[1].v_type != VAR_UNKNOWN)
11844 col = (int)get_tv_number(&argvars[1]);
11845
11846 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11847}
11848
11849/*
11850 * "strwidth()" function
11851 */
11852 static void
11853f_strwidth(typval_T *argvars, typval_T *rettv)
11854{
11855 char_u *s = get_tv_string(&argvars[0]);
11856
11857 rettv->vval.v_number = (varnumber_T)(
11858#ifdef FEAT_MBYTE
11859 mb_string2cells(s, -1)
11860#else
11861 STRLEN(s)
11862#endif
11863 );
11864}
11865
11866/*
11867 * "strcharpart()" function
11868 */
11869 static void
11870f_strcharpart(typval_T *argvars, typval_T *rettv)
11871{
11872#ifdef FEAT_MBYTE
11873 char_u *p;
11874 int nchar;
11875 int nbyte = 0;
11876 int charlen;
11877 int len = 0;
11878 int slen;
11879 int error = FALSE;
11880
11881 p = get_tv_string(&argvars[0]);
11882 slen = (int)STRLEN(p);
11883
11884 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11885 if (!error)
11886 {
11887 if (nchar > 0)
11888 while (nchar > 0 && nbyte < slen)
11889 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011890 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011891 --nchar;
11892 }
11893 else
11894 nbyte = nchar;
11895 if (argvars[2].v_type != VAR_UNKNOWN)
11896 {
11897 charlen = (int)get_tv_number(&argvars[2]);
11898 while (charlen > 0 && nbyte + len < slen)
11899 {
11900 int off = nbyte + len;
11901
11902 if (off < 0)
11903 len += 1;
11904 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011905 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011906 --charlen;
11907 }
11908 }
11909 else
11910 len = slen - nbyte; /* default: all bytes that are available. */
11911 }
11912
11913 /*
11914 * Only return the overlap between the specified part and the actual
11915 * string.
11916 */
11917 if (nbyte < 0)
11918 {
11919 len += nbyte;
11920 nbyte = 0;
11921 }
11922 else if (nbyte > slen)
11923 nbyte = slen;
11924 if (len < 0)
11925 len = 0;
11926 else if (nbyte + len > slen)
11927 len = slen - nbyte;
11928
11929 rettv->v_type = VAR_STRING;
11930 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11931#else
11932 f_strpart(argvars, rettv);
11933#endif
11934}
11935
11936/*
11937 * "strpart()" function
11938 */
11939 static void
11940f_strpart(typval_T *argvars, typval_T *rettv)
11941{
11942 char_u *p;
11943 int n;
11944 int len;
11945 int slen;
11946 int error = FALSE;
11947
11948 p = get_tv_string(&argvars[0]);
11949 slen = (int)STRLEN(p);
11950
11951 n = (int)get_tv_number_chk(&argvars[1], &error);
11952 if (error)
11953 len = 0;
11954 else if (argvars[2].v_type != VAR_UNKNOWN)
11955 len = (int)get_tv_number(&argvars[2]);
11956 else
11957 len = slen - n; /* default len: all bytes that are available. */
11958
11959 /*
11960 * Only return the overlap between the specified part and the actual
11961 * string.
11962 */
11963 if (n < 0)
11964 {
11965 len += n;
11966 n = 0;
11967 }
11968 else if (n > slen)
11969 n = slen;
11970 if (len < 0)
11971 len = 0;
11972 else if (n + len > slen)
11973 len = slen - n;
11974
11975 rettv->v_type = VAR_STRING;
11976 rettv->vval.v_string = vim_strnsave(p + n, len);
11977}
11978
11979/*
11980 * "strridx()" function
11981 */
11982 static void
11983f_strridx(typval_T *argvars, typval_T *rettv)
11984{
11985 char_u buf[NUMBUFLEN];
11986 char_u *needle;
11987 char_u *haystack;
11988 char_u *rest;
11989 char_u *lastmatch = NULL;
11990 int haystack_len, end_idx;
11991
11992 needle = get_tv_string_chk(&argvars[1]);
11993 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11994
11995 rettv->vval.v_number = -1;
11996 if (needle == NULL || haystack == NULL)
11997 return; /* type error; errmsg already given */
11998
11999 haystack_len = (int)STRLEN(haystack);
12000 if (argvars[2].v_type != VAR_UNKNOWN)
12001 {
12002 /* Third argument: upper limit for index */
12003 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12004 if (end_idx < 0)
12005 return; /* can never find a match */
12006 }
12007 else
12008 end_idx = haystack_len;
12009
12010 if (*needle == NUL)
12011 {
12012 /* Empty string matches past the end. */
12013 lastmatch = haystack + end_idx;
12014 }
12015 else
12016 {
12017 for (rest = haystack; *rest != '\0'; ++rest)
12018 {
12019 rest = (char_u *)strstr((char *)rest, (char *)needle);
12020 if (rest == NULL || rest > haystack + end_idx)
12021 break;
12022 lastmatch = rest;
12023 }
12024 }
12025
12026 if (lastmatch == NULL)
12027 rettv->vval.v_number = -1;
12028 else
12029 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12030}
12031
12032/*
12033 * "strtrans()" function
12034 */
12035 static void
12036f_strtrans(typval_T *argvars, typval_T *rettv)
12037{
12038 rettv->v_type = VAR_STRING;
12039 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12040}
12041
12042/*
12043 * "submatch()" function
12044 */
12045 static void
12046f_submatch(typval_T *argvars, typval_T *rettv)
12047{
12048 int error = FALSE;
12049 int no;
12050 int retList = 0;
12051
12052 no = (int)get_tv_number_chk(&argvars[0], &error);
12053 if (error)
12054 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012055 if (no < 0 || no >= NSUBEXP)
12056 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012057 EMSGN(_("E935: invalid submatch number: %d"), no);
12058 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012059 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012060 if (argvars[1].v_type != VAR_UNKNOWN)
12061 retList = (int)get_tv_number_chk(&argvars[1], &error);
12062 if (error)
12063 return;
12064
12065 if (retList == 0)
12066 {
12067 rettv->v_type = VAR_STRING;
12068 rettv->vval.v_string = reg_submatch(no);
12069 }
12070 else
12071 {
12072 rettv->v_type = VAR_LIST;
12073 rettv->vval.v_list = reg_submatch_list(no);
12074 }
12075}
12076
12077/*
12078 * "substitute()" function
12079 */
12080 static void
12081f_substitute(typval_T *argvars, typval_T *rettv)
12082{
12083 char_u patbuf[NUMBUFLEN];
12084 char_u subbuf[NUMBUFLEN];
12085 char_u flagsbuf[NUMBUFLEN];
12086
12087 char_u *str = get_tv_string_chk(&argvars[0]);
12088 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012089 char_u *sub = NULL;
12090 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012091 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12092
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012093 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12094 expr = &argvars[2];
12095 else
12096 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012098 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012099 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12100 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012101 rettv->vval.v_string = NULL;
12102 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012103 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012104}
12105
12106/*
12107 * "synID(lnum, col, trans)" function
12108 */
12109 static void
12110f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12111{
12112 int id = 0;
12113#ifdef FEAT_SYN_HL
12114 linenr_T lnum;
12115 colnr_T col;
12116 int trans;
12117 int transerr = FALSE;
12118
12119 lnum = get_tv_lnum(argvars); /* -1 on type error */
12120 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12121 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12122
12123 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12124 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12125 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12126#endif
12127
12128 rettv->vval.v_number = id;
12129}
12130
12131/*
12132 * "synIDattr(id, what [, mode])" function
12133 */
12134 static void
12135f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12136{
12137 char_u *p = NULL;
12138#ifdef FEAT_SYN_HL
12139 int id;
12140 char_u *what;
12141 char_u *mode;
12142 char_u modebuf[NUMBUFLEN];
12143 int modec;
12144
12145 id = (int)get_tv_number(&argvars[0]);
12146 what = get_tv_string(&argvars[1]);
12147 if (argvars[2].v_type != VAR_UNKNOWN)
12148 {
12149 mode = get_tv_string_buf(&argvars[2], modebuf);
12150 modec = TOLOWER_ASC(mode[0]);
12151 if (modec != 't' && modec != 'c' && modec != 'g')
12152 modec = 0; /* replace invalid with current */
12153 }
12154 else
12155 {
12156#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12157 if (USE_24BIT)
12158 modec = 'g';
12159 else
12160#endif
12161 if (t_colors > 1)
12162 modec = 'c';
12163 else
12164 modec = 't';
12165 }
12166
12167
12168 switch (TOLOWER_ASC(what[0]))
12169 {
12170 case 'b':
12171 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12172 p = highlight_color(id, what, modec);
12173 else /* bold */
12174 p = highlight_has_attr(id, HL_BOLD, modec);
12175 break;
12176
12177 case 'f': /* fg[#] or font */
12178 p = highlight_color(id, what, modec);
12179 break;
12180
12181 case 'i':
12182 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12183 p = highlight_has_attr(id, HL_INVERSE, modec);
12184 else /* italic */
12185 p = highlight_has_attr(id, HL_ITALIC, modec);
12186 break;
12187
12188 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012189 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012190 break;
12191
12192 case 'r': /* reverse */
12193 p = highlight_has_attr(id, HL_INVERSE, modec);
12194 break;
12195
12196 case 's':
12197 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12198 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012199 /* strikeout */
12200 else if (TOLOWER_ASC(what[1]) == 't' &&
12201 TOLOWER_ASC(what[2]) == 'r')
12202 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012203 else /* standout */
12204 p = highlight_has_attr(id, HL_STANDOUT, modec);
12205 break;
12206
12207 case 'u':
12208 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12209 /* underline */
12210 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12211 else
12212 /* undercurl */
12213 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12214 break;
12215 }
12216
12217 if (p != NULL)
12218 p = vim_strsave(p);
12219#endif
12220 rettv->v_type = VAR_STRING;
12221 rettv->vval.v_string = p;
12222}
12223
12224/*
12225 * "synIDtrans(id)" function
12226 */
12227 static void
12228f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12229{
12230 int id;
12231
12232#ifdef FEAT_SYN_HL
12233 id = (int)get_tv_number(&argvars[0]);
12234
12235 if (id > 0)
12236 id = syn_get_final_id(id);
12237 else
12238#endif
12239 id = 0;
12240
12241 rettv->vval.v_number = id;
12242}
12243
12244/*
12245 * "synconcealed(lnum, col)" function
12246 */
12247 static void
12248f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12249{
12250#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12251 linenr_T lnum;
12252 colnr_T col;
12253 int syntax_flags = 0;
12254 int cchar;
12255 int matchid = 0;
12256 char_u str[NUMBUFLEN];
12257#endif
12258
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012259 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012260
12261#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12262 lnum = get_tv_lnum(argvars); /* -1 on type error */
12263 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12264
12265 vim_memset(str, NUL, sizeof(str));
12266
12267 if (rettv_list_alloc(rettv) != FAIL)
12268 {
12269 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12270 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12271 && curwin->w_p_cole > 0)
12272 {
12273 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12274 syntax_flags = get_syntax_info(&matchid);
12275
12276 /* get the conceal character */
12277 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12278 {
12279 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012280 if (cchar == NUL && curwin->w_p_cole == 1)
12281 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012282 if (cchar != NUL)
12283 {
12284# ifdef FEAT_MBYTE
12285 if (has_mbyte)
12286 (*mb_char2bytes)(cchar, str);
12287 else
12288# endif
12289 str[0] = cchar;
12290 }
12291 }
12292 }
12293
12294 list_append_number(rettv->vval.v_list,
12295 (syntax_flags & HL_CONCEAL) != 0);
12296 /* -1 to auto-determine strlen */
12297 list_append_string(rettv->vval.v_list, str, -1);
12298 list_append_number(rettv->vval.v_list, matchid);
12299 }
12300#endif
12301}
12302
12303/*
12304 * "synstack(lnum, col)" function
12305 */
12306 static void
12307f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12308{
12309#ifdef FEAT_SYN_HL
12310 linenr_T lnum;
12311 colnr_T col;
12312 int i;
12313 int id;
12314#endif
12315
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012316 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012317
12318#ifdef FEAT_SYN_HL
12319 lnum = get_tv_lnum(argvars); /* -1 on type error */
12320 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12321
12322 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12323 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12324 && rettv_list_alloc(rettv) != FAIL)
12325 {
12326 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12327 for (i = 0; ; ++i)
12328 {
12329 id = syn_get_stack_item(i);
12330 if (id < 0)
12331 break;
12332 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12333 break;
12334 }
12335 }
12336#endif
12337}
12338
12339 static void
12340get_cmd_output_as_rettv(
12341 typval_T *argvars,
12342 typval_T *rettv,
12343 int retlist)
12344{
12345 char_u *res = NULL;
12346 char_u *p;
12347 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012348 int err = FALSE;
12349 FILE *fd;
12350 list_T *list = NULL;
12351 int flags = SHELL_SILENT;
12352
12353 rettv->v_type = VAR_STRING;
12354 rettv->vval.v_string = NULL;
12355 if (check_restricted() || check_secure())
12356 goto errret;
12357
12358 if (argvars[1].v_type != VAR_UNKNOWN)
12359 {
12360 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012361 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012362 * command.
12363 */
12364 if ((infile = vim_tempname('i', TRUE)) == NULL)
12365 {
12366 EMSG(_(e_notmp));
12367 goto errret;
12368 }
12369
12370 fd = mch_fopen((char *)infile, WRITEBIN);
12371 if (fd == NULL)
12372 {
12373 EMSG2(_(e_notopen), infile);
12374 goto errret;
12375 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012376 if (argvars[1].v_type == VAR_NUMBER)
12377 {
12378 linenr_T lnum;
12379 buf_T *buf;
12380
12381 buf = buflist_findnr(argvars[1].vval.v_number);
12382 if (buf == NULL)
12383 {
12384 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012385 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012386 goto errret;
12387 }
12388
12389 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12390 {
12391 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12392 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12393 {
12394 err = TRUE;
12395 break;
12396 }
12397 if (putc(NL, fd) == EOF)
12398 {
12399 err = TRUE;
12400 break;
12401 }
12402 }
12403 }
12404 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012405 {
12406 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12407 err = TRUE;
12408 }
12409 else
12410 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012411 size_t len;
12412 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012413
12414 p = get_tv_string_buf_chk(&argvars[1], buf);
12415 if (p == NULL)
12416 {
12417 fclose(fd);
12418 goto errret; /* type error; errmsg already given */
12419 }
12420 len = STRLEN(p);
12421 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12422 err = TRUE;
12423 }
12424 if (fclose(fd) != 0)
12425 err = TRUE;
12426 if (err)
12427 {
12428 EMSG(_("E677: Error writing temp file"));
12429 goto errret;
12430 }
12431 }
12432
12433 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12434 * echoes typeahead, that messes up the display. */
12435 if (!msg_silent)
12436 flags += SHELL_COOKED;
12437
12438 if (retlist)
12439 {
12440 int len;
12441 listitem_T *li;
12442 char_u *s = NULL;
12443 char_u *start;
12444 char_u *end;
12445 int i;
12446
12447 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12448 if (res == NULL)
12449 goto errret;
12450
12451 list = list_alloc();
12452 if (list == NULL)
12453 goto errret;
12454
12455 for (i = 0; i < len; ++i)
12456 {
12457 start = res + i;
12458 while (i < len && res[i] != NL)
12459 ++i;
12460 end = res + i;
12461
12462 s = alloc((unsigned)(end - start + 1));
12463 if (s == NULL)
12464 goto errret;
12465
12466 for (p = s; start < end; ++p, ++start)
12467 *p = *start == NUL ? NL : *start;
12468 *p = NUL;
12469
12470 li = listitem_alloc();
12471 if (li == NULL)
12472 {
12473 vim_free(s);
12474 goto errret;
12475 }
12476 li->li_tv.v_type = VAR_STRING;
12477 li->li_tv.v_lock = 0;
12478 li->li_tv.vval.v_string = s;
12479 list_append(list, li);
12480 }
12481
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012482 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012483 list = NULL;
12484 }
12485 else
12486 {
12487 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12488#ifdef USE_CR
12489 /* translate <CR> into <NL> */
12490 if (res != NULL)
12491 {
12492 char_u *s;
12493
12494 for (s = res; *s; ++s)
12495 {
12496 if (*s == CAR)
12497 *s = NL;
12498 }
12499 }
12500#else
12501# ifdef USE_CRNL
12502 /* translate <CR><NL> into <NL> */
12503 if (res != NULL)
12504 {
12505 char_u *s, *d;
12506
12507 d = res;
12508 for (s = res; *s; ++s)
12509 {
12510 if (s[0] == CAR && s[1] == NL)
12511 ++s;
12512 *d++ = *s;
12513 }
12514 *d = NUL;
12515 }
12516# endif
12517#endif
12518 rettv->vval.v_string = res;
12519 res = NULL;
12520 }
12521
12522errret:
12523 if (infile != NULL)
12524 {
12525 mch_remove(infile);
12526 vim_free(infile);
12527 }
12528 if (res != NULL)
12529 vim_free(res);
12530 if (list != NULL)
12531 list_free(list);
12532}
12533
12534/*
12535 * "system()" function
12536 */
12537 static void
12538f_system(typval_T *argvars, typval_T *rettv)
12539{
12540 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12541}
12542
12543/*
12544 * "systemlist()" function
12545 */
12546 static void
12547f_systemlist(typval_T *argvars, typval_T *rettv)
12548{
12549 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12550}
12551
12552/*
12553 * "tabpagebuflist()" function
12554 */
12555 static void
12556f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12557{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012558 tabpage_T *tp;
12559 win_T *wp = NULL;
12560
12561 if (argvars[0].v_type == VAR_UNKNOWN)
12562 wp = firstwin;
12563 else
12564 {
12565 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12566 if (tp != NULL)
12567 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12568 }
12569 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12570 {
12571 for (; wp != NULL; wp = wp->w_next)
12572 if (list_append_number(rettv->vval.v_list,
12573 wp->w_buffer->b_fnum) == FAIL)
12574 break;
12575 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012576}
12577
12578
12579/*
12580 * "tabpagenr()" function
12581 */
12582 static void
12583f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12584{
12585 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012586 char_u *arg;
12587
12588 if (argvars[0].v_type != VAR_UNKNOWN)
12589 {
12590 arg = get_tv_string_chk(&argvars[0]);
12591 nr = 0;
12592 if (arg != NULL)
12593 {
12594 if (STRCMP(arg, "$") == 0)
12595 nr = tabpage_index(NULL) - 1;
12596 else
12597 EMSG2(_(e_invexpr2), arg);
12598 }
12599 }
12600 else
12601 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012602 rettv->vval.v_number = nr;
12603}
12604
12605
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012606static int get_winnr(tabpage_T *tp, typval_T *argvar);
12607
12608/*
12609 * Common code for tabpagewinnr() and winnr().
12610 */
12611 static int
12612get_winnr(tabpage_T *tp, typval_T *argvar)
12613{
12614 win_T *twin;
12615 int nr = 1;
12616 win_T *wp;
12617 char_u *arg;
12618
12619 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12620 if (argvar->v_type != VAR_UNKNOWN)
12621 {
12622 arg = get_tv_string_chk(argvar);
12623 if (arg == NULL)
12624 nr = 0; /* type error; errmsg already given */
12625 else if (STRCMP(arg, "$") == 0)
12626 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12627 else if (STRCMP(arg, "#") == 0)
12628 {
12629 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12630 if (twin == NULL)
12631 nr = 0;
12632 }
12633 else
12634 {
12635 EMSG2(_(e_invexpr2), arg);
12636 nr = 0;
12637 }
12638 }
12639
12640 if (nr > 0)
12641 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12642 wp != twin; wp = wp->w_next)
12643 {
12644 if (wp == NULL)
12645 {
12646 /* didn't find it in this tabpage */
12647 nr = 0;
12648 break;
12649 }
12650 ++nr;
12651 }
12652 return nr;
12653}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012654
12655/*
12656 * "tabpagewinnr()" function
12657 */
12658 static void
12659f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12660{
12661 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012662 tabpage_T *tp;
12663
12664 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12665 if (tp == NULL)
12666 nr = 0;
12667 else
12668 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012669 rettv->vval.v_number = nr;
12670}
12671
12672
12673/*
12674 * "tagfiles()" function
12675 */
12676 static void
12677f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12678{
12679 char_u *fname;
12680 tagname_T tn;
12681 int first;
12682
12683 if (rettv_list_alloc(rettv) == FAIL)
12684 return;
12685 fname = alloc(MAXPATHL);
12686 if (fname == NULL)
12687 return;
12688
12689 for (first = TRUE; ; first = FALSE)
12690 if (get_tagfname(&tn, first, fname) == FAIL
12691 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12692 break;
12693 tagname_free(&tn);
12694 vim_free(fname);
12695}
12696
12697/*
12698 * "taglist()" function
12699 */
12700 static void
12701f_taglist(typval_T *argvars, typval_T *rettv)
12702{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012703 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012704 char_u *tag_pattern;
12705
12706 tag_pattern = get_tv_string(&argvars[0]);
12707
12708 rettv->vval.v_number = FALSE;
12709 if (*tag_pattern == NUL)
12710 return;
12711
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012712 if (argvars[1].v_type != VAR_UNKNOWN)
12713 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012714 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012715 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012716}
12717
12718/*
12719 * "tempname()" function
12720 */
12721 static void
12722f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12723{
12724 static int x = 'A';
12725
12726 rettv->v_type = VAR_STRING;
12727 rettv->vval.v_string = vim_tempname(x, FALSE);
12728
12729 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12730 * names. Skip 'I' and 'O', they are used for shell redirection. */
12731 do
12732 {
12733 if (x == 'Z')
12734 x = '0';
12735 else if (x == '9')
12736 x = 'A';
12737 else
12738 {
12739#ifdef EBCDIC
12740 if (x == 'I')
12741 x = 'J';
12742 else if (x == 'R')
12743 x = 'S';
12744 else
12745#endif
12746 ++x;
12747 }
12748 } while (x == 'I' || x == 'O');
12749}
12750
12751#ifdef FEAT_FLOAT
12752/*
12753 * "tan()" function
12754 */
12755 static void
12756f_tan(typval_T *argvars, typval_T *rettv)
12757{
12758 float_T f = 0.0;
12759
12760 rettv->v_type = VAR_FLOAT;
12761 if (get_float_arg(argvars, &f) == OK)
12762 rettv->vval.v_float = tan(f);
12763 else
12764 rettv->vval.v_float = 0.0;
12765}
12766
12767/*
12768 * "tanh()" function
12769 */
12770 static void
12771f_tanh(typval_T *argvars, typval_T *rettv)
12772{
12773 float_T f = 0.0;
12774
12775 rettv->v_type = VAR_FLOAT;
12776 if (get_float_arg(argvars, &f) == OK)
12777 rettv->vval.v_float = tanh(f);
12778 else
12779 rettv->vval.v_float = 0.0;
12780}
12781#endif
12782
12783/*
12784 * "test_alloc_fail(id, countdown, repeat)" function
12785 */
12786 static void
12787f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12788{
12789 if (argvars[0].v_type != VAR_NUMBER
12790 || argvars[0].vval.v_number <= 0
12791 || argvars[1].v_type != VAR_NUMBER
12792 || argvars[1].vval.v_number < 0
12793 || argvars[2].v_type != VAR_NUMBER)
12794 EMSG(_(e_invarg));
12795 else
12796 {
12797 alloc_fail_id = argvars[0].vval.v_number;
12798 if (alloc_fail_id >= aid_last)
12799 EMSG(_(e_invarg));
12800 alloc_fail_countdown = argvars[1].vval.v_number;
12801 alloc_fail_repeat = argvars[2].vval.v_number;
12802 did_outofmem_msg = FALSE;
12803 }
12804}
12805
12806/*
12807 * "test_autochdir()"
12808 */
12809 static void
12810f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12811{
12812#if defined(FEAT_AUTOCHDIR)
12813 test_autochdir = TRUE;
12814#endif
12815}
12816
12817/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012818 * "test_feedinput()"
12819 */
12820 static void
12821f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12822{
12823#ifdef USE_INPUT_BUF
12824 char_u *val = get_tv_string_chk(&argvars[0]);
12825
12826 if (val != NULL)
12827 {
12828 trash_input_buf();
12829 add_to_input_buf_csi(val, (int)STRLEN(val));
12830 }
12831#endif
12832}
12833
12834/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012835 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012836 */
12837 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012838f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012839{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012840 char_u *name = (char_u *)"";
12841 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012842 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012843
12844 if (argvars[0].v_type != VAR_STRING
12845 || (argvars[1].v_type) != VAR_NUMBER)
12846 EMSG(_(e_invarg));
12847 else
12848 {
12849 name = get_tv_string_chk(&argvars[0]);
12850 val = (int)get_tv_number(&argvars[1]);
12851
12852 if (STRCMP(name, (char_u *)"redraw") == 0)
12853 disable_redraw_for_testing = val;
12854 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12855 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012856 else if (STRCMP(name, (char_u *)"starting") == 0)
12857 {
12858 if (val)
12859 {
12860 if (save_starting < 0)
12861 save_starting = starting;
12862 starting = 0;
12863 }
12864 else
12865 {
12866 starting = save_starting;
12867 save_starting = -1;
12868 }
12869 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012870 else if (STRCMP(name, (char_u *)"ALL") == 0)
12871 {
12872 disable_char_avail_for_testing = FALSE;
12873 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012874 if (save_starting >= 0)
12875 {
12876 starting = save_starting;
12877 save_starting = -1;
12878 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012879 }
12880 else
12881 EMSG2(_(e_invarg2), name);
12882 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012883}
12884
12885/*
12886 * "test_garbagecollect_now()" function
12887 */
12888 static void
12889f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12890{
12891 /* This is dangerous, any Lists and Dicts used internally may be freed
12892 * while still in use. */
12893 garbage_collect(TRUE);
12894}
12895
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012896/*
12897 * "test_ignore_error()" function
12898 */
12899 static void
12900f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12901{
12902 ignore_error_for_testing(get_tv_string(&argvars[0]));
12903}
12904
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012905#ifdef FEAT_JOB_CHANNEL
12906 static void
12907f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12908{
12909 rettv->v_type = VAR_CHANNEL;
12910 rettv->vval.v_channel = NULL;
12911}
12912#endif
12913
12914 static void
12915f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12916{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012917 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012918}
12919
12920#ifdef FEAT_JOB_CHANNEL
12921 static void
12922f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12923{
12924 rettv->v_type = VAR_JOB;
12925 rettv->vval.v_job = NULL;
12926}
12927#endif
12928
12929 static void
12930f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12931{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012932 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012933}
12934
12935 static void
12936f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12937{
12938 rettv->v_type = VAR_PARTIAL;
12939 rettv->vval.v_partial = NULL;
12940}
12941
12942 static void
12943f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12944{
12945 rettv->v_type = VAR_STRING;
12946 rettv->vval.v_string = NULL;
12947}
12948
12949 static void
12950f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12951{
12952 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12953}
12954
12955#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12956/*
12957 * Get a callback from "arg". It can be a Funcref or a function name.
12958 * When "arg" is zero return an empty string.
12959 * Return NULL for an invalid argument.
12960 */
12961 char_u *
12962get_callback(typval_T *arg, partial_T **pp)
12963{
12964 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12965 {
12966 *pp = arg->vval.v_partial;
12967 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012968 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012969 }
12970 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012971 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012972 {
12973 func_ref(arg->vval.v_string);
12974 return arg->vval.v_string;
12975 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012976 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12977 return (char_u *)"";
12978 EMSG(_("E921: Invalid callback argument"));
12979 return NULL;
12980}
12981
12982/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020012983 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012984 */
12985 void
12986free_callback(char_u *callback, partial_T *partial)
12987{
12988 if (partial != NULL)
12989 partial_unref(partial);
12990 else if (callback != NULL)
12991 {
12992 func_unref(callback);
12993 vim_free(callback);
12994 }
12995}
12996#endif
12997
12998#ifdef FEAT_TIMERS
12999/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013000 * "timer_info([timer])" function
13001 */
13002 static void
13003f_timer_info(typval_T *argvars, typval_T *rettv)
13004{
13005 timer_T *timer = NULL;
13006
13007 if (rettv_list_alloc(rettv) != OK)
13008 return;
13009 if (argvars[0].v_type != VAR_UNKNOWN)
13010 {
13011 if (argvars[0].v_type != VAR_NUMBER)
13012 EMSG(_(e_number_exp));
13013 else
13014 {
13015 timer = find_timer((int)get_tv_number(&argvars[0]));
13016 if (timer != NULL)
13017 add_timer_info(rettv, timer);
13018 }
13019 }
13020 else
13021 add_timer_info_all(rettv);
13022}
13023
13024/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013025 * "timer_pause(timer, paused)" function
13026 */
13027 static void
13028f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13029{
13030 timer_T *timer = NULL;
13031 int paused = (int)get_tv_number(&argvars[1]);
13032
13033 if (argvars[0].v_type != VAR_NUMBER)
13034 EMSG(_(e_number_exp));
13035 else
13036 {
13037 timer = find_timer((int)get_tv_number(&argvars[0]));
13038 if (timer != NULL)
13039 timer->tr_paused = paused;
13040 }
13041}
13042
13043/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013044 * "timer_start(time, callback [, options])" function
13045 */
13046 static void
13047f_timer_start(typval_T *argvars, typval_T *rettv)
13048{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013049 long msec = (long)get_tv_number(&argvars[0]);
13050 timer_T *timer;
13051 int repeat = 0;
13052 char_u *callback;
13053 dict_T *dict;
13054 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013055
Bram Moolenaar75537a92016-09-05 22:45:28 +020013056 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013057 if (check_secure())
13058 return;
13059 if (argvars[2].v_type != VAR_UNKNOWN)
13060 {
13061 if (argvars[2].v_type != VAR_DICT
13062 || (dict = argvars[2].vval.v_dict) == NULL)
13063 {
13064 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13065 return;
13066 }
13067 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13068 repeat = get_dict_number(dict, (char_u *)"repeat");
13069 }
13070
Bram Moolenaar75537a92016-09-05 22:45:28 +020013071 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013072 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013073 return;
13074
13075 timer = create_timer(msec, repeat);
13076 if (timer == NULL)
13077 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013078 else
13079 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013080 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013081 timer->tr_callback = vim_strsave(callback);
13082 else
13083 /* pointer into the partial */
13084 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013085 timer->tr_partial = partial;
13086 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013087 }
13088}
13089
13090/*
13091 * "timer_stop(timer)" function
13092 */
13093 static void
13094f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13095{
13096 timer_T *timer;
13097
13098 if (argvars[0].v_type != VAR_NUMBER)
13099 {
13100 EMSG(_(e_number_exp));
13101 return;
13102 }
13103 timer = find_timer((int)get_tv_number(&argvars[0]));
13104 if (timer != NULL)
13105 stop_timer(timer);
13106}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013107
13108/*
13109 * "timer_stopall()" function
13110 */
13111 static void
13112f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13113{
13114 stop_all_timers();
13115}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013116#endif
13117
13118/*
13119 * "tolower(string)" function
13120 */
13121 static void
13122f_tolower(typval_T *argvars, typval_T *rettv)
13123{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013124 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013125 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013126}
13127
13128/*
13129 * "toupper(string)" function
13130 */
13131 static void
13132f_toupper(typval_T *argvars, typval_T *rettv)
13133{
13134 rettv->v_type = VAR_STRING;
13135 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13136}
13137
13138/*
13139 * "tr(string, fromstr, tostr)" function
13140 */
13141 static void
13142f_tr(typval_T *argvars, typval_T *rettv)
13143{
13144 char_u *in_str;
13145 char_u *fromstr;
13146 char_u *tostr;
13147 char_u *p;
13148#ifdef FEAT_MBYTE
13149 int inlen;
13150 int fromlen;
13151 int tolen;
13152 int idx;
13153 char_u *cpstr;
13154 int cplen;
13155 int first = TRUE;
13156#endif
13157 char_u buf[NUMBUFLEN];
13158 char_u buf2[NUMBUFLEN];
13159 garray_T ga;
13160
13161 in_str = get_tv_string(&argvars[0]);
13162 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13163 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13164
13165 /* Default return value: empty string. */
13166 rettv->v_type = VAR_STRING;
13167 rettv->vval.v_string = NULL;
13168 if (fromstr == NULL || tostr == NULL)
13169 return; /* type error; errmsg already given */
13170 ga_init2(&ga, (int)sizeof(char), 80);
13171
13172#ifdef FEAT_MBYTE
13173 if (!has_mbyte)
13174#endif
13175 /* not multi-byte: fromstr and tostr must be the same length */
13176 if (STRLEN(fromstr) != STRLEN(tostr))
13177 {
13178#ifdef FEAT_MBYTE
13179error:
13180#endif
13181 EMSG2(_(e_invarg2), fromstr);
13182 ga_clear(&ga);
13183 return;
13184 }
13185
13186 /* fromstr and tostr have to contain the same number of chars */
13187 while (*in_str != NUL)
13188 {
13189#ifdef FEAT_MBYTE
13190 if (has_mbyte)
13191 {
13192 inlen = (*mb_ptr2len)(in_str);
13193 cpstr = in_str;
13194 cplen = inlen;
13195 idx = 0;
13196 for (p = fromstr; *p != NUL; p += fromlen)
13197 {
13198 fromlen = (*mb_ptr2len)(p);
13199 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13200 {
13201 for (p = tostr; *p != NUL; p += tolen)
13202 {
13203 tolen = (*mb_ptr2len)(p);
13204 if (idx-- == 0)
13205 {
13206 cplen = tolen;
13207 cpstr = p;
13208 break;
13209 }
13210 }
13211 if (*p == NUL) /* tostr is shorter than fromstr */
13212 goto error;
13213 break;
13214 }
13215 ++idx;
13216 }
13217
13218 if (first && cpstr == in_str)
13219 {
13220 /* Check that fromstr and tostr have the same number of
13221 * (multi-byte) characters. Done only once when a character
13222 * of in_str doesn't appear in fromstr. */
13223 first = FALSE;
13224 for (p = tostr; *p != NUL; p += tolen)
13225 {
13226 tolen = (*mb_ptr2len)(p);
13227 --idx;
13228 }
13229 if (idx != 0)
13230 goto error;
13231 }
13232
13233 (void)ga_grow(&ga, cplen);
13234 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13235 ga.ga_len += cplen;
13236
13237 in_str += inlen;
13238 }
13239 else
13240#endif
13241 {
13242 /* When not using multi-byte chars we can do it faster. */
13243 p = vim_strchr(fromstr, *in_str);
13244 if (p != NULL)
13245 ga_append(&ga, tostr[p - fromstr]);
13246 else
13247 ga_append(&ga, *in_str);
13248 ++in_str;
13249 }
13250 }
13251
13252 /* add a terminating NUL */
13253 (void)ga_grow(&ga, 1);
13254 ga_append(&ga, NUL);
13255
13256 rettv->vval.v_string = ga.ga_data;
13257}
13258
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013259/*
13260 * "trim({expr})" function
13261 */
13262 static void
13263f_trim(typval_T *argvars, typval_T *rettv)
13264{
13265 char_u buf1[NUMBUFLEN];
13266 char_u buf2[NUMBUFLEN];
13267 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13268 char_u *mask = NULL;
13269 char_u *tail;
13270 char_u *prev;
13271 char_u *p;
13272 int c1;
13273
13274 rettv->v_type = VAR_STRING;
13275 if (head == NULL)
13276 {
13277 rettv->vval.v_string = NULL;
13278 return;
13279 }
13280
13281 if (argvars[1].v_type == VAR_STRING)
13282 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13283
13284 while (*head != NUL)
13285 {
13286 c1 = PTR2CHAR(head);
13287 if (mask == NULL)
13288 {
13289 if (c1 > ' ' && c1 != 0xa0)
13290 break;
13291 }
13292 else
13293 {
13294 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13295 if (c1 == PTR2CHAR(p))
13296 break;
13297 if (*p == NUL)
13298 break;
13299 }
13300 MB_PTR_ADV(head);
13301 }
13302
13303 for (tail = head + STRLEN(head); tail > head; tail = prev)
13304 {
13305 prev = tail;
13306 MB_PTR_BACK(head, prev);
13307 c1 = PTR2CHAR(prev);
13308 if (mask == NULL)
13309 {
13310 if (c1 > ' ' && c1 != 0xa0)
13311 break;
13312 }
13313 else
13314 {
13315 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13316 if (c1 == PTR2CHAR(p))
13317 break;
13318 if (*p == NUL)
13319 break;
13320 }
13321 }
13322 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13323}
13324
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013325#ifdef FEAT_FLOAT
13326/*
13327 * "trunc({float})" function
13328 */
13329 static void
13330f_trunc(typval_T *argvars, typval_T *rettv)
13331{
13332 float_T f = 0.0;
13333
13334 rettv->v_type = VAR_FLOAT;
13335 if (get_float_arg(argvars, &f) == OK)
13336 /* trunc() is not in C90, use floor() or ceil() instead. */
13337 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13338 else
13339 rettv->vval.v_float = 0.0;
13340}
13341#endif
13342
13343/*
13344 * "type(expr)" function
13345 */
13346 static void
13347f_type(typval_T *argvars, typval_T *rettv)
13348{
13349 int n = -1;
13350
13351 switch (argvars[0].v_type)
13352 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013353 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13354 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013355 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013356 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13357 case VAR_LIST: n = VAR_TYPE_LIST; break;
13358 case VAR_DICT: n = VAR_TYPE_DICT; break;
13359 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013360 case VAR_SPECIAL:
13361 if (argvars[0].vval.v_number == VVAL_FALSE
13362 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013363 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013364 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013365 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013366 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013367 case VAR_JOB: n = VAR_TYPE_JOB; break;
13368 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013369 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013370 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013371 n = -1;
13372 break;
13373 }
13374 rettv->vval.v_number = n;
13375}
13376
13377/*
13378 * "undofile(name)" function
13379 */
13380 static void
13381f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13382{
13383 rettv->v_type = VAR_STRING;
13384#ifdef FEAT_PERSISTENT_UNDO
13385 {
13386 char_u *fname = get_tv_string(&argvars[0]);
13387
13388 if (*fname == NUL)
13389 {
13390 /* If there is no file name there will be no undo file. */
13391 rettv->vval.v_string = NULL;
13392 }
13393 else
13394 {
13395 char_u *ffname = FullName_save(fname, FALSE);
13396
13397 if (ffname != NULL)
13398 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13399 vim_free(ffname);
13400 }
13401 }
13402#else
13403 rettv->vval.v_string = NULL;
13404#endif
13405}
13406
13407/*
13408 * "undotree()" function
13409 */
13410 static void
13411f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13412{
13413 if (rettv_dict_alloc(rettv) == OK)
13414 {
13415 dict_T *dict = rettv->vval.v_dict;
13416 list_T *list;
13417
13418 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13419 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13420 dict_add_nr_str(dict, "save_last",
13421 (long)curbuf->b_u_save_nr_last, NULL);
13422 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13423 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13424 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13425
13426 list = list_alloc();
13427 if (list != NULL)
13428 {
13429 u_eval_tree(curbuf->b_u_oldhead, list);
13430 dict_add_list(dict, "entries", list);
13431 }
13432 }
13433}
13434
13435/*
13436 * "values(dict)" function
13437 */
13438 static void
13439f_values(typval_T *argvars, typval_T *rettv)
13440{
13441 dict_list(argvars, rettv, 1);
13442}
13443
13444/*
13445 * "virtcol(string)" function
13446 */
13447 static void
13448f_virtcol(typval_T *argvars, typval_T *rettv)
13449{
13450 colnr_T vcol = 0;
13451 pos_T *fp;
13452 int fnum = curbuf->b_fnum;
13453
13454 fp = var2fpos(&argvars[0], FALSE, &fnum);
13455 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13456 && fnum == curbuf->b_fnum)
13457 {
13458 getvvcol(curwin, fp, NULL, NULL, &vcol);
13459 ++vcol;
13460 }
13461
13462 rettv->vval.v_number = vcol;
13463}
13464
13465/*
13466 * "visualmode()" function
13467 */
13468 static void
13469f_visualmode(typval_T *argvars, typval_T *rettv)
13470{
13471 char_u str[2];
13472
13473 rettv->v_type = VAR_STRING;
13474 str[0] = curbuf->b_visual_mode_eval;
13475 str[1] = NUL;
13476 rettv->vval.v_string = vim_strsave(str);
13477
13478 /* A non-zero number or non-empty string argument: reset mode. */
13479 if (non_zero_arg(&argvars[0]))
13480 curbuf->b_visual_mode_eval = NUL;
13481}
13482
13483/*
13484 * "wildmenumode()" function
13485 */
13486 static void
13487f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13488{
13489#ifdef FEAT_WILDMENU
13490 if (wild_menu_showing)
13491 rettv->vval.v_number = 1;
13492#endif
13493}
13494
13495/*
13496 * "winbufnr(nr)" function
13497 */
13498 static void
13499f_winbufnr(typval_T *argvars, typval_T *rettv)
13500{
13501 win_T *wp;
13502
13503 wp = find_win_by_nr(&argvars[0], NULL);
13504 if (wp == NULL)
13505 rettv->vval.v_number = -1;
13506 else
13507 rettv->vval.v_number = wp->w_buffer->b_fnum;
13508}
13509
13510/*
13511 * "wincol()" function
13512 */
13513 static void
13514f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13515{
13516 validate_cursor();
13517 rettv->vval.v_number = curwin->w_wcol + 1;
13518}
13519
13520/*
13521 * "winheight(nr)" function
13522 */
13523 static void
13524f_winheight(typval_T *argvars, typval_T *rettv)
13525{
13526 win_T *wp;
13527
13528 wp = find_win_by_nr(&argvars[0], NULL);
13529 if (wp == NULL)
13530 rettv->vval.v_number = -1;
13531 else
13532 rettv->vval.v_number = wp->w_height;
13533}
13534
13535/*
13536 * "winline()" function
13537 */
13538 static void
13539f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13540{
13541 validate_cursor();
13542 rettv->vval.v_number = curwin->w_wrow + 1;
13543}
13544
13545/*
13546 * "winnr()" function
13547 */
13548 static void
13549f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13550{
13551 int nr = 1;
13552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013553 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013554 rettv->vval.v_number = nr;
13555}
13556
13557/*
13558 * "winrestcmd()" function
13559 */
13560 static void
13561f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13562{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013563 win_T *wp;
13564 int winnr = 1;
13565 garray_T ga;
13566 char_u buf[50];
13567
13568 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013569 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013570 {
13571 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13572 ga_concat(&ga, buf);
13573 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13574 ga_concat(&ga, buf);
13575 ++winnr;
13576 }
13577 ga_append(&ga, NUL);
13578
13579 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013580 rettv->v_type = VAR_STRING;
13581}
13582
13583/*
13584 * "winrestview()" function
13585 */
13586 static void
13587f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13588{
13589 dict_T *dict;
13590
13591 if (argvars[0].v_type != VAR_DICT
13592 || (dict = argvars[0].vval.v_dict) == NULL)
13593 EMSG(_(e_invarg));
13594 else
13595 {
13596 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13597 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13598 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13599 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13600#ifdef FEAT_VIRTUALEDIT
13601 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13602 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13603#endif
13604 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13605 {
13606 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13607 curwin->w_set_curswant = FALSE;
13608 }
13609
13610 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13611 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13612#ifdef FEAT_DIFF
13613 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13614 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13615#endif
13616 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13617 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13618 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13619 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13620
13621 check_cursor();
13622 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013623 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013624 changed_window_setting();
13625
13626 if (curwin->w_topline <= 0)
13627 curwin->w_topline = 1;
13628 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13629 curwin->w_topline = curbuf->b_ml.ml_line_count;
13630#ifdef FEAT_DIFF
13631 check_topfill(curwin, TRUE);
13632#endif
13633 }
13634}
13635
13636/*
13637 * "winsaveview()" function
13638 */
13639 static void
13640f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13641{
13642 dict_T *dict;
13643
13644 if (rettv_dict_alloc(rettv) == FAIL)
13645 return;
13646 dict = rettv->vval.v_dict;
13647
13648 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13649 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13650#ifdef FEAT_VIRTUALEDIT
13651 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13652#endif
13653 update_curswant();
13654 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13655
13656 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13657#ifdef FEAT_DIFF
13658 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13659#endif
13660 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13661 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13662}
13663
13664/*
13665 * "winwidth(nr)" function
13666 */
13667 static void
13668f_winwidth(typval_T *argvars, typval_T *rettv)
13669{
13670 win_T *wp;
13671
13672 wp = find_win_by_nr(&argvars[0], NULL);
13673 if (wp == NULL)
13674 rettv->vval.v_number = -1;
13675 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013676 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013677}
13678
13679/*
13680 * "wordcount()" function
13681 */
13682 static void
13683f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13684{
13685 if (rettv_dict_alloc(rettv) == FAIL)
13686 return;
13687 cursor_pos_info(rettv->vval.v_dict);
13688}
13689
13690/*
13691 * "writefile()" function
13692 */
13693 static void
13694f_writefile(typval_T *argvars, typval_T *rettv)
13695{
13696 int binary = FALSE;
13697 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013698#ifdef HAVE_FSYNC
13699 int do_fsync = p_fs;
13700#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013701 char_u *fname;
13702 FILE *fd;
13703 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013704 listitem_T *li;
13705 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013706
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013707 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013708 if (check_restricted() || check_secure())
13709 return;
13710
13711 if (argvars[0].v_type != VAR_LIST)
13712 {
13713 EMSG2(_(e_listarg), "writefile()");
13714 return;
13715 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013716 list = argvars[0].vval.v_list;
13717 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013718 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013719 for (li = list->lv_first; li != NULL; li = li->li_next)
13720 if (get_tv_string_chk(&li->li_tv) == NULL)
13721 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013722
13723 if (argvars[2].v_type != VAR_UNKNOWN)
13724 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013725 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13726
13727 if (arg2 == NULL)
13728 return;
13729 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013730 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013731 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013732 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013733#ifdef HAVE_FSYNC
13734 if (vim_strchr(arg2, 's') != NULL)
13735 do_fsync = TRUE;
13736 else if (vim_strchr(arg2, 'S') != NULL)
13737 do_fsync = FALSE;
13738#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013739 }
13740
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013741 fname = get_tv_string_chk(&argvars[1]);
13742 if (fname == NULL)
13743 return;
13744
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013745 /* Always open the file in binary mode, library functions have a mind of
13746 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013747 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13748 append ? APPENDBIN : WRITEBIN)) == NULL)
13749 {
13750 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13751 ret = -1;
13752 }
13753 else
13754 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013755 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013756 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013757#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013758 else if (do_fsync)
13759 /* Ignore the error, the user wouldn't know what to do about it.
13760 * May happen for a device. */
13761 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013762#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013763 fclose(fd);
13764 }
13765
13766 rettv->vval.v_number = ret;
13767}
13768
13769/*
13770 * "xor(expr, expr)" function
13771 */
13772 static void
13773f_xor(typval_T *argvars, typval_T *rettv)
13774{
13775 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13776 ^ get_tv_number_chk(&argvars[1], NULL);
13777}
13778
13779
13780#endif /* FEAT_EVAL */