blob: 4b34538b7b1910da70ba2c38d4fdd527cf39da7c [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);
47static void f_assert_equal(typval_T *argvars, typval_T *rettv);
48static void f_assert_exception(typval_T *argvars, typval_T *rettv);
49static void f_assert_fails(typval_T *argvars, typval_T *rettv);
50static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020051static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_assert_match(typval_T *argvars, typval_T *rettv);
53static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
54static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010055static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020056static void f_assert_true(typval_T *argvars, typval_T *rettv);
57#ifdef FEAT_FLOAT
58static void f_asin(typval_T *argvars, typval_T *rettv);
59static void f_atan(typval_T *argvars, typval_T *rettv);
60static void f_atan2(typval_T *argvars, typval_T *rettv);
61#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010062#ifdef FEAT_BEVAL
63static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010064# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010065static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010066# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010067#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020068static void f_browse(typval_T *argvars, typval_T *rettv);
69static void f_browsedir(typval_T *argvars, typval_T *rettv);
70static void f_bufexists(typval_T *argvars, typval_T *rettv);
71static void f_buflisted(typval_T *argvars, typval_T *rettv);
72static void f_bufloaded(typval_T *argvars, typval_T *rettv);
73static void f_bufname(typval_T *argvars, typval_T *rettv);
74static void f_bufnr(typval_T *argvars, typval_T *rettv);
75static void f_bufwinid(typval_T *argvars, typval_T *rettv);
76static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
77static void f_byte2line(typval_T *argvars, typval_T *rettv);
78static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
79static void f_byteidx(typval_T *argvars, typval_T *rettv);
80static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
81static void f_call(typval_T *argvars, typval_T *rettv);
82#ifdef FEAT_FLOAT
83static void f_ceil(typval_T *argvars, typval_T *rettv);
84#endif
85#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010086static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020087static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020088static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
90static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
91static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
92static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
93static void f_ch_info(typval_T *argvars, typval_T *rettv);
94static void f_ch_log(typval_T *argvars, typval_T *rettv);
95static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
96static void f_ch_open(typval_T *argvars, typval_T *rettv);
97static void f_ch_read(typval_T *argvars, typval_T *rettv);
98static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
99static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
100static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
101static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
102static void f_ch_status(typval_T *argvars, typval_T *rettv);
103#endif
104static void f_changenr(typval_T *argvars, typval_T *rettv);
105static void f_char2nr(typval_T *argvars, typval_T *rettv);
106static void f_cindent(typval_T *argvars, typval_T *rettv);
107static void f_clearmatches(typval_T *argvars, typval_T *rettv);
108static void f_col(typval_T *argvars, typval_T *rettv);
109#if defined(FEAT_INS_EXPAND)
110static void f_complete(typval_T *argvars, typval_T *rettv);
111static void f_complete_add(typval_T *argvars, typval_T *rettv);
112static void f_complete_check(typval_T *argvars, typval_T *rettv);
113#endif
114static void f_confirm(typval_T *argvars, typval_T *rettv);
115static void f_copy(typval_T *argvars, typval_T *rettv);
116#ifdef FEAT_FLOAT
117static void f_cos(typval_T *argvars, typval_T *rettv);
118static void f_cosh(typval_T *argvars, typval_T *rettv);
119#endif
120static void f_count(typval_T *argvars, typval_T *rettv);
121static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
122static void f_cursor(typval_T *argsvars, typval_T *rettv);
123static void f_deepcopy(typval_T *argvars, typval_T *rettv);
124static void f_delete(typval_T *argvars, typval_T *rettv);
125static void f_did_filetype(typval_T *argvars, typval_T *rettv);
126static void f_diff_filler(typval_T *argvars, typval_T *rettv);
127static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
128static void f_empty(typval_T *argvars, typval_T *rettv);
129static void f_escape(typval_T *argvars, typval_T *rettv);
130static void f_eval(typval_T *argvars, typval_T *rettv);
131static void f_eventhandler(typval_T *argvars, typval_T *rettv);
132static void f_executable(typval_T *argvars, typval_T *rettv);
133static void f_execute(typval_T *argvars, typval_T *rettv);
134static void f_exepath(typval_T *argvars, typval_T *rettv);
135static void f_exists(typval_T *argvars, typval_T *rettv);
136#ifdef FEAT_FLOAT
137static void f_exp(typval_T *argvars, typval_T *rettv);
138#endif
139static void f_expand(typval_T *argvars, typval_T *rettv);
140static void f_extend(typval_T *argvars, typval_T *rettv);
141static void f_feedkeys(typval_T *argvars, typval_T *rettv);
142static void f_filereadable(typval_T *argvars, typval_T *rettv);
143static void f_filewritable(typval_T *argvars, typval_T *rettv);
144static void f_filter(typval_T *argvars, typval_T *rettv);
145static void f_finddir(typval_T *argvars, typval_T *rettv);
146static void f_findfile(typval_T *argvars, typval_T *rettv);
147#ifdef FEAT_FLOAT
148static void f_float2nr(typval_T *argvars, typval_T *rettv);
149static void f_floor(typval_T *argvars, typval_T *rettv);
150static void f_fmod(typval_T *argvars, typval_T *rettv);
151#endif
152static void f_fnameescape(typval_T *argvars, typval_T *rettv);
153static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
154static void f_foldclosed(typval_T *argvars, typval_T *rettv);
155static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
156static void f_foldlevel(typval_T *argvars, typval_T *rettv);
157static void f_foldtext(typval_T *argvars, typval_T *rettv);
158static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
159static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200160static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200161static void f_function(typval_T *argvars, typval_T *rettv);
162static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
163static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200164static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_getbufline(typval_T *argvars, typval_T *rettv);
166static void f_getbufvar(typval_T *argvars, typval_T *rettv);
167static void f_getchar(typval_T *argvars, typval_T *rettv);
168static void f_getcharmod(typval_T *argvars, typval_T *rettv);
169static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
170static void f_getcmdline(typval_T *argvars, typval_T *rettv);
171#if defined(FEAT_CMDL_COMPL)
172static void f_getcompletion(typval_T *argvars, typval_T *rettv);
173#endif
174static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
175static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
176static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
177static void f_getcwd(typval_T *argvars, typval_T *rettv);
178static void f_getfontname(typval_T *argvars, typval_T *rettv);
179static void f_getfperm(typval_T *argvars, typval_T *rettv);
180static void f_getfsize(typval_T *argvars, typval_T *rettv);
181static void f_getftime(typval_T *argvars, typval_T *rettv);
182static void f_getftype(typval_T *argvars, typval_T *rettv);
183static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200184static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_getmatches(typval_T *argvars, typval_T *rettv);
186static void f_getpid(typval_T *argvars, typval_T *rettv);
187static void f_getcurpos(typval_T *argvars, typval_T *rettv);
188static void f_getpos(typval_T *argvars, typval_T *rettv);
189static void f_getqflist(typval_T *argvars, typval_T *rettv);
190static void f_getreg(typval_T *argvars, typval_T *rettv);
191static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200192static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_gettabvar(typval_T *argvars, typval_T *rettv);
194static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200195static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_getwinposx(typval_T *argvars, typval_T *rettv);
197static void f_getwinposy(typval_T *argvars, typval_T *rettv);
198static void f_getwinvar(typval_T *argvars, typval_T *rettv);
199static void f_glob(typval_T *argvars, typval_T *rettv);
200static void f_globpath(typval_T *argvars, typval_T *rettv);
201static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
202static void f_has(typval_T *argvars, typval_T *rettv);
203static void f_has_key(typval_T *argvars, typval_T *rettv);
204static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
205static void f_hasmapto(typval_T *argvars, typval_T *rettv);
206static void f_histadd(typval_T *argvars, typval_T *rettv);
207static void f_histdel(typval_T *argvars, typval_T *rettv);
208static void f_histget(typval_T *argvars, typval_T *rettv);
209static void f_histnr(typval_T *argvars, typval_T *rettv);
210static void f_hlID(typval_T *argvars, typval_T *rettv);
211static void f_hlexists(typval_T *argvars, typval_T *rettv);
212static void f_hostname(typval_T *argvars, typval_T *rettv);
213static void f_iconv(typval_T *argvars, typval_T *rettv);
214static void f_indent(typval_T *argvars, typval_T *rettv);
215static void f_index(typval_T *argvars, typval_T *rettv);
216static void f_input(typval_T *argvars, typval_T *rettv);
217static void f_inputdialog(typval_T *argvars, typval_T *rettv);
218static void f_inputlist(typval_T *argvars, typval_T *rettv);
219static void f_inputrestore(typval_T *argvars, typval_T *rettv);
220static void f_inputsave(typval_T *argvars, typval_T *rettv);
221static void f_inputsecret(typval_T *argvars, typval_T *rettv);
222static void f_insert(typval_T *argvars, typval_T *rettv);
223static void f_invert(typval_T *argvars, typval_T *rettv);
224static void f_isdirectory(typval_T *argvars, typval_T *rettv);
225static void f_islocked(typval_T *argvars, typval_T *rettv);
226#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
227static void f_isnan(typval_T *argvars, typval_T *rettv);
228#endif
229static void f_items(typval_T *argvars, typval_T *rettv);
230#ifdef FEAT_JOB_CHANNEL
231static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
232static void f_job_info(typval_T *argvars, typval_T *rettv);
233static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
234static void f_job_start(typval_T *argvars, typval_T *rettv);
235static void f_job_stop(typval_T *argvars, typval_T *rettv);
236static void f_job_status(typval_T *argvars, typval_T *rettv);
237#endif
238static void f_join(typval_T *argvars, typval_T *rettv);
239static void f_js_decode(typval_T *argvars, typval_T *rettv);
240static void f_js_encode(typval_T *argvars, typval_T *rettv);
241static void f_json_decode(typval_T *argvars, typval_T *rettv);
242static void f_json_encode(typval_T *argvars, typval_T *rettv);
243static void f_keys(typval_T *argvars, typval_T *rettv);
244static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
245static void f_len(typval_T *argvars, typval_T *rettv);
246static void f_libcall(typval_T *argvars, typval_T *rettv);
247static void f_libcallnr(typval_T *argvars, typval_T *rettv);
248static void f_line(typval_T *argvars, typval_T *rettv);
249static void f_line2byte(typval_T *argvars, typval_T *rettv);
250static void f_lispindent(typval_T *argvars, typval_T *rettv);
251static void f_localtime(typval_T *argvars, typval_T *rettv);
252#ifdef FEAT_FLOAT
253static void f_log(typval_T *argvars, typval_T *rettv);
254static void f_log10(typval_T *argvars, typval_T *rettv);
255#endif
256#ifdef FEAT_LUA
257static void f_luaeval(typval_T *argvars, typval_T *rettv);
258#endif
259static void f_map(typval_T *argvars, typval_T *rettv);
260static void f_maparg(typval_T *argvars, typval_T *rettv);
261static void f_mapcheck(typval_T *argvars, typval_T *rettv);
262static void f_match(typval_T *argvars, typval_T *rettv);
263static void f_matchadd(typval_T *argvars, typval_T *rettv);
264static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
265static void f_matcharg(typval_T *argvars, typval_T *rettv);
266static void f_matchdelete(typval_T *argvars, typval_T *rettv);
267static void f_matchend(typval_T *argvars, typval_T *rettv);
268static void f_matchlist(typval_T *argvars, typval_T *rettv);
269static void f_matchstr(typval_T *argvars, typval_T *rettv);
270static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
271static void f_max(typval_T *argvars, typval_T *rettv);
272static void f_min(typval_T *argvars, typval_T *rettv);
273#ifdef vim_mkdir
274static void f_mkdir(typval_T *argvars, typval_T *rettv);
275#endif
276static void f_mode(typval_T *argvars, typval_T *rettv);
277#ifdef FEAT_MZSCHEME
278static void f_mzeval(typval_T *argvars, typval_T *rettv);
279#endif
280static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
281static void f_nr2char(typval_T *argvars, typval_T *rettv);
282static void f_or(typval_T *argvars, typval_T *rettv);
283static void f_pathshorten(typval_T *argvars, typval_T *rettv);
284#ifdef FEAT_PERL
285static void f_perleval(typval_T *argvars, typval_T *rettv);
286#endif
287#ifdef FEAT_FLOAT
288static void f_pow(typval_T *argvars, typval_T *rettv);
289#endif
290static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
291static void f_printf(typval_T *argvars, typval_T *rettv);
292static void f_pumvisible(typval_T *argvars, typval_T *rettv);
293#ifdef FEAT_PYTHON3
294static void f_py3eval(typval_T *argvars, typval_T *rettv);
295#endif
296#ifdef FEAT_PYTHON
297static void f_pyeval(typval_T *argvars, typval_T *rettv);
298#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100299#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
300static void f_pyxeval(typval_T *argvars, typval_T *rettv);
301#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_range(typval_T *argvars, typval_T *rettv);
303static void f_readfile(typval_T *argvars, typval_T *rettv);
304static void f_reltime(typval_T *argvars, typval_T *rettv);
305#ifdef FEAT_FLOAT
306static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
307#endif
308static void f_reltimestr(typval_T *argvars, typval_T *rettv);
309static void f_remote_expr(typval_T *argvars, typval_T *rettv);
310static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
311static void f_remote_peek(typval_T *argvars, typval_T *rettv);
312static void f_remote_read(typval_T *argvars, typval_T *rettv);
313static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100314static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315static void f_remove(typval_T *argvars, typval_T *rettv);
316static void f_rename(typval_T *argvars, typval_T *rettv);
317static void f_repeat(typval_T *argvars, typval_T *rettv);
318static void f_resolve(typval_T *argvars, typval_T *rettv);
319static void f_reverse(typval_T *argvars, typval_T *rettv);
320#ifdef FEAT_FLOAT
321static void f_round(typval_T *argvars, typval_T *rettv);
322#endif
323static void f_screenattr(typval_T *argvars, typval_T *rettv);
324static void f_screenchar(typval_T *argvars, typval_T *rettv);
325static void f_screencol(typval_T *argvars, typval_T *rettv);
326static void f_screenrow(typval_T *argvars, typval_T *rettv);
327static void f_search(typval_T *argvars, typval_T *rettv);
328static void f_searchdecl(typval_T *argvars, typval_T *rettv);
329static void f_searchpair(typval_T *argvars, typval_T *rettv);
330static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
331static void f_searchpos(typval_T *argvars, typval_T *rettv);
332static void f_server2client(typval_T *argvars, typval_T *rettv);
333static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200334static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200335static void f_setbufvar(typval_T *argvars, typval_T *rettv);
336static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
337static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
338static void f_setfperm(typval_T *argvars, typval_T *rettv);
339static void f_setline(typval_T *argvars, typval_T *rettv);
340static void f_setloclist(typval_T *argvars, typval_T *rettv);
341static void f_setmatches(typval_T *argvars, typval_T *rettv);
342static void f_setpos(typval_T *argvars, typval_T *rettv);
343static void f_setqflist(typval_T *argvars, typval_T *rettv);
344static void f_setreg(typval_T *argvars, typval_T *rettv);
345static void f_settabvar(typval_T *argvars, typval_T *rettv);
346static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
347static void f_setwinvar(typval_T *argvars, typval_T *rettv);
348#ifdef FEAT_CRYPT
349static void f_sha256(typval_T *argvars, typval_T *rettv);
350#endif /* FEAT_CRYPT */
351static void f_shellescape(typval_T *argvars, typval_T *rettv);
352static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
353static void f_simplify(typval_T *argvars, typval_T *rettv);
354#ifdef FEAT_FLOAT
355static void f_sin(typval_T *argvars, typval_T *rettv);
356static void f_sinh(typval_T *argvars, typval_T *rettv);
357#endif
358static void f_sort(typval_T *argvars, typval_T *rettv);
359static void f_soundfold(typval_T *argvars, typval_T *rettv);
360static void f_spellbadword(typval_T *argvars, typval_T *rettv);
361static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
362static void f_split(typval_T *argvars, typval_T *rettv);
363#ifdef FEAT_FLOAT
364static void f_sqrt(typval_T *argvars, typval_T *rettv);
365static void f_str2float(typval_T *argvars, typval_T *rettv);
366#endif
367static void f_str2nr(typval_T *argvars, typval_T *rettv);
368static void f_strchars(typval_T *argvars, typval_T *rettv);
369#ifdef HAVE_STRFTIME
370static void f_strftime(typval_T *argvars, typval_T *rettv);
371#endif
372static void f_strgetchar(typval_T *argvars, typval_T *rettv);
373static void f_stridx(typval_T *argvars, typval_T *rettv);
374static void f_string(typval_T *argvars, typval_T *rettv);
375static void f_strlen(typval_T *argvars, typval_T *rettv);
376static void f_strcharpart(typval_T *argvars, typval_T *rettv);
377static void f_strpart(typval_T *argvars, typval_T *rettv);
378static void f_strridx(typval_T *argvars, typval_T *rettv);
379static void f_strtrans(typval_T *argvars, typval_T *rettv);
380static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
381static void f_strwidth(typval_T *argvars, typval_T *rettv);
382static void f_submatch(typval_T *argvars, typval_T *rettv);
383static void f_substitute(typval_T *argvars, typval_T *rettv);
384static void f_synID(typval_T *argvars, typval_T *rettv);
385static void f_synIDattr(typval_T *argvars, typval_T *rettv);
386static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
387static void f_synstack(typval_T *argvars, typval_T *rettv);
388static void f_synconcealed(typval_T *argvars, typval_T *rettv);
389static void f_system(typval_T *argvars, typval_T *rettv);
390static void f_systemlist(typval_T *argvars, typval_T *rettv);
391static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
392static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
393static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
394static void f_taglist(typval_T *argvars, typval_T *rettv);
395static void f_tagfiles(typval_T *argvars, typval_T *rettv);
396static void f_tempname(typval_T *argvars, typval_T *rettv);
397static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
398static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200399static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100400static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100402static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200403#ifdef FEAT_JOB_CHANNEL
404static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
405#endif
406static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
407#ifdef FEAT_JOB_CHANNEL
408static void f_test_null_job(typval_T *argvars, typval_T *rettv);
409#endif
410static void f_test_null_list(typval_T *argvars, typval_T *rettv);
411static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
412static void f_test_null_string(typval_T *argvars, typval_T *rettv);
413static void f_test_settime(typval_T *argvars, typval_T *rettv);
414#ifdef FEAT_FLOAT
415static void f_tan(typval_T *argvars, typval_T *rettv);
416static void f_tanh(typval_T *argvars, typval_T *rettv);
417#endif
418#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200419static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200420static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421static void f_timer_start(typval_T *argvars, typval_T *rettv);
422static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200423static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200424#endif
425static void f_tolower(typval_T *argvars, typval_T *rettv);
426static void f_toupper(typval_T *argvars, typval_T *rettv);
427static void f_tr(typval_T *argvars, typval_T *rettv);
428#ifdef FEAT_FLOAT
429static void f_trunc(typval_T *argvars, typval_T *rettv);
430#endif
431static void f_type(typval_T *argvars, typval_T *rettv);
432static void f_undofile(typval_T *argvars, typval_T *rettv);
433static void f_undotree(typval_T *argvars, typval_T *rettv);
434static void f_uniq(typval_T *argvars, typval_T *rettv);
435static void f_values(typval_T *argvars, typval_T *rettv);
436static void f_virtcol(typval_T *argvars, typval_T *rettv);
437static void f_visualmode(typval_T *argvars, typval_T *rettv);
438static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
439static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
440static void f_win_getid(typval_T *argvars, typval_T *rettv);
441static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
442static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
443static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100444static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200445static void f_winbufnr(typval_T *argvars, typval_T *rettv);
446static void f_wincol(typval_T *argvars, typval_T *rettv);
447static void f_winheight(typval_T *argvars, typval_T *rettv);
448static void f_winline(typval_T *argvars, typval_T *rettv);
449static void f_winnr(typval_T *argvars, typval_T *rettv);
450static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
451static void f_winrestview(typval_T *argvars, typval_T *rettv);
452static void f_winsaveview(typval_T *argvars, typval_T *rettv);
453static void f_winwidth(typval_T *argvars, typval_T *rettv);
454static void f_writefile(typval_T *argvars, typval_T *rettv);
455static void f_wordcount(typval_T *argvars, typval_T *rettv);
456static void f_xor(typval_T *argvars, typval_T *rettv);
457
458/*
459 * Array with names and number of arguments of all internal functions
460 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
461 */
462static struct fst
463{
464 char *f_name; /* function name */
465 char f_min_argc; /* minimal number of arguments */
466 char f_max_argc; /* maximal number of arguments */
467 void (*f_func)(typval_T *args, typval_T *rvar);
468 /* implementation of function */
469} functions[] =
470{
471#ifdef FEAT_FLOAT
472 {"abs", 1, 1, f_abs},
473 {"acos", 1, 1, f_acos}, /* WJMc */
474#endif
475 {"add", 2, 2, f_add},
476 {"and", 2, 2, f_and},
477 {"append", 2, 2, f_append},
478 {"argc", 0, 0, f_argc},
479 {"argidx", 0, 0, f_argidx},
480 {"arglistid", 0, 2, f_arglistid},
481 {"argv", 0, 1, f_argv},
482#ifdef FEAT_FLOAT
483 {"asin", 1, 1, f_asin}, /* WJMc */
484#endif
485 {"assert_equal", 2, 3, f_assert_equal},
486 {"assert_exception", 1, 2, f_assert_exception},
487 {"assert_fails", 1, 2, f_assert_fails},
488 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100489 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200490 {"assert_match", 2, 3, f_assert_match},
491 {"assert_notequal", 2, 3, f_assert_notequal},
492 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100493 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200494 {"assert_true", 1, 2, f_assert_true},
495#ifdef FEAT_FLOAT
496 {"atan", 1, 1, f_atan},
497 {"atan2", 2, 2, f_atan2},
498#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100499#ifdef FEAT_BEVAL
500 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100501# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100502 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100503# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100504#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200505 {"browse", 4, 4, f_browse},
506 {"browsedir", 2, 2, f_browsedir},
507 {"bufexists", 1, 1, f_bufexists},
508 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
509 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
510 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
511 {"buflisted", 1, 1, f_buflisted},
512 {"bufloaded", 1, 1, f_bufloaded},
513 {"bufname", 1, 1, f_bufname},
514 {"bufnr", 1, 2, f_bufnr},
515 {"bufwinid", 1, 1, f_bufwinid},
516 {"bufwinnr", 1, 1, f_bufwinnr},
517 {"byte2line", 1, 1, f_byte2line},
518 {"byteidx", 2, 2, f_byteidx},
519 {"byteidxcomp", 2, 2, f_byteidxcomp},
520 {"call", 2, 3, f_call},
521#ifdef FEAT_FLOAT
522 {"ceil", 1, 1, f_ceil},
523#endif
524#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100525 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200527 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
529 {"ch_evalraw", 2, 3, f_ch_evalraw},
530 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
531 {"ch_getjob", 1, 1, f_ch_getjob},
532 {"ch_info", 1, 1, f_ch_info},
533 {"ch_log", 1, 2, f_ch_log},
534 {"ch_logfile", 1, 2, f_ch_logfile},
535 {"ch_open", 1, 2, f_ch_open},
536 {"ch_read", 1, 2, f_ch_read},
537 {"ch_readraw", 1, 2, f_ch_readraw},
538 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
539 {"ch_sendraw", 2, 3, f_ch_sendraw},
540 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200541 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200542#endif
543 {"changenr", 0, 0, f_changenr},
544 {"char2nr", 1, 2, f_char2nr},
545 {"cindent", 1, 1, f_cindent},
546 {"clearmatches", 0, 0, f_clearmatches},
547 {"col", 1, 1, f_col},
548#if defined(FEAT_INS_EXPAND)
549 {"complete", 2, 2, f_complete},
550 {"complete_add", 1, 1, f_complete_add},
551 {"complete_check", 0, 0, f_complete_check},
552#endif
553 {"confirm", 1, 4, f_confirm},
554 {"copy", 1, 1, f_copy},
555#ifdef FEAT_FLOAT
556 {"cos", 1, 1, f_cos},
557 {"cosh", 1, 1, f_cosh},
558#endif
559 {"count", 2, 4, f_count},
560 {"cscope_connection",0,3, f_cscope_connection},
561 {"cursor", 1, 3, f_cursor},
562 {"deepcopy", 1, 2, f_deepcopy},
563 {"delete", 1, 2, f_delete},
564 {"did_filetype", 0, 0, f_did_filetype},
565 {"diff_filler", 1, 1, f_diff_filler},
566 {"diff_hlID", 2, 2, f_diff_hlID},
567 {"empty", 1, 1, f_empty},
568 {"escape", 2, 2, f_escape},
569 {"eval", 1, 1, f_eval},
570 {"eventhandler", 0, 0, f_eventhandler},
571 {"executable", 1, 1, f_executable},
572 {"execute", 1, 2, f_execute},
573 {"exepath", 1, 1, f_exepath},
574 {"exists", 1, 1, f_exists},
575#ifdef FEAT_FLOAT
576 {"exp", 1, 1, f_exp},
577#endif
578 {"expand", 1, 3, f_expand},
579 {"extend", 2, 3, f_extend},
580 {"feedkeys", 1, 2, f_feedkeys},
581 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
582 {"filereadable", 1, 1, f_filereadable},
583 {"filewritable", 1, 1, f_filewritable},
584 {"filter", 2, 2, f_filter},
585 {"finddir", 1, 3, f_finddir},
586 {"findfile", 1, 3, f_findfile},
587#ifdef FEAT_FLOAT
588 {"float2nr", 1, 1, f_float2nr},
589 {"floor", 1, 1, f_floor},
590 {"fmod", 2, 2, f_fmod},
591#endif
592 {"fnameescape", 1, 1, f_fnameescape},
593 {"fnamemodify", 2, 2, f_fnamemodify},
594 {"foldclosed", 1, 1, f_foldclosed},
595 {"foldclosedend", 1, 1, f_foldclosedend},
596 {"foldlevel", 1, 1, f_foldlevel},
597 {"foldtext", 0, 0, f_foldtext},
598 {"foldtextresult", 1, 1, f_foldtextresult},
599 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200600 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601 {"function", 1, 3, f_function},
602 {"garbagecollect", 0, 1, f_garbagecollect},
603 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200604 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200605 {"getbufline", 2, 3, f_getbufline},
606 {"getbufvar", 2, 3, f_getbufvar},
607 {"getchar", 0, 1, f_getchar},
608 {"getcharmod", 0, 0, f_getcharmod},
609 {"getcharsearch", 0, 0, f_getcharsearch},
610 {"getcmdline", 0, 0, f_getcmdline},
611 {"getcmdpos", 0, 0, f_getcmdpos},
612 {"getcmdtype", 0, 0, f_getcmdtype},
613 {"getcmdwintype", 0, 0, f_getcmdwintype},
614#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200615 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200616#endif
617 {"getcurpos", 0, 0, f_getcurpos},
618 {"getcwd", 0, 2, f_getcwd},
619 {"getfontname", 0, 1, f_getfontname},
620 {"getfperm", 1, 1, f_getfperm},
621 {"getfsize", 1, 1, f_getfsize},
622 {"getftime", 1, 1, f_getftime},
623 {"getftype", 1, 1, f_getftype},
624 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200625 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200626 {"getmatches", 0, 0, f_getmatches},
627 {"getpid", 0, 0, f_getpid},
628 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200629 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200630 {"getreg", 0, 3, f_getreg},
631 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200632 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633 {"gettabvar", 2, 3, f_gettabvar},
634 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200635 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636 {"getwinposx", 0, 0, f_getwinposx},
637 {"getwinposy", 0, 0, f_getwinposy},
638 {"getwinvar", 2, 3, f_getwinvar},
639 {"glob", 1, 4, f_glob},
640 {"glob2regpat", 1, 1, f_glob2regpat},
641 {"globpath", 2, 5, f_globpath},
642 {"has", 1, 1, f_has},
643 {"has_key", 2, 2, f_has_key},
644 {"haslocaldir", 0, 2, f_haslocaldir},
645 {"hasmapto", 1, 3, f_hasmapto},
646 {"highlightID", 1, 1, f_hlID}, /* obsolete */
647 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
648 {"histadd", 2, 2, f_histadd},
649 {"histdel", 1, 2, f_histdel},
650 {"histget", 1, 2, f_histget},
651 {"histnr", 1, 1, f_histnr},
652 {"hlID", 1, 1, f_hlID},
653 {"hlexists", 1, 1, f_hlexists},
654 {"hostname", 0, 0, f_hostname},
655 {"iconv", 3, 3, f_iconv},
656 {"indent", 1, 1, f_indent},
657 {"index", 2, 4, f_index},
658 {"input", 1, 3, f_input},
659 {"inputdialog", 1, 3, f_inputdialog},
660 {"inputlist", 1, 1, f_inputlist},
661 {"inputrestore", 0, 0, f_inputrestore},
662 {"inputsave", 0, 0, f_inputsave},
663 {"inputsecret", 1, 2, f_inputsecret},
664 {"insert", 2, 3, f_insert},
665 {"invert", 1, 1, f_invert},
666 {"isdirectory", 1, 1, f_isdirectory},
667 {"islocked", 1, 1, f_islocked},
668#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
669 {"isnan", 1, 1, f_isnan},
670#endif
671 {"items", 1, 1, f_items},
672#ifdef FEAT_JOB_CHANNEL
673 {"job_getchannel", 1, 1, f_job_getchannel},
674 {"job_info", 1, 1, f_job_info},
675 {"job_setoptions", 2, 2, f_job_setoptions},
676 {"job_start", 1, 2, f_job_start},
677 {"job_status", 1, 1, f_job_status},
678 {"job_stop", 1, 2, f_job_stop},
679#endif
680 {"join", 1, 2, f_join},
681 {"js_decode", 1, 1, f_js_decode},
682 {"js_encode", 1, 1, f_js_encode},
683 {"json_decode", 1, 1, f_json_decode},
684 {"json_encode", 1, 1, f_json_encode},
685 {"keys", 1, 1, f_keys},
686 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
687 {"len", 1, 1, f_len},
688 {"libcall", 3, 3, f_libcall},
689 {"libcallnr", 3, 3, f_libcallnr},
690 {"line", 1, 1, f_line},
691 {"line2byte", 1, 1, f_line2byte},
692 {"lispindent", 1, 1, f_lispindent},
693 {"localtime", 0, 0, f_localtime},
694#ifdef FEAT_FLOAT
695 {"log", 1, 1, f_log},
696 {"log10", 1, 1, f_log10},
697#endif
698#ifdef FEAT_LUA
699 {"luaeval", 1, 2, f_luaeval},
700#endif
701 {"map", 2, 2, f_map},
702 {"maparg", 1, 4, f_maparg},
703 {"mapcheck", 1, 3, f_mapcheck},
704 {"match", 2, 4, f_match},
705 {"matchadd", 2, 5, f_matchadd},
706 {"matchaddpos", 2, 5, f_matchaddpos},
707 {"matcharg", 1, 1, f_matcharg},
708 {"matchdelete", 1, 1, f_matchdelete},
709 {"matchend", 2, 4, f_matchend},
710 {"matchlist", 2, 4, f_matchlist},
711 {"matchstr", 2, 4, f_matchstr},
712 {"matchstrpos", 2, 4, f_matchstrpos},
713 {"max", 1, 1, f_max},
714 {"min", 1, 1, f_min},
715#ifdef vim_mkdir
716 {"mkdir", 1, 3, f_mkdir},
717#endif
718 {"mode", 0, 1, f_mode},
719#ifdef FEAT_MZSCHEME
720 {"mzeval", 1, 1, f_mzeval},
721#endif
722 {"nextnonblank", 1, 1, f_nextnonblank},
723 {"nr2char", 1, 2, f_nr2char},
724 {"or", 2, 2, f_or},
725 {"pathshorten", 1, 1, f_pathshorten},
726#ifdef FEAT_PERL
727 {"perleval", 1, 1, f_perleval},
728#endif
729#ifdef FEAT_FLOAT
730 {"pow", 2, 2, f_pow},
731#endif
732 {"prevnonblank", 1, 1, f_prevnonblank},
733 {"printf", 2, 19, f_printf},
734 {"pumvisible", 0, 0, f_pumvisible},
735#ifdef FEAT_PYTHON3
736 {"py3eval", 1, 1, f_py3eval},
737#endif
738#ifdef FEAT_PYTHON
739 {"pyeval", 1, 1, f_pyeval},
740#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100741#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
742 {"pyxeval", 1, 1, f_pyxeval},
743#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744 {"range", 1, 3, f_range},
745 {"readfile", 1, 3, f_readfile},
746 {"reltime", 0, 2, f_reltime},
747#ifdef FEAT_FLOAT
748 {"reltimefloat", 1, 1, f_reltimefloat},
749#endif
750 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100751 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200752 {"remote_foreground", 1, 1, f_remote_foreground},
753 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100754 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200755 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100756 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757 {"remove", 2, 3, f_remove},
758 {"rename", 2, 2, f_rename},
759 {"repeat", 2, 2, f_repeat},
760 {"resolve", 1, 1, f_resolve},
761 {"reverse", 1, 1, f_reverse},
762#ifdef FEAT_FLOAT
763 {"round", 1, 1, f_round},
764#endif
765 {"screenattr", 2, 2, f_screenattr},
766 {"screenchar", 2, 2, f_screenchar},
767 {"screencol", 0, 0, f_screencol},
768 {"screenrow", 0, 0, f_screenrow},
769 {"search", 1, 4, f_search},
770 {"searchdecl", 1, 3, f_searchdecl},
771 {"searchpair", 3, 7, f_searchpair},
772 {"searchpairpos", 3, 7, f_searchpairpos},
773 {"searchpos", 1, 4, f_searchpos},
774 {"server2client", 2, 2, f_server2client},
775 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200776 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777 {"setbufvar", 3, 3, f_setbufvar},
778 {"setcharsearch", 1, 1, f_setcharsearch},
779 {"setcmdpos", 1, 1, f_setcmdpos},
780 {"setfperm", 2, 2, f_setfperm},
781 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200782 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783 {"setmatches", 1, 1, f_setmatches},
784 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200785 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200786 {"setreg", 2, 3, f_setreg},
787 {"settabvar", 3, 3, f_settabvar},
788 {"settabwinvar", 4, 4, f_settabwinvar},
789 {"setwinvar", 3, 3, f_setwinvar},
790#ifdef FEAT_CRYPT
791 {"sha256", 1, 1, f_sha256},
792#endif
793 {"shellescape", 1, 2, f_shellescape},
794 {"shiftwidth", 0, 0, f_shiftwidth},
795 {"simplify", 1, 1, f_simplify},
796#ifdef FEAT_FLOAT
797 {"sin", 1, 1, f_sin},
798 {"sinh", 1, 1, f_sinh},
799#endif
800 {"sort", 1, 3, f_sort},
801 {"soundfold", 1, 1, f_soundfold},
802 {"spellbadword", 0, 1, f_spellbadword},
803 {"spellsuggest", 1, 3, f_spellsuggest},
804 {"split", 1, 3, f_split},
805#ifdef FEAT_FLOAT
806 {"sqrt", 1, 1, f_sqrt},
807 {"str2float", 1, 1, f_str2float},
808#endif
809 {"str2nr", 1, 2, f_str2nr},
810 {"strcharpart", 2, 3, f_strcharpart},
811 {"strchars", 1, 2, f_strchars},
812 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
813#ifdef HAVE_STRFTIME
814 {"strftime", 1, 2, f_strftime},
815#endif
816 {"strgetchar", 2, 2, f_strgetchar},
817 {"stridx", 2, 3, f_stridx},
818 {"string", 1, 1, f_string},
819 {"strlen", 1, 1, f_strlen},
820 {"strpart", 2, 3, f_strpart},
821 {"strridx", 2, 3, f_strridx},
822 {"strtrans", 1, 1, f_strtrans},
823 {"strwidth", 1, 1, f_strwidth},
824 {"submatch", 1, 2, f_submatch},
825 {"substitute", 4, 4, f_substitute},
826 {"synID", 3, 3, f_synID},
827 {"synIDattr", 2, 3, f_synIDattr},
828 {"synIDtrans", 1, 1, f_synIDtrans},
829 {"synconcealed", 2, 2, f_synconcealed},
830 {"synstack", 2, 2, f_synstack},
831 {"system", 1, 2, f_system},
832 {"systemlist", 1, 2, f_systemlist},
833 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
834 {"tabpagenr", 0, 1, f_tabpagenr},
835 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
836 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100837 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200838#ifdef FEAT_FLOAT
839 {"tan", 1, 1, f_tan},
840 {"tanh", 1, 1, f_tanh},
841#endif
842 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200843#ifdef FEAT_TERMINAL
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200844 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200845 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200846 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200847 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200848 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200849 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200850 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200851 {"term_getstatus", 1, 1, f_term_getstatus},
852 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200853 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200854 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200855 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200856 {"term_sendkeys", 2, 2, f_term_sendkeys},
857 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200858 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200859#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200860 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
861 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200862 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200863 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100864 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200865#ifdef FEAT_JOB_CHANNEL
866 {"test_null_channel", 0, 0, f_test_null_channel},
867#endif
868 {"test_null_dict", 0, 0, f_test_null_dict},
869#ifdef FEAT_JOB_CHANNEL
870 {"test_null_job", 0, 0, f_test_null_job},
871#endif
872 {"test_null_list", 0, 0, f_test_null_list},
873 {"test_null_partial", 0, 0, f_test_null_partial},
874 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100875 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876 {"test_settime", 1, 1, f_test_settime},
877#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200878 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200879 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200880 {"timer_start", 2, 3, f_timer_start},
881 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200882 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883#endif
884 {"tolower", 1, 1, f_tolower},
885 {"toupper", 1, 1, f_toupper},
886 {"tr", 3, 3, f_tr},
887#ifdef FEAT_FLOAT
888 {"trunc", 1, 1, f_trunc},
889#endif
890 {"type", 1, 1, f_type},
891 {"undofile", 1, 1, f_undofile},
892 {"undotree", 0, 0, f_undotree},
893 {"uniq", 1, 3, f_uniq},
894 {"values", 1, 1, f_values},
895 {"virtcol", 1, 1, f_virtcol},
896 {"visualmode", 0, 1, f_visualmode},
897 {"wildmenumode", 0, 0, f_wildmenumode},
898 {"win_findbuf", 1, 1, f_win_findbuf},
899 {"win_getid", 0, 2, f_win_getid},
900 {"win_gotoid", 1, 1, f_win_gotoid},
901 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
902 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100903 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200904 {"winbufnr", 1, 1, f_winbufnr},
905 {"wincol", 0, 0, f_wincol},
906 {"winheight", 1, 1, f_winheight},
907 {"winline", 0, 0, f_winline},
908 {"winnr", 0, 1, f_winnr},
909 {"winrestcmd", 0, 0, f_winrestcmd},
910 {"winrestview", 1, 1, f_winrestview},
911 {"winsaveview", 0, 0, f_winsaveview},
912 {"winwidth", 1, 1, f_winwidth},
913 {"wordcount", 0, 0, f_wordcount},
914 {"writefile", 2, 3, f_writefile},
915 {"xor", 2, 2, f_xor},
916};
917
918#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
919
920/*
921 * Function given to ExpandGeneric() to obtain the list of internal
922 * or user defined function names.
923 */
924 char_u *
925get_function_name(expand_T *xp, int idx)
926{
927 static int intidx = -1;
928 char_u *name;
929
930 if (idx == 0)
931 intidx = -1;
932 if (intidx < 0)
933 {
934 name = get_user_func_name(xp, idx);
935 if (name != NULL)
936 return name;
937 }
938 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
939 {
940 STRCPY(IObuff, functions[intidx].f_name);
941 STRCAT(IObuff, "(");
942 if (functions[intidx].f_max_argc == 0)
943 STRCAT(IObuff, ")");
944 return IObuff;
945 }
946
947 return NULL;
948}
949
950/*
951 * Function given to ExpandGeneric() to obtain the list of internal or
952 * user defined variable or function names.
953 */
954 char_u *
955get_expr_name(expand_T *xp, int idx)
956{
957 static int intidx = -1;
958 char_u *name;
959
960 if (idx == 0)
961 intidx = -1;
962 if (intidx < 0)
963 {
964 name = get_function_name(xp, idx);
965 if (name != NULL)
966 return name;
967 }
968 return get_user_var_name(xp, ++intidx);
969}
970
971#endif /* FEAT_CMDL_COMPL */
972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973/*
974 * Find internal function in table above.
975 * Return index, or -1 if not found
976 */
977 int
978find_internal_func(
979 char_u *name) /* name of the function */
980{
981 int first = 0;
982 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
983 int cmp;
984 int x;
985
986 /*
987 * Find the function name in the table. Binary search.
988 */
989 while (first <= last)
990 {
991 x = first + ((unsigned)(last - first) >> 1);
992 cmp = STRCMP(name, functions[x].f_name);
993 if (cmp < 0)
994 last = x - 1;
995 else if (cmp > 0)
996 first = x + 1;
997 else
998 return x;
999 }
1000 return -1;
1001}
1002
1003 int
1004call_internal_func(
1005 char_u *name,
1006 int argcount,
1007 typval_T *argvars,
1008 typval_T *rettv)
1009{
1010 int i;
1011
1012 i = find_internal_func(name);
1013 if (i < 0)
1014 return ERROR_UNKNOWN;
1015 if (argcount < functions[i].f_min_argc)
1016 return ERROR_TOOFEW;
1017 if (argcount > functions[i].f_max_argc)
1018 return ERROR_TOOMANY;
1019 argvars[argcount].v_type = VAR_UNKNOWN;
1020 functions[i].f_func(argvars, rettv);
1021 return ERROR_NONE;
1022}
1023
1024/*
1025 * Return TRUE for a non-zero Number and a non-empty String.
1026 */
1027 static int
1028non_zero_arg(typval_T *argvars)
1029{
1030 return ((argvars[0].v_type == VAR_NUMBER
1031 && argvars[0].vval.v_number != 0)
1032 || (argvars[0].v_type == VAR_SPECIAL
1033 && argvars[0].vval.v_number == VVAL_TRUE)
1034 || (argvars[0].v_type == VAR_STRING
1035 && argvars[0].vval.v_string != NULL
1036 && *argvars[0].vval.v_string != NUL));
1037}
1038
1039/*
1040 * Get the lnum from the first argument.
1041 * Also accepts ".", "$", etc., but that only works for the current buffer.
1042 * Returns -1 on error.
1043 */
1044 static linenr_T
1045get_tv_lnum(typval_T *argvars)
1046{
1047 typval_T rettv;
1048 linenr_T lnum;
1049
1050 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1051 if (lnum == 0) /* no valid number, try using line() */
1052 {
1053 rettv.v_type = VAR_NUMBER;
1054 f_line(argvars, &rettv);
1055 lnum = (linenr_T)rettv.vval.v_number;
1056 clear_tv(&rettv);
1057 }
1058 return lnum;
1059}
1060
1061#ifdef FEAT_FLOAT
1062static int get_float_arg(typval_T *argvars, float_T *f);
1063
1064/*
1065 * Get the float value of "argvars[0]" into "f".
1066 * Returns FAIL when the argument is not a Number or Float.
1067 */
1068 static int
1069get_float_arg(typval_T *argvars, float_T *f)
1070{
1071 if (argvars[0].v_type == VAR_FLOAT)
1072 {
1073 *f = argvars[0].vval.v_float;
1074 return OK;
1075 }
1076 if (argvars[0].v_type == VAR_NUMBER)
1077 {
1078 *f = (float_T)argvars[0].vval.v_number;
1079 return OK;
1080 }
1081 EMSG(_("E808: Number or Float required"));
1082 return FAIL;
1083}
1084
1085/*
1086 * "abs(expr)" function
1087 */
1088 static void
1089f_abs(typval_T *argvars, typval_T *rettv)
1090{
1091 if (argvars[0].v_type == VAR_FLOAT)
1092 {
1093 rettv->v_type = VAR_FLOAT;
1094 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1095 }
1096 else
1097 {
1098 varnumber_T n;
1099 int error = FALSE;
1100
1101 n = get_tv_number_chk(&argvars[0], &error);
1102 if (error)
1103 rettv->vval.v_number = -1;
1104 else if (n > 0)
1105 rettv->vval.v_number = n;
1106 else
1107 rettv->vval.v_number = -n;
1108 }
1109}
1110
1111/*
1112 * "acos()" function
1113 */
1114 static void
1115f_acos(typval_T *argvars, typval_T *rettv)
1116{
1117 float_T f = 0.0;
1118
1119 rettv->v_type = VAR_FLOAT;
1120 if (get_float_arg(argvars, &f) == OK)
1121 rettv->vval.v_float = acos(f);
1122 else
1123 rettv->vval.v_float = 0.0;
1124}
1125#endif
1126
1127/*
1128 * "add(list, item)" function
1129 */
1130 static void
1131f_add(typval_T *argvars, typval_T *rettv)
1132{
1133 list_T *l;
1134
1135 rettv->vval.v_number = 1; /* Default: Failed */
1136 if (argvars[0].v_type == VAR_LIST)
1137 {
1138 if ((l = argvars[0].vval.v_list) != NULL
1139 && !tv_check_lock(l->lv_lock,
1140 (char_u *)N_("add() argument"), TRUE)
1141 && list_append_tv(l, &argvars[1]) == OK)
1142 copy_tv(&argvars[0], rettv);
1143 }
1144 else
1145 EMSG(_(e_listreq));
1146}
1147
1148/*
1149 * "and(expr, expr)" function
1150 */
1151 static void
1152f_and(typval_T *argvars, typval_T *rettv)
1153{
1154 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1155 & get_tv_number_chk(&argvars[1], NULL);
1156}
1157
1158/*
1159 * "append(lnum, string/list)" function
1160 */
1161 static void
1162f_append(typval_T *argvars, typval_T *rettv)
1163{
1164 long lnum;
1165 char_u *line;
1166 list_T *l = NULL;
1167 listitem_T *li = NULL;
1168 typval_T *tv;
1169 long added = 0;
1170
1171 /* When coming here from Insert mode, sync undo, so that this can be
1172 * undone separately from what was previously inserted. */
1173 if (u_sync_once == 2)
1174 {
1175 u_sync_once = 1; /* notify that u_sync() was called */
1176 u_sync(TRUE);
1177 }
1178
1179 lnum = get_tv_lnum(argvars);
1180 if (lnum >= 0
1181 && lnum <= curbuf->b_ml.ml_line_count
1182 && u_save(lnum, lnum + 1) == OK)
1183 {
1184 if (argvars[1].v_type == VAR_LIST)
1185 {
1186 l = argvars[1].vval.v_list;
1187 if (l == NULL)
1188 return;
1189 li = l->lv_first;
1190 }
1191 for (;;)
1192 {
1193 if (l == NULL)
1194 tv = &argvars[1]; /* append a string */
1195 else if (li == NULL)
1196 break; /* end of list */
1197 else
1198 tv = &li->li_tv; /* append item from list */
1199 line = get_tv_string_chk(tv);
1200 if (line == NULL) /* type error */
1201 {
1202 rettv->vval.v_number = 1; /* Failed */
1203 break;
1204 }
1205 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1206 ++added;
1207 if (l == NULL)
1208 break;
1209 li = li->li_next;
1210 }
1211
1212 appended_lines_mark(lnum, added);
1213 if (curwin->w_cursor.lnum > lnum)
1214 curwin->w_cursor.lnum += added;
1215 }
1216 else
1217 rettv->vval.v_number = 1; /* Failed */
1218}
1219
1220/*
1221 * "argc()" function
1222 */
1223 static void
1224f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1225{
1226 rettv->vval.v_number = ARGCOUNT;
1227}
1228
1229/*
1230 * "argidx()" function
1231 */
1232 static void
1233f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1234{
1235 rettv->vval.v_number = curwin->w_arg_idx;
1236}
1237
1238/*
1239 * "arglistid()" function
1240 */
1241 static void
1242f_arglistid(typval_T *argvars, typval_T *rettv)
1243{
1244 win_T *wp;
1245
1246 rettv->vval.v_number = -1;
1247 wp = find_tabwin(&argvars[0], &argvars[1]);
1248 if (wp != NULL)
1249 rettv->vval.v_number = wp->w_alist->id;
1250}
1251
1252/*
1253 * "argv(nr)" function
1254 */
1255 static void
1256f_argv(typval_T *argvars, typval_T *rettv)
1257{
1258 int idx;
1259
1260 if (argvars[0].v_type != VAR_UNKNOWN)
1261 {
1262 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1263 if (idx >= 0 && idx < ARGCOUNT)
1264 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1265 else
1266 rettv->vval.v_string = NULL;
1267 rettv->v_type = VAR_STRING;
1268 }
1269 else if (rettv_list_alloc(rettv) == OK)
1270 for (idx = 0; idx < ARGCOUNT; ++idx)
1271 list_append_string(rettv->vval.v_list,
1272 alist_name(&ARGLIST[idx]), -1);
1273}
1274
1275/*
1276 * "assert_equal(expected, actual[, msg])" function
1277 */
1278 static void
1279f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1280{
1281 assert_equal_common(argvars, ASSERT_EQUAL);
1282}
1283
1284/*
1285 * "assert_notequal(expected, actual[, msg])" function
1286 */
1287 static void
1288f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1289{
1290 assert_equal_common(argvars, ASSERT_NOTEQUAL);
1291}
1292
1293/*
1294 * "assert_exception(string[, msg])" function
1295 */
1296 static void
1297f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1298{
1299 assert_exception(argvars);
1300}
1301
1302/*
1303 * "assert_fails(cmd [, error])" function
1304 */
1305 static void
1306f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1307{
1308 assert_fails(argvars);
1309}
1310
1311/*
1312 * "assert_false(actual[, msg])" function
1313 */
1314 static void
1315f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1316{
1317 assert_bool(argvars, FALSE);
1318}
1319
1320/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001321 * "assert_inrange(lower, upper[, msg])" function
1322 */
1323 static void
1324f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1325{
1326 assert_inrange(argvars);
1327}
1328
1329/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001330 * "assert_match(pattern, actual[, msg])" function
1331 */
1332 static void
1333f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1334{
1335 assert_match_common(argvars, ASSERT_MATCH);
1336}
1337
1338/*
1339 * "assert_notmatch(pattern, actual[, msg])" function
1340 */
1341 static void
1342f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1343{
1344 assert_match_common(argvars, ASSERT_NOTMATCH);
1345}
1346
1347/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001348 * "assert_report(msg)" function
1349 */
1350 static void
1351f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
1352{
1353 assert_report(argvars);
1354}
1355
1356/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001357 * "assert_true(actual[, msg])" function
1358 */
1359 static void
1360f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1361{
1362 assert_bool(argvars, TRUE);
1363}
1364
1365#ifdef FEAT_FLOAT
1366/*
1367 * "asin()" function
1368 */
1369 static void
1370f_asin(typval_T *argvars, typval_T *rettv)
1371{
1372 float_T f = 0.0;
1373
1374 rettv->v_type = VAR_FLOAT;
1375 if (get_float_arg(argvars, &f) == OK)
1376 rettv->vval.v_float = asin(f);
1377 else
1378 rettv->vval.v_float = 0.0;
1379}
1380
1381/*
1382 * "atan()" function
1383 */
1384 static void
1385f_atan(typval_T *argvars, typval_T *rettv)
1386{
1387 float_T f = 0.0;
1388
1389 rettv->v_type = VAR_FLOAT;
1390 if (get_float_arg(argvars, &f) == OK)
1391 rettv->vval.v_float = atan(f);
1392 else
1393 rettv->vval.v_float = 0.0;
1394}
1395
1396/*
1397 * "atan2()" function
1398 */
1399 static void
1400f_atan2(typval_T *argvars, typval_T *rettv)
1401{
1402 float_T fx = 0.0, fy = 0.0;
1403
1404 rettv->v_type = VAR_FLOAT;
1405 if (get_float_arg(argvars, &fx) == OK
1406 && get_float_arg(&argvars[1], &fy) == OK)
1407 rettv->vval.v_float = atan2(fx, fy);
1408 else
1409 rettv->vval.v_float = 0.0;
1410}
1411#endif
1412
1413/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001414 * "balloon_show()" function
1415 */
1416#ifdef FEAT_BEVAL
1417 static void
1418f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1419{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001420 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001421 {
1422 if (argvars[0].v_type == VAR_LIST
1423# ifdef FEAT_GUI
1424 && !gui.in_use
1425# endif
1426 )
1427 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1428 else
1429 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1430 }
1431}
1432
Bram Moolenaar669a8282017-11-19 20:13:05 +01001433# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001434 static void
1435f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1436{
1437 if (rettv_list_alloc(rettv) == OK)
1438 {
1439 char_u *msg = get_tv_string_chk(&argvars[0]);
1440
1441 if (msg != NULL)
1442 {
1443 pumitem_T *array;
1444 int size = split_message(msg, &array);
1445 int i;
1446
1447 /* Skip the first and last item, they are always empty. */
1448 for (i = 1; i < size - 1; ++i)
1449 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001450 while (size > 0)
1451 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001452 vim_free(array);
1453 }
1454 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001455}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001456# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001457#endif
1458
1459/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001460 * "browse(save, title, initdir, default)" function
1461 */
1462 static void
1463f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1464{
1465#ifdef FEAT_BROWSE
1466 int save;
1467 char_u *title;
1468 char_u *initdir;
1469 char_u *defname;
1470 char_u buf[NUMBUFLEN];
1471 char_u buf2[NUMBUFLEN];
1472 int error = FALSE;
1473
1474 save = (int)get_tv_number_chk(&argvars[0], &error);
1475 title = get_tv_string_chk(&argvars[1]);
1476 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1477 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1478
1479 if (error || title == NULL || initdir == NULL || defname == NULL)
1480 rettv->vval.v_string = NULL;
1481 else
1482 rettv->vval.v_string =
1483 do_browse(save ? BROWSE_SAVE : 0,
1484 title, defname, NULL, initdir, NULL, curbuf);
1485#else
1486 rettv->vval.v_string = NULL;
1487#endif
1488 rettv->v_type = VAR_STRING;
1489}
1490
1491/*
1492 * "browsedir(title, initdir)" function
1493 */
1494 static void
1495f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1496{
1497#ifdef FEAT_BROWSE
1498 char_u *title;
1499 char_u *initdir;
1500 char_u buf[NUMBUFLEN];
1501
1502 title = get_tv_string_chk(&argvars[0]);
1503 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1504
1505 if (title == NULL || initdir == NULL)
1506 rettv->vval.v_string = NULL;
1507 else
1508 rettv->vval.v_string = do_browse(BROWSE_DIR,
1509 title, NULL, NULL, initdir, NULL, curbuf);
1510#else
1511 rettv->vval.v_string = NULL;
1512#endif
1513 rettv->v_type = VAR_STRING;
1514}
1515
1516static buf_T *find_buffer(typval_T *avar);
1517
1518/*
1519 * Find a buffer by number or exact name.
1520 */
1521 static buf_T *
1522find_buffer(typval_T *avar)
1523{
1524 buf_T *buf = NULL;
1525
1526 if (avar->v_type == VAR_NUMBER)
1527 buf = buflist_findnr((int)avar->vval.v_number);
1528 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1529 {
1530 buf = buflist_findname_exp(avar->vval.v_string);
1531 if (buf == NULL)
1532 {
1533 /* No full path name match, try a match with a URL or a "nofile"
1534 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001535 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001536 if (buf->b_fname != NULL
1537 && (path_with_url(buf->b_fname)
1538#ifdef FEAT_QUICKFIX
1539 || bt_nofile(buf)
1540#endif
1541 )
1542 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1543 break;
1544 }
1545 }
1546 return buf;
1547}
1548
1549/*
1550 * "bufexists(expr)" function
1551 */
1552 static void
1553f_bufexists(typval_T *argvars, typval_T *rettv)
1554{
1555 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1556}
1557
1558/*
1559 * "buflisted(expr)" function
1560 */
1561 static void
1562f_buflisted(typval_T *argvars, typval_T *rettv)
1563{
1564 buf_T *buf;
1565
1566 buf = find_buffer(&argvars[0]);
1567 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1568}
1569
1570/*
1571 * "bufloaded(expr)" function
1572 */
1573 static void
1574f_bufloaded(typval_T *argvars, typval_T *rettv)
1575{
1576 buf_T *buf;
1577
1578 buf = find_buffer(&argvars[0]);
1579 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1580}
1581
1582 buf_T *
1583buflist_find_by_name(char_u *name, int curtab_only)
1584{
1585 int save_magic;
1586 char_u *save_cpo;
1587 buf_T *buf;
1588
1589 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1590 save_magic = p_magic;
1591 p_magic = TRUE;
1592 save_cpo = p_cpo;
1593 p_cpo = (char_u *)"";
1594
1595 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1596 TRUE, FALSE, curtab_only));
1597
1598 p_magic = save_magic;
1599 p_cpo = save_cpo;
1600 return buf;
1601}
1602
1603/*
1604 * Get buffer by number or pattern.
1605 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001606 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607get_buf_tv(typval_T *tv, int curtab_only)
1608{
1609 char_u *name = tv->vval.v_string;
1610 buf_T *buf;
1611
1612 if (tv->v_type == VAR_NUMBER)
1613 return buflist_findnr((int)tv->vval.v_number);
1614 if (tv->v_type != VAR_STRING)
1615 return NULL;
1616 if (name == NULL || *name == NUL)
1617 return curbuf;
1618 if (name[0] == '$' && name[1] == NUL)
1619 return lastbuf;
1620
1621 buf = buflist_find_by_name(name, curtab_only);
1622
1623 /* If not found, try expanding the name, like done for bufexists(). */
1624 if (buf == NULL)
1625 buf = find_buffer(tv);
1626
1627 return buf;
1628}
1629
1630/*
1631 * "bufname(expr)" function
1632 */
1633 static void
1634f_bufname(typval_T *argvars, typval_T *rettv)
1635{
1636 buf_T *buf;
1637
1638 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1639 ++emsg_off;
1640 buf = get_buf_tv(&argvars[0], FALSE);
1641 rettv->v_type = VAR_STRING;
1642 if (buf != NULL && buf->b_fname != NULL)
1643 rettv->vval.v_string = vim_strsave(buf->b_fname);
1644 else
1645 rettv->vval.v_string = NULL;
1646 --emsg_off;
1647}
1648
1649/*
1650 * "bufnr(expr)" function
1651 */
1652 static void
1653f_bufnr(typval_T *argvars, typval_T *rettv)
1654{
1655 buf_T *buf;
1656 int error = FALSE;
1657 char_u *name;
1658
1659 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1660 ++emsg_off;
1661 buf = get_buf_tv(&argvars[0], FALSE);
1662 --emsg_off;
1663
1664 /* If the buffer isn't found and the second argument is not zero create a
1665 * new buffer. */
1666 if (buf == NULL
1667 && argvars[1].v_type != VAR_UNKNOWN
1668 && get_tv_number_chk(&argvars[1], &error) != 0
1669 && !error
1670 && (name = get_tv_string_chk(&argvars[0])) != NULL
1671 && !error)
1672 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1673
1674 if (buf != NULL)
1675 rettv->vval.v_number = buf->b_fnum;
1676 else
1677 rettv->vval.v_number = -1;
1678}
1679
1680 static void
1681buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1682{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001683 win_T *wp;
1684 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 buf_T *buf;
1686
1687 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1688 ++emsg_off;
1689 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001690 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691 {
1692 ++winnr;
1693 if (wp->w_buffer == buf)
1694 break;
1695 }
1696 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697 --emsg_off;
1698}
1699
1700/*
1701 * "bufwinid(nr)" function
1702 */
1703 static void
1704f_bufwinid(typval_T *argvars, typval_T *rettv)
1705{
1706 buf_win_common(argvars, rettv, FALSE);
1707}
1708
1709/*
1710 * "bufwinnr(nr)" function
1711 */
1712 static void
1713f_bufwinnr(typval_T *argvars, typval_T *rettv)
1714{
1715 buf_win_common(argvars, rettv, TRUE);
1716}
1717
1718/*
1719 * "byte2line(byte)" function
1720 */
1721 static void
1722f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1723{
1724#ifndef FEAT_BYTEOFF
1725 rettv->vval.v_number = -1;
1726#else
1727 long boff = 0;
1728
1729 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1730 if (boff < 0)
1731 rettv->vval.v_number = -1;
1732 else
1733 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1734 (linenr_T)0, &boff);
1735#endif
1736}
1737
1738 static void
1739byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1740{
1741#ifdef FEAT_MBYTE
1742 char_u *t;
1743#endif
1744 char_u *str;
1745 varnumber_T idx;
1746
1747 str = get_tv_string_chk(&argvars[0]);
1748 idx = get_tv_number_chk(&argvars[1], NULL);
1749 rettv->vval.v_number = -1;
1750 if (str == NULL || idx < 0)
1751 return;
1752
1753#ifdef FEAT_MBYTE
1754 t = str;
1755 for ( ; idx > 0; idx--)
1756 {
1757 if (*t == NUL) /* EOL reached */
1758 return;
1759 if (enc_utf8 && comp)
1760 t += utf_ptr2len(t);
1761 else
1762 t += (*mb_ptr2len)(t);
1763 }
1764 rettv->vval.v_number = (varnumber_T)(t - str);
1765#else
1766 if ((size_t)idx <= STRLEN(str))
1767 rettv->vval.v_number = idx;
1768#endif
1769}
1770
1771/*
1772 * "byteidx()" function
1773 */
1774 static void
1775f_byteidx(typval_T *argvars, typval_T *rettv)
1776{
1777 byteidx(argvars, rettv, FALSE);
1778}
1779
1780/*
1781 * "byteidxcomp()" function
1782 */
1783 static void
1784f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1785{
1786 byteidx(argvars, rettv, TRUE);
1787}
1788
1789/*
1790 * "call(func, arglist [, dict])" function
1791 */
1792 static void
1793f_call(typval_T *argvars, typval_T *rettv)
1794{
1795 char_u *func;
1796 partial_T *partial = NULL;
1797 dict_T *selfdict = NULL;
1798
1799 if (argvars[1].v_type != VAR_LIST)
1800 {
1801 EMSG(_(e_listreq));
1802 return;
1803 }
1804 if (argvars[1].vval.v_list == NULL)
1805 return;
1806
1807 if (argvars[0].v_type == VAR_FUNC)
1808 func = argvars[0].vval.v_string;
1809 else if (argvars[0].v_type == VAR_PARTIAL)
1810 {
1811 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001812 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 }
1814 else
1815 func = get_tv_string(&argvars[0]);
1816 if (*func == NUL)
1817 return; /* type error or empty name */
1818
1819 if (argvars[2].v_type != VAR_UNKNOWN)
1820 {
1821 if (argvars[2].v_type != VAR_DICT)
1822 {
1823 EMSG(_(e_dictreq));
1824 return;
1825 }
1826 selfdict = argvars[2].vval.v_dict;
1827 }
1828
1829 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1830}
1831
1832#ifdef FEAT_FLOAT
1833/*
1834 * "ceil({float})" function
1835 */
1836 static void
1837f_ceil(typval_T *argvars, typval_T *rettv)
1838{
1839 float_T f = 0.0;
1840
1841 rettv->v_type = VAR_FLOAT;
1842 if (get_float_arg(argvars, &f) == OK)
1843 rettv->vval.v_float = ceil(f);
1844 else
1845 rettv->vval.v_float = 0.0;
1846}
1847#endif
1848
1849#ifdef FEAT_JOB_CHANNEL
1850/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001851 * "ch_canread()" function
1852 */
1853 static void
1854f_ch_canread(typval_T *argvars, typval_T *rettv)
1855{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001856 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001857
1858 rettv->vval.v_number = 0;
1859 if (channel != NULL)
1860 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1861 || channel_has_readahead(channel, PART_OUT)
1862 || channel_has_readahead(channel, PART_ERR);
1863}
1864
1865/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001866 * "ch_close()" function
1867 */
1868 static void
1869f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1870{
1871 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1872
1873 if (channel != NULL)
1874 {
1875 channel_close(channel, FALSE);
1876 channel_clear(channel);
1877 }
1878}
1879
1880/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001881 * "ch_close()" function
1882 */
1883 static void
1884f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1885{
1886 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1887
1888 if (channel != NULL)
1889 channel_close_in(channel);
1890}
1891
1892/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001893 * "ch_getbufnr()" function
1894 */
1895 static void
1896f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1897{
1898 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1899
1900 rettv->vval.v_number = -1;
1901 if (channel != NULL)
1902 {
1903 char_u *what = get_tv_string(&argvars[1]);
1904 int part;
1905
1906 if (STRCMP(what, "err") == 0)
1907 part = PART_ERR;
1908 else if (STRCMP(what, "out") == 0)
1909 part = PART_OUT;
1910 else if (STRCMP(what, "in") == 0)
1911 part = PART_IN;
1912 else
1913 part = PART_SOCK;
1914 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1915 rettv->vval.v_number =
1916 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1917 }
1918}
1919
1920/*
1921 * "ch_getjob()" function
1922 */
1923 static void
1924f_ch_getjob(typval_T *argvars, typval_T *rettv)
1925{
1926 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1927
1928 if (channel != NULL)
1929 {
1930 rettv->v_type = VAR_JOB;
1931 rettv->vval.v_job = channel->ch_job;
1932 if (channel->ch_job != NULL)
1933 ++channel->ch_job->jv_refcount;
1934 }
1935}
1936
1937/*
1938 * "ch_info()" function
1939 */
1940 static void
1941f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1942{
1943 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1944
1945 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1946 channel_info(channel, rettv->vval.v_dict);
1947}
1948
1949/*
1950 * "ch_log()" function
1951 */
1952 static void
1953f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1954{
1955 char_u *msg = get_tv_string(&argvars[0]);
1956 channel_T *channel = NULL;
1957
1958 if (argvars[1].v_type != VAR_UNKNOWN)
1959 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
1960
1961 ch_log(channel, (char *)msg);
1962}
1963
1964/*
1965 * "ch_logfile()" function
1966 */
1967 static void
1968f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
1969{
1970 char_u *fname;
1971 char_u *opt = (char_u *)"";
1972 char_u buf[NUMBUFLEN];
1973
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02001974 /* Don't open a file in restricted mode. */
1975 if (check_restricted() || check_secure())
1976 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001977 fname = get_tv_string(&argvars[0]);
1978 if (argvars[1].v_type == VAR_STRING)
1979 opt = get_tv_string_buf(&argvars[1], buf);
1980 ch_logfile(fname, opt);
1981}
1982
1983/*
1984 * "ch_open()" function
1985 */
1986 static void
1987f_ch_open(typval_T *argvars, typval_T *rettv)
1988{
1989 rettv->v_type = VAR_CHANNEL;
1990 if (check_restricted() || check_secure())
1991 return;
1992 rettv->vval.v_channel = channel_open_func(argvars);
1993}
1994
1995/*
1996 * "ch_read()" function
1997 */
1998 static void
1999f_ch_read(typval_T *argvars, typval_T *rettv)
2000{
2001 common_channel_read(argvars, rettv, FALSE);
2002}
2003
2004/*
2005 * "ch_readraw()" function
2006 */
2007 static void
2008f_ch_readraw(typval_T *argvars, typval_T *rettv)
2009{
2010 common_channel_read(argvars, rettv, TRUE);
2011}
2012
2013/*
2014 * "ch_evalexpr()" function
2015 */
2016 static void
2017f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2018{
2019 ch_expr_common(argvars, rettv, TRUE);
2020}
2021
2022/*
2023 * "ch_sendexpr()" function
2024 */
2025 static void
2026f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2027{
2028 ch_expr_common(argvars, rettv, FALSE);
2029}
2030
2031/*
2032 * "ch_evalraw()" function
2033 */
2034 static void
2035f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2036{
2037 ch_raw_common(argvars, rettv, TRUE);
2038}
2039
2040/*
2041 * "ch_sendraw()" function
2042 */
2043 static void
2044f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2045{
2046 ch_raw_common(argvars, rettv, FALSE);
2047}
2048
2049/*
2050 * "ch_setoptions()" function
2051 */
2052 static void
2053f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2054{
2055 channel_T *channel;
2056 jobopt_T opt;
2057
2058 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2059 if (channel == NULL)
2060 return;
2061 clear_job_options(&opt);
2062 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002063 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002064 channel_set_options(channel, &opt);
2065 free_job_options(&opt);
2066}
2067
2068/*
2069 * "ch_status()" function
2070 */
2071 static void
2072f_ch_status(typval_T *argvars, typval_T *rettv)
2073{
2074 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002075 jobopt_T opt;
2076 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077
2078 /* return an empty string by default */
2079 rettv->v_type = VAR_STRING;
2080 rettv->vval.v_string = NULL;
2081
2082 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002083
2084 if (argvars[1].v_type != VAR_UNKNOWN)
2085 {
2086 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002087 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002088 && (opt.jo_set & JO_PART))
2089 part = opt.jo_part;
2090 }
2091
2092 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093}
2094#endif
2095
2096/*
2097 * "changenr()" function
2098 */
2099 static void
2100f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2101{
2102 rettv->vval.v_number = curbuf->b_u_seq_cur;
2103}
2104
2105/*
2106 * "char2nr(string)" function
2107 */
2108 static void
2109f_char2nr(typval_T *argvars, typval_T *rettv)
2110{
2111#ifdef FEAT_MBYTE
2112 if (has_mbyte)
2113 {
2114 int utf8 = 0;
2115
2116 if (argvars[1].v_type != VAR_UNKNOWN)
2117 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2118
2119 if (utf8)
2120 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2121 else
2122 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2123 }
2124 else
2125#endif
2126 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2127}
2128
2129/*
2130 * "cindent(lnum)" function
2131 */
2132 static void
2133f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2134{
2135#ifdef FEAT_CINDENT
2136 pos_T pos;
2137 linenr_T lnum;
2138
2139 pos = curwin->w_cursor;
2140 lnum = get_tv_lnum(argvars);
2141 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2142 {
2143 curwin->w_cursor.lnum = lnum;
2144 rettv->vval.v_number = get_c_indent();
2145 curwin->w_cursor = pos;
2146 }
2147 else
2148#endif
2149 rettv->vval.v_number = -1;
2150}
2151
2152/*
2153 * "clearmatches()" function
2154 */
2155 static void
2156f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2157{
2158#ifdef FEAT_SEARCH_EXTRA
2159 clear_matches(curwin);
2160#endif
2161}
2162
2163/*
2164 * "col(string)" function
2165 */
2166 static void
2167f_col(typval_T *argvars, typval_T *rettv)
2168{
2169 colnr_T col = 0;
2170 pos_T *fp;
2171 int fnum = curbuf->b_fnum;
2172
2173 fp = var2fpos(&argvars[0], FALSE, &fnum);
2174 if (fp != NULL && fnum == curbuf->b_fnum)
2175 {
2176 if (fp->col == MAXCOL)
2177 {
2178 /* '> can be MAXCOL, get the length of the line then */
2179 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2180 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2181 else
2182 col = MAXCOL;
2183 }
2184 else
2185 {
2186 col = fp->col + 1;
2187#ifdef FEAT_VIRTUALEDIT
2188 /* col(".") when the cursor is on the NUL at the end of the line
2189 * because of "coladd" can be seen as an extra column. */
2190 if (virtual_active() && fp == &curwin->w_cursor)
2191 {
2192 char_u *p = ml_get_cursor();
2193
2194 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2195 curwin->w_virtcol - curwin->w_cursor.coladd))
2196 {
2197# ifdef FEAT_MBYTE
2198 int l;
2199
2200 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2201 col += l;
2202# else
2203 if (*p != NUL && p[1] == NUL)
2204 ++col;
2205# endif
2206 }
2207 }
2208#endif
2209 }
2210 }
2211 rettv->vval.v_number = col;
2212}
2213
2214#if defined(FEAT_INS_EXPAND)
2215/*
2216 * "complete()" function
2217 */
2218 static void
2219f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2220{
2221 int startcol;
2222
2223 if ((State & INSERT) == 0)
2224 {
2225 EMSG(_("E785: complete() can only be used in Insert mode"));
2226 return;
2227 }
2228
2229 /* Check for undo allowed here, because if something was already inserted
2230 * the line was already saved for undo and this check isn't done. */
2231 if (!undo_allowed())
2232 return;
2233
2234 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2235 {
2236 EMSG(_(e_invarg));
2237 return;
2238 }
2239
2240 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2241 if (startcol <= 0)
2242 return;
2243
2244 set_completion(startcol - 1, argvars[1].vval.v_list);
2245}
2246
2247/*
2248 * "complete_add()" function
2249 */
2250 static void
2251f_complete_add(typval_T *argvars, typval_T *rettv)
2252{
2253 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2254}
2255
2256/*
2257 * "complete_check()" function
2258 */
2259 static void
2260f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2261{
2262 int saved = RedrawingDisabled;
2263
2264 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002265 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 rettv->vval.v_number = compl_interrupted;
2267 RedrawingDisabled = saved;
2268}
2269#endif
2270
2271/*
2272 * "confirm(message, buttons[, default [, type]])" function
2273 */
2274 static void
2275f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2276{
2277#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2278 char_u *message;
2279 char_u *buttons = NULL;
2280 char_u buf[NUMBUFLEN];
2281 char_u buf2[NUMBUFLEN];
2282 int def = 1;
2283 int type = VIM_GENERIC;
2284 char_u *typestr;
2285 int error = FALSE;
2286
2287 message = get_tv_string_chk(&argvars[0]);
2288 if (message == NULL)
2289 error = TRUE;
2290 if (argvars[1].v_type != VAR_UNKNOWN)
2291 {
2292 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2293 if (buttons == NULL)
2294 error = TRUE;
2295 if (argvars[2].v_type != VAR_UNKNOWN)
2296 {
2297 def = (int)get_tv_number_chk(&argvars[2], &error);
2298 if (argvars[3].v_type != VAR_UNKNOWN)
2299 {
2300 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2301 if (typestr == NULL)
2302 error = TRUE;
2303 else
2304 {
2305 switch (TOUPPER_ASC(*typestr))
2306 {
2307 case 'E': type = VIM_ERROR; break;
2308 case 'Q': type = VIM_QUESTION; break;
2309 case 'I': type = VIM_INFO; break;
2310 case 'W': type = VIM_WARNING; break;
2311 case 'G': type = VIM_GENERIC; break;
2312 }
2313 }
2314 }
2315 }
2316 }
2317
2318 if (buttons == NULL || *buttons == NUL)
2319 buttons = (char_u *)_("&Ok");
2320
2321 if (!error)
2322 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2323 def, NULL, FALSE);
2324#endif
2325}
2326
2327/*
2328 * "copy()" function
2329 */
2330 static void
2331f_copy(typval_T *argvars, typval_T *rettv)
2332{
2333 item_copy(&argvars[0], rettv, FALSE, 0);
2334}
2335
2336#ifdef FEAT_FLOAT
2337/*
2338 * "cos()" function
2339 */
2340 static void
2341f_cos(typval_T *argvars, typval_T *rettv)
2342{
2343 float_T f = 0.0;
2344
2345 rettv->v_type = VAR_FLOAT;
2346 if (get_float_arg(argvars, &f) == OK)
2347 rettv->vval.v_float = cos(f);
2348 else
2349 rettv->vval.v_float = 0.0;
2350}
2351
2352/*
2353 * "cosh()" function
2354 */
2355 static void
2356f_cosh(typval_T *argvars, typval_T *rettv)
2357{
2358 float_T f = 0.0;
2359
2360 rettv->v_type = VAR_FLOAT;
2361 if (get_float_arg(argvars, &f) == OK)
2362 rettv->vval.v_float = cosh(f);
2363 else
2364 rettv->vval.v_float = 0.0;
2365}
2366#endif
2367
2368/*
2369 * "count()" function
2370 */
2371 static void
2372f_count(typval_T *argvars, typval_T *rettv)
2373{
2374 long n = 0;
2375 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002376 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002377
Bram Moolenaar9966b212017-07-28 16:46:57 +02002378 if (argvars[2].v_type != VAR_UNKNOWN)
2379 ic = (int)get_tv_number_chk(&argvars[2], &error);
2380
2381 if (argvars[0].v_type == VAR_STRING)
2382 {
2383 char_u *expr = get_tv_string_chk(&argvars[1]);
2384 char_u *p = argvars[0].vval.v_string;
2385 char_u *next;
2386
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002387 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002388 {
2389 if (ic)
2390 {
2391 size_t len = STRLEN(expr);
2392
2393 while (*p != NUL)
2394 {
2395 if (MB_STRNICMP(p, expr, len) == 0)
2396 {
2397 ++n;
2398 p += len;
2399 }
2400 else
2401 MB_PTR_ADV(p);
2402 }
2403 }
2404 else
2405 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2406 != NULL)
2407 {
2408 ++n;
2409 p = next + STRLEN(expr);
2410 }
2411 }
2412
2413 }
2414 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002415 {
2416 listitem_T *li;
2417 list_T *l;
2418 long idx;
2419
2420 if ((l = argvars[0].vval.v_list) != NULL)
2421 {
2422 li = l->lv_first;
2423 if (argvars[2].v_type != VAR_UNKNOWN)
2424 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002425 if (argvars[3].v_type != VAR_UNKNOWN)
2426 {
2427 idx = (long)get_tv_number_chk(&argvars[3], &error);
2428 if (!error)
2429 {
2430 li = list_find(l, idx);
2431 if (li == NULL)
2432 EMSGN(_(e_listidx), idx);
2433 }
2434 }
2435 if (error)
2436 li = NULL;
2437 }
2438
2439 for ( ; li != NULL; li = li->li_next)
2440 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2441 ++n;
2442 }
2443 }
2444 else if (argvars[0].v_type == VAR_DICT)
2445 {
2446 int todo;
2447 dict_T *d;
2448 hashitem_T *hi;
2449
2450 if ((d = argvars[0].vval.v_dict) != NULL)
2451 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 if (argvars[2].v_type != VAR_UNKNOWN)
2453 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002454 if (argvars[3].v_type != VAR_UNKNOWN)
2455 EMSG(_(e_invarg));
2456 }
2457
2458 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2459 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2460 {
2461 if (!HASHITEM_EMPTY(hi))
2462 {
2463 --todo;
2464 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2465 ++n;
2466 }
2467 }
2468 }
2469 }
2470 else
2471 EMSG2(_(e_listdictarg), "count()");
2472 rettv->vval.v_number = n;
2473}
2474
2475/*
2476 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2477 *
2478 * Checks the existence of a cscope connection.
2479 */
2480 static void
2481f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2482{
2483#ifdef FEAT_CSCOPE
2484 int num = 0;
2485 char_u *dbpath = NULL;
2486 char_u *prepend = NULL;
2487 char_u buf[NUMBUFLEN];
2488
2489 if (argvars[0].v_type != VAR_UNKNOWN
2490 && argvars[1].v_type != VAR_UNKNOWN)
2491 {
2492 num = (int)get_tv_number(&argvars[0]);
2493 dbpath = get_tv_string(&argvars[1]);
2494 if (argvars[2].v_type != VAR_UNKNOWN)
2495 prepend = get_tv_string_buf(&argvars[2], buf);
2496 }
2497
2498 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2499#endif
2500}
2501
2502/*
2503 * "cursor(lnum, col)" function, or
2504 * "cursor(list)"
2505 *
2506 * Moves the cursor to the specified line and column.
2507 * Returns 0 when the position could be set, -1 otherwise.
2508 */
2509 static void
2510f_cursor(typval_T *argvars, typval_T *rettv)
2511{
2512 long line, col;
2513#ifdef FEAT_VIRTUALEDIT
2514 long coladd = 0;
2515#endif
2516 int set_curswant = TRUE;
2517
2518 rettv->vval.v_number = -1;
2519 if (argvars[1].v_type == VAR_UNKNOWN)
2520 {
2521 pos_T pos;
2522 colnr_T curswant = -1;
2523
2524 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2525 {
2526 EMSG(_(e_invarg));
2527 return;
2528 }
2529 line = pos.lnum;
2530 col = pos.col;
2531#ifdef FEAT_VIRTUALEDIT
2532 coladd = pos.coladd;
2533#endif
2534 if (curswant >= 0)
2535 {
2536 curwin->w_curswant = curswant - 1;
2537 set_curswant = FALSE;
2538 }
2539 }
2540 else
2541 {
2542 line = get_tv_lnum(argvars);
2543 col = (long)get_tv_number_chk(&argvars[1], NULL);
2544#ifdef FEAT_VIRTUALEDIT
2545 if (argvars[2].v_type != VAR_UNKNOWN)
2546 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2547#endif
2548 }
2549 if (line < 0 || col < 0
2550#ifdef FEAT_VIRTUALEDIT
2551 || coladd < 0
2552#endif
2553 )
2554 return; /* type error; errmsg already given */
2555 if (line > 0)
2556 curwin->w_cursor.lnum = line;
2557 if (col > 0)
2558 curwin->w_cursor.col = col - 1;
2559#ifdef FEAT_VIRTUALEDIT
2560 curwin->w_cursor.coladd = coladd;
2561#endif
2562
2563 /* Make sure the cursor is in a valid position. */
2564 check_cursor();
2565#ifdef FEAT_MBYTE
2566 /* Correct cursor for multi-byte character. */
2567 if (has_mbyte)
2568 mb_adjust_cursor();
2569#endif
2570
2571 curwin->w_set_curswant = set_curswant;
2572 rettv->vval.v_number = 0;
2573}
2574
2575/*
2576 * "deepcopy()" function
2577 */
2578 static void
2579f_deepcopy(typval_T *argvars, typval_T *rettv)
2580{
2581 int noref = 0;
2582 int copyID;
2583
2584 if (argvars[1].v_type != VAR_UNKNOWN)
2585 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2586 if (noref < 0 || noref > 1)
2587 EMSG(_(e_invarg));
2588 else
2589 {
2590 copyID = get_copyID();
2591 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2592 }
2593}
2594
2595/*
2596 * "delete()" function
2597 */
2598 static void
2599f_delete(typval_T *argvars, typval_T *rettv)
2600{
2601 char_u nbuf[NUMBUFLEN];
2602 char_u *name;
2603 char_u *flags;
2604
2605 rettv->vval.v_number = -1;
2606 if (check_restricted() || check_secure())
2607 return;
2608
2609 name = get_tv_string(&argvars[0]);
2610 if (name == NULL || *name == NUL)
2611 {
2612 EMSG(_(e_invarg));
2613 return;
2614 }
2615
2616 if (argvars[1].v_type != VAR_UNKNOWN)
2617 flags = get_tv_string_buf(&argvars[1], nbuf);
2618 else
2619 flags = (char_u *)"";
2620
2621 if (*flags == NUL)
2622 /* delete a file */
2623 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2624 else if (STRCMP(flags, "d") == 0)
2625 /* delete an empty directory */
2626 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2627 else if (STRCMP(flags, "rf") == 0)
2628 /* delete a directory recursively */
2629 rettv->vval.v_number = delete_recursive(name);
2630 else
2631 EMSG2(_(e_invexpr2), flags);
2632}
2633
2634/*
2635 * "did_filetype()" function
2636 */
2637 static void
2638f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2639{
2640#ifdef FEAT_AUTOCMD
2641 rettv->vval.v_number = did_filetype;
2642#endif
2643}
2644
2645/*
2646 * "diff_filler()" function
2647 */
2648 static void
2649f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2650{
2651#ifdef FEAT_DIFF
2652 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2653#endif
2654}
2655
2656/*
2657 * "diff_hlID()" function
2658 */
2659 static void
2660f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2661{
2662#ifdef FEAT_DIFF
2663 linenr_T lnum = get_tv_lnum(argvars);
2664 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002665 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666 static int fnum = 0;
2667 static int change_start = 0;
2668 static int change_end = 0;
2669 static hlf_T hlID = (hlf_T)0;
2670 int filler_lines;
2671 int col;
2672
2673 if (lnum < 0) /* ignore type error in {lnum} arg */
2674 lnum = 0;
2675 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002676 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 || fnum != curbuf->b_fnum)
2678 {
2679 /* New line, buffer, change: need to get the values. */
2680 filler_lines = diff_check(curwin, lnum);
2681 if (filler_lines < 0)
2682 {
2683 if (filler_lines == -1)
2684 {
2685 change_start = MAXCOL;
2686 change_end = -1;
2687 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2688 hlID = HLF_ADD; /* added line */
2689 else
2690 hlID = HLF_CHD; /* changed line */
2691 }
2692 else
2693 hlID = HLF_ADD; /* added line */
2694 }
2695 else
2696 hlID = (hlf_T)0;
2697 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002698 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699 fnum = curbuf->b_fnum;
2700 }
2701
2702 if (hlID == HLF_CHD || hlID == HLF_TXD)
2703 {
2704 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2705 if (col >= change_start && col <= change_end)
2706 hlID = HLF_TXD; /* changed text */
2707 else
2708 hlID = HLF_CHD; /* changed line */
2709 }
2710 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2711#endif
2712}
2713
2714/*
2715 * "empty({expr})" function
2716 */
2717 static void
2718f_empty(typval_T *argvars, typval_T *rettv)
2719{
2720 int n = FALSE;
2721
2722 switch (argvars[0].v_type)
2723 {
2724 case VAR_STRING:
2725 case VAR_FUNC:
2726 n = argvars[0].vval.v_string == NULL
2727 || *argvars[0].vval.v_string == NUL;
2728 break;
2729 case VAR_PARTIAL:
2730 n = FALSE;
2731 break;
2732 case VAR_NUMBER:
2733 n = argvars[0].vval.v_number == 0;
2734 break;
2735 case VAR_FLOAT:
2736#ifdef FEAT_FLOAT
2737 n = argvars[0].vval.v_float == 0.0;
2738 break;
2739#endif
2740 case VAR_LIST:
2741 n = argvars[0].vval.v_list == NULL
2742 || argvars[0].vval.v_list->lv_first == NULL;
2743 break;
2744 case VAR_DICT:
2745 n = argvars[0].vval.v_dict == NULL
2746 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2747 break;
2748 case VAR_SPECIAL:
2749 n = argvars[0].vval.v_number != VVAL_TRUE;
2750 break;
2751
2752 case VAR_JOB:
2753#ifdef FEAT_JOB_CHANNEL
2754 n = argvars[0].vval.v_job == NULL
2755 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2756 break;
2757#endif
2758 case VAR_CHANNEL:
2759#ifdef FEAT_JOB_CHANNEL
2760 n = argvars[0].vval.v_channel == NULL
2761 || !channel_is_open(argvars[0].vval.v_channel);
2762 break;
2763#endif
2764 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002765 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002766 n = TRUE;
2767 break;
2768 }
2769
2770 rettv->vval.v_number = n;
2771}
2772
2773/*
2774 * "escape({string}, {chars})" function
2775 */
2776 static void
2777f_escape(typval_T *argvars, typval_T *rettv)
2778{
2779 char_u buf[NUMBUFLEN];
2780
2781 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2782 get_tv_string_buf(&argvars[1], buf));
2783 rettv->v_type = VAR_STRING;
2784}
2785
2786/*
2787 * "eval()" function
2788 */
2789 static void
2790f_eval(typval_T *argvars, typval_T *rettv)
2791{
2792 char_u *s, *p;
2793
2794 s = get_tv_string_chk(&argvars[0]);
2795 if (s != NULL)
2796 s = skipwhite(s);
2797
2798 p = s;
2799 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2800 {
2801 if (p != NULL && !aborting())
2802 EMSG2(_(e_invexpr2), p);
2803 need_clr_eos = FALSE;
2804 rettv->v_type = VAR_NUMBER;
2805 rettv->vval.v_number = 0;
2806 }
2807 else if (*s != NUL)
2808 EMSG(_(e_trailing));
2809}
2810
2811/*
2812 * "eventhandler()" function
2813 */
2814 static void
2815f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2816{
2817 rettv->vval.v_number = vgetc_busy;
2818}
2819
2820/*
2821 * "executable()" function
2822 */
2823 static void
2824f_executable(typval_T *argvars, typval_T *rettv)
2825{
2826 char_u *name = get_tv_string(&argvars[0]);
2827
2828 /* Check in $PATH and also check directly if there is a directory name. */
2829 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2830 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2831}
2832
2833static garray_T redir_execute_ga;
2834
2835/*
2836 * Append "value[value_len]" to the execute() output.
2837 */
2838 void
2839execute_redir_str(char_u *value, int value_len)
2840{
2841 int len;
2842
2843 if (value_len == -1)
2844 len = (int)STRLEN(value); /* Append the entire string */
2845 else
2846 len = value_len; /* Append only "value_len" characters */
2847 if (ga_grow(&redir_execute_ga, len) == OK)
2848 {
2849 mch_memmove((char *)redir_execute_ga.ga_data
2850 + redir_execute_ga.ga_len, value, len);
2851 redir_execute_ga.ga_len += len;
2852 }
2853}
2854
2855/*
2856 * Get next line from a list.
2857 * Called by do_cmdline() to get the next line.
2858 * Returns allocated string, or NULL for end of function.
2859 */
2860
2861 static char_u *
2862get_list_line(
2863 int c UNUSED,
2864 void *cookie,
2865 int indent UNUSED)
2866{
2867 listitem_T **p = (listitem_T **)cookie;
2868 listitem_T *item = *p;
2869 char_u buf[NUMBUFLEN];
2870 char_u *s;
2871
2872 if (item == NULL)
2873 return NULL;
2874 s = get_tv_string_buf_chk(&item->li_tv, buf);
2875 *p = item->li_next;
2876 return s == NULL ? NULL : vim_strsave(s);
2877}
2878
2879/*
2880 * "execute()" function
2881 */
2882 static void
2883f_execute(typval_T *argvars, typval_T *rettv)
2884{
2885 char_u *cmd = NULL;
2886 list_T *list = NULL;
2887 int save_msg_silent = msg_silent;
2888 int save_emsg_silent = emsg_silent;
2889 int save_emsg_noredir = emsg_noredir;
2890 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002891 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002892 garray_T save_ga;
2893
2894 rettv->vval.v_string = NULL;
2895 rettv->v_type = VAR_STRING;
2896
2897 if (argvars[0].v_type == VAR_LIST)
2898 {
2899 list = argvars[0].vval.v_list;
2900 if (list == NULL || list->lv_first == NULL)
2901 /* empty list, no commands, empty output */
2902 return;
2903 ++list->lv_refcount;
2904 }
2905 else
2906 {
2907 cmd = get_tv_string_chk(&argvars[0]);
2908 if (cmd == NULL)
2909 return;
2910 }
2911
2912 if (argvars[1].v_type != VAR_UNKNOWN)
2913 {
2914 char_u buf[NUMBUFLEN];
2915 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2916
2917 if (s == NULL)
2918 return;
2919 if (STRNCMP(s, "silent", 6) == 0)
2920 ++msg_silent;
2921 if (STRCMP(s, "silent!") == 0)
2922 {
2923 emsg_silent = TRUE;
2924 emsg_noredir = TRUE;
2925 }
2926 }
2927 else
2928 ++msg_silent;
2929
2930 if (redir_execute)
2931 save_ga = redir_execute_ga;
2932 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2933 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002934 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002935
2936 if (cmd != NULL)
2937 do_cmdline_cmd(cmd);
2938 else
2939 {
2940 listitem_T *item = list->lv_first;
2941
2942 do_cmdline(NULL, get_list_line, (void *)&item,
2943 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2944 --list->lv_refcount;
2945 }
2946
Bram Moolenaard297f352017-01-29 20:31:21 +01002947 /* Need to append a NUL to the result. */
2948 if (ga_grow(&redir_execute_ga, 1) == OK)
2949 {
2950 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2951 rettv->vval.v_string = redir_execute_ga.ga_data;
2952 }
2953 else
2954 {
2955 ga_clear(&redir_execute_ga);
2956 rettv->vval.v_string = NULL;
2957 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002958 msg_silent = save_msg_silent;
2959 emsg_silent = save_emsg_silent;
2960 emsg_noredir = save_emsg_noredir;
2961
2962 redir_execute = save_redir_execute;
2963 if (redir_execute)
2964 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002965 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002966
2967 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
2968 * line. Put it back in the first column. */
2969 msg_col = 0;
2970}
2971
2972/*
2973 * "exepath()" function
2974 */
2975 static void
2976f_exepath(typval_T *argvars, typval_T *rettv)
2977{
2978 char_u *p = NULL;
2979
2980 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
2981 rettv->v_type = VAR_STRING;
2982 rettv->vval.v_string = p;
2983}
2984
2985/*
2986 * "exists()" function
2987 */
2988 static void
2989f_exists(typval_T *argvars, typval_T *rettv)
2990{
2991 char_u *p;
2992 char_u *name;
2993 int n = FALSE;
2994 int len = 0;
2995
2996 p = get_tv_string(&argvars[0]);
2997 if (*p == '$') /* environment variable */
2998 {
2999 /* first try "normal" environment variables (fast) */
3000 if (mch_getenv(p + 1) != NULL)
3001 n = TRUE;
3002 else
3003 {
3004 /* try expanding things like $VIM and ${HOME} */
3005 p = expand_env_save(p);
3006 if (p != NULL && *p != '$')
3007 n = TRUE;
3008 vim_free(p);
3009 }
3010 }
3011 else if (*p == '&' || *p == '+') /* option */
3012 {
3013 n = (get_option_tv(&p, NULL, TRUE) == OK);
3014 if (*skipwhite(p) != NUL)
3015 n = FALSE; /* trailing garbage */
3016 }
3017 else if (*p == '*') /* internal or user defined function */
3018 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003019 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003020 }
3021 else if (*p == ':')
3022 {
3023 n = cmd_exists(p + 1);
3024 }
3025 else if (*p == '#')
3026 {
3027#ifdef FEAT_AUTOCMD
3028 if (p[1] == '#')
3029 n = autocmd_supported(p + 2);
3030 else
3031 n = au_exists(p + 1);
3032#endif
3033 }
3034 else /* internal variable */
3035 {
3036 char_u *tofree;
3037 typval_T tv;
3038
3039 /* get_name_len() takes care of expanding curly braces */
3040 name = p;
3041 len = get_name_len(&p, &tofree, TRUE, FALSE);
3042 if (len > 0)
3043 {
3044 if (tofree != NULL)
3045 name = tofree;
3046 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
3047 if (n)
3048 {
3049 /* handle d.key, l[idx], f(expr) */
3050 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
3051 if (n)
3052 clear_tv(&tv);
3053 }
3054 }
3055 if (*p != NUL)
3056 n = FALSE;
3057
3058 vim_free(tofree);
3059 }
3060
3061 rettv->vval.v_number = n;
3062}
3063
3064#ifdef FEAT_FLOAT
3065/*
3066 * "exp()" function
3067 */
3068 static void
3069f_exp(typval_T *argvars, typval_T *rettv)
3070{
3071 float_T f = 0.0;
3072
3073 rettv->v_type = VAR_FLOAT;
3074 if (get_float_arg(argvars, &f) == OK)
3075 rettv->vval.v_float = exp(f);
3076 else
3077 rettv->vval.v_float = 0.0;
3078}
3079#endif
3080
3081/*
3082 * "expand()" function
3083 */
3084 static void
3085f_expand(typval_T *argvars, typval_T *rettv)
3086{
3087 char_u *s;
3088 int len;
3089 char_u *errormsg;
3090 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3091 expand_T xpc;
3092 int error = FALSE;
3093 char_u *result;
3094
3095 rettv->v_type = VAR_STRING;
3096 if (argvars[1].v_type != VAR_UNKNOWN
3097 && argvars[2].v_type != VAR_UNKNOWN
3098 && get_tv_number_chk(&argvars[2], &error)
3099 && !error)
3100 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003101 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102 }
3103
3104 s = get_tv_string(&argvars[0]);
3105 if (*s == '%' || *s == '#' || *s == '<')
3106 {
3107 ++emsg_off;
3108 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3109 --emsg_off;
3110 if (rettv->v_type == VAR_LIST)
3111 {
3112 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3113 list_append_string(rettv->vval.v_list, result, -1);
3114 else
3115 vim_free(result);
3116 }
3117 else
3118 rettv->vval.v_string = result;
3119 }
3120 else
3121 {
3122 /* When the optional second argument is non-zero, don't remove matches
3123 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3124 if (argvars[1].v_type != VAR_UNKNOWN
3125 && get_tv_number_chk(&argvars[1], &error))
3126 options |= WILD_KEEP_ALL;
3127 if (!error)
3128 {
3129 ExpandInit(&xpc);
3130 xpc.xp_context = EXPAND_FILES;
3131 if (p_wic)
3132 options += WILD_ICASE;
3133 if (rettv->v_type == VAR_STRING)
3134 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3135 options, WILD_ALL);
3136 else if (rettv_list_alloc(rettv) != FAIL)
3137 {
3138 int i;
3139
3140 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3141 for (i = 0; i < xpc.xp_numfiles; i++)
3142 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3143 ExpandCleanup(&xpc);
3144 }
3145 }
3146 else
3147 rettv->vval.v_string = NULL;
3148 }
3149}
3150
3151/*
3152 * "extend(list, list [, idx])" function
3153 * "extend(dict, dict [, action])" function
3154 */
3155 static void
3156f_extend(typval_T *argvars, typval_T *rettv)
3157{
3158 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3159
3160 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3161 {
3162 list_T *l1, *l2;
3163 listitem_T *item;
3164 long before;
3165 int error = FALSE;
3166
3167 l1 = argvars[0].vval.v_list;
3168 l2 = argvars[1].vval.v_list;
3169 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3170 && l2 != NULL)
3171 {
3172 if (argvars[2].v_type != VAR_UNKNOWN)
3173 {
3174 before = (long)get_tv_number_chk(&argvars[2], &error);
3175 if (error)
3176 return; /* type error; errmsg already given */
3177
3178 if (before == l1->lv_len)
3179 item = NULL;
3180 else
3181 {
3182 item = list_find(l1, before);
3183 if (item == NULL)
3184 {
3185 EMSGN(_(e_listidx), before);
3186 return;
3187 }
3188 }
3189 }
3190 else
3191 item = NULL;
3192 list_extend(l1, l2, item);
3193
3194 copy_tv(&argvars[0], rettv);
3195 }
3196 }
3197 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3198 {
3199 dict_T *d1, *d2;
3200 char_u *action;
3201 int i;
3202
3203 d1 = argvars[0].vval.v_dict;
3204 d2 = argvars[1].vval.v_dict;
3205 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3206 && d2 != NULL)
3207 {
3208 /* Check the third argument. */
3209 if (argvars[2].v_type != VAR_UNKNOWN)
3210 {
3211 static char *(av[]) = {"keep", "force", "error"};
3212
3213 action = get_tv_string_chk(&argvars[2]);
3214 if (action == NULL)
3215 return; /* type error; errmsg already given */
3216 for (i = 0; i < 3; ++i)
3217 if (STRCMP(action, av[i]) == 0)
3218 break;
3219 if (i == 3)
3220 {
3221 EMSG2(_(e_invarg2), action);
3222 return;
3223 }
3224 }
3225 else
3226 action = (char_u *)"force";
3227
3228 dict_extend(d1, d2, action);
3229
3230 copy_tv(&argvars[0], rettv);
3231 }
3232 }
3233 else
3234 EMSG2(_(e_listdictarg), "extend()");
3235}
3236
3237/*
3238 * "feedkeys()" function
3239 */
3240 static void
3241f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3242{
3243 int remap = TRUE;
3244 int insert = FALSE;
3245 char_u *keys, *flags;
3246 char_u nbuf[NUMBUFLEN];
3247 int typed = FALSE;
3248 int execute = FALSE;
3249 int dangerous = FALSE;
3250 char_u *keys_esc;
3251
3252 /* This is not allowed in the sandbox. If the commands would still be
3253 * executed in the sandbox it would be OK, but it probably happens later,
3254 * when "sandbox" is no longer set. */
3255 if (check_secure())
3256 return;
3257
3258 keys = get_tv_string(&argvars[0]);
3259
3260 if (argvars[1].v_type != VAR_UNKNOWN)
3261 {
3262 flags = get_tv_string_buf(&argvars[1], nbuf);
3263 for ( ; *flags != NUL; ++flags)
3264 {
3265 switch (*flags)
3266 {
3267 case 'n': remap = FALSE; break;
3268 case 'm': remap = TRUE; break;
3269 case 't': typed = TRUE; break;
3270 case 'i': insert = TRUE; break;
3271 case 'x': execute = TRUE; break;
3272 case '!': dangerous = TRUE; break;
3273 }
3274 }
3275 }
3276
3277 if (*keys != NUL || execute)
3278 {
3279 /* Need to escape K_SPECIAL and CSI before putting the string in the
3280 * typeahead buffer. */
3281 keys_esc = vim_strsave_escape_csi(keys);
3282 if (keys_esc != NULL)
3283 {
3284 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3285 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3286 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003287 if (vgetc_busy
3288#ifdef FEAT_TIMERS
3289 || timer_busy
3290#endif
3291 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292 typebuf_was_filled = TRUE;
3293 if (execute)
3294 {
3295 int save_msg_scroll = msg_scroll;
3296
3297 /* Avoid a 1 second delay when the keys start Insert mode. */
3298 msg_scroll = FALSE;
3299
Bram Moolenaar69fbc9e2017-09-14 20:37:57 +02003300#ifdef FEAT_TERMINAL
3301 if (term_use_loop())
3302 terminal_loop(FALSE);
3303 else
3304#endif
3305 {
3306 if (!dangerous)
3307 ++ex_normal_busy;
3308 exec_normal(TRUE);
3309 if (!dangerous)
3310 --ex_normal_busy;
3311 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312 msg_scroll |= save_msg_scroll;
3313 }
3314 }
3315 }
3316}
3317
3318/*
3319 * "filereadable()" function
3320 */
3321 static void
3322f_filereadable(typval_T *argvars, typval_T *rettv)
3323{
3324 int fd;
3325 char_u *p;
3326 int n;
3327
3328#ifndef O_NONBLOCK
3329# define O_NONBLOCK 0
3330#endif
3331 p = get_tv_string(&argvars[0]);
3332 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3333 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3334 {
3335 n = TRUE;
3336 close(fd);
3337 }
3338 else
3339 n = FALSE;
3340
3341 rettv->vval.v_number = n;
3342}
3343
3344/*
3345 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3346 * rights to write into.
3347 */
3348 static void
3349f_filewritable(typval_T *argvars, typval_T *rettv)
3350{
3351 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3352}
3353
3354 static void
3355findfilendir(
3356 typval_T *argvars UNUSED,
3357 typval_T *rettv,
3358 int find_what UNUSED)
3359{
3360#ifdef FEAT_SEARCHPATH
3361 char_u *fname;
3362 char_u *fresult = NULL;
3363 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3364 char_u *p;
3365 char_u pathbuf[NUMBUFLEN];
3366 int count = 1;
3367 int first = TRUE;
3368 int error = FALSE;
3369#endif
3370
3371 rettv->vval.v_string = NULL;
3372 rettv->v_type = VAR_STRING;
3373
3374#ifdef FEAT_SEARCHPATH
3375 fname = get_tv_string(&argvars[0]);
3376
3377 if (argvars[1].v_type != VAR_UNKNOWN)
3378 {
3379 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3380 if (p == NULL)
3381 error = TRUE;
3382 else
3383 {
3384 if (*p != NUL)
3385 path = p;
3386
3387 if (argvars[2].v_type != VAR_UNKNOWN)
3388 count = (int)get_tv_number_chk(&argvars[2], &error);
3389 }
3390 }
3391
3392 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3393 error = TRUE;
3394
3395 if (*fname != NUL && !error)
3396 {
3397 do
3398 {
3399 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3400 vim_free(fresult);
3401 fresult = find_file_in_path_option(first ? fname : NULL,
3402 first ? (int)STRLEN(fname) : 0,
3403 0, first, path,
3404 find_what,
3405 curbuf->b_ffname,
3406 find_what == FINDFILE_DIR
3407 ? (char_u *)"" : curbuf->b_p_sua);
3408 first = FALSE;
3409
3410 if (fresult != NULL && rettv->v_type == VAR_LIST)
3411 list_append_string(rettv->vval.v_list, fresult, -1);
3412
3413 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3414 }
3415
3416 if (rettv->v_type == VAR_STRING)
3417 rettv->vval.v_string = fresult;
3418#endif
3419}
3420
3421/*
3422 * "filter()" function
3423 */
3424 static void
3425f_filter(typval_T *argvars, typval_T *rettv)
3426{
3427 filter_map(argvars, rettv, FALSE);
3428}
3429
3430/*
3431 * "finddir({fname}[, {path}[, {count}]])" function
3432 */
3433 static void
3434f_finddir(typval_T *argvars, typval_T *rettv)
3435{
3436 findfilendir(argvars, rettv, FINDFILE_DIR);
3437}
3438
3439/*
3440 * "findfile({fname}[, {path}[, {count}]])" function
3441 */
3442 static void
3443f_findfile(typval_T *argvars, typval_T *rettv)
3444{
3445 findfilendir(argvars, rettv, FINDFILE_FILE);
3446}
3447
3448#ifdef FEAT_FLOAT
3449/*
3450 * "float2nr({float})" function
3451 */
3452 static void
3453f_float2nr(typval_T *argvars, typval_T *rettv)
3454{
3455 float_T f = 0.0;
3456
3457 if (get_float_arg(argvars, &f) == OK)
3458 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003459 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003460 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003461 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003462 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003463 else
3464 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003465 }
3466}
3467
3468/*
3469 * "floor({float})" function
3470 */
3471 static void
3472f_floor(typval_T *argvars, typval_T *rettv)
3473{
3474 float_T f = 0.0;
3475
3476 rettv->v_type = VAR_FLOAT;
3477 if (get_float_arg(argvars, &f) == OK)
3478 rettv->vval.v_float = floor(f);
3479 else
3480 rettv->vval.v_float = 0.0;
3481}
3482
3483/*
3484 * "fmod()" function
3485 */
3486 static void
3487f_fmod(typval_T *argvars, typval_T *rettv)
3488{
3489 float_T fx = 0.0, fy = 0.0;
3490
3491 rettv->v_type = VAR_FLOAT;
3492 if (get_float_arg(argvars, &fx) == OK
3493 && get_float_arg(&argvars[1], &fy) == OK)
3494 rettv->vval.v_float = fmod(fx, fy);
3495 else
3496 rettv->vval.v_float = 0.0;
3497}
3498#endif
3499
3500/*
3501 * "fnameescape({string})" function
3502 */
3503 static void
3504f_fnameescape(typval_T *argvars, typval_T *rettv)
3505{
3506 rettv->vval.v_string = vim_strsave_fnameescape(
3507 get_tv_string(&argvars[0]), FALSE);
3508 rettv->v_type = VAR_STRING;
3509}
3510
3511/*
3512 * "fnamemodify({fname}, {mods})" function
3513 */
3514 static void
3515f_fnamemodify(typval_T *argvars, typval_T *rettv)
3516{
3517 char_u *fname;
3518 char_u *mods;
3519 int usedlen = 0;
3520 int len;
3521 char_u *fbuf = NULL;
3522 char_u buf[NUMBUFLEN];
3523
3524 fname = get_tv_string_chk(&argvars[0]);
3525 mods = get_tv_string_buf_chk(&argvars[1], buf);
3526 if (fname == NULL || mods == NULL)
3527 fname = NULL;
3528 else
3529 {
3530 len = (int)STRLEN(fname);
3531 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3532 }
3533
3534 rettv->v_type = VAR_STRING;
3535 if (fname == NULL)
3536 rettv->vval.v_string = NULL;
3537 else
3538 rettv->vval.v_string = vim_strnsave(fname, len);
3539 vim_free(fbuf);
3540}
3541
3542static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3543
3544/*
3545 * "foldclosed()" function
3546 */
3547 static void
3548foldclosed_both(
3549 typval_T *argvars UNUSED,
3550 typval_T *rettv,
3551 int end UNUSED)
3552{
3553#ifdef FEAT_FOLDING
3554 linenr_T lnum;
3555 linenr_T first, last;
3556
3557 lnum = get_tv_lnum(argvars);
3558 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3559 {
3560 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3561 {
3562 if (end)
3563 rettv->vval.v_number = (varnumber_T)last;
3564 else
3565 rettv->vval.v_number = (varnumber_T)first;
3566 return;
3567 }
3568 }
3569#endif
3570 rettv->vval.v_number = -1;
3571}
3572
3573/*
3574 * "foldclosed()" function
3575 */
3576 static void
3577f_foldclosed(typval_T *argvars, typval_T *rettv)
3578{
3579 foldclosed_both(argvars, rettv, FALSE);
3580}
3581
3582/*
3583 * "foldclosedend()" function
3584 */
3585 static void
3586f_foldclosedend(typval_T *argvars, typval_T *rettv)
3587{
3588 foldclosed_both(argvars, rettv, TRUE);
3589}
3590
3591/*
3592 * "foldlevel()" function
3593 */
3594 static void
3595f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3596{
3597#ifdef FEAT_FOLDING
3598 linenr_T lnum;
3599
3600 lnum = get_tv_lnum(argvars);
3601 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3602 rettv->vval.v_number = foldLevel(lnum);
3603#endif
3604}
3605
3606/*
3607 * "foldtext()" function
3608 */
3609 static void
3610f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3611{
3612#ifdef FEAT_FOLDING
3613 linenr_T foldstart;
3614 linenr_T foldend;
3615 char_u *dashes;
3616 linenr_T lnum;
3617 char_u *s;
3618 char_u *r;
3619 int len;
3620 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003621 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003622#endif
3623
3624 rettv->v_type = VAR_STRING;
3625 rettv->vval.v_string = NULL;
3626#ifdef FEAT_FOLDING
3627 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3628 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3629 dashes = get_vim_var_str(VV_FOLDDASHES);
3630 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3631 && dashes != NULL)
3632 {
3633 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003634 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635 if (!linewhite(lnum))
3636 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637
3638 /* Find interesting text in this line. */
3639 s = skipwhite(ml_get(lnum));
3640 /* skip C comment-start */
3641 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3642 {
3643 s = skipwhite(s + 2);
3644 if (*skipwhite(s) == NUL
3645 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3646 {
3647 s = skipwhite(ml_get(lnum + 1));
3648 if (*s == '*')
3649 s = skipwhite(s + 1);
3650 }
3651 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003652 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003653 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 r = alloc((unsigned)(STRLEN(txt)
3655 + STRLEN(dashes) /* for %s */
3656 + 20 /* for %3ld */
3657 + STRLEN(s))); /* concatenated */
3658 if (r != NULL)
3659 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003660 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661 len = (int)STRLEN(r);
3662 STRCAT(r, s);
3663 /* remove 'foldmarker' and 'commentstring' */
3664 foldtext_cleanup(r + len);
3665 rettv->vval.v_string = r;
3666 }
3667 }
3668#endif
3669}
3670
3671/*
3672 * "foldtextresult(lnum)" function
3673 */
3674 static void
3675f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3676{
3677#ifdef FEAT_FOLDING
3678 linenr_T lnum;
3679 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003680 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681 foldinfo_T foldinfo;
3682 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003683 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003684#endif
3685
3686 rettv->v_type = VAR_STRING;
3687 rettv->vval.v_string = NULL;
3688#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003689 if (entered)
3690 return; /* reject recursive use */
3691 entered = TRUE;
3692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003693 lnum = get_tv_lnum(argvars);
3694 /* treat illegal types and illegal string values for {lnum} the same */
3695 if (lnum < 0)
3696 lnum = 0;
3697 fold_count = foldedCount(curwin, lnum, &foldinfo);
3698 if (fold_count > 0)
3699 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003700 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3701 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003702 if (text == buf)
3703 text = vim_strsave(text);
3704 rettv->vval.v_string = text;
3705 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003706
3707 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003708#endif
3709}
3710
3711/*
3712 * "foreground()" function
3713 */
3714 static void
3715f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3716{
3717#ifdef FEAT_GUI
3718 if (gui.in_use)
3719 gui_mch_set_foreground();
3720#else
3721# ifdef WIN32
3722 win32_set_foreground();
3723# endif
3724#endif
3725}
3726
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003728common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003729{
3730 char_u *s;
3731 char_u *name;
3732 int use_string = FALSE;
3733 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003734 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735
3736 if (argvars[0].v_type == VAR_FUNC)
3737 {
3738 /* function(MyFunc, [arg], dict) */
3739 s = argvars[0].vval.v_string;
3740 }
3741 else if (argvars[0].v_type == VAR_PARTIAL
3742 && argvars[0].vval.v_partial != NULL)
3743 {
3744 /* function(dict.MyFunc, [arg]) */
3745 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003746 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747 }
3748 else
3749 {
3750 /* function('MyFunc', [arg], dict) */
3751 s = get_tv_string(&argvars[0]);
3752 use_string = TRUE;
3753 }
3754
Bram Moolenaar843b8842016-08-21 14:36:15 +02003755 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003756 {
3757 name = s;
3758 trans_name = trans_function_name(&name, FALSE,
3759 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3760 if (*name != NUL)
3761 s = NULL;
3762 }
3763
Bram Moolenaar843b8842016-08-21 14:36:15 +02003764 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3765 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003766 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003768 else if (trans_name != NULL && (is_funcref
3769 ? find_func(trans_name) == NULL
3770 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003771 EMSG2(_("E700: Unknown function: %s"), s);
3772 else
3773 {
3774 int dict_idx = 0;
3775 int arg_idx = 0;
3776 list_T *list = NULL;
3777
3778 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3779 {
3780 char sid_buf[25];
3781 int off = *s == 's' ? 2 : 5;
3782
3783 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3784 * also be called from another script. Using trans_function_name()
3785 * would also work, but some plugins depend on the name being
3786 * printable text. */
3787 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3788 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3789 if (name != NULL)
3790 {
3791 STRCPY(name, sid_buf);
3792 STRCAT(name, s + off);
3793 }
3794 }
3795 else
3796 name = vim_strsave(s);
3797
3798 if (argvars[1].v_type != VAR_UNKNOWN)
3799 {
3800 if (argvars[2].v_type != VAR_UNKNOWN)
3801 {
3802 /* function(name, [args], dict) */
3803 arg_idx = 1;
3804 dict_idx = 2;
3805 }
3806 else if (argvars[1].v_type == VAR_DICT)
3807 /* function(name, dict) */
3808 dict_idx = 1;
3809 else
3810 /* function(name, [args]) */
3811 arg_idx = 1;
3812 if (dict_idx > 0)
3813 {
3814 if (argvars[dict_idx].v_type != VAR_DICT)
3815 {
3816 EMSG(_("E922: expected a dict"));
3817 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003818 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003819 }
3820 if (argvars[dict_idx].vval.v_dict == NULL)
3821 dict_idx = 0;
3822 }
3823 if (arg_idx > 0)
3824 {
3825 if (argvars[arg_idx].v_type != VAR_LIST)
3826 {
3827 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3828 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003829 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003830 }
3831 list = argvars[arg_idx].vval.v_list;
3832 if (list == NULL || list->lv_len == 0)
3833 arg_idx = 0;
3834 }
3835 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003836 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003837 {
3838 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3839
3840 /* result is a VAR_PARTIAL */
3841 if (pt == NULL)
3842 vim_free(name);
3843 else
3844 {
3845 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3846 {
3847 listitem_T *li;
3848 int i = 0;
3849 int arg_len = 0;
3850 int lv_len = 0;
3851
3852 if (arg_pt != NULL)
3853 arg_len = arg_pt->pt_argc;
3854 if (list != NULL)
3855 lv_len = list->lv_len;
3856 pt->pt_argc = arg_len + lv_len;
3857 pt->pt_argv = (typval_T *)alloc(
3858 sizeof(typval_T) * pt->pt_argc);
3859 if (pt->pt_argv == NULL)
3860 {
3861 vim_free(pt);
3862 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003863 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003865 for (i = 0; i < arg_len; i++)
3866 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3867 if (lv_len > 0)
3868 for (li = list->lv_first; li != NULL;
3869 li = li->li_next)
3870 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871 }
3872
3873 /* For "function(dict.func, [], dict)" and "func" is a partial
3874 * use "dict". That is backwards compatible. */
3875 if (dict_idx > 0)
3876 {
3877 /* The dict is bound explicitly, pt_auto is FALSE. */
3878 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3879 ++pt->pt_dict->dv_refcount;
3880 }
3881 else if (arg_pt != NULL)
3882 {
3883 /* If the dict was bound automatically the result is also
3884 * bound automatically. */
3885 pt->pt_dict = arg_pt->pt_dict;
3886 pt->pt_auto = arg_pt->pt_auto;
3887 if (pt->pt_dict != NULL)
3888 ++pt->pt_dict->dv_refcount;
3889 }
3890
3891 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003892 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3893 {
3894 pt->pt_func = arg_pt->pt_func;
3895 func_ptr_ref(pt->pt_func);
3896 vim_free(name);
3897 }
3898 else if (is_funcref)
3899 {
3900 pt->pt_func = find_func(trans_name);
3901 func_ptr_ref(pt->pt_func);
3902 vim_free(name);
3903 }
3904 else
3905 {
3906 pt->pt_name = name;
3907 func_ref(name);
3908 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 }
3910 rettv->v_type = VAR_PARTIAL;
3911 rettv->vval.v_partial = pt;
3912 }
3913 else
3914 {
3915 /* result is a VAR_FUNC */
3916 rettv->v_type = VAR_FUNC;
3917 rettv->vval.v_string = name;
3918 func_ref(name);
3919 }
3920 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003921theend:
3922 vim_free(trans_name);
3923}
3924
3925/*
3926 * "funcref()" function
3927 */
3928 static void
3929f_funcref(typval_T *argvars, typval_T *rettv)
3930{
3931 common_function(argvars, rettv, TRUE);
3932}
3933
3934/*
3935 * "function()" function
3936 */
3937 static void
3938f_function(typval_T *argvars, typval_T *rettv)
3939{
3940 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941}
3942
3943/*
3944 * "garbagecollect()" function
3945 */
3946 static void
3947f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3948{
3949 /* This is postponed until we are back at the toplevel, because we may be
3950 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3951 want_garbage_collect = TRUE;
3952
3953 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3954 garbage_collect_at_exit = TRUE;
3955}
3956
3957/*
3958 * "get()" function
3959 */
3960 static void
3961f_get(typval_T *argvars, typval_T *rettv)
3962{
3963 listitem_T *li;
3964 list_T *l;
3965 dictitem_T *di;
3966 dict_T *d;
3967 typval_T *tv = NULL;
3968
3969 if (argvars[0].v_type == VAR_LIST)
3970 {
3971 if ((l = argvars[0].vval.v_list) != NULL)
3972 {
3973 int error = FALSE;
3974
3975 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3976 if (!error && li != NULL)
3977 tv = &li->li_tv;
3978 }
3979 }
3980 else if (argvars[0].v_type == VAR_DICT)
3981 {
3982 if ((d = argvars[0].vval.v_dict) != NULL)
3983 {
3984 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3985 if (di != NULL)
3986 tv = &di->di_tv;
3987 }
3988 }
3989 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3990 {
3991 partial_T *pt;
3992 partial_T fref_pt;
3993
3994 if (argvars[0].v_type == VAR_PARTIAL)
3995 pt = argvars[0].vval.v_partial;
3996 else
3997 {
3998 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3999 fref_pt.pt_name = argvars[0].vval.v_string;
4000 pt = &fref_pt;
4001 }
4002
4003 if (pt != NULL)
4004 {
4005 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004006 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007
4008 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4009 {
4010 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004011 n = partial_name(pt);
4012 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 rettv->vval.v_string = NULL;
4014 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004015 {
4016 rettv->vval.v_string = vim_strsave(n);
4017 if (rettv->v_type == VAR_FUNC)
4018 func_ref(rettv->vval.v_string);
4019 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 }
4021 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004022 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023 else if (STRCMP(what, "args") == 0)
4024 {
4025 rettv->v_type = VAR_LIST;
4026 if (rettv_list_alloc(rettv) == OK)
4027 {
4028 int i;
4029
4030 for (i = 0; i < pt->pt_argc; ++i)
4031 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4032 }
4033 }
4034 else
4035 EMSG2(_(e_invarg2), what);
4036 return;
4037 }
4038 }
4039 else
4040 EMSG2(_(e_listdictarg), "get()");
4041
4042 if (tv == NULL)
4043 {
4044 if (argvars[2].v_type != VAR_UNKNOWN)
4045 copy_tv(&argvars[2], rettv);
4046 }
4047 else
4048 copy_tv(tv, rettv);
4049}
4050
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004051#ifdef FEAT_SIGNS
4052/*
4053 * Returns information about signs placed in a buffer as list of dicts.
4054 */
4055 static void
4056get_buffer_signs(buf_T *buf, list_T *l)
4057{
4058 signlist_T *sign;
4059
4060 for (sign = buf->b_signlist; sign; sign = sign->next)
4061 {
4062 dict_T *d = dict_alloc();
4063
4064 if (d != NULL)
4065 {
4066 dict_add_nr_str(d, "id", sign->id, NULL);
4067 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004068 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004069
4070 list_append_dict(l, d);
4071 }
4072 }
4073}
4074#endif
4075
4076/*
4077 * Returns buffer options, variables and other attributes in a dictionary.
4078 */
4079 static dict_T *
4080get_buffer_info(buf_T *buf)
4081{
4082 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004083 tabpage_T *tp;
4084 win_T *wp;
4085 list_T *windows;
4086
4087 dict = dict_alloc();
4088 if (dict == NULL)
4089 return NULL;
4090
Bram Moolenaar33928832016-08-18 21:22:04 +02004091 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004092 dict_add_nr_str(dict, "name", 0L,
4093 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004094 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4095 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004096 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4097 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4098 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004099 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004100 dict_add_nr_str(dict, "hidden",
4101 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4102 NULL);
4103
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004104 /* Get a reference to buffer variables */
4105 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004106
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004107 /* List of windows displaying this buffer */
4108 windows = list_alloc();
4109 if (windows != NULL)
4110 {
4111 FOR_ALL_TAB_WINDOWS(tp, wp)
4112 if (wp->w_buffer == buf)
4113 list_append_number(windows, (varnumber_T)wp->w_id);
4114 dict_add_list(dict, "windows", windows);
4115 }
4116
4117#ifdef FEAT_SIGNS
4118 if (buf->b_signlist != NULL)
4119 {
4120 /* List of signs placed in this buffer */
4121 list_T *signs = list_alloc();
4122 if (signs != NULL)
4123 {
4124 get_buffer_signs(buf, signs);
4125 dict_add_list(dict, "signs", signs);
4126 }
4127 }
4128#endif
4129
4130 return dict;
4131}
4132
4133/*
4134 * "getbufinfo()" function
4135 */
4136 static void
4137f_getbufinfo(typval_T *argvars, typval_T *rettv)
4138{
4139 buf_T *buf = NULL;
4140 buf_T *argbuf = NULL;
4141 dict_T *d;
4142 int filtered = FALSE;
4143 int sel_buflisted = FALSE;
4144 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004145 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004146
4147 if (rettv_list_alloc(rettv) != OK)
4148 return;
4149
4150 /* List of all the buffers or selected buffers */
4151 if (argvars[0].v_type == VAR_DICT)
4152 {
4153 dict_T *sel_d = argvars[0].vval.v_dict;
4154
4155 if (sel_d != NULL)
4156 {
4157 dictitem_T *di;
4158
4159 filtered = TRUE;
4160
4161 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4162 if (di != NULL && get_tv_number(&di->di_tv))
4163 sel_buflisted = TRUE;
4164
4165 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4166 if (di != NULL && get_tv_number(&di->di_tv))
4167 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004168
4169 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4170 if (di != NULL && get_tv_number(&di->di_tv))
4171 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004172 }
4173 }
4174 else if (argvars[0].v_type != VAR_UNKNOWN)
4175 {
4176 /* Information about one buffer. Argument specifies the buffer */
4177 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4178 ++emsg_off;
4179 argbuf = get_buf_tv(&argvars[0], FALSE);
4180 --emsg_off;
4181 if (argbuf == NULL)
4182 return;
4183 }
4184
4185 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004186 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004187 {
4188 if (argbuf != NULL && argbuf != buf)
4189 continue;
4190 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004191 || (sel_buflisted && !buf->b_p_bl)
4192 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004193 continue;
4194
4195 d = get_buffer_info(buf);
4196 if (d != NULL)
4197 list_append_dict(rettv->vval.v_list, d);
4198 if (argbuf != NULL)
4199 return;
4200 }
4201}
4202
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4204
4205/*
4206 * Get line or list of lines from buffer "buf" into "rettv".
4207 * Return a range (from start to end) of lines in rettv from the specified
4208 * buffer.
4209 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4210 */
4211 static void
4212get_buffer_lines(
4213 buf_T *buf,
4214 linenr_T start,
4215 linenr_T end,
4216 int retlist,
4217 typval_T *rettv)
4218{
4219 char_u *p;
4220
4221 rettv->v_type = VAR_STRING;
4222 rettv->vval.v_string = NULL;
4223 if (retlist && rettv_list_alloc(rettv) == FAIL)
4224 return;
4225
4226 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4227 return;
4228
4229 if (!retlist)
4230 {
4231 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4232 p = ml_get_buf(buf, start, FALSE);
4233 else
4234 p = (char_u *)"";
4235 rettv->vval.v_string = vim_strsave(p);
4236 }
4237 else
4238 {
4239 if (end < start)
4240 return;
4241
4242 if (start < 1)
4243 start = 1;
4244 if (end > buf->b_ml.ml_line_count)
4245 end = buf->b_ml.ml_line_count;
4246 while (start <= end)
4247 if (list_append_string(rettv->vval.v_list,
4248 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4249 break;
4250 }
4251}
4252
4253/*
4254 * Get the lnum from the first argument.
4255 * Also accepts "$", then "buf" is used.
4256 * Returns 0 on error.
4257 */
4258 static linenr_T
4259get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4260{
4261 if (argvars[0].v_type == VAR_STRING
4262 && argvars[0].vval.v_string != NULL
4263 && argvars[0].vval.v_string[0] == '$'
4264 && buf != NULL)
4265 return buf->b_ml.ml_line_count;
4266 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4267}
4268
4269/*
4270 * "getbufline()" function
4271 */
4272 static void
4273f_getbufline(typval_T *argvars, typval_T *rettv)
4274{
4275 linenr_T lnum;
4276 linenr_T end;
4277 buf_T *buf;
4278
4279 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4280 ++emsg_off;
4281 buf = get_buf_tv(&argvars[0], FALSE);
4282 --emsg_off;
4283
4284 lnum = get_tv_lnum_buf(&argvars[1], buf);
4285 if (argvars[2].v_type == VAR_UNKNOWN)
4286 end = lnum;
4287 else
4288 end = get_tv_lnum_buf(&argvars[2], buf);
4289
4290 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4291}
4292
4293/*
4294 * "getbufvar()" function
4295 */
4296 static void
4297f_getbufvar(typval_T *argvars, typval_T *rettv)
4298{
4299 buf_T *buf;
4300 buf_T *save_curbuf;
4301 char_u *varname;
4302 dictitem_T *v;
4303 int done = FALSE;
4304
4305 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4306 varname = get_tv_string_chk(&argvars[1]);
4307 ++emsg_off;
4308 buf = get_buf_tv(&argvars[0], FALSE);
4309
4310 rettv->v_type = VAR_STRING;
4311 rettv->vval.v_string = NULL;
4312
4313 if (buf != NULL && varname != NULL)
4314 {
4315 /* set curbuf to be our buf, temporarily */
4316 save_curbuf = curbuf;
4317 curbuf = buf;
4318
Bram Moolenaar30567352016-08-27 21:25:44 +02004319 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004320 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004321 if (varname[1] == NUL)
4322 {
4323 /* get all buffer-local options in a dict */
4324 dict_T *opts = get_winbuf_options(TRUE);
4325
4326 if (opts != NULL)
4327 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004328 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004329 done = TRUE;
4330 }
4331 }
4332 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4333 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004334 done = TRUE;
4335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004336 else
4337 {
4338 /* Look up the variable. */
4339 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4340 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4341 'b', varname, FALSE);
4342 if (v != NULL)
4343 {
4344 copy_tv(&v->di_tv, rettv);
4345 done = TRUE;
4346 }
4347 }
4348
4349 /* restore previous notion of curbuf */
4350 curbuf = save_curbuf;
4351 }
4352
4353 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4354 /* use the default value */
4355 copy_tv(&argvars[2], rettv);
4356
4357 --emsg_off;
4358}
4359
4360/*
4361 * "getchar()" function
4362 */
4363 static void
4364f_getchar(typval_T *argvars, typval_T *rettv)
4365{
4366 varnumber_T n;
4367 int error = FALSE;
4368
4369 /* Position the cursor. Needed after a message that ends in a space. */
4370 windgoto(msg_row, msg_col);
4371
4372 ++no_mapping;
4373 ++allow_keys;
4374 for (;;)
4375 {
4376 if (argvars[0].v_type == VAR_UNKNOWN)
4377 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004378 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004379 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4380 /* getchar(1): only check if char avail */
4381 n = vpeekc_any();
4382 else if (error || vpeekc_any() == NUL)
4383 /* illegal argument or getchar(0) and no char avail: return zero */
4384 n = 0;
4385 else
4386 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004387 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004388
4389 if (n == K_IGNORE)
4390 continue;
4391 break;
4392 }
4393 --no_mapping;
4394 --allow_keys;
4395
4396 set_vim_var_nr(VV_MOUSE_WIN, 0);
4397 set_vim_var_nr(VV_MOUSE_WINID, 0);
4398 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4399 set_vim_var_nr(VV_MOUSE_COL, 0);
4400
4401 rettv->vval.v_number = n;
4402 if (IS_SPECIAL(n) || mod_mask != 0)
4403 {
4404 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4405 int i = 0;
4406
4407 /* Turn a special key into three bytes, plus modifier. */
4408 if (mod_mask != 0)
4409 {
4410 temp[i++] = K_SPECIAL;
4411 temp[i++] = KS_MODIFIER;
4412 temp[i++] = mod_mask;
4413 }
4414 if (IS_SPECIAL(n))
4415 {
4416 temp[i++] = K_SPECIAL;
4417 temp[i++] = K_SECOND(n);
4418 temp[i++] = K_THIRD(n);
4419 }
4420#ifdef FEAT_MBYTE
4421 else if (has_mbyte)
4422 i += (*mb_char2bytes)(n, temp + i);
4423#endif
4424 else
4425 temp[i++] = n;
4426 temp[i++] = NUL;
4427 rettv->v_type = VAR_STRING;
4428 rettv->vval.v_string = vim_strsave(temp);
4429
4430#ifdef FEAT_MOUSE
4431 if (is_mouse_key(n))
4432 {
4433 int row = mouse_row;
4434 int col = mouse_col;
4435 win_T *win;
4436 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004437 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004438 int winnr = 1;
4439
4440 if (row >= 0 && col >= 0)
4441 {
4442 /* Find the window at the mouse coordinates and compute the
4443 * text position. */
4444 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004445 if (win == NULL)
4446 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004447 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448 for (wp = firstwin; wp != win; wp = wp->w_next)
4449 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004450 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4451 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4452 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4453 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4454 }
4455 }
4456#endif
4457 }
4458}
4459
4460/*
4461 * "getcharmod()" function
4462 */
4463 static void
4464f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4465{
4466 rettv->vval.v_number = mod_mask;
4467}
4468
4469/*
4470 * "getcharsearch()" function
4471 */
4472 static void
4473f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4474{
4475 if (rettv_dict_alloc(rettv) != FAIL)
4476 {
4477 dict_T *dict = rettv->vval.v_dict;
4478
4479 dict_add_nr_str(dict, "char", 0L, last_csearch());
4480 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4481 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4482 }
4483}
4484
4485/*
4486 * "getcmdline()" function
4487 */
4488 static void
4489f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4490{
4491 rettv->v_type = VAR_STRING;
4492 rettv->vval.v_string = get_cmdline_str();
4493}
4494
4495/*
4496 * "getcmdpos()" function
4497 */
4498 static void
4499f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4500{
4501 rettv->vval.v_number = get_cmdline_pos() + 1;
4502}
4503
4504/*
4505 * "getcmdtype()" function
4506 */
4507 static void
4508f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4509{
4510 rettv->v_type = VAR_STRING;
4511 rettv->vval.v_string = alloc(2);
4512 if (rettv->vval.v_string != NULL)
4513 {
4514 rettv->vval.v_string[0] = get_cmdline_type();
4515 rettv->vval.v_string[1] = NUL;
4516 }
4517}
4518
4519/*
4520 * "getcmdwintype()" function
4521 */
4522 static void
4523f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4524{
4525 rettv->v_type = VAR_STRING;
4526 rettv->vval.v_string = NULL;
4527#ifdef FEAT_CMDWIN
4528 rettv->vval.v_string = alloc(2);
4529 if (rettv->vval.v_string != NULL)
4530 {
4531 rettv->vval.v_string[0] = cmdwin_type;
4532 rettv->vval.v_string[1] = NUL;
4533 }
4534#endif
4535}
4536
4537#if defined(FEAT_CMDL_COMPL)
4538/*
4539 * "getcompletion()" function
4540 */
4541 static void
4542f_getcompletion(typval_T *argvars, typval_T *rettv)
4543{
4544 char_u *pat;
4545 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004546 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004547 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4548 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004550 if (argvars[2].v_type != VAR_UNKNOWN)
4551 filtered = get_tv_number_chk(&argvars[2], NULL);
4552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004553 if (p_wic)
4554 options |= WILD_ICASE;
4555
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004556 /* For filtered results, 'wildignore' is used */
4557 if (!filtered)
4558 options |= WILD_KEEP_ALL;
4559
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560 ExpandInit(&xpc);
4561 xpc.xp_pattern = get_tv_string(&argvars[0]);
4562 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4563 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4564 if (xpc.xp_context == EXPAND_NOTHING)
4565 {
4566 if (argvars[1].v_type == VAR_STRING)
4567 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4568 else
4569 EMSG(_(e_invarg));
4570 return;
4571 }
4572
4573# if defined(FEAT_MENU)
4574 if (xpc.xp_context == EXPAND_MENUS)
4575 {
4576 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4577 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4578 }
4579# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004580#ifdef FEAT_CSCOPE
4581 if (xpc.xp_context == EXPAND_CSCOPE)
4582 {
4583 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4584 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4585 }
4586#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004587#ifdef FEAT_SIGNS
4588 if (xpc.xp_context == EXPAND_SIGN)
4589 {
4590 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4591 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4592 }
4593#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594
4595 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4596 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4597 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004598 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004599
4600 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4601
4602 for (i = 0; i < xpc.xp_numfiles; i++)
4603 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4604 }
4605 vim_free(pat);
4606 ExpandCleanup(&xpc);
4607}
4608#endif
4609
4610/*
4611 * "getcwd()" function
4612 */
4613 static void
4614f_getcwd(typval_T *argvars, typval_T *rettv)
4615{
4616 win_T *wp = NULL;
4617 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004618 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004619
4620 rettv->v_type = VAR_STRING;
4621 rettv->vval.v_string = NULL;
4622
Bram Moolenaar54591292018-02-09 20:53:59 +01004623 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4624 global = TRUE;
4625 else
4626 wp = find_tabwin(&argvars[0], &argvars[1]);
4627
4628 if (wp != NULL && wp->w_localdir != NULL)
4629 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4630 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004631 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004632 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004633 rettv->vval.v_string = vim_strsave(globaldir);
4634 else
4635 {
4636 cwd = alloc(MAXPATHL);
4637 if (cwd != NULL)
4638 {
4639 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4640 rettv->vval.v_string = vim_strsave(cwd);
4641 vim_free(cwd);
4642 }
4643 }
4644#ifdef BACKSLASH_IN_FILENAME
4645 if (rettv->vval.v_string != NULL)
4646 slash_adjust(rettv->vval.v_string);
4647#endif
4648 }
4649}
4650
4651/*
4652 * "getfontname()" function
4653 */
4654 static void
4655f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4656{
4657 rettv->v_type = VAR_STRING;
4658 rettv->vval.v_string = NULL;
4659#ifdef FEAT_GUI
4660 if (gui.in_use)
4661 {
4662 GuiFont font;
4663 char_u *name = NULL;
4664
4665 if (argvars[0].v_type == VAR_UNKNOWN)
4666 {
4667 /* Get the "Normal" font. Either the name saved by
4668 * hl_set_font_name() or from the font ID. */
4669 font = gui.norm_font;
4670 name = hl_get_font_name();
4671 }
4672 else
4673 {
4674 name = get_tv_string(&argvars[0]);
4675 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4676 return;
4677 font = gui_mch_get_font(name, FALSE);
4678 if (font == NOFONT)
4679 return; /* Invalid font name, return empty string. */
4680 }
4681 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4682 if (argvars[0].v_type != VAR_UNKNOWN)
4683 gui_mch_free_font(font);
4684 }
4685#endif
4686}
4687
4688/*
4689 * "getfperm({fname})" function
4690 */
4691 static void
4692f_getfperm(typval_T *argvars, typval_T *rettv)
4693{
4694 char_u *fname;
4695 stat_T st;
4696 char_u *perm = NULL;
4697 char_u flags[] = "rwx";
4698 int i;
4699
4700 fname = get_tv_string(&argvars[0]);
4701
4702 rettv->v_type = VAR_STRING;
4703 if (mch_stat((char *)fname, &st) >= 0)
4704 {
4705 perm = vim_strsave((char_u *)"---------");
4706 if (perm != NULL)
4707 {
4708 for (i = 0; i < 9; i++)
4709 {
4710 if (st.st_mode & (1 << (8 - i)))
4711 perm[i] = flags[i % 3];
4712 }
4713 }
4714 }
4715 rettv->vval.v_string = perm;
4716}
4717
4718/*
4719 * "getfsize({fname})" function
4720 */
4721 static void
4722f_getfsize(typval_T *argvars, typval_T *rettv)
4723{
4724 char_u *fname;
4725 stat_T st;
4726
4727 fname = get_tv_string(&argvars[0]);
4728
4729 rettv->v_type = VAR_NUMBER;
4730
4731 if (mch_stat((char *)fname, &st) >= 0)
4732 {
4733 if (mch_isdir(fname))
4734 rettv->vval.v_number = 0;
4735 else
4736 {
4737 rettv->vval.v_number = (varnumber_T)st.st_size;
4738
4739 /* non-perfect check for overflow */
4740 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4741 rettv->vval.v_number = -2;
4742 }
4743 }
4744 else
4745 rettv->vval.v_number = -1;
4746}
4747
4748/*
4749 * "getftime({fname})" function
4750 */
4751 static void
4752f_getftime(typval_T *argvars, typval_T *rettv)
4753{
4754 char_u *fname;
4755 stat_T st;
4756
4757 fname = get_tv_string(&argvars[0]);
4758
4759 if (mch_stat((char *)fname, &st) >= 0)
4760 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4761 else
4762 rettv->vval.v_number = -1;
4763}
4764
4765/*
4766 * "getftype({fname})" function
4767 */
4768 static void
4769f_getftype(typval_T *argvars, typval_T *rettv)
4770{
4771 char_u *fname;
4772 stat_T st;
4773 char_u *type = NULL;
4774 char *t;
4775
4776 fname = get_tv_string(&argvars[0]);
4777
4778 rettv->v_type = VAR_STRING;
4779 if (mch_lstat((char *)fname, &st) >= 0)
4780 {
4781#ifdef S_ISREG
4782 if (S_ISREG(st.st_mode))
4783 t = "file";
4784 else if (S_ISDIR(st.st_mode))
4785 t = "dir";
4786# ifdef S_ISLNK
4787 else if (S_ISLNK(st.st_mode))
4788 t = "link";
4789# endif
4790# ifdef S_ISBLK
4791 else if (S_ISBLK(st.st_mode))
4792 t = "bdev";
4793# endif
4794# ifdef S_ISCHR
4795 else if (S_ISCHR(st.st_mode))
4796 t = "cdev";
4797# endif
4798# ifdef S_ISFIFO
4799 else if (S_ISFIFO(st.st_mode))
4800 t = "fifo";
4801# endif
4802# ifdef S_ISSOCK
4803 else if (S_ISSOCK(st.st_mode))
4804 t = "fifo";
4805# endif
4806 else
4807 t = "other";
4808#else
4809# ifdef S_IFMT
4810 switch (st.st_mode & S_IFMT)
4811 {
4812 case S_IFREG: t = "file"; break;
4813 case S_IFDIR: t = "dir"; break;
4814# ifdef S_IFLNK
4815 case S_IFLNK: t = "link"; break;
4816# endif
4817# ifdef S_IFBLK
4818 case S_IFBLK: t = "bdev"; break;
4819# endif
4820# ifdef S_IFCHR
4821 case S_IFCHR: t = "cdev"; break;
4822# endif
4823# ifdef S_IFIFO
4824 case S_IFIFO: t = "fifo"; break;
4825# endif
4826# ifdef S_IFSOCK
4827 case S_IFSOCK: t = "socket"; break;
4828# endif
4829 default: t = "other";
4830 }
4831# else
4832 if (mch_isdir(fname))
4833 t = "dir";
4834 else
4835 t = "file";
4836# endif
4837#endif
4838 type = vim_strsave((char_u *)t);
4839 }
4840 rettv->vval.v_string = type;
4841}
4842
4843/*
4844 * "getline(lnum, [end])" function
4845 */
4846 static void
4847f_getline(typval_T *argvars, typval_T *rettv)
4848{
4849 linenr_T lnum;
4850 linenr_T end;
4851 int retlist;
4852
4853 lnum = get_tv_lnum(argvars);
4854 if (argvars[1].v_type == VAR_UNKNOWN)
4855 {
4856 end = 0;
4857 retlist = FALSE;
4858 }
4859 else
4860 {
4861 end = get_tv_lnum(&argvars[1]);
4862 retlist = TRUE;
4863 }
4864
4865 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4866}
4867
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004868#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004869 static void
4870get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4871{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004872 if (what_arg->v_type == VAR_UNKNOWN)
4873 {
4874 if (rettv_list_alloc(rettv) == OK)
4875 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004876 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004877 }
4878 else
4879 {
4880 if (rettv_dict_alloc(rettv) == OK)
4881 if (is_qf || (wp != NULL))
4882 {
4883 if (what_arg->v_type == VAR_DICT)
4884 {
4885 dict_T *d = what_arg->vval.v_dict;
4886
4887 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02004888 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004889 }
4890 else
4891 EMSG(_(e_dictreq));
4892 }
4893 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02004894}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004895#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02004896
4897/*
4898 * "getloclist()" function
4899 */
4900 static void
4901f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4902{
4903#ifdef FEAT_QUICKFIX
4904 win_T *wp;
4905
4906 wp = find_win_by_nr(&argvars[0], NULL);
4907 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
4908#endif
4909}
4910
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911/*
4912 * "getmatches()" function
4913 */
4914 static void
4915f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4916{
4917#ifdef FEAT_SEARCH_EXTRA
4918 dict_T *dict;
4919 matchitem_T *cur = curwin->w_match_head;
4920 int i;
4921
4922 if (rettv_list_alloc(rettv) == OK)
4923 {
4924 while (cur != NULL)
4925 {
4926 dict = dict_alloc();
4927 if (dict == NULL)
4928 return;
4929 if (cur->match.regprog == NULL)
4930 {
4931 /* match added with matchaddpos() */
4932 for (i = 0; i < MAXPOSMATCH; ++i)
4933 {
4934 llpos_T *llpos;
4935 char buf[6];
4936 list_T *l;
4937
4938 llpos = &cur->pos.pos[i];
4939 if (llpos->lnum == 0)
4940 break;
4941 l = list_alloc();
4942 if (l == NULL)
4943 break;
4944 list_append_number(l, (varnumber_T)llpos->lnum);
4945 if (llpos->col > 0)
4946 {
4947 list_append_number(l, (varnumber_T)llpos->col);
4948 list_append_number(l, (varnumber_T)llpos->len);
4949 }
4950 sprintf(buf, "pos%d", i + 1);
4951 dict_add_list(dict, buf, l);
4952 }
4953 }
4954 else
4955 {
4956 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
4957 }
4958 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
4959 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
4960 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
4961# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
4962 if (cur->conceal_char)
4963 {
4964 char_u buf[MB_MAXBYTES + 1];
4965
4966 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
4967 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
4968 }
4969# endif
4970 list_append_dict(rettv->vval.v_list, dict);
4971 cur = cur->next;
4972 }
4973 }
4974#endif
4975}
4976
4977/*
4978 * "getpid()" function
4979 */
4980 static void
4981f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4982{
4983 rettv->vval.v_number = mch_get_pid();
4984}
4985
4986 static void
4987getpos_both(
4988 typval_T *argvars,
4989 typval_T *rettv,
4990 int getcurpos)
4991{
4992 pos_T *fp;
4993 list_T *l;
4994 int fnum = -1;
4995
4996 if (rettv_list_alloc(rettv) == OK)
4997 {
4998 l = rettv->vval.v_list;
4999 if (getcurpos)
5000 fp = &curwin->w_cursor;
5001 else
5002 fp = var2fpos(&argvars[0], TRUE, &fnum);
5003 if (fnum != -1)
5004 list_append_number(l, (varnumber_T)fnum);
5005 else
5006 list_append_number(l, (varnumber_T)0);
5007 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5008 : (varnumber_T)0);
5009 list_append_number(l, (fp != NULL)
5010 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5011 : (varnumber_T)0);
5012 list_append_number(l,
5013#ifdef FEAT_VIRTUALEDIT
5014 (fp != NULL) ? (varnumber_T)fp->coladd :
5015#endif
5016 (varnumber_T)0);
5017 if (getcurpos)
5018 {
5019 update_curswant();
5020 list_append_number(l, curwin->w_curswant == MAXCOL ?
5021 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5022 }
5023 }
5024 else
5025 rettv->vval.v_number = FALSE;
5026}
5027
5028
5029/*
5030 * "getcurpos()" function
5031 */
5032 static void
5033f_getcurpos(typval_T *argvars, typval_T *rettv)
5034{
5035 getpos_both(argvars, rettv, TRUE);
5036}
5037
5038/*
5039 * "getpos(string)" function
5040 */
5041 static void
5042f_getpos(typval_T *argvars, typval_T *rettv)
5043{
5044 getpos_both(argvars, rettv, FALSE);
5045}
5046
5047/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005048 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005049 */
5050 static void
5051f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5052{
5053#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005054 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005055#endif
5056}
5057
5058/*
5059 * "getreg()" function
5060 */
5061 static void
5062f_getreg(typval_T *argvars, typval_T *rettv)
5063{
5064 char_u *strregname;
5065 int regname;
5066 int arg2 = FALSE;
5067 int return_list = FALSE;
5068 int error = FALSE;
5069
5070 if (argvars[0].v_type != VAR_UNKNOWN)
5071 {
5072 strregname = get_tv_string_chk(&argvars[0]);
5073 error = strregname == NULL;
5074 if (argvars[1].v_type != VAR_UNKNOWN)
5075 {
5076 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5077 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5078 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5079 }
5080 }
5081 else
5082 strregname = get_vim_var_str(VV_REG);
5083
5084 if (error)
5085 return;
5086
5087 regname = (strregname == NULL ? '"' : *strregname);
5088 if (regname == 0)
5089 regname = '"';
5090
5091 if (return_list)
5092 {
5093 rettv->v_type = VAR_LIST;
5094 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5095 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5096 if (rettv->vval.v_list == NULL)
5097 (void)rettv_list_alloc(rettv);
5098 else
5099 ++rettv->vval.v_list->lv_refcount;
5100 }
5101 else
5102 {
5103 rettv->v_type = VAR_STRING;
5104 rettv->vval.v_string = get_reg_contents(regname,
5105 arg2 ? GREG_EXPR_SRC : 0);
5106 }
5107}
5108
5109/*
5110 * "getregtype()" function
5111 */
5112 static void
5113f_getregtype(typval_T *argvars, typval_T *rettv)
5114{
5115 char_u *strregname;
5116 int regname;
5117 char_u buf[NUMBUFLEN + 2];
5118 long reglen = 0;
5119
5120 if (argvars[0].v_type != VAR_UNKNOWN)
5121 {
5122 strregname = get_tv_string_chk(&argvars[0]);
5123 if (strregname == NULL) /* type error; errmsg already given */
5124 {
5125 rettv->v_type = VAR_STRING;
5126 rettv->vval.v_string = NULL;
5127 return;
5128 }
5129 }
5130 else
5131 /* Default to v:register */
5132 strregname = get_vim_var_str(VV_REG);
5133
5134 regname = (strregname == NULL ? '"' : *strregname);
5135 if (regname == 0)
5136 regname = '"';
5137
5138 buf[0] = NUL;
5139 buf[1] = NUL;
5140 switch (get_reg_type(regname, &reglen))
5141 {
5142 case MLINE: buf[0] = 'V'; break;
5143 case MCHAR: buf[0] = 'v'; break;
5144 case MBLOCK:
5145 buf[0] = Ctrl_V;
5146 sprintf((char *)buf + 1, "%ld", reglen + 1);
5147 break;
5148 }
5149 rettv->v_type = VAR_STRING;
5150 rettv->vval.v_string = vim_strsave(buf);
5151}
5152
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005153/*
5154 * Returns information (variables, options, etc.) about a tab page
5155 * as a dictionary.
5156 */
5157 static dict_T *
5158get_tabpage_info(tabpage_T *tp, int tp_idx)
5159{
5160 win_T *wp;
5161 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005162 list_T *l;
5163
5164 dict = dict_alloc();
5165 if (dict == NULL)
5166 return NULL;
5167
Bram Moolenaar33928832016-08-18 21:22:04 +02005168 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005169
5170 l = list_alloc();
5171 if (l != NULL)
5172 {
5173 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5174 wp; wp = wp->w_next)
5175 list_append_number(l, (varnumber_T)wp->w_id);
5176 dict_add_list(dict, "windows", l);
5177 }
5178
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005179 /* Make a reference to tabpage variables */
5180 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005181
5182 return dict;
5183}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005184
5185/*
5186 * "gettabinfo()" function
5187 */
5188 static void
5189f_gettabinfo(typval_T *argvars, typval_T *rettv)
5190{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005191 tabpage_T *tp, *tparg = NULL;
5192 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005193 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005194
5195 if (rettv_list_alloc(rettv) != OK)
5196 return;
5197
5198 if (argvars[0].v_type != VAR_UNKNOWN)
5199 {
5200 /* Information about one tab page */
5201 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5202 if (tparg == NULL)
5203 return;
5204 }
5205
5206 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005207 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005208 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005209 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005210 if (tparg != NULL && tp != tparg)
5211 continue;
5212 d = get_tabpage_info(tp, tpnr);
5213 if (d != NULL)
5214 list_append_dict(rettv->vval.v_list, d);
5215 if (tparg != NULL)
5216 return;
5217 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005218}
5219
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005220/*
5221 * "gettabvar()" function
5222 */
5223 static void
5224f_gettabvar(typval_T *argvars, typval_T *rettv)
5225{
5226 win_T *oldcurwin;
5227 tabpage_T *tp, *oldtabpage;
5228 dictitem_T *v;
5229 char_u *varname;
5230 int done = FALSE;
5231
5232 rettv->v_type = VAR_STRING;
5233 rettv->vval.v_string = NULL;
5234
5235 varname = get_tv_string_chk(&argvars[1]);
5236 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5237 if (tp != NULL && varname != NULL)
5238 {
5239 /* Set tp to be our tabpage, temporarily. Also set the window to the
5240 * first window in the tabpage, otherwise the window is not valid. */
5241 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005242 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5243 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244 {
5245 /* look up the variable */
5246 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5247 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5248 if (v != NULL)
5249 {
5250 copy_tv(&v->di_tv, rettv);
5251 done = TRUE;
5252 }
5253 }
5254
5255 /* restore previous notion of curwin */
5256 restore_win(oldcurwin, oldtabpage, TRUE);
5257 }
5258
5259 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5260 copy_tv(&argvars[2], rettv);
5261}
5262
5263/*
5264 * "gettabwinvar()" function
5265 */
5266 static void
5267f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5268{
5269 getwinvar(argvars, rettv, 1);
5270}
5271
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005272/*
5273 * Returns information about a window as a dictionary.
5274 */
5275 static dict_T *
5276get_win_info(win_T *wp, short tpnr, short winnr)
5277{
5278 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005279
5280 dict = dict_alloc();
5281 if (dict == NULL)
5282 return NULL;
5283
Bram Moolenaar33928832016-08-18 21:22:04 +02005284 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5285 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005286 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5287 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005288#ifdef FEAT_MENU
5289 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5290#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005291 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005292 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005293
Bram Moolenaar69905d12017-08-13 18:14:47 +02005294#ifdef FEAT_TERMINAL
5295 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5296#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005297#ifdef FEAT_QUICKFIX
5298 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5299 dict_add_nr_str(dict, "loclist",
5300 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5301#endif
5302
Bram Moolenaar30567352016-08-27 21:25:44 +02005303 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005304 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005305
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005306 return dict;
5307}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005308
5309/*
5310 * "getwininfo()" function
5311 */
5312 static void
5313f_getwininfo(typval_T *argvars, typval_T *rettv)
5314{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005315 tabpage_T *tp;
5316 win_T *wp = NULL, *wparg = NULL;
5317 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005318 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005319
5320 if (rettv_list_alloc(rettv) != OK)
5321 return;
5322
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005323 if (argvars[0].v_type != VAR_UNKNOWN)
5324 {
5325 wparg = win_id2wp(argvars);
5326 if (wparg == NULL)
5327 return;
5328 }
5329
5330 /* Collect information about either all the windows across all the tab
5331 * pages or one particular window.
5332 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005333 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005334 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005335 tabnr++;
5336 winnr = 0;
5337 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005338 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005339 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005340 if (wparg != NULL && wp != wparg)
5341 continue;
5342 d = get_win_info(wp, tabnr, winnr);
5343 if (d != NULL)
5344 list_append_dict(rettv->vval.v_list, d);
5345 if (wparg != NULL)
5346 /* found information about a specific window */
5347 return;
5348 }
5349 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005350}
5351
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005352/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005353 * "win_findbuf()" function
5354 */
5355 static void
5356f_win_findbuf(typval_T *argvars, typval_T *rettv)
5357{
5358 if (rettv_list_alloc(rettv) != FAIL)
5359 win_findbuf(argvars, rettv->vval.v_list);
5360}
5361
5362/*
5363 * "win_getid()" function
5364 */
5365 static void
5366f_win_getid(typval_T *argvars, typval_T *rettv)
5367{
5368 rettv->vval.v_number = win_getid(argvars);
5369}
5370
5371/*
5372 * "win_gotoid()" function
5373 */
5374 static void
5375f_win_gotoid(typval_T *argvars, typval_T *rettv)
5376{
5377 rettv->vval.v_number = win_gotoid(argvars);
5378}
5379
5380/*
5381 * "win_id2tabwin()" function
5382 */
5383 static void
5384f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5385{
5386 if (rettv_list_alloc(rettv) != FAIL)
5387 win_id2tabwin(argvars, rettv->vval.v_list);
5388}
5389
5390/*
5391 * "win_id2win()" function
5392 */
5393 static void
5394f_win_id2win(typval_T *argvars, typval_T *rettv)
5395{
5396 rettv->vval.v_number = win_id2win(argvars);
5397}
5398
5399/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005400 * "win_screenpos()" function
5401 */
5402 static void
5403f_win_screenpos(typval_T *argvars, typval_T *rettv)
5404{
5405 win_T *wp;
5406
5407 if (rettv_list_alloc(rettv) == FAIL)
5408 return;
5409
5410 wp = find_win_by_nr(&argvars[0], NULL);
5411 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5412 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5413}
5414
5415/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005416 * "getwinposx()" function
5417 */
5418 static void
5419f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5420{
5421 rettv->vval.v_number = -1;
5422#ifdef FEAT_GUI
5423 if (gui.in_use)
5424 {
5425 int x, y;
5426
5427 if (gui_mch_get_winpos(&x, &y) == OK)
5428 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005429 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005430 }
5431#endif
5432#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5433 {
5434 int x, y;
5435
5436 if (term_get_winpos(&x, &y) == OK)
5437 rettv->vval.v_number = x;
5438 }
5439#endif
5440}
5441
5442/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005443 * "getwinposy()" function
5444 */
5445 static void
5446f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5447{
5448 rettv->vval.v_number = -1;
5449#ifdef FEAT_GUI
5450 if (gui.in_use)
5451 {
5452 int x, y;
5453
5454 if (gui_mch_get_winpos(&x, &y) == OK)
5455 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005456 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457 }
5458#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005459#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5460 {
5461 int x, y;
5462
5463 if (term_get_winpos(&x, &y) == OK)
5464 rettv->vval.v_number = y;
5465 }
5466#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005467}
5468
5469/*
5470 * "getwinvar()" function
5471 */
5472 static void
5473f_getwinvar(typval_T *argvars, typval_T *rettv)
5474{
5475 getwinvar(argvars, rettv, 0);
5476}
5477
5478/*
5479 * "glob()" function
5480 */
5481 static void
5482f_glob(typval_T *argvars, typval_T *rettv)
5483{
5484 int options = WILD_SILENT|WILD_USE_NL;
5485 expand_T xpc;
5486 int error = FALSE;
5487
5488 /* When the optional second argument is non-zero, don't remove matches
5489 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5490 rettv->v_type = VAR_STRING;
5491 if (argvars[1].v_type != VAR_UNKNOWN)
5492 {
5493 if (get_tv_number_chk(&argvars[1], &error))
5494 options |= WILD_KEEP_ALL;
5495 if (argvars[2].v_type != VAR_UNKNOWN)
5496 {
5497 if (get_tv_number_chk(&argvars[2], &error))
5498 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005499 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005500 }
5501 if (argvars[3].v_type != VAR_UNKNOWN
5502 && get_tv_number_chk(&argvars[3], &error))
5503 options |= WILD_ALLLINKS;
5504 }
5505 }
5506 if (!error)
5507 {
5508 ExpandInit(&xpc);
5509 xpc.xp_context = EXPAND_FILES;
5510 if (p_wic)
5511 options += WILD_ICASE;
5512 if (rettv->v_type == VAR_STRING)
5513 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5514 NULL, options, WILD_ALL);
5515 else if (rettv_list_alloc(rettv) != FAIL)
5516 {
5517 int i;
5518
5519 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5520 NULL, options, WILD_ALL_KEEP);
5521 for (i = 0; i < xpc.xp_numfiles; i++)
5522 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5523
5524 ExpandCleanup(&xpc);
5525 }
5526 }
5527 else
5528 rettv->vval.v_string = NULL;
5529}
5530
5531/*
5532 * "globpath()" function
5533 */
5534 static void
5535f_globpath(typval_T *argvars, typval_T *rettv)
5536{
5537 int flags = 0;
5538 char_u buf1[NUMBUFLEN];
5539 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5540 int error = FALSE;
5541 garray_T ga;
5542 int i;
5543
5544 /* When the optional second argument is non-zero, don't remove matches
5545 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5546 rettv->v_type = VAR_STRING;
5547 if (argvars[2].v_type != VAR_UNKNOWN)
5548 {
5549 if (get_tv_number_chk(&argvars[2], &error))
5550 flags |= WILD_KEEP_ALL;
5551 if (argvars[3].v_type != VAR_UNKNOWN)
5552 {
5553 if (get_tv_number_chk(&argvars[3], &error))
5554 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005555 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556 }
5557 if (argvars[4].v_type != VAR_UNKNOWN
5558 && get_tv_number_chk(&argvars[4], &error))
5559 flags |= WILD_ALLLINKS;
5560 }
5561 }
5562 if (file != NULL && !error)
5563 {
5564 ga_init2(&ga, (int)sizeof(char_u *), 10);
5565 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5566 if (rettv->v_type == VAR_STRING)
5567 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5568 else if (rettv_list_alloc(rettv) != FAIL)
5569 for (i = 0; i < ga.ga_len; ++i)
5570 list_append_string(rettv->vval.v_list,
5571 ((char_u **)(ga.ga_data))[i], -1);
5572 ga_clear_strings(&ga);
5573 }
5574 else
5575 rettv->vval.v_string = NULL;
5576}
5577
5578/*
5579 * "glob2regpat()" function
5580 */
5581 static void
5582f_glob2regpat(typval_T *argvars, typval_T *rettv)
5583{
5584 char_u *pat = get_tv_string_chk(&argvars[0]);
5585
5586 rettv->v_type = VAR_STRING;
5587 rettv->vval.v_string = (pat == NULL)
5588 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5589}
5590
5591/* for VIM_VERSION_ defines */
5592#include "version.h"
5593
5594/*
5595 * "has()" function
5596 */
5597 static void
5598f_has(typval_T *argvars, typval_T *rettv)
5599{
5600 int i;
5601 char_u *name;
5602 int n = FALSE;
5603 static char *(has_list[]) =
5604 {
5605#ifdef AMIGA
5606 "amiga",
5607# ifdef FEAT_ARP
5608 "arp",
5609# endif
5610#endif
5611#ifdef __BEOS__
5612 "beos",
5613#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005614#ifdef MACOS_X
5615 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5616 "osx", /* Mac OS X */
5617# ifdef MACOS_X_DARWIN
5618 "macunix", /* Mac OS X, with the darwin feature */
5619 "osxdarwin", /* synonym for macunix */
5620# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005621#endif
5622#ifdef __QNX__
5623 "qnx",
5624#endif
5625#ifdef UNIX
5626 "unix",
5627#endif
5628#ifdef VMS
5629 "vms",
5630#endif
5631#ifdef WIN32
5632 "win32",
5633#endif
5634#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5635 "win32unix",
5636#endif
5637#if defined(WIN64) || defined(_WIN64)
5638 "win64",
5639#endif
5640#ifdef EBCDIC
5641 "ebcdic",
5642#endif
5643#ifndef CASE_INSENSITIVE_FILENAME
5644 "fname_case",
5645#endif
5646#ifdef HAVE_ACL
5647 "acl",
5648#endif
5649#ifdef FEAT_ARABIC
5650 "arabic",
5651#endif
5652#ifdef FEAT_AUTOCMD
5653 "autocmd",
5654#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005655#ifdef FEAT_AUTOSERVERNAME
5656 "autoservername",
5657#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005658#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 "balloon_eval",
5660# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5661 "balloon_multiline",
5662# endif
5663#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005664#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005665 "balloon_eval_term",
5666#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005667#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5668 "builtin_terms",
5669# ifdef ALL_BUILTIN_TCAPS
5670 "all_builtin_terms",
5671# endif
5672#endif
5673#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5674 || defined(FEAT_GUI_W32) \
5675 || defined(FEAT_GUI_MOTIF))
5676 "browsefilter",
5677#endif
5678#ifdef FEAT_BYTEOFF
5679 "byte_offset",
5680#endif
5681#ifdef FEAT_JOB_CHANNEL
5682 "channel",
5683#endif
5684#ifdef FEAT_CINDENT
5685 "cindent",
5686#endif
5687#ifdef FEAT_CLIENTSERVER
5688 "clientserver",
5689#endif
5690#ifdef FEAT_CLIPBOARD
5691 "clipboard",
5692#endif
5693#ifdef FEAT_CMDL_COMPL
5694 "cmdline_compl",
5695#endif
5696#ifdef FEAT_CMDHIST
5697 "cmdline_hist",
5698#endif
5699#ifdef FEAT_COMMENTS
5700 "comments",
5701#endif
5702#ifdef FEAT_CONCEAL
5703 "conceal",
5704#endif
5705#ifdef FEAT_CRYPT
5706 "cryptv",
5707 "crypt-blowfish",
5708 "crypt-blowfish2",
5709#endif
5710#ifdef FEAT_CSCOPE
5711 "cscope",
5712#endif
5713#ifdef FEAT_CURSORBIND
5714 "cursorbind",
5715#endif
5716#ifdef CURSOR_SHAPE
5717 "cursorshape",
5718#endif
5719#ifdef DEBUG
5720 "debug",
5721#endif
5722#ifdef FEAT_CON_DIALOG
5723 "dialog_con",
5724#endif
5725#ifdef FEAT_GUI_DIALOG
5726 "dialog_gui",
5727#endif
5728#ifdef FEAT_DIFF
5729 "diff",
5730#endif
5731#ifdef FEAT_DIGRAPHS
5732 "digraphs",
5733#endif
5734#ifdef FEAT_DIRECTX
5735 "directx",
5736#endif
5737#ifdef FEAT_DND
5738 "dnd",
5739#endif
5740#ifdef FEAT_EMACS_TAGS
5741 "emacs_tags",
5742#endif
5743 "eval", /* always present, of course! */
5744 "ex_extra", /* graduated feature */
5745#ifdef FEAT_SEARCH_EXTRA
5746 "extra_search",
5747#endif
5748#ifdef FEAT_FKMAP
5749 "farsi",
5750#endif
5751#ifdef FEAT_SEARCHPATH
5752 "file_in_path",
5753#endif
5754#ifdef FEAT_FILTERPIPE
5755 "filterpipe",
5756#endif
5757#ifdef FEAT_FIND_ID
5758 "find_in_path",
5759#endif
5760#ifdef FEAT_FLOAT
5761 "float",
5762#endif
5763#ifdef FEAT_FOLDING
5764 "folding",
5765#endif
5766#ifdef FEAT_FOOTER
5767 "footer",
5768#endif
5769#if !defined(USE_SYSTEM) && defined(UNIX)
5770 "fork",
5771#endif
5772#ifdef FEAT_GETTEXT
5773 "gettext",
5774#endif
5775#ifdef FEAT_GUI
5776 "gui",
5777#endif
5778#ifdef FEAT_GUI_ATHENA
5779# ifdef FEAT_GUI_NEXTAW
5780 "gui_neXtaw",
5781# else
5782 "gui_athena",
5783# endif
5784#endif
5785#ifdef FEAT_GUI_GTK
5786 "gui_gtk",
5787# ifdef USE_GTK3
5788 "gui_gtk3",
5789# else
5790 "gui_gtk2",
5791# endif
5792#endif
5793#ifdef FEAT_GUI_GNOME
5794 "gui_gnome",
5795#endif
5796#ifdef FEAT_GUI_MAC
5797 "gui_mac",
5798#endif
5799#ifdef FEAT_GUI_MOTIF
5800 "gui_motif",
5801#endif
5802#ifdef FEAT_GUI_PHOTON
5803 "gui_photon",
5804#endif
5805#ifdef FEAT_GUI_W32
5806 "gui_win32",
5807#endif
5808#ifdef FEAT_HANGULIN
5809 "hangul_input",
5810#endif
5811#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5812 "iconv",
5813#endif
5814#ifdef FEAT_INS_EXPAND
5815 "insert_expand",
5816#endif
5817#ifdef FEAT_JOB_CHANNEL
5818 "job",
5819#endif
5820#ifdef FEAT_JUMPLIST
5821 "jumplist",
5822#endif
5823#ifdef FEAT_KEYMAP
5824 "keymap",
5825#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005826 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005827#ifdef FEAT_LANGMAP
5828 "langmap",
5829#endif
5830#ifdef FEAT_LIBCALL
5831 "libcall",
5832#endif
5833#ifdef FEAT_LINEBREAK
5834 "linebreak",
5835#endif
5836#ifdef FEAT_LISP
5837 "lispindent",
5838#endif
5839#ifdef FEAT_LISTCMDS
5840 "listcmds",
5841#endif
5842#ifdef FEAT_LOCALMAP
5843 "localmap",
5844#endif
5845#ifdef FEAT_LUA
5846# ifndef DYNAMIC_LUA
5847 "lua",
5848# endif
5849#endif
5850#ifdef FEAT_MENU
5851 "menu",
5852#endif
5853#ifdef FEAT_SESSION
5854 "mksession",
5855#endif
5856#ifdef FEAT_MODIFY_FNAME
5857 "modify_fname",
5858#endif
5859#ifdef FEAT_MOUSE
5860 "mouse",
5861#endif
5862#ifdef FEAT_MOUSESHAPE
5863 "mouseshape",
5864#endif
5865#if defined(UNIX) || defined(VMS)
5866# ifdef FEAT_MOUSE_DEC
5867 "mouse_dec",
5868# endif
5869# ifdef FEAT_MOUSE_GPM
5870 "mouse_gpm",
5871# endif
5872# ifdef FEAT_MOUSE_JSB
5873 "mouse_jsbterm",
5874# endif
5875# ifdef FEAT_MOUSE_NET
5876 "mouse_netterm",
5877# endif
5878# ifdef FEAT_MOUSE_PTERM
5879 "mouse_pterm",
5880# endif
5881# ifdef FEAT_MOUSE_SGR
5882 "mouse_sgr",
5883# endif
5884# ifdef FEAT_SYSMOUSE
5885 "mouse_sysmouse",
5886# endif
5887# ifdef FEAT_MOUSE_URXVT
5888 "mouse_urxvt",
5889# endif
5890# ifdef FEAT_MOUSE_XTERM
5891 "mouse_xterm",
5892# endif
5893#endif
5894#ifdef FEAT_MBYTE
5895 "multi_byte",
5896#endif
5897#ifdef FEAT_MBYTE_IME
5898 "multi_byte_ime",
5899#endif
5900#ifdef FEAT_MULTI_LANG
5901 "multi_lang",
5902#endif
5903#ifdef FEAT_MZSCHEME
5904#ifndef DYNAMIC_MZSCHEME
5905 "mzscheme",
5906#endif
5907#endif
5908#ifdef FEAT_NUM64
5909 "num64",
5910#endif
5911#ifdef FEAT_OLE
5912 "ole",
5913#endif
5914 "packages",
5915#ifdef FEAT_PATH_EXTRA
5916 "path_extra",
5917#endif
5918#ifdef FEAT_PERL
5919#ifndef DYNAMIC_PERL
5920 "perl",
5921#endif
5922#endif
5923#ifdef FEAT_PERSISTENT_UNDO
5924 "persistent_undo",
5925#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005926#if defined(FEAT_PYTHON)
5927 "python_compiled",
5928# if defined(DYNAMIC_PYTHON)
5929 "python_dynamic",
5930# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005931 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005932 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005933# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005934#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005935#if defined(FEAT_PYTHON3)
5936 "python3_compiled",
5937# if defined(DYNAMIC_PYTHON3)
5938 "python3_dynamic",
5939# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005940 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005941 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005942# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005943#endif
5944#ifdef FEAT_POSTSCRIPT
5945 "postscript",
5946#endif
5947#ifdef FEAT_PRINTER
5948 "printer",
5949#endif
5950#ifdef FEAT_PROFILE
5951 "profile",
5952#endif
5953#ifdef FEAT_RELTIME
5954 "reltime",
5955#endif
5956#ifdef FEAT_QUICKFIX
5957 "quickfix",
5958#endif
5959#ifdef FEAT_RIGHTLEFT
5960 "rightleft",
5961#endif
5962#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5963 "ruby",
5964#endif
5965#ifdef FEAT_SCROLLBIND
5966 "scrollbind",
5967#endif
5968#ifdef FEAT_CMDL_INFO
5969 "showcmd",
5970 "cmdline_info",
5971#endif
5972#ifdef FEAT_SIGNS
5973 "signs",
5974#endif
5975#ifdef FEAT_SMARTINDENT
5976 "smartindent",
5977#endif
5978#ifdef STARTUPTIME
5979 "startuptime",
5980#endif
5981#ifdef FEAT_STL_OPT
5982 "statusline",
5983#endif
5984#ifdef FEAT_SUN_WORKSHOP
5985 "sun_workshop",
5986#endif
5987#ifdef FEAT_NETBEANS_INTG
5988 "netbeans_intg",
5989#endif
5990#ifdef FEAT_SPELL
5991 "spell",
5992#endif
5993#ifdef FEAT_SYN_HL
5994 "syntax",
5995#endif
5996#if defined(USE_SYSTEM) || !defined(UNIX)
5997 "system",
5998#endif
5999#ifdef FEAT_TAG_BINS
6000 "tag_binary",
6001#endif
6002#ifdef FEAT_TAG_OLDSTATIC
6003 "tag_old_static",
6004#endif
6005#ifdef FEAT_TAG_ANYWHITE
6006 "tag_any_white",
6007#endif
6008#ifdef FEAT_TCL
6009# ifndef DYNAMIC_TCL
6010 "tcl",
6011# endif
6012#endif
6013#ifdef FEAT_TERMGUICOLORS
6014 "termguicolors",
6015#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006016#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006017 "terminal",
6018#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006019#ifdef TERMINFO
6020 "terminfo",
6021#endif
6022#ifdef FEAT_TERMRESPONSE
6023 "termresponse",
6024#endif
6025#ifdef FEAT_TEXTOBJ
6026 "textobjects",
6027#endif
6028#ifdef HAVE_TGETENT
6029 "tgetent",
6030#endif
6031#ifdef FEAT_TIMERS
6032 "timers",
6033#endif
6034#ifdef FEAT_TITLE
6035 "title",
6036#endif
6037#ifdef FEAT_TOOLBAR
6038 "toolbar",
6039#endif
6040#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6041 "unnamedplus",
6042#endif
6043#ifdef FEAT_USR_CMDS
6044 "user-commands", /* was accidentally included in 5.4 */
6045 "user_commands",
6046#endif
6047#ifdef FEAT_VIMINFO
6048 "viminfo",
6049#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006051#ifdef FEAT_VIRTUALEDIT
6052 "virtualedit",
6053#endif
6054 "visual",
6055#ifdef FEAT_VISUALEXTRA
6056 "visualextra",
6057#endif
6058#ifdef FEAT_VREPLACE
6059 "vreplace",
6060#endif
6061#ifdef FEAT_WILDIGN
6062 "wildignore",
6063#endif
6064#ifdef FEAT_WILDMENU
6065 "wildmenu",
6066#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006067 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006068#ifdef FEAT_WAK
6069 "winaltkeys",
6070#endif
6071#ifdef FEAT_WRITEBACKUP
6072 "writebackup",
6073#endif
6074#ifdef FEAT_XIM
6075 "xim",
6076#endif
6077#ifdef FEAT_XFONTSET
6078 "xfontset",
6079#endif
6080#ifdef FEAT_XPM_W32
6081 "xpm",
6082 "xpm_w32", /* for backward compatibility */
6083#else
6084# if defined(HAVE_XPM)
6085 "xpm",
6086# endif
6087#endif
6088#ifdef USE_XSMP
6089 "xsmp",
6090#endif
6091#ifdef USE_XSMP_INTERACT
6092 "xsmp_interact",
6093#endif
6094#ifdef FEAT_XCLIPBOARD
6095 "xterm_clipboard",
6096#endif
6097#ifdef FEAT_XTERM_SAVE
6098 "xterm_save",
6099#endif
6100#if defined(UNIX) && defined(FEAT_X11)
6101 "X11",
6102#endif
6103 NULL
6104 };
6105
6106 name = get_tv_string(&argvars[0]);
6107 for (i = 0; has_list[i] != NULL; ++i)
6108 if (STRICMP(name, has_list[i]) == 0)
6109 {
6110 n = TRUE;
6111 break;
6112 }
6113
6114 if (n == FALSE)
6115 {
6116 if (STRNICMP(name, "patch", 5) == 0)
6117 {
6118 if (name[5] == '-'
6119 && STRLEN(name) >= 11
6120 && vim_isdigit(name[6])
6121 && vim_isdigit(name[8])
6122 && vim_isdigit(name[10]))
6123 {
6124 int major = atoi((char *)name + 6);
6125 int minor = atoi((char *)name + 8);
6126
6127 /* Expect "patch-9.9.01234". */
6128 n = (major < VIM_VERSION_MAJOR
6129 || (major == VIM_VERSION_MAJOR
6130 && (minor < VIM_VERSION_MINOR
6131 || (minor == VIM_VERSION_MINOR
6132 && has_patch(atoi((char *)name + 10))))));
6133 }
6134 else
6135 n = has_patch(atoi((char *)name + 5));
6136 }
6137 else if (STRICMP(name, "vim_starting") == 0)
6138 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006139 else if (STRICMP(name, "ttyin") == 0)
6140 n = mch_input_isatty();
6141 else if (STRICMP(name, "ttyout") == 0)
6142 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143#ifdef FEAT_MBYTE
6144 else if (STRICMP(name, "multi_byte_encoding") == 0)
6145 n = has_mbyte;
6146#endif
6147#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6148 else if (STRICMP(name, "balloon_multiline") == 0)
6149 n = multiline_balloon_available();
6150#endif
6151#ifdef DYNAMIC_TCL
6152 else if (STRICMP(name, "tcl") == 0)
6153 n = tcl_enabled(FALSE);
6154#endif
6155#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6156 else if (STRICMP(name, "iconv") == 0)
6157 n = iconv_enabled(FALSE);
6158#endif
6159#ifdef DYNAMIC_LUA
6160 else if (STRICMP(name, "lua") == 0)
6161 n = lua_enabled(FALSE);
6162#endif
6163#ifdef DYNAMIC_MZSCHEME
6164 else if (STRICMP(name, "mzscheme") == 0)
6165 n = mzscheme_enabled(FALSE);
6166#endif
6167#ifdef DYNAMIC_RUBY
6168 else if (STRICMP(name, "ruby") == 0)
6169 n = ruby_enabled(FALSE);
6170#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006171#ifdef DYNAMIC_PYTHON
6172 else if (STRICMP(name, "python") == 0)
6173 n = python_enabled(FALSE);
6174#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175#ifdef DYNAMIC_PYTHON3
6176 else if (STRICMP(name, "python3") == 0)
6177 n = python3_enabled(FALSE);
6178#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006179#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6180 else if (STRICMP(name, "pythonx") == 0)
6181 {
6182# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6183 if (p_pyx == 0)
6184 n = python3_enabled(FALSE) || python_enabled(FALSE);
6185 else if (p_pyx == 3)
6186 n = python3_enabled(FALSE);
6187 else if (p_pyx == 2)
6188 n = python_enabled(FALSE);
6189# elif defined(DYNAMIC_PYTHON)
6190 n = python_enabled(FALSE);
6191# elif defined(DYNAMIC_PYTHON3)
6192 n = python3_enabled(FALSE);
6193# endif
6194 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195#endif
6196#ifdef DYNAMIC_PERL
6197 else if (STRICMP(name, "perl") == 0)
6198 n = perl_enabled(FALSE);
6199#endif
6200#ifdef FEAT_GUI
6201 else if (STRICMP(name, "gui_running") == 0)
6202 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006203# ifdef FEAT_BROWSE
6204 else if (STRICMP(name, "browse") == 0)
6205 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6206# endif
6207#endif
6208#ifdef FEAT_SYN_HL
6209 else if (STRICMP(name, "syntax_items") == 0)
6210 n = syntax_present(curwin);
6211#endif
6212#if defined(WIN3264)
6213 else if (STRICMP(name, "win95") == 0)
Bram Moolenaarcea912a2016-10-12 14:20:24 +02006214 n = FALSE; /* Win9x is no more supported. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215#endif
6216#ifdef FEAT_NETBEANS_INTG
6217 else if (STRICMP(name, "netbeans_enabled") == 0)
6218 n = netbeans_active();
6219#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006220#if defined(FEAT_TERMINAL) && defined(WIN3264)
6221 else if (STRICMP(name, "terminal") == 0)
6222 n = terminal_enabled();
6223#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006224 }
6225
6226 rettv->vval.v_number = n;
6227}
6228
6229/*
6230 * "has_key()" function
6231 */
6232 static void
6233f_has_key(typval_T *argvars, typval_T *rettv)
6234{
6235 if (argvars[0].v_type != VAR_DICT)
6236 {
6237 EMSG(_(e_dictreq));
6238 return;
6239 }
6240 if (argvars[0].vval.v_dict == NULL)
6241 return;
6242
6243 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6244 get_tv_string(&argvars[1]), -1) != NULL;
6245}
6246
6247/*
6248 * "haslocaldir()" function
6249 */
6250 static void
6251f_haslocaldir(typval_T *argvars, typval_T *rettv)
6252{
6253 win_T *wp = NULL;
6254
6255 wp = find_tabwin(&argvars[0], &argvars[1]);
6256 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6257}
6258
6259/*
6260 * "hasmapto()" function
6261 */
6262 static void
6263f_hasmapto(typval_T *argvars, typval_T *rettv)
6264{
6265 char_u *name;
6266 char_u *mode;
6267 char_u buf[NUMBUFLEN];
6268 int abbr = FALSE;
6269
6270 name = get_tv_string(&argvars[0]);
6271 if (argvars[1].v_type == VAR_UNKNOWN)
6272 mode = (char_u *)"nvo";
6273 else
6274 {
6275 mode = get_tv_string_buf(&argvars[1], buf);
6276 if (argvars[2].v_type != VAR_UNKNOWN)
6277 abbr = (int)get_tv_number(&argvars[2]);
6278 }
6279
6280 if (map_to_exists(name, mode, abbr))
6281 rettv->vval.v_number = TRUE;
6282 else
6283 rettv->vval.v_number = FALSE;
6284}
6285
6286/*
6287 * "histadd()" function
6288 */
6289 static void
6290f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6291{
6292#ifdef FEAT_CMDHIST
6293 int histype;
6294 char_u *str;
6295 char_u buf[NUMBUFLEN];
6296#endif
6297
6298 rettv->vval.v_number = FALSE;
6299 if (check_restricted() || check_secure())
6300 return;
6301#ifdef FEAT_CMDHIST
6302 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6303 histype = str != NULL ? get_histtype(str) : -1;
6304 if (histype >= 0)
6305 {
6306 str = get_tv_string_buf(&argvars[1], buf);
6307 if (*str != NUL)
6308 {
6309 init_history();
6310 add_to_history(histype, str, FALSE, NUL);
6311 rettv->vval.v_number = TRUE;
6312 return;
6313 }
6314 }
6315#endif
6316}
6317
6318/*
6319 * "histdel()" function
6320 */
6321 static void
6322f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6323{
6324#ifdef FEAT_CMDHIST
6325 int n;
6326 char_u buf[NUMBUFLEN];
6327 char_u *str;
6328
6329 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6330 if (str == NULL)
6331 n = 0;
6332 else if (argvars[1].v_type == VAR_UNKNOWN)
6333 /* only one argument: clear entire history */
6334 n = clr_history(get_histtype(str));
6335 else if (argvars[1].v_type == VAR_NUMBER)
6336 /* index given: remove that entry */
6337 n = del_history_idx(get_histtype(str),
6338 (int)get_tv_number(&argvars[1]));
6339 else
6340 /* string given: remove all matching entries */
6341 n = del_history_entry(get_histtype(str),
6342 get_tv_string_buf(&argvars[1], buf));
6343 rettv->vval.v_number = n;
6344#endif
6345}
6346
6347/*
6348 * "histget()" function
6349 */
6350 static void
6351f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6352{
6353#ifdef FEAT_CMDHIST
6354 int type;
6355 int idx;
6356 char_u *str;
6357
6358 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6359 if (str == NULL)
6360 rettv->vval.v_string = NULL;
6361 else
6362 {
6363 type = get_histtype(str);
6364 if (argvars[1].v_type == VAR_UNKNOWN)
6365 idx = get_history_idx(type);
6366 else
6367 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6368 /* -1 on type error */
6369 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6370 }
6371#else
6372 rettv->vval.v_string = NULL;
6373#endif
6374 rettv->v_type = VAR_STRING;
6375}
6376
6377/*
6378 * "histnr()" function
6379 */
6380 static void
6381f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6382{
6383 int i;
6384
6385#ifdef FEAT_CMDHIST
6386 char_u *history = get_tv_string_chk(&argvars[0]);
6387
6388 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6389 if (i >= HIST_CMD && i < HIST_COUNT)
6390 i = get_history_idx(i);
6391 else
6392#endif
6393 i = -1;
6394 rettv->vval.v_number = i;
6395}
6396
6397/*
6398 * "highlightID(name)" function
6399 */
6400 static void
6401f_hlID(typval_T *argvars, typval_T *rettv)
6402{
6403 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6404}
6405
6406/*
6407 * "highlight_exists()" function
6408 */
6409 static void
6410f_hlexists(typval_T *argvars, typval_T *rettv)
6411{
6412 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6413}
6414
6415/*
6416 * "hostname()" function
6417 */
6418 static void
6419f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6420{
6421 char_u hostname[256];
6422
6423 mch_get_host_name(hostname, 256);
6424 rettv->v_type = VAR_STRING;
6425 rettv->vval.v_string = vim_strsave(hostname);
6426}
6427
6428/*
6429 * iconv() function
6430 */
6431 static void
6432f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6433{
6434#ifdef FEAT_MBYTE
6435 char_u buf1[NUMBUFLEN];
6436 char_u buf2[NUMBUFLEN];
6437 char_u *from, *to, *str;
6438 vimconv_T vimconv;
6439#endif
6440
6441 rettv->v_type = VAR_STRING;
6442 rettv->vval.v_string = NULL;
6443
6444#ifdef FEAT_MBYTE
6445 str = get_tv_string(&argvars[0]);
6446 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6447 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6448 vimconv.vc_type = CONV_NONE;
6449 convert_setup(&vimconv, from, to);
6450
6451 /* If the encodings are equal, no conversion needed. */
6452 if (vimconv.vc_type == CONV_NONE)
6453 rettv->vval.v_string = vim_strsave(str);
6454 else
6455 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6456
6457 convert_setup(&vimconv, NULL, NULL);
6458 vim_free(from);
6459 vim_free(to);
6460#endif
6461}
6462
6463/*
6464 * "indent()" function
6465 */
6466 static void
6467f_indent(typval_T *argvars, typval_T *rettv)
6468{
6469 linenr_T lnum;
6470
6471 lnum = get_tv_lnum(argvars);
6472 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6473 rettv->vval.v_number = get_indent_lnum(lnum);
6474 else
6475 rettv->vval.v_number = -1;
6476}
6477
6478/*
6479 * "index()" function
6480 */
6481 static void
6482f_index(typval_T *argvars, typval_T *rettv)
6483{
6484 list_T *l;
6485 listitem_T *item;
6486 long idx = 0;
6487 int ic = FALSE;
6488
6489 rettv->vval.v_number = -1;
6490 if (argvars[0].v_type != VAR_LIST)
6491 {
6492 EMSG(_(e_listreq));
6493 return;
6494 }
6495 l = argvars[0].vval.v_list;
6496 if (l != NULL)
6497 {
6498 item = l->lv_first;
6499 if (argvars[2].v_type != VAR_UNKNOWN)
6500 {
6501 int error = FALSE;
6502
6503 /* Start at specified item. Use the cached index that list_find()
6504 * sets, so that a negative number also works. */
6505 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6506 idx = l->lv_idx;
6507 if (argvars[3].v_type != VAR_UNKNOWN)
6508 ic = (int)get_tv_number_chk(&argvars[3], &error);
6509 if (error)
6510 item = NULL;
6511 }
6512
6513 for ( ; item != NULL; item = item->li_next, ++idx)
6514 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6515 {
6516 rettv->vval.v_number = idx;
6517 break;
6518 }
6519 }
6520}
6521
6522static int inputsecret_flag = 0;
6523
6524/*
6525 * "input()" function
6526 * Also handles inputsecret() when inputsecret is set.
6527 */
6528 static void
6529f_input(typval_T *argvars, typval_T *rettv)
6530{
6531 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6532}
6533
6534/*
6535 * "inputdialog()" function
6536 */
6537 static void
6538f_inputdialog(typval_T *argvars, typval_T *rettv)
6539{
6540#if defined(FEAT_GUI_TEXTDIALOG)
6541 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6542 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6543 {
6544 char_u *message;
6545 char_u buf[NUMBUFLEN];
6546 char_u *defstr = (char_u *)"";
6547
6548 message = get_tv_string_chk(&argvars[0]);
6549 if (argvars[1].v_type != VAR_UNKNOWN
6550 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6551 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6552 else
6553 IObuff[0] = NUL;
6554 if (message != NULL && defstr != NULL
6555 && do_dialog(VIM_QUESTION, NULL, message,
6556 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6557 rettv->vval.v_string = vim_strsave(IObuff);
6558 else
6559 {
6560 if (message != NULL && defstr != NULL
6561 && argvars[1].v_type != VAR_UNKNOWN
6562 && argvars[2].v_type != VAR_UNKNOWN)
6563 rettv->vval.v_string = vim_strsave(
6564 get_tv_string_buf(&argvars[2], buf));
6565 else
6566 rettv->vval.v_string = NULL;
6567 }
6568 rettv->v_type = VAR_STRING;
6569 }
6570 else
6571#endif
6572 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6573}
6574
6575/*
6576 * "inputlist()" function
6577 */
6578 static void
6579f_inputlist(typval_T *argvars, typval_T *rettv)
6580{
6581 listitem_T *li;
6582 int selected;
6583 int mouse_used;
6584
6585#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006586 /* While starting up, there is no place to enter text. When running tests
6587 * with --not-a-term we assume feedkeys() will be used. */
6588 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589 return;
6590#endif
6591 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6592 {
6593 EMSG2(_(e_listarg), "inputlist()");
6594 return;
6595 }
6596
6597 msg_start();
6598 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6599 lines_left = Rows; /* avoid more prompt */
6600 msg_scroll = TRUE;
6601 msg_clr_eos();
6602
6603 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6604 {
6605 msg_puts(get_tv_string(&li->li_tv));
6606 msg_putchar('\n');
6607 }
6608
6609 /* Ask for choice. */
6610 selected = prompt_for_number(&mouse_used);
6611 if (mouse_used)
6612 selected -= lines_left;
6613
6614 rettv->vval.v_number = selected;
6615}
6616
6617
6618static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6619
6620/*
6621 * "inputrestore()" function
6622 */
6623 static void
6624f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6625{
6626 if (ga_userinput.ga_len > 0)
6627 {
6628 --ga_userinput.ga_len;
6629 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6630 + ga_userinput.ga_len);
6631 /* default return is zero == OK */
6632 }
6633 else if (p_verbose > 1)
6634 {
6635 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6636 rettv->vval.v_number = 1; /* Failed */
6637 }
6638}
6639
6640/*
6641 * "inputsave()" function
6642 */
6643 static void
6644f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6645{
6646 /* Add an entry to the stack of typeahead storage. */
6647 if (ga_grow(&ga_userinput, 1) == OK)
6648 {
6649 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6650 + ga_userinput.ga_len);
6651 ++ga_userinput.ga_len;
6652 /* default return is zero == OK */
6653 }
6654 else
6655 rettv->vval.v_number = 1; /* Failed */
6656}
6657
6658/*
6659 * "inputsecret()" function
6660 */
6661 static void
6662f_inputsecret(typval_T *argvars, typval_T *rettv)
6663{
6664 ++cmdline_star;
6665 ++inputsecret_flag;
6666 f_input(argvars, rettv);
6667 --cmdline_star;
6668 --inputsecret_flag;
6669}
6670
6671/*
6672 * "insert()" function
6673 */
6674 static void
6675f_insert(typval_T *argvars, typval_T *rettv)
6676{
6677 long before = 0;
6678 listitem_T *item;
6679 list_T *l;
6680 int error = FALSE;
6681
6682 if (argvars[0].v_type != VAR_LIST)
6683 EMSG2(_(e_listarg), "insert()");
6684 else if ((l = argvars[0].vval.v_list) != NULL
6685 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6686 {
6687 if (argvars[2].v_type != VAR_UNKNOWN)
6688 before = (long)get_tv_number_chk(&argvars[2], &error);
6689 if (error)
6690 return; /* type error; errmsg already given */
6691
6692 if (before == l->lv_len)
6693 item = NULL;
6694 else
6695 {
6696 item = list_find(l, before);
6697 if (item == NULL)
6698 {
6699 EMSGN(_(e_listidx), before);
6700 l = NULL;
6701 }
6702 }
6703 if (l != NULL)
6704 {
6705 list_insert_tv(l, &argvars[1], item);
6706 copy_tv(&argvars[0], rettv);
6707 }
6708 }
6709}
6710
6711/*
6712 * "invert(expr)" function
6713 */
6714 static void
6715f_invert(typval_T *argvars, typval_T *rettv)
6716{
6717 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6718}
6719
6720/*
6721 * "isdirectory()" function
6722 */
6723 static void
6724f_isdirectory(typval_T *argvars, typval_T *rettv)
6725{
6726 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6727}
6728
6729/*
6730 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6731 * or it refers to a List or Dictionary that is locked.
6732 */
6733 static int
6734tv_islocked(typval_T *tv)
6735{
6736 return (tv->v_lock & VAR_LOCKED)
6737 || (tv->v_type == VAR_LIST
6738 && tv->vval.v_list != NULL
6739 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6740 || (tv->v_type == VAR_DICT
6741 && tv->vval.v_dict != NULL
6742 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6743}
6744
6745/*
6746 * "islocked()" function
6747 */
6748 static void
6749f_islocked(typval_T *argvars, typval_T *rettv)
6750{
6751 lval_T lv;
6752 char_u *end;
6753 dictitem_T *di;
6754
6755 rettv->vval.v_number = -1;
6756 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006757 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 if (end != NULL && lv.ll_name != NULL)
6759 {
6760 if (*end != NUL)
6761 EMSG(_(e_trailing));
6762 else
6763 {
6764 if (lv.ll_tv == NULL)
6765 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006766 di = find_var(lv.ll_name, NULL, TRUE);
6767 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006769 /* Consider a variable locked when:
6770 * 1. the variable itself is locked
6771 * 2. the value of the variable is locked.
6772 * 3. the List or Dict value is locked.
6773 */
6774 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6775 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776 }
6777 }
6778 else if (lv.ll_range)
6779 EMSG(_("E786: Range not allowed"));
6780 else if (lv.ll_newkey != NULL)
6781 EMSG2(_(e_dictkey), lv.ll_newkey);
6782 else if (lv.ll_list != NULL)
6783 /* List item. */
6784 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6785 else
6786 /* Dictionary item. */
6787 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6788 }
6789 }
6790
6791 clear_lval(&lv);
6792}
6793
6794#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6795/*
6796 * "isnan()" function
6797 */
6798 static void
6799f_isnan(typval_T *argvars, typval_T *rettv)
6800{
6801 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6802 && isnan(argvars[0].vval.v_float);
6803}
6804#endif
6805
6806/*
6807 * "items(dict)" function
6808 */
6809 static void
6810f_items(typval_T *argvars, typval_T *rettv)
6811{
6812 dict_list(argvars, rettv, 2);
6813}
6814
6815#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6816/*
6817 * Get the job from the argument.
6818 * Returns NULL if the job is invalid.
6819 */
6820 static job_T *
6821get_job_arg(typval_T *tv)
6822{
6823 job_T *job;
6824
6825 if (tv->v_type != VAR_JOB)
6826 {
6827 EMSG2(_(e_invarg2), get_tv_string(tv));
6828 return NULL;
6829 }
6830 job = tv->vval.v_job;
6831
6832 if (job == NULL)
6833 EMSG(_("E916: not a valid job"));
6834 return job;
6835}
6836
6837/*
6838 * "job_getchannel()" function
6839 */
6840 static void
6841f_job_getchannel(typval_T *argvars, typval_T *rettv)
6842{
6843 job_T *job = get_job_arg(&argvars[0]);
6844
6845 if (job != NULL)
6846 {
6847 rettv->v_type = VAR_CHANNEL;
6848 rettv->vval.v_channel = job->jv_channel;
6849 if (job->jv_channel != NULL)
6850 ++job->jv_channel->ch_refcount;
6851 }
6852}
6853
6854/*
6855 * "job_info()" function
6856 */
6857 static void
6858f_job_info(typval_T *argvars, typval_T *rettv)
6859{
6860 job_T *job = get_job_arg(&argvars[0]);
6861
6862 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6863 job_info(job, rettv->vval.v_dict);
6864}
6865
6866/*
6867 * "job_setoptions()" function
6868 */
6869 static void
6870f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6871{
6872 job_T *job = get_job_arg(&argvars[0]);
6873 jobopt_T opt;
6874
6875 if (job == NULL)
6876 return;
6877 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02006878 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879 job_set_options(job, &opt);
6880 free_job_options(&opt);
6881}
6882
6883/*
6884 * "job_start()" function
6885 */
6886 static void
6887f_job_start(typval_T *argvars, typval_T *rettv)
6888{
6889 rettv->v_type = VAR_JOB;
6890 if (check_restricted() || check_secure())
6891 return;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006892 rettv->vval.v_job = job_start(argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893}
6894
6895/*
6896 * "job_status()" function
6897 */
6898 static void
6899f_job_status(typval_T *argvars, typval_T *rettv)
6900{
6901 job_T *job = get_job_arg(&argvars[0]);
6902
6903 if (job != NULL)
6904 {
6905 rettv->v_type = VAR_STRING;
6906 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6907 }
6908}
6909
6910/*
6911 * "job_stop()" function
6912 */
6913 static void
6914f_job_stop(typval_T *argvars, typval_T *rettv)
6915{
6916 job_T *job = get_job_arg(&argvars[0]);
6917
6918 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006919 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920}
6921#endif
6922
6923/*
6924 * "join()" function
6925 */
6926 static void
6927f_join(typval_T *argvars, typval_T *rettv)
6928{
6929 garray_T ga;
6930 char_u *sep;
6931
6932 if (argvars[0].v_type != VAR_LIST)
6933 {
6934 EMSG(_(e_listreq));
6935 return;
6936 }
6937 if (argvars[0].vval.v_list == NULL)
6938 return;
6939 if (argvars[1].v_type == VAR_UNKNOWN)
6940 sep = (char_u *)" ";
6941 else
6942 sep = get_tv_string_chk(&argvars[1]);
6943
6944 rettv->v_type = VAR_STRING;
6945
6946 if (sep != NULL)
6947 {
6948 ga_init2(&ga, (int)sizeof(char), 80);
6949 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6950 ga_append(&ga, NUL);
6951 rettv->vval.v_string = (char_u *)ga.ga_data;
6952 }
6953 else
6954 rettv->vval.v_string = NULL;
6955}
6956
6957/*
6958 * "js_decode()" function
6959 */
6960 static void
6961f_js_decode(typval_T *argvars, typval_T *rettv)
6962{
6963 js_read_T reader;
6964
6965 reader.js_buf = get_tv_string(&argvars[0]);
6966 reader.js_fill = NULL;
6967 reader.js_used = 0;
6968 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6969 EMSG(_(e_invarg));
6970}
6971
6972/*
6973 * "js_encode()" function
6974 */
6975 static void
6976f_js_encode(typval_T *argvars, typval_T *rettv)
6977{
6978 rettv->v_type = VAR_STRING;
6979 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6980}
6981
6982/*
6983 * "json_decode()" function
6984 */
6985 static void
6986f_json_decode(typval_T *argvars, typval_T *rettv)
6987{
6988 js_read_T reader;
6989
6990 reader.js_buf = get_tv_string(&argvars[0]);
6991 reader.js_fill = NULL;
6992 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01006993 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006994}
6995
6996/*
6997 * "json_encode()" function
6998 */
6999 static void
7000f_json_encode(typval_T *argvars, typval_T *rettv)
7001{
7002 rettv->v_type = VAR_STRING;
7003 rettv->vval.v_string = json_encode(&argvars[0], 0);
7004}
7005
7006/*
7007 * "keys()" function
7008 */
7009 static void
7010f_keys(typval_T *argvars, typval_T *rettv)
7011{
7012 dict_list(argvars, rettv, 0);
7013}
7014
7015/*
7016 * "last_buffer_nr()" function.
7017 */
7018 static void
7019f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7020{
7021 int n = 0;
7022 buf_T *buf;
7023
Bram Moolenaar29323592016-07-24 22:04:11 +02007024 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025 if (n < buf->b_fnum)
7026 n = buf->b_fnum;
7027
7028 rettv->vval.v_number = n;
7029}
7030
7031/*
7032 * "len()" function
7033 */
7034 static void
7035f_len(typval_T *argvars, typval_T *rettv)
7036{
7037 switch (argvars[0].v_type)
7038 {
7039 case VAR_STRING:
7040 case VAR_NUMBER:
7041 rettv->vval.v_number = (varnumber_T)STRLEN(
7042 get_tv_string(&argvars[0]));
7043 break;
7044 case VAR_LIST:
7045 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7046 break;
7047 case VAR_DICT:
7048 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7049 break;
7050 case VAR_UNKNOWN:
7051 case VAR_SPECIAL:
7052 case VAR_FLOAT:
7053 case VAR_FUNC:
7054 case VAR_PARTIAL:
7055 case VAR_JOB:
7056 case VAR_CHANNEL:
7057 EMSG(_("E701: Invalid type for len()"));
7058 break;
7059 }
7060}
7061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007063libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007064{
7065#ifdef FEAT_LIBCALL
7066 char_u *string_in;
7067 char_u **string_result;
7068 int nr_result;
7069#endif
7070
7071 rettv->v_type = type;
7072 if (type != VAR_NUMBER)
7073 rettv->vval.v_string = NULL;
7074
7075 if (check_restricted() || check_secure())
7076 return;
7077
7078#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007079 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7081 {
7082 string_in = NULL;
7083 if (argvars[2].v_type == VAR_STRING)
7084 string_in = argvars[2].vval.v_string;
7085 if (type == VAR_NUMBER)
7086 string_result = NULL;
7087 else
7088 string_result = &rettv->vval.v_string;
7089 if (mch_libcall(argvars[0].vval.v_string,
7090 argvars[1].vval.v_string,
7091 string_in,
7092 argvars[2].vval.v_number,
7093 string_result,
7094 &nr_result) == OK
7095 && type == VAR_NUMBER)
7096 rettv->vval.v_number = nr_result;
7097 }
7098#endif
7099}
7100
7101/*
7102 * "libcall()" function
7103 */
7104 static void
7105f_libcall(typval_T *argvars, typval_T *rettv)
7106{
7107 libcall_common(argvars, rettv, VAR_STRING);
7108}
7109
7110/*
7111 * "libcallnr()" function
7112 */
7113 static void
7114f_libcallnr(typval_T *argvars, typval_T *rettv)
7115{
7116 libcall_common(argvars, rettv, VAR_NUMBER);
7117}
7118
7119/*
7120 * "line(string)" function
7121 */
7122 static void
7123f_line(typval_T *argvars, typval_T *rettv)
7124{
7125 linenr_T lnum = 0;
7126 pos_T *fp;
7127 int fnum;
7128
7129 fp = var2fpos(&argvars[0], TRUE, &fnum);
7130 if (fp != NULL)
7131 lnum = fp->lnum;
7132 rettv->vval.v_number = lnum;
7133}
7134
7135/*
7136 * "line2byte(lnum)" function
7137 */
7138 static void
7139f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7140{
7141#ifndef FEAT_BYTEOFF
7142 rettv->vval.v_number = -1;
7143#else
7144 linenr_T lnum;
7145
7146 lnum = get_tv_lnum(argvars);
7147 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7148 rettv->vval.v_number = -1;
7149 else
7150 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7151 if (rettv->vval.v_number >= 0)
7152 ++rettv->vval.v_number;
7153#endif
7154}
7155
7156/*
7157 * "lispindent(lnum)" function
7158 */
7159 static void
7160f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7161{
7162#ifdef FEAT_LISP
7163 pos_T pos;
7164 linenr_T lnum;
7165
7166 pos = curwin->w_cursor;
7167 lnum = get_tv_lnum(argvars);
7168 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7169 {
7170 curwin->w_cursor.lnum = lnum;
7171 rettv->vval.v_number = get_lisp_indent();
7172 curwin->w_cursor = pos;
7173 }
7174 else
7175#endif
7176 rettv->vval.v_number = -1;
7177}
7178
7179/*
7180 * "localtime()" function
7181 */
7182 static void
7183f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7184{
7185 rettv->vval.v_number = (varnumber_T)time(NULL);
7186}
7187
7188static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7189
7190 static void
7191get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7192{
7193 char_u *keys;
7194 char_u *which;
7195 char_u buf[NUMBUFLEN];
7196 char_u *keys_buf = NULL;
7197 char_u *rhs;
7198 int mode;
7199 int abbr = FALSE;
7200 int get_dict = FALSE;
7201 mapblock_T *mp;
7202 int buffer_local;
7203
7204 /* return empty string for failure */
7205 rettv->v_type = VAR_STRING;
7206 rettv->vval.v_string = NULL;
7207
7208 keys = get_tv_string(&argvars[0]);
7209 if (*keys == NUL)
7210 return;
7211
7212 if (argvars[1].v_type != VAR_UNKNOWN)
7213 {
7214 which = get_tv_string_buf_chk(&argvars[1], buf);
7215 if (argvars[2].v_type != VAR_UNKNOWN)
7216 {
7217 abbr = (int)get_tv_number(&argvars[2]);
7218 if (argvars[3].v_type != VAR_UNKNOWN)
7219 get_dict = (int)get_tv_number(&argvars[3]);
7220 }
7221 }
7222 else
7223 which = (char_u *)"";
7224 if (which == NULL)
7225 return;
7226
7227 mode = get_map_mode(&which, 0);
7228
7229 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7230 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7231 vim_free(keys_buf);
7232
7233 if (!get_dict)
7234 {
7235 /* Return a string. */
7236 if (rhs != NULL)
7237 rettv->vval.v_string = str2special_save(rhs, FALSE);
7238
7239 }
7240 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7241 {
7242 /* Return a dictionary. */
7243 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7244 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7245 dict_T *dict = rettv->vval.v_dict;
7246
7247 dict_add_nr_str(dict, "lhs", 0L, lhs);
7248 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7249 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7250 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7251 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7252 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7253 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7254 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7255 dict_add_nr_str(dict, "mode", 0L, mapmode);
7256
7257 vim_free(lhs);
7258 vim_free(mapmode);
7259 }
7260}
7261
7262#ifdef FEAT_FLOAT
7263/*
7264 * "log()" function
7265 */
7266 static void
7267f_log(typval_T *argvars, typval_T *rettv)
7268{
7269 float_T f = 0.0;
7270
7271 rettv->v_type = VAR_FLOAT;
7272 if (get_float_arg(argvars, &f) == OK)
7273 rettv->vval.v_float = log(f);
7274 else
7275 rettv->vval.v_float = 0.0;
7276}
7277
7278/*
7279 * "log10()" function
7280 */
7281 static void
7282f_log10(typval_T *argvars, typval_T *rettv)
7283{
7284 float_T f = 0.0;
7285
7286 rettv->v_type = VAR_FLOAT;
7287 if (get_float_arg(argvars, &f) == OK)
7288 rettv->vval.v_float = log10(f);
7289 else
7290 rettv->vval.v_float = 0.0;
7291}
7292#endif
7293
7294#ifdef FEAT_LUA
7295/*
7296 * "luaeval()" function
7297 */
7298 static void
7299f_luaeval(typval_T *argvars, typval_T *rettv)
7300{
7301 char_u *str;
7302 char_u buf[NUMBUFLEN];
7303
7304 str = get_tv_string_buf(&argvars[0], buf);
7305 do_luaeval(str, argvars + 1, rettv);
7306}
7307#endif
7308
7309/*
7310 * "map()" function
7311 */
7312 static void
7313f_map(typval_T *argvars, typval_T *rettv)
7314{
7315 filter_map(argvars, rettv, TRUE);
7316}
7317
7318/*
7319 * "maparg()" function
7320 */
7321 static void
7322f_maparg(typval_T *argvars, typval_T *rettv)
7323{
7324 get_maparg(argvars, rettv, TRUE);
7325}
7326
7327/*
7328 * "mapcheck()" function
7329 */
7330 static void
7331f_mapcheck(typval_T *argvars, typval_T *rettv)
7332{
7333 get_maparg(argvars, rettv, FALSE);
7334}
7335
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007336typedef enum
7337{
7338 MATCH_END, /* matchend() */
7339 MATCH_MATCH, /* match() */
7340 MATCH_STR, /* matchstr() */
7341 MATCH_LIST, /* matchlist() */
7342 MATCH_POS /* matchstrpos() */
7343} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344
7345 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007346find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347{
7348 char_u *str = NULL;
7349 long len = 0;
7350 char_u *expr = NULL;
7351 char_u *pat;
7352 regmatch_T regmatch;
7353 char_u patbuf[NUMBUFLEN];
7354 char_u strbuf[NUMBUFLEN];
7355 char_u *save_cpo;
7356 long start = 0;
7357 long nth = 1;
7358 colnr_T startcol = 0;
7359 int match = 0;
7360 list_T *l = NULL;
7361 listitem_T *li = NULL;
7362 long idx = 0;
7363 char_u *tofree = NULL;
7364
7365 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7366 save_cpo = p_cpo;
7367 p_cpo = (char_u *)"";
7368
7369 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007370 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007371 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007372 /* type MATCH_LIST: return empty list when there are no matches.
7373 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 if (rettv_list_alloc(rettv) == FAIL)
7375 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007376 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 && (list_append_string(rettv->vval.v_list,
7378 (char_u *)"", 0) == FAIL
7379 || list_append_number(rettv->vval.v_list,
7380 (varnumber_T)-1) == FAIL
7381 || list_append_number(rettv->vval.v_list,
7382 (varnumber_T)-1) == FAIL
7383 || list_append_number(rettv->vval.v_list,
7384 (varnumber_T)-1) == FAIL))
7385 {
7386 list_free(rettv->vval.v_list);
7387 rettv->vval.v_list = NULL;
7388 goto theend;
7389 }
7390 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007391 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 {
7393 rettv->v_type = VAR_STRING;
7394 rettv->vval.v_string = NULL;
7395 }
7396
7397 if (argvars[0].v_type == VAR_LIST)
7398 {
7399 if ((l = argvars[0].vval.v_list) == NULL)
7400 goto theend;
7401 li = l->lv_first;
7402 }
7403 else
7404 {
7405 expr = str = get_tv_string(&argvars[0]);
7406 len = (long)STRLEN(str);
7407 }
7408
7409 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7410 if (pat == NULL)
7411 goto theend;
7412
7413 if (argvars[2].v_type != VAR_UNKNOWN)
7414 {
7415 int error = FALSE;
7416
7417 start = (long)get_tv_number_chk(&argvars[2], &error);
7418 if (error)
7419 goto theend;
7420 if (l != NULL)
7421 {
7422 li = list_find(l, start);
7423 if (li == NULL)
7424 goto theend;
7425 idx = l->lv_idx; /* use the cached index */
7426 }
7427 else
7428 {
7429 if (start < 0)
7430 start = 0;
7431 if (start > len)
7432 goto theend;
7433 /* When "count" argument is there ignore matches before "start",
7434 * otherwise skip part of the string. Differs when pattern is "^"
7435 * or "\<". */
7436 if (argvars[3].v_type != VAR_UNKNOWN)
7437 startcol = start;
7438 else
7439 {
7440 str += start;
7441 len -= start;
7442 }
7443 }
7444
7445 if (argvars[3].v_type != VAR_UNKNOWN)
7446 nth = (long)get_tv_number_chk(&argvars[3], &error);
7447 if (error)
7448 goto theend;
7449 }
7450
7451 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7452 if (regmatch.regprog != NULL)
7453 {
7454 regmatch.rm_ic = p_ic;
7455
7456 for (;;)
7457 {
7458 if (l != NULL)
7459 {
7460 if (li == NULL)
7461 {
7462 match = FALSE;
7463 break;
7464 }
7465 vim_free(tofree);
7466 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7467 if (str == NULL)
7468 break;
7469 }
7470
7471 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7472
7473 if (match && --nth <= 0)
7474 break;
7475 if (l == NULL && !match)
7476 break;
7477
7478 /* Advance to just after the match. */
7479 if (l != NULL)
7480 {
7481 li = li->li_next;
7482 ++idx;
7483 }
7484 else
7485 {
7486#ifdef FEAT_MBYTE
7487 startcol = (colnr_T)(regmatch.startp[0]
7488 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7489#else
7490 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7491#endif
7492 if (startcol > (colnr_T)len
7493 || str + startcol <= regmatch.startp[0])
7494 {
7495 match = FALSE;
7496 break;
7497 }
7498 }
7499 }
7500
7501 if (match)
7502 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007503 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 {
7505 listitem_T *li1 = rettv->vval.v_list->lv_first;
7506 listitem_T *li2 = li1->li_next;
7507 listitem_T *li3 = li2->li_next;
7508 listitem_T *li4 = li3->li_next;
7509
7510 vim_free(li1->li_tv.vval.v_string);
7511 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7512 (int)(regmatch.endp[0] - regmatch.startp[0]));
7513 li3->li_tv.vval.v_number =
7514 (varnumber_T)(regmatch.startp[0] - expr);
7515 li4->li_tv.vval.v_number =
7516 (varnumber_T)(regmatch.endp[0] - expr);
7517 if (l != NULL)
7518 li2->li_tv.vval.v_number = (varnumber_T)idx;
7519 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007520 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 {
7522 int i;
7523
7524 /* return list with matched string and submatches */
7525 for (i = 0; i < NSUBEXP; ++i)
7526 {
7527 if (regmatch.endp[i] == NULL)
7528 {
7529 if (list_append_string(rettv->vval.v_list,
7530 (char_u *)"", 0) == FAIL)
7531 break;
7532 }
7533 else if (list_append_string(rettv->vval.v_list,
7534 regmatch.startp[i],
7535 (int)(regmatch.endp[i] - regmatch.startp[i]))
7536 == FAIL)
7537 break;
7538 }
7539 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007540 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007541 {
7542 /* return matched string */
7543 if (l != NULL)
7544 copy_tv(&li->li_tv, rettv);
7545 else
7546 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7547 (int)(regmatch.endp[0] - regmatch.startp[0]));
7548 }
7549 else if (l != NULL)
7550 rettv->vval.v_number = idx;
7551 else
7552 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007553 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554 rettv->vval.v_number =
7555 (varnumber_T)(regmatch.startp[0] - str);
7556 else
7557 rettv->vval.v_number =
7558 (varnumber_T)(regmatch.endp[0] - str);
7559 rettv->vval.v_number += (varnumber_T)(str - expr);
7560 }
7561 }
7562 vim_regfree(regmatch.regprog);
7563 }
7564
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007565theend:
7566 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567 /* matchstrpos() without a list: drop the second item. */
7568 listitem_remove(rettv->vval.v_list,
7569 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570 vim_free(tofree);
7571 p_cpo = save_cpo;
7572}
7573
7574/*
7575 * "match()" function
7576 */
7577 static void
7578f_match(typval_T *argvars, typval_T *rettv)
7579{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007580 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581}
7582
7583/*
7584 * "matchadd()" function
7585 */
7586 static void
7587f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7588{
7589#ifdef FEAT_SEARCH_EXTRA
7590 char_u buf[NUMBUFLEN];
7591 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7592 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7593 int prio = 10; /* default priority */
7594 int id = -1;
7595 int error = FALSE;
7596 char_u *conceal_char = NULL;
7597
7598 rettv->vval.v_number = -1;
7599
7600 if (grp == NULL || pat == NULL)
7601 return;
7602 if (argvars[2].v_type != VAR_UNKNOWN)
7603 {
7604 prio = (int)get_tv_number_chk(&argvars[2], &error);
7605 if (argvars[3].v_type != VAR_UNKNOWN)
7606 {
7607 id = (int)get_tv_number_chk(&argvars[3], &error);
7608 if (argvars[4].v_type != VAR_UNKNOWN)
7609 {
7610 if (argvars[4].v_type != VAR_DICT)
7611 {
7612 EMSG(_(e_dictreq));
7613 return;
7614 }
7615 if (dict_find(argvars[4].vval.v_dict,
7616 (char_u *)"conceal", -1) != NULL)
7617 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7618 (char_u *)"conceal", FALSE);
7619 }
7620 }
7621 }
7622 if (error == TRUE)
7623 return;
7624 if (id >= 1 && id <= 3)
7625 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007626 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 return;
7628 }
7629
7630 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7631 conceal_char);
7632#endif
7633}
7634
7635/*
7636 * "matchaddpos()" function
7637 */
7638 static void
7639f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7640{
7641#ifdef FEAT_SEARCH_EXTRA
7642 char_u buf[NUMBUFLEN];
7643 char_u *group;
7644 int prio = 10;
7645 int id = -1;
7646 int error = FALSE;
7647 list_T *l;
7648 char_u *conceal_char = NULL;
7649
7650 rettv->vval.v_number = -1;
7651
7652 group = get_tv_string_buf_chk(&argvars[0], buf);
7653 if (group == NULL)
7654 return;
7655
7656 if (argvars[1].v_type != VAR_LIST)
7657 {
7658 EMSG2(_(e_listarg), "matchaddpos()");
7659 return;
7660 }
7661 l = argvars[1].vval.v_list;
7662 if (l == NULL)
7663 return;
7664
7665 if (argvars[2].v_type != VAR_UNKNOWN)
7666 {
7667 prio = (int)get_tv_number_chk(&argvars[2], &error);
7668 if (argvars[3].v_type != VAR_UNKNOWN)
7669 {
7670 id = (int)get_tv_number_chk(&argvars[3], &error);
7671 if (argvars[4].v_type != VAR_UNKNOWN)
7672 {
7673 if (argvars[4].v_type != VAR_DICT)
7674 {
7675 EMSG(_(e_dictreq));
7676 return;
7677 }
7678 if (dict_find(argvars[4].vval.v_dict,
7679 (char_u *)"conceal", -1) != NULL)
7680 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7681 (char_u *)"conceal", FALSE);
7682 }
7683 }
7684 }
7685 if (error == TRUE)
7686 return;
7687
7688 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7689 if (id == 1 || id == 2)
7690 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007691 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007692 return;
7693 }
7694
7695 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7696 conceal_char);
7697#endif
7698}
7699
7700/*
7701 * "matcharg()" function
7702 */
7703 static void
7704f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7705{
7706 if (rettv_list_alloc(rettv) == OK)
7707 {
7708#ifdef FEAT_SEARCH_EXTRA
7709 int id = (int)get_tv_number(&argvars[0]);
7710 matchitem_T *m;
7711
7712 if (id >= 1 && id <= 3)
7713 {
7714 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7715 {
7716 list_append_string(rettv->vval.v_list,
7717 syn_id2name(m->hlg_id), -1);
7718 list_append_string(rettv->vval.v_list, m->pattern, -1);
7719 }
7720 else
7721 {
7722 list_append_string(rettv->vval.v_list, NULL, -1);
7723 list_append_string(rettv->vval.v_list, NULL, -1);
7724 }
7725 }
7726#endif
7727 }
7728}
7729
7730/*
7731 * "matchdelete()" function
7732 */
7733 static void
7734f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7735{
7736#ifdef FEAT_SEARCH_EXTRA
7737 rettv->vval.v_number = match_delete(curwin,
7738 (int)get_tv_number(&argvars[0]), TRUE);
7739#endif
7740}
7741
7742/*
7743 * "matchend()" function
7744 */
7745 static void
7746f_matchend(typval_T *argvars, typval_T *rettv)
7747{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007748 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749}
7750
7751/*
7752 * "matchlist()" function
7753 */
7754 static void
7755f_matchlist(typval_T *argvars, typval_T *rettv)
7756{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007757 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007758}
7759
7760/*
7761 * "matchstr()" function
7762 */
7763 static void
7764f_matchstr(typval_T *argvars, typval_T *rettv)
7765{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007766 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767}
7768
7769/*
7770 * "matchstrpos()" function
7771 */
7772 static void
7773f_matchstrpos(typval_T *argvars, typval_T *rettv)
7774{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007775 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776}
7777
7778static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7779
7780 static void
7781max_min(typval_T *argvars, typval_T *rettv, int domax)
7782{
7783 varnumber_T n = 0;
7784 varnumber_T i;
7785 int error = FALSE;
7786
7787 if (argvars[0].v_type == VAR_LIST)
7788 {
7789 list_T *l;
7790 listitem_T *li;
7791
7792 l = argvars[0].vval.v_list;
7793 if (l != NULL)
7794 {
7795 li = l->lv_first;
7796 if (li != NULL)
7797 {
7798 n = get_tv_number_chk(&li->li_tv, &error);
7799 for (;;)
7800 {
7801 li = li->li_next;
7802 if (li == NULL)
7803 break;
7804 i = get_tv_number_chk(&li->li_tv, &error);
7805 if (domax ? i > n : i < n)
7806 n = i;
7807 }
7808 }
7809 }
7810 }
7811 else if (argvars[0].v_type == VAR_DICT)
7812 {
7813 dict_T *d;
7814 int first = TRUE;
7815 hashitem_T *hi;
7816 int todo;
7817
7818 d = argvars[0].vval.v_dict;
7819 if (d != NULL)
7820 {
7821 todo = (int)d->dv_hashtab.ht_used;
7822 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7823 {
7824 if (!HASHITEM_EMPTY(hi))
7825 {
7826 --todo;
7827 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7828 if (first)
7829 {
7830 n = i;
7831 first = FALSE;
7832 }
7833 else if (domax ? i > n : i < n)
7834 n = i;
7835 }
7836 }
7837 }
7838 }
7839 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007840 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841 rettv->vval.v_number = error ? 0 : n;
7842}
7843
7844/*
7845 * "max()" function
7846 */
7847 static void
7848f_max(typval_T *argvars, typval_T *rettv)
7849{
7850 max_min(argvars, rettv, TRUE);
7851}
7852
7853/*
7854 * "min()" function
7855 */
7856 static void
7857f_min(typval_T *argvars, typval_T *rettv)
7858{
7859 max_min(argvars, rettv, FALSE);
7860}
7861
7862static int mkdir_recurse(char_u *dir, int prot);
7863
7864/*
7865 * Create the directory in which "dir" is located, and higher levels when
7866 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007867 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 */
7869 static int
7870mkdir_recurse(char_u *dir, int prot)
7871{
7872 char_u *p;
7873 char_u *updir;
7874 int r = FAIL;
7875
7876 /* Get end of directory name in "dir".
7877 * We're done when it's "/" or "c:/". */
7878 p = gettail_sep(dir);
7879 if (p <= get_past_head(dir))
7880 return OK;
7881
7882 /* If the directory exists we're done. Otherwise: create it.*/
7883 updir = vim_strnsave(dir, (int)(p - dir));
7884 if (updir == NULL)
7885 return FAIL;
7886 if (mch_isdir(updir))
7887 r = OK;
7888 else if (mkdir_recurse(updir, prot) == OK)
7889 r = vim_mkdir_emsg(updir, prot);
7890 vim_free(updir);
7891 return r;
7892}
7893
7894#ifdef vim_mkdir
7895/*
7896 * "mkdir()" function
7897 */
7898 static void
7899f_mkdir(typval_T *argvars, typval_T *rettv)
7900{
7901 char_u *dir;
7902 char_u buf[NUMBUFLEN];
7903 int prot = 0755;
7904
7905 rettv->vval.v_number = FAIL;
7906 if (check_restricted() || check_secure())
7907 return;
7908
7909 dir = get_tv_string_buf(&argvars[0], buf);
7910 if (*dir == NUL)
7911 rettv->vval.v_number = FAIL;
7912 else
7913 {
7914 if (*gettail(dir) == NUL)
7915 /* remove trailing slashes */
7916 *gettail_sep(dir) = NUL;
7917
7918 if (argvars[1].v_type != VAR_UNKNOWN)
7919 {
7920 if (argvars[2].v_type != VAR_UNKNOWN)
7921 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7922 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7923 mkdir_recurse(dir, prot);
7924 }
7925 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7926 }
7927}
7928#endif
7929
7930/*
7931 * "mode()" function
7932 */
7933 static void
7934f_mode(typval_T *argvars, typval_T *rettv)
7935{
7936 char_u buf[3];
7937
7938 buf[1] = NUL;
7939 buf[2] = NUL;
7940
7941 if (time_for_testing == 93784)
7942 {
7943 /* Testing the two-character code. */
7944 buf[0] = 'x';
7945 buf[1] = '!';
7946 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007947#ifdef FEAT_TERMINAL
7948 else if (term_use_loop())
7949 buf[0] = 't';
7950#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951 else if (VIsual_active)
7952 {
7953 if (VIsual_select)
7954 buf[0] = VIsual_mode + 's' - 'v';
7955 else
7956 buf[0] = VIsual_mode;
7957 }
7958 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7959 || State == CONFIRM)
7960 {
7961 buf[0] = 'r';
7962 if (State == ASKMORE)
7963 buf[1] = 'm';
7964 else if (State == CONFIRM)
7965 buf[1] = '?';
7966 }
7967 else if (State == EXTERNCMD)
7968 buf[0] = '!';
7969 else if (State & INSERT)
7970 {
7971#ifdef FEAT_VREPLACE
7972 if (State & VREPLACE_FLAG)
7973 {
7974 buf[0] = 'R';
7975 buf[1] = 'v';
7976 }
7977 else
7978#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01007979 {
7980 if (State & REPLACE_FLAG)
7981 buf[0] = 'R';
7982 else
7983 buf[0] = 'i';
7984#ifdef FEAT_INS_EXPAND
7985 if (ins_compl_active())
7986 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007987 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007988 buf[1] = 'x';
7989#endif
7990 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007992 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 {
7994 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007995 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007996 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007997 else if (exmode_active == EXMODE_NORMAL)
7998 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007999 }
8000 else
8001 {
8002 buf[0] = 'n';
8003 if (finish_op)
8004 buf[1] = 'o';
8005 }
8006
8007 /* Clear out the minor mode when the argument is not a non-zero number or
8008 * non-empty string. */
8009 if (!non_zero_arg(&argvars[0]))
8010 buf[1] = NUL;
8011
8012 rettv->vval.v_string = vim_strsave(buf);
8013 rettv->v_type = VAR_STRING;
8014}
8015
8016#if defined(FEAT_MZSCHEME) || defined(PROTO)
8017/*
8018 * "mzeval()" function
8019 */
8020 static void
8021f_mzeval(typval_T *argvars, typval_T *rettv)
8022{
8023 char_u *str;
8024 char_u buf[NUMBUFLEN];
8025
8026 str = get_tv_string_buf(&argvars[0], buf);
8027 do_mzeval(str, rettv);
8028}
8029
8030 void
8031mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8032{
8033 typval_T argvars[3];
8034
8035 argvars[0].v_type = VAR_STRING;
8036 argvars[0].vval.v_string = name;
8037 copy_tv(args, &argvars[1]);
8038 argvars[2].v_type = VAR_UNKNOWN;
8039 f_call(argvars, rettv);
8040 clear_tv(&argvars[1]);
8041}
8042#endif
8043
8044/*
8045 * "nextnonblank()" function
8046 */
8047 static void
8048f_nextnonblank(typval_T *argvars, typval_T *rettv)
8049{
8050 linenr_T lnum;
8051
8052 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8053 {
8054 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8055 {
8056 lnum = 0;
8057 break;
8058 }
8059 if (*skipwhite(ml_get(lnum)) != NUL)
8060 break;
8061 }
8062 rettv->vval.v_number = lnum;
8063}
8064
8065/*
8066 * "nr2char()" function
8067 */
8068 static void
8069f_nr2char(typval_T *argvars, typval_T *rettv)
8070{
8071 char_u buf[NUMBUFLEN];
8072
8073#ifdef FEAT_MBYTE
8074 if (has_mbyte)
8075 {
8076 int utf8 = 0;
8077
8078 if (argvars[1].v_type != VAR_UNKNOWN)
8079 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8080 if (utf8)
8081 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8082 else
8083 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8084 }
8085 else
8086#endif
8087 {
8088 buf[0] = (char_u)get_tv_number(&argvars[0]);
8089 buf[1] = NUL;
8090 }
8091 rettv->v_type = VAR_STRING;
8092 rettv->vval.v_string = vim_strsave(buf);
8093}
8094
8095/*
8096 * "or(expr, expr)" function
8097 */
8098 static void
8099f_or(typval_T *argvars, typval_T *rettv)
8100{
8101 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8102 | get_tv_number_chk(&argvars[1], NULL);
8103}
8104
8105/*
8106 * "pathshorten()" function
8107 */
8108 static void
8109f_pathshorten(typval_T *argvars, typval_T *rettv)
8110{
8111 char_u *p;
8112
8113 rettv->v_type = VAR_STRING;
8114 p = get_tv_string_chk(&argvars[0]);
8115 if (p == NULL)
8116 rettv->vval.v_string = NULL;
8117 else
8118 {
8119 p = vim_strsave(p);
8120 rettv->vval.v_string = p;
8121 if (p != NULL)
8122 shorten_dir(p);
8123 }
8124}
8125
8126#ifdef FEAT_PERL
8127/*
8128 * "perleval()" function
8129 */
8130 static void
8131f_perleval(typval_T *argvars, typval_T *rettv)
8132{
8133 char_u *str;
8134 char_u buf[NUMBUFLEN];
8135
8136 str = get_tv_string_buf(&argvars[0], buf);
8137 do_perleval(str, rettv);
8138}
8139#endif
8140
8141#ifdef FEAT_FLOAT
8142/*
8143 * "pow()" function
8144 */
8145 static void
8146f_pow(typval_T *argvars, typval_T *rettv)
8147{
8148 float_T fx = 0.0, fy = 0.0;
8149
8150 rettv->v_type = VAR_FLOAT;
8151 if (get_float_arg(argvars, &fx) == OK
8152 && get_float_arg(&argvars[1], &fy) == OK)
8153 rettv->vval.v_float = pow(fx, fy);
8154 else
8155 rettv->vval.v_float = 0.0;
8156}
8157#endif
8158
8159/*
8160 * "prevnonblank()" function
8161 */
8162 static void
8163f_prevnonblank(typval_T *argvars, typval_T *rettv)
8164{
8165 linenr_T lnum;
8166
8167 lnum = get_tv_lnum(argvars);
8168 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8169 lnum = 0;
8170 else
8171 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8172 --lnum;
8173 rettv->vval.v_number = lnum;
8174}
8175
8176/* This dummy va_list is here because:
8177 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8178 * - locally in the function results in a "used before set" warning
8179 * - using va_start() to initialize it gives "function with fixed args" error */
8180static va_list ap;
8181
8182/*
8183 * "printf()" function
8184 */
8185 static void
8186f_printf(typval_T *argvars, typval_T *rettv)
8187{
8188 char_u buf[NUMBUFLEN];
8189 int len;
8190 char_u *s;
8191 int saved_did_emsg = did_emsg;
8192 char *fmt;
8193
8194 rettv->v_type = VAR_STRING;
8195 rettv->vval.v_string = NULL;
8196
8197 /* Get the required length, allocate the buffer and do it for real. */
8198 did_emsg = FALSE;
8199 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008200 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201 if (!did_emsg)
8202 {
8203 s = alloc(len + 1);
8204 if (s != NULL)
8205 {
8206 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008207 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8208 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209 }
8210 }
8211 did_emsg |= saved_did_emsg;
8212}
8213
8214/*
8215 * "pumvisible()" function
8216 */
8217 static void
8218f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8219{
8220#ifdef FEAT_INS_EXPAND
8221 if (pum_visible())
8222 rettv->vval.v_number = 1;
8223#endif
8224}
8225
8226#ifdef FEAT_PYTHON3
8227/*
8228 * "py3eval()" function
8229 */
8230 static void
8231f_py3eval(typval_T *argvars, typval_T *rettv)
8232{
8233 char_u *str;
8234 char_u buf[NUMBUFLEN];
8235
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008236 if (p_pyx == 0)
8237 p_pyx = 3;
8238
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239 str = get_tv_string_buf(&argvars[0], buf);
8240 do_py3eval(str, rettv);
8241}
8242#endif
8243
8244#ifdef FEAT_PYTHON
8245/*
8246 * "pyeval()" function
8247 */
8248 static void
8249f_pyeval(typval_T *argvars, typval_T *rettv)
8250{
8251 char_u *str;
8252 char_u buf[NUMBUFLEN];
8253
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008254 if (p_pyx == 0)
8255 p_pyx = 2;
8256
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 str = get_tv_string_buf(&argvars[0], buf);
8258 do_pyeval(str, rettv);
8259}
8260#endif
8261
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008262#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8263/*
8264 * "pyxeval()" function
8265 */
8266 static void
8267f_pyxeval(typval_T *argvars, typval_T *rettv)
8268{
8269# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8270 init_pyxversion();
8271 if (p_pyx == 2)
8272 f_pyeval(argvars, rettv);
8273 else
8274 f_py3eval(argvars, rettv);
8275# elif defined(FEAT_PYTHON)
8276 f_pyeval(argvars, rettv);
8277# elif defined(FEAT_PYTHON3)
8278 f_py3eval(argvars, rettv);
8279# endif
8280}
8281#endif
8282
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283/*
8284 * "range()" function
8285 */
8286 static void
8287f_range(typval_T *argvars, typval_T *rettv)
8288{
8289 varnumber_T start;
8290 varnumber_T end;
8291 varnumber_T stride = 1;
8292 varnumber_T i;
8293 int error = FALSE;
8294
8295 start = get_tv_number_chk(&argvars[0], &error);
8296 if (argvars[1].v_type == VAR_UNKNOWN)
8297 {
8298 end = start - 1;
8299 start = 0;
8300 }
8301 else
8302 {
8303 end = get_tv_number_chk(&argvars[1], &error);
8304 if (argvars[2].v_type != VAR_UNKNOWN)
8305 stride = get_tv_number_chk(&argvars[2], &error);
8306 }
8307
8308 if (error)
8309 return; /* type error; errmsg already given */
8310 if (stride == 0)
8311 EMSG(_("E726: Stride is zero"));
8312 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8313 EMSG(_("E727: Start past end"));
8314 else
8315 {
8316 if (rettv_list_alloc(rettv) == OK)
8317 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8318 if (list_append_number(rettv->vval.v_list,
8319 (varnumber_T)i) == FAIL)
8320 break;
8321 }
8322}
8323
8324/*
8325 * "readfile()" function
8326 */
8327 static void
8328f_readfile(typval_T *argvars, typval_T *rettv)
8329{
8330 int binary = FALSE;
8331 int failed = FALSE;
8332 char_u *fname;
8333 FILE *fd;
8334 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8335 int io_size = sizeof(buf);
8336 int readlen; /* size of last fread() */
8337 char_u *prev = NULL; /* previously read bytes, if any */
8338 long prevlen = 0; /* length of data in prev */
8339 long prevsize = 0; /* size of prev buffer */
8340 long maxline = MAXLNUM;
8341 long cnt = 0;
8342 char_u *p; /* position in buf */
8343 char_u *start; /* start of current line */
8344
8345 if (argvars[1].v_type != VAR_UNKNOWN)
8346 {
8347 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8348 binary = TRUE;
8349 if (argvars[2].v_type != VAR_UNKNOWN)
8350 maxline = (long)get_tv_number(&argvars[2]);
8351 }
8352
8353 if (rettv_list_alloc(rettv) == FAIL)
8354 return;
8355
8356 /* Always open the file in binary mode, library functions have a mind of
8357 * their own about CR-LF conversion. */
8358 fname = get_tv_string(&argvars[0]);
8359 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8360 {
8361 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8362 return;
8363 }
8364
8365 while (cnt < maxline || maxline < 0)
8366 {
8367 readlen = (int)fread(buf, 1, io_size, fd);
8368
8369 /* This for loop processes what was read, but is also entered at end
8370 * of file so that either:
8371 * - an incomplete line gets written
8372 * - a "binary" file gets an empty line at the end if it ends in a
8373 * newline. */
8374 for (p = buf, start = buf;
8375 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8376 ++p)
8377 {
8378 if (*p == '\n' || readlen <= 0)
8379 {
8380 listitem_T *li;
8381 char_u *s = NULL;
8382 long_u len = p - start;
8383
8384 /* Finished a line. Remove CRs before NL. */
8385 if (readlen > 0 && !binary)
8386 {
8387 while (len > 0 && start[len - 1] == '\r')
8388 --len;
8389 /* removal may cross back to the "prev" string */
8390 if (len == 0)
8391 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8392 --prevlen;
8393 }
8394 if (prevlen == 0)
8395 s = vim_strnsave(start, (int)len);
8396 else
8397 {
8398 /* Change "prev" buffer to be the right size. This way
8399 * the bytes are only copied once, and very long lines are
8400 * allocated only once. */
8401 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8402 {
8403 mch_memmove(s + prevlen, start, len);
8404 s[prevlen + len] = NUL;
8405 prev = NULL; /* the list will own the string */
8406 prevlen = prevsize = 0;
8407 }
8408 }
8409 if (s == NULL)
8410 {
8411 do_outofmem_msg((long_u) prevlen + len + 1);
8412 failed = TRUE;
8413 break;
8414 }
8415
8416 if ((li = listitem_alloc()) == NULL)
8417 {
8418 vim_free(s);
8419 failed = TRUE;
8420 break;
8421 }
8422 li->li_tv.v_type = VAR_STRING;
8423 li->li_tv.v_lock = 0;
8424 li->li_tv.vval.v_string = s;
8425 list_append(rettv->vval.v_list, li);
8426
8427 start = p + 1; /* step over newline */
8428 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8429 break;
8430 }
8431 else if (*p == NUL)
8432 *p = '\n';
8433#ifdef FEAT_MBYTE
8434 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8435 * when finding the BF and check the previous two bytes. */
8436 else if (*p == 0xbf && enc_utf8 && !binary)
8437 {
8438 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8439 * + 1, these may be in the "prev" string. */
8440 char_u back1 = p >= buf + 1 ? p[-1]
8441 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8442 char_u back2 = p >= buf + 2 ? p[-2]
8443 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8444 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8445
8446 if (back2 == 0xef && back1 == 0xbb)
8447 {
8448 char_u *dest = p - 2;
8449
8450 /* Usually a BOM is at the beginning of a file, and so at
8451 * the beginning of a line; then we can just step over it.
8452 */
8453 if (start == dest)
8454 start = p + 1;
8455 else
8456 {
8457 /* have to shuffle buf to close gap */
8458 int adjust_prevlen = 0;
8459
8460 if (dest < buf)
8461 {
8462 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8463 dest = buf;
8464 }
8465 if (readlen > p - buf + 1)
8466 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8467 readlen -= 3 - adjust_prevlen;
8468 prevlen -= adjust_prevlen;
8469 p = dest - 1;
8470 }
8471 }
8472 }
8473#endif
8474 } /* for */
8475
8476 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8477 break;
8478 if (start < p)
8479 {
8480 /* There's part of a line in buf, store it in "prev". */
8481 if (p - start + prevlen >= prevsize)
8482 {
8483 /* need bigger "prev" buffer */
8484 char_u *newprev;
8485
8486 /* A common use case is ordinary text files and "prev" gets a
8487 * fragment of a line, so the first allocation is made
8488 * small, to avoid repeatedly 'allocing' large and
8489 * 'reallocing' small. */
8490 if (prevsize == 0)
8491 prevsize = (long)(p - start);
8492 else
8493 {
8494 long grow50pc = (prevsize * 3) / 2;
8495 long growmin = (long)((p - start) * 2 + prevlen);
8496 prevsize = grow50pc > growmin ? grow50pc : growmin;
8497 }
8498 newprev = prev == NULL ? alloc(prevsize)
8499 : vim_realloc(prev, prevsize);
8500 if (newprev == NULL)
8501 {
8502 do_outofmem_msg((long_u)prevsize);
8503 failed = TRUE;
8504 break;
8505 }
8506 prev = newprev;
8507 }
8508 /* Add the line part to end of "prev". */
8509 mch_memmove(prev + prevlen, start, p - start);
8510 prevlen += (long)(p - start);
8511 }
8512 } /* while */
8513
8514 /*
8515 * For a negative line count use only the lines at the end of the file,
8516 * free the rest.
8517 */
8518 if (!failed && maxline < 0)
8519 while (cnt > -maxline)
8520 {
8521 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8522 --cnt;
8523 }
8524
8525 if (failed)
8526 {
8527 list_free(rettv->vval.v_list);
8528 /* readfile doc says an empty list is returned on error */
8529 rettv->vval.v_list = list_alloc();
8530 }
8531
8532 vim_free(prev);
8533 fclose(fd);
8534}
8535
8536#if defined(FEAT_RELTIME)
8537static int list2proftime(typval_T *arg, proftime_T *tm);
8538
8539/*
8540 * Convert a List to proftime_T.
8541 * Return FAIL when there is something wrong.
8542 */
8543 static int
8544list2proftime(typval_T *arg, proftime_T *tm)
8545{
8546 long n1, n2;
8547 int error = FALSE;
8548
8549 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8550 || arg->vval.v_list->lv_len != 2)
8551 return FAIL;
8552 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8553 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8554# ifdef WIN3264
8555 tm->HighPart = n1;
8556 tm->LowPart = n2;
8557# else
8558 tm->tv_sec = n1;
8559 tm->tv_usec = n2;
8560# endif
8561 return error ? FAIL : OK;
8562}
8563#endif /* FEAT_RELTIME */
8564
8565/*
8566 * "reltime()" function
8567 */
8568 static void
8569f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8570{
8571#ifdef FEAT_RELTIME
8572 proftime_T res;
8573 proftime_T start;
8574
8575 if (argvars[0].v_type == VAR_UNKNOWN)
8576 {
8577 /* No arguments: get current time. */
8578 profile_start(&res);
8579 }
8580 else if (argvars[1].v_type == VAR_UNKNOWN)
8581 {
8582 if (list2proftime(&argvars[0], &res) == FAIL)
8583 return;
8584 profile_end(&res);
8585 }
8586 else
8587 {
8588 /* Two arguments: compute the difference. */
8589 if (list2proftime(&argvars[0], &start) == FAIL
8590 || list2proftime(&argvars[1], &res) == FAIL)
8591 return;
8592 profile_sub(&res, &start);
8593 }
8594
8595 if (rettv_list_alloc(rettv) == OK)
8596 {
8597 long n1, n2;
8598
8599# ifdef WIN3264
8600 n1 = res.HighPart;
8601 n2 = res.LowPart;
8602# else
8603 n1 = res.tv_sec;
8604 n2 = res.tv_usec;
8605# endif
8606 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8607 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8608 }
8609#endif
8610}
8611
8612#ifdef FEAT_FLOAT
8613/*
8614 * "reltimefloat()" function
8615 */
8616 static void
8617f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8618{
8619# ifdef FEAT_RELTIME
8620 proftime_T tm;
8621# endif
8622
8623 rettv->v_type = VAR_FLOAT;
8624 rettv->vval.v_float = 0;
8625# ifdef FEAT_RELTIME
8626 if (list2proftime(&argvars[0], &tm) == OK)
8627 rettv->vval.v_float = profile_float(&tm);
8628# endif
8629}
8630#endif
8631
8632/*
8633 * "reltimestr()" function
8634 */
8635 static void
8636f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8637{
8638#ifdef FEAT_RELTIME
8639 proftime_T tm;
8640#endif
8641
8642 rettv->v_type = VAR_STRING;
8643 rettv->vval.v_string = NULL;
8644#ifdef FEAT_RELTIME
8645 if (list2proftime(&argvars[0], &tm) == OK)
8646 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8647#endif
8648}
8649
8650#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8651static void make_connection(void);
8652static int check_connection(void);
8653
8654 static void
8655make_connection(void)
8656{
8657 if (X_DISPLAY == NULL
8658# ifdef FEAT_GUI
8659 && !gui.in_use
8660# endif
8661 )
8662 {
8663 x_force_connect = TRUE;
8664 setup_term_clip();
8665 x_force_connect = FALSE;
8666 }
8667}
8668
8669 static int
8670check_connection(void)
8671{
8672 make_connection();
8673 if (X_DISPLAY == NULL)
8674 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008675 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008676 return FAIL;
8677 }
8678 return OK;
8679}
8680#endif
8681
8682#ifdef FEAT_CLIENTSERVER
8683 static void
8684remote_common(typval_T *argvars, typval_T *rettv, int expr)
8685{
8686 char_u *server_name;
8687 char_u *keys;
8688 char_u *r = NULL;
8689 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008690 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008691# ifdef WIN32
8692 HWND w;
8693# else
8694 Window w;
8695# endif
8696
8697 if (check_restricted() || check_secure())
8698 return;
8699
8700# ifdef FEAT_X11
8701 if (check_connection() == FAIL)
8702 return;
8703# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008704 if (argvars[2].v_type != VAR_UNKNOWN
8705 && argvars[3].v_type != VAR_UNKNOWN)
8706 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008707
8708 server_name = get_tv_string_chk(&argvars[0]);
8709 if (server_name == NULL)
8710 return; /* type error; errmsg already given */
8711 keys = get_tv_string_buf(&argvars[1], buf);
8712# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008713 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008714# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008715 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8716 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008717# endif
8718 {
8719 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008720 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008722 vim_free(r);
8723 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724 else
8725 EMSG2(_("E241: Unable to send to %s"), server_name);
8726 return;
8727 }
8728
8729 rettv->vval.v_string = r;
8730
8731 if (argvars[2].v_type != VAR_UNKNOWN)
8732 {
8733 dictitem_T v;
8734 char_u str[30];
8735 char_u *idvar;
8736
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008737 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008738 if (idvar != NULL && *idvar != NUL)
8739 {
8740 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8741 v.di_tv.v_type = VAR_STRING;
8742 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008743 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008744 vim_free(v.di_tv.vval.v_string);
8745 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008746 }
8747}
8748#endif
8749
8750/*
8751 * "remote_expr()" function
8752 */
8753 static void
8754f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8755{
8756 rettv->v_type = VAR_STRING;
8757 rettv->vval.v_string = NULL;
8758#ifdef FEAT_CLIENTSERVER
8759 remote_common(argvars, rettv, TRUE);
8760#endif
8761}
8762
8763/*
8764 * "remote_foreground()" function
8765 */
8766 static void
8767f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8768{
8769#ifdef FEAT_CLIENTSERVER
8770# ifdef WIN32
8771 /* On Win32 it's done in this application. */
8772 {
8773 char_u *server_name = get_tv_string_chk(&argvars[0]);
8774
8775 if (server_name != NULL)
8776 serverForeground(server_name);
8777 }
8778# else
8779 /* Send a foreground() expression to the server. */
8780 argvars[1].v_type = VAR_STRING;
8781 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8782 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008783 rettv->v_type = VAR_STRING;
8784 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008785 remote_common(argvars, rettv, TRUE);
8786 vim_free(argvars[1].vval.v_string);
8787# endif
8788#endif
8789}
8790
8791 static void
8792f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8793{
8794#ifdef FEAT_CLIENTSERVER
8795 dictitem_T v;
8796 char_u *s = NULL;
8797# ifdef WIN32
8798 long_u n = 0;
8799# endif
8800 char_u *serverid;
8801
8802 if (check_restricted() || check_secure())
8803 {
8804 rettv->vval.v_number = -1;
8805 return;
8806 }
8807 serverid = get_tv_string_chk(&argvars[0]);
8808 if (serverid == NULL)
8809 {
8810 rettv->vval.v_number = -1;
8811 return; /* type error; errmsg already given */
8812 }
8813# ifdef WIN32
8814 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8815 if (n == 0)
8816 rettv->vval.v_number = -1;
8817 else
8818 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008819 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008820 rettv->vval.v_number = (s != NULL);
8821 }
8822# else
8823 if (check_connection() == FAIL)
8824 return;
8825
8826 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8827 serverStrToWin(serverid), &s);
8828# endif
8829
8830 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8831 {
8832 char_u *retvar;
8833
8834 v.di_tv.v_type = VAR_STRING;
8835 v.di_tv.vval.v_string = vim_strsave(s);
8836 retvar = get_tv_string_chk(&argvars[1]);
8837 if (retvar != NULL)
8838 set_var(retvar, &v.di_tv, FALSE);
8839 vim_free(v.di_tv.vval.v_string);
8840 }
8841#else
8842 rettv->vval.v_number = -1;
8843#endif
8844}
8845
8846 static void
8847f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8848{
8849 char_u *r = NULL;
8850
8851#ifdef FEAT_CLIENTSERVER
8852 char_u *serverid = get_tv_string_chk(&argvars[0]);
8853
8854 if (serverid != NULL && !check_restricted() && !check_secure())
8855 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008856 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008857# ifdef WIN32
8858 /* The server's HWND is encoded in the 'id' parameter */
8859 long_u n = 0;
8860# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008861
8862 if (argvars[1].v_type != VAR_UNKNOWN)
8863 timeout = get_tv_number(&argvars[1]);
8864
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008865# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008866 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8867 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008868 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008869 if (r == NULL)
8870# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008871 if (check_connection() == FAIL
8872 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8873 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008874# endif
8875 EMSG(_("E277: Unable to read a server reply"));
8876 }
8877#endif
8878 rettv->v_type = VAR_STRING;
8879 rettv->vval.v_string = r;
8880}
8881
8882/*
8883 * "remote_send()" function
8884 */
8885 static void
8886f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8887{
8888 rettv->v_type = VAR_STRING;
8889 rettv->vval.v_string = NULL;
8890#ifdef FEAT_CLIENTSERVER
8891 remote_common(argvars, rettv, FALSE);
8892#endif
8893}
8894
8895/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008896 * "remote_startserver()" function
8897 */
8898 static void
8899f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8900{
8901#ifdef FEAT_CLIENTSERVER
8902 char_u *server = get_tv_string_chk(&argvars[0]);
8903
8904 if (server == NULL)
8905 return; /* type error; errmsg already given */
8906 if (serverName != NULL)
8907 EMSG(_("E941: already started a server"));
8908 else
8909 {
8910# ifdef FEAT_X11
8911 if (check_connection() == OK)
8912 serverRegisterName(X_DISPLAY, server);
8913# else
8914 serverSetName(server);
8915# endif
8916 }
8917#else
8918 EMSG(_("E942: +clientserver feature not available"));
8919#endif
8920}
8921
8922/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008923 * "remove()" function
8924 */
8925 static void
8926f_remove(typval_T *argvars, typval_T *rettv)
8927{
8928 list_T *l;
8929 listitem_T *item, *item2;
8930 listitem_T *li;
8931 long idx;
8932 long end;
8933 char_u *key;
8934 dict_T *d;
8935 dictitem_T *di;
8936 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8937
8938 if (argvars[0].v_type == VAR_DICT)
8939 {
8940 if (argvars[2].v_type != VAR_UNKNOWN)
8941 EMSG2(_(e_toomanyarg), "remove()");
8942 else if ((d = argvars[0].vval.v_dict) != NULL
8943 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8944 {
8945 key = get_tv_string_chk(&argvars[1]);
8946 if (key != NULL)
8947 {
8948 di = dict_find(d, key, -1);
8949 if (di == NULL)
8950 EMSG2(_(e_dictkey), key);
8951 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8952 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8953 {
8954 *rettv = di->di_tv;
8955 init_tv(&di->di_tv);
8956 dictitem_remove(d, di);
8957 }
8958 }
8959 }
8960 }
8961 else if (argvars[0].v_type != VAR_LIST)
8962 EMSG2(_(e_listdictarg), "remove()");
8963 else if ((l = argvars[0].vval.v_list) != NULL
8964 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8965 {
8966 int error = FALSE;
8967
8968 idx = (long)get_tv_number_chk(&argvars[1], &error);
8969 if (error)
8970 ; /* type error: do nothing, errmsg already given */
8971 else if ((item = list_find(l, idx)) == NULL)
8972 EMSGN(_(e_listidx), idx);
8973 else
8974 {
8975 if (argvars[2].v_type == VAR_UNKNOWN)
8976 {
8977 /* Remove one item, return its value. */
8978 vimlist_remove(l, item, item);
8979 *rettv = item->li_tv;
8980 vim_free(item);
8981 }
8982 else
8983 {
8984 /* Remove range of items, return list with values. */
8985 end = (long)get_tv_number_chk(&argvars[2], &error);
8986 if (error)
8987 ; /* type error: do nothing */
8988 else if ((item2 = list_find(l, end)) == NULL)
8989 EMSGN(_(e_listidx), end);
8990 else
8991 {
8992 int cnt = 0;
8993
8994 for (li = item; li != NULL; li = li->li_next)
8995 {
8996 ++cnt;
8997 if (li == item2)
8998 break;
8999 }
9000 if (li == NULL) /* didn't find "item2" after "item" */
9001 EMSG(_(e_invrange));
9002 else
9003 {
9004 vimlist_remove(l, item, item2);
9005 if (rettv_list_alloc(rettv) == OK)
9006 {
9007 l = rettv->vval.v_list;
9008 l->lv_first = item;
9009 l->lv_last = item2;
9010 item->li_prev = NULL;
9011 item2->li_next = NULL;
9012 l->lv_len = cnt;
9013 }
9014 }
9015 }
9016 }
9017 }
9018 }
9019}
9020
9021/*
9022 * "rename({from}, {to})" function
9023 */
9024 static void
9025f_rename(typval_T *argvars, typval_T *rettv)
9026{
9027 char_u buf[NUMBUFLEN];
9028
9029 if (check_restricted() || check_secure())
9030 rettv->vval.v_number = -1;
9031 else
9032 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9033 get_tv_string_buf(&argvars[1], buf));
9034}
9035
9036/*
9037 * "repeat()" function
9038 */
9039 static void
9040f_repeat(typval_T *argvars, typval_T *rettv)
9041{
9042 char_u *p;
9043 int n;
9044 int slen;
9045 int len;
9046 char_u *r;
9047 int i;
9048
9049 n = (int)get_tv_number(&argvars[1]);
9050 if (argvars[0].v_type == VAR_LIST)
9051 {
9052 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9053 while (n-- > 0)
9054 if (list_extend(rettv->vval.v_list,
9055 argvars[0].vval.v_list, NULL) == FAIL)
9056 break;
9057 }
9058 else
9059 {
9060 p = get_tv_string(&argvars[0]);
9061 rettv->v_type = VAR_STRING;
9062 rettv->vval.v_string = NULL;
9063
9064 slen = (int)STRLEN(p);
9065 len = slen * n;
9066 if (len <= 0)
9067 return;
9068
9069 r = alloc(len + 1);
9070 if (r != NULL)
9071 {
9072 for (i = 0; i < n; i++)
9073 mch_memmove(r + i * slen, p, (size_t)slen);
9074 r[len] = NUL;
9075 }
9076
9077 rettv->vval.v_string = r;
9078 }
9079}
9080
9081/*
9082 * "resolve()" function
9083 */
9084 static void
9085f_resolve(typval_T *argvars, typval_T *rettv)
9086{
9087 char_u *p;
9088#ifdef HAVE_READLINK
9089 char_u *buf = NULL;
9090#endif
9091
9092 p = get_tv_string(&argvars[0]);
9093#ifdef FEAT_SHORTCUT
9094 {
9095 char_u *v = NULL;
9096
9097 v = mch_resolve_shortcut(p);
9098 if (v != NULL)
9099 rettv->vval.v_string = v;
9100 else
9101 rettv->vval.v_string = vim_strsave(p);
9102 }
9103#else
9104# ifdef HAVE_READLINK
9105 {
9106 char_u *cpy;
9107 int len;
9108 char_u *remain = NULL;
9109 char_u *q;
9110 int is_relative_to_current = FALSE;
9111 int has_trailing_pathsep = FALSE;
9112 int limit = 100;
9113
9114 p = vim_strsave(p);
9115
9116 if (p[0] == '.' && (vim_ispathsep(p[1])
9117 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9118 is_relative_to_current = TRUE;
9119
9120 len = STRLEN(p);
9121 if (len > 0 && after_pathsep(p, p + len))
9122 {
9123 has_trailing_pathsep = TRUE;
9124 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9125 }
9126
9127 q = getnextcomp(p);
9128 if (*q != NUL)
9129 {
9130 /* Separate the first path component in "p", and keep the
9131 * remainder (beginning with the path separator). */
9132 remain = vim_strsave(q - 1);
9133 q[-1] = NUL;
9134 }
9135
9136 buf = alloc(MAXPATHL + 1);
9137 if (buf == NULL)
9138 goto fail;
9139
9140 for (;;)
9141 {
9142 for (;;)
9143 {
9144 len = readlink((char *)p, (char *)buf, MAXPATHL);
9145 if (len <= 0)
9146 break;
9147 buf[len] = NUL;
9148
9149 if (limit-- == 0)
9150 {
9151 vim_free(p);
9152 vim_free(remain);
9153 EMSG(_("E655: Too many symbolic links (cycle?)"));
9154 rettv->vval.v_string = NULL;
9155 goto fail;
9156 }
9157
9158 /* Ensure that the result will have a trailing path separator
9159 * if the argument has one. */
9160 if (remain == NULL && has_trailing_pathsep)
9161 add_pathsep(buf);
9162
9163 /* Separate the first path component in the link value and
9164 * concatenate the remainders. */
9165 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9166 if (*q != NUL)
9167 {
9168 if (remain == NULL)
9169 remain = vim_strsave(q - 1);
9170 else
9171 {
9172 cpy = concat_str(q - 1, remain);
9173 if (cpy != NULL)
9174 {
9175 vim_free(remain);
9176 remain = cpy;
9177 }
9178 }
9179 q[-1] = NUL;
9180 }
9181
9182 q = gettail(p);
9183 if (q > p && *q == NUL)
9184 {
9185 /* Ignore trailing path separator. */
9186 q[-1] = NUL;
9187 q = gettail(p);
9188 }
9189 if (q > p && !mch_isFullName(buf))
9190 {
9191 /* symlink is relative to directory of argument */
9192 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9193 if (cpy != NULL)
9194 {
9195 STRCPY(cpy, p);
9196 STRCPY(gettail(cpy), buf);
9197 vim_free(p);
9198 p = cpy;
9199 }
9200 }
9201 else
9202 {
9203 vim_free(p);
9204 p = vim_strsave(buf);
9205 }
9206 }
9207
9208 if (remain == NULL)
9209 break;
9210
9211 /* Append the first path component of "remain" to "p". */
9212 q = getnextcomp(remain + 1);
9213 len = q - remain - (*q != NUL);
9214 cpy = vim_strnsave(p, STRLEN(p) + len);
9215 if (cpy != NULL)
9216 {
9217 STRNCAT(cpy, remain, len);
9218 vim_free(p);
9219 p = cpy;
9220 }
9221 /* Shorten "remain". */
9222 if (*q != NUL)
9223 STRMOVE(remain, q - 1);
9224 else
9225 {
9226 vim_free(remain);
9227 remain = NULL;
9228 }
9229 }
9230
9231 /* If the result is a relative path name, make it explicitly relative to
9232 * the current directory if and only if the argument had this form. */
9233 if (!vim_ispathsep(*p))
9234 {
9235 if (is_relative_to_current
9236 && *p != NUL
9237 && !(p[0] == '.'
9238 && (p[1] == NUL
9239 || vim_ispathsep(p[1])
9240 || (p[1] == '.'
9241 && (p[2] == NUL
9242 || vim_ispathsep(p[2]))))))
9243 {
9244 /* Prepend "./". */
9245 cpy = concat_str((char_u *)"./", p);
9246 if (cpy != NULL)
9247 {
9248 vim_free(p);
9249 p = cpy;
9250 }
9251 }
9252 else if (!is_relative_to_current)
9253 {
9254 /* Strip leading "./". */
9255 q = p;
9256 while (q[0] == '.' && vim_ispathsep(q[1]))
9257 q += 2;
9258 if (q > p)
9259 STRMOVE(p, p + 2);
9260 }
9261 }
9262
9263 /* Ensure that the result will have no trailing path separator
9264 * if the argument had none. But keep "/" or "//". */
9265 if (!has_trailing_pathsep)
9266 {
9267 q = p + STRLEN(p);
9268 if (after_pathsep(p, q))
9269 *gettail_sep(p) = NUL;
9270 }
9271
9272 rettv->vval.v_string = p;
9273 }
9274# else
9275 rettv->vval.v_string = vim_strsave(p);
9276# endif
9277#endif
9278
9279 simplify_filename(rettv->vval.v_string);
9280
9281#ifdef HAVE_READLINK
9282fail:
9283 vim_free(buf);
9284#endif
9285 rettv->v_type = VAR_STRING;
9286}
9287
9288/*
9289 * "reverse({list})" function
9290 */
9291 static void
9292f_reverse(typval_T *argvars, typval_T *rettv)
9293{
9294 list_T *l;
9295 listitem_T *li, *ni;
9296
9297 if (argvars[0].v_type != VAR_LIST)
9298 EMSG2(_(e_listarg), "reverse()");
9299 else if ((l = argvars[0].vval.v_list) != NULL
9300 && !tv_check_lock(l->lv_lock,
9301 (char_u *)N_("reverse() argument"), TRUE))
9302 {
9303 li = l->lv_last;
9304 l->lv_first = l->lv_last = NULL;
9305 l->lv_len = 0;
9306 while (li != NULL)
9307 {
9308 ni = li->li_prev;
9309 list_append(l, li);
9310 li = ni;
9311 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009312 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009313 l->lv_idx = l->lv_len - l->lv_idx - 1;
9314 }
9315}
9316
9317#define SP_NOMOVE 0x01 /* don't move cursor */
9318#define SP_REPEAT 0x02 /* repeat to find outer pair */
9319#define SP_RETCOUNT 0x04 /* return matchcount */
9320#define SP_SETPCMARK 0x08 /* set previous context mark */
9321#define SP_START 0x10 /* accept match at start position */
9322#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9323#define SP_END 0x40 /* leave cursor at end of match */
9324#define SP_COLUMN 0x80 /* start at cursor column */
9325
9326static int get_search_arg(typval_T *varp, int *flagsp);
9327
9328/*
9329 * Get flags for a search function.
9330 * Possibly sets "p_ws".
9331 * Returns BACKWARD, FORWARD or zero (for an error).
9332 */
9333 static int
9334get_search_arg(typval_T *varp, int *flagsp)
9335{
9336 int dir = FORWARD;
9337 char_u *flags;
9338 char_u nbuf[NUMBUFLEN];
9339 int mask;
9340
9341 if (varp->v_type != VAR_UNKNOWN)
9342 {
9343 flags = get_tv_string_buf_chk(varp, nbuf);
9344 if (flags == NULL)
9345 return 0; /* type error; errmsg already given */
9346 while (*flags != NUL)
9347 {
9348 switch (*flags)
9349 {
9350 case 'b': dir = BACKWARD; break;
9351 case 'w': p_ws = TRUE; break;
9352 case 'W': p_ws = FALSE; break;
9353 default: mask = 0;
9354 if (flagsp != NULL)
9355 switch (*flags)
9356 {
9357 case 'c': mask = SP_START; break;
9358 case 'e': mask = SP_END; break;
9359 case 'm': mask = SP_RETCOUNT; break;
9360 case 'n': mask = SP_NOMOVE; break;
9361 case 'p': mask = SP_SUBPAT; break;
9362 case 'r': mask = SP_REPEAT; break;
9363 case 's': mask = SP_SETPCMARK; break;
9364 case 'z': mask = SP_COLUMN; break;
9365 }
9366 if (mask == 0)
9367 {
9368 EMSG2(_(e_invarg2), flags);
9369 dir = 0;
9370 }
9371 else
9372 *flagsp |= mask;
9373 }
9374 if (dir == 0)
9375 break;
9376 ++flags;
9377 }
9378 }
9379 return dir;
9380}
9381
9382/*
9383 * Shared by search() and searchpos() functions.
9384 */
9385 static int
9386search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9387{
9388 int flags;
9389 char_u *pat;
9390 pos_T pos;
9391 pos_T save_cursor;
9392 int save_p_ws = p_ws;
9393 int dir;
9394 int retval = 0; /* default: FAIL */
9395 long lnum_stop = 0;
9396 proftime_T tm;
9397#ifdef FEAT_RELTIME
9398 long time_limit = 0;
9399#endif
9400 int options = SEARCH_KEEP;
9401 int subpatnum;
9402
9403 pat = get_tv_string(&argvars[0]);
9404 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9405 if (dir == 0)
9406 goto theend;
9407 flags = *flagsp;
9408 if (flags & SP_START)
9409 options |= SEARCH_START;
9410 if (flags & SP_END)
9411 options |= SEARCH_END;
9412 if (flags & SP_COLUMN)
9413 options |= SEARCH_COL;
9414
9415 /* Optional arguments: line number to stop searching and timeout. */
9416 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9417 {
9418 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9419 if (lnum_stop < 0)
9420 goto theend;
9421#ifdef FEAT_RELTIME
9422 if (argvars[3].v_type != VAR_UNKNOWN)
9423 {
9424 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9425 if (time_limit < 0)
9426 goto theend;
9427 }
9428#endif
9429 }
9430
9431#ifdef FEAT_RELTIME
9432 /* Set the time limit, if there is one. */
9433 profile_setlimit(time_limit, &tm);
9434#endif
9435
9436 /*
9437 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9438 * Check to make sure only those flags are set.
9439 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9440 * flags cannot be set. Check for that condition also.
9441 */
9442 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9443 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9444 {
9445 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9446 goto theend;
9447 }
9448
9449 pos = save_cursor = curwin->w_cursor;
9450 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009451 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009452 if (subpatnum != FAIL)
9453 {
9454 if (flags & SP_SUBPAT)
9455 retval = subpatnum;
9456 else
9457 retval = pos.lnum;
9458 if (flags & SP_SETPCMARK)
9459 setpcmark();
9460 curwin->w_cursor = pos;
9461 if (match_pos != NULL)
9462 {
9463 /* Store the match cursor position */
9464 match_pos->lnum = pos.lnum;
9465 match_pos->col = pos.col + 1;
9466 }
9467 /* "/$" will put the cursor after the end of the line, may need to
9468 * correct that here */
9469 check_cursor();
9470 }
9471
9472 /* If 'n' flag is used: restore cursor position. */
9473 if (flags & SP_NOMOVE)
9474 curwin->w_cursor = save_cursor;
9475 else
9476 curwin->w_set_curswant = TRUE;
9477theend:
9478 p_ws = save_p_ws;
9479
9480 return retval;
9481}
9482
9483#ifdef FEAT_FLOAT
9484
9485/*
9486 * round() is not in C90, use ceil() or floor() instead.
9487 */
9488 float_T
9489vim_round(float_T f)
9490{
9491 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9492}
9493
9494/*
9495 * "round({float})" function
9496 */
9497 static void
9498f_round(typval_T *argvars, typval_T *rettv)
9499{
9500 float_T f = 0.0;
9501
9502 rettv->v_type = VAR_FLOAT;
9503 if (get_float_arg(argvars, &f) == OK)
9504 rettv->vval.v_float = vim_round(f);
9505 else
9506 rettv->vval.v_float = 0.0;
9507}
9508#endif
9509
9510/*
9511 * "screenattr()" function
9512 */
9513 static void
9514f_screenattr(typval_T *argvars, typval_T *rettv)
9515{
9516 int row;
9517 int col;
9518 int c;
9519
9520 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9521 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9522 if (row < 0 || row >= screen_Rows
9523 || col < 0 || col >= screen_Columns)
9524 c = -1;
9525 else
9526 c = ScreenAttrs[LineOffset[row] + col];
9527 rettv->vval.v_number = c;
9528}
9529
9530/*
9531 * "screenchar()" function
9532 */
9533 static void
9534f_screenchar(typval_T *argvars, typval_T *rettv)
9535{
9536 int row;
9537 int col;
9538 int off;
9539 int c;
9540
9541 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9542 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9543 if (row < 0 || row >= screen_Rows
9544 || col < 0 || col >= screen_Columns)
9545 c = -1;
9546 else
9547 {
9548 off = LineOffset[row] + col;
9549#ifdef FEAT_MBYTE
9550 if (enc_utf8 && ScreenLinesUC[off] != 0)
9551 c = ScreenLinesUC[off];
9552 else
9553#endif
9554 c = ScreenLines[off];
9555 }
9556 rettv->vval.v_number = c;
9557}
9558
9559/*
9560 * "screencol()" function
9561 *
9562 * First column is 1 to be consistent with virtcol().
9563 */
9564 static void
9565f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9566{
9567 rettv->vval.v_number = screen_screencol() + 1;
9568}
9569
9570/*
9571 * "screenrow()" function
9572 */
9573 static void
9574f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9575{
9576 rettv->vval.v_number = screen_screenrow() + 1;
9577}
9578
9579/*
9580 * "search()" function
9581 */
9582 static void
9583f_search(typval_T *argvars, typval_T *rettv)
9584{
9585 int flags = 0;
9586
9587 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9588}
9589
9590/*
9591 * "searchdecl()" function
9592 */
9593 static void
9594f_searchdecl(typval_T *argvars, typval_T *rettv)
9595{
9596 int locally = 1;
9597 int thisblock = 0;
9598 int error = FALSE;
9599 char_u *name;
9600
9601 rettv->vval.v_number = 1; /* default: FAIL */
9602
9603 name = get_tv_string_chk(&argvars[0]);
9604 if (argvars[1].v_type != VAR_UNKNOWN)
9605 {
9606 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9607 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9608 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9609 }
9610 if (!error && name != NULL)
9611 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9612 locally, thisblock, SEARCH_KEEP) == FAIL;
9613}
9614
9615/*
9616 * Used by searchpair() and searchpairpos()
9617 */
9618 static int
9619searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9620{
9621 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009622 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009623 int save_p_ws = p_ws;
9624 int dir;
9625 int flags = 0;
9626 char_u nbuf1[NUMBUFLEN];
9627 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009628 int retval = 0; /* default: FAIL */
9629 long lnum_stop = 0;
9630 long time_limit = 0;
9631
9632 /* Get the three pattern arguments: start, middle, end. */
9633 spat = get_tv_string_chk(&argvars[0]);
9634 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9635 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9636 if (spat == NULL || mpat == NULL || epat == NULL)
9637 goto theend; /* type error */
9638
9639 /* Handle the optional fourth argument: flags */
9640 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9641 if (dir == 0)
9642 goto theend;
9643
9644 /* Don't accept SP_END or SP_SUBPAT.
9645 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9646 */
9647 if ((flags & (SP_END | SP_SUBPAT)) != 0
9648 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9649 {
9650 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9651 goto theend;
9652 }
9653
9654 /* Using 'r' implies 'W', otherwise it doesn't work. */
9655 if (flags & SP_REPEAT)
9656 p_ws = FALSE;
9657
9658 /* Optional fifth argument: skip expression */
9659 if (argvars[3].v_type == VAR_UNKNOWN
9660 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009661 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009662 else
9663 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009664 skip = &argvars[4];
9665 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9666 && skip->v_type != VAR_STRING)
9667 {
9668 /* Type error */
9669 goto theend;
9670 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671 if (argvars[5].v_type != VAR_UNKNOWN)
9672 {
9673 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9674 if (lnum_stop < 0)
9675 goto theend;
9676#ifdef FEAT_RELTIME
9677 if (argvars[6].v_type != VAR_UNKNOWN)
9678 {
9679 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9680 if (time_limit < 0)
9681 goto theend;
9682 }
9683#endif
9684 }
9685 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009686
9687 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9688 match_pos, lnum_stop, time_limit);
9689
9690theend:
9691 p_ws = save_p_ws;
9692
9693 return retval;
9694}
9695
9696/*
9697 * "searchpair()" function
9698 */
9699 static void
9700f_searchpair(typval_T *argvars, typval_T *rettv)
9701{
9702 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9703}
9704
9705/*
9706 * "searchpairpos()" function
9707 */
9708 static void
9709f_searchpairpos(typval_T *argvars, typval_T *rettv)
9710{
9711 pos_T match_pos;
9712 int lnum = 0;
9713 int col = 0;
9714
9715 if (rettv_list_alloc(rettv) == FAIL)
9716 return;
9717
9718 if (searchpair_cmn(argvars, &match_pos) > 0)
9719 {
9720 lnum = match_pos.lnum;
9721 col = match_pos.col;
9722 }
9723
9724 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9725 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9726}
9727
9728/*
9729 * Search for a start/middle/end thing.
9730 * Used by searchpair(), see its documentation for the details.
9731 * Returns 0 or -1 for no match,
9732 */
9733 long
9734do_searchpair(
9735 char_u *spat, /* start pattern */
9736 char_u *mpat, /* middle pattern */
9737 char_u *epat, /* end pattern */
9738 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009739 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009740 int flags, /* SP_SETPCMARK and other SP_ values */
9741 pos_T *match_pos,
9742 linenr_T lnum_stop, /* stop at this line if not zero */
9743 long time_limit UNUSED) /* stop after this many msec */
9744{
9745 char_u *save_cpo;
9746 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9747 long retval = 0;
9748 pos_T pos;
9749 pos_T firstpos;
9750 pos_T foundpos;
9751 pos_T save_cursor;
9752 pos_T save_pos;
9753 int n;
9754 int r;
9755 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009756 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009757 int err;
9758 int options = SEARCH_KEEP;
9759 proftime_T tm;
9760
9761 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9762 save_cpo = p_cpo;
9763 p_cpo = empty_option;
9764
9765#ifdef FEAT_RELTIME
9766 /* Set the time limit, if there is one. */
9767 profile_setlimit(time_limit, &tm);
9768#endif
9769
9770 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9771 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009772 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9773 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009774 if (pat2 == NULL || pat3 == NULL)
9775 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009776 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009777 if (*mpat == NUL)
9778 STRCPY(pat3, pat2);
9779 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009780 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009781 spat, epat, mpat);
9782 if (flags & SP_START)
9783 options |= SEARCH_START;
9784
Bram Moolenaar48570482017-10-30 21:48:41 +01009785 if (skip != NULL)
9786 {
9787 /* Empty string means to not use the skip expression. */
9788 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9789 use_skip = skip->vval.v_string != NULL
9790 && *skip->vval.v_string != NUL;
9791 }
9792
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009793 save_cursor = curwin->w_cursor;
9794 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009795 CLEAR_POS(&firstpos);
9796 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009797 pat = pat3;
9798 for (;;)
9799 {
9800 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009801 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009802 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009803 /* didn't find it or found the first match again: FAIL */
9804 break;
9805
9806 if (firstpos.lnum == 0)
9807 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009808 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 {
9810 /* Found the same position again. Can happen with a pattern that
9811 * has "\zs" at the end and searching backwards. Advance one
9812 * character and try again. */
9813 if (dir == BACKWARD)
9814 decl(&pos);
9815 else
9816 incl(&pos);
9817 }
9818 foundpos = pos;
9819
9820 /* clear the start flag to avoid getting stuck here */
9821 options &= ~SEARCH_START;
9822
9823 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009824 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009825 {
9826 save_pos = curwin->w_cursor;
9827 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009828 err = FALSE;
9829 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009830 curwin->w_cursor = save_pos;
9831 if (err)
9832 {
9833 /* Evaluating {skip} caused an error, break here. */
9834 curwin->w_cursor = save_cursor;
9835 retval = -1;
9836 break;
9837 }
9838 if (r)
9839 continue;
9840 }
9841
9842 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9843 {
9844 /* Found end when searching backwards or start when searching
9845 * forward: nested pair. */
9846 ++nest;
9847 pat = pat2; /* nested, don't search for middle */
9848 }
9849 else
9850 {
9851 /* Found end when searching forward or start when searching
9852 * backward: end of (nested) pair; or found middle in outer pair. */
9853 if (--nest == 1)
9854 pat = pat3; /* outer level, search for middle */
9855 }
9856
9857 if (nest == 0)
9858 {
9859 /* Found the match: return matchcount or line number. */
9860 if (flags & SP_RETCOUNT)
9861 ++retval;
9862 else
9863 retval = pos.lnum;
9864 if (flags & SP_SETPCMARK)
9865 setpcmark();
9866 curwin->w_cursor = pos;
9867 if (!(flags & SP_REPEAT))
9868 break;
9869 nest = 1; /* search for next unmatched */
9870 }
9871 }
9872
9873 if (match_pos != NULL)
9874 {
9875 /* Store the match cursor position */
9876 match_pos->lnum = curwin->w_cursor.lnum;
9877 match_pos->col = curwin->w_cursor.col + 1;
9878 }
9879
9880 /* If 'n' flag is used or search failed: restore cursor position. */
9881 if ((flags & SP_NOMOVE) || retval == 0)
9882 curwin->w_cursor = save_cursor;
9883
9884theend:
9885 vim_free(pat2);
9886 vim_free(pat3);
9887 if (p_cpo == empty_option)
9888 p_cpo = save_cpo;
9889 else
9890 /* Darn, evaluating the {skip} expression changed the value. */
9891 free_string_option(save_cpo);
9892
9893 return retval;
9894}
9895
9896/*
9897 * "searchpos()" function
9898 */
9899 static void
9900f_searchpos(typval_T *argvars, typval_T *rettv)
9901{
9902 pos_T match_pos;
9903 int lnum = 0;
9904 int col = 0;
9905 int n;
9906 int flags = 0;
9907
9908 if (rettv_list_alloc(rettv) == FAIL)
9909 return;
9910
9911 n = search_cmn(argvars, &match_pos, &flags);
9912 if (n > 0)
9913 {
9914 lnum = match_pos.lnum;
9915 col = match_pos.col;
9916 }
9917
9918 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9919 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9920 if (flags & SP_SUBPAT)
9921 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9922}
9923
9924 static void
9925f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9926{
9927#ifdef FEAT_CLIENTSERVER
9928 char_u buf[NUMBUFLEN];
9929 char_u *server = get_tv_string_chk(&argvars[0]);
9930 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9931
9932 rettv->vval.v_number = -1;
9933 if (server == NULL || reply == NULL)
9934 return;
9935 if (check_restricted() || check_secure())
9936 return;
9937# ifdef FEAT_X11
9938 if (check_connection() == FAIL)
9939 return;
9940# endif
9941
9942 if (serverSendReply(server, reply) < 0)
9943 {
9944 EMSG(_("E258: Unable to send to client"));
9945 return;
9946 }
9947 rettv->vval.v_number = 0;
9948#else
9949 rettv->vval.v_number = -1;
9950#endif
9951}
9952
9953 static void
9954f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9955{
9956 char_u *r = NULL;
9957
9958#ifdef FEAT_CLIENTSERVER
9959# ifdef WIN32
9960 r = serverGetVimNames();
9961# else
9962 make_connection();
9963 if (X_DISPLAY != NULL)
9964 r = serverGetVimNames(X_DISPLAY);
9965# endif
9966#endif
9967 rettv->v_type = VAR_STRING;
9968 rettv->vval.v_string = r;
9969}
9970
9971/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009972 * Set line or list of lines in buffer "buf".
9973 */
9974 static void
9975set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
9976{
9977 char_u *line = NULL;
9978 list_T *l = NULL;
9979 listitem_T *li = NULL;
9980 long added = 0;
9981 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009982 buf_T *curbuf_save = NULL;
9983 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009984 int is_curbuf = buf == curbuf;
9985
Bram Moolenaar9d954202017-09-04 20:34:19 +02009986 /* When using the current buffer ml_mfp will be set if needed. Useful when
9987 * setline() is used on startup. For other buffers the buffer must be
9988 * loaded. */
9989 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009990 {
9991 rettv->vval.v_number = 1; /* FAIL */
9992 return;
9993 }
9994
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009995 if (!is_curbuf)
9996 {
9997 wininfo_T *wip;
9998
9999 curbuf_save = curbuf;
10000 curwin_save = curwin;
10001 curbuf = buf;
10002 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
10003 {
10004 if (wip->wi_win != NULL)
10005 {
10006 curwin = wip->wi_win;
10007 break;
10008 }
10009 }
10010 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010011
10012 lcount = curbuf->b_ml.ml_line_count;
10013
10014 if (lines->v_type == VAR_LIST)
10015 {
10016 l = lines->vval.v_list;
10017 li = l->lv_first;
10018 }
10019 else
10020 line = get_tv_string_chk(lines);
10021
10022 /* default result is zero == OK */
10023 for (;;)
10024 {
10025 if (l != NULL)
10026 {
10027 /* list argument, get next string */
10028 if (li == NULL)
10029 break;
10030 line = get_tv_string_chk(&li->li_tv);
10031 li = li->li_next;
10032 }
10033
10034 rettv->vval.v_number = 1; /* FAIL */
10035 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10036 break;
10037
10038 /* When coming here from Insert mode, sync undo, so that this can be
10039 * undone separately from what was previously inserted. */
10040 if (u_sync_once == 2)
10041 {
10042 u_sync_once = 1; /* notify that u_sync() was called */
10043 u_sync(TRUE);
10044 }
10045
10046 if (lnum <= curbuf->b_ml.ml_line_count)
10047 {
10048 /* existing line, replace it */
10049 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10050 {
10051 changed_bytes(lnum, 0);
10052 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10053 check_cursor_col();
10054 rettv->vval.v_number = 0; /* OK */
10055 }
10056 }
10057 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10058 {
10059 /* lnum is one past the last line, append the line */
10060 ++added;
10061 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10062 rettv->vval.v_number = 0; /* OK */
10063 }
10064
10065 if (l == NULL) /* only one string argument */
10066 break;
10067 ++lnum;
10068 }
10069
10070 if (added > 0)
10071 appended_lines_mark(lcount, added);
10072
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010073 if (!is_curbuf)
10074 {
10075 curbuf = curbuf_save;
10076 curwin = curwin_save;
10077 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010078}
10079
10080/*
10081 * "setbufline()" function
10082 */
10083 static void
10084f_setbufline(argvars, rettv)
10085 typval_T *argvars;
10086 typval_T *rettv;
10087{
10088 linenr_T lnum;
10089 buf_T *buf;
10090
10091 buf = get_buf_tv(&argvars[0], FALSE);
10092 if (buf == NULL)
10093 rettv->vval.v_number = 1; /* FAIL */
10094 else
10095 {
10096 lnum = get_tv_lnum_buf(&argvars[1], buf);
10097
10098 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10099 }
10100}
10101
10102/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010103 * "setbufvar()" function
10104 */
10105 static void
10106f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10107{
10108 buf_T *buf;
10109 char_u *varname, *bufvarname;
10110 typval_T *varp;
10111 char_u nbuf[NUMBUFLEN];
10112
10113 if (check_restricted() || check_secure())
10114 return;
10115 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10116 varname = get_tv_string_chk(&argvars[1]);
10117 buf = get_buf_tv(&argvars[0], FALSE);
10118 varp = &argvars[2];
10119
10120 if (buf != NULL && varname != NULL && varp != NULL)
10121 {
10122 if (*varname == '&')
10123 {
10124 long numval;
10125 char_u *strval;
10126 int error = FALSE;
10127 aco_save_T aco;
10128
10129 /* set curbuf to be our buf, temporarily */
10130 aucmd_prepbuf(&aco, buf);
10131
10132 ++varname;
10133 numval = (long)get_tv_number_chk(varp, &error);
10134 strval = get_tv_string_buf_chk(varp, nbuf);
10135 if (!error && strval != NULL)
10136 set_option_value(varname, numval, strval, OPT_LOCAL);
10137
10138 /* reset notion of buffer */
10139 aucmd_restbuf(&aco);
10140 }
10141 else
10142 {
10143 buf_T *save_curbuf = curbuf;
10144
10145 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10146 if (bufvarname != NULL)
10147 {
10148 curbuf = buf;
10149 STRCPY(bufvarname, "b:");
10150 STRCPY(bufvarname + 2, varname);
10151 set_var(bufvarname, varp, TRUE);
10152 vim_free(bufvarname);
10153 curbuf = save_curbuf;
10154 }
10155 }
10156 }
10157}
10158
10159 static void
10160f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10161{
10162 dict_T *d;
10163 dictitem_T *di;
10164 char_u *csearch;
10165
10166 if (argvars[0].v_type != VAR_DICT)
10167 {
10168 EMSG(_(e_dictreq));
10169 return;
10170 }
10171
10172 if ((d = argvars[0].vval.v_dict) != NULL)
10173 {
10174 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10175 if (csearch != NULL)
10176 {
10177#ifdef FEAT_MBYTE
10178 if (enc_utf8)
10179 {
10180 int pcc[MAX_MCO];
10181 int c = utfc_ptr2char(csearch, pcc);
10182
10183 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10184 }
10185 else
10186#endif
10187 set_last_csearch(PTR2CHAR(csearch),
10188 csearch, MB_PTR2LEN(csearch));
10189 }
10190
10191 di = dict_find(d, (char_u *)"forward", -1);
10192 if (di != NULL)
10193 set_csearch_direction((int)get_tv_number(&di->di_tv)
10194 ? FORWARD : BACKWARD);
10195
10196 di = dict_find(d, (char_u *)"until", -1);
10197 if (di != NULL)
10198 set_csearch_until(!!get_tv_number(&di->di_tv));
10199 }
10200}
10201
10202/*
10203 * "setcmdpos()" function
10204 */
10205 static void
10206f_setcmdpos(typval_T *argvars, typval_T *rettv)
10207{
10208 int pos = (int)get_tv_number(&argvars[0]) - 1;
10209
10210 if (pos >= 0)
10211 rettv->vval.v_number = set_cmdline_pos(pos);
10212}
10213
10214/*
10215 * "setfperm({fname}, {mode})" function
10216 */
10217 static void
10218f_setfperm(typval_T *argvars, typval_T *rettv)
10219{
10220 char_u *fname;
10221 char_u modebuf[NUMBUFLEN];
10222 char_u *mode_str;
10223 int i;
10224 int mask;
10225 int mode = 0;
10226
10227 rettv->vval.v_number = 0;
10228 fname = get_tv_string_chk(&argvars[0]);
10229 if (fname == NULL)
10230 return;
10231 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10232 if (mode_str == NULL)
10233 return;
10234 if (STRLEN(mode_str) != 9)
10235 {
10236 EMSG2(_(e_invarg2), mode_str);
10237 return;
10238 }
10239
10240 mask = 1;
10241 for (i = 8; i >= 0; --i)
10242 {
10243 if (mode_str[i] != '-')
10244 mode |= mask;
10245 mask = mask << 1;
10246 }
10247 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10248}
10249
10250/*
10251 * "setline()" function
10252 */
10253 static void
10254f_setline(typval_T *argvars, typval_T *rettv)
10255{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010256 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010257
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010258 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010259}
10260
Bram Moolenaard823fa92016-08-12 16:29:27 +020010261static 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 +020010262
10263/*
10264 * Used by "setqflist()" and "setloclist()" functions
10265 */
10266 static void
10267set_qf_ll_list(
10268 win_T *wp UNUSED,
10269 typval_T *list_arg UNUSED,
10270 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010271 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010272 typval_T *rettv)
10273{
10274#ifdef FEAT_QUICKFIX
10275 static char *e_invact = N_("E927: Invalid action: '%s'");
10276 char_u *act;
10277 int action = 0;
10278#endif
10279
10280 rettv->vval.v_number = -1;
10281
10282#ifdef FEAT_QUICKFIX
10283 if (list_arg->v_type != VAR_LIST)
10284 EMSG(_(e_listreq));
10285 else
10286 {
10287 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010288 dict_T *d = NULL;
10289 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010290
10291 if (action_arg->v_type == VAR_STRING)
10292 {
10293 act = get_tv_string_chk(action_arg);
10294 if (act == NULL)
10295 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010296 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10297 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010298 action = *act;
10299 else
10300 EMSG2(_(e_invact), act);
10301 }
10302 else if (action_arg->v_type == VAR_UNKNOWN)
10303 action = ' ';
10304 else
10305 EMSG(_(e_stringreq));
10306
Bram Moolenaard823fa92016-08-12 16:29:27 +020010307 if (action_arg->v_type != VAR_UNKNOWN
10308 && what_arg->v_type != VAR_UNKNOWN)
10309 {
10310 if (what_arg->v_type == VAR_DICT)
10311 d = what_arg->vval.v_dict;
10312 else
10313 {
10314 EMSG(_(e_dictreq));
10315 valid_dict = FALSE;
10316 }
10317 }
10318
10319 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10320 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010321 rettv->vval.v_number = 0;
10322 }
10323#endif
10324}
10325
10326/*
10327 * "setloclist()" function
10328 */
10329 static void
10330f_setloclist(typval_T *argvars, typval_T *rettv)
10331{
10332 win_T *win;
10333
10334 rettv->vval.v_number = -1;
10335
10336 win = find_win_by_nr(&argvars[0], NULL);
10337 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010338 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010339}
10340
10341/*
10342 * "setmatches()" function
10343 */
10344 static void
10345f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10346{
10347#ifdef FEAT_SEARCH_EXTRA
10348 list_T *l;
10349 listitem_T *li;
10350 dict_T *d;
10351 list_T *s = NULL;
10352
10353 rettv->vval.v_number = -1;
10354 if (argvars[0].v_type != VAR_LIST)
10355 {
10356 EMSG(_(e_listreq));
10357 return;
10358 }
10359 if ((l = argvars[0].vval.v_list) != NULL)
10360 {
10361
10362 /* To some extent make sure that we are dealing with a list from
10363 * "getmatches()". */
10364 li = l->lv_first;
10365 while (li != NULL)
10366 {
10367 if (li->li_tv.v_type != VAR_DICT
10368 || (d = li->li_tv.vval.v_dict) == NULL)
10369 {
10370 EMSG(_(e_invarg));
10371 return;
10372 }
10373 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10374 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10375 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10376 && dict_find(d, (char_u *)"priority", -1) != NULL
10377 && dict_find(d, (char_u *)"id", -1) != NULL))
10378 {
10379 EMSG(_(e_invarg));
10380 return;
10381 }
10382 li = li->li_next;
10383 }
10384
10385 clear_matches(curwin);
10386 li = l->lv_first;
10387 while (li != NULL)
10388 {
10389 int i = 0;
10390 char_u buf[5];
10391 dictitem_T *di;
10392 char_u *group;
10393 int priority;
10394 int id;
10395 char_u *conceal;
10396
10397 d = li->li_tv.vval.v_dict;
10398 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10399 {
10400 if (s == NULL)
10401 {
10402 s = list_alloc();
10403 if (s == NULL)
10404 return;
10405 }
10406
10407 /* match from matchaddpos() */
10408 for (i = 1; i < 9; i++)
10409 {
10410 sprintf((char *)buf, (char *)"pos%d", i);
10411 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10412 {
10413 if (di->di_tv.v_type != VAR_LIST)
10414 return;
10415
10416 list_append_tv(s, &di->di_tv);
10417 s->lv_refcount++;
10418 }
10419 else
10420 break;
10421 }
10422 }
10423
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010424 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010425 priority = (int)get_dict_number(d, (char_u *)"priority");
10426 id = (int)get_dict_number(d, (char_u *)"id");
10427 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010428 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010429 : NULL;
10430 if (i == 0)
10431 {
10432 match_add(curwin, group,
10433 get_dict_string(d, (char_u *)"pattern", FALSE),
10434 priority, id, NULL, conceal);
10435 }
10436 else
10437 {
10438 match_add(curwin, group, NULL, priority, id, s, conceal);
10439 list_unref(s);
10440 s = NULL;
10441 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010442 vim_free(group);
10443 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010444
10445 li = li->li_next;
10446 }
10447 rettv->vval.v_number = 0;
10448 }
10449#endif
10450}
10451
10452/*
10453 * "setpos()" function
10454 */
10455 static void
10456f_setpos(typval_T *argvars, typval_T *rettv)
10457{
10458 pos_T pos;
10459 int fnum;
10460 char_u *name;
10461 colnr_T curswant = -1;
10462
10463 rettv->vval.v_number = -1;
10464 name = get_tv_string_chk(argvars);
10465 if (name != NULL)
10466 {
10467 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10468 {
10469 if (--pos.col < 0)
10470 pos.col = 0;
10471 if (name[0] == '.' && name[1] == NUL)
10472 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010473 /* set cursor; "fnum" is ignored */
10474 curwin->w_cursor = pos;
10475 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010476 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010477 curwin->w_curswant = curswant - 1;
10478 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010479 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010480 check_cursor();
10481 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010482 }
10483 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10484 {
10485 /* set mark */
10486 if (setmark_pos(name[1], &pos, fnum) == OK)
10487 rettv->vval.v_number = 0;
10488 }
10489 else
10490 EMSG(_(e_invarg));
10491 }
10492 }
10493}
10494
10495/*
10496 * "setqflist()" function
10497 */
10498 static void
10499f_setqflist(typval_T *argvars, typval_T *rettv)
10500{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010501 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010502}
10503
10504/*
10505 * "setreg()" function
10506 */
10507 static void
10508f_setreg(typval_T *argvars, typval_T *rettv)
10509{
10510 int regname;
10511 char_u *strregname;
10512 char_u *stropt;
10513 char_u *strval;
10514 int append;
10515 char_u yank_type;
10516 long block_len;
10517
10518 block_len = -1;
10519 yank_type = MAUTO;
10520 append = FALSE;
10521
10522 strregname = get_tv_string_chk(argvars);
10523 rettv->vval.v_number = 1; /* FAIL is default */
10524
10525 if (strregname == NULL)
10526 return; /* type error; errmsg already given */
10527 regname = *strregname;
10528 if (regname == 0 || regname == '@')
10529 regname = '"';
10530
10531 if (argvars[2].v_type != VAR_UNKNOWN)
10532 {
10533 stropt = get_tv_string_chk(&argvars[2]);
10534 if (stropt == NULL)
10535 return; /* type error */
10536 for (; *stropt != NUL; ++stropt)
10537 switch (*stropt)
10538 {
10539 case 'a': case 'A': /* append */
10540 append = TRUE;
10541 break;
10542 case 'v': case 'c': /* character-wise selection */
10543 yank_type = MCHAR;
10544 break;
10545 case 'V': case 'l': /* line-wise selection */
10546 yank_type = MLINE;
10547 break;
10548 case 'b': case Ctrl_V: /* block-wise selection */
10549 yank_type = MBLOCK;
10550 if (VIM_ISDIGIT(stropt[1]))
10551 {
10552 ++stropt;
10553 block_len = getdigits(&stropt) - 1;
10554 --stropt;
10555 }
10556 break;
10557 }
10558 }
10559
10560 if (argvars[1].v_type == VAR_LIST)
10561 {
10562 char_u **lstval;
10563 char_u **allocval;
10564 char_u buf[NUMBUFLEN];
10565 char_u **curval;
10566 char_u **curallocval;
10567 list_T *ll = argvars[1].vval.v_list;
10568 listitem_T *li;
10569 int len;
10570
10571 /* If the list is NULL handle like an empty list. */
10572 len = ll == NULL ? 0 : ll->lv_len;
10573
10574 /* First half: use for pointers to result lines; second half: use for
10575 * pointers to allocated copies. */
10576 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10577 if (lstval == NULL)
10578 return;
10579 curval = lstval;
10580 allocval = lstval + len + 2;
10581 curallocval = allocval;
10582
10583 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10584 li = li->li_next)
10585 {
10586 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10587 if (strval == NULL)
10588 goto free_lstval;
10589 if (strval == buf)
10590 {
10591 /* Need to make a copy, next get_tv_string_buf_chk() will
10592 * overwrite the string. */
10593 strval = vim_strsave(buf);
10594 if (strval == NULL)
10595 goto free_lstval;
10596 *curallocval++ = strval;
10597 }
10598 *curval++ = strval;
10599 }
10600 *curval++ = NULL;
10601
10602 write_reg_contents_lst(regname, lstval, -1,
10603 append, yank_type, block_len);
10604free_lstval:
10605 while (curallocval > allocval)
10606 vim_free(*--curallocval);
10607 vim_free(lstval);
10608 }
10609 else
10610 {
10611 strval = get_tv_string_chk(&argvars[1]);
10612 if (strval == NULL)
10613 return;
10614 write_reg_contents_ex(regname, strval, -1,
10615 append, yank_type, block_len);
10616 }
10617 rettv->vval.v_number = 0;
10618}
10619
10620/*
10621 * "settabvar()" function
10622 */
10623 static void
10624f_settabvar(typval_T *argvars, typval_T *rettv)
10625{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010626 tabpage_T *save_curtab;
10627 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010628 char_u *varname, *tabvarname;
10629 typval_T *varp;
10630
10631 rettv->vval.v_number = 0;
10632
10633 if (check_restricted() || check_secure())
10634 return;
10635
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010636 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010637 varname = get_tv_string_chk(&argvars[1]);
10638 varp = &argvars[2];
10639
Bram Moolenaar4033c552017-09-16 20:54:51 +020010640 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010641 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010642 save_curtab = curtab;
10643 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644
10645 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10646 if (tabvarname != NULL)
10647 {
10648 STRCPY(tabvarname, "t:");
10649 STRCPY(tabvarname + 2, varname);
10650 set_var(tabvarname, varp, TRUE);
10651 vim_free(tabvarname);
10652 }
10653
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010654 /* Restore current tabpage */
10655 if (valid_tabpage(save_curtab))
10656 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010657 }
10658}
10659
10660/*
10661 * "settabwinvar()" function
10662 */
10663 static void
10664f_settabwinvar(typval_T *argvars, typval_T *rettv)
10665{
10666 setwinvar(argvars, rettv, 1);
10667}
10668
10669/*
10670 * "setwinvar()" function
10671 */
10672 static void
10673f_setwinvar(typval_T *argvars, typval_T *rettv)
10674{
10675 setwinvar(argvars, rettv, 0);
10676}
10677
10678#ifdef FEAT_CRYPT
10679/*
10680 * "sha256({string})" function
10681 */
10682 static void
10683f_sha256(typval_T *argvars, typval_T *rettv)
10684{
10685 char_u *p;
10686
10687 p = get_tv_string(&argvars[0]);
10688 rettv->vval.v_string = vim_strsave(
10689 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10690 rettv->v_type = VAR_STRING;
10691}
10692#endif /* FEAT_CRYPT */
10693
10694/*
10695 * "shellescape({string})" function
10696 */
10697 static void
10698f_shellescape(typval_T *argvars, typval_T *rettv)
10699{
Bram Moolenaar20615522017-06-05 18:46:26 +020010700 int do_special = non_zero_arg(&argvars[1]);
10701
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010702 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010703 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010704 rettv->v_type = VAR_STRING;
10705}
10706
10707/*
10708 * shiftwidth() function
10709 */
10710 static void
10711f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10712{
10713 rettv->vval.v_number = get_sw_value(curbuf);
10714}
10715
10716/*
10717 * "simplify()" function
10718 */
10719 static void
10720f_simplify(typval_T *argvars, typval_T *rettv)
10721{
10722 char_u *p;
10723
10724 p = get_tv_string(&argvars[0]);
10725 rettv->vval.v_string = vim_strsave(p);
10726 simplify_filename(rettv->vval.v_string); /* simplify in place */
10727 rettv->v_type = VAR_STRING;
10728}
10729
10730#ifdef FEAT_FLOAT
10731/*
10732 * "sin()" function
10733 */
10734 static void
10735f_sin(typval_T *argvars, typval_T *rettv)
10736{
10737 float_T f = 0.0;
10738
10739 rettv->v_type = VAR_FLOAT;
10740 if (get_float_arg(argvars, &f) == OK)
10741 rettv->vval.v_float = sin(f);
10742 else
10743 rettv->vval.v_float = 0.0;
10744}
10745
10746/*
10747 * "sinh()" function
10748 */
10749 static void
10750f_sinh(typval_T *argvars, typval_T *rettv)
10751{
10752 float_T f = 0.0;
10753
10754 rettv->v_type = VAR_FLOAT;
10755 if (get_float_arg(argvars, &f) == OK)
10756 rettv->vval.v_float = sinh(f);
10757 else
10758 rettv->vval.v_float = 0.0;
10759}
10760#endif
10761
10762static int
10763#ifdef __BORLANDC__
10764 _RTLENTRYF
10765#endif
10766 item_compare(const void *s1, const void *s2);
10767static int
10768#ifdef __BORLANDC__
10769 _RTLENTRYF
10770#endif
10771 item_compare2(const void *s1, const void *s2);
10772
10773/* struct used in the array that's given to qsort() */
10774typedef struct
10775{
10776 listitem_T *item;
10777 int idx;
10778} sortItem_T;
10779
10780/* struct storing information about current sort */
10781typedef struct
10782{
10783 int item_compare_ic;
10784 int item_compare_numeric;
10785 int item_compare_numbers;
10786#ifdef FEAT_FLOAT
10787 int item_compare_float;
10788#endif
10789 char_u *item_compare_func;
10790 partial_T *item_compare_partial;
10791 dict_T *item_compare_selfdict;
10792 int item_compare_func_err;
10793 int item_compare_keep_zero;
10794} sortinfo_T;
10795static sortinfo_T *sortinfo = NULL;
10796static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10797#define ITEM_COMPARE_FAIL 999
10798
10799/*
10800 * Compare functions for f_sort() and f_uniq() below.
10801 */
10802 static int
10803#ifdef __BORLANDC__
10804_RTLENTRYF
10805#endif
10806item_compare(const void *s1, const void *s2)
10807{
10808 sortItem_T *si1, *si2;
10809 typval_T *tv1, *tv2;
10810 char_u *p1, *p2;
10811 char_u *tofree1 = NULL, *tofree2 = NULL;
10812 int res;
10813 char_u numbuf1[NUMBUFLEN];
10814 char_u numbuf2[NUMBUFLEN];
10815
10816 si1 = (sortItem_T *)s1;
10817 si2 = (sortItem_T *)s2;
10818 tv1 = &si1->item->li_tv;
10819 tv2 = &si2->item->li_tv;
10820
10821 if (sortinfo->item_compare_numbers)
10822 {
10823 varnumber_T v1 = get_tv_number(tv1);
10824 varnumber_T v2 = get_tv_number(tv2);
10825
10826 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10827 }
10828
10829#ifdef FEAT_FLOAT
10830 if (sortinfo->item_compare_float)
10831 {
10832 float_T v1 = get_tv_float(tv1);
10833 float_T v2 = get_tv_float(tv2);
10834
10835 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10836 }
10837#endif
10838
10839 /* tv2string() puts quotes around a string and allocates memory. Don't do
10840 * that for string variables. Use a single quote when comparing with a
10841 * non-string to do what the docs promise. */
10842 if (tv1->v_type == VAR_STRING)
10843 {
10844 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10845 p1 = (char_u *)"'";
10846 else
10847 p1 = tv1->vval.v_string;
10848 }
10849 else
10850 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10851 if (tv2->v_type == VAR_STRING)
10852 {
10853 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10854 p2 = (char_u *)"'";
10855 else
10856 p2 = tv2->vval.v_string;
10857 }
10858 else
10859 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10860 if (p1 == NULL)
10861 p1 = (char_u *)"";
10862 if (p2 == NULL)
10863 p2 = (char_u *)"";
10864 if (!sortinfo->item_compare_numeric)
10865 {
10866 if (sortinfo->item_compare_ic)
10867 res = STRICMP(p1, p2);
10868 else
10869 res = STRCMP(p1, p2);
10870 }
10871 else
10872 {
10873 double n1, n2;
10874 n1 = strtod((char *)p1, (char **)&p1);
10875 n2 = strtod((char *)p2, (char **)&p2);
10876 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10877 }
10878
10879 /* When the result would be zero, compare the item indexes. Makes the
10880 * sort stable. */
10881 if (res == 0 && !sortinfo->item_compare_keep_zero)
10882 res = si1->idx > si2->idx ? 1 : -1;
10883
10884 vim_free(tofree1);
10885 vim_free(tofree2);
10886 return res;
10887}
10888
10889 static int
10890#ifdef __BORLANDC__
10891_RTLENTRYF
10892#endif
10893item_compare2(const void *s1, const void *s2)
10894{
10895 sortItem_T *si1, *si2;
10896 int res;
10897 typval_T rettv;
10898 typval_T argv[3];
10899 int dummy;
10900 char_u *func_name;
10901 partial_T *partial = sortinfo->item_compare_partial;
10902
10903 /* shortcut after failure in previous call; compare all items equal */
10904 if (sortinfo->item_compare_func_err)
10905 return 0;
10906
10907 si1 = (sortItem_T *)s1;
10908 si2 = (sortItem_T *)s2;
10909
10910 if (partial == NULL)
10911 func_name = sortinfo->item_compare_func;
10912 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010913 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010914
10915 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10916 * in the copy without changing the original list items. */
10917 copy_tv(&si1->item->li_tv, &argv[0]);
10918 copy_tv(&si2->item->li_tv, &argv[1]);
10919
10920 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10921 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010922 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010923 partial, sortinfo->item_compare_selfdict);
10924 clear_tv(&argv[0]);
10925 clear_tv(&argv[1]);
10926
10927 if (res == FAIL)
10928 res = ITEM_COMPARE_FAIL;
10929 else
10930 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10931 if (sortinfo->item_compare_func_err)
10932 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10933 clear_tv(&rettv);
10934
10935 /* When the result would be zero, compare the pointers themselves. Makes
10936 * the sort stable. */
10937 if (res == 0 && !sortinfo->item_compare_keep_zero)
10938 res = si1->idx > si2->idx ? 1 : -1;
10939
10940 return res;
10941}
10942
10943/*
10944 * "sort({list})" function
10945 */
10946 static void
10947do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10948{
10949 list_T *l;
10950 listitem_T *li;
10951 sortItem_T *ptrs;
10952 sortinfo_T *old_sortinfo;
10953 sortinfo_T info;
10954 long len;
10955 long i;
10956
10957 /* Pointer to current info struct used in compare function. Save and
10958 * restore the current one for nested calls. */
10959 old_sortinfo = sortinfo;
10960 sortinfo = &info;
10961
10962 if (argvars[0].v_type != VAR_LIST)
10963 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10964 else
10965 {
10966 l = argvars[0].vval.v_list;
10967 if (l == NULL || tv_check_lock(l->lv_lock,
10968 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10969 TRUE))
10970 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010971 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010972
10973 len = list_len(l);
10974 if (len <= 1)
10975 goto theend; /* short list sorts pretty quickly */
10976
10977 info.item_compare_ic = FALSE;
10978 info.item_compare_numeric = FALSE;
10979 info.item_compare_numbers = FALSE;
10980#ifdef FEAT_FLOAT
10981 info.item_compare_float = FALSE;
10982#endif
10983 info.item_compare_func = NULL;
10984 info.item_compare_partial = NULL;
10985 info.item_compare_selfdict = NULL;
10986 if (argvars[1].v_type != VAR_UNKNOWN)
10987 {
10988 /* optional second argument: {func} */
10989 if (argvars[1].v_type == VAR_FUNC)
10990 info.item_compare_func = argvars[1].vval.v_string;
10991 else if (argvars[1].v_type == VAR_PARTIAL)
10992 info.item_compare_partial = argvars[1].vval.v_partial;
10993 else
10994 {
10995 int error = FALSE;
10996
10997 i = (long)get_tv_number_chk(&argvars[1], &error);
10998 if (error)
10999 goto theend; /* type error; errmsg already given */
11000 if (i == 1)
11001 info.item_compare_ic = TRUE;
11002 else if (argvars[1].v_type != VAR_NUMBER)
11003 info.item_compare_func = get_tv_string(&argvars[1]);
11004 else if (i != 0)
11005 {
11006 EMSG(_(e_invarg));
11007 goto theend;
11008 }
11009 if (info.item_compare_func != NULL)
11010 {
11011 if (*info.item_compare_func == NUL)
11012 {
11013 /* empty string means default sort */
11014 info.item_compare_func = NULL;
11015 }
11016 else if (STRCMP(info.item_compare_func, "n") == 0)
11017 {
11018 info.item_compare_func = NULL;
11019 info.item_compare_numeric = TRUE;
11020 }
11021 else if (STRCMP(info.item_compare_func, "N") == 0)
11022 {
11023 info.item_compare_func = NULL;
11024 info.item_compare_numbers = TRUE;
11025 }
11026#ifdef FEAT_FLOAT
11027 else if (STRCMP(info.item_compare_func, "f") == 0)
11028 {
11029 info.item_compare_func = NULL;
11030 info.item_compare_float = TRUE;
11031 }
11032#endif
11033 else if (STRCMP(info.item_compare_func, "i") == 0)
11034 {
11035 info.item_compare_func = NULL;
11036 info.item_compare_ic = TRUE;
11037 }
11038 }
11039 }
11040
11041 if (argvars[2].v_type != VAR_UNKNOWN)
11042 {
11043 /* optional third argument: {dict} */
11044 if (argvars[2].v_type != VAR_DICT)
11045 {
11046 EMSG(_(e_dictreq));
11047 goto theend;
11048 }
11049 info.item_compare_selfdict = argvars[2].vval.v_dict;
11050 }
11051 }
11052
11053 /* Make an array with each entry pointing to an item in the List. */
11054 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11055 if (ptrs == NULL)
11056 goto theend;
11057
11058 i = 0;
11059 if (sort)
11060 {
11061 /* sort(): ptrs will be the list to sort */
11062 for (li = l->lv_first; li != NULL; li = li->li_next)
11063 {
11064 ptrs[i].item = li;
11065 ptrs[i].idx = i;
11066 ++i;
11067 }
11068
11069 info.item_compare_func_err = FALSE;
11070 info.item_compare_keep_zero = FALSE;
11071 /* test the compare function */
11072 if ((info.item_compare_func != NULL
11073 || info.item_compare_partial != NULL)
11074 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11075 == ITEM_COMPARE_FAIL)
11076 EMSG(_("E702: Sort compare function failed"));
11077 else
11078 {
11079 /* Sort the array with item pointers. */
11080 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11081 info.item_compare_func == NULL
11082 && info.item_compare_partial == NULL
11083 ? item_compare : item_compare2);
11084
11085 if (!info.item_compare_func_err)
11086 {
11087 /* Clear the List and append the items in sorted order. */
11088 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11089 l->lv_len = 0;
11090 for (i = 0; i < len; ++i)
11091 list_append(l, ptrs[i].item);
11092 }
11093 }
11094 }
11095 else
11096 {
11097 int (*item_compare_func_ptr)(const void *, const void *);
11098
11099 /* f_uniq(): ptrs will be a stack of items to remove */
11100 info.item_compare_func_err = FALSE;
11101 info.item_compare_keep_zero = TRUE;
11102 item_compare_func_ptr = info.item_compare_func != NULL
11103 || info.item_compare_partial != NULL
11104 ? item_compare2 : item_compare;
11105
11106 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11107 li = li->li_next)
11108 {
11109 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11110 == 0)
11111 ptrs[i++].item = li;
11112 if (info.item_compare_func_err)
11113 {
11114 EMSG(_("E882: Uniq compare function failed"));
11115 break;
11116 }
11117 }
11118
11119 if (!info.item_compare_func_err)
11120 {
11121 while (--i >= 0)
11122 {
11123 li = ptrs[i].item->li_next;
11124 ptrs[i].item->li_next = li->li_next;
11125 if (li->li_next != NULL)
11126 li->li_next->li_prev = ptrs[i].item;
11127 else
11128 l->lv_last = ptrs[i].item;
11129 list_fix_watch(l, li);
11130 listitem_free(li);
11131 l->lv_len--;
11132 }
11133 }
11134 }
11135
11136 vim_free(ptrs);
11137 }
11138theend:
11139 sortinfo = old_sortinfo;
11140}
11141
11142/*
11143 * "sort({list})" function
11144 */
11145 static void
11146f_sort(typval_T *argvars, typval_T *rettv)
11147{
11148 do_sort_uniq(argvars, rettv, TRUE);
11149}
11150
11151/*
11152 * "uniq({list})" function
11153 */
11154 static void
11155f_uniq(typval_T *argvars, typval_T *rettv)
11156{
11157 do_sort_uniq(argvars, rettv, FALSE);
11158}
11159
11160/*
11161 * "soundfold({word})" function
11162 */
11163 static void
11164f_soundfold(typval_T *argvars, typval_T *rettv)
11165{
11166 char_u *s;
11167
11168 rettv->v_type = VAR_STRING;
11169 s = get_tv_string(&argvars[0]);
11170#ifdef FEAT_SPELL
11171 rettv->vval.v_string = eval_soundfold(s);
11172#else
11173 rettv->vval.v_string = vim_strsave(s);
11174#endif
11175}
11176
11177/*
11178 * "spellbadword()" function
11179 */
11180 static void
11181f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11182{
11183 char_u *word = (char_u *)"";
11184 hlf_T attr = HLF_COUNT;
11185 int len = 0;
11186
11187 if (rettv_list_alloc(rettv) == FAIL)
11188 return;
11189
11190#ifdef FEAT_SPELL
11191 if (argvars[0].v_type == VAR_UNKNOWN)
11192 {
11193 /* Find the start and length of the badly spelled word. */
11194 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11195 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011196 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011197 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011198 curwin->w_set_curswant = TRUE;
11199 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011200 }
11201 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11202 {
11203 char_u *str = get_tv_string_chk(&argvars[0]);
11204 int capcol = -1;
11205
11206 if (str != NULL)
11207 {
11208 /* Check the argument for spelling. */
11209 while (*str != NUL)
11210 {
11211 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11212 if (attr != HLF_COUNT)
11213 {
11214 word = str;
11215 break;
11216 }
11217 str += len;
11218 }
11219 }
11220 }
11221#endif
11222
11223 list_append_string(rettv->vval.v_list, word, len);
11224 list_append_string(rettv->vval.v_list, (char_u *)(
11225 attr == HLF_SPB ? "bad" :
11226 attr == HLF_SPR ? "rare" :
11227 attr == HLF_SPL ? "local" :
11228 attr == HLF_SPC ? "caps" :
11229 ""), -1);
11230}
11231
11232/*
11233 * "spellsuggest()" function
11234 */
11235 static void
11236f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11237{
11238#ifdef FEAT_SPELL
11239 char_u *str;
11240 int typeerr = FALSE;
11241 int maxcount;
11242 garray_T ga;
11243 int i;
11244 listitem_T *li;
11245 int need_capital = FALSE;
11246#endif
11247
11248 if (rettv_list_alloc(rettv) == FAIL)
11249 return;
11250
11251#ifdef FEAT_SPELL
11252 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11253 {
11254 str = get_tv_string(&argvars[0]);
11255 if (argvars[1].v_type != VAR_UNKNOWN)
11256 {
11257 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11258 if (maxcount <= 0)
11259 return;
11260 if (argvars[2].v_type != VAR_UNKNOWN)
11261 {
11262 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11263 if (typeerr)
11264 return;
11265 }
11266 }
11267 else
11268 maxcount = 25;
11269
11270 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11271
11272 for (i = 0; i < ga.ga_len; ++i)
11273 {
11274 str = ((char_u **)ga.ga_data)[i];
11275
11276 li = listitem_alloc();
11277 if (li == NULL)
11278 vim_free(str);
11279 else
11280 {
11281 li->li_tv.v_type = VAR_STRING;
11282 li->li_tv.v_lock = 0;
11283 li->li_tv.vval.v_string = str;
11284 list_append(rettv->vval.v_list, li);
11285 }
11286 }
11287 ga_clear(&ga);
11288 }
11289#endif
11290}
11291
11292 static void
11293f_split(typval_T *argvars, typval_T *rettv)
11294{
11295 char_u *str;
11296 char_u *end;
11297 char_u *pat = NULL;
11298 regmatch_T regmatch;
11299 char_u patbuf[NUMBUFLEN];
11300 char_u *save_cpo;
11301 int match;
11302 colnr_T col = 0;
11303 int keepempty = FALSE;
11304 int typeerr = FALSE;
11305
11306 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11307 save_cpo = p_cpo;
11308 p_cpo = (char_u *)"";
11309
11310 str = get_tv_string(&argvars[0]);
11311 if (argvars[1].v_type != VAR_UNKNOWN)
11312 {
11313 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11314 if (pat == NULL)
11315 typeerr = TRUE;
11316 if (argvars[2].v_type != VAR_UNKNOWN)
11317 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11318 }
11319 if (pat == NULL || *pat == NUL)
11320 pat = (char_u *)"[\\x01- ]\\+";
11321
11322 if (rettv_list_alloc(rettv) == FAIL)
11323 return;
11324 if (typeerr)
11325 return;
11326
11327 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11328 if (regmatch.regprog != NULL)
11329 {
11330 regmatch.rm_ic = FALSE;
11331 while (*str != NUL || keepempty)
11332 {
11333 if (*str == NUL)
11334 match = FALSE; /* empty item at the end */
11335 else
11336 match = vim_regexec_nl(&regmatch, str, col);
11337 if (match)
11338 end = regmatch.startp[0];
11339 else
11340 end = str + STRLEN(str);
11341 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11342 && *str != NUL && match && end < regmatch.endp[0]))
11343 {
11344 if (list_append_string(rettv->vval.v_list, str,
11345 (int)(end - str)) == FAIL)
11346 break;
11347 }
11348 if (!match)
11349 break;
11350 /* Advance to just after the match. */
11351 if (regmatch.endp[0] > str)
11352 col = 0;
11353 else
11354 {
11355 /* Don't get stuck at the same match. */
11356#ifdef FEAT_MBYTE
11357 col = (*mb_ptr2len)(regmatch.endp[0]);
11358#else
11359 col = 1;
11360#endif
11361 }
11362 str = regmatch.endp[0];
11363 }
11364
11365 vim_regfree(regmatch.regprog);
11366 }
11367
11368 p_cpo = save_cpo;
11369}
11370
11371#ifdef FEAT_FLOAT
11372/*
11373 * "sqrt()" function
11374 */
11375 static void
11376f_sqrt(typval_T *argvars, typval_T *rettv)
11377{
11378 float_T f = 0.0;
11379
11380 rettv->v_type = VAR_FLOAT;
11381 if (get_float_arg(argvars, &f) == OK)
11382 rettv->vval.v_float = sqrt(f);
11383 else
11384 rettv->vval.v_float = 0.0;
11385}
11386
11387/*
11388 * "str2float()" function
11389 */
11390 static void
11391f_str2float(typval_T *argvars, typval_T *rettv)
11392{
11393 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011394 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011395
Bram Moolenaar08243d22017-01-10 16:12:29 +010011396 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011397 p = skipwhite(p + 1);
11398 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011399 if (isneg)
11400 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011401 rettv->v_type = VAR_FLOAT;
11402}
11403#endif
11404
11405/*
11406 * "str2nr()" function
11407 */
11408 static void
11409f_str2nr(typval_T *argvars, typval_T *rettv)
11410{
11411 int base = 10;
11412 char_u *p;
11413 varnumber_T n;
11414 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011415 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011416
11417 if (argvars[1].v_type != VAR_UNKNOWN)
11418 {
11419 base = (int)get_tv_number(&argvars[1]);
11420 if (base != 2 && base != 8 && base != 10 && base != 16)
11421 {
11422 EMSG(_(e_invarg));
11423 return;
11424 }
11425 }
11426
11427 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011428 isneg = (*p == '-');
11429 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011430 p = skipwhite(p + 1);
11431 switch (base)
11432 {
11433 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11434 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11435 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11436 default: what = 0;
11437 }
11438 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011439 if (isneg)
11440 rettv->vval.v_number = -n;
11441 else
11442 rettv->vval.v_number = n;
11443
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011444}
11445
11446#ifdef HAVE_STRFTIME
11447/*
11448 * "strftime({format}[, {time}])" function
11449 */
11450 static void
11451f_strftime(typval_T *argvars, typval_T *rettv)
11452{
11453 char_u result_buf[256];
11454 struct tm *curtime;
11455 time_t seconds;
11456 char_u *p;
11457
11458 rettv->v_type = VAR_STRING;
11459
11460 p = get_tv_string(&argvars[0]);
11461 if (argvars[1].v_type == VAR_UNKNOWN)
11462 seconds = time(NULL);
11463 else
11464 seconds = (time_t)get_tv_number(&argvars[1]);
11465 curtime = localtime(&seconds);
11466 /* MSVC returns NULL for an invalid value of seconds. */
11467 if (curtime == NULL)
11468 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11469 else
11470 {
11471# ifdef FEAT_MBYTE
11472 vimconv_T conv;
11473 char_u *enc;
11474
11475 conv.vc_type = CONV_NONE;
11476 enc = enc_locale();
11477 convert_setup(&conv, p_enc, enc);
11478 if (conv.vc_type != CONV_NONE)
11479 p = string_convert(&conv, p, NULL);
11480# endif
11481 if (p != NULL)
11482 (void)strftime((char *)result_buf, sizeof(result_buf),
11483 (char *)p, curtime);
11484 else
11485 result_buf[0] = NUL;
11486
11487# ifdef FEAT_MBYTE
11488 if (conv.vc_type != CONV_NONE)
11489 vim_free(p);
11490 convert_setup(&conv, enc, p_enc);
11491 if (conv.vc_type != CONV_NONE)
11492 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11493 else
11494# endif
11495 rettv->vval.v_string = vim_strsave(result_buf);
11496
11497# ifdef FEAT_MBYTE
11498 /* Release conversion descriptors */
11499 convert_setup(&conv, NULL, NULL);
11500 vim_free(enc);
11501# endif
11502 }
11503}
11504#endif
11505
11506/*
11507 * "strgetchar()" function
11508 */
11509 static void
11510f_strgetchar(typval_T *argvars, typval_T *rettv)
11511{
11512 char_u *str;
11513 int len;
11514 int error = FALSE;
11515 int charidx;
11516
11517 rettv->vval.v_number = -1;
11518 str = get_tv_string_chk(&argvars[0]);
11519 if (str == NULL)
11520 return;
11521 len = (int)STRLEN(str);
11522 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11523 if (error)
11524 return;
11525#ifdef FEAT_MBYTE
11526 {
11527 int byteidx = 0;
11528
11529 while (charidx >= 0 && byteidx < len)
11530 {
11531 if (charidx == 0)
11532 {
11533 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11534 break;
11535 }
11536 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011537 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011538 }
11539 }
11540#else
11541 if (charidx < len)
11542 rettv->vval.v_number = str[charidx];
11543#endif
11544}
11545
11546/*
11547 * "stridx()" function
11548 */
11549 static void
11550f_stridx(typval_T *argvars, typval_T *rettv)
11551{
11552 char_u buf[NUMBUFLEN];
11553 char_u *needle;
11554 char_u *haystack;
11555 char_u *save_haystack;
11556 char_u *pos;
11557 int start_idx;
11558
11559 needle = get_tv_string_chk(&argvars[1]);
11560 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11561 rettv->vval.v_number = -1;
11562 if (needle == NULL || haystack == NULL)
11563 return; /* type error; errmsg already given */
11564
11565 if (argvars[2].v_type != VAR_UNKNOWN)
11566 {
11567 int error = FALSE;
11568
11569 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11570 if (error || start_idx >= (int)STRLEN(haystack))
11571 return;
11572 if (start_idx >= 0)
11573 haystack += start_idx;
11574 }
11575
11576 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11577 if (pos != NULL)
11578 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11579}
11580
11581/*
11582 * "string()" function
11583 */
11584 static void
11585f_string(typval_T *argvars, typval_T *rettv)
11586{
11587 char_u *tofree;
11588 char_u numbuf[NUMBUFLEN];
11589
11590 rettv->v_type = VAR_STRING;
11591 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11592 get_copyID());
11593 /* Make a copy if we have a value but it's not in allocated memory. */
11594 if (rettv->vval.v_string != NULL && tofree == NULL)
11595 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11596}
11597
11598/*
11599 * "strlen()" function
11600 */
11601 static void
11602f_strlen(typval_T *argvars, typval_T *rettv)
11603{
11604 rettv->vval.v_number = (varnumber_T)(STRLEN(
11605 get_tv_string(&argvars[0])));
11606}
11607
11608/*
11609 * "strchars()" function
11610 */
11611 static void
11612f_strchars(typval_T *argvars, typval_T *rettv)
11613{
11614 char_u *s = get_tv_string(&argvars[0]);
11615 int skipcc = 0;
11616#ifdef FEAT_MBYTE
11617 varnumber_T len = 0;
11618 int (*func_mb_ptr2char_adv)(char_u **pp);
11619#endif
11620
11621 if (argvars[1].v_type != VAR_UNKNOWN)
11622 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11623 if (skipcc < 0 || skipcc > 1)
11624 EMSG(_(e_invarg));
11625 else
11626 {
11627#ifdef FEAT_MBYTE
11628 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11629 while (*s != NUL)
11630 {
11631 func_mb_ptr2char_adv(&s);
11632 ++len;
11633 }
11634 rettv->vval.v_number = len;
11635#else
11636 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11637#endif
11638 }
11639}
11640
11641/*
11642 * "strdisplaywidth()" function
11643 */
11644 static void
11645f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11646{
11647 char_u *s = get_tv_string(&argvars[0]);
11648 int col = 0;
11649
11650 if (argvars[1].v_type != VAR_UNKNOWN)
11651 col = (int)get_tv_number(&argvars[1]);
11652
11653 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11654}
11655
11656/*
11657 * "strwidth()" function
11658 */
11659 static void
11660f_strwidth(typval_T *argvars, typval_T *rettv)
11661{
11662 char_u *s = get_tv_string(&argvars[0]);
11663
11664 rettv->vval.v_number = (varnumber_T)(
11665#ifdef FEAT_MBYTE
11666 mb_string2cells(s, -1)
11667#else
11668 STRLEN(s)
11669#endif
11670 );
11671}
11672
11673/*
11674 * "strcharpart()" function
11675 */
11676 static void
11677f_strcharpart(typval_T *argvars, typval_T *rettv)
11678{
11679#ifdef FEAT_MBYTE
11680 char_u *p;
11681 int nchar;
11682 int nbyte = 0;
11683 int charlen;
11684 int len = 0;
11685 int slen;
11686 int error = FALSE;
11687
11688 p = get_tv_string(&argvars[0]);
11689 slen = (int)STRLEN(p);
11690
11691 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11692 if (!error)
11693 {
11694 if (nchar > 0)
11695 while (nchar > 0 && nbyte < slen)
11696 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011697 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011698 --nchar;
11699 }
11700 else
11701 nbyte = nchar;
11702 if (argvars[2].v_type != VAR_UNKNOWN)
11703 {
11704 charlen = (int)get_tv_number(&argvars[2]);
11705 while (charlen > 0 && nbyte + len < slen)
11706 {
11707 int off = nbyte + len;
11708
11709 if (off < 0)
11710 len += 1;
11711 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011712 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011713 --charlen;
11714 }
11715 }
11716 else
11717 len = slen - nbyte; /* default: all bytes that are available. */
11718 }
11719
11720 /*
11721 * Only return the overlap between the specified part and the actual
11722 * string.
11723 */
11724 if (nbyte < 0)
11725 {
11726 len += nbyte;
11727 nbyte = 0;
11728 }
11729 else if (nbyte > slen)
11730 nbyte = slen;
11731 if (len < 0)
11732 len = 0;
11733 else if (nbyte + len > slen)
11734 len = slen - nbyte;
11735
11736 rettv->v_type = VAR_STRING;
11737 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11738#else
11739 f_strpart(argvars, rettv);
11740#endif
11741}
11742
11743/*
11744 * "strpart()" function
11745 */
11746 static void
11747f_strpart(typval_T *argvars, typval_T *rettv)
11748{
11749 char_u *p;
11750 int n;
11751 int len;
11752 int slen;
11753 int error = FALSE;
11754
11755 p = get_tv_string(&argvars[0]);
11756 slen = (int)STRLEN(p);
11757
11758 n = (int)get_tv_number_chk(&argvars[1], &error);
11759 if (error)
11760 len = 0;
11761 else if (argvars[2].v_type != VAR_UNKNOWN)
11762 len = (int)get_tv_number(&argvars[2]);
11763 else
11764 len = slen - n; /* default len: all bytes that are available. */
11765
11766 /*
11767 * Only return the overlap between the specified part and the actual
11768 * string.
11769 */
11770 if (n < 0)
11771 {
11772 len += n;
11773 n = 0;
11774 }
11775 else if (n > slen)
11776 n = slen;
11777 if (len < 0)
11778 len = 0;
11779 else if (n + len > slen)
11780 len = slen - n;
11781
11782 rettv->v_type = VAR_STRING;
11783 rettv->vval.v_string = vim_strnsave(p + n, len);
11784}
11785
11786/*
11787 * "strridx()" function
11788 */
11789 static void
11790f_strridx(typval_T *argvars, typval_T *rettv)
11791{
11792 char_u buf[NUMBUFLEN];
11793 char_u *needle;
11794 char_u *haystack;
11795 char_u *rest;
11796 char_u *lastmatch = NULL;
11797 int haystack_len, end_idx;
11798
11799 needle = get_tv_string_chk(&argvars[1]);
11800 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11801
11802 rettv->vval.v_number = -1;
11803 if (needle == NULL || haystack == NULL)
11804 return; /* type error; errmsg already given */
11805
11806 haystack_len = (int)STRLEN(haystack);
11807 if (argvars[2].v_type != VAR_UNKNOWN)
11808 {
11809 /* Third argument: upper limit for index */
11810 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11811 if (end_idx < 0)
11812 return; /* can never find a match */
11813 }
11814 else
11815 end_idx = haystack_len;
11816
11817 if (*needle == NUL)
11818 {
11819 /* Empty string matches past the end. */
11820 lastmatch = haystack + end_idx;
11821 }
11822 else
11823 {
11824 for (rest = haystack; *rest != '\0'; ++rest)
11825 {
11826 rest = (char_u *)strstr((char *)rest, (char *)needle);
11827 if (rest == NULL || rest > haystack + end_idx)
11828 break;
11829 lastmatch = rest;
11830 }
11831 }
11832
11833 if (lastmatch == NULL)
11834 rettv->vval.v_number = -1;
11835 else
11836 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11837}
11838
11839/*
11840 * "strtrans()" function
11841 */
11842 static void
11843f_strtrans(typval_T *argvars, typval_T *rettv)
11844{
11845 rettv->v_type = VAR_STRING;
11846 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11847}
11848
11849/*
11850 * "submatch()" function
11851 */
11852 static void
11853f_submatch(typval_T *argvars, typval_T *rettv)
11854{
11855 int error = FALSE;
11856 int no;
11857 int retList = 0;
11858
11859 no = (int)get_tv_number_chk(&argvars[0], &error);
11860 if (error)
11861 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011862 if (no < 0 || no >= NSUBEXP)
11863 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010011864 EMSGN(_("E935: invalid submatch number: %d"), no);
11865 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011866 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011867 if (argvars[1].v_type != VAR_UNKNOWN)
11868 retList = (int)get_tv_number_chk(&argvars[1], &error);
11869 if (error)
11870 return;
11871
11872 if (retList == 0)
11873 {
11874 rettv->v_type = VAR_STRING;
11875 rettv->vval.v_string = reg_submatch(no);
11876 }
11877 else
11878 {
11879 rettv->v_type = VAR_LIST;
11880 rettv->vval.v_list = reg_submatch_list(no);
11881 }
11882}
11883
11884/*
11885 * "substitute()" function
11886 */
11887 static void
11888f_substitute(typval_T *argvars, typval_T *rettv)
11889{
11890 char_u patbuf[NUMBUFLEN];
11891 char_u subbuf[NUMBUFLEN];
11892 char_u flagsbuf[NUMBUFLEN];
11893
11894 char_u *str = get_tv_string_chk(&argvars[0]);
11895 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011896 char_u *sub = NULL;
11897 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011898 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11899
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011900 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11901 expr = &argvars[2];
11902 else
11903 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11904
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011905 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011906 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11907 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011908 rettv->vval.v_string = NULL;
11909 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011910 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011911}
11912
11913/*
11914 * "synID(lnum, col, trans)" function
11915 */
11916 static void
11917f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11918{
11919 int id = 0;
11920#ifdef FEAT_SYN_HL
11921 linenr_T lnum;
11922 colnr_T col;
11923 int trans;
11924 int transerr = FALSE;
11925
11926 lnum = get_tv_lnum(argvars); /* -1 on type error */
11927 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11928 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11929
11930 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11931 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11932 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11933#endif
11934
11935 rettv->vval.v_number = id;
11936}
11937
11938/*
11939 * "synIDattr(id, what [, mode])" function
11940 */
11941 static void
11942f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11943{
11944 char_u *p = NULL;
11945#ifdef FEAT_SYN_HL
11946 int id;
11947 char_u *what;
11948 char_u *mode;
11949 char_u modebuf[NUMBUFLEN];
11950 int modec;
11951
11952 id = (int)get_tv_number(&argvars[0]);
11953 what = get_tv_string(&argvars[1]);
11954 if (argvars[2].v_type != VAR_UNKNOWN)
11955 {
11956 mode = get_tv_string_buf(&argvars[2], modebuf);
11957 modec = TOLOWER_ASC(mode[0]);
11958 if (modec != 't' && modec != 'c' && modec != 'g')
11959 modec = 0; /* replace invalid with current */
11960 }
11961 else
11962 {
11963#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11964 if (USE_24BIT)
11965 modec = 'g';
11966 else
11967#endif
11968 if (t_colors > 1)
11969 modec = 'c';
11970 else
11971 modec = 't';
11972 }
11973
11974
11975 switch (TOLOWER_ASC(what[0]))
11976 {
11977 case 'b':
11978 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11979 p = highlight_color(id, what, modec);
11980 else /* bold */
11981 p = highlight_has_attr(id, HL_BOLD, modec);
11982 break;
11983
11984 case 'f': /* fg[#] or font */
11985 p = highlight_color(id, what, modec);
11986 break;
11987
11988 case 'i':
11989 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11990 p = highlight_has_attr(id, HL_INVERSE, modec);
11991 else /* italic */
11992 p = highlight_has_attr(id, HL_ITALIC, modec);
11993 break;
11994
11995 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011996 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011997 break;
11998
11999 case 'r': /* reverse */
12000 p = highlight_has_attr(id, HL_INVERSE, modec);
12001 break;
12002
12003 case 's':
12004 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12005 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012006 /* strikeout */
12007 else if (TOLOWER_ASC(what[1]) == 't' &&
12008 TOLOWER_ASC(what[2]) == 'r')
12009 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012010 else /* standout */
12011 p = highlight_has_attr(id, HL_STANDOUT, modec);
12012 break;
12013
12014 case 'u':
12015 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12016 /* underline */
12017 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12018 else
12019 /* undercurl */
12020 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12021 break;
12022 }
12023
12024 if (p != NULL)
12025 p = vim_strsave(p);
12026#endif
12027 rettv->v_type = VAR_STRING;
12028 rettv->vval.v_string = p;
12029}
12030
12031/*
12032 * "synIDtrans(id)" function
12033 */
12034 static void
12035f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12036{
12037 int id;
12038
12039#ifdef FEAT_SYN_HL
12040 id = (int)get_tv_number(&argvars[0]);
12041
12042 if (id > 0)
12043 id = syn_get_final_id(id);
12044 else
12045#endif
12046 id = 0;
12047
12048 rettv->vval.v_number = id;
12049}
12050
12051/*
12052 * "synconcealed(lnum, col)" function
12053 */
12054 static void
12055f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12056{
12057#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12058 linenr_T lnum;
12059 colnr_T col;
12060 int syntax_flags = 0;
12061 int cchar;
12062 int matchid = 0;
12063 char_u str[NUMBUFLEN];
12064#endif
12065
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012066 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012067
12068#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12069 lnum = get_tv_lnum(argvars); /* -1 on type error */
12070 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12071
12072 vim_memset(str, NUL, sizeof(str));
12073
12074 if (rettv_list_alloc(rettv) != FAIL)
12075 {
12076 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12077 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12078 && curwin->w_p_cole > 0)
12079 {
12080 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12081 syntax_flags = get_syntax_info(&matchid);
12082
12083 /* get the conceal character */
12084 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12085 {
12086 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012087 if (cchar == NUL && curwin->w_p_cole == 1)
12088 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012089 if (cchar != NUL)
12090 {
12091# ifdef FEAT_MBYTE
12092 if (has_mbyte)
12093 (*mb_char2bytes)(cchar, str);
12094 else
12095# endif
12096 str[0] = cchar;
12097 }
12098 }
12099 }
12100
12101 list_append_number(rettv->vval.v_list,
12102 (syntax_flags & HL_CONCEAL) != 0);
12103 /* -1 to auto-determine strlen */
12104 list_append_string(rettv->vval.v_list, str, -1);
12105 list_append_number(rettv->vval.v_list, matchid);
12106 }
12107#endif
12108}
12109
12110/*
12111 * "synstack(lnum, col)" function
12112 */
12113 static void
12114f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12115{
12116#ifdef FEAT_SYN_HL
12117 linenr_T lnum;
12118 colnr_T col;
12119 int i;
12120 int id;
12121#endif
12122
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012123 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012124
12125#ifdef FEAT_SYN_HL
12126 lnum = get_tv_lnum(argvars); /* -1 on type error */
12127 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12128
12129 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12130 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12131 && rettv_list_alloc(rettv) != FAIL)
12132 {
12133 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12134 for (i = 0; ; ++i)
12135 {
12136 id = syn_get_stack_item(i);
12137 if (id < 0)
12138 break;
12139 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12140 break;
12141 }
12142 }
12143#endif
12144}
12145
12146 static void
12147get_cmd_output_as_rettv(
12148 typval_T *argvars,
12149 typval_T *rettv,
12150 int retlist)
12151{
12152 char_u *res = NULL;
12153 char_u *p;
12154 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012155 int err = FALSE;
12156 FILE *fd;
12157 list_T *list = NULL;
12158 int flags = SHELL_SILENT;
12159
12160 rettv->v_type = VAR_STRING;
12161 rettv->vval.v_string = NULL;
12162 if (check_restricted() || check_secure())
12163 goto errret;
12164
12165 if (argvars[1].v_type != VAR_UNKNOWN)
12166 {
12167 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012168 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012169 * command.
12170 */
12171 if ((infile = vim_tempname('i', TRUE)) == NULL)
12172 {
12173 EMSG(_(e_notmp));
12174 goto errret;
12175 }
12176
12177 fd = mch_fopen((char *)infile, WRITEBIN);
12178 if (fd == NULL)
12179 {
12180 EMSG2(_(e_notopen), infile);
12181 goto errret;
12182 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012183 if (argvars[1].v_type == VAR_NUMBER)
12184 {
12185 linenr_T lnum;
12186 buf_T *buf;
12187
12188 buf = buflist_findnr(argvars[1].vval.v_number);
12189 if (buf == NULL)
12190 {
12191 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012192 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012193 goto errret;
12194 }
12195
12196 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12197 {
12198 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12199 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12200 {
12201 err = TRUE;
12202 break;
12203 }
12204 if (putc(NL, fd) == EOF)
12205 {
12206 err = TRUE;
12207 break;
12208 }
12209 }
12210 }
12211 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012212 {
12213 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12214 err = TRUE;
12215 }
12216 else
12217 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012218 size_t len;
12219 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012220
12221 p = get_tv_string_buf_chk(&argvars[1], buf);
12222 if (p == NULL)
12223 {
12224 fclose(fd);
12225 goto errret; /* type error; errmsg already given */
12226 }
12227 len = STRLEN(p);
12228 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12229 err = TRUE;
12230 }
12231 if (fclose(fd) != 0)
12232 err = TRUE;
12233 if (err)
12234 {
12235 EMSG(_("E677: Error writing temp file"));
12236 goto errret;
12237 }
12238 }
12239
12240 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12241 * echoes typeahead, that messes up the display. */
12242 if (!msg_silent)
12243 flags += SHELL_COOKED;
12244
12245 if (retlist)
12246 {
12247 int len;
12248 listitem_T *li;
12249 char_u *s = NULL;
12250 char_u *start;
12251 char_u *end;
12252 int i;
12253
12254 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12255 if (res == NULL)
12256 goto errret;
12257
12258 list = list_alloc();
12259 if (list == NULL)
12260 goto errret;
12261
12262 for (i = 0; i < len; ++i)
12263 {
12264 start = res + i;
12265 while (i < len && res[i] != NL)
12266 ++i;
12267 end = res + i;
12268
12269 s = alloc((unsigned)(end - start + 1));
12270 if (s == NULL)
12271 goto errret;
12272
12273 for (p = s; start < end; ++p, ++start)
12274 *p = *start == NUL ? NL : *start;
12275 *p = NUL;
12276
12277 li = listitem_alloc();
12278 if (li == NULL)
12279 {
12280 vim_free(s);
12281 goto errret;
12282 }
12283 li->li_tv.v_type = VAR_STRING;
12284 li->li_tv.v_lock = 0;
12285 li->li_tv.vval.v_string = s;
12286 list_append(list, li);
12287 }
12288
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012289 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012290 list = NULL;
12291 }
12292 else
12293 {
12294 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12295#ifdef USE_CR
12296 /* translate <CR> into <NL> */
12297 if (res != NULL)
12298 {
12299 char_u *s;
12300
12301 for (s = res; *s; ++s)
12302 {
12303 if (*s == CAR)
12304 *s = NL;
12305 }
12306 }
12307#else
12308# ifdef USE_CRNL
12309 /* translate <CR><NL> into <NL> */
12310 if (res != NULL)
12311 {
12312 char_u *s, *d;
12313
12314 d = res;
12315 for (s = res; *s; ++s)
12316 {
12317 if (s[0] == CAR && s[1] == NL)
12318 ++s;
12319 *d++ = *s;
12320 }
12321 *d = NUL;
12322 }
12323# endif
12324#endif
12325 rettv->vval.v_string = res;
12326 res = NULL;
12327 }
12328
12329errret:
12330 if (infile != NULL)
12331 {
12332 mch_remove(infile);
12333 vim_free(infile);
12334 }
12335 if (res != NULL)
12336 vim_free(res);
12337 if (list != NULL)
12338 list_free(list);
12339}
12340
12341/*
12342 * "system()" function
12343 */
12344 static void
12345f_system(typval_T *argvars, typval_T *rettv)
12346{
12347 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12348}
12349
12350/*
12351 * "systemlist()" function
12352 */
12353 static void
12354f_systemlist(typval_T *argvars, typval_T *rettv)
12355{
12356 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12357}
12358
12359/*
12360 * "tabpagebuflist()" function
12361 */
12362 static void
12363f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12364{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012365 tabpage_T *tp;
12366 win_T *wp = NULL;
12367
12368 if (argvars[0].v_type == VAR_UNKNOWN)
12369 wp = firstwin;
12370 else
12371 {
12372 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12373 if (tp != NULL)
12374 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12375 }
12376 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12377 {
12378 for (; wp != NULL; wp = wp->w_next)
12379 if (list_append_number(rettv->vval.v_list,
12380 wp->w_buffer->b_fnum) == FAIL)
12381 break;
12382 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012383}
12384
12385
12386/*
12387 * "tabpagenr()" function
12388 */
12389 static void
12390f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12391{
12392 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012393 char_u *arg;
12394
12395 if (argvars[0].v_type != VAR_UNKNOWN)
12396 {
12397 arg = get_tv_string_chk(&argvars[0]);
12398 nr = 0;
12399 if (arg != NULL)
12400 {
12401 if (STRCMP(arg, "$") == 0)
12402 nr = tabpage_index(NULL) - 1;
12403 else
12404 EMSG2(_(e_invexpr2), arg);
12405 }
12406 }
12407 else
12408 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012409 rettv->vval.v_number = nr;
12410}
12411
12412
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012413static int get_winnr(tabpage_T *tp, typval_T *argvar);
12414
12415/*
12416 * Common code for tabpagewinnr() and winnr().
12417 */
12418 static int
12419get_winnr(tabpage_T *tp, typval_T *argvar)
12420{
12421 win_T *twin;
12422 int nr = 1;
12423 win_T *wp;
12424 char_u *arg;
12425
12426 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12427 if (argvar->v_type != VAR_UNKNOWN)
12428 {
12429 arg = get_tv_string_chk(argvar);
12430 if (arg == NULL)
12431 nr = 0; /* type error; errmsg already given */
12432 else if (STRCMP(arg, "$") == 0)
12433 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12434 else if (STRCMP(arg, "#") == 0)
12435 {
12436 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12437 if (twin == NULL)
12438 nr = 0;
12439 }
12440 else
12441 {
12442 EMSG2(_(e_invexpr2), arg);
12443 nr = 0;
12444 }
12445 }
12446
12447 if (nr > 0)
12448 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12449 wp != twin; wp = wp->w_next)
12450 {
12451 if (wp == NULL)
12452 {
12453 /* didn't find it in this tabpage */
12454 nr = 0;
12455 break;
12456 }
12457 ++nr;
12458 }
12459 return nr;
12460}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012461
12462/*
12463 * "tabpagewinnr()" function
12464 */
12465 static void
12466f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12467{
12468 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012469 tabpage_T *tp;
12470
12471 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12472 if (tp == NULL)
12473 nr = 0;
12474 else
12475 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012476 rettv->vval.v_number = nr;
12477}
12478
12479
12480/*
12481 * "tagfiles()" function
12482 */
12483 static void
12484f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12485{
12486 char_u *fname;
12487 tagname_T tn;
12488 int first;
12489
12490 if (rettv_list_alloc(rettv) == FAIL)
12491 return;
12492 fname = alloc(MAXPATHL);
12493 if (fname == NULL)
12494 return;
12495
12496 for (first = TRUE; ; first = FALSE)
12497 if (get_tagfname(&tn, first, fname) == FAIL
12498 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12499 break;
12500 tagname_free(&tn);
12501 vim_free(fname);
12502}
12503
12504/*
12505 * "taglist()" function
12506 */
12507 static void
12508f_taglist(typval_T *argvars, typval_T *rettv)
12509{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012510 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012511 char_u *tag_pattern;
12512
12513 tag_pattern = get_tv_string(&argvars[0]);
12514
12515 rettv->vval.v_number = FALSE;
12516 if (*tag_pattern == NUL)
12517 return;
12518
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012519 if (argvars[1].v_type != VAR_UNKNOWN)
12520 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012521 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012522 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012523}
12524
12525/*
12526 * "tempname()" function
12527 */
12528 static void
12529f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12530{
12531 static int x = 'A';
12532
12533 rettv->v_type = VAR_STRING;
12534 rettv->vval.v_string = vim_tempname(x, FALSE);
12535
12536 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12537 * names. Skip 'I' and 'O', they are used for shell redirection. */
12538 do
12539 {
12540 if (x == 'Z')
12541 x = '0';
12542 else if (x == '9')
12543 x = 'A';
12544 else
12545 {
12546#ifdef EBCDIC
12547 if (x == 'I')
12548 x = 'J';
12549 else if (x == 'R')
12550 x = 'S';
12551 else
12552#endif
12553 ++x;
12554 }
12555 } while (x == 'I' || x == 'O');
12556}
12557
12558#ifdef FEAT_FLOAT
12559/*
12560 * "tan()" function
12561 */
12562 static void
12563f_tan(typval_T *argvars, typval_T *rettv)
12564{
12565 float_T f = 0.0;
12566
12567 rettv->v_type = VAR_FLOAT;
12568 if (get_float_arg(argvars, &f) == OK)
12569 rettv->vval.v_float = tan(f);
12570 else
12571 rettv->vval.v_float = 0.0;
12572}
12573
12574/*
12575 * "tanh()" function
12576 */
12577 static void
12578f_tanh(typval_T *argvars, typval_T *rettv)
12579{
12580 float_T f = 0.0;
12581
12582 rettv->v_type = VAR_FLOAT;
12583 if (get_float_arg(argvars, &f) == OK)
12584 rettv->vval.v_float = tanh(f);
12585 else
12586 rettv->vval.v_float = 0.0;
12587}
12588#endif
12589
12590/*
12591 * "test_alloc_fail(id, countdown, repeat)" function
12592 */
12593 static void
12594f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12595{
12596 if (argvars[0].v_type != VAR_NUMBER
12597 || argvars[0].vval.v_number <= 0
12598 || argvars[1].v_type != VAR_NUMBER
12599 || argvars[1].vval.v_number < 0
12600 || argvars[2].v_type != VAR_NUMBER)
12601 EMSG(_(e_invarg));
12602 else
12603 {
12604 alloc_fail_id = argvars[0].vval.v_number;
12605 if (alloc_fail_id >= aid_last)
12606 EMSG(_(e_invarg));
12607 alloc_fail_countdown = argvars[1].vval.v_number;
12608 alloc_fail_repeat = argvars[2].vval.v_number;
12609 did_outofmem_msg = FALSE;
12610 }
12611}
12612
12613/*
12614 * "test_autochdir()"
12615 */
12616 static void
12617f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12618{
12619#if defined(FEAT_AUTOCHDIR)
12620 test_autochdir = TRUE;
12621#endif
12622}
12623
12624/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012625 * "test_feedinput()"
12626 */
12627 static void
12628f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12629{
12630#ifdef USE_INPUT_BUF
12631 char_u *val = get_tv_string_chk(&argvars[0]);
12632
12633 if (val != NULL)
12634 {
12635 trash_input_buf();
12636 add_to_input_buf_csi(val, (int)STRLEN(val));
12637 }
12638#endif
12639}
12640
12641/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012642 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012643 */
12644 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012645f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012646{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012647 char_u *name = (char_u *)"";
12648 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012649 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012650
12651 if (argvars[0].v_type != VAR_STRING
12652 || (argvars[1].v_type) != VAR_NUMBER)
12653 EMSG(_(e_invarg));
12654 else
12655 {
12656 name = get_tv_string_chk(&argvars[0]);
12657 val = (int)get_tv_number(&argvars[1]);
12658
12659 if (STRCMP(name, (char_u *)"redraw") == 0)
12660 disable_redraw_for_testing = val;
12661 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12662 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012663 else if (STRCMP(name, (char_u *)"starting") == 0)
12664 {
12665 if (val)
12666 {
12667 if (save_starting < 0)
12668 save_starting = starting;
12669 starting = 0;
12670 }
12671 else
12672 {
12673 starting = save_starting;
12674 save_starting = -1;
12675 }
12676 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012677 else if (STRCMP(name, (char_u *)"ALL") == 0)
12678 {
12679 disable_char_avail_for_testing = FALSE;
12680 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012681 if (save_starting >= 0)
12682 {
12683 starting = save_starting;
12684 save_starting = -1;
12685 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012686 }
12687 else
12688 EMSG2(_(e_invarg2), name);
12689 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012690}
12691
12692/*
12693 * "test_garbagecollect_now()" function
12694 */
12695 static void
12696f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12697{
12698 /* This is dangerous, any Lists and Dicts used internally may be freed
12699 * while still in use. */
12700 garbage_collect(TRUE);
12701}
12702
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012703/*
12704 * "test_ignore_error()" function
12705 */
12706 static void
12707f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12708{
12709 ignore_error_for_testing(get_tv_string(&argvars[0]));
12710}
12711
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012712#ifdef FEAT_JOB_CHANNEL
12713 static void
12714f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12715{
12716 rettv->v_type = VAR_CHANNEL;
12717 rettv->vval.v_channel = NULL;
12718}
12719#endif
12720
12721 static void
12722f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12723{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012724 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012725}
12726
12727#ifdef FEAT_JOB_CHANNEL
12728 static void
12729f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12730{
12731 rettv->v_type = VAR_JOB;
12732 rettv->vval.v_job = NULL;
12733}
12734#endif
12735
12736 static void
12737f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12738{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012739 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012740}
12741
12742 static void
12743f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12744{
12745 rettv->v_type = VAR_PARTIAL;
12746 rettv->vval.v_partial = NULL;
12747}
12748
12749 static void
12750f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12751{
12752 rettv->v_type = VAR_STRING;
12753 rettv->vval.v_string = NULL;
12754}
12755
12756 static void
12757f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12758{
12759 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12760}
12761
12762#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12763/*
12764 * Get a callback from "arg". It can be a Funcref or a function name.
12765 * When "arg" is zero return an empty string.
12766 * Return NULL for an invalid argument.
12767 */
12768 char_u *
12769get_callback(typval_T *arg, partial_T **pp)
12770{
12771 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12772 {
12773 *pp = arg->vval.v_partial;
12774 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012775 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012776 }
12777 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012778 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012779 {
12780 func_ref(arg->vval.v_string);
12781 return arg->vval.v_string;
12782 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012783 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12784 return (char_u *)"";
12785 EMSG(_("E921: Invalid callback argument"));
12786 return NULL;
12787}
12788
12789/*
12790 * Unref/free "callback" and "partial" retured by get_callback().
12791 */
12792 void
12793free_callback(char_u *callback, partial_T *partial)
12794{
12795 if (partial != NULL)
12796 partial_unref(partial);
12797 else if (callback != NULL)
12798 {
12799 func_unref(callback);
12800 vim_free(callback);
12801 }
12802}
12803#endif
12804
12805#ifdef FEAT_TIMERS
12806/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012807 * "timer_info([timer])" function
12808 */
12809 static void
12810f_timer_info(typval_T *argvars, typval_T *rettv)
12811{
12812 timer_T *timer = NULL;
12813
12814 if (rettv_list_alloc(rettv) != OK)
12815 return;
12816 if (argvars[0].v_type != VAR_UNKNOWN)
12817 {
12818 if (argvars[0].v_type != VAR_NUMBER)
12819 EMSG(_(e_number_exp));
12820 else
12821 {
12822 timer = find_timer((int)get_tv_number(&argvars[0]));
12823 if (timer != NULL)
12824 add_timer_info(rettv, timer);
12825 }
12826 }
12827 else
12828 add_timer_info_all(rettv);
12829}
12830
12831/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012832 * "timer_pause(timer, paused)" function
12833 */
12834 static void
12835f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12836{
12837 timer_T *timer = NULL;
12838 int paused = (int)get_tv_number(&argvars[1]);
12839
12840 if (argvars[0].v_type != VAR_NUMBER)
12841 EMSG(_(e_number_exp));
12842 else
12843 {
12844 timer = find_timer((int)get_tv_number(&argvars[0]));
12845 if (timer != NULL)
12846 timer->tr_paused = paused;
12847 }
12848}
12849
12850/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012851 * "timer_start(time, callback [, options])" function
12852 */
12853 static void
12854f_timer_start(typval_T *argvars, typval_T *rettv)
12855{
Bram Moolenaar75537a92016-09-05 22:45:28 +020012856 long msec = (long)get_tv_number(&argvars[0]);
12857 timer_T *timer;
12858 int repeat = 0;
12859 char_u *callback;
12860 dict_T *dict;
12861 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012862
Bram Moolenaar75537a92016-09-05 22:45:28 +020012863 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012864 if (check_secure())
12865 return;
12866 if (argvars[2].v_type != VAR_UNKNOWN)
12867 {
12868 if (argvars[2].v_type != VAR_DICT
12869 || (dict = argvars[2].vval.v_dict) == NULL)
12870 {
12871 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12872 return;
12873 }
12874 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12875 repeat = get_dict_number(dict, (char_u *)"repeat");
12876 }
12877
Bram Moolenaar75537a92016-09-05 22:45:28 +020012878 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012879 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012880 return;
12881
12882 timer = create_timer(msec, repeat);
12883 if (timer == NULL)
12884 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012885 else
12886 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020012887 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020012888 timer->tr_callback = vim_strsave(callback);
12889 else
12890 /* pointer into the partial */
12891 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012892 timer->tr_partial = partial;
12893 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012894 }
12895}
12896
12897/*
12898 * "timer_stop(timer)" function
12899 */
12900 static void
12901f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12902{
12903 timer_T *timer;
12904
12905 if (argvars[0].v_type != VAR_NUMBER)
12906 {
12907 EMSG(_(e_number_exp));
12908 return;
12909 }
12910 timer = find_timer((int)get_tv_number(&argvars[0]));
12911 if (timer != NULL)
12912 stop_timer(timer);
12913}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012914
12915/*
12916 * "timer_stopall()" function
12917 */
12918 static void
12919f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12920{
12921 stop_all_timers();
12922}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012923#endif
12924
12925/*
12926 * "tolower(string)" function
12927 */
12928 static void
12929f_tolower(typval_T *argvars, typval_T *rettv)
12930{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012931 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010012932 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012933}
12934
12935/*
12936 * "toupper(string)" function
12937 */
12938 static void
12939f_toupper(typval_T *argvars, typval_T *rettv)
12940{
12941 rettv->v_type = VAR_STRING;
12942 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12943}
12944
12945/*
12946 * "tr(string, fromstr, tostr)" function
12947 */
12948 static void
12949f_tr(typval_T *argvars, typval_T *rettv)
12950{
12951 char_u *in_str;
12952 char_u *fromstr;
12953 char_u *tostr;
12954 char_u *p;
12955#ifdef FEAT_MBYTE
12956 int inlen;
12957 int fromlen;
12958 int tolen;
12959 int idx;
12960 char_u *cpstr;
12961 int cplen;
12962 int first = TRUE;
12963#endif
12964 char_u buf[NUMBUFLEN];
12965 char_u buf2[NUMBUFLEN];
12966 garray_T ga;
12967
12968 in_str = get_tv_string(&argvars[0]);
12969 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12970 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12971
12972 /* Default return value: empty string. */
12973 rettv->v_type = VAR_STRING;
12974 rettv->vval.v_string = NULL;
12975 if (fromstr == NULL || tostr == NULL)
12976 return; /* type error; errmsg already given */
12977 ga_init2(&ga, (int)sizeof(char), 80);
12978
12979#ifdef FEAT_MBYTE
12980 if (!has_mbyte)
12981#endif
12982 /* not multi-byte: fromstr and tostr must be the same length */
12983 if (STRLEN(fromstr) != STRLEN(tostr))
12984 {
12985#ifdef FEAT_MBYTE
12986error:
12987#endif
12988 EMSG2(_(e_invarg2), fromstr);
12989 ga_clear(&ga);
12990 return;
12991 }
12992
12993 /* fromstr and tostr have to contain the same number of chars */
12994 while (*in_str != NUL)
12995 {
12996#ifdef FEAT_MBYTE
12997 if (has_mbyte)
12998 {
12999 inlen = (*mb_ptr2len)(in_str);
13000 cpstr = in_str;
13001 cplen = inlen;
13002 idx = 0;
13003 for (p = fromstr; *p != NUL; p += fromlen)
13004 {
13005 fromlen = (*mb_ptr2len)(p);
13006 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13007 {
13008 for (p = tostr; *p != NUL; p += tolen)
13009 {
13010 tolen = (*mb_ptr2len)(p);
13011 if (idx-- == 0)
13012 {
13013 cplen = tolen;
13014 cpstr = p;
13015 break;
13016 }
13017 }
13018 if (*p == NUL) /* tostr is shorter than fromstr */
13019 goto error;
13020 break;
13021 }
13022 ++idx;
13023 }
13024
13025 if (first && cpstr == in_str)
13026 {
13027 /* Check that fromstr and tostr have the same number of
13028 * (multi-byte) characters. Done only once when a character
13029 * of in_str doesn't appear in fromstr. */
13030 first = FALSE;
13031 for (p = tostr; *p != NUL; p += tolen)
13032 {
13033 tolen = (*mb_ptr2len)(p);
13034 --idx;
13035 }
13036 if (idx != 0)
13037 goto error;
13038 }
13039
13040 (void)ga_grow(&ga, cplen);
13041 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13042 ga.ga_len += cplen;
13043
13044 in_str += inlen;
13045 }
13046 else
13047#endif
13048 {
13049 /* When not using multi-byte chars we can do it faster. */
13050 p = vim_strchr(fromstr, *in_str);
13051 if (p != NULL)
13052 ga_append(&ga, tostr[p - fromstr]);
13053 else
13054 ga_append(&ga, *in_str);
13055 ++in_str;
13056 }
13057 }
13058
13059 /* add a terminating NUL */
13060 (void)ga_grow(&ga, 1);
13061 ga_append(&ga, NUL);
13062
13063 rettv->vval.v_string = ga.ga_data;
13064}
13065
13066#ifdef FEAT_FLOAT
13067/*
13068 * "trunc({float})" function
13069 */
13070 static void
13071f_trunc(typval_T *argvars, typval_T *rettv)
13072{
13073 float_T f = 0.0;
13074
13075 rettv->v_type = VAR_FLOAT;
13076 if (get_float_arg(argvars, &f) == OK)
13077 /* trunc() is not in C90, use floor() or ceil() instead. */
13078 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13079 else
13080 rettv->vval.v_float = 0.0;
13081}
13082#endif
13083
13084/*
13085 * "type(expr)" function
13086 */
13087 static void
13088f_type(typval_T *argvars, typval_T *rettv)
13089{
13090 int n = -1;
13091
13092 switch (argvars[0].v_type)
13093 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013094 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13095 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013096 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013097 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13098 case VAR_LIST: n = VAR_TYPE_LIST; break;
13099 case VAR_DICT: n = VAR_TYPE_DICT; break;
13100 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013101 case VAR_SPECIAL:
13102 if (argvars[0].vval.v_number == VVAL_FALSE
13103 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013104 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013105 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013106 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013107 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013108 case VAR_JOB: n = VAR_TYPE_JOB; break;
13109 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013110 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013111 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013112 n = -1;
13113 break;
13114 }
13115 rettv->vval.v_number = n;
13116}
13117
13118/*
13119 * "undofile(name)" function
13120 */
13121 static void
13122f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13123{
13124 rettv->v_type = VAR_STRING;
13125#ifdef FEAT_PERSISTENT_UNDO
13126 {
13127 char_u *fname = get_tv_string(&argvars[0]);
13128
13129 if (*fname == NUL)
13130 {
13131 /* If there is no file name there will be no undo file. */
13132 rettv->vval.v_string = NULL;
13133 }
13134 else
13135 {
13136 char_u *ffname = FullName_save(fname, FALSE);
13137
13138 if (ffname != NULL)
13139 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13140 vim_free(ffname);
13141 }
13142 }
13143#else
13144 rettv->vval.v_string = NULL;
13145#endif
13146}
13147
13148/*
13149 * "undotree()" function
13150 */
13151 static void
13152f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13153{
13154 if (rettv_dict_alloc(rettv) == OK)
13155 {
13156 dict_T *dict = rettv->vval.v_dict;
13157 list_T *list;
13158
13159 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13160 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13161 dict_add_nr_str(dict, "save_last",
13162 (long)curbuf->b_u_save_nr_last, NULL);
13163 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13164 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13165 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13166
13167 list = list_alloc();
13168 if (list != NULL)
13169 {
13170 u_eval_tree(curbuf->b_u_oldhead, list);
13171 dict_add_list(dict, "entries", list);
13172 }
13173 }
13174}
13175
13176/*
13177 * "values(dict)" function
13178 */
13179 static void
13180f_values(typval_T *argvars, typval_T *rettv)
13181{
13182 dict_list(argvars, rettv, 1);
13183}
13184
13185/*
13186 * "virtcol(string)" function
13187 */
13188 static void
13189f_virtcol(typval_T *argvars, typval_T *rettv)
13190{
13191 colnr_T vcol = 0;
13192 pos_T *fp;
13193 int fnum = curbuf->b_fnum;
13194
13195 fp = var2fpos(&argvars[0], FALSE, &fnum);
13196 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13197 && fnum == curbuf->b_fnum)
13198 {
13199 getvvcol(curwin, fp, NULL, NULL, &vcol);
13200 ++vcol;
13201 }
13202
13203 rettv->vval.v_number = vcol;
13204}
13205
13206/*
13207 * "visualmode()" function
13208 */
13209 static void
13210f_visualmode(typval_T *argvars, typval_T *rettv)
13211{
13212 char_u str[2];
13213
13214 rettv->v_type = VAR_STRING;
13215 str[0] = curbuf->b_visual_mode_eval;
13216 str[1] = NUL;
13217 rettv->vval.v_string = vim_strsave(str);
13218
13219 /* A non-zero number or non-empty string argument: reset mode. */
13220 if (non_zero_arg(&argvars[0]))
13221 curbuf->b_visual_mode_eval = NUL;
13222}
13223
13224/*
13225 * "wildmenumode()" function
13226 */
13227 static void
13228f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13229{
13230#ifdef FEAT_WILDMENU
13231 if (wild_menu_showing)
13232 rettv->vval.v_number = 1;
13233#endif
13234}
13235
13236/*
13237 * "winbufnr(nr)" function
13238 */
13239 static void
13240f_winbufnr(typval_T *argvars, typval_T *rettv)
13241{
13242 win_T *wp;
13243
13244 wp = find_win_by_nr(&argvars[0], NULL);
13245 if (wp == NULL)
13246 rettv->vval.v_number = -1;
13247 else
13248 rettv->vval.v_number = wp->w_buffer->b_fnum;
13249}
13250
13251/*
13252 * "wincol()" function
13253 */
13254 static void
13255f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13256{
13257 validate_cursor();
13258 rettv->vval.v_number = curwin->w_wcol + 1;
13259}
13260
13261/*
13262 * "winheight(nr)" function
13263 */
13264 static void
13265f_winheight(typval_T *argvars, typval_T *rettv)
13266{
13267 win_T *wp;
13268
13269 wp = find_win_by_nr(&argvars[0], NULL);
13270 if (wp == NULL)
13271 rettv->vval.v_number = -1;
13272 else
13273 rettv->vval.v_number = wp->w_height;
13274}
13275
13276/*
13277 * "winline()" function
13278 */
13279 static void
13280f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13281{
13282 validate_cursor();
13283 rettv->vval.v_number = curwin->w_wrow + 1;
13284}
13285
13286/*
13287 * "winnr()" function
13288 */
13289 static void
13290f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13291{
13292 int nr = 1;
13293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013294 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013295 rettv->vval.v_number = nr;
13296}
13297
13298/*
13299 * "winrestcmd()" function
13300 */
13301 static void
13302f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13303{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013304 win_T *wp;
13305 int winnr = 1;
13306 garray_T ga;
13307 char_u buf[50];
13308
13309 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013310 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013311 {
13312 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13313 ga_concat(&ga, buf);
13314 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13315 ga_concat(&ga, buf);
13316 ++winnr;
13317 }
13318 ga_append(&ga, NUL);
13319
13320 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013321 rettv->v_type = VAR_STRING;
13322}
13323
13324/*
13325 * "winrestview()" function
13326 */
13327 static void
13328f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13329{
13330 dict_T *dict;
13331
13332 if (argvars[0].v_type != VAR_DICT
13333 || (dict = argvars[0].vval.v_dict) == NULL)
13334 EMSG(_(e_invarg));
13335 else
13336 {
13337 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13338 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13339 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13340 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13341#ifdef FEAT_VIRTUALEDIT
13342 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13343 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13344#endif
13345 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13346 {
13347 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13348 curwin->w_set_curswant = FALSE;
13349 }
13350
13351 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13352 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13353#ifdef FEAT_DIFF
13354 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13355 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13356#endif
13357 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13358 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13359 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13360 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13361
13362 check_cursor();
13363 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013364 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013365 changed_window_setting();
13366
13367 if (curwin->w_topline <= 0)
13368 curwin->w_topline = 1;
13369 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13370 curwin->w_topline = curbuf->b_ml.ml_line_count;
13371#ifdef FEAT_DIFF
13372 check_topfill(curwin, TRUE);
13373#endif
13374 }
13375}
13376
13377/*
13378 * "winsaveview()" function
13379 */
13380 static void
13381f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13382{
13383 dict_T *dict;
13384
13385 if (rettv_dict_alloc(rettv) == FAIL)
13386 return;
13387 dict = rettv->vval.v_dict;
13388
13389 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13390 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13391#ifdef FEAT_VIRTUALEDIT
13392 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13393#endif
13394 update_curswant();
13395 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13396
13397 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13398#ifdef FEAT_DIFF
13399 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13400#endif
13401 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13402 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13403}
13404
13405/*
13406 * "winwidth(nr)" function
13407 */
13408 static void
13409f_winwidth(typval_T *argvars, typval_T *rettv)
13410{
13411 win_T *wp;
13412
13413 wp = find_win_by_nr(&argvars[0], NULL);
13414 if (wp == NULL)
13415 rettv->vval.v_number = -1;
13416 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013417 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013418}
13419
13420/*
13421 * "wordcount()" function
13422 */
13423 static void
13424f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13425{
13426 if (rettv_dict_alloc(rettv) == FAIL)
13427 return;
13428 cursor_pos_info(rettv->vval.v_dict);
13429}
13430
13431/*
13432 * "writefile()" function
13433 */
13434 static void
13435f_writefile(typval_T *argvars, typval_T *rettv)
13436{
13437 int binary = FALSE;
13438 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013439#ifdef HAVE_FSYNC
13440 int do_fsync = p_fs;
13441#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013442 char_u *fname;
13443 FILE *fd;
13444 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013445 listitem_T *li;
13446 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013447
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013448 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013449 if (check_restricted() || check_secure())
13450 return;
13451
13452 if (argvars[0].v_type != VAR_LIST)
13453 {
13454 EMSG2(_(e_listarg), "writefile()");
13455 return;
13456 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013457 list = argvars[0].vval.v_list;
13458 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013459 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013460 for (li = list->lv_first; li != NULL; li = li->li_next)
13461 if (get_tv_string_chk(&li->li_tv) == NULL)
13462 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013463
13464 if (argvars[2].v_type != VAR_UNKNOWN)
13465 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013466 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13467
13468 if (arg2 == NULL)
13469 return;
13470 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013471 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013472 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013473 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013474#ifdef HAVE_FSYNC
13475 if (vim_strchr(arg2, 's') != NULL)
13476 do_fsync = TRUE;
13477 else if (vim_strchr(arg2, 'S') != NULL)
13478 do_fsync = FALSE;
13479#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013480 }
13481
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013482 fname = get_tv_string_chk(&argvars[1]);
13483 if (fname == NULL)
13484 return;
13485
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013486 /* Always open the file in binary mode, library functions have a mind of
13487 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013488 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13489 append ? APPENDBIN : WRITEBIN)) == NULL)
13490 {
13491 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13492 ret = -1;
13493 }
13494 else
13495 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013496 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013497 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013498#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013499 else if (do_fsync)
13500 /* Ignore the error, the user wouldn't know what to do about it.
13501 * May happen for a device. */
13502 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013503#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013504 fclose(fd);
13505 }
13506
13507 rettv->vval.v_number = ret;
13508}
13509
13510/*
13511 * "xor(expr, expr)" function
13512 */
13513 static void
13514f_xor(typval_T *argvars, typval_T *rettv)
13515{
13516 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13517 ^ get_tv_number_chk(&argvars[1], NULL);
13518}
13519
13520
13521#endif /* FEAT_EVAL */