blob: 8d288e0dc5a36516ab144ea4d450aa5399c25723 [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);
444static void f_winbufnr(typval_T *argvars, typval_T *rettv);
445static void f_wincol(typval_T *argvars, typval_T *rettv);
446static void f_winheight(typval_T *argvars, typval_T *rettv);
447static void f_winline(typval_T *argvars, typval_T *rettv);
448static void f_winnr(typval_T *argvars, typval_T *rettv);
449static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
450static void f_winrestview(typval_T *argvars, typval_T *rettv);
451static void f_winsaveview(typval_T *argvars, typval_T *rettv);
452static void f_winwidth(typval_T *argvars, typval_T *rettv);
453static void f_writefile(typval_T *argvars, typval_T *rettv);
454static void f_wordcount(typval_T *argvars, typval_T *rettv);
455static void f_xor(typval_T *argvars, typval_T *rettv);
456
457/*
458 * Array with names and number of arguments of all internal functions
459 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
460 */
461static struct fst
462{
463 char *f_name; /* function name */
464 char f_min_argc; /* minimal number of arguments */
465 char f_max_argc; /* maximal number of arguments */
466 void (*f_func)(typval_T *args, typval_T *rvar);
467 /* implementation of function */
468} functions[] =
469{
470#ifdef FEAT_FLOAT
471 {"abs", 1, 1, f_abs},
472 {"acos", 1, 1, f_acos}, /* WJMc */
473#endif
474 {"add", 2, 2, f_add},
475 {"and", 2, 2, f_and},
476 {"append", 2, 2, f_append},
477 {"argc", 0, 0, f_argc},
478 {"argidx", 0, 0, f_argidx},
479 {"arglistid", 0, 2, f_arglistid},
480 {"argv", 0, 1, f_argv},
481#ifdef FEAT_FLOAT
482 {"asin", 1, 1, f_asin}, /* WJMc */
483#endif
484 {"assert_equal", 2, 3, f_assert_equal},
485 {"assert_exception", 1, 2, f_assert_exception},
486 {"assert_fails", 1, 2, f_assert_fails},
487 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100488 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200489 {"assert_match", 2, 3, f_assert_match},
490 {"assert_notequal", 2, 3, f_assert_notequal},
491 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100492 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200493 {"assert_true", 1, 2, f_assert_true},
494#ifdef FEAT_FLOAT
495 {"atan", 1, 1, f_atan},
496 {"atan2", 2, 2, f_atan2},
497#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100498#ifdef FEAT_BEVAL
499 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100500# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100501 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100502# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100503#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200504 {"browse", 4, 4, f_browse},
505 {"browsedir", 2, 2, f_browsedir},
506 {"bufexists", 1, 1, f_bufexists},
507 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
508 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
509 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
510 {"buflisted", 1, 1, f_buflisted},
511 {"bufloaded", 1, 1, f_bufloaded},
512 {"bufname", 1, 1, f_bufname},
513 {"bufnr", 1, 2, f_bufnr},
514 {"bufwinid", 1, 1, f_bufwinid},
515 {"bufwinnr", 1, 1, f_bufwinnr},
516 {"byte2line", 1, 1, f_byte2line},
517 {"byteidx", 2, 2, f_byteidx},
518 {"byteidxcomp", 2, 2, f_byteidxcomp},
519 {"call", 2, 3, f_call},
520#ifdef FEAT_FLOAT
521 {"ceil", 1, 1, f_ceil},
522#endif
523#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100524 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200526 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
528 {"ch_evalraw", 2, 3, f_ch_evalraw},
529 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
530 {"ch_getjob", 1, 1, f_ch_getjob},
531 {"ch_info", 1, 1, f_ch_info},
532 {"ch_log", 1, 2, f_ch_log},
533 {"ch_logfile", 1, 2, f_ch_logfile},
534 {"ch_open", 1, 2, f_ch_open},
535 {"ch_read", 1, 2, f_ch_read},
536 {"ch_readraw", 1, 2, f_ch_readraw},
537 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
538 {"ch_sendraw", 2, 3, f_ch_sendraw},
539 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200540 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200541#endif
542 {"changenr", 0, 0, f_changenr},
543 {"char2nr", 1, 2, f_char2nr},
544 {"cindent", 1, 1, f_cindent},
545 {"clearmatches", 0, 0, f_clearmatches},
546 {"col", 1, 1, f_col},
547#if defined(FEAT_INS_EXPAND)
548 {"complete", 2, 2, f_complete},
549 {"complete_add", 1, 1, f_complete_add},
550 {"complete_check", 0, 0, f_complete_check},
551#endif
552 {"confirm", 1, 4, f_confirm},
553 {"copy", 1, 1, f_copy},
554#ifdef FEAT_FLOAT
555 {"cos", 1, 1, f_cos},
556 {"cosh", 1, 1, f_cosh},
557#endif
558 {"count", 2, 4, f_count},
559 {"cscope_connection",0,3, f_cscope_connection},
560 {"cursor", 1, 3, f_cursor},
561 {"deepcopy", 1, 2, f_deepcopy},
562 {"delete", 1, 2, f_delete},
563 {"did_filetype", 0, 0, f_did_filetype},
564 {"diff_filler", 1, 1, f_diff_filler},
565 {"diff_hlID", 2, 2, f_diff_hlID},
566 {"empty", 1, 1, f_empty},
567 {"escape", 2, 2, f_escape},
568 {"eval", 1, 1, f_eval},
569 {"eventhandler", 0, 0, f_eventhandler},
570 {"executable", 1, 1, f_executable},
571 {"execute", 1, 2, f_execute},
572 {"exepath", 1, 1, f_exepath},
573 {"exists", 1, 1, f_exists},
574#ifdef FEAT_FLOAT
575 {"exp", 1, 1, f_exp},
576#endif
577 {"expand", 1, 3, f_expand},
578 {"extend", 2, 3, f_extend},
579 {"feedkeys", 1, 2, f_feedkeys},
580 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
581 {"filereadable", 1, 1, f_filereadable},
582 {"filewritable", 1, 1, f_filewritable},
583 {"filter", 2, 2, f_filter},
584 {"finddir", 1, 3, f_finddir},
585 {"findfile", 1, 3, f_findfile},
586#ifdef FEAT_FLOAT
587 {"float2nr", 1, 1, f_float2nr},
588 {"floor", 1, 1, f_floor},
589 {"fmod", 2, 2, f_fmod},
590#endif
591 {"fnameescape", 1, 1, f_fnameescape},
592 {"fnamemodify", 2, 2, f_fnamemodify},
593 {"foldclosed", 1, 1, f_foldclosed},
594 {"foldclosedend", 1, 1, f_foldclosedend},
595 {"foldlevel", 1, 1, f_foldlevel},
596 {"foldtext", 0, 0, f_foldtext},
597 {"foldtextresult", 1, 1, f_foldtextresult},
598 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200599 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600 {"function", 1, 3, f_function},
601 {"garbagecollect", 0, 1, f_garbagecollect},
602 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200603 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200604 {"getbufline", 2, 3, f_getbufline},
605 {"getbufvar", 2, 3, f_getbufvar},
606 {"getchar", 0, 1, f_getchar},
607 {"getcharmod", 0, 0, f_getcharmod},
608 {"getcharsearch", 0, 0, f_getcharsearch},
609 {"getcmdline", 0, 0, f_getcmdline},
610 {"getcmdpos", 0, 0, f_getcmdpos},
611 {"getcmdtype", 0, 0, f_getcmdtype},
612 {"getcmdwintype", 0, 0, f_getcmdwintype},
613#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200614 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200615#endif
616 {"getcurpos", 0, 0, f_getcurpos},
617 {"getcwd", 0, 2, f_getcwd},
618 {"getfontname", 0, 1, f_getfontname},
619 {"getfperm", 1, 1, f_getfperm},
620 {"getfsize", 1, 1, f_getfsize},
621 {"getftime", 1, 1, f_getftime},
622 {"getftype", 1, 1, f_getftype},
623 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200624 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625 {"getmatches", 0, 0, f_getmatches},
626 {"getpid", 0, 0, f_getpid},
627 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200628 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200629 {"getreg", 0, 3, f_getreg},
630 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200631 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632 {"gettabvar", 2, 3, f_gettabvar},
633 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200634 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635 {"getwinposx", 0, 0, f_getwinposx},
636 {"getwinposy", 0, 0, f_getwinposy},
637 {"getwinvar", 2, 3, f_getwinvar},
638 {"glob", 1, 4, f_glob},
639 {"glob2regpat", 1, 1, f_glob2regpat},
640 {"globpath", 2, 5, f_globpath},
641 {"has", 1, 1, f_has},
642 {"has_key", 2, 2, f_has_key},
643 {"haslocaldir", 0, 2, f_haslocaldir},
644 {"hasmapto", 1, 3, f_hasmapto},
645 {"highlightID", 1, 1, f_hlID}, /* obsolete */
646 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
647 {"histadd", 2, 2, f_histadd},
648 {"histdel", 1, 2, f_histdel},
649 {"histget", 1, 2, f_histget},
650 {"histnr", 1, 1, f_histnr},
651 {"hlID", 1, 1, f_hlID},
652 {"hlexists", 1, 1, f_hlexists},
653 {"hostname", 0, 0, f_hostname},
654 {"iconv", 3, 3, f_iconv},
655 {"indent", 1, 1, f_indent},
656 {"index", 2, 4, f_index},
657 {"input", 1, 3, f_input},
658 {"inputdialog", 1, 3, f_inputdialog},
659 {"inputlist", 1, 1, f_inputlist},
660 {"inputrestore", 0, 0, f_inputrestore},
661 {"inputsave", 0, 0, f_inputsave},
662 {"inputsecret", 1, 2, f_inputsecret},
663 {"insert", 2, 3, f_insert},
664 {"invert", 1, 1, f_invert},
665 {"isdirectory", 1, 1, f_isdirectory},
666 {"islocked", 1, 1, f_islocked},
667#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
668 {"isnan", 1, 1, f_isnan},
669#endif
670 {"items", 1, 1, f_items},
671#ifdef FEAT_JOB_CHANNEL
672 {"job_getchannel", 1, 1, f_job_getchannel},
673 {"job_info", 1, 1, f_job_info},
674 {"job_setoptions", 2, 2, f_job_setoptions},
675 {"job_start", 1, 2, f_job_start},
676 {"job_status", 1, 1, f_job_status},
677 {"job_stop", 1, 2, f_job_stop},
678#endif
679 {"join", 1, 2, f_join},
680 {"js_decode", 1, 1, f_js_decode},
681 {"js_encode", 1, 1, f_js_encode},
682 {"json_decode", 1, 1, f_json_decode},
683 {"json_encode", 1, 1, f_json_encode},
684 {"keys", 1, 1, f_keys},
685 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
686 {"len", 1, 1, f_len},
687 {"libcall", 3, 3, f_libcall},
688 {"libcallnr", 3, 3, f_libcallnr},
689 {"line", 1, 1, f_line},
690 {"line2byte", 1, 1, f_line2byte},
691 {"lispindent", 1, 1, f_lispindent},
692 {"localtime", 0, 0, f_localtime},
693#ifdef FEAT_FLOAT
694 {"log", 1, 1, f_log},
695 {"log10", 1, 1, f_log10},
696#endif
697#ifdef FEAT_LUA
698 {"luaeval", 1, 2, f_luaeval},
699#endif
700 {"map", 2, 2, f_map},
701 {"maparg", 1, 4, f_maparg},
702 {"mapcheck", 1, 3, f_mapcheck},
703 {"match", 2, 4, f_match},
704 {"matchadd", 2, 5, f_matchadd},
705 {"matchaddpos", 2, 5, f_matchaddpos},
706 {"matcharg", 1, 1, f_matcharg},
707 {"matchdelete", 1, 1, f_matchdelete},
708 {"matchend", 2, 4, f_matchend},
709 {"matchlist", 2, 4, f_matchlist},
710 {"matchstr", 2, 4, f_matchstr},
711 {"matchstrpos", 2, 4, f_matchstrpos},
712 {"max", 1, 1, f_max},
713 {"min", 1, 1, f_min},
714#ifdef vim_mkdir
715 {"mkdir", 1, 3, f_mkdir},
716#endif
717 {"mode", 0, 1, f_mode},
718#ifdef FEAT_MZSCHEME
719 {"mzeval", 1, 1, f_mzeval},
720#endif
721 {"nextnonblank", 1, 1, f_nextnonblank},
722 {"nr2char", 1, 2, f_nr2char},
723 {"or", 2, 2, f_or},
724 {"pathshorten", 1, 1, f_pathshorten},
725#ifdef FEAT_PERL
726 {"perleval", 1, 1, f_perleval},
727#endif
728#ifdef FEAT_FLOAT
729 {"pow", 2, 2, f_pow},
730#endif
731 {"prevnonblank", 1, 1, f_prevnonblank},
732 {"printf", 2, 19, f_printf},
733 {"pumvisible", 0, 0, f_pumvisible},
734#ifdef FEAT_PYTHON3
735 {"py3eval", 1, 1, f_py3eval},
736#endif
737#ifdef FEAT_PYTHON
738 {"pyeval", 1, 1, f_pyeval},
739#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100740#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
741 {"pyxeval", 1, 1, f_pyxeval},
742#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200743 {"range", 1, 3, f_range},
744 {"readfile", 1, 3, f_readfile},
745 {"reltime", 0, 2, f_reltime},
746#ifdef FEAT_FLOAT
747 {"reltimefloat", 1, 1, f_reltimefloat},
748#endif
749 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100750 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200751 {"remote_foreground", 1, 1, f_remote_foreground},
752 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100753 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200754 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100755 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200756 {"remove", 2, 3, f_remove},
757 {"rename", 2, 2, f_rename},
758 {"repeat", 2, 2, f_repeat},
759 {"resolve", 1, 1, f_resolve},
760 {"reverse", 1, 1, f_reverse},
761#ifdef FEAT_FLOAT
762 {"round", 1, 1, f_round},
763#endif
764 {"screenattr", 2, 2, f_screenattr},
765 {"screenchar", 2, 2, f_screenchar},
766 {"screencol", 0, 0, f_screencol},
767 {"screenrow", 0, 0, f_screenrow},
768 {"search", 1, 4, f_search},
769 {"searchdecl", 1, 3, f_searchdecl},
770 {"searchpair", 3, 7, f_searchpair},
771 {"searchpairpos", 3, 7, f_searchpairpos},
772 {"searchpos", 1, 4, f_searchpos},
773 {"server2client", 2, 2, f_server2client},
774 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200775 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200776 {"setbufvar", 3, 3, f_setbufvar},
777 {"setcharsearch", 1, 1, f_setcharsearch},
778 {"setcmdpos", 1, 1, f_setcmdpos},
779 {"setfperm", 2, 2, f_setfperm},
780 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200781 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200782 {"setmatches", 1, 1, f_setmatches},
783 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200784 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200785 {"setreg", 2, 3, f_setreg},
786 {"settabvar", 3, 3, f_settabvar},
787 {"settabwinvar", 4, 4, f_settabwinvar},
788 {"setwinvar", 3, 3, f_setwinvar},
789#ifdef FEAT_CRYPT
790 {"sha256", 1, 1, f_sha256},
791#endif
792 {"shellescape", 1, 2, f_shellescape},
793 {"shiftwidth", 0, 0, f_shiftwidth},
794 {"simplify", 1, 1, f_simplify},
795#ifdef FEAT_FLOAT
796 {"sin", 1, 1, f_sin},
797 {"sinh", 1, 1, f_sinh},
798#endif
799 {"sort", 1, 3, f_sort},
800 {"soundfold", 1, 1, f_soundfold},
801 {"spellbadword", 0, 1, f_spellbadword},
802 {"spellsuggest", 1, 3, f_spellsuggest},
803 {"split", 1, 3, f_split},
804#ifdef FEAT_FLOAT
805 {"sqrt", 1, 1, f_sqrt},
806 {"str2float", 1, 1, f_str2float},
807#endif
808 {"str2nr", 1, 2, f_str2nr},
809 {"strcharpart", 2, 3, f_strcharpart},
810 {"strchars", 1, 2, f_strchars},
811 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
812#ifdef HAVE_STRFTIME
813 {"strftime", 1, 2, f_strftime},
814#endif
815 {"strgetchar", 2, 2, f_strgetchar},
816 {"stridx", 2, 3, f_stridx},
817 {"string", 1, 1, f_string},
818 {"strlen", 1, 1, f_strlen},
819 {"strpart", 2, 3, f_strpart},
820 {"strridx", 2, 3, f_strridx},
821 {"strtrans", 1, 1, f_strtrans},
822 {"strwidth", 1, 1, f_strwidth},
823 {"submatch", 1, 2, f_submatch},
824 {"substitute", 4, 4, f_substitute},
825 {"synID", 3, 3, f_synID},
826 {"synIDattr", 2, 3, f_synIDattr},
827 {"synIDtrans", 1, 1, f_synIDtrans},
828 {"synconcealed", 2, 2, f_synconcealed},
829 {"synstack", 2, 2, f_synstack},
830 {"system", 1, 2, f_system},
831 {"systemlist", 1, 2, f_systemlist},
832 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
833 {"tabpagenr", 0, 1, f_tabpagenr},
834 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
835 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100836 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200837#ifdef FEAT_FLOAT
838 {"tan", 1, 1, f_tan},
839 {"tanh", 1, 1, f_tanh},
840#endif
841 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200842#ifdef FEAT_TERMINAL
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200843 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200844 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200845 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200846 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200847 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200848 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200849 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200850 {"term_getstatus", 1, 1, f_term_getstatus},
851 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200852 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200853 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200854 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200855 {"term_sendkeys", 2, 2, f_term_sendkeys},
856 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200857 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200858#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200859 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
860 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200861 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200862 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100863 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200864#ifdef FEAT_JOB_CHANNEL
865 {"test_null_channel", 0, 0, f_test_null_channel},
866#endif
867 {"test_null_dict", 0, 0, f_test_null_dict},
868#ifdef FEAT_JOB_CHANNEL
869 {"test_null_job", 0, 0, f_test_null_job},
870#endif
871 {"test_null_list", 0, 0, f_test_null_list},
872 {"test_null_partial", 0, 0, f_test_null_partial},
873 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100874 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200875 {"test_settime", 1, 1, f_test_settime},
876#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200877 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200878 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200879 {"timer_start", 2, 3, f_timer_start},
880 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200881 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200882#endif
883 {"tolower", 1, 1, f_tolower},
884 {"toupper", 1, 1, f_toupper},
885 {"tr", 3, 3, f_tr},
886#ifdef FEAT_FLOAT
887 {"trunc", 1, 1, f_trunc},
888#endif
889 {"type", 1, 1, f_type},
890 {"undofile", 1, 1, f_undofile},
891 {"undotree", 0, 0, f_undotree},
892 {"uniq", 1, 3, f_uniq},
893 {"values", 1, 1, f_values},
894 {"virtcol", 1, 1, f_virtcol},
895 {"visualmode", 0, 1, f_visualmode},
896 {"wildmenumode", 0, 0, f_wildmenumode},
897 {"win_findbuf", 1, 1, f_win_findbuf},
898 {"win_getid", 0, 2, f_win_getid},
899 {"win_gotoid", 1, 1, f_win_gotoid},
900 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
901 {"win_id2win", 1, 1, f_win_id2win},
902 {"winbufnr", 1, 1, f_winbufnr},
903 {"wincol", 0, 0, f_wincol},
904 {"winheight", 1, 1, f_winheight},
905 {"winline", 0, 0, f_winline},
906 {"winnr", 0, 1, f_winnr},
907 {"winrestcmd", 0, 0, f_winrestcmd},
908 {"winrestview", 1, 1, f_winrestview},
909 {"winsaveview", 0, 0, f_winsaveview},
910 {"winwidth", 1, 1, f_winwidth},
911 {"wordcount", 0, 0, f_wordcount},
912 {"writefile", 2, 3, f_writefile},
913 {"xor", 2, 2, f_xor},
914};
915
916#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
917
918/*
919 * Function given to ExpandGeneric() to obtain the list of internal
920 * or user defined function names.
921 */
922 char_u *
923get_function_name(expand_T *xp, int idx)
924{
925 static int intidx = -1;
926 char_u *name;
927
928 if (idx == 0)
929 intidx = -1;
930 if (intidx < 0)
931 {
932 name = get_user_func_name(xp, idx);
933 if (name != NULL)
934 return name;
935 }
936 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
937 {
938 STRCPY(IObuff, functions[intidx].f_name);
939 STRCAT(IObuff, "(");
940 if (functions[intidx].f_max_argc == 0)
941 STRCAT(IObuff, ")");
942 return IObuff;
943 }
944
945 return NULL;
946}
947
948/*
949 * Function given to ExpandGeneric() to obtain the list of internal or
950 * user defined variable or function names.
951 */
952 char_u *
953get_expr_name(expand_T *xp, int idx)
954{
955 static int intidx = -1;
956 char_u *name;
957
958 if (idx == 0)
959 intidx = -1;
960 if (intidx < 0)
961 {
962 name = get_function_name(xp, idx);
963 if (name != NULL)
964 return name;
965 }
966 return get_user_var_name(xp, ++intidx);
967}
968
969#endif /* FEAT_CMDL_COMPL */
970
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200971/*
972 * Find internal function in table above.
973 * Return index, or -1 if not found
974 */
975 int
976find_internal_func(
977 char_u *name) /* name of the function */
978{
979 int first = 0;
980 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
981 int cmp;
982 int x;
983
984 /*
985 * Find the function name in the table. Binary search.
986 */
987 while (first <= last)
988 {
989 x = first + ((unsigned)(last - first) >> 1);
990 cmp = STRCMP(name, functions[x].f_name);
991 if (cmp < 0)
992 last = x - 1;
993 else if (cmp > 0)
994 first = x + 1;
995 else
996 return x;
997 }
998 return -1;
999}
1000
1001 int
1002call_internal_func(
1003 char_u *name,
1004 int argcount,
1005 typval_T *argvars,
1006 typval_T *rettv)
1007{
1008 int i;
1009
1010 i = find_internal_func(name);
1011 if (i < 0)
1012 return ERROR_UNKNOWN;
1013 if (argcount < functions[i].f_min_argc)
1014 return ERROR_TOOFEW;
1015 if (argcount > functions[i].f_max_argc)
1016 return ERROR_TOOMANY;
1017 argvars[argcount].v_type = VAR_UNKNOWN;
1018 functions[i].f_func(argvars, rettv);
1019 return ERROR_NONE;
1020}
1021
1022/*
1023 * Return TRUE for a non-zero Number and a non-empty String.
1024 */
1025 static int
1026non_zero_arg(typval_T *argvars)
1027{
1028 return ((argvars[0].v_type == VAR_NUMBER
1029 && argvars[0].vval.v_number != 0)
1030 || (argvars[0].v_type == VAR_SPECIAL
1031 && argvars[0].vval.v_number == VVAL_TRUE)
1032 || (argvars[0].v_type == VAR_STRING
1033 && argvars[0].vval.v_string != NULL
1034 && *argvars[0].vval.v_string != NUL));
1035}
1036
1037/*
1038 * Get the lnum from the first argument.
1039 * Also accepts ".", "$", etc., but that only works for the current buffer.
1040 * Returns -1 on error.
1041 */
1042 static linenr_T
1043get_tv_lnum(typval_T *argvars)
1044{
1045 typval_T rettv;
1046 linenr_T lnum;
1047
1048 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1049 if (lnum == 0) /* no valid number, try using line() */
1050 {
1051 rettv.v_type = VAR_NUMBER;
1052 f_line(argvars, &rettv);
1053 lnum = (linenr_T)rettv.vval.v_number;
1054 clear_tv(&rettv);
1055 }
1056 return lnum;
1057}
1058
1059#ifdef FEAT_FLOAT
1060static int get_float_arg(typval_T *argvars, float_T *f);
1061
1062/*
1063 * Get the float value of "argvars[0]" into "f".
1064 * Returns FAIL when the argument is not a Number or Float.
1065 */
1066 static int
1067get_float_arg(typval_T *argvars, float_T *f)
1068{
1069 if (argvars[0].v_type == VAR_FLOAT)
1070 {
1071 *f = argvars[0].vval.v_float;
1072 return OK;
1073 }
1074 if (argvars[0].v_type == VAR_NUMBER)
1075 {
1076 *f = (float_T)argvars[0].vval.v_number;
1077 return OK;
1078 }
1079 EMSG(_("E808: Number or Float required"));
1080 return FAIL;
1081}
1082
1083/*
1084 * "abs(expr)" function
1085 */
1086 static void
1087f_abs(typval_T *argvars, typval_T *rettv)
1088{
1089 if (argvars[0].v_type == VAR_FLOAT)
1090 {
1091 rettv->v_type = VAR_FLOAT;
1092 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1093 }
1094 else
1095 {
1096 varnumber_T n;
1097 int error = FALSE;
1098
1099 n = get_tv_number_chk(&argvars[0], &error);
1100 if (error)
1101 rettv->vval.v_number = -1;
1102 else if (n > 0)
1103 rettv->vval.v_number = n;
1104 else
1105 rettv->vval.v_number = -n;
1106 }
1107}
1108
1109/*
1110 * "acos()" function
1111 */
1112 static void
1113f_acos(typval_T *argvars, typval_T *rettv)
1114{
1115 float_T f = 0.0;
1116
1117 rettv->v_type = VAR_FLOAT;
1118 if (get_float_arg(argvars, &f) == OK)
1119 rettv->vval.v_float = acos(f);
1120 else
1121 rettv->vval.v_float = 0.0;
1122}
1123#endif
1124
1125/*
1126 * "add(list, item)" function
1127 */
1128 static void
1129f_add(typval_T *argvars, typval_T *rettv)
1130{
1131 list_T *l;
1132
1133 rettv->vval.v_number = 1; /* Default: Failed */
1134 if (argvars[0].v_type == VAR_LIST)
1135 {
1136 if ((l = argvars[0].vval.v_list) != NULL
1137 && !tv_check_lock(l->lv_lock,
1138 (char_u *)N_("add() argument"), TRUE)
1139 && list_append_tv(l, &argvars[1]) == OK)
1140 copy_tv(&argvars[0], rettv);
1141 }
1142 else
1143 EMSG(_(e_listreq));
1144}
1145
1146/*
1147 * "and(expr, expr)" function
1148 */
1149 static void
1150f_and(typval_T *argvars, typval_T *rettv)
1151{
1152 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1153 & get_tv_number_chk(&argvars[1], NULL);
1154}
1155
1156/*
1157 * "append(lnum, string/list)" function
1158 */
1159 static void
1160f_append(typval_T *argvars, typval_T *rettv)
1161{
1162 long lnum;
1163 char_u *line;
1164 list_T *l = NULL;
1165 listitem_T *li = NULL;
1166 typval_T *tv;
1167 long added = 0;
1168
1169 /* When coming here from Insert mode, sync undo, so that this can be
1170 * undone separately from what was previously inserted. */
1171 if (u_sync_once == 2)
1172 {
1173 u_sync_once = 1; /* notify that u_sync() was called */
1174 u_sync(TRUE);
1175 }
1176
1177 lnum = get_tv_lnum(argvars);
1178 if (lnum >= 0
1179 && lnum <= curbuf->b_ml.ml_line_count
1180 && u_save(lnum, lnum + 1) == OK)
1181 {
1182 if (argvars[1].v_type == VAR_LIST)
1183 {
1184 l = argvars[1].vval.v_list;
1185 if (l == NULL)
1186 return;
1187 li = l->lv_first;
1188 }
1189 for (;;)
1190 {
1191 if (l == NULL)
1192 tv = &argvars[1]; /* append a string */
1193 else if (li == NULL)
1194 break; /* end of list */
1195 else
1196 tv = &li->li_tv; /* append item from list */
1197 line = get_tv_string_chk(tv);
1198 if (line == NULL) /* type error */
1199 {
1200 rettv->vval.v_number = 1; /* Failed */
1201 break;
1202 }
1203 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1204 ++added;
1205 if (l == NULL)
1206 break;
1207 li = li->li_next;
1208 }
1209
1210 appended_lines_mark(lnum, added);
1211 if (curwin->w_cursor.lnum > lnum)
1212 curwin->w_cursor.lnum += added;
1213 }
1214 else
1215 rettv->vval.v_number = 1; /* Failed */
1216}
1217
1218/*
1219 * "argc()" function
1220 */
1221 static void
1222f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1223{
1224 rettv->vval.v_number = ARGCOUNT;
1225}
1226
1227/*
1228 * "argidx()" function
1229 */
1230 static void
1231f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1232{
1233 rettv->vval.v_number = curwin->w_arg_idx;
1234}
1235
1236/*
1237 * "arglistid()" function
1238 */
1239 static void
1240f_arglistid(typval_T *argvars, typval_T *rettv)
1241{
1242 win_T *wp;
1243
1244 rettv->vval.v_number = -1;
1245 wp = find_tabwin(&argvars[0], &argvars[1]);
1246 if (wp != NULL)
1247 rettv->vval.v_number = wp->w_alist->id;
1248}
1249
1250/*
1251 * "argv(nr)" function
1252 */
1253 static void
1254f_argv(typval_T *argvars, typval_T *rettv)
1255{
1256 int idx;
1257
1258 if (argvars[0].v_type != VAR_UNKNOWN)
1259 {
1260 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1261 if (idx >= 0 && idx < ARGCOUNT)
1262 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1263 else
1264 rettv->vval.v_string = NULL;
1265 rettv->v_type = VAR_STRING;
1266 }
1267 else if (rettv_list_alloc(rettv) == OK)
1268 for (idx = 0; idx < ARGCOUNT; ++idx)
1269 list_append_string(rettv->vval.v_list,
1270 alist_name(&ARGLIST[idx]), -1);
1271}
1272
1273/*
1274 * "assert_equal(expected, actual[, msg])" function
1275 */
1276 static void
1277f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1278{
1279 assert_equal_common(argvars, ASSERT_EQUAL);
1280}
1281
1282/*
1283 * "assert_notequal(expected, actual[, msg])" function
1284 */
1285 static void
1286f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1287{
1288 assert_equal_common(argvars, ASSERT_NOTEQUAL);
1289}
1290
1291/*
1292 * "assert_exception(string[, msg])" function
1293 */
1294 static void
1295f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1296{
1297 assert_exception(argvars);
1298}
1299
1300/*
1301 * "assert_fails(cmd [, error])" function
1302 */
1303 static void
1304f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1305{
1306 assert_fails(argvars);
1307}
1308
1309/*
1310 * "assert_false(actual[, msg])" function
1311 */
1312 static void
1313f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1314{
1315 assert_bool(argvars, FALSE);
1316}
1317
1318/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001319 * "assert_inrange(lower, upper[, msg])" function
1320 */
1321 static void
1322f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1323{
1324 assert_inrange(argvars);
1325}
1326
1327/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001328 * "assert_match(pattern, actual[, msg])" function
1329 */
1330 static void
1331f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1332{
1333 assert_match_common(argvars, ASSERT_MATCH);
1334}
1335
1336/*
1337 * "assert_notmatch(pattern, actual[, msg])" function
1338 */
1339 static void
1340f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1341{
1342 assert_match_common(argvars, ASSERT_NOTMATCH);
1343}
1344
1345/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001346 * "assert_report(msg)" function
1347 */
1348 static void
1349f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
1350{
1351 assert_report(argvars);
1352}
1353
1354/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001355 * "assert_true(actual[, msg])" function
1356 */
1357 static void
1358f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1359{
1360 assert_bool(argvars, TRUE);
1361}
1362
1363#ifdef FEAT_FLOAT
1364/*
1365 * "asin()" function
1366 */
1367 static void
1368f_asin(typval_T *argvars, typval_T *rettv)
1369{
1370 float_T f = 0.0;
1371
1372 rettv->v_type = VAR_FLOAT;
1373 if (get_float_arg(argvars, &f) == OK)
1374 rettv->vval.v_float = asin(f);
1375 else
1376 rettv->vval.v_float = 0.0;
1377}
1378
1379/*
1380 * "atan()" function
1381 */
1382 static void
1383f_atan(typval_T *argvars, typval_T *rettv)
1384{
1385 float_T f = 0.0;
1386
1387 rettv->v_type = VAR_FLOAT;
1388 if (get_float_arg(argvars, &f) == OK)
1389 rettv->vval.v_float = atan(f);
1390 else
1391 rettv->vval.v_float = 0.0;
1392}
1393
1394/*
1395 * "atan2()" function
1396 */
1397 static void
1398f_atan2(typval_T *argvars, typval_T *rettv)
1399{
1400 float_T fx = 0.0, fy = 0.0;
1401
1402 rettv->v_type = VAR_FLOAT;
1403 if (get_float_arg(argvars, &fx) == OK
1404 && get_float_arg(&argvars[1], &fy) == OK)
1405 rettv->vval.v_float = atan2(fx, fy);
1406 else
1407 rettv->vval.v_float = 0.0;
1408}
1409#endif
1410
1411/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001412 * "balloon_show()" function
1413 */
1414#ifdef FEAT_BEVAL
1415 static void
1416f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1417{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001418 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001419 {
1420 if (argvars[0].v_type == VAR_LIST
1421# ifdef FEAT_GUI
1422 && !gui.in_use
1423# endif
1424 )
1425 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1426 else
1427 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1428 }
1429}
1430
Bram Moolenaar669a8282017-11-19 20:13:05 +01001431# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001432 static void
1433f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1434{
1435 if (rettv_list_alloc(rettv) == OK)
1436 {
1437 char_u *msg = get_tv_string_chk(&argvars[0]);
1438
1439 if (msg != NULL)
1440 {
1441 pumitem_T *array;
1442 int size = split_message(msg, &array);
1443 int i;
1444
1445 /* Skip the first and last item, they are always empty. */
1446 for (i = 1; i < size - 1; ++i)
1447 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
1448 vim_free(array);
1449 }
1450 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001451}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001452# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001453#endif
1454
1455/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001456 * "browse(save, title, initdir, default)" function
1457 */
1458 static void
1459f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1460{
1461#ifdef FEAT_BROWSE
1462 int save;
1463 char_u *title;
1464 char_u *initdir;
1465 char_u *defname;
1466 char_u buf[NUMBUFLEN];
1467 char_u buf2[NUMBUFLEN];
1468 int error = FALSE;
1469
1470 save = (int)get_tv_number_chk(&argvars[0], &error);
1471 title = get_tv_string_chk(&argvars[1]);
1472 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1473 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1474
1475 if (error || title == NULL || initdir == NULL || defname == NULL)
1476 rettv->vval.v_string = NULL;
1477 else
1478 rettv->vval.v_string =
1479 do_browse(save ? BROWSE_SAVE : 0,
1480 title, defname, NULL, initdir, NULL, curbuf);
1481#else
1482 rettv->vval.v_string = NULL;
1483#endif
1484 rettv->v_type = VAR_STRING;
1485}
1486
1487/*
1488 * "browsedir(title, initdir)" function
1489 */
1490 static void
1491f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1492{
1493#ifdef FEAT_BROWSE
1494 char_u *title;
1495 char_u *initdir;
1496 char_u buf[NUMBUFLEN];
1497
1498 title = get_tv_string_chk(&argvars[0]);
1499 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1500
1501 if (title == NULL || initdir == NULL)
1502 rettv->vval.v_string = NULL;
1503 else
1504 rettv->vval.v_string = do_browse(BROWSE_DIR,
1505 title, NULL, NULL, initdir, NULL, curbuf);
1506#else
1507 rettv->vval.v_string = NULL;
1508#endif
1509 rettv->v_type = VAR_STRING;
1510}
1511
1512static buf_T *find_buffer(typval_T *avar);
1513
1514/*
1515 * Find a buffer by number or exact name.
1516 */
1517 static buf_T *
1518find_buffer(typval_T *avar)
1519{
1520 buf_T *buf = NULL;
1521
1522 if (avar->v_type == VAR_NUMBER)
1523 buf = buflist_findnr((int)avar->vval.v_number);
1524 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1525 {
1526 buf = buflist_findname_exp(avar->vval.v_string);
1527 if (buf == NULL)
1528 {
1529 /* No full path name match, try a match with a URL or a "nofile"
1530 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001531 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001532 if (buf->b_fname != NULL
1533 && (path_with_url(buf->b_fname)
1534#ifdef FEAT_QUICKFIX
1535 || bt_nofile(buf)
1536#endif
1537 )
1538 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1539 break;
1540 }
1541 }
1542 return buf;
1543}
1544
1545/*
1546 * "bufexists(expr)" function
1547 */
1548 static void
1549f_bufexists(typval_T *argvars, typval_T *rettv)
1550{
1551 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1552}
1553
1554/*
1555 * "buflisted(expr)" function
1556 */
1557 static void
1558f_buflisted(typval_T *argvars, typval_T *rettv)
1559{
1560 buf_T *buf;
1561
1562 buf = find_buffer(&argvars[0]);
1563 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1564}
1565
1566/*
1567 * "bufloaded(expr)" function
1568 */
1569 static void
1570f_bufloaded(typval_T *argvars, typval_T *rettv)
1571{
1572 buf_T *buf;
1573
1574 buf = find_buffer(&argvars[0]);
1575 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1576}
1577
1578 buf_T *
1579buflist_find_by_name(char_u *name, int curtab_only)
1580{
1581 int save_magic;
1582 char_u *save_cpo;
1583 buf_T *buf;
1584
1585 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1586 save_magic = p_magic;
1587 p_magic = TRUE;
1588 save_cpo = p_cpo;
1589 p_cpo = (char_u *)"";
1590
1591 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1592 TRUE, FALSE, curtab_only));
1593
1594 p_magic = save_magic;
1595 p_cpo = save_cpo;
1596 return buf;
1597}
1598
1599/*
1600 * Get buffer by number or pattern.
1601 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001602 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603get_buf_tv(typval_T *tv, int curtab_only)
1604{
1605 char_u *name = tv->vval.v_string;
1606 buf_T *buf;
1607
1608 if (tv->v_type == VAR_NUMBER)
1609 return buflist_findnr((int)tv->vval.v_number);
1610 if (tv->v_type != VAR_STRING)
1611 return NULL;
1612 if (name == NULL || *name == NUL)
1613 return curbuf;
1614 if (name[0] == '$' && name[1] == NUL)
1615 return lastbuf;
1616
1617 buf = buflist_find_by_name(name, curtab_only);
1618
1619 /* If not found, try expanding the name, like done for bufexists(). */
1620 if (buf == NULL)
1621 buf = find_buffer(tv);
1622
1623 return buf;
1624}
1625
1626/*
1627 * "bufname(expr)" function
1628 */
1629 static void
1630f_bufname(typval_T *argvars, typval_T *rettv)
1631{
1632 buf_T *buf;
1633
1634 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1635 ++emsg_off;
1636 buf = get_buf_tv(&argvars[0], FALSE);
1637 rettv->v_type = VAR_STRING;
1638 if (buf != NULL && buf->b_fname != NULL)
1639 rettv->vval.v_string = vim_strsave(buf->b_fname);
1640 else
1641 rettv->vval.v_string = NULL;
1642 --emsg_off;
1643}
1644
1645/*
1646 * "bufnr(expr)" function
1647 */
1648 static void
1649f_bufnr(typval_T *argvars, typval_T *rettv)
1650{
1651 buf_T *buf;
1652 int error = FALSE;
1653 char_u *name;
1654
1655 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1656 ++emsg_off;
1657 buf = get_buf_tv(&argvars[0], FALSE);
1658 --emsg_off;
1659
1660 /* If the buffer isn't found and the second argument is not zero create a
1661 * new buffer. */
1662 if (buf == NULL
1663 && argvars[1].v_type != VAR_UNKNOWN
1664 && get_tv_number_chk(&argvars[1], &error) != 0
1665 && !error
1666 && (name = get_tv_string_chk(&argvars[0])) != NULL
1667 && !error)
1668 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1669
1670 if (buf != NULL)
1671 rettv->vval.v_number = buf->b_fnum;
1672 else
1673 rettv->vval.v_number = -1;
1674}
1675
1676 static void
1677buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1678{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001679 win_T *wp;
1680 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 buf_T *buf;
1682
1683 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1684 ++emsg_off;
1685 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001686 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 {
1688 ++winnr;
1689 if (wp->w_buffer == buf)
1690 break;
1691 }
1692 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693 --emsg_off;
1694}
1695
1696/*
1697 * "bufwinid(nr)" function
1698 */
1699 static void
1700f_bufwinid(typval_T *argvars, typval_T *rettv)
1701{
1702 buf_win_common(argvars, rettv, FALSE);
1703}
1704
1705/*
1706 * "bufwinnr(nr)" function
1707 */
1708 static void
1709f_bufwinnr(typval_T *argvars, typval_T *rettv)
1710{
1711 buf_win_common(argvars, rettv, TRUE);
1712}
1713
1714/*
1715 * "byte2line(byte)" function
1716 */
1717 static void
1718f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1719{
1720#ifndef FEAT_BYTEOFF
1721 rettv->vval.v_number = -1;
1722#else
1723 long boff = 0;
1724
1725 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1726 if (boff < 0)
1727 rettv->vval.v_number = -1;
1728 else
1729 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1730 (linenr_T)0, &boff);
1731#endif
1732}
1733
1734 static void
1735byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1736{
1737#ifdef FEAT_MBYTE
1738 char_u *t;
1739#endif
1740 char_u *str;
1741 varnumber_T idx;
1742
1743 str = get_tv_string_chk(&argvars[0]);
1744 idx = get_tv_number_chk(&argvars[1], NULL);
1745 rettv->vval.v_number = -1;
1746 if (str == NULL || idx < 0)
1747 return;
1748
1749#ifdef FEAT_MBYTE
1750 t = str;
1751 for ( ; idx > 0; idx--)
1752 {
1753 if (*t == NUL) /* EOL reached */
1754 return;
1755 if (enc_utf8 && comp)
1756 t += utf_ptr2len(t);
1757 else
1758 t += (*mb_ptr2len)(t);
1759 }
1760 rettv->vval.v_number = (varnumber_T)(t - str);
1761#else
1762 if ((size_t)idx <= STRLEN(str))
1763 rettv->vval.v_number = idx;
1764#endif
1765}
1766
1767/*
1768 * "byteidx()" function
1769 */
1770 static void
1771f_byteidx(typval_T *argvars, typval_T *rettv)
1772{
1773 byteidx(argvars, rettv, FALSE);
1774}
1775
1776/*
1777 * "byteidxcomp()" function
1778 */
1779 static void
1780f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1781{
1782 byteidx(argvars, rettv, TRUE);
1783}
1784
1785/*
1786 * "call(func, arglist [, dict])" function
1787 */
1788 static void
1789f_call(typval_T *argvars, typval_T *rettv)
1790{
1791 char_u *func;
1792 partial_T *partial = NULL;
1793 dict_T *selfdict = NULL;
1794
1795 if (argvars[1].v_type != VAR_LIST)
1796 {
1797 EMSG(_(e_listreq));
1798 return;
1799 }
1800 if (argvars[1].vval.v_list == NULL)
1801 return;
1802
1803 if (argvars[0].v_type == VAR_FUNC)
1804 func = argvars[0].vval.v_string;
1805 else if (argvars[0].v_type == VAR_PARTIAL)
1806 {
1807 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001808 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001809 }
1810 else
1811 func = get_tv_string(&argvars[0]);
1812 if (*func == NUL)
1813 return; /* type error or empty name */
1814
1815 if (argvars[2].v_type != VAR_UNKNOWN)
1816 {
1817 if (argvars[2].v_type != VAR_DICT)
1818 {
1819 EMSG(_(e_dictreq));
1820 return;
1821 }
1822 selfdict = argvars[2].vval.v_dict;
1823 }
1824
1825 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1826}
1827
1828#ifdef FEAT_FLOAT
1829/*
1830 * "ceil({float})" function
1831 */
1832 static void
1833f_ceil(typval_T *argvars, typval_T *rettv)
1834{
1835 float_T f = 0.0;
1836
1837 rettv->v_type = VAR_FLOAT;
1838 if (get_float_arg(argvars, &f) == OK)
1839 rettv->vval.v_float = ceil(f);
1840 else
1841 rettv->vval.v_float = 0.0;
1842}
1843#endif
1844
1845#ifdef FEAT_JOB_CHANNEL
1846/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001847 * "ch_canread()" function
1848 */
1849 static void
1850f_ch_canread(typval_T *argvars, typval_T *rettv)
1851{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001852 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001853
1854 rettv->vval.v_number = 0;
1855 if (channel != NULL)
1856 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1857 || channel_has_readahead(channel, PART_OUT)
1858 || channel_has_readahead(channel, PART_ERR);
1859}
1860
1861/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001862 * "ch_close()" function
1863 */
1864 static void
1865f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1866{
1867 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1868
1869 if (channel != NULL)
1870 {
1871 channel_close(channel, FALSE);
1872 channel_clear(channel);
1873 }
1874}
1875
1876/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001877 * "ch_close()" function
1878 */
1879 static void
1880f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1881{
1882 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1883
1884 if (channel != NULL)
1885 channel_close_in(channel);
1886}
1887
1888/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 * "ch_getbufnr()" function
1890 */
1891 static void
1892f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1893{
1894 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1895
1896 rettv->vval.v_number = -1;
1897 if (channel != NULL)
1898 {
1899 char_u *what = get_tv_string(&argvars[1]);
1900 int part;
1901
1902 if (STRCMP(what, "err") == 0)
1903 part = PART_ERR;
1904 else if (STRCMP(what, "out") == 0)
1905 part = PART_OUT;
1906 else if (STRCMP(what, "in") == 0)
1907 part = PART_IN;
1908 else
1909 part = PART_SOCK;
1910 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1911 rettv->vval.v_number =
1912 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1913 }
1914}
1915
1916/*
1917 * "ch_getjob()" function
1918 */
1919 static void
1920f_ch_getjob(typval_T *argvars, typval_T *rettv)
1921{
1922 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1923
1924 if (channel != NULL)
1925 {
1926 rettv->v_type = VAR_JOB;
1927 rettv->vval.v_job = channel->ch_job;
1928 if (channel->ch_job != NULL)
1929 ++channel->ch_job->jv_refcount;
1930 }
1931}
1932
1933/*
1934 * "ch_info()" function
1935 */
1936 static void
1937f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1938{
1939 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1940
1941 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1942 channel_info(channel, rettv->vval.v_dict);
1943}
1944
1945/*
1946 * "ch_log()" function
1947 */
1948 static void
1949f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1950{
1951 char_u *msg = get_tv_string(&argvars[0]);
1952 channel_T *channel = NULL;
1953
1954 if (argvars[1].v_type != VAR_UNKNOWN)
1955 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
1956
1957 ch_log(channel, (char *)msg);
1958}
1959
1960/*
1961 * "ch_logfile()" function
1962 */
1963 static void
1964f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
1965{
1966 char_u *fname;
1967 char_u *opt = (char_u *)"";
1968 char_u buf[NUMBUFLEN];
1969
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02001970 /* Don't open a file in restricted mode. */
1971 if (check_restricted() || check_secure())
1972 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001973 fname = get_tv_string(&argvars[0]);
1974 if (argvars[1].v_type == VAR_STRING)
1975 opt = get_tv_string_buf(&argvars[1], buf);
1976 ch_logfile(fname, opt);
1977}
1978
1979/*
1980 * "ch_open()" function
1981 */
1982 static void
1983f_ch_open(typval_T *argvars, typval_T *rettv)
1984{
1985 rettv->v_type = VAR_CHANNEL;
1986 if (check_restricted() || check_secure())
1987 return;
1988 rettv->vval.v_channel = channel_open_func(argvars);
1989}
1990
1991/*
1992 * "ch_read()" function
1993 */
1994 static void
1995f_ch_read(typval_T *argvars, typval_T *rettv)
1996{
1997 common_channel_read(argvars, rettv, FALSE);
1998}
1999
2000/*
2001 * "ch_readraw()" function
2002 */
2003 static void
2004f_ch_readraw(typval_T *argvars, typval_T *rettv)
2005{
2006 common_channel_read(argvars, rettv, TRUE);
2007}
2008
2009/*
2010 * "ch_evalexpr()" function
2011 */
2012 static void
2013f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2014{
2015 ch_expr_common(argvars, rettv, TRUE);
2016}
2017
2018/*
2019 * "ch_sendexpr()" function
2020 */
2021 static void
2022f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2023{
2024 ch_expr_common(argvars, rettv, FALSE);
2025}
2026
2027/*
2028 * "ch_evalraw()" function
2029 */
2030 static void
2031f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2032{
2033 ch_raw_common(argvars, rettv, TRUE);
2034}
2035
2036/*
2037 * "ch_sendraw()" function
2038 */
2039 static void
2040f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2041{
2042 ch_raw_common(argvars, rettv, FALSE);
2043}
2044
2045/*
2046 * "ch_setoptions()" function
2047 */
2048 static void
2049f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2050{
2051 channel_T *channel;
2052 jobopt_T opt;
2053
2054 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2055 if (channel == NULL)
2056 return;
2057 clear_job_options(&opt);
2058 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002059 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002060 channel_set_options(channel, &opt);
2061 free_job_options(&opt);
2062}
2063
2064/*
2065 * "ch_status()" function
2066 */
2067 static void
2068f_ch_status(typval_T *argvars, typval_T *rettv)
2069{
2070 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002071 jobopt_T opt;
2072 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002073
2074 /* return an empty string by default */
2075 rettv->v_type = VAR_STRING;
2076 rettv->vval.v_string = NULL;
2077
2078 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002079
2080 if (argvars[1].v_type != VAR_UNKNOWN)
2081 {
2082 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002083 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002084 && (opt.jo_set & JO_PART))
2085 part = opt.jo_part;
2086 }
2087
2088 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089}
2090#endif
2091
2092/*
2093 * "changenr()" function
2094 */
2095 static void
2096f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2097{
2098 rettv->vval.v_number = curbuf->b_u_seq_cur;
2099}
2100
2101/*
2102 * "char2nr(string)" function
2103 */
2104 static void
2105f_char2nr(typval_T *argvars, typval_T *rettv)
2106{
2107#ifdef FEAT_MBYTE
2108 if (has_mbyte)
2109 {
2110 int utf8 = 0;
2111
2112 if (argvars[1].v_type != VAR_UNKNOWN)
2113 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2114
2115 if (utf8)
2116 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2117 else
2118 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2119 }
2120 else
2121#endif
2122 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2123}
2124
2125/*
2126 * "cindent(lnum)" function
2127 */
2128 static void
2129f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2130{
2131#ifdef FEAT_CINDENT
2132 pos_T pos;
2133 linenr_T lnum;
2134
2135 pos = curwin->w_cursor;
2136 lnum = get_tv_lnum(argvars);
2137 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2138 {
2139 curwin->w_cursor.lnum = lnum;
2140 rettv->vval.v_number = get_c_indent();
2141 curwin->w_cursor = pos;
2142 }
2143 else
2144#endif
2145 rettv->vval.v_number = -1;
2146}
2147
2148/*
2149 * "clearmatches()" function
2150 */
2151 static void
2152f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2153{
2154#ifdef FEAT_SEARCH_EXTRA
2155 clear_matches(curwin);
2156#endif
2157}
2158
2159/*
2160 * "col(string)" function
2161 */
2162 static void
2163f_col(typval_T *argvars, typval_T *rettv)
2164{
2165 colnr_T col = 0;
2166 pos_T *fp;
2167 int fnum = curbuf->b_fnum;
2168
2169 fp = var2fpos(&argvars[0], FALSE, &fnum);
2170 if (fp != NULL && fnum == curbuf->b_fnum)
2171 {
2172 if (fp->col == MAXCOL)
2173 {
2174 /* '> can be MAXCOL, get the length of the line then */
2175 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2176 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2177 else
2178 col = MAXCOL;
2179 }
2180 else
2181 {
2182 col = fp->col + 1;
2183#ifdef FEAT_VIRTUALEDIT
2184 /* col(".") when the cursor is on the NUL at the end of the line
2185 * because of "coladd" can be seen as an extra column. */
2186 if (virtual_active() && fp == &curwin->w_cursor)
2187 {
2188 char_u *p = ml_get_cursor();
2189
2190 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2191 curwin->w_virtcol - curwin->w_cursor.coladd))
2192 {
2193# ifdef FEAT_MBYTE
2194 int l;
2195
2196 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2197 col += l;
2198# else
2199 if (*p != NUL && p[1] == NUL)
2200 ++col;
2201# endif
2202 }
2203 }
2204#endif
2205 }
2206 }
2207 rettv->vval.v_number = col;
2208}
2209
2210#if defined(FEAT_INS_EXPAND)
2211/*
2212 * "complete()" function
2213 */
2214 static void
2215f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2216{
2217 int startcol;
2218
2219 if ((State & INSERT) == 0)
2220 {
2221 EMSG(_("E785: complete() can only be used in Insert mode"));
2222 return;
2223 }
2224
2225 /* Check for undo allowed here, because if something was already inserted
2226 * the line was already saved for undo and this check isn't done. */
2227 if (!undo_allowed())
2228 return;
2229
2230 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2231 {
2232 EMSG(_(e_invarg));
2233 return;
2234 }
2235
2236 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2237 if (startcol <= 0)
2238 return;
2239
2240 set_completion(startcol - 1, argvars[1].vval.v_list);
2241}
2242
2243/*
2244 * "complete_add()" function
2245 */
2246 static void
2247f_complete_add(typval_T *argvars, typval_T *rettv)
2248{
2249 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2250}
2251
2252/*
2253 * "complete_check()" function
2254 */
2255 static void
2256f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2257{
2258 int saved = RedrawingDisabled;
2259
2260 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002261 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002262 rettv->vval.v_number = compl_interrupted;
2263 RedrawingDisabled = saved;
2264}
2265#endif
2266
2267/*
2268 * "confirm(message, buttons[, default [, type]])" function
2269 */
2270 static void
2271f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2272{
2273#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2274 char_u *message;
2275 char_u *buttons = NULL;
2276 char_u buf[NUMBUFLEN];
2277 char_u buf2[NUMBUFLEN];
2278 int def = 1;
2279 int type = VIM_GENERIC;
2280 char_u *typestr;
2281 int error = FALSE;
2282
2283 message = get_tv_string_chk(&argvars[0]);
2284 if (message == NULL)
2285 error = TRUE;
2286 if (argvars[1].v_type != VAR_UNKNOWN)
2287 {
2288 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2289 if (buttons == NULL)
2290 error = TRUE;
2291 if (argvars[2].v_type != VAR_UNKNOWN)
2292 {
2293 def = (int)get_tv_number_chk(&argvars[2], &error);
2294 if (argvars[3].v_type != VAR_UNKNOWN)
2295 {
2296 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2297 if (typestr == NULL)
2298 error = TRUE;
2299 else
2300 {
2301 switch (TOUPPER_ASC(*typestr))
2302 {
2303 case 'E': type = VIM_ERROR; break;
2304 case 'Q': type = VIM_QUESTION; break;
2305 case 'I': type = VIM_INFO; break;
2306 case 'W': type = VIM_WARNING; break;
2307 case 'G': type = VIM_GENERIC; break;
2308 }
2309 }
2310 }
2311 }
2312 }
2313
2314 if (buttons == NULL || *buttons == NUL)
2315 buttons = (char_u *)_("&Ok");
2316
2317 if (!error)
2318 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2319 def, NULL, FALSE);
2320#endif
2321}
2322
2323/*
2324 * "copy()" function
2325 */
2326 static void
2327f_copy(typval_T *argvars, typval_T *rettv)
2328{
2329 item_copy(&argvars[0], rettv, FALSE, 0);
2330}
2331
2332#ifdef FEAT_FLOAT
2333/*
2334 * "cos()" function
2335 */
2336 static void
2337f_cos(typval_T *argvars, typval_T *rettv)
2338{
2339 float_T f = 0.0;
2340
2341 rettv->v_type = VAR_FLOAT;
2342 if (get_float_arg(argvars, &f) == OK)
2343 rettv->vval.v_float = cos(f);
2344 else
2345 rettv->vval.v_float = 0.0;
2346}
2347
2348/*
2349 * "cosh()" function
2350 */
2351 static void
2352f_cosh(typval_T *argvars, typval_T *rettv)
2353{
2354 float_T f = 0.0;
2355
2356 rettv->v_type = VAR_FLOAT;
2357 if (get_float_arg(argvars, &f) == OK)
2358 rettv->vval.v_float = cosh(f);
2359 else
2360 rettv->vval.v_float = 0.0;
2361}
2362#endif
2363
2364/*
2365 * "count()" function
2366 */
2367 static void
2368f_count(typval_T *argvars, typval_T *rettv)
2369{
2370 long n = 0;
2371 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002372 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002373
Bram Moolenaar9966b212017-07-28 16:46:57 +02002374 if (argvars[2].v_type != VAR_UNKNOWN)
2375 ic = (int)get_tv_number_chk(&argvars[2], &error);
2376
2377 if (argvars[0].v_type == VAR_STRING)
2378 {
2379 char_u *expr = get_tv_string_chk(&argvars[1]);
2380 char_u *p = argvars[0].vval.v_string;
2381 char_u *next;
2382
2383 if (!error && expr != NULL && p != NULL)
2384 {
2385 if (ic)
2386 {
2387 size_t len = STRLEN(expr);
2388
2389 while (*p != NUL)
2390 {
2391 if (MB_STRNICMP(p, expr, len) == 0)
2392 {
2393 ++n;
2394 p += len;
2395 }
2396 else
2397 MB_PTR_ADV(p);
2398 }
2399 }
2400 else
2401 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2402 != NULL)
2403 {
2404 ++n;
2405 p = next + STRLEN(expr);
2406 }
2407 }
2408
2409 }
2410 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002411 {
2412 listitem_T *li;
2413 list_T *l;
2414 long idx;
2415
2416 if ((l = argvars[0].vval.v_list) != NULL)
2417 {
2418 li = l->lv_first;
2419 if (argvars[2].v_type != VAR_UNKNOWN)
2420 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002421 if (argvars[3].v_type != VAR_UNKNOWN)
2422 {
2423 idx = (long)get_tv_number_chk(&argvars[3], &error);
2424 if (!error)
2425 {
2426 li = list_find(l, idx);
2427 if (li == NULL)
2428 EMSGN(_(e_listidx), idx);
2429 }
2430 }
2431 if (error)
2432 li = NULL;
2433 }
2434
2435 for ( ; li != NULL; li = li->li_next)
2436 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2437 ++n;
2438 }
2439 }
2440 else if (argvars[0].v_type == VAR_DICT)
2441 {
2442 int todo;
2443 dict_T *d;
2444 hashitem_T *hi;
2445
2446 if ((d = argvars[0].vval.v_dict) != NULL)
2447 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 if (argvars[2].v_type != VAR_UNKNOWN)
2449 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 if (argvars[3].v_type != VAR_UNKNOWN)
2451 EMSG(_(e_invarg));
2452 }
2453
2454 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2455 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2456 {
2457 if (!HASHITEM_EMPTY(hi))
2458 {
2459 --todo;
2460 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2461 ++n;
2462 }
2463 }
2464 }
2465 }
2466 else
2467 EMSG2(_(e_listdictarg), "count()");
2468 rettv->vval.v_number = n;
2469}
2470
2471/*
2472 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2473 *
2474 * Checks the existence of a cscope connection.
2475 */
2476 static void
2477f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2478{
2479#ifdef FEAT_CSCOPE
2480 int num = 0;
2481 char_u *dbpath = NULL;
2482 char_u *prepend = NULL;
2483 char_u buf[NUMBUFLEN];
2484
2485 if (argvars[0].v_type != VAR_UNKNOWN
2486 && argvars[1].v_type != VAR_UNKNOWN)
2487 {
2488 num = (int)get_tv_number(&argvars[0]);
2489 dbpath = get_tv_string(&argvars[1]);
2490 if (argvars[2].v_type != VAR_UNKNOWN)
2491 prepend = get_tv_string_buf(&argvars[2], buf);
2492 }
2493
2494 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2495#endif
2496}
2497
2498/*
2499 * "cursor(lnum, col)" function, or
2500 * "cursor(list)"
2501 *
2502 * Moves the cursor to the specified line and column.
2503 * Returns 0 when the position could be set, -1 otherwise.
2504 */
2505 static void
2506f_cursor(typval_T *argvars, typval_T *rettv)
2507{
2508 long line, col;
2509#ifdef FEAT_VIRTUALEDIT
2510 long coladd = 0;
2511#endif
2512 int set_curswant = TRUE;
2513
2514 rettv->vval.v_number = -1;
2515 if (argvars[1].v_type == VAR_UNKNOWN)
2516 {
2517 pos_T pos;
2518 colnr_T curswant = -1;
2519
2520 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2521 {
2522 EMSG(_(e_invarg));
2523 return;
2524 }
2525 line = pos.lnum;
2526 col = pos.col;
2527#ifdef FEAT_VIRTUALEDIT
2528 coladd = pos.coladd;
2529#endif
2530 if (curswant >= 0)
2531 {
2532 curwin->w_curswant = curswant - 1;
2533 set_curswant = FALSE;
2534 }
2535 }
2536 else
2537 {
2538 line = get_tv_lnum(argvars);
2539 col = (long)get_tv_number_chk(&argvars[1], NULL);
2540#ifdef FEAT_VIRTUALEDIT
2541 if (argvars[2].v_type != VAR_UNKNOWN)
2542 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2543#endif
2544 }
2545 if (line < 0 || col < 0
2546#ifdef FEAT_VIRTUALEDIT
2547 || coladd < 0
2548#endif
2549 )
2550 return; /* type error; errmsg already given */
2551 if (line > 0)
2552 curwin->w_cursor.lnum = line;
2553 if (col > 0)
2554 curwin->w_cursor.col = col - 1;
2555#ifdef FEAT_VIRTUALEDIT
2556 curwin->w_cursor.coladd = coladd;
2557#endif
2558
2559 /* Make sure the cursor is in a valid position. */
2560 check_cursor();
2561#ifdef FEAT_MBYTE
2562 /* Correct cursor for multi-byte character. */
2563 if (has_mbyte)
2564 mb_adjust_cursor();
2565#endif
2566
2567 curwin->w_set_curswant = set_curswant;
2568 rettv->vval.v_number = 0;
2569}
2570
2571/*
2572 * "deepcopy()" function
2573 */
2574 static void
2575f_deepcopy(typval_T *argvars, typval_T *rettv)
2576{
2577 int noref = 0;
2578 int copyID;
2579
2580 if (argvars[1].v_type != VAR_UNKNOWN)
2581 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2582 if (noref < 0 || noref > 1)
2583 EMSG(_(e_invarg));
2584 else
2585 {
2586 copyID = get_copyID();
2587 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2588 }
2589}
2590
2591/*
2592 * "delete()" function
2593 */
2594 static void
2595f_delete(typval_T *argvars, typval_T *rettv)
2596{
2597 char_u nbuf[NUMBUFLEN];
2598 char_u *name;
2599 char_u *flags;
2600
2601 rettv->vval.v_number = -1;
2602 if (check_restricted() || check_secure())
2603 return;
2604
2605 name = get_tv_string(&argvars[0]);
2606 if (name == NULL || *name == NUL)
2607 {
2608 EMSG(_(e_invarg));
2609 return;
2610 }
2611
2612 if (argvars[1].v_type != VAR_UNKNOWN)
2613 flags = get_tv_string_buf(&argvars[1], nbuf);
2614 else
2615 flags = (char_u *)"";
2616
2617 if (*flags == NUL)
2618 /* delete a file */
2619 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2620 else if (STRCMP(flags, "d") == 0)
2621 /* delete an empty directory */
2622 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2623 else if (STRCMP(flags, "rf") == 0)
2624 /* delete a directory recursively */
2625 rettv->vval.v_number = delete_recursive(name);
2626 else
2627 EMSG2(_(e_invexpr2), flags);
2628}
2629
2630/*
2631 * "did_filetype()" function
2632 */
2633 static void
2634f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2635{
2636#ifdef FEAT_AUTOCMD
2637 rettv->vval.v_number = did_filetype;
2638#endif
2639}
2640
2641/*
2642 * "diff_filler()" function
2643 */
2644 static void
2645f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2646{
2647#ifdef FEAT_DIFF
2648 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2649#endif
2650}
2651
2652/*
2653 * "diff_hlID()" function
2654 */
2655 static void
2656f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2657{
2658#ifdef FEAT_DIFF
2659 linenr_T lnum = get_tv_lnum(argvars);
2660 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002661 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002662 static int fnum = 0;
2663 static int change_start = 0;
2664 static int change_end = 0;
2665 static hlf_T hlID = (hlf_T)0;
2666 int filler_lines;
2667 int col;
2668
2669 if (lnum < 0) /* ignore type error in {lnum} arg */
2670 lnum = 0;
2671 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002672 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002673 || fnum != curbuf->b_fnum)
2674 {
2675 /* New line, buffer, change: need to get the values. */
2676 filler_lines = diff_check(curwin, lnum);
2677 if (filler_lines < 0)
2678 {
2679 if (filler_lines == -1)
2680 {
2681 change_start = MAXCOL;
2682 change_end = -1;
2683 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2684 hlID = HLF_ADD; /* added line */
2685 else
2686 hlID = HLF_CHD; /* changed line */
2687 }
2688 else
2689 hlID = HLF_ADD; /* added line */
2690 }
2691 else
2692 hlID = (hlf_T)0;
2693 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002694 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002695 fnum = curbuf->b_fnum;
2696 }
2697
2698 if (hlID == HLF_CHD || hlID == HLF_TXD)
2699 {
2700 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2701 if (col >= change_start && col <= change_end)
2702 hlID = HLF_TXD; /* changed text */
2703 else
2704 hlID = HLF_CHD; /* changed line */
2705 }
2706 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2707#endif
2708}
2709
2710/*
2711 * "empty({expr})" function
2712 */
2713 static void
2714f_empty(typval_T *argvars, typval_T *rettv)
2715{
2716 int n = FALSE;
2717
2718 switch (argvars[0].v_type)
2719 {
2720 case VAR_STRING:
2721 case VAR_FUNC:
2722 n = argvars[0].vval.v_string == NULL
2723 || *argvars[0].vval.v_string == NUL;
2724 break;
2725 case VAR_PARTIAL:
2726 n = FALSE;
2727 break;
2728 case VAR_NUMBER:
2729 n = argvars[0].vval.v_number == 0;
2730 break;
2731 case VAR_FLOAT:
2732#ifdef FEAT_FLOAT
2733 n = argvars[0].vval.v_float == 0.0;
2734 break;
2735#endif
2736 case VAR_LIST:
2737 n = argvars[0].vval.v_list == NULL
2738 || argvars[0].vval.v_list->lv_first == NULL;
2739 break;
2740 case VAR_DICT:
2741 n = argvars[0].vval.v_dict == NULL
2742 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2743 break;
2744 case VAR_SPECIAL:
2745 n = argvars[0].vval.v_number != VVAL_TRUE;
2746 break;
2747
2748 case VAR_JOB:
2749#ifdef FEAT_JOB_CHANNEL
2750 n = argvars[0].vval.v_job == NULL
2751 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2752 break;
2753#endif
2754 case VAR_CHANNEL:
2755#ifdef FEAT_JOB_CHANNEL
2756 n = argvars[0].vval.v_channel == NULL
2757 || !channel_is_open(argvars[0].vval.v_channel);
2758 break;
2759#endif
2760 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002761 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 n = TRUE;
2763 break;
2764 }
2765
2766 rettv->vval.v_number = n;
2767}
2768
2769/*
2770 * "escape({string}, {chars})" function
2771 */
2772 static void
2773f_escape(typval_T *argvars, typval_T *rettv)
2774{
2775 char_u buf[NUMBUFLEN];
2776
2777 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2778 get_tv_string_buf(&argvars[1], buf));
2779 rettv->v_type = VAR_STRING;
2780}
2781
2782/*
2783 * "eval()" function
2784 */
2785 static void
2786f_eval(typval_T *argvars, typval_T *rettv)
2787{
2788 char_u *s, *p;
2789
2790 s = get_tv_string_chk(&argvars[0]);
2791 if (s != NULL)
2792 s = skipwhite(s);
2793
2794 p = s;
2795 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2796 {
2797 if (p != NULL && !aborting())
2798 EMSG2(_(e_invexpr2), p);
2799 need_clr_eos = FALSE;
2800 rettv->v_type = VAR_NUMBER;
2801 rettv->vval.v_number = 0;
2802 }
2803 else if (*s != NUL)
2804 EMSG(_(e_trailing));
2805}
2806
2807/*
2808 * "eventhandler()" function
2809 */
2810 static void
2811f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2812{
2813 rettv->vval.v_number = vgetc_busy;
2814}
2815
2816/*
2817 * "executable()" function
2818 */
2819 static void
2820f_executable(typval_T *argvars, typval_T *rettv)
2821{
2822 char_u *name = get_tv_string(&argvars[0]);
2823
2824 /* Check in $PATH and also check directly if there is a directory name. */
2825 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2826 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2827}
2828
2829static garray_T redir_execute_ga;
2830
2831/*
2832 * Append "value[value_len]" to the execute() output.
2833 */
2834 void
2835execute_redir_str(char_u *value, int value_len)
2836{
2837 int len;
2838
2839 if (value_len == -1)
2840 len = (int)STRLEN(value); /* Append the entire string */
2841 else
2842 len = value_len; /* Append only "value_len" characters */
2843 if (ga_grow(&redir_execute_ga, len) == OK)
2844 {
2845 mch_memmove((char *)redir_execute_ga.ga_data
2846 + redir_execute_ga.ga_len, value, len);
2847 redir_execute_ga.ga_len += len;
2848 }
2849}
2850
2851/*
2852 * Get next line from a list.
2853 * Called by do_cmdline() to get the next line.
2854 * Returns allocated string, or NULL for end of function.
2855 */
2856
2857 static char_u *
2858get_list_line(
2859 int c UNUSED,
2860 void *cookie,
2861 int indent UNUSED)
2862{
2863 listitem_T **p = (listitem_T **)cookie;
2864 listitem_T *item = *p;
2865 char_u buf[NUMBUFLEN];
2866 char_u *s;
2867
2868 if (item == NULL)
2869 return NULL;
2870 s = get_tv_string_buf_chk(&item->li_tv, buf);
2871 *p = item->li_next;
2872 return s == NULL ? NULL : vim_strsave(s);
2873}
2874
2875/*
2876 * "execute()" function
2877 */
2878 static void
2879f_execute(typval_T *argvars, typval_T *rettv)
2880{
2881 char_u *cmd = NULL;
2882 list_T *list = NULL;
2883 int save_msg_silent = msg_silent;
2884 int save_emsg_silent = emsg_silent;
2885 int save_emsg_noredir = emsg_noredir;
2886 int save_redir_execute = redir_execute;
2887 garray_T save_ga;
2888
2889 rettv->vval.v_string = NULL;
2890 rettv->v_type = VAR_STRING;
2891
2892 if (argvars[0].v_type == VAR_LIST)
2893 {
2894 list = argvars[0].vval.v_list;
2895 if (list == NULL || list->lv_first == NULL)
2896 /* empty list, no commands, empty output */
2897 return;
2898 ++list->lv_refcount;
2899 }
2900 else
2901 {
2902 cmd = get_tv_string_chk(&argvars[0]);
2903 if (cmd == NULL)
2904 return;
2905 }
2906
2907 if (argvars[1].v_type != VAR_UNKNOWN)
2908 {
2909 char_u buf[NUMBUFLEN];
2910 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2911
2912 if (s == NULL)
2913 return;
2914 if (STRNCMP(s, "silent", 6) == 0)
2915 ++msg_silent;
2916 if (STRCMP(s, "silent!") == 0)
2917 {
2918 emsg_silent = TRUE;
2919 emsg_noredir = TRUE;
2920 }
2921 }
2922 else
2923 ++msg_silent;
2924
2925 if (redir_execute)
2926 save_ga = redir_execute_ga;
2927 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2928 redir_execute = TRUE;
2929
2930 if (cmd != NULL)
2931 do_cmdline_cmd(cmd);
2932 else
2933 {
2934 listitem_T *item = list->lv_first;
2935
2936 do_cmdline(NULL, get_list_line, (void *)&item,
2937 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2938 --list->lv_refcount;
2939 }
2940
Bram Moolenaard297f352017-01-29 20:31:21 +01002941 /* Need to append a NUL to the result. */
2942 if (ga_grow(&redir_execute_ga, 1) == OK)
2943 {
2944 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2945 rettv->vval.v_string = redir_execute_ga.ga_data;
2946 }
2947 else
2948 {
2949 ga_clear(&redir_execute_ga);
2950 rettv->vval.v_string = NULL;
2951 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002952 msg_silent = save_msg_silent;
2953 emsg_silent = save_emsg_silent;
2954 emsg_noredir = save_emsg_noredir;
2955
2956 redir_execute = save_redir_execute;
2957 if (redir_execute)
2958 redir_execute_ga = save_ga;
2959
2960 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
2961 * line. Put it back in the first column. */
2962 msg_col = 0;
2963}
2964
2965/*
2966 * "exepath()" function
2967 */
2968 static void
2969f_exepath(typval_T *argvars, typval_T *rettv)
2970{
2971 char_u *p = NULL;
2972
2973 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
2974 rettv->v_type = VAR_STRING;
2975 rettv->vval.v_string = p;
2976}
2977
2978/*
2979 * "exists()" function
2980 */
2981 static void
2982f_exists(typval_T *argvars, typval_T *rettv)
2983{
2984 char_u *p;
2985 char_u *name;
2986 int n = FALSE;
2987 int len = 0;
2988
2989 p = get_tv_string(&argvars[0]);
2990 if (*p == '$') /* environment variable */
2991 {
2992 /* first try "normal" environment variables (fast) */
2993 if (mch_getenv(p + 1) != NULL)
2994 n = TRUE;
2995 else
2996 {
2997 /* try expanding things like $VIM and ${HOME} */
2998 p = expand_env_save(p);
2999 if (p != NULL && *p != '$')
3000 n = TRUE;
3001 vim_free(p);
3002 }
3003 }
3004 else if (*p == '&' || *p == '+') /* option */
3005 {
3006 n = (get_option_tv(&p, NULL, TRUE) == OK);
3007 if (*skipwhite(p) != NUL)
3008 n = FALSE; /* trailing garbage */
3009 }
3010 else if (*p == '*') /* internal or user defined function */
3011 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003012 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003013 }
3014 else if (*p == ':')
3015 {
3016 n = cmd_exists(p + 1);
3017 }
3018 else if (*p == '#')
3019 {
3020#ifdef FEAT_AUTOCMD
3021 if (p[1] == '#')
3022 n = autocmd_supported(p + 2);
3023 else
3024 n = au_exists(p + 1);
3025#endif
3026 }
3027 else /* internal variable */
3028 {
3029 char_u *tofree;
3030 typval_T tv;
3031
3032 /* get_name_len() takes care of expanding curly braces */
3033 name = p;
3034 len = get_name_len(&p, &tofree, TRUE, FALSE);
3035 if (len > 0)
3036 {
3037 if (tofree != NULL)
3038 name = tofree;
3039 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
3040 if (n)
3041 {
3042 /* handle d.key, l[idx], f(expr) */
3043 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
3044 if (n)
3045 clear_tv(&tv);
3046 }
3047 }
3048 if (*p != NUL)
3049 n = FALSE;
3050
3051 vim_free(tofree);
3052 }
3053
3054 rettv->vval.v_number = n;
3055}
3056
3057#ifdef FEAT_FLOAT
3058/*
3059 * "exp()" function
3060 */
3061 static void
3062f_exp(typval_T *argvars, typval_T *rettv)
3063{
3064 float_T f = 0.0;
3065
3066 rettv->v_type = VAR_FLOAT;
3067 if (get_float_arg(argvars, &f) == OK)
3068 rettv->vval.v_float = exp(f);
3069 else
3070 rettv->vval.v_float = 0.0;
3071}
3072#endif
3073
3074/*
3075 * "expand()" function
3076 */
3077 static void
3078f_expand(typval_T *argvars, typval_T *rettv)
3079{
3080 char_u *s;
3081 int len;
3082 char_u *errormsg;
3083 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3084 expand_T xpc;
3085 int error = FALSE;
3086 char_u *result;
3087
3088 rettv->v_type = VAR_STRING;
3089 if (argvars[1].v_type != VAR_UNKNOWN
3090 && argvars[2].v_type != VAR_UNKNOWN
3091 && get_tv_number_chk(&argvars[2], &error)
3092 && !error)
3093 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003094 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003095 }
3096
3097 s = get_tv_string(&argvars[0]);
3098 if (*s == '%' || *s == '#' || *s == '<')
3099 {
3100 ++emsg_off;
3101 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3102 --emsg_off;
3103 if (rettv->v_type == VAR_LIST)
3104 {
3105 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3106 list_append_string(rettv->vval.v_list, result, -1);
3107 else
3108 vim_free(result);
3109 }
3110 else
3111 rettv->vval.v_string = result;
3112 }
3113 else
3114 {
3115 /* When the optional second argument is non-zero, don't remove matches
3116 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3117 if (argvars[1].v_type != VAR_UNKNOWN
3118 && get_tv_number_chk(&argvars[1], &error))
3119 options |= WILD_KEEP_ALL;
3120 if (!error)
3121 {
3122 ExpandInit(&xpc);
3123 xpc.xp_context = EXPAND_FILES;
3124 if (p_wic)
3125 options += WILD_ICASE;
3126 if (rettv->v_type == VAR_STRING)
3127 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3128 options, WILD_ALL);
3129 else if (rettv_list_alloc(rettv) != FAIL)
3130 {
3131 int i;
3132
3133 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3134 for (i = 0; i < xpc.xp_numfiles; i++)
3135 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3136 ExpandCleanup(&xpc);
3137 }
3138 }
3139 else
3140 rettv->vval.v_string = NULL;
3141 }
3142}
3143
3144/*
3145 * "extend(list, list [, idx])" function
3146 * "extend(dict, dict [, action])" function
3147 */
3148 static void
3149f_extend(typval_T *argvars, typval_T *rettv)
3150{
3151 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3152
3153 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3154 {
3155 list_T *l1, *l2;
3156 listitem_T *item;
3157 long before;
3158 int error = FALSE;
3159
3160 l1 = argvars[0].vval.v_list;
3161 l2 = argvars[1].vval.v_list;
3162 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3163 && l2 != NULL)
3164 {
3165 if (argvars[2].v_type != VAR_UNKNOWN)
3166 {
3167 before = (long)get_tv_number_chk(&argvars[2], &error);
3168 if (error)
3169 return; /* type error; errmsg already given */
3170
3171 if (before == l1->lv_len)
3172 item = NULL;
3173 else
3174 {
3175 item = list_find(l1, before);
3176 if (item == NULL)
3177 {
3178 EMSGN(_(e_listidx), before);
3179 return;
3180 }
3181 }
3182 }
3183 else
3184 item = NULL;
3185 list_extend(l1, l2, item);
3186
3187 copy_tv(&argvars[0], rettv);
3188 }
3189 }
3190 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3191 {
3192 dict_T *d1, *d2;
3193 char_u *action;
3194 int i;
3195
3196 d1 = argvars[0].vval.v_dict;
3197 d2 = argvars[1].vval.v_dict;
3198 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3199 && d2 != NULL)
3200 {
3201 /* Check the third argument. */
3202 if (argvars[2].v_type != VAR_UNKNOWN)
3203 {
3204 static char *(av[]) = {"keep", "force", "error"};
3205
3206 action = get_tv_string_chk(&argvars[2]);
3207 if (action == NULL)
3208 return; /* type error; errmsg already given */
3209 for (i = 0; i < 3; ++i)
3210 if (STRCMP(action, av[i]) == 0)
3211 break;
3212 if (i == 3)
3213 {
3214 EMSG2(_(e_invarg2), action);
3215 return;
3216 }
3217 }
3218 else
3219 action = (char_u *)"force";
3220
3221 dict_extend(d1, d2, action);
3222
3223 copy_tv(&argvars[0], rettv);
3224 }
3225 }
3226 else
3227 EMSG2(_(e_listdictarg), "extend()");
3228}
3229
3230/*
3231 * "feedkeys()" function
3232 */
3233 static void
3234f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3235{
3236 int remap = TRUE;
3237 int insert = FALSE;
3238 char_u *keys, *flags;
3239 char_u nbuf[NUMBUFLEN];
3240 int typed = FALSE;
3241 int execute = FALSE;
3242 int dangerous = FALSE;
3243 char_u *keys_esc;
3244
3245 /* This is not allowed in the sandbox. If the commands would still be
3246 * executed in the sandbox it would be OK, but it probably happens later,
3247 * when "sandbox" is no longer set. */
3248 if (check_secure())
3249 return;
3250
3251 keys = get_tv_string(&argvars[0]);
3252
3253 if (argvars[1].v_type != VAR_UNKNOWN)
3254 {
3255 flags = get_tv_string_buf(&argvars[1], nbuf);
3256 for ( ; *flags != NUL; ++flags)
3257 {
3258 switch (*flags)
3259 {
3260 case 'n': remap = FALSE; break;
3261 case 'm': remap = TRUE; break;
3262 case 't': typed = TRUE; break;
3263 case 'i': insert = TRUE; break;
3264 case 'x': execute = TRUE; break;
3265 case '!': dangerous = TRUE; break;
3266 }
3267 }
3268 }
3269
3270 if (*keys != NUL || execute)
3271 {
3272 /* Need to escape K_SPECIAL and CSI before putting the string in the
3273 * typeahead buffer. */
3274 keys_esc = vim_strsave_escape_csi(keys);
3275 if (keys_esc != NULL)
3276 {
3277 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3278 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3279 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003280 if (vgetc_busy
3281#ifdef FEAT_TIMERS
3282 || timer_busy
3283#endif
3284 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003285 typebuf_was_filled = TRUE;
3286 if (execute)
3287 {
3288 int save_msg_scroll = msg_scroll;
3289
3290 /* Avoid a 1 second delay when the keys start Insert mode. */
3291 msg_scroll = FALSE;
3292
Bram Moolenaar69fbc9e2017-09-14 20:37:57 +02003293#ifdef FEAT_TERMINAL
3294 if (term_use_loop())
3295 terminal_loop(FALSE);
3296 else
3297#endif
3298 {
3299 if (!dangerous)
3300 ++ex_normal_busy;
3301 exec_normal(TRUE);
3302 if (!dangerous)
3303 --ex_normal_busy;
3304 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003305 msg_scroll |= save_msg_scroll;
3306 }
3307 }
3308 }
3309}
3310
3311/*
3312 * "filereadable()" function
3313 */
3314 static void
3315f_filereadable(typval_T *argvars, typval_T *rettv)
3316{
3317 int fd;
3318 char_u *p;
3319 int n;
3320
3321#ifndef O_NONBLOCK
3322# define O_NONBLOCK 0
3323#endif
3324 p = get_tv_string(&argvars[0]);
3325 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3326 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3327 {
3328 n = TRUE;
3329 close(fd);
3330 }
3331 else
3332 n = FALSE;
3333
3334 rettv->vval.v_number = n;
3335}
3336
3337/*
3338 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3339 * rights to write into.
3340 */
3341 static void
3342f_filewritable(typval_T *argvars, typval_T *rettv)
3343{
3344 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3345}
3346
3347 static void
3348findfilendir(
3349 typval_T *argvars UNUSED,
3350 typval_T *rettv,
3351 int find_what UNUSED)
3352{
3353#ifdef FEAT_SEARCHPATH
3354 char_u *fname;
3355 char_u *fresult = NULL;
3356 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3357 char_u *p;
3358 char_u pathbuf[NUMBUFLEN];
3359 int count = 1;
3360 int first = TRUE;
3361 int error = FALSE;
3362#endif
3363
3364 rettv->vval.v_string = NULL;
3365 rettv->v_type = VAR_STRING;
3366
3367#ifdef FEAT_SEARCHPATH
3368 fname = get_tv_string(&argvars[0]);
3369
3370 if (argvars[1].v_type != VAR_UNKNOWN)
3371 {
3372 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3373 if (p == NULL)
3374 error = TRUE;
3375 else
3376 {
3377 if (*p != NUL)
3378 path = p;
3379
3380 if (argvars[2].v_type != VAR_UNKNOWN)
3381 count = (int)get_tv_number_chk(&argvars[2], &error);
3382 }
3383 }
3384
3385 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3386 error = TRUE;
3387
3388 if (*fname != NUL && !error)
3389 {
3390 do
3391 {
3392 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3393 vim_free(fresult);
3394 fresult = find_file_in_path_option(first ? fname : NULL,
3395 first ? (int)STRLEN(fname) : 0,
3396 0, first, path,
3397 find_what,
3398 curbuf->b_ffname,
3399 find_what == FINDFILE_DIR
3400 ? (char_u *)"" : curbuf->b_p_sua);
3401 first = FALSE;
3402
3403 if (fresult != NULL && rettv->v_type == VAR_LIST)
3404 list_append_string(rettv->vval.v_list, fresult, -1);
3405
3406 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3407 }
3408
3409 if (rettv->v_type == VAR_STRING)
3410 rettv->vval.v_string = fresult;
3411#endif
3412}
3413
3414/*
3415 * "filter()" function
3416 */
3417 static void
3418f_filter(typval_T *argvars, typval_T *rettv)
3419{
3420 filter_map(argvars, rettv, FALSE);
3421}
3422
3423/*
3424 * "finddir({fname}[, {path}[, {count}]])" function
3425 */
3426 static void
3427f_finddir(typval_T *argvars, typval_T *rettv)
3428{
3429 findfilendir(argvars, rettv, FINDFILE_DIR);
3430}
3431
3432/*
3433 * "findfile({fname}[, {path}[, {count}]])" function
3434 */
3435 static void
3436f_findfile(typval_T *argvars, typval_T *rettv)
3437{
3438 findfilendir(argvars, rettv, FINDFILE_FILE);
3439}
3440
3441#ifdef FEAT_FLOAT
3442/*
3443 * "float2nr({float})" function
3444 */
3445 static void
3446f_float2nr(typval_T *argvars, typval_T *rettv)
3447{
3448 float_T f = 0.0;
3449
3450 if (get_float_arg(argvars, &f) == OK)
3451 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003452 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003453 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003454 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003455 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003456 else
3457 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003458 }
3459}
3460
3461/*
3462 * "floor({float})" function
3463 */
3464 static void
3465f_floor(typval_T *argvars, typval_T *rettv)
3466{
3467 float_T f = 0.0;
3468
3469 rettv->v_type = VAR_FLOAT;
3470 if (get_float_arg(argvars, &f) == OK)
3471 rettv->vval.v_float = floor(f);
3472 else
3473 rettv->vval.v_float = 0.0;
3474}
3475
3476/*
3477 * "fmod()" function
3478 */
3479 static void
3480f_fmod(typval_T *argvars, typval_T *rettv)
3481{
3482 float_T fx = 0.0, fy = 0.0;
3483
3484 rettv->v_type = VAR_FLOAT;
3485 if (get_float_arg(argvars, &fx) == OK
3486 && get_float_arg(&argvars[1], &fy) == OK)
3487 rettv->vval.v_float = fmod(fx, fy);
3488 else
3489 rettv->vval.v_float = 0.0;
3490}
3491#endif
3492
3493/*
3494 * "fnameescape({string})" function
3495 */
3496 static void
3497f_fnameescape(typval_T *argvars, typval_T *rettv)
3498{
3499 rettv->vval.v_string = vim_strsave_fnameescape(
3500 get_tv_string(&argvars[0]), FALSE);
3501 rettv->v_type = VAR_STRING;
3502}
3503
3504/*
3505 * "fnamemodify({fname}, {mods})" function
3506 */
3507 static void
3508f_fnamemodify(typval_T *argvars, typval_T *rettv)
3509{
3510 char_u *fname;
3511 char_u *mods;
3512 int usedlen = 0;
3513 int len;
3514 char_u *fbuf = NULL;
3515 char_u buf[NUMBUFLEN];
3516
3517 fname = get_tv_string_chk(&argvars[0]);
3518 mods = get_tv_string_buf_chk(&argvars[1], buf);
3519 if (fname == NULL || mods == NULL)
3520 fname = NULL;
3521 else
3522 {
3523 len = (int)STRLEN(fname);
3524 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3525 }
3526
3527 rettv->v_type = VAR_STRING;
3528 if (fname == NULL)
3529 rettv->vval.v_string = NULL;
3530 else
3531 rettv->vval.v_string = vim_strnsave(fname, len);
3532 vim_free(fbuf);
3533}
3534
3535static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3536
3537/*
3538 * "foldclosed()" function
3539 */
3540 static void
3541foldclosed_both(
3542 typval_T *argvars UNUSED,
3543 typval_T *rettv,
3544 int end UNUSED)
3545{
3546#ifdef FEAT_FOLDING
3547 linenr_T lnum;
3548 linenr_T first, last;
3549
3550 lnum = get_tv_lnum(argvars);
3551 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3552 {
3553 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3554 {
3555 if (end)
3556 rettv->vval.v_number = (varnumber_T)last;
3557 else
3558 rettv->vval.v_number = (varnumber_T)first;
3559 return;
3560 }
3561 }
3562#endif
3563 rettv->vval.v_number = -1;
3564}
3565
3566/*
3567 * "foldclosed()" function
3568 */
3569 static void
3570f_foldclosed(typval_T *argvars, typval_T *rettv)
3571{
3572 foldclosed_both(argvars, rettv, FALSE);
3573}
3574
3575/*
3576 * "foldclosedend()" function
3577 */
3578 static void
3579f_foldclosedend(typval_T *argvars, typval_T *rettv)
3580{
3581 foldclosed_both(argvars, rettv, TRUE);
3582}
3583
3584/*
3585 * "foldlevel()" function
3586 */
3587 static void
3588f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3589{
3590#ifdef FEAT_FOLDING
3591 linenr_T lnum;
3592
3593 lnum = get_tv_lnum(argvars);
3594 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3595 rettv->vval.v_number = foldLevel(lnum);
3596#endif
3597}
3598
3599/*
3600 * "foldtext()" function
3601 */
3602 static void
3603f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3604{
3605#ifdef FEAT_FOLDING
3606 linenr_T foldstart;
3607 linenr_T foldend;
3608 char_u *dashes;
3609 linenr_T lnum;
3610 char_u *s;
3611 char_u *r;
3612 int len;
3613 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003614 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003615#endif
3616
3617 rettv->v_type = VAR_STRING;
3618 rettv->vval.v_string = NULL;
3619#ifdef FEAT_FOLDING
3620 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3621 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3622 dashes = get_vim_var_str(VV_FOLDDASHES);
3623 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3624 && dashes != NULL)
3625 {
3626 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003627 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003628 if (!linewhite(lnum))
3629 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003630
3631 /* Find interesting text in this line. */
3632 s = skipwhite(ml_get(lnum));
3633 /* skip C comment-start */
3634 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3635 {
3636 s = skipwhite(s + 2);
3637 if (*skipwhite(s) == NUL
3638 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3639 {
3640 s = skipwhite(ml_get(lnum + 1));
3641 if (*s == '*')
3642 s = skipwhite(s + 1);
3643 }
3644 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003645 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003646 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647 r = alloc((unsigned)(STRLEN(txt)
3648 + STRLEN(dashes) /* for %s */
3649 + 20 /* for %3ld */
3650 + STRLEN(s))); /* concatenated */
3651 if (r != NULL)
3652 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003653 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 len = (int)STRLEN(r);
3655 STRCAT(r, s);
3656 /* remove 'foldmarker' and 'commentstring' */
3657 foldtext_cleanup(r + len);
3658 rettv->vval.v_string = r;
3659 }
3660 }
3661#endif
3662}
3663
3664/*
3665 * "foldtextresult(lnum)" function
3666 */
3667 static void
3668f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3669{
3670#ifdef FEAT_FOLDING
3671 linenr_T lnum;
3672 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003673 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003674 foldinfo_T foldinfo;
3675 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003676 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677#endif
3678
3679 rettv->v_type = VAR_STRING;
3680 rettv->vval.v_string = NULL;
3681#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003682 if (entered)
3683 return; /* reject recursive use */
3684 entered = TRUE;
3685
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003686 lnum = get_tv_lnum(argvars);
3687 /* treat illegal types and illegal string values for {lnum} the same */
3688 if (lnum < 0)
3689 lnum = 0;
3690 fold_count = foldedCount(curwin, lnum, &foldinfo);
3691 if (fold_count > 0)
3692 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003693 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3694 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003695 if (text == buf)
3696 text = vim_strsave(text);
3697 rettv->vval.v_string = text;
3698 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003699
3700 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003701#endif
3702}
3703
3704/*
3705 * "foreground()" function
3706 */
3707 static void
3708f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3709{
3710#ifdef FEAT_GUI
3711 if (gui.in_use)
3712 gui_mch_set_foreground();
3713#else
3714# ifdef WIN32
3715 win32_set_foreground();
3716# endif
3717#endif
3718}
3719
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003721common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722{
3723 char_u *s;
3724 char_u *name;
3725 int use_string = FALSE;
3726 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003727 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003728
3729 if (argvars[0].v_type == VAR_FUNC)
3730 {
3731 /* function(MyFunc, [arg], dict) */
3732 s = argvars[0].vval.v_string;
3733 }
3734 else if (argvars[0].v_type == VAR_PARTIAL
3735 && argvars[0].vval.v_partial != NULL)
3736 {
3737 /* function(dict.MyFunc, [arg]) */
3738 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003739 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740 }
3741 else
3742 {
3743 /* function('MyFunc', [arg], dict) */
3744 s = get_tv_string(&argvars[0]);
3745 use_string = TRUE;
3746 }
3747
Bram Moolenaar843b8842016-08-21 14:36:15 +02003748 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003749 {
3750 name = s;
3751 trans_name = trans_function_name(&name, FALSE,
3752 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3753 if (*name != NUL)
3754 s = NULL;
3755 }
3756
Bram Moolenaar843b8842016-08-21 14:36:15 +02003757 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3758 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003759 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003760 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003761 else if (trans_name != NULL && (is_funcref
3762 ? find_func(trans_name) == NULL
3763 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003764 EMSG2(_("E700: Unknown function: %s"), s);
3765 else
3766 {
3767 int dict_idx = 0;
3768 int arg_idx = 0;
3769 list_T *list = NULL;
3770
3771 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3772 {
3773 char sid_buf[25];
3774 int off = *s == 's' ? 2 : 5;
3775
3776 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3777 * also be called from another script. Using trans_function_name()
3778 * would also work, but some plugins depend on the name being
3779 * printable text. */
3780 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3781 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3782 if (name != NULL)
3783 {
3784 STRCPY(name, sid_buf);
3785 STRCAT(name, s + off);
3786 }
3787 }
3788 else
3789 name = vim_strsave(s);
3790
3791 if (argvars[1].v_type != VAR_UNKNOWN)
3792 {
3793 if (argvars[2].v_type != VAR_UNKNOWN)
3794 {
3795 /* function(name, [args], dict) */
3796 arg_idx = 1;
3797 dict_idx = 2;
3798 }
3799 else if (argvars[1].v_type == VAR_DICT)
3800 /* function(name, dict) */
3801 dict_idx = 1;
3802 else
3803 /* function(name, [args]) */
3804 arg_idx = 1;
3805 if (dict_idx > 0)
3806 {
3807 if (argvars[dict_idx].v_type != VAR_DICT)
3808 {
3809 EMSG(_("E922: expected a dict"));
3810 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003811 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003812 }
3813 if (argvars[dict_idx].vval.v_dict == NULL)
3814 dict_idx = 0;
3815 }
3816 if (arg_idx > 0)
3817 {
3818 if (argvars[arg_idx].v_type != VAR_LIST)
3819 {
3820 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3821 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003822 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003823 }
3824 list = argvars[arg_idx].vval.v_list;
3825 if (list == NULL || list->lv_len == 0)
3826 arg_idx = 0;
3827 }
3828 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003829 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003830 {
3831 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3832
3833 /* result is a VAR_PARTIAL */
3834 if (pt == NULL)
3835 vim_free(name);
3836 else
3837 {
3838 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3839 {
3840 listitem_T *li;
3841 int i = 0;
3842 int arg_len = 0;
3843 int lv_len = 0;
3844
3845 if (arg_pt != NULL)
3846 arg_len = arg_pt->pt_argc;
3847 if (list != NULL)
3848 lv_len = list->lv_len;
3849 pt->pt_argc = arg_len + lv_len;
3850 pt->pt_argv = (typval_T *)alloc(
3851 sizeof(typval_T) * pt->pt_argc);
3852 if (pt->pt_argv == NULL)
3853 {
3854 vim_free(pt);
3855 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003856 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003857 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003858 for (i = 0; i < arg_len; i++)
3859 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3860 if (lv_len > 0)
3861 for (li = list->lv_first; li != NULL;
3862 li = li->li_next)
3863 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 }
3865
3866 /* For "function(dict.func, [], dict)" and "func" is a partial
3867 * use "dict". That is backwards compatible. */
3868 if (dict_idx > 0)
3869 {
3870 /* The dict is bound explicitly, pt_auto is FALSE. */
3871 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3872 ++pt->pt_dict->dv_refcount;
3873 }
3874 else if (arg_pt != NULL)
3875 {
3876 /* If the dict was bound automatically the result is also
3877 * bound automatically. */
3878 pt->pt_dict = arg_pt->pt_dict;
3879 pt->pt_auto = arg_pt->pt_auto;
3880 if (pt->pt_dict != NULL)
3881 ++pt->pt_dict->dv_refcount;
3882 }
3883
3884 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003885 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3886 {
3887 pt->pt_func = arg_pt->pt_func;
3888 func_ptr_ref(pt->pt_func);
3889 vim_free(name);
3890 }
3891 else if (is_funcref)
3892 {
3893 pt->pt_func = find_func(trans_name);
3894 func_ptr_ref(pt->pt_func);
3895 vim_free(name);
3896 }
3897 else
3898 {
3899 pt->pt_name = name;
3900 func_ref(name);
3901 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003902 }
3903 rettv->v_type = VAR_PARTIAL;
3904 rettv->vval.v_partial = pt;
3905 }
3906 else
3907 {
3908 /* result is a VAR_FUNC */
3909 rettv->v_type = VAR_FUNC;
3910 rettv->vval.v_string = name;
3911 func_ref(name);
3912 }
3913 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003914theend:
3915 vim_free(trans_name);
3916}
3917
3918/*
3919 * "funcref()" function
3920 */
3921 static void
3922f_funcref(typval_T *argvars, typval_T *rettv)
3923{
3924 common_function(argvars, rettv, TRUE);
3925}
3926
3927/*
3928 * "function()" function
3929 */
3930 static void
3931f_function(typval_T *argvars, typval_T *rettv)
3932{
3933 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934}
3935
3936/*
3937 * "garbagecollect()" function
3938 */
3939 static void
3940f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3941{
3942 /* This is postponed until we are back at the toplevel, because we may be
3943 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3944 want_garbage_collect = TRUE;
3945
3946 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3947 garbage_collect_at_exit = TRUE;
3948}
3949
3950/*
3951 * "get()" function
3952 */
3953 static void
3954f_get(typval_T *argvars, typval_T *rettv)
3955{
3956 listitem_T *li;
3957 list_T *l;
3958 dictitem_T *di;
3959 dict_T *d;
3960 typval_T *tv = NULL;
3961
3962 if (argvars[0].v_type == VAR_LIST)
3963 {
3964 if ((l = argvars[0].vval.v_list) != NULL)
3965 {
3966 int error = FALSE;
3967
3968 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3969 if (!error && li != NULL)
3970 tv = &li->li_tv;
3971 }
3972 }
3973 else if (argvars[0].v_type == VAR_DICT)
3974 {
3975 if ((d = argvars[0].vval.v_dict) != NULL)
3976 {
3977 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3978 if (di != NULL)
3979 tv = &di->di_tv;
3980 }
3981 }
3982 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3983 {
3984 partial_T *pt;
3985 partial_T fref_pt;
3986
3987 if (argvars[0].v_type == VAR_PARTIAL)
3988 pt = argvars[0].vval.v_partial;
3989 else
3990 {
3991 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3992 fref_pt.pt_name = argvars[0].vval.v_string;
3993 pt = &fref_pt;
3994 }
3995
3996 if (pt != NULL)
3997 {
3998 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003999 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004000
4001 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4002 {
4003 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004004 n = partial_name(pt);
4005 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004006 rettv->vval.v_string = NULL;
4007 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004008 {
4009 rettv->vval.v_string = vim_strsave(n);
4010 if (rettv->v_type == VAR_FUNC)
4011 func_ref(rettv->vval.v_string);
4012 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 }
4014 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004015 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004016 else if (STRCMP(what, "args") == 0)
4017 {
4018 rettv->v_type = VAR_LIST;
4019 if (rettv_list_alloc(rettv) == OK)
4020 {
4021 int i;
4022
4023 for (i = 0; i < pt->pt_argc; ++i)
4024 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4025 }
4026 }
4027 else
4028 EMSG2(_(e_invarg2), what);
4029 return;
4030 }
4031 }
4032 else
4033 EMSG2(_(e_listdictarg), "get()");
4034
4035 if (tv == NULL)
4036 {
4037 if (argvars[2].v_type != VAR_UNKNOWN)
4038 copy_tv(&argvars[2], rettv);
4039 }
4040 else
4041 copy_tv(tv, rettv);
4042}
4043
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004044#ifdef FEAT_SIGNS
4045/*
4046 * Returns information about signs placed in a buffer as list of dicts.
4047 */
4048 static void
4049get_buffer_signs(buf_T *buf, list_T *l)
4050{
4051 signlist_T *sign;
4052
4053 for (sign = buf->b_signlist; sign; sign = sign->next)
4054 {
4055 dict_T *d = dict_alloc();
4056
4057 if (d != NULL)
4058 {
4059 dict_add_nr_str(d, "id", sign->id, NULL);
4060 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004061 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004062
4063 list_append_dict(l, d);
4064 }
4065 }
4066}
4067#endif
4068
4069/*
4070 * Returns buffer options, variables and other attributes in a dictionary.
4071 */
4072 static dict_T *
4073get_buffer_info(buf_T *buf)
4074{
4075 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004076 tabpage_T *tp;
4077 win_T *wp;
4078 list_T *windows;
4079
4080 dict = dict_alloc();
4081 if (dict == NULL)
4082 return NULL;
4083
Bram Moolenaar33928832016-08-18 21:22:04 +02004084 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004085 dict_add_nr_str(dict, "name", 0L,
4086 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004087 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4088 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004089 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4090 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4091 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004092 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004093 dict_add_nr_str(dict, "hidden",
4094 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4095 NULL);
4096
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004097 /* Get a reference to buffer variables */
4098 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004099
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004100 /* List of windows displaying this buffer */
4101 windows = list_alloc();
4102 if (windows != NULL)
4103 {
4104 FOR_ALL_TAB_WINDOWS(tp, wp)
4105 if (wp->w_buffer == buf)
4106 list_append_number(windows, (varnumber_T)wp->w_id);
4107 dict_add_list(dict, "windows", windows);
4108 }
4109
4110#ifdef FEAT_SIGNS
4111 if (buf->b_signlist != NULL)
4112 {
4113 /* List of signs placed in this buffer */
4114 list_T *signs = list_alloc();
4115 if (signs != NULL)
4116 {
4117 get_buffer_signs(buf, signs);
4118 dict_add_list(dict, "signs", signs);
4119 }
4120 }
4121#endif
4122
4123 return dict;
4124}
4125
4126/*
4127 * "getbufinfo()" function
4128 */
4129 static void
4130f_getbufinfo(typval_T *argvars, typval_T *rettv)
4131{
4132 buf_T *buf = NULL;
4133 buf_T *argbuf = NULL;
4134 dict_T *d;
4135 int filtered = FALSE;
4136 int sel_buflisted = FALSE;
4137 int sel_bufloaded = FALSE;
4138
4139 if (rettv_list_alloc(rettv) != OK)
4140 return;
4141
4142 /* List of all the buffers or selected buffers */
4143 if (argvars[0].v_type == VAR_DICT)
4144 {
4145 dict_T *sel_d = argvars[0].vval.v_dict;
4146
4147 if (sel_d != NULL)
4148 {
4149 dictitem_T *di;
4150
4151 filtered = TRUE;
4152
4153 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4154 if (di != NULL && get_tv_number(&di->di_tv))
4155 sel_buflisted = TRUE;
4156
4157 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4158 if (di != NULL && get_tv_number(&di->di_tv))
4159 sel_bufloaded = TRUE;
4160 }
4161 }
4162 else if (argvars[0].v_type != VAR_UNKNOWN)
4163 {
4164 /* Information about one buffer. Argument specifies the buffer */
4165 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4166 ++emsg_off;
4167 argbuf = get_buf_tv(&argvars[0], FALSE);
4168 --emsg_off;
4169 if (argbuf == NULL)
4170 return;
4171 }
4172
4173 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004174 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004175 {
4176 if (argbuf != NULL && argbuf != buf)
4177 continue;
4178 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
4179 || (sel_buflisted && !buf->b_p_bl)))
4180 continue;
4181
4182 d = get_buffer_info(buf);
4183 if (d != NULL)
4184 list_append_dict(rettv->vval.v_list, d);
4185 if (argbuf != NULL)
4186 return;
4187 }
4188}
4189
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004190static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4191
4192/*
4193 * Get line or list of lines from buffer "buf" into "rettv".
4194 * Return a range (from start to end) of lines in rettv from the specified
4195 * buffer.
4196 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4197 */
4198 static void
4199get_buffer_lines(
4200 buf_T *buf,
4201 linenr_T start,
4202 linenr_T end,
4203 int retlist,
4204 typval_T *rettv)
4205{
4206 char_u *p;
4207
4208 rettv->v_type = VAR_STRING;
4209 rettv->vval.v_string = NULL;
4210 if (retlist && rettv_list_alloc(rettv) == FAIL)
4211 return;
4212
4213 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4214 return;
4215
4216 if (!retlist)
4217 {
4218 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4219 p = ml_get_buf(buf, start, FALSE);
4220 else
4221 p = (char_u *)"";
4222 rettv->vval.v_string = vim_strsave(p);
4223 }
4224 else
4225 {
4226 if (end < start)
4227 return;
4228
4229 if (start < 1)
4230 start = 1;
4231 if (end > buf->b_ml.ml_line_count)
4232 end = buf->b_ml.ml_line_count;
4233 while (start <= end)
4234 if (list_append_string(rettv->vval.v_list,
4235 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4236 break;
4237 }
4238}
4239
4240/*
4241 * Get the lnum from the first argument.
4242 * Also accepts "$", then "buf" is used.
4243 * Returns 0 on error.
4244 */
4245 static linenr_T
4246get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4247{
4248 if (argvars[0].v_type == VAR_STRING
4249 && argvars[0].vval.v_string != NULL
4250 && argvars[0].vval.v_string[0] == '$'
4251 && buf != NULL)
4252 return buf->b_ml.ml_line_count;
4253 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4254}
4255
4256/*
4257 * "getbufline()" function
4258 */
4259 static void
4260f_getbufline(typval_T *argvars, typval_T *rettv)
4261{
4262 linenr_T lnum;
4263 linenr_T end;
4264 buf_T *buf;
4265
4266 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4267 ++emsg_off;
4268 buf = get_buf_tv(&argvars[0], FALSE);
4269 --emsg_off;
4270
4271 lnum = get_tv_lnum_buf(&argvars[1], buf);
4272 if (argvars[2].v_type == VAR_UNKNOWN)
4273 end = lnum;
4274 else
4275 end = get_tv_lnum_buf(&argvars[2], buf);
4276
4277 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4278}
4279
4280/*
4281 * "getbufvar()" function
4282 */
4283 static void
4284f_getbufvar(typval_T *argvars, typval_T *rettv)
4285{
4286 buf_T *buf;
4287 buf_T *save_curbuf;
4288 char_u *varname;
4289 dictitem_T *v;
4290 int done = FALSE;
4291
4292 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4293 varname = get_tv_string_chk(&argvars[1]);
4294 ++emsg_off;
4295 buf = get_buf_tv(&argvars[0], FALSE);
4296
4297 rettv->v_type = VAR_STRING;
4298 rettv->vval.v_string = NULL;
4299
4300 if (buf != NULL && varname != NULL)
4301 {
4302 /* set curbuf to be our buf, temporarily */
4303 save_curbuf = curbuf;
4304 curbuf = buf;
4305
Bram Moolenaar30567352016-08-27 21:25:44 +02004306 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004308 if (varname[1] == NUL)
4309 {
4310 /* get all buffer-local options in a dict */
4311 dict_T *opts = get_winbuf_options(TRUE);
4312
4313 if (opts != NULL)
4314 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004315 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004316 done = TRUE;
4317 }
4318 }
4319 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4320 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004321 done = TRUE;
4322 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004323 else
4324 {
4325 /* Look up the variable. */
4326 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4327 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4328 'b', varname, FALSE);
4329 if (v != NULL)
4330 {
4331 copy_tv(&v->di_tv, rettv);
4332 done = TRUE;
4333 }
4334 }
4335
4336 /* restore previous notion of curbuf */
4337 curbuf = save_curbuf;
4338 }
4339
4340 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4341 /* use the default value */
4342 copy_tv(&argvars[2], rettv);
4343
4344 --emsg_off;
4345}
4346
4347/*
4348 * "getchar()" function
4349 */
4350 static void
4351f_getchar(typval_T *argvars, typval_T *rettv)
4352{
4353 varnumber_T n;
4354 int error = FALSE;
4355
4356 /* Position the cursor. Needed after a message that ends in a space. */
4357 windgoto(msg_row, msg_col);
4358
4359 ++no_mapping;
4360 ++allow_keys;
4361 for (;;)
4362 {
4363 if (argvars[0].v_type == VAR_UNKNOWN)
4364 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004365 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004366 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4367 /* getchar(1): only check if char avail */
4368 n = vpeekc_any();
4369 else if (error || vpeekc_any() == NUL)
4370 /* illegal argument or getchar(0) and no char avail: return zero */
4371 n = 0;
4372 else
4373 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004374 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004375
4376 if (n == K_IGNORE)
4377 continue;
4378 break;
4379 }
4380 --no_mapping;
4381 --allow_keys;
4382
4383 set_vim_var_nr(VV_MOUSE_WIN, 0);
4384 set_vim_var_nr(VV_MOUSE_WINID, 0);
4385 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4386 set_vim_var_nr(VV_MOUSE_COL, 0);
4387
4388 rettv->vval.v_number = n;
4389 if (IS_SPECIAL(n) || mod_mask != 0)
4390 {
4391 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4392 int i = 0;
4393
4394 /* Turn a special key into three bytes, plus modifier. */
4395 if (mod_mask != 0)
4396 {
4397 temp[i++] = K_SPECIAL;
4398 temp[i++] = KS_MODIFIER;
4399 temp[i++] = mod_mask;
4400 }
4401 if (IS_SPECIAL(n))
4402 {
4403 temp[i++] = K_SPECIAL;
4404 temp[i++] = K_SECOND(n);
4405 temp[i++] = K_THIRD(n);
4406 }
4407#ifdef FEAT_MBYTE
4408 else if (has_mbyte)
4409 i += (*mb_char2bytes)(n, temp + i);
4410#endif
4411 else
4412 temp[i++] = n;
4413 temp[i++] = NUL;
4414 rettv->v_type = VAR_STRING;
4415 rettv->vval.v_string = vim_strsave(temp);
4416
4417#ifdef FEAT_MOUSE
4418 if (is_mouse_key(n))
4419 {
4420 int row = mouse_row;
4421 int col = mouse_col;
4422 win_T *win;
4423 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004424 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004425 int winnr = 1;
4426
4427 if (row >= 0 && col >= 0)
4428 {
4429 /* Find the window at the mouse coordinates and compute the
4430 * text position. */
4431 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004432 if (win == NULL)
4433 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004434 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004435 for (wp = firstwin; wp != win; wp = wp->w_next)
4436 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004437 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4438 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4439 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4440 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4441 }
4442 }
4443#endif
4444 }
4445}
4446
4447/*
4448 * "getcharmod()" function
4449 */
4450 static void
4451f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4452{
4453 rettv->vval.v_number = mod_mask;
4454}
4455
4456/*
4457 * "getcharsearch()" function
4458 */
4459 static void
4460f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4461{
4462 if (rettv_dict_alloc(rettv) != FAIL)
4463 {
4464 dict_T *dict = rettv->vval.v_dict;
4465
4466 dict_add_nr_str(dict, "char", 0L, last_csearch());
4467 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4468 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4469 }
4470}
4471
4472/*
4473 * "getcmdline()" function
4474 */
4475 static void
4476f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4477{
4478 rettv->v_type = VAR_STRING;
4479 rettv->vval.v_string = get_cmdline_str();
4480}
4481
4482/*
4483 * "getcmdpos()" function
4484 */
4485 static void
4486f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4487{
4488 rettv->vval.v_number = get_cmdline_pos() + 1;
4489}
4490
4491/*
4492 * "getcmdtype()" function
4493 */
4494 static void
4495f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4496{
4497 rettv->v_type = VAR_STRING;
4498 rettv->vval.v_string = alloc(2);
4499 if (rettv->vval.v_string != NULL)
4500 {
4501 rettv->vval.v_string[0] = get_cmdline_type();
4502 rettv->vval.v_string[1] = NUL;
4503 }
4504}
4505
4506/*
4507 * "getcmdwintype()" function
4508 */
4509 static void
4510f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4511{
4512 rettv->v_type = VAR_STRING;
4513 rettv->vval.v_string = NULL;
4514#ifdef FEAT_CMDWIN
4515 rettv->vval.v_string = alloc(2);
4516 if (rettv->vval.v_string != NULL)
4517 {
4518 rettv->vval.v_string[0] = cmdwin_type;
4519 rettv->vval.v_string[1] = NUL;
4520 }
4521#endif
4522}
4523
4524#if defined(FEAT_CMDL_COMPL)
4525/*
4526 * "getcompletion()" function
4527 */
4528 static void
4529f_getcompletion(typval_T *argvars, typval_T *rettv)
4530{
4531 char_u *pat;
4532 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004533 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004534 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4535 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004536
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004537 if (argvars[2].v_type != VAR_UNKNOWN)
4538 filtered = get_tv_number_chk(&argvars[2], NULL);
4539
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004540 if (p_wic)
4541 options |= WILD_ICASE;
4542
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004543 /* For filtered results, 'wildignore' is used */
4544 if (!filtered)
4545 options |= WILD_KEEP_ALL;
4546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004547 ExpandInit(&xpc);
4548 xpc.xp_pattern = get_tv_string(&argvars[0]);
4549 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4550 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4551 if (xpc.xp_context == EXPAND_NOTHING)
4552 {
4553 if (argvars[1].v_type == VAR_STRING)
4554 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4555 else
4556 EMSG(_(e_invarg));
4557 return;
4558 }
4559
4560# if defined(FEAT_MENU)
4561 if (xpc.xp_context == EXPAND_MENUS)
4562 {
4563 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4564 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4565 }
4566# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004567#ifdef FEAT_CSCOPE
4568 if (xpc.xp_context == EXPAND_CSCOPE)
4569 {
4570 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4571 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4572 }
4573#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004574#ifdef FEAT_SIGNS
4575 if (xpc.xp_context == EXPAND_SIGN)
4576 {
4577 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4578 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4579 }
4580#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004581
4582 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4583 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4584 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004585 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004586
4587 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4588
4589 for (i = 0; i < xpc.xp_numfiles; i++)
4590 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4591 }
4592 vim_free(pat);
4593 ExpandCleanup(&xpc);
4594}
4595#endif
4596
4597/*
4598 * "getcwd()" function
4599 */
4600 static void
4601f_getcwd(typval_T *argvars, typval_T *rettv)
4602{
4603 win_T *wp = NULL;
4604 char_u *cwd;
4605
4606 rettv->v_type = VAR_STRING;
4607 rettv->vval.v_string = NULL;
4608
4609 wp = find_tabwin(&argvars[0], &argvars[1]);
4610 if (wp != NULL)
4611 {
4612 if (wp->w_localdir != NULL)
4613 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4614 else if (globaldir != NULL)
4615 rettv->vval.v_string = vim_strsave(globaldir);
4616 else
4617 {
4618 cwd = alloc(MAXPATHL);
4619 if (cwd != NULL)
4620 {
4621 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4622 rettv->vval.v_string = vim_strsave(cwd);
4623 vim_free(cwd);
4624 }
4625 }
4626#ifdef BACKSLASH_IN_FILENAME
4627 if (rettv->vval.v_string != NULL)
4628 slash_adjust(rettv->vval.v_string);
4629#endif
4630 }
4631}
4632
4633/*
4634 * "getfontname()" function
4635 */
4636 static void
4637f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4638{
4639 rettv->v_type = VAR_STRING;
4640 rettv->vval.v_string = NULL;
4641#ifdef FEAT_GUI
4642 if (gui.in_use)
4643 {
4644 GuiFont font;
4645 char_u *name = NULL;
4646
4647 if (argvars[0].v_type == VAR_UNKNOWN)
4648 {
4649 /* Get the "Normal" font. Either the name saved by
4650 * hl_set_font_name() or from the font ID. */
4651 font = gui.norm_font;
4652 name = hl_get_font_name();
4653 }
4654 else
4655 {
4656 name = get_tv_string(&argvars[0]);
4657 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4658 return;
4659 font = gui_mch_get_font(name, FALSE);
4660 if (font == NOFONT)
4661 return; /* Invalid font name, return empty string. */
4662 }
4663 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4664 if (argvars[0].v_type != VAR_UNKNOWN)
4665 gui_mch_free_font(font);
4666 }
4667#endif
4668}
4669
4670/*
4671 * "getfperm({fname})" function
4672 */
4673 static void
4674f_getfperm(typval_T *argvars, typval_T *rettv)
4675{
4676 char_u *fname;
4677 stat_T st;
4678 char_u *perm = NULL;
4679 char_u flags[] = "rwx";
4680 int i;
4681
4682 fname = get_tv_string(&argvars[0]);
4683
4684 rettv->v_type = VAR_STRING;
4685 if (mch_stat((char *)fname, &st) >= 0)
4686 {
4687 perm = vim_strsave((char_u *)"---------");
4688 if (perm != NULL)
4689 {
4690 for (i = 0; i < 9; i++)
4691 {
4692 if (st.st_mode & (1 << (8 - i)))
4693 perm[i] = flags[i % 3];
4694 }
4695 }
4696 }
4697 rettv->vval.v_string = perm;
4698}
4699
4700/*
4701 * "getfsize({fname})" function
4702 */
4703 static void
4704f_getfsize(typval_T *argvars, typval_T *rettv)
4705{
4706 char_u *fname;
4707 stat_T st;
4708
4709 fname = get_tv_string(&argvars[0]);
4710
4711 rettv->v_type = VAR_NUMBER;
4712
4713 if (mch_stat((char *)fname, &st) >= 0)
4714 {
4715 if (mch_isdir(fname))
4716 rettv->vval.v_number = 0;
4717 else
4718 {
4719 rettv->vval.v_number = (varnumber_T)st.st_size;
4720
4721 /* non-perfect check for overflow */
4722 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4723 rettv->vval.v_number = -2;
4724 }
4725 }
4726 else
4727 rettv->vval.v_number = -1;
4728}
4729
4730/*
4731 * "getftime({fname})" function
4732 */
4733 static void
4734f_getftime(typval_T *argvars, typval_T *rettv)
4735{
4736 char_u *fname;
4737 stat_T st;
4738
4739 fname = get_tv_string(&argvars[0]);
4740
4741 if (mch_stat((char *)fname, &st) >= 0)
4742 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4743 else
4744 rettv->vval.v_number = -1;
4745}
4746
4747/*
4748 * "getftype({fname})" function
4749 */
4750 static void
4751f_getftype(typval_T *argvars, typval_T *rettv)
4752{
4753 char_u *fname;
4754 stat_T st;
4755 char_u *type = NULL;
4756 char *t;
4757
4758 fname = get_tv_string(&argvars[0]);
4759
4760 rettv->v_type = VAR_STRING;
4761 if (mch_lstat((char *)fname, &st) >= 0)
4762 {
4763#ifdef S_ISREG
4764 if (S_ISREG(st.st_mode))
4765 t = "file";
4766 else if (S_ISDIR(st.st_mode))
4767 t = "dir";
4768# ifdef S_ISLNK
4769 else if (S_ISLNK(st.st_mode))
4770 t = "link";
4771# endif
4772# ifdef S_ISBLK
4773 else if (S_ISBLK(st.st_mode))
4774 t = "bdev";
4775# endif
4776# ifdef S_ISCHR
4777 else if (S_ISCHR(st.st_mode))
4778 t = "cdev";
4779# endif
4780# ifdef S_ISFIFO
4781 else if (S_ISFIFO(st.st_mode))
4782 t = "fifo";
4783# endif
4784# ifdef S_ISSOCK
4785 else if (S_ISSOCK(st.st_mode))
4786 t = "fifo";
4787# endif
4788 else
4789 t = "other";
4790#else
4791# ifdef S_IFMT
4792 switch (st.st_mode & S_IFMT)
4793 {
4794 case S_IFREG: t = "file"; break;
4795 case S_IFDIR: t = "dir"; break;
4796# ifdef S_IFLNK
4797 case S_IFLNK: t = "link"; break;
4798# endif
4799# ifdef S_IFBLK
4800 case S_IFBLK: t = "bdev"; break;
4801# endif
4802# ifdef S_IFCHR
4803 case S_IFCHR: t = "cdev"; break;
4804# endif
4805# ifdef S_IFIFO
4806 case S_IFIFO: t = "fifo"; break;
4807# endif
4808# ifdef S_IFSOCK
4809 case S_IFSOCK: t = "socket"; break;
4810# endif
4811 default: t = "other";
4812 }
4813# else
4814 if (mch_isdir(fname))
4815 t = "dir";
4816 else
4817 t = "file";
4818# endif
4819#endif
4820 type = vim_strsave((char_u *)t);
4821 }
4822 rettv->vval.v_string = type;
4823}
4824
4825/*
4826 * "getline(lnum, [end])" function
4827 */
4828 static void
4829f_getline(typval_T *argvars, typval_T *rettv)
4830{
4831 linenr_T lnum;
4832 linenr_T end;
4833 int retlist;
4834
4835 lnum = get_tv_lnum(argvars);
4836 if (argvars[1].v_type == VAR_UNKNOWN)
4837 {
4838 end = 0;
4839 retlist = FALSE;
4840 }
4841 else
4842 {
4843 end = get_tv_lnum(&argvars[1]);
4844 retlist = TRUE;
4845 }
4846
4847 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4848}
4849
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004850#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004851 static void
4852get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4853{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004854 if (what_arg->v_type == VAR_UNKNOWN)
4855 {
4856 if (rettv_list_alloc(rettv) == OK)
4857 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004858 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004859 }
4860 else
4861 {
4862 if (rettv_dict_alloc(rettv) == OK)
4863 if (is_qf || (wp != NULL))
4864 {
4865 if (what_arg->v_type == VAR_DICT)
4866 {
4867 dict_T *d = what_arg->vval.v_dict;
4868
4869 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02004870 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004871 }
4872 else
4873 EMSG(_(e_dictreq));
4874 }
4875 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02004876}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004877#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02004878
4879/*
4880 * "getloclist()" function
4881 */
4882 static void
4883f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4884{
4885#ifdef FEAT_QUICKFIX
4886 win_T *wp;
4887
4888 wp = find_win_by_nr(&argvars[0], NULL);
4889 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
4890#endif
4891}
4892
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004893/*
4894 * "getmatches()" function
4895 */
4896 static void
4897f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4898{
4899#ifdef FEAT_SEARCH_EXTRA
4900 dict_T *dict;
4901 matchitem_T *cur = curwin->w_match_head;
4902 int i;
4903
4904 if (rettv_list_alloc(rettv) == OK)
4905 {
4906 while (cur != NULL)
4907 {
4908 dict = dict_alloc();
4909 if (dict == NULL)
4910 return;
4911 if (cur->match.regprog == NULL)
4912 {
4913 /* match added with matchaddpos() */
4914 for (i = 0; i < MAXPOSMATCH; ++i)
4915 {
4916 llpos_T *llpos;
4917 char buf[6];
4918 list_T *l;
4919
4920 llpos = &cur->pos.pos[i];
4921 if (llpos->lnum == 0)
4922 break;
4923 l = list_alloc();
4924 if (l == NULL)
4925 break;
4926 list_append_number(l, (varnumber_T)llpos->lnum);
4927 if (llpos->col > 0)
4928 {
4929 list_append_number(l, (varnumber_T)llpos->col);
4930 list_append_number(l, (varnumber_T)llpos->len);
4931 }
4932 sprintf(buf, "pos%d", i + 1);
4933 dict_add_list(dict, buf, l);
4934 }
4935 }
4936 else
4937 {
4938 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
4939 }
4940 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
4941 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
4942 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
4943# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
4944 if (cur->conceal_char)
4945 {
4946 char_u buf[MB_MAXBYTES + 1];
4947
4948 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
4949 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
4950 }
4951# endif
4952 list_append_dict(rettv->vval.v_list, dict);
4953 cur = cur->next;
4954 }
4955 }
4956#endif
4957}
4958
4959/*
4960 * "getpid()" function
4961 */
4962 static void
4963f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4964{
4965 rettv->vval.v_number = mch_get_pid();
4966}
4967
4968 static void
4969getpos_both(
4970 typval_T *argvars,
4971 typval_T *rettv,
4972 int getcurpos)
4973{
4974 pos_T *fp;
4975 list_T *l;
4976 int fnum = -1;
4977
4978 if (rettv_list_alloc(rettv) == OK)
4979 {
4980 l = rettv->vval.v_list;
4981 if (getcurpos)
4982 fp = &curwin->w_cursor;
4983 else
4984 fp = var2fpos(&argvars[0], TRUE, &fnum);
4985 if (fnum != -1)
4986 list_append_number(l, (varnumber_T)fnum);
4987 else
4988 list_append_number(l, (varnumber_T)0);
4989 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4990 : (varnumber_T)0);
4991 list_append_number(l, (fp != NULL)
4992 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4993 : (varnumber_T)0);
4994 list_append_number(l,
4995#ifdef FEAT_VIRTUALEDIT
4996 (fp != NULL) ? (varnumber_T)fp->coladd :
4997#endif
4998 (varnumber_T)0);
4999 if (getcurpos)
5000 {
5001 update_curswant();
5002 list_append_number(l, curwin->w_curswant == MAXCOL ?
5003 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5004 }
5005 }
5006 else
5007 rettv->vval.v_number = FALSE;
5008}
5009
5010
5011/*
5012 * "getcurpos()" function
5013 */
5014 static void
5015f_getcurpos(typval_T *argvars, typval_T *rettv)
5016{
5017 getpos_both(argvars, rettv, TRUE);
5018}
5019
5020/*
5021 * "getpos(string)" function
5022 */
5023 static void
5024f_getpos(typval_T *argvars, typval_T *rettv)
5025{
5026 getpos_both(argvars, rettv, FALSE);
5027}
5028
5029/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005030 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031 */
5032 static void
5033f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5034{
5035#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005036 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037#endif
5038}
5039
5040/*
5041 * "getreg()" function
5042 */
5043 static void
5044f_getreg(typval_T *argvars, typval_T *rettv)
5045{
5046 char_u *strregname;
5047 int regname;
5048 int arg2 = FALSE;
5049 int return_list = FALSE;
5050 int error = FALSE;
5051
5052 if (argvars[0].v_type != VAR_UNKNOWN)
5053 {
5054 strregname = get_tv_string_chk(&argvars[0]);
5055 error = strregname == NULL;
5056 if (argvars[1].v_type != VAR_UNKNOWN)
5057 {
5058 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5059 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5060 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5061 }
5062 }
5063 else
5064 strregname = get_vim_var_str(VV_REG);
5065
5066 if (error)
5067 return;
5068
5069 regname = (strregname == NULL ? '"' : *strregname);
5070 if (regname == 0)
5071 regname = '"';
5072
5073 if (return_list)
5074 {
5075 rettv->v_type = VAR_LIST;
5076 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5077 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5078 if (rettv->vval.v_list == NULL)
5079 (void)rettv_list_alloc(rettv);
5080 else
5081 ++rettv->vval.v_list->lv_refcount;
5082 }
5083 else
5084 {
5085 rettv->v_type = VAR_STRING;
5086 rettv->vval.v_string = get_reg_contents(regname,
5087 arg2 ? GREG_EXPR_SRC : 0);
5088 }
5089}
5090
5091/*
5092 * "getregtype()" function
5093 */
5094 static void
5095f_getregtype(typval_T *argvars, typval_T *rettv)
5096{
5097 char_u *strregname;
5098 int regname;
5099 char_u buf[NUMBUFLEN + 2];
5100 long reglen = 0;
5101
5102 if (argvars[0].v_type != VAR_UNKNOWN)
5103 {
5104 strregname = get_tv_string_chk(&argvars[0]);
5105 if (strregname == NULL) /* type error; errmsg already given */
5106 {
5107 rettv->v_type = VAR_STRING;
5108 rettv->vval.v_string = NULL;
5109 return;
5110 }
5111 }
5112 else
5113 /* Default to v:register */
5114 strregname = get_vim_var_str(VV_REG);
5115
5116 regname = (strregname == NULL ? '"' : *strregname);
5117 if (regname == 0)
5118 regname = '"';
5119
5120 buf[0] = NUL;
5121 buf[1] = NUL;
5122 switch (get_reg_type(regname, &reglen))
5123 {
5124 case MLINE: buf[0] = 'V'; break;
5125 case MCHAR: buf[0] = 'v'; break;
5126 case MBLOCK:
5127 buf[0] = Ctrl_V;
5128 sprintf((char *)buf + 1, "%ld", reglen + 1);
5129 break;
5130 }
5131 rettv->v_type = VAR_STRING;
5132 rettv->vval.v_string = vim_strsave(buf);
5133}
5134
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005135/*
5136 * Returns information (variables, options, etc.) about a tab page
5137 * as a dictionary.
5138 */
5139 static dict_T *
5140get_tabpage_info(tabpage_T *tp, int tp_idx)
5141{
5142 win_T *wp;
5143 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005144 list_T *l;
5145
5146 dict = dict_alloc();
5147 if (dict == NULL)
5148 return NULL;
5149
Bram Moolenaar33928832016-08-18 21:22:04 +02005150 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005151
5152 l = list_alloc();
5153 if (l != NULL)
5154 {
5155 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5156 wp; wp = wp->w_next)
5157 list_append_number(l, (varnumber_T)wp->w_id);
5158 dict_add_list(dict, "windows", l);
5159 }
5160
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005161 /* Make a reference to tabpage variables */
5162 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005163
5164 return dict;
5165}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005166
5167/*
5168 * "gettabinfo()" function
5169 */
5170 static void
5171f_gettabinfo(typval_T *argvars, typval_T *rettv)
5172{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005173 tabpage_T *tp, *tparg = NULL;
5174 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005175 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005176
5177 if (rettv_list_alloc(rettv) != OK)
5178 return;
5179
5180 if (argvars[0].v_type != VAR_UNKNOWN)
5181 {
5182 /* Information about one tab page */
5183 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5184 if (tparg == NULL)
5185 return;
5186 }
5187
5188 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005189 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005190 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005191 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005192 if (tparg != NULL && tp != tparg)
5193 continue;
5194 d = get_tabpage_info(tp, tpnr);
5195 if (d != NULL)
5196 list_append_dict(rettv->vval.v_list, d);
5197 if (tparg != NULL)
5198 return;
5199 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005200}
5201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005202/*
5203 * "gettabvar()" function
5204 */
5205 static void
5206f_gettabvar(typval_T *argvars, typval_T *rettv)
5207{
5208 win_T *oldcurwin;
5209 tabpage_T *tp, *oldtabpage;
5210 dictitem_T *v;
5211 char_u *varname;
5212 int done = FALSE;
5213
5214 rettv->v_type = VAR_STRING;
5215 rettv->vval.v_string = NULL;
5216
5217 varname = get_tv_string_chk(&argvars[1]);
5218 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5219 if (tp != NULL && varname != NULL)
5220 {
5221 /* Set tp to be our tabpage, temporarily. Also set the window to the
5222 * first window in the tabpage, otherwise the window is not valid. */
5223 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005224 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5225 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005226 {
5227 /* look up the variable */
5228 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5229 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5230 if (v != NULL)
5231 {
5232 copy_tv(&v->di_tv, rettv);
5233 done = TRUE;
5234 }
5235 }
5236
5237 /* restore previous notion of curwin */
5238 restore_win(oldcurwin, oldtabpage, TRUE);
5239 }
5240
5241 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5242 copy_tv(&argvars[2], rettv);
5243}
5244
5245/*
5246 * "gettabwinvar()" function
5247 */
5248 static void
5249f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5250{
5251 getwinvar(argvars, rettv, 1);
5252}
5253
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005254/*
5255 * Returns information about a window as a dictionary.
5256 */
5257 static dict_T *
5258get_win_info(win_T *wp, short tpnr, short winnr)
5259{
5260 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005261
5262 dict = dict_alloc();
5263 if (dict == NULL)
5264 return NULL;
5265
Bram Moolenaar33928832016-08-18 21:22:04 +02005266 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5267 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005268 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5269 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005270#ifdef FEAT_MENU
5271 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5272#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005273 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005274 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005275
Bram Moolenaar69905d12017-08-13 18:14:47 +02005276#ifdef FEAT_TERMINAL
5277 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5278#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005279#ifdef FEAT_QUICKFIX
5280 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5281 dict_add_nr_str(dict, "loclist",
5282 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5283#endif
5284
Bram Moolenaar30567352016-08-27 21:25:44 +02005285 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005286 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005287
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005288 return dict;
5289}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005290
5291/*
5292 * "getwininfo()" function
5293 */
5294 static void
5295f_getwininfo(typval_T *argvars, typval_T *rettv)
5296{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005297 tabpage_T *tp;
5298 win_T *wp = NULL, *wparg = NULL;
5299 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005300 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005301
5302 if (rettv_list_alloc(rettv) != OK)
5303 return;
5304
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005305 if (argvars[0].v_type != VAR_UNKNOWN)
5306 {
5307 wparg = win_id2wp(argvars);
5308 if (wparg == NULL)
5309 return;
5310 }
5311
5312 /* Collect information about either all the windows across all the tab
5313 * pages or one particular window.
5314 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005315 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005316 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005317 tabnr++;
5318 winnr = 0;
5319 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005320 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005321 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005322 if (wparg != NULL && wp != wparg)
5323 continue;
5324 d = get_win_info(wp, tabnr, winnr);
5325 if (d != NULL)
5326 list_append_dict(rettv->vval.v_list, d);
5327 if (wparg != NULL)
5328 /* found information about a specific window */
5329 return;
5330 }
5331 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005332}
5333
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005334/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005335 * "win_findbuf()" function
5336 */
5337 static void
5338f_win_findbuf(typval_T *argvars, typval_T *rettv)
5339{
5340 if (rettv_list_alloc(rettv) != FAIL)
5341 win_findbuf(argvars, rettv->vval.v_list);
5342}
5343
5344/*
5345 * "win_getid()" function
5346 */
5347 static void
5348f_win_getid(typval_T *argvars, typval_T *rettv)
5349{
5350 rettv->vval.v_number = win_getid(argvars);
5351}
5352
5353/*
5354 * "win_gotoid()" function
5355 */
5356 static void
5357f_win_gotoid(typval_T *argvars, typval_T *rettv)
5358{
5359 rettv->vval.v_number = win_gotoid(argvars);
5360}
5361
5362/*
5363 * "win_id2tabwin()" function
5364 */
5365 static void
5366f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5367{
5368 if (rettv_list_alloc(rettv) != FAIL)
5369 win_id2tabwin(argvars, rettv->vval.v_list);
5370}
5371
5372/*
5373 * "win_id2win()" function
5374 */
5375 static void
5376f_win_id2win(typval_T *argvars, typval_T *rettv)
5377{
5378 rettv->vval.v_number = win_id2win(argvars);
5379}
5380
5381/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005382 * "getwinposx()" function
5383 */
5384 static void
5385f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5386{
5387 rettv->vval.v_number = -1;
5388#ifdef FEAT_GUI
5389 if (gui.in_use)
5390 {
5391 int x, y;
5392
5393 if (gui_mch_get_winpos(&x, &y) == OK)
5394 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005395 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005396 }
5397#endif
5398#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5399 {
5400 int x, y;
5401
5402 if (term_get_winpos(&x, &y) == OK)
5403 rettv->vval.v_number = x;
5404 }
5405#endif
5406}
5407
5408/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005409 * "getwinposy()" function
5410 */
5411 static void
5412f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5413{
5414 rettv->vval.v_number = -1;
5415#ifdef FEAT_GUI
5416 if (gui.in_use)
5417 {
5418 int x, y;
5419
5420 if (gui_mch_get_winpos(&x, &y) == OK)
5421 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005422 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005423 }
5424#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005425#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5426 {
5427 int x, y;
5428
5429 if (term_get_winpos(&x, &y) == OK)
5430 rettv->vval.v_number = y;
5431 }
5432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005433}
5434
5435/*
5436 * "getwinvar()" function
5437 */
5438 static void
5439f_getwinvar(typval_T *argvars, typval_T *rettv)
5440{
5441 getwinvar(argvars, rettv, 0);
5442}
5443
5444/*
5445 * "glob()" function
5446 */
5447 static void
5448f_glob(typval_T *argvars, typval_T *rettv)
5449{
5450 int options = WILD_SILENT|WILD_USE_NL;
5451 expand_T xpc;
5452 int error = FALSE;
5453
5454 /* When the optional second argument is non-zero, don't remove matches
5455 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5456 rettv->v_type = VAR_STRING;
5457 if (argvars[1].v_type != VAR_UNKNOWN)
5458 {
5459 if (get_tv_number_chk(&argvars[1], &error))
5460 options |= WILD_KEEP_ALL;
5461 if (argvars[2].v_type != VAR_UNKNOWN)
5462 {
5463 if (get_tv_number_chk(&argvars[2], &error))
5464 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005465 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005466 }
5467 if (argvars[3].v_type != VAR_UNKNOWN
5468 && get_tv_number_chk(&argvars[3], &error))
5469 options |= WILD_ALLLINKS;
5470 }
5471 }
5472 if (!error)
5473 {
5474 ExpandInit(&xpc);
5475 xpc.xp_context = EXPAND_FILES;
5476 if (p_wic)
5477 options += WILD_ICASE;
5478 if (rettv->v_type == VAR_STRING)
5479 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5480 NULL, options, WILD_ALL);
5481 else if (rettv_list_alloc(rettv) != FAIL)
5482 {
5483 int i;
5484
5485 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5486 NULL, options, WILD_ALL_KEEP);
5487 for (i = 0; i < xpc.xp_numfiles; i++)
5488 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5489
5490 ExpandCleanup(&xpc);
5491 }
5492 }
5493 else
5494 rettv->vval.v_string = NULL;
5495}
5496
5497/*
5498 * "globpath()" function
5499 */
5500 static void
5501f_globpath(typval_T *argvars, typval_T *rettv)
5502{
5503 int flags = 0;
5504 char_u buf1[NUMBUFLEN];
5505 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5506 int error = FALSE;
5507 garray_T ga;
5508 int i;
5509
5510 /* When the optional second argument is non-zero, don't remove matches
5511 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5512 rettv->v_type = VAR_STRING;
5513 if (argvars[2].v_type != VAR_UNKNOWN)
5514 {
5515 if (get_tv_number_chk(&argvars[2], &error))
5516 flags |= WILD_KEEP_ALL;
5517 if (argvars[3].v_type != VAR_UNKNOWN)
5518 {
5519 if (get_tv_number_chk(&argvars[3], &error))
5520 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005521 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005522 }
5523 if (argvars[4].v_type != VAR_UNKNOWN
5524 && get_tv_number_chk(&argvars[4], &error))
5525 flags |= WILD_ALLLINKS;
5526 }
5527 }
5528 if (file != NULL && !error)
5529 {
5530 ga_init2(&ga, (int)sizeof(char_u *), 10);
5531 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5532 if (rettv->v_type == VAR_STRING)
5533 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5534 else if (rettv_list_alloc(rettv) != FAIL)
5535 for (i = 0; i < ga.ga_len; ++i)
5536 list_append_string(rettv->vval.v_list,
5537 ((char_u **)(ga.ga_data))[i], -1);
5538 ga_clear_strings(&ga);
5539 }
5540 else
5541 rettv->vval.v_string = NULL;
5542}
5543
5544/*
5545 * "glob2regpat()" function
5546 */
5547 static void
5548f_glob2regpat(typval_T *argvars, typval_T *rettv)
5549{
5550 char_u *pat = get_tv_string_chk(&argvars[0]);
5551
5552 rettv->v_type = VAR_STRING;
5553 rettv->vval.v_string = (pat == NULL)
5554 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5555}
5556
5557/* for VIM_VERSION_ defines */
5558#include "version.h"
5559
5560/*
5561 * "has()" function
5562 */
5563 static void
5564f_has(typval_T *argvars, typval_T *rettv)
5565{
5566 int i;
5567 char_u *name;
5568 int n = FALSE;
5569 static char *(has_list[]) =
5570 {
5571#ifdef AMIGA
5572 "amiga",
5573# ifdef FEAT_ARP
5574 "arp",
5575# endif
5576#endif
5577#ifdef __BEOS__
5578 "beos",
5579#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005580#ifdef MACOS_X
5581 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5582 "osx", /* Mac OS X */
5583# ifdef MACOS_X_DARWIN
5584 "macunix", /* Mac OS X, with the darwin feature */
5585 "osxdarwin", /* synonym for macunix */
5586# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005587#endif
5588#ifdef __QNX__
5589 "qnx",
5590#endif
5591#ifdef UNIX
5592 "unix",
5593#endif
5594#ifdef VMS
5595 "vms",
5596#endif
5597#ifdef WIN32
5598 "win32",
5599#endif
5600#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5601 "win32unix",
5602#endif
5603#if defined(WIN64) || defined(_WIN64)
5604 "win64",
5605#endif
5606#ifdef EBCDIC
5607 "ebcdic",
5608#endif
5609#ifndef CASE_INSENSITIVE_FILENAME
5610 "fname_case",
5611#endif
5612#ifdef HAVE_ACL
5613 "acl",
5614#endif
5615#ifdef FEAT_ARABIC
5616 "arabic",
5617#endif
5618#ifdef FEAT_AUTOCMD
5619 "autocmd",
5620#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005621#ifdef FEAT_AUTOSERVERNAME
5622 "autoservername",
5623#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005624#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625 "balloon_eval",
5626# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5627 "balloon_multiline",
5628# endif
5629#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005630#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005631 "balloon_eval_term",
5632#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005633#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5634 "builtin_terms",
5635# ifdef ALL_BUILTIN_TCAPS
5636 "all_builtin_terms",
5637# endif
5638#endif
5639#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5640 || defined(FEAT_GUI_W32) \
5641 || defined(FEAT_GUI_MOTIF))
5642 "browsefilter",
5643#endif
5644#ifdef FEAT_BYTEOFF
5645 "byte_offset",
5646#endif
5647#ifdef FEAT_JOB_CHANNEL
5648 "channel",
5649#endif
5650#ifdef FEAT_CINDENT
5651 "cindent",
5652#endif
5653#ifdef FEAT_CLIENTSERVER
5654 "clientserver",
5655#endif
5656#ifdef FEAT_CLIPBOARD
5657 "clipboard",
5658#endif
5659#ifdef FEAT_CMDL_COMPL
5660 "cmdline_compl",
5661#endif
5662#ifdef FEAT_CMDHIST
5663 "cmdline_hist",
5664#endif
5665#ifdef FEAT_COMMENTS
5666 "comments",
5667#endif
5668#ifdef FEAT_CONCEAL
5669 "conceal",
5670#endif
5671#ifdef FEAT_CRYPT
5672 "cryptv",
5673 "crypt-blowfish",
5674 "crypt-blowfish2",
5675#endif
5676#ifdef FEAT_CSCOPE
5677 "cscope",
5678#endif
5679#ifdef FEAT_CURSORBIND
5680 "cursorbind",
5681#endif
5682#ifdef CURSOR_SHAPE
5683 "cursorshape",
5684#endif
5685#ifdef DEBUG
5686 "debug",
5687#endif
5688#ifdef FEAT_CON_DIALOG
5689 "dialog_con",
5690#endif
5691#ifdef FEAT_GUI_DIALOG
5692 "dialog_gui",
5693#endif
5694#ifdef FEAT_DIFF
5695 "diff",
5696#endif
5697#ifdef FEAT_DIGRAPHS
5698 "digraphs",
5699#endif
5700#ifdef FEAT_DIRECTX
5701 "directx",
5702#endif
5703#ifdef FEAT_DND
5704 "dnd",
5705#endif
5706#ifdef FEAT_EMACS_TAGS
5707 "emacs_tags",
5708#endif
5709 "eval", /* always present, of course! */
5710 "ex_extra", /* graduated feature */
5711#ifdef FEAT_SEARCH_EXTRA
5712 "extra_search",
5713#endif
5714#ifdef FEAT_FKMAP
5715 "farsi",
5716#endif
5717#ifdef FEAT_SEARCHPATH
5718 "file_in_path",
5719#endif
5720#ifdef FEAT_FILTERPIPE
5721 "filterpipe",
5722#endif
5723#ifdef FEAT_FIND_ID
5724 "find_in_path",
5725#endif
5726#ifdef FEAT_FLOAT
5727 "float",
5728#endif
5729#ifdef FEAT_FOLDING
5730 "folding",
5731#endif
5732#ifdef FEAT_FOOTER
5733 "footer",
5734#endif
5735#if !defined(USE_SYSTEM) && defined(UNIX)
5736 "fork",
5737#endif
5738#ifdef FEAT_GETTEXT
5739 "gettext",
5740#endif
5741#ifdef FEAT_GUI
5742 "gui",
5743#endif
5744#ifdef FEAT_GUI_ATHENA
5745# ifdef FEAT_GUI_NEXTAW
5746 "gui_neXtaw",
5747# else
5748 "gui_athena",
5749# endif
5750#endif
5751#ifdef FEAT_GUI_GTK
5752 "gui_gtk",
5753# ifdef USE_GTK3
5754 "gui_gtk3",
5755# else
5756 "gui_gtk2",
5757# endif
5758#endif
5759#ifdef FEAT_GUI_GNOME
5760 "gui_gnome",
5761#endif
5762#ifdef FEAT_GUI_MAC
5763 "gui_mac",
5764#endif
5765#ifdef FEAT_GUI_MOTIF
5766 "gui_motif",
5767#endif
5768#ifdef FEAT_GUI_PHOTON
5769 "gui_photon",
5770#endif
5771#ifdef FEAT_GUI_W32
5772 "gui_win32",
5773#endif
5774#ifdef FEAT_HANGULIN
5775 "hangul_input",
5776#endif
5777#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5778 "iconv",
5779#endif
5780#ifdef FEAT_INS_EXPAND
5781 "insert_expand",
5782#endif
5783#ifdef FEAT_JOB_CHANNEL
5784 "job",
5785#endif
5786#ifdef FEAT_JUMPLIST
5787 "jumplist",
5788#endif
5789#ifdef FEAT_KEYMAP
5790 "keymap",
5791#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005792 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005793#ifdef FEAT_LANGMAP
5794 "langmap",
5795#endif
5796#ifdef FEAT_LIBCALL
5797 "libcall",
5798#endif
5799#ifdef FEAT_LINEBREAK
5800 "linebreak",
5801#endif
5802#ifdef FEAT_LISP
5803 "lispindent",
5804#endif
5805#ifdef FEAT_LISTCMDS
5806 "listcmds",
5807#endif
5808#ifdef FEAT_LOCALMAP
5809 "localmap",
5810#endif
5811#ifdef FEAT_LUA
5812# ifndef DYNAMIC_LUA
5813 "lua",
5814# endif
5815#endif
5816#ifdef FEAT_MENU
5817 "menu",
5818#endif
5819#ifdef FEAT_SESSION
5820 "mksession",
5821#endif
5822#ifdef FEAT_MODIFY_FNAME
5823 "modify_fname",
5824#endif
5825#ifdef FEAT_MOUSE
5826 "mouse",
5827#endif
5828#ifdef FEAT_MOUSESHAPE
5829 "mouseshape",
5830#endif
5831#if defined(UNIX) || defined(VMS)
5832# ifdef FEAT_MOUSE_DEC
5833 "mouse_dec",
5834# endif
5835# ifdef FEAT_MOUSE_GPM
5836 "mouse_gpm",
5837# endif
5838# ifdef FEAT_MOUSE_JSB
5839 "mouse_jsbterm",
5840# endif
5841# ifdef FEAT_MOUSE_NET
5842 "mouse_netterm",
5843# endif
5844# ifdef FEAT_MOUSE_PTERM
5845 "mouse_pterm",
5846# endif
5847# ifdef FEAT_MOUSE_SGR
5848 "mouse_sgr",
5849# endif
5850# ifdef FEAT_SYSMOUSE
5851 "mouse_sysmouse",
5852# endif
5853# ifdef FEAT_MOUSE_URXVT
5854 "mouse_urxvt",
5855# endif
5856# ifdef FEAT_MOUSE_XTERM
5857 "mouse_xterm",
5858# endif
5859#endif
5860#ifdef FEAT_MBYTE
5861 "multi_byte",
5862#endif
5863#ifdef FEAT_MBYTE_IME
5864 "multi_byte_ime",
5865#endif
5866#ifdef FEAT_MULTI_LANG
5867 "multi_lang",
5868#endif
5869#ifdef FEAT_MZSCHEME
5870#ifndef DYNAMIC_MZSCHEME
5871 "mzscheme",
5872#endif
5873#endif
5874#ifdef FEAT_NUM64
5875 "num64",
5876#endif
5877#ifdef FEAT_OLE
5878 "ole",
5879#endif
5880 "packages",
5881#ifdef FEAT_PATH_EXTRA
5882 "path_extra",
5883#endif
5884#ifdef FEAT_PERL
5885#ifndef DYNAMIC_PERL
5886 "perl",
5887#endif
5888#endif
5889#ifdef FEAT_PERSISTENT_UNDO
5890 "persistent_undo",
5891#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005892#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005893 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005894 "pythonx",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005895#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005896#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005897 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005898 "pythonx",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005899#endif
5900#ifdef FEAT_POSTSCRIPT
5901 "postscript",
5902#endif
5903#ifdef FEAT_PRINTER
5904 "printer",
5905#endif
5906#ifdef FEAT_PROFILE
5907 "profile",
5908#endif
5909#ifdef FEAT_RELTIME
5910 "reltime",
5911#endif
5912#ifdef FEAT_QUICKFIX
5913 "quickfix",
5914#endif
5915#ifdef FEAT_RIGHTLEFT
5916 "rightleft",
5917#endif
5918#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5919 "ruby",
5920#endif
5921#ifdef FEAT_SCROLLBIND
5922 "scrollbind",
5923#endif
5924#ifdef FEAT_CMDL_INFO
5925 "showcmd",
5926 "cmdline_info",
5927#endif
5928#ifdef FEAT_SIGNS
5929 "signs",
5930#endif
5931#ifdef FEAT_SMARTINDENT
5932 "smartindent",
5933#endif
5934#ifdef STARTUPTIME
5935 "startuptime",
5936#endif
5937#ifdef FEAT_STL_OPT
5938 "statusline",
5939#endif
5940#ifdef FEAT_SUN_WORKSHOP
5941 "sun_workshop",
5942#endif
5943#ifdef FEAT_NETBEANS_INTG
5944 "netbeans_intg",
5945#endif
5946#ifdef FEAT_SPELL
5947 "spell",
5948#endif
5949#ifdef FEAT_SYN_HL
5950 "syntax",
5951#endif
5952#if defined(USE_SYSTEM) || !defined(UNIX)
5953 "system",
5954#endif
5955#ifdef FEAT_TAG_BINS
5956 "tag_binary",
5957#endif
5958#ifdef FEAT_TAG_OLDSTATIC
5959 "tag_old_static",
5960#endif
5961#ifdef FEAT_TAG_ANYWHITE
5962 "tag_any_white",
5963#endif
5964#ifdef FEAT_TCL
5965# ifndef DYNAMIC_TCL
5966 "tcl",
5967# endif
5968#endif
5969#ifdef FEAT_TERMGUICOLORS
5970 "termguicolors",
5971#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02005972#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02005973 "terminal",
5974#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975#ifdef TERMINFO
5976 "terminfo",
5977#endif
5978#ifdef FEAT_TERMRESPONSE
5979 "termresponse",
5980#endif
5981#ifdef FEAT_TEXTOBJ
5982 "textobjects",
5983#endif
5984#ifdef HAVE_TGETENT
5985 "tgetent",
5986#endif
5987#ifdef FEAT_TIMERS
5988 "timers",
5989#endif
5990#ifdef FEAT_TITLE
5991 "title",
5992#endif
5993#ifdef FEAT_TOOLBAR
5994 "toolbar",
5995#endif
5996#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5997 "unnamedplus",
5998#endif
5999#ifdef FEAT_USR_CMDS
6000 "user-commands", /* was accidentally included in 5.4 */
6001 "user_commands",
6002#endif
6003#ifdef FEAT_VIMINFO
6004 "viminfo",
6005#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006007#ifdef FEAT_VIRTUALEDIT
6008 "virtualedit",
6009#endif
6010 "visual",
6011#ifdef FEAT_VISUALEXTRA
6012 "visualextra",
6013#endif
6014#ifdef FEAT_VREPLACE
6015 "vreplace",
6016#endif
6017#ifdef FEAT_WILDIGN
6018 "wildignore",
6019#endif
6020#ifdef FEAT_WILDMENU
6021 "wildmenu",
6022#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024#ifdef FEAT_WAK
6025 "winaltkeys",
6026#endif
6027#ifdef FEAT_WRITEBACKUP
6028 "writebackup",
6029#endif
6030#ifdef FEAT_XIM
6031 "xim",
6032#endif
6033#ifdef FEAT_XFONTSET
6034 "xfontset",
6035#endif
6036#ifdef FEAT_XPM_W32
6037 "xpm",
6038 "xpm_w32", /* for backward compatibility */
6039#else
6040# if defined(HAVE_XPM)
6041 "xpm",
6042# endif
6043#endif
6044#ifdef USE_XSMP
6045 "xsmp",
6046#endif
6047#ifdef USE_XSMP_INTERACT
6048 "xsmp_interact",
6049#endif
6050#ifdef FEAT_XCLIPBOARD
6051 "xterm_clipboard",
6052#endif
6053#ifdef FEAT_XTERM_SAVE
6054 "xterm_save",
6055#endif
6056#if defined(UNIX) && defined(FEAT_X11)
6057 "X11",
6058#endif
6059 NULL
6060 };
6061
6062 name = get_tv_string(&argvars[0]);
6063 for (i = 0; has_list[i] != NULL; ++i)
6064 if (STRICMP(name, has_list[i]) == 0)
6065 {
6066 n = TRUE;
6067 break;
6068 }
6069
6070 if (n == FALSE)
6071 {
6072 if (STRNICMP(name, "patch", 5) == 0)
6073 {
6074 if (name[5] == '-'
6075 && STRLEN(name) >= 11
6076 && vim_isdigit(name[6])
6077 && vim_isdigit(name[8])
6078 && vim_isdigit(name[10]))
6079 {
6080 int major = atoi((char *)name + 6);
6081 int minor = atoi((char *)name + 8);
6082
6083 /* Expect "patch-9.9.01234". */
6084 n = (major < VIM_VERSION_MAJOR
6085 || (major == VIM_VERSION_MAJOR
6086 && (minor < VIM_VERSION_MINOR
6087 || (minor == VIM_VERSION_MINOR
6088 && has_patch(atoi((char *)name + 10))))));
6089 }
6090 else
6091 n = has_patch(atoi((char *)name + 5));
6092 }
6093 else if (STRICMP(name, "vim_starting") == 0)
6094 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006095 else if (STRICMP(name, "ttyin") == 0)
6096 n = mch_input_isatty();
6097 else if (STRICMP(name, "ttyout") == 0)
6098 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006099#ifdef FEAT_MBYTE
6100 else if (STRICMP(name, "multi_byte_encoding") == 0)
6101 n = has_mbyte;
6102#endif
6103#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6104 else if (STRICMP(name, "balloon_multiline") == 0)
6105 n = multiline_balloon_available();
6106#endif
6107#ifdef DYNAMIC_TCL
6108 else if (STRICMP(name, "tcl") == 0)
6109 n = tcl_enabled(FALSE);
6110#endif
6111#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6112 else if (STRICMP(name, "iconv") == 0)
6113 n = iconv_enabled(FALSE);
6114#endif
6115#ifdef DYNAMIC_LUA
6116 else if (STRICMP(name, "lua") == 0)
6117 n = lua_enabled(FALSE);
6118#endif
6119#ifdef DYNAMIC_MZSCHEME
6120 else if (STRICMP(name, "mzscheme") == 0)
6121 n = mzscheme_enabled(FALSE);
6122#endif
6123#ifdef DYNAMIC_RUBY
6124 else if (STRICMP(name, "ruby") == 0)
6125 n = ruby_enabled(FALSE);
6126#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006127#ifdef DYNAMIC_PYTHON
6128 else if (STRICMP(name, "python") == 0)
6129 n = python_enabled(FALSE);
6130#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006131#ifdef DYNAMIC_PYTHON3
6132 else if (STRICMP(name, "python3") == 0)
6133 n = python3_enabled(FALSE);
6134#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006135#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6136 else if (STRICMP(name, "pythonx") == 0)
6137 {
6138# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6139 if (p_pyx == 0)
6140 n = python3_enabled(FALSE) || python_enabled(FALSE);
6141 else if (p_pyx == 3)
6142 n = python3_enabled(FALSE);
6143 else if (p_pyx == 2)
6144 n = python_enabled(FALSE);
6145# elif defined(DYNAMIC_PYTHON)
6146 n = python_enabled(FALSE);
6147# elif defined(DYNAMIC_PYTHON3)
6148 n = python3_enabled(FALSE);
6149# endif
6150 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006151#endif
6152#ifdef DYNAMIC_PERL
6153 else if (STRICMP(name, "perl") == 0)
6154 n = perl_enabled(FALSE);
6155#endif
6156#ifdef FEAT_GUI
6157 else if (STRICMP(name, "gui_running") == 0)
6158 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006159# ifdef FEAT_BROWSE
6160 else if (STRICMP(name, "browse") == 0)
6161 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6162# endif
6163#endif
6164#ifdef FEAT_SYN_HL
6165 else if (STRICMP(name, "syntax_items") == 0)
6166 n = syntax_present(curwin);
6167#endif
6168#if defined(WIN3264)
6169 else if (STRICMP(name, "win95") == 0)
Bram Moolenaarcea912a2016-10-12 14:20:24 +02006170 n = FALSE; /* Win9x is no more supported. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006171#endif
6172#ifdef FEAT_NETBEANS_INTG
6173 else if (STRICMP(name, "netbeans_enabled") == 0)
6174 n = netbeans_active();
6175#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006176#if defined(FEAT_TERMINAL) && defined(WIN3264)
6177 else if (STRICMP(name, "terminal") == 0)
6178 n = terminal_enabled();
6179#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006180 }
6181
6182 rettv->vval.v_number = n;
6183}
6184
6185/*
6186 * "has_key()" function
6187 */
6188 static void
6189f_has_key(typval_T *argvars, typval_T *rettv)
6190{
6191 if (argvars[0].v_type != VAR_DICT)
6192 {
6193 EMSG(_(e_dictreq));
6194 return;
6195 }
6196 if (argvars[0].vval.v_dict == NULL)
6197 return;
6198
6199 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6200 get_tv_string(&argvars[1]), -1) != NULL;
6201}
6202
6203/*
6204 * "haslocaldir()" function
6205 */
6206 static void
6207f_haslocaldir(typval_T *argvars, typval_T *rettv)
6208{
6209 win_T *wp = NULL;
6210
6211 wp = find_tabwin(&argvars[0], &argvars[1]);
6212 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6213}
6214
6215/*
6216 * "hasmapto()" function
6217 */
6218 static void
6219f_hasmapto(typval_T *argvars, typval_T *rettv)
6220{
6221 char_u *name;
6222 char_u *mode;
6223 char_u buf[NUMBUFLEN];
6224 int abbr = FALSE;
6225
6226 name = get_tv_string(&argvars[0]);
6227 if (argvars[1].v_type == VAR_UNKNOWN)
6228 mode = (char_u *)"nvo";
6229 else
6230 {
6231 mode = get_tv_string_buf(&argvars[1], buf);
6232 if (argvars[2].v_type != VAR_UNKNOWN)
6233 abbr = (int)get_tv_number(&argvars[2]);
6234 }
6235
6236 if (map_to_exists(name, mode, abbr))
6237 rettv->vval.v_number = TRUE;
6238 else
6239 rettv->vval.v_number = FALSE;
6240}
6241
6242/*
6243 * "histadd()" function
6244 */
6245 static void
6246f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6247{
6248#ifdef FEAT_CMDHIST
6249 int histype;
6250 char_u *str;
6251 char_u buf[NUMBUFLEN];
6252#endif
6253
6254 rettv->vval.v_number = FALSE;
6255 if (check_restricted() || check_secure())
6256 return;
6257#ifdef FEAT_CMDHIST
6258 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6259 histype = str != NULL ? get_histtype(str) : -1;
6260 if (histype >= 0)
6261 {
6262 str = get_tv_string_buf(&argvars[1], buf);
6263 if (*str != NUL)
6264 {
6265 init_history();
6266 add_to_history(histype, str, FALSE, NUL);
6267 rettv->vval.v_number = TRUE;
6268 return;
6269 }
6270 }
6271#endif
6272}
6273
6274/*
6275 * "histdel()" function
6276 */
6277 static void
6278f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6279{
6280#ifdef FEAT_CMDHIST
6281 int n;
6282 char_u buf[NUMBUFLEN];
6283 char_u *str;
6284
6285 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6286 if (str == NULL)
6287 n = 0;
6288 else if (argvars[1].v_type == VAR_UNKNOWN)
6289 /* only one argument: clear entire history */
6290 n = clr_history(get_histtype(str));
6291 else if (argvars[1].v_type == VAR_NUMBER)
6292 /* index given: remove that entry */
6293 n = del_history_idx(get_histtype(str),
6294 (int)get_tv_number(&argvars[1]));
6295 else
6296 /* string given: remove all matching entries */
6297 n = del_history_entry(get_histtype(str),
6298 get_tv_string_buf(&argvars[1], buf));
6299 rettv->vval.v_number = n;
6300#endif
6301}
6302
6303/*
6304 * "histget()" function
6305 */
6306 static void
6307f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6308{
6309#ifdef FEAT_CMDHIST
6310 int type;
6311 int idx;
6312 char_u *str;
6313
6314 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6315 if (str == NULL)
6316 rettv->vval.v_string = NULL;
6317 else
6318 {
6319 type = get_histtype(str);
6320 if (argvars[1].v_type == VAR_UNKNOWN)
6321 idx = get_history_idx(type);
6322 else
6323 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6324 /* -1 on type error */
6325 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6326 }
6327#else
6328 rettv->vval.v_string = NULL;
6329#endif
6330 rettv->v_type = VAR_STRING;
6331}
6332
6333/*
6334 * "histnr()" function
6335 */
6336 static void
6337f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6338{
6339 int i;
6340
6341#ifdef FEAT_CMDHIST
6342 char_u *history = get_tv_string_chk(&argvars[0]);
6343
6344 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6345 if (i >= HIST_CMD && i < HIST_COUNT)
6346 i = get_history_idx(i);
6347 else
6348#endif
6349 i = -1;
6350 rettv->vval.v_number = i;
6351}
6352
6353/*
6354 * "highlightID(name)" function
6355 */
6356 static void
6357f_hlID(typval_T *argvars, typval_T *rettv)
6358{
6359 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6360}
6361
6362/*
6363 * "highlight_exists()" function
6364 */
6365 static void
6366f_hlexists(typval_T *argvars, typval_T *rettv)
6367{
6368 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6369}
6370
6371/*
6372 * "hostname()" function
6373 */
6374 static void
6375f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6376{
6377 char_u hostname[256];
6378
6379 mch_get_host_name(hostname, 256);
6380 rettv->v_type = VAR_STRING;
6381 rettv->vval.v_string = vim_strsave(hostname);
6382}
6383
6384/*
6385 * iconv() function
6386 */
6387 static void
6388f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6389{
6390#ifdef FEAT_MBYTE
6391 char_u buf1[NUMBUFLEN];
6392 char_u buf2[NUMBUFLEN];
6393 char_u *from, *to, *str;
6394 vimconv_T vimconv;
6395#endif
6396
6397 rettv->v_type = VAR_STRING;
6398 rettv->vval.v_string = NULL;
6399
6400#ifdef FEAT_MBYTE
6401 str = get_tv_string(&argvars[0]);
6402 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6403 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6404 vimconv.vc_type = CONV_NONE;
6405 convert_setup(&vimconv, from, to);
6406
6407 /* If the encodings are equal, no conversion needed. */
6408 if (vimconv.vc_type == CONV_NONE)
6409 rettv->vval.v_string = vim_strsave(str);
6410 else
6411 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6412
6413 convert_setup(&vimconv, NULL, NULL);
6414 vim_free(from);
6415 vim_free(to);
6416#endif
6417}
6418
6419/*
6420 * "indent()" function
6421 */
6422 static void
6423f_indent(typval_T *argvars, typval_T *rettv)
6424{
6425 linenr_T lnum;
6426
6427 lnum = get_tv_lnum(argvars);
6428 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6429 rettv->vval.v_number = get_indent_lnum(lnum);
6430 else
6431 rettv->vval.v_number = -1;
6432}
6433
6434/*
6435 * "index()" function
6436 */
6437 static void
6438f_index(typval_T *argvars, typval_T *rettv)
6439{
6440 list_T *l;
6441 listitem_T *item;
6442 long idx = 0;
6443 int ic = FALSE;
6444
6445 rettv->vval.v_number = -1;
6446 if (argvars[0].v_type != VAR_LIST)
6447 {
6448 EMSG(_(e_listreq));
6449 return;
6450 }
6451 l = argvars[0].vval.v_list;
6452 if (l != NULL)
6453 {
6454 item = l->lv_first;
6455 if (argvars[2].v_type != VAR_UNKNOWN)
6456 {
6457 int error = FALSE;
6458
6459 /* Start at specified item. Use the cached index that list_find()
6460 * sets, so that a negative number also works. */
6461 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6462 idx = l->lv_idx;
6463 if (argvars[3].v_type != VAR_UNKNOWN)
6464 ic = (int)get_tv_number_chk(&argvars[3], &error);
6465 if (error)
6466 item = NULL;
6467 }
6468
6469 for ( ; item != NULL; item = item->li_next, ++idx)
6470 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6471 {
6472 rettv->vval.v_number = idx;
6473 break;
6474 }
6475 }
6476}
6477
6478static int inputsecret_flag = 0;
6479
6480/*
6481 * "input()" function
6482 * Also handles inputsecret() when inputsecret is set.
6483 */
6484 static void
6485f_input(typval_T *argvars, typval_T *rettv)
6486{
6487 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6488}
6489
6490/*
6491 * "inputdialog()" function
6492 */
6493 static void
6494f_inputdialog(typval_T *argvars, typval_T *rettv)
6495{
6496#if defined(FEAT_GUI_TEXTDIALOG)
6497 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6498 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6499 {
6500 char_u *message;
6501 char_u buf[NUMBUFLEN];
6502 char_u *defstr = (char_u *)"";
6503
6504 message = get_tv_string_chk(&argvars[0]);
6505 if (argvars[1].v_type != VAR_UNKNOWN
6506 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6507 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6508 else
6509 IObuff[0] = NUL;
6510 if (message != NULL && defstr != NULL
6511 && do_dialog(VIM_QUESTION, NULL, message,
6512 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6513 rettv->vval.v_string = vim_strsave(IObuff);
6514 else
6515 {
6516 if (message != NULL && defstr != NULL
6517 && argvars[1].v_type != VAR_UNKNOWN
6518 && argvars[2].v_type != VAR_UNKNOWN)
6519 rettv->vval.v_string = vim_strsave(
6520 get_tv_string_buf(&argvars[2], buf));
6521 else
6522 rettv->vval.v_string = NULL;
6523 }
6524 rettv->v_type = VAR_STRING;
6525 }
6526 else
6527#endif
6528 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6529}
6530
6531/*
6532 * "inputlist()" function
6533 */
6534 static void
6535f_inputlist(typval_T *argvars, typval_T *rettv)
6536{
6537 listitem_T *li;
6538 int selected;
6539 int mouse_used;
6540
6541#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006542 /* While starting up, there is no place to enter text. When running tests
6543 * with --not-a-term we assume feedkeys() will be used. */
6544 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006545 return;
6546#endif
6547 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6548 {
6549 EMSG2(_(e_listarg), "inputlist()");
6550 return;
6551 }
6552
6553 msg_start();
6554 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6555 lines_left = Rows; /* avoid more prompt */
6556 msg_scroll = TRUE;
6557 msg_clr_eos();
6558
6559 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6560 {
6561 msg_puts(get_tv_string(&li->li_tv));
6562 msg_putchar('\n');
6563 }
6564
6565 /* Ask for choice. */
6566 selected = prompt_for_number(&mouse_used);
6567 if (mouse_used)
6568 selected -= lines_left;
6569
6570 rettv->vval.v_number = selected;
6571}
6572
6573
6574static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6575
6576/*
6577 * "inputrestore()" function
6578 */
6579 static void
6580f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6581{
6582 if (ga_userinput.ga_len > 0)
6583 {
6584 --ga_userinput.ga_len;
6585 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6586 + ga_userinput.ga_len);
6587 /* default return is zero == OK */
6588 }
6589 else if (p_verbose > 1)
6590 {
6591 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6592 rettv->vval.v_number = 1; /* Failed */
6593 }
6594}
6595
6596/*
6597 * "inputsave()" function
6598 */
6599 static void
6600f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6601{
6602 /* Add an entry to the stack of typeahead storage. */
6603 if (ga_grow(&ga_userinput, 1) == OK)
6604 {
6605 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6606 + ga_userinput.ga_len);
6607 ++ga_userinput.ga_len;
6608 /* default return is zero == OK */
6609 }
6610 else
6611 rettv->vval.v_number = 1; /* Failed */
6612}
6613
6614/*
6615 * "inputsecret()" function
6616 */
6617 static void
6618f_inputsecret(typval_T *argvars, typval_T *rettv)
6619{
6620 ++cmdline_star;
6621 ++inputsecret_flag;
6622 f_input(argvars, rettv);
6623 --cmdline_star;
6624 --inputsecret_flag;
6625}
6626
6627/*
6628 * "insert()" function
6629 */
6630 static void
6631f_insert(typval_T *argvars, typval_T *rettv)
6632{
6633 long before = 0;
6634 listitem_T *item;
6635 list_T *l;
6636 int error = FALSE;
6637
6638 if (argvars[0].v_type != VAR_LIST)
6639 EMSG2(_(e_listarg), "insert()");
6640 else if ((l = argvars[0].vval.v_list) != NULL
6641 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6642 {
6643 if (argvars[2].v_type != VAR_UNKNOWN)
6644 before = (long)get_tv_number_chk(&argvars[2], &error);
6645 if (error)
6646 return; /* type error; errmsg already given */
6647
6648 if (before == l->lv_len)
6649 item = NULL;
6650 else
6651 {
6652 item = list_find(l, before);
6653 if (item == NULL)
6654 {
6655 EMSGN(_(e_listidx), before);
6656 l = NULL;
6657 }
6658 }
6659 if (l != NULL)
6660 {
6661 list_insert_tv(l, &argvars[1], item);
6662 copy_tv(&argvars[0], rettv);
6663 }
6664 }
6665}
6666
6667/*
6668 * "invert(expr)" function
6669 */
6670 static void
6671f_invert(typval_T *argvars, typval_T *rettv)
6672{
6673 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6674}
6675
6676/*
6677 * "isdirectory()" function
6678 */
6679 static void
6680f_isdirectory(typval_T *argvars, typval_T *rettv)
6681{
6682 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6683}
6684
6685/*
6686 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6687 * or it refers to a List or Dictionary that is locked.
6688 */
6689 static int
6690tv_islocked(typval_T *tv)
6691{
6692 return (tv->v_lock & VAR_LOCKED)
6693 || (tv->v_type == VAR_LIST
6694 && tv->vval.v_list != NULL
6695 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6696 || (tv->v_type == VAR_DICT
6697 && tv->vval.v_dict != NULL
6698 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6699}
6700
6701/*
6702 * "islocked()" function
6703 */
6704 static void
6705f_islocked(typval_T *argvars, typval_T *rettv)
6706{
6707 lval_T lv;
6708 char_u *end;
6709 dictitem_T *di;
6710
6711 rettv->vval.v_number = -1;
6712 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006713 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006714 if (end != NULL && lv.ll_name != NULL)
6715 {
6716 if (*end != NUL)
6717 EMSG(_(e_trailing));
6718 else
6719 {
6720 if (lv.ll_tv == NULL)
6721 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006722 di = find_var(lv.ll_name, NULL, TRUE);
6723 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006724 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006725 /* Consider a variable locked when:
6726 * 1. the variable itself is locked
6727 * 2. the value of the variable is locked.
6728 * 3. the List or Dict value is locked.
6729 */
6730 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6731 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006732 }
6733 }
6734 else if (lv.ll_range)
6735 EMSG(_("E786: Range not allowed"));
6736 else if (lv.ll_newkey != NULL)
6737 EMSG2(_(e_dictkey), lv.ll_newkey);
6738 else if (lv.ll_list != NULL)
6739 /* List item. */
6740 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6741 else
6742 /* Dictionary item. */
6743 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6744 }
6745 }
6746
6747 clear_lval(&lv);
6748}
6749
6750#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6751/*
6752 * "isnan()" function
6753 */
6754 static void
6755f_isnan(typval_T *argvars, typval_T *rettv)
6756{
6757 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6758 && isnan(argvars[0].vval.v_float);
6759}
6760#endif
6761
6762/*
6763 * "items(dict)" function
6764 */
6765 static void
6766f_items(typval_T *argvars, typval_T *rettv)
6767{
6768 dict_list(argvars, rettv, 2);
6769}
6770
6771#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6772/*
6773 * Get the job from the argument.
6774 * Returns NULL if the job is invalid.
6775 */
6776 static job_T *
6777get_job_arg(typval_T *tv)
6778{
6779 job_T *job;
6780
6781 if (tv->v_type != VAR_JOB)
6782 {
6783 EMSG2(_(e_invarg2), get_tv_string(tv));
6784 return NULL;
6785 }
6786 job = tv->vval.v_job;
6787
6788 if (job == NULL)
6789 EMSG(_("E916: not a valid job"));
6790 return job;
6791}
6792
6793/*
6794 * "job_getchannel()" function
6795 */
6796 static void
6797f_job_getchannel(typval_T *argvars, typval_T *rettv)
6798{
6799 job_T *job = get_job_arg(&argvars[0]);
6800
6801 if (job != NULL)
6802 {
6803 rettv->v_type = VAR_CHANNEL;
6804 rettv->vval.v_channel = job->jv_channel;
6805 if (job->jv_channel != NULL)
6806 ++job->jv_channel->ch_refcount;
6807 }
6808}
6809
6810/*
6811 * "job_info()" function
6812 */
6813 static void
6814f_job_info(typval_T *argvars, typval_T *rettv)
6815{
6816 job_T *job = get_job_arg(&argvars[0]);
6817
6818 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6819 job_info(job, rettv->vval.v_dict);
6820}
6821
6822/*
6823 * "job_setoptions()" function
6824 */
6825 static void
6826f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6827{
6828 job_T *job = get_job_arg(&argvars[0]);
6829 jobopt_T opt;
6830
6831 if (job == NULL)
6832 return;
6833 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02006834 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006835 job_set_options(job, &opt);
6836 free_job_options(&opt);
6837}
6838
6839/*
6840 * "job_start()" function
6841 */
6842 static void
6843f_job_start(typval_T *argvars, typval_T *rettv)
6844{
6845 rettv->v_type = VAR_JOB;
6846 if (check_restricted() || check_secure())
6847 return;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006848 rettv->vval.v_job = job_start(argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006849}
6850
6851/*
6852 * "job_status()" function
6853 */
6854 static void
6855f_job_status(typval_T *argvars, typval_T *rettv)
6856{
6857 job_T *job = get_job_arg(&argvars[0]);
6858
6859 if (job != NULL)
6860 {
6861 rettv->v_type = VAR_STRING;
6862 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6863 }
6864}
6865
6866/*
6867 * "job_stop()" function
6868 */
6869 static void
6870f_job_stop(typval_T *argvars, typval_T *rettv)
6871{
6872 job_T *job = get_job_arg(&argvars[0]);
6873
6874 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006875 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006876}
6877#endif
6878
6879/*
6880 * "join()" function
6881 */
6882 static void
6883f_join(typval_T *argvars, typval_T *rettv)
6884{
6885 garray_T ga;
6886 char_u *sep;
6887
6888 if (argvars[0].v_type != VAR_LIST)
6889 {
6890 EMSG(_(e_listreq));
6891 return;
6892 }
6893 if (argvars[0].vval.v_list == NULL)
6894 return;
6895 if (argvars[1].v_type == VAR_UNKNOWN)
6896 sep = (char_u *)" ";
6897 else
6898 sep = get_tv_string_chk(&argvars[1]);
6899
6900 rettv->v_type = VAR_STRING;
6901
6902 if (sep != NULL)
6903 {
6904 ga_init2(&ga, (int)sizeof(char), 80);
6905 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6906 ga_append(&ga, NUL);
6907 rettv->vval.v_string = (char_u *)ga.ga_data;
6908 }
6909 else
6910 rettv->vval.v_string = NULL;
6911}
6912
6913/*
6914 * "js_decode()" function
6915 */
6916 static void
6917f_js_decode(typval_T *argvars, typval_T *rettv)
6918{
6919 js_read_T reader;
6920
6921 reader.js_buf = get_tv_string(&argvars[0]);
6922 reader.js_fill = NULL;
6923 reader.js_used = 0;
6924 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6925 EMSG(_(e_invarg));
6926}
6927
6928/*
6929 * "js_encode()" function
6930 */
6931 static void
6932f_js_encode(typval_T *argvars, typval_T *rettv)
6933{
6934 rettv->v_type = VAR_STRING;
6935 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6936}
6937
6938/*
6939 * "json_decode()" function
6940 */
6941 static void
6942f_json_decode(typval_T *argvars, typval_T *rettv)
6943{
6944 js_read_T reader;
6945
6946 reader.js_buf = get_tv_string(&argvars[0]);
6947 reader.js_fill = NULL;
6948 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01006949 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950}
6951
6952/*
6953 * "json_encode()" function
6954 */
6955 static void
6956f_json_encode(typval_T *argvars, typval_T *rettv)
6957{
6958 rettv->v_type = VAR_STRING;
6959 rettv->vval.v_string = json_encode(&argvars[0], 0);
6960}
6961
6962/*
6963 * "keys()" function
6964 */
6965 static void
6966f_keys(typval_T *argvars, typval_T *rettv)
6967{
6968 dict_list(argvars, rettv, 0);
6969}
6970
6971/*
6972 * "last_buffer_nr()" function.
6973 */
6974 static void
6975f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6976{
6977 int n = 0;
6978 buf_T *buf;
6979
Bram Moolenaar29323592016-07-24 22:04:11 +02006980 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981 if (n < buf->b_fnum)
6982 n = buf->b_fnum;
6983
6984 rettv->vval.v_number = n;
6985}
6986
6987/*
6988 * "len()" function
6989 */
6990 static void
6991f_len(typval_T *argvars, typval_T *rettv)
6992{
6993 switch (argvars[0].v_type)
6994 {
6995 case VAR_STRING:
6996 case VAR_NUMBER:
6997 rettv->vval.v_number = (varnumber_T)STRLEN(
6998 get_tv_string(&argvars[0]));
6999 break;
7000 case VAR_LIST:
7001 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7002 break;
7003 case VAR_DICT:
7004 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7005 break;
7006 case VAR_UNKNOWN:
7007 case VAR_SPECIAL:
7008 case VAR_FLOAT:
7009 case VAR_FUNC:
7010 case VAR_PARTIAL:
7011 case VAR_JOB:
7012 case VAR_CHANNEL:
7013 EMSG(_("E701: Invalid type for len()"));
7014 break;
7015 }
7016}
7017
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007018 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007019libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007020{
7021#ifdef FEAT_LIBCALL
7022 char_u *string_in;
7023 char_u **string_result;
7024 int nr_result;
7025#endif
7026
7027 rettv->v_type = type;
7028 if (type != VAR_NUMBER)
7029 rettv->vval.v_string = NULL;
7030
7031 if (check_restricted() || check_secure())
7032 return;
7033
7034#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007035 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7037 {
7038 string_in = NULL;
7039 if (argvars[2].v_type == VAR_STRING)
7040 string_in = argvars[2].vval.v_string;
7041 if (type == VAR_NUMBER)
7042 string_result = NULL;
7043 else
7044 string_result = &rettv->vval.v_string;
7045 if (mch_libcall(argvars[0].vval.v_string,
7046 argvars[1].vval.v_string,
7047 string_in,
7048 argvars[2].vval.v_number,
7049 string_result,
7050 &nr_result) == OK
7051 && type == VAR_NUMBER)
7052 rettv->vval.v_number = nr_result;
7053 }
7054#endif
7055}
7056
7057/*
7058 * "libcall()" function
7059 */
7060 static void
7061f_libcall(typval_T *argvars, typval_T *rettv)
7062{
7063 libcall_common(argvars, rettv, VAR_STRING);
7064}
7065
7066/*
7067 * "libcallnr()" function
7068 */
7069 static void
7070f_libcallnr(typval_T *argvars, typval_T *rettv)
7071{
7072 libcall_common(argvars, rettv, VAR_NUMBER);
7073}
7074
7075/*
7076 * "line(string)" function
7077 */
7078 static void
7079f_line(typval_T *argvars, typval_T *rettv)
7080{
7081 linenr_T lnum = 0;
7082 pos_T *fp;
7083 int fnum;
7084
7085 fp = var2fpos(&argvars[0], TRUE, &fnum);
7086 if (fp != NULL)
7087 lnum = fp->lnum;
7088 rettv->vval.v_number = lnum;
7089}
7090
7091/*
7092 * "line2byte(lnum)" function
7093 */
7094 static void
7095f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7096{
7097#ifndef FEAT_BYTEOFF
7098 rettv->vval.v_number = -1;
7099#else
7100 linenr_T lnum;
7101
7102 lnum = get_tv_lnum(argvars);
7103 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7104 rettv->vval.v_number = -1;
7105 else
7106 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7107 if (rettv->vval.v_number >= 0)
7108 ++rettv->vval.v_number;
7109#endif
7110}
7111
7112/*
7113 * "lispindent(lnum)" function
7114 */
7115 static void
7116f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7117{
7118#ifdef FEAT_LISP
7119 pos_T pos;
7120 linenr_T lnum;
7121
7122 pos = curwin->w_cursor;
7123 lnum = get_tv_lnum(argvars);
7124 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7125 {
7126 curwin->w_cursor.lnum = lnum;
7127 rettv->vval.v_number = get_lisp_indent();
7128 curwin->w_cursor = pos;
7129 }
7130 else
7131#endif
7132 rettv->vval.v_number = -1;
7133}
7134
7135/*
7136 * "localtime()" function
7137 */
7138 static void
7139f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7140{
7141 rettv->vval.v_number = (varnumber_T)time(NULL);
7142}
7143
7144static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7145
7146 static void
7147get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7148{
7149 char_u *keys;
7150 char_u *which;
7151 char_u buf[NUMBUFLEN];
7152 char_u *keys_buf = NULL;
7153 char_u *rhs;
7154 int mode;
7155 int abbr = FALSE;
7156 int get_dict = FALSE;
7157 mapblock_T *mp;
7158 int buffer_local;
7159
7160 /* return empty string for failure */
7161 rettv->v_type = VAR_STRING;
7162 rettv->vval.v_string = NULL;
7163
7164 keys = get_tv_string(&argvars[0]);
7165 if (*keys == NUL)
7166 return;
7167
7168 if (argvars[1].v_type != VAR_UNKNOWN)
7169 {
7170 which = get_tv_string_buf_chk(&argvars[1], buf);
7171 if (argvars[2].v_type != VAR_UNKNOWN)
7172 {
7173 abbr = (int)get_tv_number(&argvars[2]);
7174 if (argvars[3].v_type != VAR_UNKNOWN)
7175 get_dict = (int)get_tv_number(&argvars[3]);
7176 }
7177 }
7178 else
7179 which = (char_u *)"";
7180 if (which == NULL)
7181 return;
7182
7183 mode = get_map_mode(&which, 0);
7184
7185 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7186 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7187 vim_free(keys_buf);
7188
7189 if (!get_dict)
7190 {
7191 /* Return a string. */
7192 if (rhs != NULL)
7193 rettv->vval.v_string = str2special_save(rhs, FALSE);
7194
7195 }
7196 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7197 {
7198 /* Return a dictionary. */
7199 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7200 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7201 dict_T *dict = rettv->vval.v_dict;
7202
7203 dict_add_nr_str(dict, "lhs", 0L, lhs);
7204 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7205 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7206 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7207 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7208 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7209 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7210 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7211 dict_add_nr_str(dict, "mode", 0L, mapmode);
7212
7213 vim_free(lhs);
7214 vim_free(mapmode);
7215 }
7216}
7217
7218#ifdef FEAT_FLOAT
7219/*
7220 * "log()" function
7221 */
7222 static void
7223f_log(typval_T *argvars, typval_T *rettv)
7224{
7225 float_T f = 0.0;
7226
7227 rettv->v_type = VAR_FLOAT;
7228 if (get_float_arg(argvars, &f) == OK)
7229 rettv->vval.v_float = log(f);
7230 else
7231 rettv->vval.v_float = 0.0;
7232}
7233
7234/*
7235 * "log10()" function
7236 */
7237 static void
7238f_log10(typval_T *argvars, typval_T *rettv)
7239{
7240 float_T f = 0.0;
7241
7242 rettv->v_type = VAR_FLOAT;
7243 if (get_float_arg(argvars, &f) == OK)
7244 rettv->vval.v_float = log10(f);
7245 else
7246 rettv->vval.v_float = 0.0;
7247}
7248#endif
7249
7250#ifdef FEAT_LUA
7251/*
7252 * "luaeval()" function
7253 */
7254 static void
7255f_luaeval(typval_T *argvars, typval_T *rettv)
7256{
7257 char_u *str;
7258 char_u buf[NUMBUFLEN];
7259
7260 str = get_tv_string_buf(&argvars[0], buf);
7261 do_luaeval(str, argvars + 1, rettv);
7262}
7263#endif
7264
7265/*
7266 * "map()" function
7267 */
7268 static void
7269f_map(typval_T *argvars, typval_T *rettv)
7270{
7271 filter_map(argvars, rettv, TRUE);
7272}
7273
7274/*
7275 * "maparg()" function
7276 */
7277 static void
7278f_maparg(typval_T *argvars, typval_T *rettv)
7279{
7280 get_maparg(argvars, rettv, TRUE);
7281}
7282
7283/*
7284 * "mapcheck()" function
7285 */
7286 static void
7287f_mapcheck(typval_T *argvars, typval_T *rettv)
7288{
7289 get_maparg(argvars, rettv, FALSE);
7290}
7291
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007292typedef enum
7293{
7294 MATCH_END, /* matchend() */
7295 MATCH_MATCH, /* match() */
7296 MATCH_STR, /* matchstr() */
7297 MATCH_LIST, /* matchlist() */
7298 MATCH_POS /* matchstrpos() */
7299} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007300
7301 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007302find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007303{
7304 char_u *str = NULL;
7305 long len = 0;
7306 char_u *expr = NULL;
7307 char_u *pat;
7308 regmatch_T regmatch;
7309 char_u patbuf[NUMBUFLEN];
7310 char_u strbuf[NUMBUFLEN];
7311 char_u *save_cpo;
7312 long start = 0;
7313 long nth = 1;
7314 colnr_T startcol = 0;
7315 int match = 0;
7316 list_T *l = NULL;
7317 listitem_T *li = NULL;
7318 long idx = 0;
7319 char_u *tofree = NULL;
7320
7321 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7322 save_cpo = p_cpo;
7323 p_cpo = (char_u *)"";
7324
7325 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007326 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007327 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007328 /* type MATCH_LIST: return empty list when there are no matches.
7329 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007330 if (rettv_list_alloc(rettv) == FAIL)
7331 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007332 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007333 && (list_append_string(rettv->vval.v_list,
7334 (char_u *)"", 0) == FAIL
7335 || list_append_number(rettv->vval.v_list,
7336 (varnumber_T)-1) == FAIL
7337 || list_append_number(rettv->vval.v_list,
7338 (varnumber_T)-1) == FAIL
7339 || list_append_number(rettv->vval.v_list,
7340 (varnumber_T)-1) == FAIL))
7341 {
7342 list_free(rettv->vval.v_list);
7343 rettv->vval.v_list = NULL;
7344 goto theend;
7345 }
7346 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007347 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007348 {
7349 rettv->v_type = VAR_STRING;
7350 rettv->vval.v_string = NULL;
7351 }
7352
7353 if (argvars[0].v_type == VAR_LIST)
7354 {
7355 if ((l = argvars[0].vval.v_list) == NULL)
7356 goto theend;
7357 li = l->lv_first;
7358 }
7359 else
7360 {
7361 expr = str = get_tv_string(&argvars[0]);
7362 len = (long)STRLEN(str);
7363 }
7364
7365 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7366 if (pat == NULL)
7367 goto theend;
7368
7369 if (argvars[2].v_type != VAR_UNKNOWN)
7370 {
7371 int error = FALSE;
7372
7373 start = (long)get_tv_number_chk(&argvars[2], &error);
7374 if (error)
7375 goto theend;
7376 if (l != NULL)
7377 {
7378 li = list_find(l, start);
7379 if (li == NULL)
7380 goto theend;
7381 idx = l->lv_idx; /* use the cached index */
7382 }
7383 else
7384 {
7385 if (start < 0)
7386 start = 0;
7387 if (start > len)
7388 goto theend;
7389 /* When "count" argument is there ignore matches before "start",
7390 * otherwise skip part of the string. Differs when pattern is "^"
7391 * or "\<". */
7392 if (argvars[3].v_type != VAR_UNKNOWN)
7393 startcol = start;
7394 else
7395 {
7396 str += start;
7397 len -= start;
7398 }
7399 }
7400
7401 if (argvars[3].v_type != VAR_UNKNOWN)
7402 nth = (long)get_tv_number_chk(&argvars[3], &error);
7403 if (error)
7404 goto theend;
7405 }
7406
7407 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7408 if (regmatch.regprog != NULL)
7409 {
7410 regmatch.rm_ic = p_ic;
7411
7412 for (;;)
7413 {
7414 if (l != NULL)
7415 {
7416 if (li == NULL)
7417 {
7418 match = FALSE;
7419 break;
7420 }
7421 vim_free(tofree);
7422 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7423 if (str == NULL)
7424 break;
7425 }
7426
7427 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7428
7429 if (match && --nth <= 0)
7430 break;
7431 if (l == NULL && !match)
7432 break;
7433
7434 /* Advance to just after the match. */
7435 if (l != NULL)
7436 {
7437 li = li->li_next;
7438 ++idx;
7439 }
7440 else
7441 {
7442#ifdef FEAT_MBYTE
7443 startcol = (colnr_T)(regmatch.startp[0]
7444 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7445#else
7446 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7447#endif
7448 if (startcol > (colnr_T)len
7449 || str + startcol <= regmatch.startp[0])
7450 {
7451 match = FALSE;
7452 break;
7453 }
7454 }
7455 }
7456
7457 if (match)
7458 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007459 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007460 {
7461 listitem_T *li1 = rettv->vval.v_list->lv_first;
7462 listitem_T *li2 = li1->li_next;
7463 listitem_T *li3 = li2->li_next;
7464 listitem_T *li4 = li3->li_next;
7465
7466 vim_free(li1->li_tv.vval.v_string);
7467 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7468 (int)(regmatch.endp[0] - regmatch.startp[0]));
7469 li3->li_tv.vval.v_number =
7470 (varnumber_T)(regmatch.startp[0] - expr);
7471 li4->li_tv.vval.v_number =
7472 (varnumber_T)(regmatch.endp[0] - expr);
7473 if (l != NULL)
7474 li2->li_tv.vval.v_number = (varnumber_T)idx;
7475 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007476 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007477 {
7478 int i;
7479
7480 /* return list with matched string and submatches */
7481 for (i = 0; i < NSUBEXP; ++i)
7482 {
7483 if (regmatch.endp[i] == NULL)
7484 {
7485 if (list_append_string(rettv->vval.v_list,
7486 (char_u *)"", 0) == FAIL)
7487 break;
7488 }
7489 else if (list_append_string(rettv->vval.v_list,
7490 regmatch.startp[i],
7491 (int)(regmatch.endp[i] - regmatch.startp[i]))
7492 == FAIL)
7493 break;
7494 }
7495 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007496 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007497 {
7498 /* return matched string */
7499 if (l != NULL)
7500 copy_tv(&li->li_tv, rettv);
7501 else
7502 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7503 (int)(regmatch.endp[0] - regmatch.startp[0]));
7504 }
7505 else if (l != NULL)
7506 rettv->vval.v_number = idx;
7507 else
7508 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007509 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007510 rettv->vval.v_number =
7511 (varnumber_T)(regmatch.startp[0] - str);
7512 else
7513 rettv->vval.v_number =
7514 (varnumber_T)(regmatch.endp[0] - str);
7515 rettv->vval.v_number += (varnumber_T)(str - expr);
7516 }
7517 }
7518 vim_regfree(regmatch.regprog);
7519 }
7520
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007521theend:
7522 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007523 /* matchstrpos() without a list: drop the second item. */
7524 listitem_remove(rettv->vval.v_list,
7525 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 vim_free(tofree);
7527 p_cpo = save_cpo;
7528}
7529
7530/*
7531 * "match()" function
7532 */
7533 static void
7534f_match(typval_T *argvars, typval_T *rettv)
7535{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007536 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537}
7538
7539/*
7540 * "matchadd()" function
7541 */
7542 static void
7543f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7544{
7545#ifdef FEAT_SEARCH_EXTRA
7546 char_u buf[NUMBUFLEN];
7547 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7548 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7549 int prio = 10; /* default priority */
7550 int id = -1;
7551 int error = FALSE;
7552 char_u *conceal_char = NULL;
7553
7554 rettv->vval.v_number = -1;
7555
7556 if (grp == NULL || pat == NULL)
7557 return;
7558 if (argvars[2].v_type != VAR_UNKNOWN)
7559 {
7560 prio = (int)get_tv_number_chk(&argvars[2], &error);
7561 if (argvars[3].v_type != VAR_UNKNOWN)
7562 {
7563 id = (int)get_tv_number_chk(&argvars[3], &error);
7564 if (argvars[4].v_type != VAR_UNKNOWN)
7565 {
7566 if (argvars[4].v_type != VAR_DICT)
7567 {
7568 EMSG(_(e_dictreq));
7569 return;
7570 }
7571 if (dict_find(argvars[4].vval.v_dict,
7572 (char_u *)"conceal", -1) != NULL)
7573 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7574 (char_u *)"conceal", FALSE);
7575 }
7576 }
7577 }
7578 if (error == TRUE)
7579 return;
7580 if (id >= 1 && id <= 3)
7581 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007582 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007583 return;
7584 }
7585
7586 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7587 conceal_char);
7588#endif
7589}
7590
7591/*
7592 * "matchaddpos()" function
7593 */
7594 static void
7595f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7596{
7597#ifdef FEAT_SEARCH_EXTRA
7598 char_u buf[NUMBUFLEN];
7599 char_u *group;
7600 int prio = 10;
7601 int id = -1;
7602 int error = FALSE;
7603 list_T *l;
7604 char_u *conceal_char = NULL;
7605
7606 rettv->vval.v_number = -1;
7607
7608 group = get_tv_string_buf_chk(&argvars[0], buf);
7609 if (group == NULL)
7610 return;
7611
7612 if (argvars[1].v_type != VAR_LIST)
7613 {
7614 EMSG2(_(e_listarg), "matchaddpos()");
7615 return;
7616 }
7617 l = argvars[1].vval.v_list;
7618 if (l == NULL)
7619 return;
7620
7621 if (argvars[2].v_type != VAR_UNKNOWN)
7622 {
7623 prio = (int)get_tv_number_chk(&argvars[2], &error);
7624 if (argvars[3].v_type != VAR_UNKNOWN)
7625 {
7626 id = (int)get_tv_number_chk(&argvars[3], &error);
7627 if (argvars[4].v_type != VAR_UNKNOWN)
7628 {
7629 if (argvars[4].v_type != VAR_DICT)
7630 {
7631 EMSG(_(e_dictreq));
7632 return;
7633 }
7634 if (dict_find(argvars[4].vval.v_dict,
7635 (char_u *)"conceal", -1) != NULL)
7636 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7637 (char_u *)"conceal", FALSE);
7638 }
7639 }
7640 }
7641 if (error == TRUE)
7642 return;
7643
7644 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7645 if (id == 1 || id == 2)
7646 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007647 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 return;
7649 }
7650
7651 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7652 conceal_char);
7653#endif
7654}
7655
7656/*
7657 * "matcharg()" function
7658 */
7659 static void
7660f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7661{
7662 if (rettv_list_alloc(rettv) == OK)
7663 {
7664#ifdef FEAT_SEARCH_EXTRA
7665 int id = (int)get_tv_number(&argvars[0]);
7666 matchitem_T *m;
7667
7668 if (id >= 1 && id <= 3)
7669 {
7670 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7671 {
7672 list_append_string(rettv->vval.v_list,
7673 syn_id2name(m->hlg_id), -1);
7674 list_append_string(rettv->vval.v_list, m->pattern, -1);
7675 }
7676 else
7677 {
7678 list_append_string(rettv->vval.v_list, NULL, -1);
7679 list_append_string(rettv->vval.v_list, NULL, -1);
7680 }
7681 }
7682#endif
7683 }
7684}
7685
7686/*
7687 * "matchdelete()" function
7688 */
7689 static void
7690f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7691{
7692#ifdef FEAT_SEARCH_EXTRA
7693 rettv->vval.v_number = match_delete(curwin,
7694 (int)get_tv_number(&argvars[0]), TRUE);
7695#endif
7696}
7697
7698/*
7699 * "matchend()" function
7700 */
7701 static void
7702f_matchend(typval_T *argvars, typval_T *rettv)
7703{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007704 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007705}
7706
7707/*
7708 * "matchlist()" function
7709 */
7710 static void
7711f_matchlist(typval_T *argvars, typval_T *rettv)
7712{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007713 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714}
7715
7716/*
7717 * "matchstr()" function
7718 */
7719 static void
7720f_matchstr(typval_T *argvars, typval_T *rettv)
7721{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007722 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007723}
7724
7725/*
7726 * "matchstrpos()" function
7727 */
7728 static void
7729f_matchstrpos(typval_T *argvars, typval_T *rettv)
7730{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007731 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007732}
7733
7734static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7735
7736 static void
7737max_min(typval_T *argvars, typval_T *rettv, int domax)
7738{
7739 varnumber_T n = 0;
7740 varnumber_T i;
7741 int error = FALSE;
7742
7743 if (argvars[0].v_type == VAR_LIST)
7744 {
7745 list_T *l;
7746 listitem_T *li;
7747
7748 l = argvars[0].vval.v_list;
7749 if (l != NULL)
7750 {
7751 li = l->lv_first;
7752 if (li != NULL)
7753 {
7754 n = get_tv_number_chk(&li->li_tv, &error);
7755 for (;;)
7756 {
7757 li = li->li_next;
7758 if (li == NULL)
7759 break;
7760 i = get_tv_number_chk(&li->li_tv, &error);
7761 if (domax ? i > n : i < n)
7762 n = i;
7763 }
7764 }
7765 }
7766 }
7767 else if (argvars[0].v_type == VAR_DICT)
7768 {
7769 dict_T *d;
7770 int first = TRUE;
7771 hashitem_T *hi;
7772 int todo;
7773
7774 d = argvars[0].vval.v_dict;
7775 if (d != NULL)
7776 {
7777 todo = (int)d->dv_hashtab.ht_used;
7778 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7779 {
7780 if (!HASHITEM_EMPTY(hi))
7781 {
7782 --todo;
7783 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7784 if (first)
7785 {
7786 n = i;
7787 first = FALSE;
7788 }
7789 else if (domax ? i > n : i < n)
7790 n = i;
7791 }
7792 }
7793 }
7794 }
7795 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007796 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007797 rettv->vval.v_number = error ? 0 : n;
7798}
7799
7800/*
7801 * "max()" function
7802 */
7803 static void
7804f_max(typval_T *argvars, typval_T *rettv)
7805{
7806 max_min(argvars, rettv, TRUE);
7807}
7808
7809/*
7810 * "min()" function
7811 */
7812 static void
7813f_min(typval_T *argvars, typval_T *rettv)
7814{
7815 max_min(argvars, rettv, FALSE);
7816}
7817
7818static int mkdir_recurse(char_u *dir, int prot);
7819
7820/*
7821 * Create the directory in which "dir" is located, and higher levels when
7822 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007823 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007824 */
7825 static int
7826mkdir_recurse(char_u *dir, int prot)
7827{
7828 char_u *p;
7829 char_u *updir;
7830 int r = FAIL;
7831
7832 /* Get end of directory name in "dir".
7833 * We're done when it's "/" or "c:/". */
7834 p = gettail_sep(dir);
7835 if (p <= get_past_head(dir))
7836 return OK;
7837
7838 /* If the directory exists we're done. Otherwise: create it.*/
7839 updir = vim_strnsave(dir, (int)(p - dir));
7840 if (updir == NULL)
7841 return FAIL;
7842 if (mch_isdir(updir))
7843 r = OK;
7844 else if (mkdir_recurse(updir, prot) == OK)
7845 r = vim_mkdir_emsg(updir, prot);
7846 vim_free(updir);
7847 return r;
7848}
7849
7850#ifdef vim_mkdir
7851/*
7852 * "mkdir()" function
7853 */
7854 static void
7855f_mkdir(typval_T *argvars, typval_T *rettv)
7856{
7857 char_u *dir;
7858 char_u buf[NUMBUFLEN];
7859 int prot = 0755;
7860
7861 rettv->vval.v_number = FAIL;
7862 if (check_restricted() || check_secure())
7863 return;
7864
7865 dir = get_tv_string_buf(&argvars[0], buf);
7866 if (*dir == NUL)
7867 rettv->vval.v_number = FAIL;
7868 else
7869 {
7870 if (*gettail(dir) == NUL)
7871 /* remove trailing slashes */
7872 *gettail_sep(dir) = NUL;
7873
7874 if (argvars[1].v_type != VAR_UNKNOWN)
7875 {
7876 if (argvars[2].v_type != VAR_UNKNOWN)
7877 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7878 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7879 mkdir_recurse(dir, prot);
7880 }
7881 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7882 }
7883}
7884#endif
7885
7886/*
7887 * "mode()" function
7888 */
7889 static void
7890f_mode(typval_T *argvars, typval_T *rettv)
7891{
7892 char_u buf[3];
7893
7894 buf[1] = NUL;
7895 buf[2] = NUL;
7896
7897 if (time_for_testing == 93784)
7898 {
7899 /* Testing the two-character code. */
7900 buf[0] = 'x';
7901 buf[1] = '!';
7902 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007903#ifdef FEAT_TERMINAL
7904 else if (term_use_loop())
7905 buf[0] = 't';
7906#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007907 else if (VIsual_active)
7908 {
7909 if (VIsual_select)
7910 buf[0] = VIsual_mode + 's' - 'v';
7911 else
7912 buf[0] = VIsual_mode;
7913 }
7914 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7915 || State == CONFIRM)
7916 {
7917 buf[0] = 'r';
7918 if (State == ASKMORE)
7919 buf[1] = 'm';
7920 else if (State == CONFIRM)
7921 buf[1] = '?';
7922 }
7923 else if (State == EXTERNCMD)
7924 buf[0] = '!';
7925 else if (State & INSERT)
7926 {
7927#ifdef FEAT_VREPLACE
7928 if (State & VREPLACE_FLAG)
7929 {
7930 buf[0] = 'R';
7931 buf[1] = 'v';
7932 }
7933 else
7934#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01007935 {
7936 if (State & REPLACE_FLAG)
7937 buf[0] = 'R';
7938 else
7939 buf[0] = 'i';
7940#ifdef FEAT_INS_EXPAND
7941 if (ins_compl_active())
7942 buf[1] = 'c';
7943 else if (ctrl_x_mode == 1)
7944 buf[1] = 'x';
7945#endif
7946 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007947 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007948 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007949 {
7950 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007951 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007952 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007953 else if (exmode_active == EXMODE_NORMAL)
7954 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007955 }
7956 else
7957 {
7958 buf[0] = 'n';
7959 if (finish_op)
7960 buf[1] = 'o';
7961 }
7962
7963 /* Clear out the minor mode when the argument is not a non-zero number or
7964 * non-empty string. */
7965 if (!non_zero_arg(&argvars[0]))
7966 buf[1] = NUL;
7967
7968 rettv->vval.v_string = vim_strsave(buf);
7969 rettv->v_type = VAR_STRING;
7970}
7971
7972#if defined(FEAT_MZSCHEME) || defined(PROTO)
7973/*
7974 * "mzeval()" function
7975 */
7976 static void
7977f_mzeval(typval_T *argvars, typval_T *rettv)
7978{
7979 char_u *str;
7980 char_u buf[NUMBUFLEN];
7981
7982 str = get_tv_string_buf(&argvars[0], buf);
7983 do_mzeval(str, rettv);
7984}
7985
7986 void
7987mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7988{
7989 typval_T argvars[3];
7990
7991 argvars[0].v_type = VAR_STRING;
7992 argvars[0].vval.v_string = name;
7993 copy_tv(args, &argvars[1]);
7994 argvars[2].v_type = VAR_UNKNOWN;
7995 f_call(argvars, rettv);
7996 clear_tv(&argvars[1]);
7997}
7998#endif
7999
8000/*
8001 * "nextnonblank()" function
8002 */
8003 static void
8004f_nextnonblank(typval_T *argvars, typval_T *rettv)
8005{
8006 linenr_T lnum;
8007
8008 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8009 {
8010 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8011 {
8012 lnum = 0;
8013 break;
8014 }
8015 if (*skipwhite(ml_get(lnum)) != NUL)
8016 break;
8017 }
8018 rettv->vval.v_number = lnum;
8019}
8020
8021/*
8022 * "nr2char()" function
8023 */
8024 static void
8025f_nr2char(typval_T *argvars, typval_T *rettv)
8026{
8027 char_u buf[NUMBUFLEN];
8028
8029#ifdef FEAT_MBYTE
8030 if (has_mbyte)
8031 {
8032 int utf8 = 0;
8033
8034 if (argvars[1].v_type != VAR_UNKNOWN)
8035 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8036 if (utf8)
8037 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8038 else
8039 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8040 }
8041 else
8042#endif
8043 {
8044 buf[0] = (char_u)get_tv_number(&argvars[0]);
8045 buf[1] = NUL;
8046 }
8047 rettv->v_type = VAR_STRING;
8048 rettv->vval.v_string = vim_strsave(buf);
8049}
8050
8051/*
8052 * "or(expr, expr)" function
8053 */
8054 static void
8055f_or(typval_T *argvars, typval_T *rettv)
8056{
8057 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8058 | get_tv_number_chk(&argvars[1], NULL);
8059}
8060
8061/*
8062 * "pathshorten()" function
8063 */
8064 static void
8065f_pathshorten(typval_T *argvars, typval_T *rettv)
8066{
8067 char_u *p;
8068
8069 rettv->v_type = VAR_STRING;
8070 p = get_tv_string_chk(&argvars[0]);
8071 if (p == NULL)
8072 rettv->vval.v_string = NULL;
8073 else
8074 {
8075 p = vim_strsave(p);
8076 rettv->vval.v_string = p;
8077 if (p != NULL)
8078 shorten_dir(p);
8079 }
8080}
8081
8082#ifdef FEAT_PERL
8083/*
8084 * "perleval()" function
8085 */
8086 static void
8087f_perleval(typval_T *argvars, typval_T *rettv)
8088{
8089 char_u *str;
8090 char_u buf[NUMBUFLEN];
8091
8092 str = get_tv_string_buf(&argvars[0], buf);
8093 do_perleval(str, rettv);
8094}
8095#endif
8096
8097#ifdef FEAT_FLOAT
8098/*
8099 * "pow()" function
8100 */
8101 static void
8102f_pow(typval_T *argvars, typval_T *rettv)
8103{
8104 float_T fx = 0.0, fy = 0.0;
8105
8106 rettv->v_type = VAR_FLOAT;
8107 if (get_float_arg(argvars, &fx) == OK
8108 && get_float_arg(&argvars[1], &fy) == OK)
8109 rettv->vval.v_float = pow(fx, fy);
8110 else
8111 rettv->vval.v_float = 0.0;
8112}
8113#endif
8114
8115/*
8116 * "prevnonblank()" function
8117 */
8118 static void
8119f_prevnonblank(typval_T *argvars, typval_T *rettv)
8120{
8121 linenr_T lnum;
8122
8123 lnum = get_tv_lnum(argvars);
8124 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8125 lnum = 0;
8126 else
8127 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8128 --lnum;
8129 rettv->vval.v_number = lnum;
8130}
8131
8132/* This dummy va_list is here because:
8133 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8134 * - locally in the function results in a "used before set" warning
8135 * - using va_start() to initialize it gives "function with fixed args" error */
8136static va_list ap;
8137
8138/*
8139 * "printf()" function
8140 */
8141 static void
8142f_printf(typval_T *argvars, typval_T *rettv)
8143{
8144 char_u buf[NUMBUFLEN];
8145 int len;
8146 char_u *s;
8147 int saved_did_emsg = did_emsg;
8148 char *fmt;
8149
8150 rettv->v_type = VAR_STRING;
8151 rettv->vval.v_string = NULL;
8152
8153 /* Get the required length, allocate the buffer and do it for real. */
8154 did_emsg = FALSE;
8155 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008156 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008157 if (!did_emsg)
8158 {
8159 s = alloc(len + 1);
8160 if (s != NULL)
8161 {
8162 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008163 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8164 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165 }
8166 }
8167 did_emsg |= saved_did_emsg;
8168}
8169
8170/*
8171 * "pumvisible()" function
8172 */
8173 static void
8174f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8175{
8176#ifdef FEAT_INS_EXPAND
8177 if (pum_visible())
8178 rettv->vval.v_number = 1;
8179#endif
8180}
8181
8182#ifdef FEAT_PYTHON3
8183/*
8184 * "py3eval()" function
8185 */
8186 static void
8187f_py3eval(typval_T *argvars, typval_T *rettv)
8188{
8189 char_u *str;
8190 char_u buf[NUMBUFLEN];
8191
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008192 if (p_pyx == 0)
8193 p_pyx = 3;
8194
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 str = get_tv_string_buf(&argvars[0], buf);
8196 do_py3eval(str, rettv);
8197}
8198#endif
8199
8200#ifdef FEAT_PYTHON
8201/*
8202 * "pyeval()" function
8203 */
8204 static void
8205f_pyeval(typval_T *argvars, typval_T *rettv)
8206{
8207 char_u *str;
8208 char_u buf[NUMBUFLEN];
8209
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008210 if (p_pyx == 0)
8211 p_pyx = 2;
8212
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 str = get_tv_string_buf(&argvars[0], buf);
8214 do_pyeval(str, rettv);
8215}
8216#endif
8217
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008218#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8219/*
8220 * "pyxeval()" function
8221 */
8222 static void
8223f_pyxeval(typval_T *argvars, typval_T *rettv)
8224{
8225# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8226 init_pyxversion();
8227 if (p_pyx == 2)
8228 f_pyeval(argvars, rettv);
8229 else
8230 f_py3eval(argvars, rettv);
8231# elif defined(FEAT_PYTHON)
8232 f_pyeval(argvars, rettv);
8233# elif defined(FEAT_PYTHON3)
8234 f_py3eval(argvars, rettv);
8235# endif
8236}
8237#endif
8238
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239/*
8240 * "range()" function
8241 */
8242 static void
8243f_range(typval_T *argvars, typval_T *rettv)
8244{
8245 varnumber_T start;
8246 varnumber_T end;
8247 varnumber_T stride = 1;
8248 varnumber_T i;
8249 int error = FALSE;
8250
8251 start = get_tv_number_chk(&argvars[0], &error);
8252 if (argvars[1].v_type == VAR_UNKNOWN)
8253 {
8254 end = start - 1;
8255 start = 0;
8256 }
8257 else
8258 {
8259 end = get_tv_number_chk(&argvars[1], &error);
8260 if (argvars[2].v_type != VAR_UNKNOWN)
8261 stride = get_tv_number_chk(&argvars[2], &error);
8262 }
8263
8264 if (error)
8265 return; /* type error; errmsg already given */
8266 if (stride == 0)
8267 EMSG(_("E726: Stride is zero"));
8268 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8269 EMSG(_("E727: Start past end"));
8270 else
8271 {
8272 if (rettv_list_alloc(rettv) == OK)
8273 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8274 if (list_append_number(rettv->vval.v_list,
8275 (varnumber_T)i) == FAIL)
8276 break;
8277 }
8278}
8279
8280/*
8281 * "readfile()" function
8282 */
8283 static void
8284f_readfile(typval_T *argvars, typval_T *rettv)
8285{
8286 int binary = FALSE;
8287 int failed = FALSE;
8288 char_u *fname;
8289 FILE *fd;
8290 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8291 int io_size = sizeof(buf);
8292 int readlen; /* size of last fread() */
8293 char_u *prev = NULL; /* previously read bytes, if any */
8294 long prevlen = 0; /* length of data in prev */
8295 long prevsize = 0; /* size of prev buffer */
8296 long maxline = MAXLNUM;
8297 long cnt = 0;
8298 char_u *p; /* position in buf */
8299 char_u *start; /* start of current line */
8300
8301 if (argvars[1].v_type != VAR_UNKNOWN)
8302 {
8303 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8304 binary = TRUE;
8305 if (argvars[2].v_type != VAR_UNKNOWN)
8306 maxline = (long)get_tv_number(&argvars[2]);
8307 }
8308
8309 if (rettv_list_alloc(rettv) == FAIL)
8310 return;
8311
8312 /* Always open the file in binary mode, library functions have a mind of
8313 * their own about CR-LF conversion. */
8314 fname = get_tv_string(&argvars[0]);
8315 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8316 {
8317 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8318 return;
8319 }
8320
8321 while (cnt < maxline || maxline < 0)
8322 {
8323 readlen = (int)fread(buf, 1, io_size, fd);
8324
8325 /* This for loop processes what was read, but is also entered at end
8326 * of file so that either:
8327 * - an incomplete line gets written
8328 * - a "binary" file gets an empty line at the end if it ends in a
8329 * newline. */
8330 for (p = buf, start = buf;
8331 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8332 ++p)
8333 {
8334 if (*p == '\n' || readlen <= 0)
8335 {
8336 listitem_T *li;
8337 char_u *s = NULL;
8338 long_u len = p - start;
8339
8340 /* Finished a line. Remove CRs before NL. */
8341 if (readlen > 0 && !binary)
8342 {
8343 while (len > 0 && start[len - 1] == '\r')
8344 --len;
8345 /* removal may cross back to the "prev" string */
8346 if (len == 0)
8347 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8348 --prevlen;
8349 }
8350 if (prevlen == 0)
8351 s = vim_strnsave(start, (int)len);
8352 else
8353 {
8354 /* Change "prev" buffer to be the right size. This way
8355 * the bytes are only copied once, and very long lines are
8356 * allocated only once. */
8357 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8358 {
8359 mch_memmove(s + prevlen, start, len);
8360 s[prevlen + len] = NUL;
8361 prev = NULL; /* the list will own the string */
8362 prevlen = prevsize = 0;
8363 }
8364 }
8365 if (s == NULL)
8366 {
8367 do_outofmem_msg((long_u) prevlen + len + 1);
8368 failed = TRUE;
8369 break;
8370 }
8371
8372 if ((li = listitem_alloc()) == NULL)
8373 {
8374 vim_free(s);
8375 failed = TRUE;
8376 break;
8377 }
8378 li->li_tv.v_type = VAR_STRING;
8379 li->li_tv.v_lock = 0;
8380 li->li_tv.vval.v_string = s;
8381 list_append(rettv->vval.v_list, li);
8382
8383 start = p + 1; /* step over newline */
8384 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8385 break;
8386 }
8387 else if (*p == NUL)
8388 *p = '\n';
8389#ifdef FEAT_MBYTE
8390 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8391 * when finding the BF and check the previous two bytes. */
8392 else if (*p == 0xbf && enc_utf8 && !binary)
8393 {
8394 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8395 * + 1, these may be in the "prev" string. */
8396 char_u back1 = p >= buf + 1 ? p[-1]
8397 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8398 char_u back2 = p >= buf + 2 ? p[-2]
8399 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8400 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8401
8402 if (back2 == 0xef && back1 == 0xbb)
8403 {
8404 char_u *dest = p - 2;
8405
8406 /* Usually a BOM is at the beginning of a file, and so at
8407 * the beginning of a line; then we can just step over it.
8408 */
8409 if (start == dest)
8410 start = p + 1;
8411 else
8412 {
8413 /* have to shuffle buf to close gap */
8414 int adjust_prevlen = 0;
8415
8416 if (dest < buf)
8417 {
8418 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8419 dest = buf;
8420 }
8421 if (readlen > p - buf + 1)
8422 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8423 readlen -= 3 - adjust_prevlen;
8424 prevlen -= adjust_prevlen;
8425 p = dest - 1;
8426 }
8427 }
8428 }
8429#endif
8430 } /* for */
8431
8432 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8433 break;
8434 if (start < p)
8435 {
8436 /* There's part of a line in buf, store it in "prev". */
8437 if (p - start + prevlen >= prevsize)
8438 {
8439 /* need bigger "prev" buffer */
8440 char_u *newprev;
8441
8442 /* A common use case is ordinary text files and "prev" gets a
8443 * fragment of a line, so the first allocation is made
8444 * small, to avoid repeatedly 'allocing' large and
8445 * 'reallocing' small. */
8446 if (prevsize == 0)
8447 prevsize = (long)(p - start);
8448 else
8449 {
8450 long grow50pc = (prevsize * 3) / 2;
8451 long growmin = (long)((p - start) * 2 + prevlen);
8452 prevsize = grow50pc > growmin ? grow50pc : growmin;
8453 }
8454 newprev = prev == NULL ? alloc(prevsize)
8455 : vim_realloc(prev, prevsize);
8456 if (newprev == NULL)
8457 {
8458 do_outofmem_msg((long_u)prevsize);
8459 failed = TRUE;
8460 break;
8461 }
8462 prev = newprev;
8463 }
8464 /* Add the line part to end of "prev". */
8465 mch_memmove(prev + prevlen, start, p - start);
8466 prevlen += (long)(p - start);
8467 }
8468 } /* while */
8469
8470 /*
8471 * For a negative line count use only the lines at the end of the file,
8472 * free the rest.
8473 */
8474 if (!failed && maxline < 0)
8475 while (cnt > -maxline)
8476 {
8477 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8478 --cnt;
8479 }
8480
8481 if (failed)
8482 {
8483 list_free(rettv->vval.v_list);
8484 /* readfile doc says an empty list is returned on error */
8485 rettv->vval.v_list = list_alloc();
8486 }
8487
8488 vim_free(prev);
8489 fclose(fd);
8490}
8491
8492#if defined(FEAT_RELTIME)
8493static int list2proftime(typval_T *arg, proftime_T *tm);
8494
8495/*
8496 * Convert a List to proftime_T.
8497 * Return FAIL when there is something wrong.
8498 */
8499 static int
8500list2proftime(typval_T *arg, proftime_T *tm)
8501{
8502 long n1, n2;
8503 int error = FALSE;
8504
8505 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8506 || arg->vval.v_list->lv_len != 2)
8507 return FAIL;
8508 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8509 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8510# ifdef WIN3264
8511 tm->HighPart = n1;
8512 tm->LowPart = n2;
8513# else
8514 tm->tv_sec = n1;
8515 tm->tv_usec = n2;
8516# endif
8517 return error ? FAIL : OK;
8518}
8519#endif /* FEAT_RELTIME */
8520
8521/*
8522 * "reltime()" function
8523 */
8524 static void
8525f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8526{
8527#ifdef FEAT_RELTIME
8528 proftime_T res;
8529 proftime_T start;
8530
8531 if (argvars[0].v_type == VAR_UNKNOWN)
8532 {
8533 /* No arguments: get current time. */
8534 profile_start(&res);
8535 }
8536 else if (argvars[1].v_type == VAR_UNKNOWN)
8537 {
8538 if (list2proftime(&argvars[0], &res) == FAIL)
8539 return;
8540 profile_end(&res);
8541 }
8542 else
8543 {
8544 /* Two arguments: compute the difference. */
8545 if (list2proftime(&argvars[0], &start) == FAIL
8546 || list2proftime(&argvars[1], &res) == FAIL)
8547 return;
8548 profile_sub(&res, &start);
8549 }
8550
8551 if (rettv_list_alloc(rettv) == OK)
8552 {
8553 long n1, n2;
8554
8555# ifdef WIN3264
8556 n1 = res.HighPart;
8557 n2 = res.LowPart;
8558# else
8559 n1 = res.tv_sec;
8560 n2 = res.tv_usec;
8561# endif
8562 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8563 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8564 }
8565#endif
8566}
8567
8568#ifdef FEAT_FLOAT
8569/*
8570 * "reltimefloat()" function
8571 */
8572 static void
8573f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8574{
8575# ifdef FEAT_RELTIME
8576 proftime_T tm;
8577# endif
8578
8579 rettv->v_type = VAR_FLOAT;
8580 rettv->vval.v_float = 0;
8581# ifdef FEAT_RELTIME
8582 if (list2proftime(&argvars[0], &tm) == OK)
8583 rettv->vval.v_float = profile_float(&tm);
8584# endif
8585}
8586#endif
8587
8588/*
8589 * "reltimestr()" function
8590 */
8591 static void
8592f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8593{
8594#ifdef FEAT_RELTIME
8595 proftime_T tm;
8596#endif
8597
8598 rettv->v_type = VAR_STRING;
8599 rettv->vval.v_string = NULL;
8600#ifdef FEAT_RELTIME
8601 if (list2proftime(&argvars[0], &tm) == OK)
8602 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8603#endif
8604}
8605
8606#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8607static void make_connection(void);
8608static int check_connection(void);
8609
8610 static void
8611make_connection(void)
8612{
8613 if (X_DISPLAY == NULL
8614# ifdef FEAT_GUI
8615 && !gui.in_use
8616# endif
8617 )
8618 {
8619 x_force_connect = TRUE;
8620 setup_term_clip();
8621 x_force_connect = FALSE;
8622 }
8623}
8624
8625 static int
8626check_connection(void)
8627{
8628 make_connection();
8629 if (X_DISPLAY == NULL)
8630 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008631 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008632 return FAIL;
8633 }
8634 return OK;
8635}
8636#endif
8637
8638#ifdef FEAT_CLIENTSERVER
8639 static void
8640remote_common(typval_T *argvars, typval_T *rettv, int expr)
8641{
8642 char_u *server_name;
8643 char_u *keys;
8644 char_u *r = NULL;
8645 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008646 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008647# ifdef WIN32
8648 HWND w;
8649# else
8650 Window w;
8651# endif
8652
8653 if (check_restricted() || check_secure())
8654 return;
8655
8656# ifdef FEAT_X11
8657 if (check_connection() == FAIL)
8658 return;
8659# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008660 if (argvars[2].v_type != VAR_UNKNOWN
8661 && argvars[3].v_type != VAR_UNKNOWN)
8662 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008663
8664 server_name = get_tv_string_chk(&argvars[0]);
8665 if (server_name == NULL)
8666 return; /* type error; errmsg already given */
8667 keys = get_tv_string_buf(&argvars[1], buf);
8668# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008669 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008670# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008671 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8672 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008673# endif
8674 {
8675 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008676 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008677 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008678 vim_free(r);
8679 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008680 else
8681 EMSG2(_("E241: Unable to send to %s"), server_name);
8682 return;
8683 }
8684
8685 rettv->vval.v_string = r;
8686
8687 if (argvars[2].v_type != VAR_UNKNOWN)
8688 {
8689 dictitem_T v;
8690 char_u str[30];
8691 char_u *idvar;
8692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008693 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008694 if (idvar != NULL && *idvar != NUL)
8695 {
8696 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8697 v.di_tv.v_type = VAR_STRING;
8698 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008699 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008700 vim_free(v.di_tv.vval.v_string);
8701 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008702 }
8703}
8704#endif
8705
8706/*
8707 * "remote_expr()" function
8708 */
8709 static void
8710f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8711{
8712 rettv->v_type = VAR_STRING;
8713 rettv->vval.v_string = NULL;
8714#ifdef FEAT_CLIENTSERVER
8715 remote_common(argvars, rettv, TRUE);
8716#endif
8717}
8718
8719/*
8720 * "remote_foreground()" function
8721 */
8722 static void
8723f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8724{
8725#ifdef FEAT_CLIENTSERVER
8726# ifdef WIN32
8727 /* On Win32 it's done in this application. */
8728 {
8729 char_u *server_name = get_tv_string_chk(&argvars[0]);
8730
8731 if (server_name != NULL)
8732 serverForeground(server_name);
8733 }
8734# else
8735 /* Send a foreground() expression to the server. */
8736 argvars[1].v_type = VAR_STRING;
8737 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8738 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008739 rettv->v_type = VAR_STRING;
8740 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008741 remote_common(argvars, rettv, TRUE);
8742 vim_free(argvars[1].vval.v_string);
8743# endif
8744#endif
8745}
8746
8747 static void
8748f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8749{
8750#ifdef FEAT_CLIENTSERVER
8751 dictitem_T v;
8752 char_u *s = NULL;
8753# ifdef WIN32
8754 long_u n = 0;
8755# endif
8756 char_u *serverid;
8757
8758 if (check_restricted() || check_secure())
8759 {
8760 rettv->vval.v_number = -1;
8761 return;
8762 }
8763 serverid = get_tv_string_chk(&argvars[0]);
8764 if (serverid == NULL)
8765 {
8766 rettv->vval.v_number = -1;
8767 return; /* type error; errmsg already given */
8768 }
8769# ifdef WIN32
8770 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8771 if (n == 0)
8772 rettv->vval.v_number = -1;
8773 else
8774 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008775 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008776 rettv->vval.v_number = (s != NULL);
8777 }
8778# else
8779 if (check_connection() == FAIL)
8780 return;
8781
8782 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8783 serverStrToWin(serverid), &s);
8784# endif
8785
8786 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8787 {
8788 char_u *retvar;
8789
8790 v.di_tv.v_type = VAR_STRING;
8791 v.di_tv.vval.v_string = vim_strsave(s);
8792 retvar = get_tv_string_chk(&argvars[1]);
8793 if (retvar != NULL)
8794 set_var(retvar, &v.di_tv, FALSE);
8795 vim_free(v.di_tv.vval.v_string);
8796 }
8797#else
8798 rettv->vval.v_number = -1;
8799#endif
8800}
8801
8802 static void
8803f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8804{
8805 char_u *r = NULL;
8806
8807#ifdef FEAT_CLIENTSERVER
8808 char_u *serverid = get_tv_string_chk(&argvars[0]);
8809
8810 if (serverid != NULL && !check_restricted() && !check_secure())
8811 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008812 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008813# ifdef WIN32
8814 /* The server's HWND is encoded in the 'id' parameter */
8815 long_u n = 0;
8816# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008817
8818 if (argvars[1].v_type != VAR_UNKNOWN)
8819 timeout = get_tv_number(&argvars[1]);
8820
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008821# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008822 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8823 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008824 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008825 if (r == NULL)
8826# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008827 if (check_connection() == FAIL
8828 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8829 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008830# endif
8831 EMSG(_("E277: Unable to read a server reply"));
8832 }
8833#endif
8834 rettv->v_type = VAR_STRING;
8835 rettv->vval.v_string = r;
8836}
8837
8838/*
8839 * "remote_send()" function
8840 */
8841 static void
8842f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8843{
8844 rettv->v_type = VAR_STRING;
8845 rettv->vval.v_string = NULL;
8846#ifdef FEAT_CLIENTSERVER
8847 remote_common(argvars, rettv, FALSE);
8848#endif
8849}
8850
8851/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008852 * "remote_startserver()" function
8853 */
8854 static void
8855f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8856{
8857#ifdef FEAT_CLIENTSERVER
8858 char_u *server = get_tv_string_chk(&argvars[0]);
8859
8860 if (server == NULL)
8861 return; /* type error; errmsg already given */
8862 if (serverName != NULL)
8863 EMSG(_("E941: already started a server"));
8864 else
8865 {
8866# ifdef FEAT_X11
8867 if (check_connection() == OK)
8868 serverRegisterName(X_DISPLAY, server);
8869# else
8870 serverSetName(server);
8871# endif
8872 }
8873#else
8874 EMSG(_("E942: +clientserver feature not available"));
8875#endif
8876}
8877
8878/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008879 * "remove()" function
8880 */
8881 static void
8882f_remove(typval_T *argvars, typval_T *rettv)
8883{
8884 list_T *l;
8885 listitem_T *item, *item2;
8886 listitem_T *li;
8887 long idx;
8888 long end;
8889 char_u *key;
8890 dict_T *d;
8891 dictitem_T *di;
8892 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8893
8894 if (argvars[0].v_type == VAR_DICT)
8895 {
8896 if (argvars[2].v_type != VAR_UNKNOWN)
8897 EMSG2(_(e_toomanyarg), "remove()");
8898 else if ((d = argvars[0].vval.v_dict) != NULL
8899 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8900 {
8901 key = get_tv_string_chk(&argvars[1]);
8902 if (key != NULL)
8903 {
8904 di = dict_find(d, key, -1);
8905 if (di == NULL)
8906 EMSG2(_(e_dictkey), key);
8907 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8908 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8909 {
8910 *rettv = di->di_tv;
8911 init_tv(&di->di_tv);
8912 dictitem_remove(d, di);
8913 }
8914 }
8915 }
8916 }
8917 else if (argvars[0].v_type != VAR_LIST)
8918 EMSG2(_(e_listdictarg), "remove()");
8919 else if ((l = argvars[0].vval.v_list) != NULL
8920 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8921 {
8922 int error = FALSE;
8923
8924 idx = (long)get_tv_number_chk(&argvars[1], &error);
8925 if (error)
8926 ; /* type error: do nothing, errmsg already given */
8927 else if ((item = list_find(l, idx)) == NULL)
8928 EMSGN(_(e_listidx), idx);
8929 else
8930 {
8931 if (argvars[2].v_type == VAR_UNKNOWN)
8932 {
8933 /* Remove one item, return its value. */
8934 vimlist_remove(l, item, item);
8935 *rettv = item->li_tv;
8936 vim_free(item);
8937 }
8938 else
8939 {
8940 /* Remove range of items, return list with values. */
8941 end = (long)get_tv_number_chk(&argvars[2], &error);
8942 if (error)
8943 ; /* type error: do nothing */
8944 else if ((item2 = list_find(l, end)) == NULL)
8945 EMSGN(_(e_listidx), end);
8946 else
8947 {
8948 int cnt = 0;
8949
8950 for (li = item; li != NULL; li = li->li_next)
8951 {
8952 ++cnt;
8953 if (li == item2)
8954 break;
8955 }
8956 if (li == NULL) /* didn't find "item2" after "item" */
8957 EMSG(_(e_invrange));
8958 else
8959 {
8960 vimlist_remove(l, item, item2);
8961 if (rettv_list_alloc(rettv) == OK)
8962 {
8963 l = rettv->vval.v_list;
8964 l->lv_first = item;
8965 l->lv_last = item2;
8966 item->li_prev = NULL;
8967 item2->li_next = NULL;
8968 l->lv_len = cnt;
8969 }
8970 }
8971 }
8972 }
8973 }
8974 }
8975}
8976
8977/*
8978 * "rename({from}, {to})" function
8979 */
8980 static void
8981f_rename(typval_T *argvars, typval_T *rettv)
8982{
8983 char_u buf[NUMBUFLEN];
8984
8985 if (check_restricted() || check_secure())
8986 rettv->vval.v_number = -1;
8987 else
8988 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8989 get_tv_string_buf(&argvars[1], buf));
8990}
8991
8992/*
8993 * "repeat()" function
8994 */
8995 static void
8996f_repeat(typval_T *argvars, typval_T *rettv)
8997{
8998 char_u *p;
8999 int n;
9000 int slen;
9001 int len;
9002 char_u *r;
9003 int i;
9004
9005 n = (int)get_tv_number(&argvars[1]);
9006 if (argvars[0].v_type == VAR_LIST)
9007 {
9008 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9009 while (n-- > 0)
9010 if (list_extend(rettv->vval.v_list,
9011 argvars[0].vval.v_list, NULL) == FAIL)
9012 break;
9013 }
9014 else
9015 {
9016 p = get_tv_string(&argvars[0]);
9017 rettv->v_type = VAR_STRING;
9018 rettv->vval.v_string = NULL;
9019
9020 slen = (int)STRLEN(p);
9021 len = slen * n;
9022 if (len <= 0)
9023 return;
9024
9025 r = alloc(len + 1);
9026 if (r != NULL)
9027 {
9028 for (i = 0; i < n; i++)
9029 mch_memmove(r + i * slen, p, (size_t)slen);
9030 r[len] = NUL;
9031 }
9032
9033 rettv->vval.v_string = r;
9034 }
9035}
9036
9037/*
9038 * "resolve()" function
9039 */
9040 static void
9041f_resolve(typval_T *argvars, typval_T *rettv)
9042{
9043 char_u *p;
9044#ifdef HAVE_READLINK
9045 char_u *buf = NULL;
9046#endif
9047
9048 p = get_tv_string(&argvars[0]);
9049#ifdef FEAT_SHORTCUT
9050 {
9051 char_u *v = NULL;
9052
9053 v = mch_resolve_shortcut(p);
9054 if (v != NULL)
9055 rettv->vval.v_string = v;
9056 else
9057 rettv->vval.v_string = vim_strsave(p);
9058 }
9059#else
9060# ifdef HAVE_READLINK
9061 {
9062 char_u *cpy;
9063 int len;
9064 char_u *remain = NULL;
9065 char_u *q;
9066 int is_relative_to_current = FALSE;
9067 int has_trailing_pathsep = FALSE;
9068 int limit = 100;
9069
9070 p = vim_strsave(p);
9071
9072 if (p[0] == '.' && (vim_ispathsep(p[1])
9073 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9074 is_relative_to_current = TRUE;
9075
9076 len = STRLEN(p);
9077 if (len > 0 && after_pathsep(p, p + len))
9078 {
9079 has_trailing_pathsep = TRUE;
9080 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9081 }
9082
9083 q = getnextcomp(p);
9084 if (*q != NUL)
9085 {
9086 /* Separate the first path component in "p", and keep the
9087 * remainder (beginning with the path separator). */
9088 remain = vim_strsave(q - 1);
9089 q[-1] = NUL;
9090 }
9091
9092 buf = alloc(MAXPATHL + 1);
9093 if (buf == NULL)
9094 goto fail;
9095
9096 for (;;)
9097 {
9098 for (;;)
9099 {
9100 len = readlink((char *)p, (char *)buf, MAXPATHL);
9101 if (len <= 0)
9102 break;
9103 buf[len] = NUL;
9104
9105 if (limit-- == 0)
9106 {
9107 vim_free(p);
9108 vim_free(remain);
9109 EMSG(_("E655: Too many symbolic links (cycle?)"));
9110 rettv->vval.v_string = NULL;
9111 goto fail;
9112 }
9113
9114 /* Ensure that the result will have a trailing path separator
9115 * if the argument has one. */
9116 if (remain == NULL && has_trailing_pathsep)
9117 add_pathsep(buf);
9118
9119 /* Separate the first path component in the link value and
9120 * concatenate the remainders. */
9121 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9122 if (*q != NUL)
9123 {
9124 if (remain == NULL)
9125 remain = vim_strsave(q - 1);
9126 else
9127 {
9128 cpy = concat_str(q - 1, remain);
9129 if (cpy != NULL)
9130 {
9131 vim_free(remain);
9132 remain = cpy;
9133 }
9134 }
9135 q[-1] = NUL;
9136 }
9137
9138 q = gettail(p);
9139 if (q > p && *q == NUL)
9140 {
9141 /* Ignore trailing path separator. */
9142 q[-1] = NUL;
9143 q = gettail(p);
9144 }
9145 if (q > p && !mch_isFullName(buf))
9146 {
9147 /* symlink is relative to directory of argument */
9148 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9149 if (cpy != NULL)
9150 {
9151 STRCPY(cpy, p);
9152 STRCPY(gettail(cpy), buf);
9153 vim_free(p);
9154 p = cpy;
9155 }
9156 }
9157 else
9158 {
9159 vim_free(p);
9160 p = vim_strsave(buf);
9161 }
9162 }
9163
9164 if (remain == NULL)
9165 break;
9166
9167 /* Append the first path component of "remain" to "p". */
9168 q = getnextcomp(remain + 1);
9169 len = q - remain - (*q != NUL);
9170 cpy = vim_strnsave(p, STRLEN(p) + len);
9171 if (cpy != NULL)
9172 {
9173 STRNCAT(cpy, remain, len);
9174 vim_free(p);
9175 p = cpy;
9176 }
9177 /* Shorten "remain". */
9178 if (*q != NUL)
9179 STRMOVE(remain, q - 1);
9180 else
9181 {
9182 vim_free(remain);
9183 remain = NULL;
9184 }
9185 }
9186
9187 /* If the result is a relative path name, make it explicitly relative to
9188 * the current directory if and only if the argument had this form. */
9189 if (!vim_ispathsep(*p))
9190 {
9191 if (is_relative_to_current
9192 && *p != NUL
9193 && !(p[0] == '.'
9194 && (p[1] == NUL
9195 || vim_ispathsep(p[1])
9196 || (p[1] == '.'
9197 && (p[2] == NUL
9198 || vim_ispathsep(p[2]))))))
9199 {
9200 /* Prepend "./". */
9201 cpy = concat_str((char_u *)"./", p);
9202 if (cpy != NULL)
9203 {
9204 vim_free(p);
9205 p = cpy;
9206 }
9207 }
9208 else if (!is_relative_to_current)
9209 {
9210 /* Strip leading "./". */
9211 q = p;
9212 while (q[0] == '.' && vim_ispathsep(q[1]))
9213 q += 2;
9214 if (q > p)
9215 STRMOVE(p, p + 2);
9216 }
9217 }
9218
9219 /* Ensure that the result will have no trailing path separator
9220 * if the argument had none. But keep "/" or "//". */
9221 if (!has_trailing_pathsep)
9222 {
9223 q = p + STRLEN(p);
9224 if (after_pathsep(p, q))
9225 *gettail_sep(p) = NUL;
9226 }
9227
9228 rettv->vval.v_string = p;
9229 }
9230# else
9231 rettv->vval.v_string = vim_strsave(p);
9232# endif
9233#endif
9234
9235 simplify_filename(rettv->vval.v_string);
9236
9237#ifdef HAVE_READLINK
9238fail:
9239 vim_free(buf);
9240#endif
9241 rettv->v_type = VAR_STRING;
9242}
9243
9244/*
9245 * "reverse({list})" function
9246 */
9247 static void
9248f_reverse(typval_T *argvars, typval_T *rettv)
9249{
9250 list_T *l;
9251 listitem_T *li, *ni;
9252
9253 if (argvars[0].v_type != VAR_LIST)
9254 EMSG2(_(e_listarg), "reverse()");
9255 else if ((l = argvars[0].vval.v_list) != NULL
9256 && !tv_check_lock(l->lv_lock,
9257 (char_u *)N_("reverse() argument"), TRUE))
9258 {
9259 li = l->lv_last;
9260 l->lv_first = l->lv_last = NULL;
9261 l->lv_len = 0;
9262 while (li != NULL)
9263 {
9264 ni = li->li_prev;
9265 list_append(l, li);
9266 li = ni;
9267 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009268 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009269 l->lv_idx = l->lv_len - l->lv_idx - 1;
9270 }
9271}
9272
9273#define SP_NOMOVE 0x01 /* don't move cursor */
9274#define SP_REPEAT 0x02 /* repeat to find outer pair */
9275#define SP_RETCOUNT 0x04 /* return matchcount */
9276#define SP_SETPCMARK 0x08 /* set previous context mark */
9277#define SP_START 0x10 /* accept match at start position */
9278#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9279#define SP_END 0x40 /* leave cursor at end of match */
9280#define SP_COLUMN 0x80 /* start at cursor column */
9281
9282static int get_search_arg(typval_T *varp, int *flagsp);
9283
9284/*
9285 * Get flags for a search function.
9286 * Possibly sets "p_ws".
9287 * Returns BACKWARD, FORWARD or zero (for an error).
9288 */
9289 static int
9290get_search_arg(typval_T *varp, int *flagsp)
9291{
9292 int dir = FORWARD;
9293 char_u *flags;
9294 char_u nbuf[NUMBUFLEN];
9295 int mask;
9296
9297 if (varp->v_type != VAR_UNKNOWN)
9298 {
9299 flags = get_tv_string_buf_chk(varp, nbuf);
9300 if (flags == NULL)
9301 return 0; /* type error; errmsg already given */
9302 while (*flags != NUL)
9303 {
9304 switch (*flags)
9305 {
9306 case 'b': dir = BACKWARD; break;
9307 case 'w': p_ws = TRUE; break;
9308 case 'W': p_ws = FALSE; break;
9309 default: mask = 0;
9310 if (flagsp != NULL)
9311 switch (*flags)
9312 {
9313 case 'c': mask = SP_START; break;
9314 case 'e': mask = SP_END; break;
9315 case 'm': mask = SP_RETCOUNT; break;
9316 case 'n': mask = SP_NOMOVE; break;
9317 case 'p': mask = SP_SUBPAT; break;
9318 case 'r': mask = SP_REPEAT; break;
9319 case 's': mask = SP_SETPCMARK; break;
9320 case 'z': mask = SP_COLUMN; break;
9321 }
9322 if (mask == 0)
9323 {
9324 EMSG2(_(e_invarg2), flags);
9325 dir = 0;
9326 }
9327 else
9328 *flagsp |= mask;
9329 }
9330 if (dir == 0)
9331 break;
9332 ++flags;
9333 }
9334 }
9335 return dir;
9336}
9337
9338/*
9339 * Shared by search() and searchpos() functions.
9340 */
9341 static int
9342search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9343{
9344 int flags;
9345 char_u *pat;
9346 pos_T pos;
9347 pos_T save_cursor;
9348 int save_p_ws = p_ws;
9349 int dir;
9350 int retval = 0; /* default: FAIL */
9351 long lnum_stop = 0;
9352 proftime_T tm;
9353#ifdef FEAT_RELTIME
9354 long time_limit = 0;
9355#endif
9356 int options = SEARCH_KEEP;
9357 int subpatnum;
9358
9359 pat = get_tv_string(&argvars[0]);
9360 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9361 if (dir == 0)
9362 goto theend;
9363 flags = *flagsp;
9364 if (flags & SP_START)
9365 options |= SEARCH_START;
9366 if (flags & SP_END)
9367 options |= SEARCH_END;
9368 if (flags & SP_COLUMN)
9369 options |= SEARCH_COL;
9370
9371 /* Optional arguments: line number to stop searching and timeout. */
9372 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9373 {
9374 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9375 if (lnum_stop < 0)
9376 goto theend;
9377#ifdef FEAT_RELTIME
9378 if (argvars[3].v_type != VAR_UNKNOWN)
9379 {
9380 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9381 if (time_limit < 0)
9382 goto theend;
9383 }
9384#endif
9385 }
9386
9387#ifdef FEAT_RELTIME
9388 /* Set the time limit, if there is one. */
9389 profile_setlimit(time_limit, &tm);
9390#endif
9391
9392 /*
9393 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9394 * Check to make sure only those flags are set.
9395 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9396 * flags cannot be set. Check for that condition also.
9397 */
9398 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9399 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9400 {
9401 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9402 goto theend;
9403 }
9404
9405 pos = save_cursor = curwin->w_cursor;
9406 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009407 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009408 if (subpatnum != FAIL)
9409 {
9410 if (flags & SP_SUBPAT)
9411 retval = subpatnum;
9412 else
9413 retval = pos.lnum;
9414 if (flags & SP_SETPCMARK)
9415 setpcmark();
9416 curwin->w_cursor = pos;
9417 if (match_pos != NULL)
9418 {
9419 /* Store the match cursor position */
9420 match_pos->lnum = pos.lnum;
9421 match_pos->col = pos.col + 1;
9422 }
9423 /* "/$" will put the cursor after the end of the line, may need to
9424 * correct that here */
9425 check_cursor();
9426 }
9427
9428 /* If 'n' flag is used: restore cursor position. */
9429 if (flags & SP_NOMOVE)
9430 curwin->w_cursor = save_cursor;
9431 else
9432 curwin->w_set_curswant = TRUE;
9433theend:
9434 p_ws = save_p_ws;
9435
9436 return retval;
9437}
9438
9439#ifdef FEAT_FLOAT
9440
9441/*
9442 * round() is not in C90, use ceil() or floor() instead.
9443 */
9444 float_T
9445vim_round(float_T f)
9446{
9447 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9448}
9449
9450/*
9451 * "round({float})" function
9452 */
9453 static void
9454f_round(typval_T *argvars, typval_T *rettv)
9455{
9456 float_T f = 0.0;
9457
9458 rettv->v_type = VAR_FLOAT;
9459 if (get_float_arg(argvars, &f) == OK)
9460 rettv->vval.v_float = vim_round(f);
9461 else
9462 rettv->vval.v_float = 0.0;
9463}
9464#endif
9465
9466/*
9467 * "screenattr()" function
9468 */
9469 static void
9470f_screenattr(typval_T *argvars, typval_T *rettv)
9471{
9472 int row;
9473 int col;
9474 int c;
9475
9476 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9477 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9478 if (row < 0 || row >= screen_Rows
9479 || col < 0 || col >= screen_Columns)
9480 c = -1;
9481 else
9482 c = ScreenAttrs[LineOffset[row] + col];
9483 rettv->vval.v_number = c;
9484}
9485
9486/*
9487 * "screenchar()" function
9488 */
9489 static void
9490f_screenchar(typval_T *argvars, typval_T *rettv)
9491{
9492 int row;
9493 int col;
9494 int off;
9495 int c;
9496
9497 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9498 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9499 if (row < 0 || row >= screen_Rows
9500 || col < 0 || col >= screen_Columns)
9501 c = -1;
9502 else
9503 {
9504 off = LineOffset[row] + col;
9505#ifdef FEAT_MBYTE
9506 if (enc_utf8 && ScreenLinesUC[off] != 0)
9507 c = ScreenLinesUC[off];
9508 else
9509#endif
9510 c = ScreenLines[off];
9511 }
9512 rettv->vval.v_number = c;
9513}
9514
9515/*
9516 * "screencol()" function
9517 *
9518 * First column is 1 to be consistent with virtcol().
9519 */
9520 static void
9521f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9522{
9523 rettv->vval.v_number = screen_screencol() + 1;
9524}
9525
9526/*
9527 * "screenrow()" function
9528 */
9529 static void
9530f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9531{
9532 rettv->vval.v_number = screen_screenrow() + 1;
9533}
9534
9535/*
9536 * "search()" function
9537 */
9538 static void
9539f_search(typval_T *argvars, typval_T *rettv)
9540{
9541 int flags = 0;
9542
9543 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9544}
9545
9546/*
9547 * "searchdecl()" function
9548 */
9549 static void
9550f_searchdecl(typval_T *argvars, typval_T *rettv)
9551{
9552 int locally = 1;
9553 int thisblock = 0;
9554 int error = FALSE;
9555 char_u *name;
9556
9557 rettv->vval.v_number = 1; /* default: FAIL */
9558
9559 name = get_tv_string_chk(&argvars[0]);
9560 if (argvars[1].v_type != VAR_UNKNOWN)
9561 {
9562 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9563 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9564 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9565 }
9566 if (!error && name != NULL)
9567 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9568 locally, thisblock, SEARCH_KEEP) == FAIL;
9569}
9570
9571/*
9572 * Used by searchpair() and searchpairpos()
9573 */
9574 static int
9575searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9576{
9577 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009578 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009579 int save_p_ws = p_ws;
9580 int dir;
9581 int flags = 0;
9582 char_u nbuf1[NUMBUFLEN];
9583 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009584 int retval = 0; /* default: FAIL */
9585 long lnum_stop = 0;
9586 long time_limit = 0;
9587
9588 /* Get the three pattern arguments: start, middle, end. */
9589 spat = get_tv_string_chk(&argvars[0]);
9590 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9591 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9592 if (spat == NULL || mpat == NULL || epat == NULL)
9593 goto theend; /* type error */
9594
9595 /* Handle the optional fourth argument: flags */
9596 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9597 if (dir == 0)
9598 goto theend;
9599
9600 /* Don't accept SP_END or SP_SUBPAT.
9601 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9602 */
9603 if ((flags & (SP_END | SP_SUBPAT)) != 0
9604 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9605 {
9606 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9607 goto theend;
9608 }
9609
9610 /* Using 'r' implies 'W', otherwise it doesn't work. */
9611 if (flags & SP_REPEAT)
9612 p_ws = FALSE;
9613
9614 /* Optional fifth argument: skip expression */
9615 if (argvars[3].v_type == VAR_UNKNOWN
9616 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009617 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009618 else
9619 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009620 skip = &argvars[4];
9621 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9622 && skip->v_type != VAR_STRING)
9623 {
9624 /* Type error */
9625 goto theend;
9626 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009627 if (argvars[5].v_type != VAR_UNKNOWN)
9628 {
9629 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9630 if (lnum_stop < 0)
9631 goto theend;
9632#ifdef FEAT_RELTIME
9633 if (argvars[6].v_type != VAR_UNKNOWN)
9634 {
9635 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9636 if (time_limit < 0)
9637 goto theend;
9638 }
9639#endif
9640 }
9641 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009642
9643 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9644 match_pos, lnum_stop, time_limit);
9645
9646theend:
9647 p_ws = save_p_ws;
9648
9649 return retval;
9650}
9651
9652/*
9653 * "searchpair()" function
9654 */
9655 static void
9656f_searchpair(typval_T *argvars, typval_T *rettv)
9657{
9658 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9659}
9660
9661/*
9662 * "searchpairpos()" function
9663 */
9664 static void
9665f_searchpairpos(typval_T *argvars, typval_T *rettv)
9666{
9667 pos_T match_pos;
9668 int lnum = 0;
9669 int col = 0;
9670
9671 if (rettv_list_alloc(rettv) == FAIL)
9672 return;
9673
9674 if (searchpair_cmn(argvars, &match_pos) > 0)
9675 {
9676 lnum = match_pos.lnum;
9677 col = match_pos.col;
9678 }
9679
9680 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9681 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9682}
9683
9684/*
9685 * Search for a start/middle/end thing.
9686 * Used by searchpair(), see its documentation for the details.
9687 * Returns 0 or -1 for no match,
9688 */
9689 long
9690do_searchpair(
9691 char_u *spat, /* start pattern */
9692 char_u *mpat, /* middle pattern */
9693 char_u *epat, /* end pattern */
9694 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009695 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009696 int flags, /* SP_SETPCMARK and other SP_ values */
9697 pos_T *match_pos,
9698 linenr_T lnum_stop, /* stop at this line if not zero */
9699 long time_limit UNUSED) /* stop after this many msec */
9700{
9701 char_u *save_cpo;
9702 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9703 long retval = 0;
9704 pos_T pos;
9705 pos_T firstpos;
9706 pos_T foundpos;
9707 pos_T save_cursor;
9708 pos_T save_pos;
9709 int n;
9710 int r;
9711 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009712 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009713 int err;
9714 int options = SEARCH_KEEP;
9715 proftime_T tm;
9716
9717 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9718 save_cpo = p_cpo;
9719 p_cpo = empty_option;
9720
9721#ifdef FEAT_RELTIME
9722 /* Set the time limit, if there is one. */
9723 profile_setlimit(time_limit, &tm);
9724#endif
9725
9726 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9727 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009728 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9729 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009730 if (pat2 == NULL || pat3 == NULL)
9731 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009732 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009733 if (*mpat == NUL)
9734 STRCPY(pat3, pat2);
9735 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009736 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009737 spat, epat, mpat);
9738 if (flags & SP_START)
9739 options |= SEARCH_START;
9740
Bram Moolenaar48570482017-10-30 21:48:41 +01009741 if (skip != NULL)
9742 {
9743 /* Empty string means to not use the skip expression. */
9744 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9745 use_skip = skip->vval.v_string != NULL
9746 && *skip->vval.v_string != NUL;
9747 }
9748
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009749 save_cursor = curwin->w_cursor;
9750 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009751 CLEAR_POS(&firstpos);
9752 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009753 pat = pat3;
9754 for (;;)
9755 {
9756 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009757 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009758 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009759 /* didn't find it or found the first match again: FAIL */
9760 break;
9761
9762 if (firstpos.lnum == 0)
9763 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009764 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009765 {
9766 /* Found the same position again. Can happen with a pattern that
9767 * has "\zs" at the end and searching backwards. Advance one
9768 * character and try again. */
9769 if (dir == BACKWARD)
9770 decl(&pos);
9771 else
9772 incl(&pos);
9773 }
9774 foundpos = pos;
9775
9776 /* clear the start flag to avoid getting stuck here */
9777 options &= ~SEARCH_START;
9778
9779 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009780 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009781 {
9782 save_pos = curwin->w_cursor;
9783 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009784 err = FALSE;
9785 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009786 curwin->w_cursor = save_pos;
9787 if (err)
9788 {
9789 /* Evaluating {skip} caused an error, break here. */
9790 curwin->w_cursor = save_cursor;
9791 retval = -1;
9792 break;
9793 }
9794 if (r)
9795 continue;
9796 }
9797
9798 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9799 {
9800 /* Found end when searching backwards or start when searching
9801 * forward: nested pair. */
9802 ++nest;
9803 pat = pat2; /* nested, don't search for middle */
9804 }
9805 else
9806 {
9807 /* Found end when searching forward or start when searching
9808 * backward: end of (nested) pair; or found middle in outer pair. */
9809 if (--nest == 1)
9810 pat = pat3; /* outer level, search for middle */
9811 }
9812
9813 if (nest == 0)
9814 {
9815 /* Found the match: return matchcount or line number. */
9816 if (flags & SP_RETCOUNT)
9817 ++retval;
9818 else
9819 retval = pos.lnum;
9820 if (flags & SP_SETPCMARK)
9821 setpcmark();
9822 curwin->w_cursor = pos;
9823 if (!(flags & SP_REPEAT))
9824 break;
9825 nest = 1; /* search for next unmatched */
9826 }
9827 }
9828
9829 if (match_pos != NULL)
9830 {
9831 /* Store the match cursor position */
9832 match_pos->lnum = curwin->w_cursor.lnum;
9833 match_pos->col = curwin->w_cursor.col + 1;
9834 }
9835
9836 /* If 'n' flag is used or search failed: restore cursor position. */
9837 if ((flags & SP_NOMOVE) || retval == 0)
9838 curwin->w_cursor = save_cursor;
9839
9840theend:
9841 vim_free(pat2);
9842 vim_free(pat3);
9843 if (p_cpo == empty_option)
9844 p_cpo = save_cpo;
9845 else
9846 /* Darn, evaluating the {skip} expression changed the value. */
9847 free_string_option(save_cpo);
9848
9849 return retval;
9850}
9851
9852/*
9853 * "searchpos()" function
9854 */
9855 static void
9856f_searchpos(typval_T *argvars, typval_T *rettv)
9857{
9858 pos_T match_pos;
9859 int lnum = 0;
9860 int col = 0;
9861 int n;
9862 int flags = 0;
9863
9864 if (rettv_list_alloc(rettv) == FAIL)
9865 return;
9866
9867 n = search_cmn(argvars, &match_pos, &flags);
9868 if (n > 0)
9869 {
9870 lnum = match_pos.lnum;
9871 col = match_pos.col;
9872 }
9873
9874 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9875 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9876 if (flags & SP_SUBPAT)
9877 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9878}
9879
9880 static void
9881f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9882{
9883#ifdef FEAT_CLIENTSERVER
9884 char_u buf[NUMBUFLEN];
9885 char_u *server = get_tv_string_chk(&argvars[0]);
9886 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9887
9888 rettv->vval.v_number = -1;
9889 if (server == NULL || reply == NULL)
9890 return;
9891 if (check_restricted() || check_secure())
9892 return;
9893# ifdef FEAT_X11
9894 if (check_connection() == FAIL)
9895 return;
9896# endif
9897
9898 if (serverSendReply(server, reply) < 0)
9899 {
9900 EMSG(_("E258: Unable to send to client"));
9901 return;
9902 }
9903 rettv->vval.v_number = 0;
9904#else
9905 rettv->vval.v_number = -1;
9906#endif
9907}
9908
9909 static void
9910f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9911{
9912 char_u *r = NULL;
9913
9914#ifdef FEAT_CLIENTSERVER
9915# ifdef WIN32
9916 r = serverGetVimNames();
9917# else
9918 make_connection();
9919 if (X_DISPLAY != NULL)
9920 r = serverGetVimNames(X_DISPLAY);
9921# endif
9922#endif
9923 rettv->v_type = VAR_STRING;
9924 rettv->vval.v_string = r;
9925}
9926
9927/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009928 * Set line or list of lines in buffer "buf".
9929 */
9930 static void
9931set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
9932{
9933 char_u *line = NULL;
9934 list_T *l = NULL;
9935 listitem_T *li = NULL;
9936 long added = 0;
9937 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009938 buf_T *curbuf_save = NULL;
9939 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009940 int is_curbuf = buf == curbuf;
9941
Bram Moolenaar9d954202017-09-04 20:34:19 +02009942 /* When using the current buffer ml_mfp will be set if needed. Useful when
9943 * setline() is used on startup. For other buffers the buffer must be
9944 * loaded. */
9945 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009946 {
9947 rettv->vval.v_number = 1; /* FAIL */
9948 return;
9949 }
9950
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009951 if (!is_curbuf)
9952 {
9953 wininfo_T *wip;
9954
9955 curbuf_save = curbuf;
9956 curwin_save = curwin;
9957 curbuf = buf;
9958 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
9959 {
9960 if (wip->wi_win != NULL)
9961 {
9962 curwin = wip->wi_win;
9963 break;
9964 }
9965 }
9966 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009967
9968 lcount = curbuf->b_ml.ml_line_count;
9969
9970 if (lines->v_type == VAR_LIST)
9971 {
9972 l = lines->vval.v_list;
9973 li = l->lv_first;
9974 }
9975 else
9976 line = get_tv_string_chk(lines);
9977
9978 /* default result is zero == OK */
9979 for (;;)
9980 {
9981 if (l != NULL)
9982 {
9983 /* list argument, get next string */
9984 if (li == NULL)
9985 break;
9986 line = get_tv_string_chk(&li->li_tv);
9987 li = li->li_next;
9988 }
9989
9990 rettv->vval.v_number = 1; /* FAIL */
9991 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
9992 break;
9993
9994 /* When coming here from Insert mode, sync undo, so that this can be
9995 * undone separately from what was previously inserted. */
9996 if (u_sync_once == 2)
9997 {
9998 u_sync_once = 1; /* notify that u_sync() was called */
9999 u_sync(TRUE);
10000 }
10001
10002 if (lnum <= curbuf->b_ml.ml_line_count)
10003 {
10004 /* existing line, replace it */
10005 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10006 {
10007 changed_bytes(lnum, 0);
10008 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10009 check_cursor_col();
10010 rettv->vval.v_number = 0; /* OK */
10011 }
10012 }
10013 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10014 {
10015 /* lnum is one past the last line, append the line */
10016 ++added;
10017 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10018 rettv->vval.v_number = 0; /* OK */
10019 }
10020
10021 if (l == NULL) /* only one string argument */
10022 break;
10023 ++lnum;
10024 }
10025
10026 if (added > 0)
10027 appended_lines_mark(lcount, added);
10028
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010029 if (!is_curbuf)
10030 {
10031 curbuf = curbuf_save;
10032 curwin = curwin_save;
10033 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010034}
10035
10036/*
10037 * "setbufline()" function
10038 */
10039 static void
10040f_setbufline(argvars, rettv)
10041 typval_T *argvars;
10042 typval_T *rettv;
10043{
10044 linenr_T lnum;
10045 buf_T *buf;
10046
10047 buf = get_buf_tv(&argvars[0], FALSE);
10048 if (buf == NULL)
10049 rettv->vval.v_number = 1; /* FAIL */
10050 else
10051 {
10052 lnum = get_tv_lnum_buf(&argvars[1], buf);
10053
10054 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10055 }
10056}
10057
10058/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010059 * "setbufvar()" function
10060 */
10061 static void
10062f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10063{
10064 buf_T *buf;
10065 char_u *varname, *bufvarname;
10066 typval_T *varp;
10067 char_u nbuf[NUMBUFLEN];
10068
10069 if (check_restricted() || check_secure())
10070 return;
10071 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10072 varname = get_tv_string_chk(&argvars[1]);
10073 buf = get_buf_tv(&argvars[0], FALSE);
10074 varp = &argvars[2];
10075
10076 if (buf != NULL && varname != NULL && varp != NULL)
10077 {
10078 if (*varname == '&')
10079 {
10080 long numval;
10081 char_u *strval;
10082 int error = FALSE;
10083 aco_save_T aco;
10084
10085 /* set curbuf to be our buf, temporarily */
10086 aucmd_prepbuf(&aco, buf);
10087
10088 ++varname;
10089 numval = (long)get_tv_number_chk(varp, &error);
10090 strval = get_tv_string_buf_chk(varp, nbuf);
10091 if (!error && strval != NULL)
10092 set_option_value(varname, numval, strval, OPT_LOCAL);
10093
10094 /* reset notion of buffer */
10095 aucmd_restbuf(&aco);
10096 }
10097 else
10098 {
10099 buf_T *save_curbuf = curbuf;
10100
10101 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10102 if (bufvarname != NULL)
10103 {
10104 curbuf = buf;
10105 STRCPY(bufvarname, "b:");
10106 STRCPY(bufvarname + 2, varname);
10107 set_var(bufvarname, varp, TRUE);
10108 vim_free(bufvarname);
10109 curbuf = save_curbuf;
10110 }
10111 }
10112 }
10113}
10114
10115 static void
10116f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10117{
10118 dict_T *d;
10119 dictitem_T *di;
10120 char_u *csearch;
10121
10122 if (argvars[0].v_type != VAR_DICT)
10123 {
10124 EMSG(_(e_dictreq));
10125 return;
10126 }
10127
10128 if ((d = argvars[0].vval.v_dict) != NULL)
10129 {
10130 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10131 if (csearch != NULL)
10132 {
10133#ifdef FEAT_MBYTE
10134 if (enc_utf8)
10135 {
10136 int pcc[MAX_MCO];
10137 int c = utfc_ptr2char(csearch, pcc);
10138
10139 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10140 }
10141 else
10142#endif
10143 set_last_csearch(PTR2CHAR(csearch),
10144 csearch, MB_PTR2LEN(csearch));
10145 }
10146
10147 di = dict_find(d, (char_u *)"forward", -1);
10148 if (di != NULL)
10149 set_csearch_direction((int)get_tv_number(&di->di_tv)
10150 ? FORWARD : BACKWARD);
10151
10152 di = dict_find(d, (char_u *)"until", -1);
10153 if (di != NULL)
10154 set_csearch_until(!!get_tv_number(&di->di_tv));
10155 }
10156}
10157
10158/*
10159 * "setcmdpos()" function
10160 */
10161 static void
10162f_setcmdpos(typval_T *argvars, typval_T *rettv)
10163{
10164 int pos = (int)get_tv_number(&argvars[0]) - 1;
10165
10166 if (pos >= 0)
10167 rettv->vval.v_number = set_cmdline_pos(pos);
10168}
10169
10170/*
10171 * "setfperm({fname}, {mode})" function
10172 */
10173 static void
10174f_setfperm(typval_T *argvars, typval_T *rettv)
10175{
10176 char_u *fname;
10177 char_u modebuf[NUMBUFLEN];
10178 char_u *mode_str;
10179 int i;
10180 int mask;
10181 int mode = 0;
10182
10183 rettv->vval.v_number = 0;
10184 fname = get_tv_string_chk(&argvars[0]);
10185 if (fname == NULL)
10186 return;
10187 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10188 if (mode_str == NULL)
10189 return;
10190 if (STRLEN(mode_str) != 9)
10191 {
10192 EMSG2(_(e_invarg2), mode_str);
10193 return;
10194 }
10195
10196 mask = 1;
10197 for (i = 8; i >= 0; --i)
10198 {
10199 if (mode_str[i] != '-')
10200 mode |= mask;
10201 mask = mask << 1;
10202 }
10203 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10204}
10205
10206/*
10207 * "setline()" function
10208 */
10209 static void
10210f_setline(typval_T *argvars, typval_T *rettv)
10211{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010212 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010213
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010214 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010215}
10216
Bram Moolenaard823fa92016-08-12 16:29:27 +020010217static 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 +020010218
10219/*
10220 * Used by "setqflist()" and "setloclist()" functions
10221 */
10222 static void
10223set_qf_ll_list(
10224 win_T *wp UNUSED,
10225 typval_T *list_arg UNUSED,
10226 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010227 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010228 typval_T *rettv)
10229{
10230#ifdef FEAT_QUICKFIX
10231 static char *e_invact = N_("E927: Invalid action: '%s'");
10232 char_u *act;
10233 int action = 0;
10234#endif
10235
10236 rettv->vval.v_number = -1;
10237
10238#ifdef FEAT_QUICKFIX
10239 if (list_arg->v_type != VAR_LIST)
10240 EMSG(_(e_listreq));
10241 else
10242 {
10243 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010244 dict_T *d = NULL;
10245 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010246
10247 if (action_arg->v_type == VAR_STRING)
10248 {
10249 act = get_tv_string_chk(action_arg);
10250 if (act == NULL)
10251 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010252 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10253 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010254 action = *act;
10255 else
10256 EMSG2(_(e_invact), act);
10257 }
10258 else if (action_arg->v_type == VAR_UNKNOWN)
10259 action = ' ';
10260 else
10261 EMSG(_(e_stringreq));
10262
Bram Moolenaard823fa92016-08-12 16:29:27 +020010263 if (action_arg->v_type != VAR_UNKNOWN
10264 && what_arg->v_type != VAR_UNKNOWN)
10265 {
10266 if (what_arg->v_type == VAR_DICT)
10267 d = what_arg->vval.v_dict;
10268 else
10269 {
10270 EMSG(_(e_dictreq));
10271 valid_dict = FALSE;
10272 }
10273 }
10274
10275 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10276 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010277 rettv->vval.v_number = 0;
10278 }
10279#endif
10280}
10281
10282/*
10283 * "setloclist()" function
10284 */
10285 static void
10286f_setloclist(typval_T *argvars, typval_T *rettv)
10287{
10288 win_T *win;
10289
10290 rettv->vval.v_number = -1;
10291
10292 win = find_win_by_nr(&argvars[0], NULL);
10293 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010294 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010295}
10296
10297/*
10298 * "setmatches()" function
10299 */
10300 static void
10301f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10302{
10303#ifdef FEAT_SEARCH_EXTRA
10304 list_T *l;
10305 listitem_T *li;
10306 dict_T *d;
10307 list_T *s = NULL;
10308
10309 rettv->vval.v_number = -1;
10310 if (argvars[0].v_type != VAR_LIST)
10311 {
10312 EMSG(_(e_listreq));
10313 return;
10314 }
10315 if ((l = argvars[0].vval.v_list) != NULL)
10316 {
10317
10318 /* To some extent make sure that we are dealing with a list from
10319 * "getmatches()". */
10320 li = l->lv_first;
10321 while (li != NULL)
10322 {
10323 if (li->li_tv.v_type != VAR_DICT
10324 || (d = li->li_tv.vval.v_dict) == NULL)
10325 {
10326 EMSG(_(e_invarg));
10327 return;
10328 }
10329 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10330 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10331 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10332 && dict_find(d, (char_u *)"priority", -1) != NULL
10333 && dict_find(d, (char_u *)"id", -1) != NULL))
10334 {
10335 EMSG(_(e_invarg));
10336 return;
10337 }
10338 li = li->li_next;
10339 }
10340
10341 clear_matches(curwin);
10342 li = l->lv_first;
10343 while (li != NULL)
10344 {
10345 int i = 0;
10346 char_u buf[5];
10347 dictitem_T *di;
10348 char_u *group;
10349 int priority;
10350 int id;
10351 char_u *conceal;
10352
10353 d = li->li_tv.vval.v_dict;
10354 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10355 {
10356 if (s == NULL)
10357 {
10358 s = list_alloc();
10359 if (s == NULL)
10360 return;
10361 }
10362
10363 /* match from matchaddpos() */
10364 for (i = 1; i < 9; i++)
10365 {
10366 sprintf((char *)buf, (char *)"pos%d", i);
10367 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10368 {
10369 if (di->di_tv.v_type != VAR_LIST)
10370 return;
10371
10372 list_append_tv(s, &di->di_tv);
10373 s->lv_refcount++;
10374 }
10375 else
10376 break;
10377 }
10378 }
10379
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010380 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010381 priority = (int)get_dict_number(d, (char_u *)"priority");
10382 id = (int)get_dict_number(d, (char_u *)"id");
10383 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010384 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010385 : NULL;
10386 if (i == 0)
10387 {
10388 match_add(curwin, group,
10389 get_dict_string(d, (char_u *)"pattern", FALSE),
10390 priority, id, NULL, conceal);
10391 }
10392 else
10393 {
10394 match_add(curwin, group, NULL, priority, id, s, conceal);
10395 list_unref(s);
10396 s = NULL;
10397 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010398 vim_free(group);
10399 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010400
10401 li = li->li_next;
10402 }
10403 rettv->vval.v_number = 0;
10404 }
10405#endif
10406}
10407
10408/*
10409 * "setpos()" function
10410 */
10411 static void
10412f_setpos(typval_T *argvars, typval_T *rettv)
10413{
10414 pos_T pos;
10415 int fnum;
10416 char_u *name;
10417 colnr_T curswant = -1;
10418
10419 rettv->vval.v_number = -1;
10420 name = get_tv_string_chk(argvars);
10421 if (name != NULL)
10422 {
10423 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10424 {
10425 if (--pos.col < 0)
10426 pos.col = 0;
10427 if (name[0] == '.' && name[1] == NUL)
10428 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010429 /* set cursor; "fnum" is ignored */
10430 curwin->w_cursor = pos;
10431 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010432 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010433 curwin->w_curswant = curswant - 1;
10434 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010435 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010436 check_cursor();
10437 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010438 }
10439 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10440 {
10441 /* set mark */
10442 if (setmark_pos(name[1], &pos, fnum) == OK)
10443 rettv->vval.v_number = 0;
10444 }
10445 else
10446 EMSG(_(e_invarg));
10447 }
10448 }
10449}
10450
10451/*
10452 * "setqflist()" function
10453 */
10454 static void
10455f_setqflist(typval_T *argvars, typval_T *rettv)
10456{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010457 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010458}
10459
10460/*
10461 * "setreg()" function
10462 */
10463 static void
10464f_setreg(typval_T *argvars, typval_T *rettv)
10465{
10466 int regname;
10467 char_u *strregname;
10468 char_u *stropt;
10469 char_u *strval;
10470 int append;
10471 char_u yank_type;
10472 long block_len;
10473
10474 block_len = -1;
10475 yank_type = MAUTO;
10476 append = FALSE;
10477
10478 strregname = get_tv_string_chk(argvars);
10479 rettv->vval.v_number = 1; /* FAIL is default */
10480
10481 if (strregname == NULL)
10482 return; /* type error; errmsg already given */
10483 regname = *strregname;
10484 if (regname == 0 || regname == '@')
10485 regname = '"';
10486
10487 if (argvars[2].v_type != VAR_UNKNOWN)
10488 {
10489 stropt = get_tv_string_chk(&argvars[2]);
10490 if (stropt == NULL)
10491 return; /* type error */
10492 for (; *stropt != NUL; ++stropt)
10493 switch (*stropt)
10494 {
10495 case 'a': case 'A': /* append */
10496 append = TRUE;
10497 break;
10498 case 'v': case 'c': /* character-wise selection */
10499 yank_type = MCHAR;
10500 break;
10501 case 'V': case 'l': /* line-wise selection */
10502 yank_type = MLINE;
10503 break;
10504 case 'b': case Ctrl_V: /* block-wise selection */
10505 yank_type = MBLOCK;
10506 if (VIM_ISDIGIT(stropt[1]))
10507 {
10508 ++stropt;
10509 block_len = getdigits(&stropt) - 1;
10510 --stropt;
10511 }
10512 break;
10513 }
10514 }
10515
10516 if (argvars[1].v_type == VAR_LIST)
10517 {
10518 char_u **lstval;
10519 char_u **allocval;
10520 char_u buf[NUMBUFLEN];
10521 char_u **curval;
10522 char_u **curallocval;
10523 list_T *ll = argvars[1].vval.v_list;
10524 listitem_T *li;
10525 int len;
10526
10527 /* If the list is NULL handle like an empty list. */
10528 len = ll == NULL ? 0 : ll->lv_len;
10529
10530 /* First half: use for pointers to result lines; second half: use for
10531 * pointers to allocated copies. */
10532 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10533 if (lstval == NULL)
10534 return;
10535 curval = lstval;
10536 allocval = lstval + len + 2;
10537 curallocval = allocval;
10538
10539 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10540 li = li->li_next)
10541 {
10542 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10543 if (strval == NULL)
10544 goto free_lstval;
10545 if (strval == buf)
10546 {
10547 /* Need to make a copy, next get_tv_string_buf_chk() will
10548 * overwrite the string. */
10549 strval = vim_strsave(buf);
10550 if (strval == NULL)
10551 goto free_lstval;
10552 *curallocval++ = strval;
10553 }
10554 *curval++ = strval;
10555 }
10556 *curval++ = NULL;
10557
10558 write_reg_contents_lst(regname, lstval, -1,
10559 append, yank_type, block_len);
10560free_lstval:
10561 while (curallocval > allocval)
10562 vim_free(*--curallocval);
10563 vim_free(lstval);
10564 }
10565 else
10566 {
10567 strval = get_tv_string_chk(&argvars[1]);
10568 if (strval == NULL)
10569 return;
10570 write_reg_contents_ex(regname, strval, -1,
10571 append, yank_type, block_len);
10572 }
10573 rettv->vval.v_number = 0;
10574}
10575
10576/*
10577 * "settabvar()" function
10578 */
10579 static void
10580f_settabvar(typval_T *argvars, typval_T *rettv)
10581{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010582 tabpage_T *save_curtab;
10583 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010584 char_u *varname, *tabvarname;
10585 typval_T *varp;
10586
10587 rettv->vval.v_number = 0;
10588
10589 if (check_restricted() || check_secure())
10590 return;
10591
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010592 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010593 varname = get_tv_string_chk(&argvars[1]);
10594 varp = &argvars[2];
10595
Bram Moolenaar4033c552017-09-16 20:54:51 +020010596 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010597 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010598 save_curtab = curtab;
10599 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010600
10601 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10602 if (tabvarname != NULL)
10603 {
10604 STRCPY(tabvarname, "t:");
10605 STRCPY(tabvarname + 2, varname);
10606 set_var(tabvarname, varp, TRUE);
10607 vim_free(tabvarname);
10608 }
10609
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010610 /* Restore current tabpage */
10611 if (valid_tabpage(save_curtab))
10612 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010613 }
10614}
10615
10616/*
10617 * "settabwinvar()" function
10618 */
10619 static void
10620f_settabwinvar(typval_T *argvars, typval_T *rettv)
10621{
10622 setwinvar(argvars, rettv, 1);
10623}
10624
10625/*
10626 * "setwinvar()" function
10627 */
10628 static void
10629f_setwinvar(typval_T *argvars, typval_T *rettv)
10630{
10631 setwinvar(argvars, rettv, 0);
10632}
10633
10634#ifdef FEAT_CRYPT
10635/*
10636 * "sha256({string})" function
10637 */
10638 static void
10639f_sha256(typval_T *argvars, typval_T *rettv)
10640{
10641 char_u *p;
10642
10643 p = get_tv_string(&argvars[0]);
10644 rettv->vval.v_string = vim_strsave(
10645 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10646 rettv->v_type = VAR_STRING;
10647}
10648#endif /* FEAT_CRYPT */
10649
10650/*
10651 * "shellescape({string})" function
10652 */
10653 static void
10654f_shellescape(typval_T *argvars, typval_T *rettv)
10655{
Bram Moolenaar20615522017-06-05 18:46:26 +020010656 int do_special = non_zero_arg(&argvars[1]);
10657
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010658 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010659 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010660 rettv->v_type = VAR_STRING;
10661}
10662
10663/*
10664 * shiftwidth() function
10665 */
10666 static void
10667f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10668{
10669 rettv->vval.v_number = get_sw_value(curbuf);
10670}
10671
10672/*
10673 * "simplify()" function
10674 */
10675 static void
10676f_simplify(typval_T *argvars, typval_T *rettv)
10677{
10678 char_u *p;
10679
10680 p = get_tv_string(&argvars[0]);
10681 rettv->vval.v_string = vim_strsave(p);
10682 simplify_filename(rettv->vval.v_string); /* simplify in place */
10683 rettv->v_type = VAR_STRING;
10684}
10685
10686#ifdef FEAT_FLOAT
10687/*
10688 * "sin()" function
10689 */
10690 static void
10691f_sin(typval_T *argvars, typval_T *rettv)
10692{
10693 float_T f = 0.0;
10694
10695 rettv->v_type = VAR_FLOAT;
10696 if (get_float_arg(argvars, &f) == OK)
10697 rettv->vval.v_float = sin(f);
10698 else
10699 rettv->vval.v_float = 0.0;
10700}
10701
10702/*
10703 * "sinh()" function
10704 */
10705 static void
10706f_sinh(typval_T *argvars, typval_T *rettv)
10707{
10708 float_T f = 0.0;
10709
10710 rettv->v_type = VAR_FLOAT;
10711 if (get_float_arg(argvars, &f) == OK)
10712 rettv->vval.v_float = sinh(f);
10713 else
10714 rettv->vval.v_float = 0.0;
10715}
10716#endif
10717
10718static int
10719#ifdef __BORLANDC__
10720 _RTLENTRYF
10721#endif
10722 item_compare(const void *s1, const void *s2);
10723static int
10724#ifdef __BORLANDC__
10725 _RTLENTRYF
10726#endif
10727 item_compare2(const void *s1, const void *s2);
10728
10729/* struct used in the array that's given to qsort() */
10730typedef struct
10731{
10732 listitem_T *item;
10733 int idx;
10734} sortItem_T;
10735
10736/* struct storing information about current sort */
10737typedef struct
10738{
10739 int item_compare_ic;
10740 int item_compare_numeric;
10741 int item_compare_numbers;
10742#ifdef FEAT_FLOAT
10743 int item_compare_float;
10744#endif
10745 char_u *item_compare_func;
10746 partial_T *item_compare_partial;
10747 dict_T *item_compare_selfdict;
10748 int item_compare_func_err;
10749 int item_compare_keep_zero;
10750} sortinfo_T;
10751static sortinfo_T *sortinfo = NULL;
10752static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10753#define ITEM_COMPARE_FAIL 999
10754
10755/*
10756 * Compare functions for f_sort() and f_uniq() below.
10757 */
10758 static int
10759#ifdef __BORLANDC__
10760_RTLENTRYF
10761#endif
10762item_compare(const void *s1, const void *s2)
10763{
10764 sortItem_T *si1, *si2;
10765 typval_T *tv1, *tv2;
10766 char_u *p1, *p2;
10767 char_u *tofree1 = NULL, *tofree2 = NULL;
10768 int res;
10769 char_u numbuf1[NUMBUFLEN];
10770 char_u numbuf2[NUMBUFLEN];
10771
10772 si1 = (sortItem_T *)s1;
10773 si2 = (sortItem_T *)s2;
10774 tv1 = &si1->item->li_tv;
10775 tv2 = &si2->item->li_tv;
10776
10777 if (sortinfo->item_compare_numbers)
10778 {
10779 varnumber_T v1 = get_tv_number(tv1);
10780 varnumber_T v2 = get_tv_number(tv2);
10781
10782 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10783 }
10784
10785#ifdef FEAT_FLOAT
10786 if (sortinfo->item_compare_float)
10787 {
10788 float_T v1 = get_tv_float(tv1);
10789 float_T v2 = get_tv_float(tv2);
10790
10791 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10792 }
10793#endif
10794
10795 /* tv2string() puts quotes around a string and allocates memory. Don't do
10796 * that for string variables. Use a single quote when comparing with a
10797 * non-string to do what the docs promise. */
10798 if (tv1->v_type == VAR_STRING)
10799 {
10800 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10801 p1 = (char_u *)"'";
10802 else
10803 p1 = tv1->vval.v_string;
10804 }
10805 else
10806 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10807 if (tv2->v_type == VAR_STRING)
10808 {
10809 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10810 p2 = (char_u *)"'";
10811 else
10812 p2 = tv2->vval.v_string;
10813 }
10814 else
10815 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10816 if (p1 == NULL)
10817 p1 = (char_u *)"";
10818 if (p2 == NULL)
10819 p2 = (char_u *)"";
10820 if (!sortinfo->item_compare_numeric)
10821 {
10822 if (sortinfo->item_compare_ic)
10823 res = STRICMP(p1, p2);
10824 else
10825 res = STRCMP(p1, p2);
10826 }
10827 else
10828 {
10829 double n1, n2;
10830 n1 = strtod((char *)p1, (char **)&p1);
10831 n2 = strtod((char *)p2, (char **)&p2);
10832 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10833 }
10834
10835 /* When the result would be zero, compare the item indexes. Makes the
10836 * sort stable. */
10837 if (res == 0 && !sortinfo->item_compare_keep_zero)
10838 res = si1->idx > si2->idx ? 1 : -1;
10839
10840 vim_free(tofree1);
10841 vim_free(tofree2);
10842 return res;
10843}
10844
10845 static int
10846#ifdef __BORLANDC__
10847_RTLENTRYF
10848#endif
10849item_compare2(const void *s1, const void *s2)
10850{
10851 sortItem_T *si1, *si2;
10852 int res;
10853 typval_T rettv;
10854 typval_T argv[3];
10855 int dummy;
10856 char_u *func_name;
10857 partial_T *partial = sortinfo->item_compare_partial;
10858
10859 /* shortcut after failure in previous call; compare all items equal */
10860 if (sortinfo->item_compare_func_err)
10861 return 0;
10862
10863 si1 = (sortItem_T *)s1;
10864 si2 = (sortItem_T *)s2;
10865
10866 if (partial == NULL)
10867 func_name = sortinfo->item_compare_func;
10868 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010869 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010870
10871 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10872 * in the copy without changing the original list items. */
10873 copy_tv(&si1->item->li_tv, &argv[0]);
10874 copy_tv(&si2->item->li_tv, &argv[1]);
10875
10876 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10877 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010878 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010879 partial, sortinfo->item_compare_selfdict);
10880 clear_tv(&argv[0]);
10881 clear_tv(&argv[1]);
10882
10883 if (res == FAIL)
10884 res = ITEM_COMPARE_FAIL;
10885 else
10886 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10887 if (sortinfo->item_compare_func_err)
10888 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10889 clear_tv(&rettv);
10890
10891 /* When the result would be zero, compare the pointers themselves. Makes
10892 * the sort stable. */
10893 if (res == 0 && !sortinfo->item_compare_keep_zero)
10894 res = si1->idx > si2->idx ? 1 : -1;
10895
10896 return res;
10897}
10898
10899/*
10900 * "sort({list})" function
10901 */
10902 static void
10903do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10904{
10905 list_T *l;
10906 listitem_T *li;
10907 sortItem_T *ptrs;
10908 sortinfo_T *old_sortinfo;
10909 sortinfo_T info;
10910 long len;
10911 long i;
10912
10913 /* Pointer to current info struct used in compare function. Save and
10914 * restore the current one for nested calls. */
10915 old_sortinfo = sortinfo;
10916 sortinfo = &info;
10917
10918 if (argvars[0].v_type != VAR_LIST)
10919 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10920 else
10921 {
10922 l = argvars[0].vval.v_list;
10923 if (l == NULL || tv_check_lock(l->lv_lock,
10924 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10925 TRUE))
10926 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010927 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010928
10929 len = list_len(l);
10930 if (len <= 1)
10931 goto theend; /* short list sorts pretty quickly */
10932
10933 info.item_compare_ic = FALSE;
10934 info.item_compare_numeric = FALSE;
10935 info.item_compare_numbers = FALSE;
10936#ifdef FEAT_FLOAT
10937 info.item_compare_float = FALSE;
10938#endif
10939 info.item_compare_func = NULL;
10940 info.item_compare_partial = NULL;
10941 info.item_compare_selfdict = NULL;
10942 if (argvars[1].v_type != VAR_UNKNOWN)
10943 {
10944 /* optional second argument: {func} */
10945 if (argvars[1].v_type == VAR_FUNC)
10946 info.item_compare_func = argvars[1].vval.v_string;
10947 else if (argvars[1].v_type == VAR_PARTIAL)
10948 info.item_compare_partial = argvars[1].vval.v_partial;
10949 else
10950 {
10951 int error = FALSE;
10952
10953 i = (long)get_tv_number_chk(&argvars[1], &error);
10954 if (error)
10955 goto theend; /* type error; errmsg already given */
10956 if (i == 1)
10957 info.item_compare_ic = TRUE;
10958 else if (argvars[1].v_type != VAR_NUMBER)
10959 info.item_compare_func = get_tv_string(&argvars[1]);
10960 else if (i != 0)
10961 {
10962 EMSG(_(e_invarg));
10963 goto theend;
10964 }
10965 if (info.item_compare_func != NULL)
10966 {
10967 if (*info.item_compare_func == NUL)
10968 {
10969 /* empty string means default sort */
10970 info.item_compare_func = NULL;
10971 }
10972 else if (STRCMP(info.item_compare_func, "n") == 0)
10973 {
10974 info.item_compare_func = NULL;
10975 info.item_compare_numeric = TRUE;
10976 }
10977 else if (STRCMP(info.item_compare_func, "N") == 0)
10978 {
10979 info.item_compare_func = NULL;
10980 info.item_compare_numbers = TRUE;
10981 }
10982#ifdef FEAT_FLOAT
10983 else if (STRCMP(info.item_compare_func, "f") == 0)
10984 {
10985 info.item_compare_func = NULL;
10986 info.item_compare_float = TRUE;
10987 }
10988#endif
10989 else if (STRCMP(info.item_compare_func, "i") == 0)
10990 {
10991 info.item_compare_func = NULL;
10992 info.item_compare_ic = TRUE;
10993 }
10994 }
10995 }
10996
10997 if (argvars[2].v_type != VAR_UNKNOWN)
10998 {
10999 /* optional third argument: {dict} */
11000 if (argvars[2].v_type != VAR_DICT)
11001 {
11002 EMSG(_(e_dictreq));
11003 goto theend;
11004 }
11005 info.item_compare_selfdict = argvars[2].vval.v_dict;
11006 }
11007 }
11008
11009 /* Make an array with each entry pointing to an item in the List. */
11010 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11011 if (ptrs == NULL)
11012 goto theend;
11013
11014 i = 0;
11015 if (sort)
11016 {
11017 /* sort(): ptrs will be the list to sort */
11018 for (li = l->lv_first; li != NULL; li = li->li_next)
11019 {
11020 ptrs[i].item = li;
11021 ptrs[i].idx = i;
11022 ++i;
11023 }
11024
11025 info.item_compare_func_err = FALSE;
11026 info.item_compare_keep_zero = FALSE;
11027 /* test the compare function */
11028 if ((info.item_compare_func != NULL
11029 || info.item_compare_partial != NULL)
11030 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11031 == ITEM_COMPARE_FAIL)
11032 EMSG(_("E702: Sort compare function failed"));
11033 else
11034 {
11035 /* Sort the array with item pointers. */
11036 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11037 info.item_compare_func == NULL
11038 && info.item_compare_partial == NULL
11039 ? item_compare : item_compare2);
11040
11041 if (!info.item_compare_func_err)
11042 {
11043 /* Clear the List and append the items in sorted order. */
11044 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11045 l->lv_len = 0;
11046 for (i = 0; i < len; ++i)
11047 list_append(l, ptrs[i].item);
11048 }
11049 }
11050 }
11051 else
11052 {
11053 int (*item_compare_func_ptr)(const void *, const void *);
11054
11055 /* f_uniq(): ptrs will be a stack of items to remove */
11056 info.item_compare_func_err = FALSE;
11057 info.item_compare_keep_zero = TRUE;
11058 item_compare_func_ptr = info.item_compare_func != NULL
11059 || info.item_compare_partial != NULL
11060 ? item_compare2 : item_compare;
11061
11062 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11063 li = li->li_next)
11064 {
11065 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11066 == 0)
11067 ptrs[i++].item = li;
11068 if (info.item_compare_func_err)
11069 {
11070 EMSG(_("E882: Uniq compare function failed"));
11071 break;
11072 }
11073 }
11074
11075 if (!info.item_compare_func_err)
11076 {
11077 while (--i >= 0)
11078 {
11079 li = ptrs[i].item->li_next;
11080 ptrs[i].item->li_next = li->li_next;
11081 if (li->li_next != NULL)
11082 li->li_next->li_prev = ptrs[i].item;
11083 else
11084 l->lv_last = ptrs[i].item;
11085 list_fix_watch(l, li);
11086 listitem_free(li);
11087 l->lv_len--;
11088 }
11089 }
11090 }
11091
11092 vim_free(ptrs);
11093 }
11094theend:
11095 sortinfo = old_sortinfo;
11096}
11097
11098/*
11099 * "sort({list})" function
11100 */
11101 static void
11102f_sort(typval_T *argvars, typval_T *rettv)
11103{
11104 do_sort_uniq(argvars, rettv, TRUE);
11105}
11106
11107/*
11108 * "uniq({list})" function
11109 */
11110 static void
11111f_uniq(typval_T *argvars, typval_T *rettv)
11112{
11113 do_sort_uniq(argvars, rettv, FALSE);
11114}
11115
11116/*
11117 * "soundfold({word})" function
11118 */
11119 static void
11120f_soundfold(typval_T *argvars, typval_T *rettv)
11121{
11122 char_u *s;
11123
11124 rettv->v_type = VAR_STRING;
11125 s = get_tv_string(&argvars[0]);
11126#ifdef FEAT_SPELL
11127 rettv->vval.v_string = eval_soundfold(s);
11128#else
11129 rettv->vval.v_string = vim_strsave(s);
11130#endif
11131}
11132
11133/*
11134 * "spellbadword()" function
11135 */
11136 static void
11137f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11138{
11139 char_u *word = (char_u *)"";
11140 hlf_T attr = HLF_COUNT;
11141 int len = 0;
11142
11143 if (rettv_list_alloc(rettv) == FAIL)
11144 return;
11145
11146#ifdef FEAT_SPELL
11147 if (argvars[0].v_type == VAR_UNKNOWN)
11148 {
11149 /* Find the start and length of the badly spelled word. */
11150 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11151 if (len != 0)
11152 word = ml_get_cursor();
11153 }
11154 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11155 {
11156 char_u *str = get_tv_string_chk(&argvars[0]);
11157 int capcol = -1;
11158
11159 if (str != NULL)
11160 {
11161 /* Check the argument for spelling. */
11162 while (*str != NUL)
11163 {
11164 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11165 if (attr != HLF_COUNT)
11166 {
11167 word = str;
11168 break;
11169 }
11170 str += len;
11171 }
11172 }
11173 }
11174#endif
11175
11176 list_append_string(rettv->vval.v_list, word, len);
11177 list_append_string(rettv->vval.v_list, (char_u *)(
11178 attr == HLF_SPB ? "bad" :
11179 attr == HLF_SPR ? "rare" :
11180 attr == HLF_SPL ? "local" :
11181 attr == HLF_SPC ? "caps" :
11182 ""), -1);
11183}
11184
11185/*
11186 * "spellsuggest()" function
11187 */
11188 static void
11189f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11190{
11191#ifdef FEAT_SPELL
11192 char_u *str;
11193 int typeerr = FALSE;
11194 int maxcount;
11195 garray_T ga;
11196 int i;
11197 listitem_T *li;
11198 int need_capital = FALSE;
11199#endif
11200
11201 if (rettv_list_alloc(rettv) == FAIL)
11202 return;
11203
11204#ifdef FEAT_SPELL
11205 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11206 {
11207 str = get_tv_string(&argvars[0]);
11208 if (argvars[1].v_type != VAR_UNKNOWN)
11209 {
11210 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11211 if (maxcount <= 0)
11212 return;
11213 if (argvars[2].v_type != VAR_UNKNOWN)
11214 {
11215 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11216 if (typeerr)
11217 return;
11218 }
11219 }
11220 else
11221 maxcount = 25;
11222
11223 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11224
11225 for (i = 0; i < ga.ga_len; ++i)
11226 {
11227 str = ((char_u **)ga.ga_data)[i];
11228
11229 li = listitem_alloc();
11230 if (li == NULL)
11231 vim_free(str);
11232 else
11233 {
11234 li->li_tv.v_type = VAR_STRING;
11235 li->li_tv.v_lock = 0;
11236 li->li_tv.vval.v_string = str;
11237 list_append(rettv->vval.v_list, li);
11238 }
11239 }
11240 ga_clear(&ga);
11241 }
11242#endif
11243}
11244
11245 static void
11246f_split(typval_T *argvars, typval_T *rettv)
11247{
11248 char_u *str;
11249 char_u *end;
11250 char_u *pat = NULL;
11251 regmatch_T regmatch;
11252 char_u patbuf[NUMBUFLEN];
11253 char_u *save_cpo;
11254 int match;
11255 colnr_T col = 0;
11256 int keepempty = FALSE;
11257 int typeerr = FALSE;
11258
11259 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11260 save_cpo = p_cpo;
11261 p_cpo = (char_u *)"";
11262
11263 str = get_tv_string(&argvars[0]);
11264 if (argvars[1].v_type != VAR_UNKNOWN)
11265 {
11266 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11267 if (pat == NULL)
11268 typeerr = TRUE;
11269 if (argvars[2].v_type != VAR_UNKNOWN)
11270 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11271 }
11272 if (pat == NULL || *pat == NUL)
11273 pat = (char_u *)"[\\x01- ]\\+";
11274
11275 if (rettv_list_alloc(rettv) == FAIL)
11276 return;
11277 if (typeerr)
11278 return;
11279
11280 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11281 if (regmatch.regprog != NULL)
11282 {
11283 regmatch.rm_ic = FALSE;
11284 while (*str != NUL || keepempty)
11285 {
11286 if (*str == NUL)
11287 match = FALSE; /* empty item at the end */
11288 else
11289 match = vim_regexec_nl(&regmatch, str, col);
11290 if (match)
11291 end = regmatch.startp[0];
11292 else
11293 end = str + STRLEN(str);
11294 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11295 && *str != NUL && match && end < regmatch.endp[0]))
11296 {
11297 if (list_append_string(rettv->vval.v_list, str,
11298 (int)(end - str)) == FAIL)
11299 break;
11300 }
11301 if (!match)
11302 break;
11303 /* Advance to just after the match. */
11304 if (regmatch.endp[0] > str)
11305 col = 0;
11306 else
11307 {
11308 /* Don't get stuck at the same match. */
11309#ifdef FEAT_MBYTE
11310 col = (*mb_ptr2len)(regmatch.endp[0]);
11311#else
11312 col = 1;
11313#endif
11314 }
11315 str = regmatch.endp[0];
11316 }
11317
11318 vim_regfree(regmatch.regprog);
11319 }
11320
11321 p_cpo = save_cpo;
11322}
11323
11324#ifdef FEAT_FLOAT
11325/*
11326 * "sqrt()" function
11327 */
11328 static void
11329f_sqrt(typval_T *argvars, typval_T *rettv)
11330{
11331 float_T f = 0.0;
11332
11333 rettv->v_type = VAR_FLOAT;
11334 if (get_float_arg(argvars, &f) == OK)
11335 rettv->vval.v_float = sqrt(f);
11336 else
11337 rettv->vval.v_float = 0.0;
11338}
11339
11340/*
11341 * "str2float()" function
11342 */
11343 static void
11344f_str2float(typval_T *argvars, typval_T *rettv)
11345{
11346 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011347 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011348
Bram Moolenaar08243d22017-01-10 16:12:29 +010011349 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011350 p = skipwhite(p + 1);
11351 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011352 if (isneg)
11353 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011354 rettv->v_type = VAR_FLOAT;
11355}
11356#endif
11357
11358/*
11359 * "str2nr()" function
11360 */
11361 static void
11362f_str2nr(typval_T *argvars, typval_T *rettv)
11363{
11364 int base = 10;
11365 char_u *p;
11366 varnumber_T n;
11367 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011368 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011369
11370 if (argvars[1].v_type != VAR_UNKNOWN)
11371 {
11372 base = (int)get_tv_number(&argvars[1]);
11373 if (base != 2 && base != 8 && base != 10 && base != 16)
11374 {
11375 EMSG(_(e_invarg));
11376 return;
11377 }
11378 }
11379
11380 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011381 isneg = (*p == '-');
11382 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011383 p = skipwhite(p + 1);
11384 switch (base)
11385 {
11386 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11387 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11388 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11389 default: what = 0;
11390 }
11391 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011392 if (isneg)
11393 rettv->vval.v_number = -n;
11394 else
11395 rettv->vval.v_number = n;
11396
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011397}
11398
11399#ifdef HAVE_STRFTIME
11400/*
11401 * "strftime({format}[, {time}])" function
11402 */
11403 static void
11404f_strftime(typval_T *argvars, typval_T *rettv)
11405{
11406 char_u result_buf[256];
11407 struct tm *curtime;
11408 time_t seconds;
11409 char_u *p;
11410
11411 rettv->v_type = VAR_STRING;
11412
11413 p = get_tv_string(&argvars[0]);
11414 if (argvars[1].v_type == VAR_UNKNOWN)
11415 seconds = time(NULL);
11416 else
11417 seconds = (time_t)get_tv_number(&argvars[1]);
11418 curtime = localtime(&seconds);
11419 /* MSVC returns NULL for an invalid value of seconds. */
11420 if (curtime == NULL)
11421 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11422 else
11423 {
11424# ifdef FEAT_MBYTE
11425 vimconv_T conv;
11426 char_u *enc;
11427
11428 conv.vc_type = CONV_NONE;
11429 enc = enc_locale();
11430 convert_setup(&conv, p_enc, enc);
11431 if (conv.vc_type != CONV_NONE)
11432 p = string_convert(&conv, p, NULL);
11433# endif
11434 if (p != NULL)
11435 (void)strftime((char *)result_buf, sizeof(result_buf),
11436 (char *)p, curtime);
11437 else
11438 result_buf[0] = NUL;
11439
11440# ifdef FEAT_MBYTE
11441 if (conv.vc_type != CONV_NONE)
11442 vim_free(p);
11443 convert_setup(&conv, enc, p_enc);
11444 if (conv.vc_type != CONV_NONE)
11445 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11446 else
11447# endif
11448 rettv->vval.v_string = vim_strsave(result_buf);
11449
11450# ifdef FEAT_MBYTE
11451 /* Release conversion descriptors */
11452 convert_setup(&conv, NULL, NULL);
11453 vim_free(enc);
11454# endif
11455 }
11456}
11457#endif
11458
11459/*
11460 * "strgetchar()" function
11461 */
11462 static void
11463f_strgetchar(typval_T *argvars, typval_T *rettv)
11464{
11465 char_u *str;
11466 int len;
11467 int error = FALSE;
11468 int charidx;
11469
11470 rettv->vval.v_number = -1;
11471 str = get_tv_string_chk(&argvars[0]);
11472 if (str == NULL)
11473 return;
11474 len = (int)STRLEN(str);
11475 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11476 if (error)
11477 return;
11478#ifdef FEAT_MBYTE
11479 {
11480 int byteidx = 0;
11481
11482 while (charidx >= 0 && byteidx < len)
11483 {
11484 if (charidx == 0)
11485 {
11486 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11487 break;
11488 }
11489 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011490 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011491 }
11492 }
11493#else
11494 if (charidx < len)
11495 rettv->vval.v_number = str[charidx];
11496#endif
11497}
11498
11499/*
11500 * "stridx()" function
11501 */
11502 static void
11503f_stridx(typval_T *argvars, typval_T *rettv)
11504{
11505 char_u buf[NUMBUFLEN];
11506 char_u *needle;
11507 char_u *haystack;
11508 char_u *save_haystack;
11509 char_u *pos;
11510 int start_idx;
11511
11512 needle = get_tv_string_chk(&argvars[1]);
11513 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11514 rettv->vval.v_number = -1;
11515 if (needle == NULL || haystack == NULL)
11516 return; /* type error; errmsg already given */
11517
11518 if (argvars[2].v_type != VAR_UNKNOWN)
11519 {
11520 int error = FALSE;
11521
11522 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11523 if (error || start_idx >= (int)STRLEN(haystack))
11524 return;
11525 if (start_idx >= 0)
11526 haystack += start_idx;
11527 }
11528
11529 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11530 if (pos != NULL)
11531 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11532}
11533
11534/*
11535 * "string()" function
11536 */
11537 static void
11538f_string(typval_T *argvars, typval_T *rettv)
11539{
11540 char_u *tofree;
11541 char_u numbuf[NUMBUFLEN];
11542
11543 rettv->v_type = VAR_STRING;
11544 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11545 get_copyID());
11546 /* Make a copy if we have a value but it's not in allocated memory. */
11547 if (rettv->vval.v_string != NULL && tofree == NULL)
11548 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11549}
11550
11551/*
11552 * "strlen()" function
11553 */
11554 static void
11555f_strlen(typval_T *argvars, typval_T *rettv)
11556{
11557 rettv->vval.v_number = (varnumber_T)(STRLEN(
11558 get_tv_string(&argvars[0])));
11559}
11560
11561/*
11562 * "strchars()" function
11563 */
11564 static void
11565f_strchars(typval_T *argvars, typval_T *rettv)
11566{
11567 char_u *s = get_tv_string(&argvars[0]);
11568 int skipcc = 0;
11569#ifdef FEAT_MBYTE
11570 varnumber_T len = 0;
11571 int (*func_mb_ptr2char_adv)(char_u **pp);
11572#endif
11573
11574 if (argvars[1].v_type != VAR_UNKNOWN)
11575 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11576 if (skipcc < 0 || skipcc > 1)
11577 EMSG(_(e_invarg));
11578 else
11579 {
11580#ifdef FEAT_MBYTE
11581 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11582 while (*s != NUL)
11583 {
11584 func_mb_ptr2char_adv(&s);
11585 ++len;
11586 }
11587 rettv->vval.v_number = len;
11588#else
11589 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11590#endif
11591 }
11592}
11593
11594/*
11595 * "strdisplaywidth()" function
11596 */
11597 static void
11598f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11599{
11600 char_u *s = get_tv_string(&argvars[0]);
11601 int col = 0;
11602
11603 if (argvars[1].v_type != VAR_UNKNOWN)
11604 col = (int)get_tv_number(&argvars[1]);
11605
11606 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11607}
11608
11609/*
11610 * "strwidth()" function
11611 */
11612 static void
11613f_strwidth(typval_T *argvars, typval_T *rettv)
11614{
11615 char_u *s = get_tv_string(&argvars[0]);
11616
11617 rettv->vval.v_number = (varnumber_T)(
11618#ifdef FEAT_MBYTE
11619 mb_string2cells(s, -1)
11620#else
11621 STRLEN(s)
11622#endif
11623 );
11624}
11625
11626/*
11627 * "strcharpart()" function
11628 */
11629 static void
11630f_strcharpart(typval_T *argvars, typval_T *rettv)
11631{
11632#ifdef FEAT_MBYTE
11633 char_u *p;
11634 int nchar;
11635 int nbyte = 0;
11636 int charlen;
11637 int len = 0;
11638 int slen;
11639 int error = FALSE;
11640
11641 p = get_tv_string(&argvars[0]);
11642 slen = (int)STRLEN(p);
11643
11644 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11645 if (!error)
11646 {
11647 if (nchar > 0)
11648 while (nchar > 0 && nbyte < slen)
11649 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011650 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011651 --nchar;
11652 }
11653 else
11654 nbyte = nchar;
11655 if (argvars[2].v_type != VAR_UNKNOWN)
11656 {
11657 charlen = (int)get_tv_number(&argvars[2]);
11658 while (charlen > 0 && nbyte + len < slen)
11659 {
11660 int off = nbyte + len;
11661
11662 if (off < 0)
11663 len += 1;
11664 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011665 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011666 --charlen;
11667 }
11668 }
11669 else
11670 len = slen - nbyte; /* default: all bytes that are available. */
11671 }
11672
11673 /*
11674 * Only return the overlap between the specified part and the actual
11675 * string.
11676 */
11677 if (nbyte < 0)
11678 {
11679 len += nbyte;
11680 nbyte = 0;
11681 }
11682 else if (nbyte > slen)
11683 nbyte = slen;
11684 if (len < 0)
11685 len = 0;
11686 else if (nbyte + len > slen)
11687 len = slen - nbyte;
11688
11689 rettv->v_type = VAR_STRING;
11690 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11691#else
11692 f_strpart(argvars, rettv);
11693#endif
11694}
11695
11696/*
11697 * "strpart()" function
11698 */
11699 static void
11700f_strpart(typval_T *argvars, typval_T *rettv)
11701{
11702 char_u *p;
11703 int n;
11704 int len;
11705 int slen;
11706 int error = FALSE;
11707
11708 p = get_tv_string(&argvars[0]);
11709 slen = (int)STRLEN(p);
11710
11711 n = (int)get_tv_number_chk(&argvars[1], &error);
11712 if (error)
11713 len = 0;
11714 else if (argvars[2].v_type != VAR_UNKNOWN)
11715 len = (int)get_tv_number(&argvars[2]);
11716 else
11717 len = slen - n; /* default len: all bytes that are available. */
11718
11719 /*
11720 * Only return the overlap between the specified part and the actual
11721 * string.
11722 */
11723 if (n < 0)
11724 {
11725 len += n;
11726 n = 0;
11727 }
11728 else if (n > slen)
11729 n = slen;
11730 if (len < 0)
11731 len = 0;
11732 else if (n + len > slen)
11733 len = slen - n;
11734
11735 rettv->v_type = VAR_STRING;
11736 rettv->vval.v_string = vim_strnsave(p + n, len);
11737}
11738
11739/*
11740 * "strridx()" function
11741 */
11742 static void
11743f_strridx(typval_T *argvars, typval_T *rettv)
11744{
11745 char_u buf[NUMBUFLEN];
11746 char_u *needle;
11747 char_u *haystack;
11748 char_u *rest;
11749 char_u *lastmatch = NULL;
11750 int haystack_len, end_idx;
11751
11752 needle = get_tv_string_chk(&argvars[1]);
11753 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11754
11755 rettv->vval.v_number = -1;
11756 if (needle == NULL || haystack == NULL)
11757 return; /* type error; errmsg already given */
11758
11759 haystack_len = (int)STRLEN(haystack);
11760 if (argvars[2].v_type != VAR_UNKNOWN)
11761 {
11762 /* Third argument: upper limit for index */
11763 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11764 if (end_idx < 0)
11765 return; /* can never find a match */
11766 }
11767 else
11768 end_idx = haystack_len;
11769
11770 if (*needle == NUL)
11771 {
11772 /* Empty string matches past the end. */
11773 lastmatch = haystack + end_idx;
11774 }
11775 else
11776 {
11777 for (rest = haystack; *rest != '\0'; ++rest)
11778 {
11779 rest = (char_u *)strstr((char *)rest, (char *)needle);
11780 if (rest == NULL || rest > haystack + end_idx)
11781 break;
11782 lastmatch = rest;
11783 }
11784 }
11785
11786 if (lastmatch == NULL)
11787 rettv->vval.v_number = -1;
11788 else
11789 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11790}
11791
11792/*
11793 * "strtrans()" function
11794 */
11795 static void
11796f_strtrans(typval_T *argvars, typval_T *rettv)
11797{
11798 rettv->v_type = VAR_STRING;
11799 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11800}
11801
11802/*
11803 * "submatch()" function
11804 */
11805 static void
11806f_submatch(typval_T *argvars, typval_T *rettv)
11807{
11808 int error = FALSE;
11809 int no;
11810 int retList = 0;
11811
11812 no = (int)get_tv_number_chk(&argvars[0], &error);
11813 if (error)
11814 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011815 if (no < 0 || no >= NSUBEXP)
11816 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010011817 EMSGN(_("E935: invalid submatch number: %d"), no);
11818 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011819 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011820 if (argvars[1].v_type != VAR_UNKNOWN)
11821 retList = (int)get_tv_number_chk(&argvars[1], &error);
11822 if (error)
11823 return;
11824
11825 if (retList == 0)
11826 {
11827 rettv->v_type = VAR_STRING;
11828 rettv->vval.v_string = reg_submatch(no);
11829 }
11830 else
11831 {
11832 rettv->v_type = VAR_LIST;
11833 rettv->vval.v_list = reg_submatch_list(no);
11834 }
11835}
11836
11837/*
11838 * "substitute()" function
11839 */
11840 static void
11841f_substitute(typval_T *argvars, typval_T *rettv)
11842{
11843 char_u patbuf[NUMBUFLEN];
11844 char_u subbuf[NUMBUFLEN];
11845 char_u flagsbuf[NUMBUFLEN];
11846
11847 char_u *str = get_tv_string_chk(&argvars[0]);
11848 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011849 char_u *sub = NULL;
11850 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011851 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11852
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011853 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11854 expr = &argvars[2];
11855 else
11856 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11857
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011858 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011859 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11860 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011861 rettv->vval.v_string = NULL;
11862 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011863 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011864}
11865
11866/*
11867 * "synID(lnum, col, trans)" function
11868 */
11869 static void
11870f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11871{
11872 int id = 0;
11873#ifdef FEAT_SYN_HL
11874 linenr_T lnum;
11875 colnr_T col;
11876 int trans;
11877 int transerr = FALSE;
11878
11879 lnum = get_tv_lnum(argvars); /* -1 on type error */
11880 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11881 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11882
11883 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11884 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11885 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11886#endif
11887
11888 rettv->vval.v_number = id;
11889}
11890
11891/*
11892 * "synIDattr(id, what [, mode])" function
11893 */
11894 static void
11895f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11896{
11897 char_u *p = NULL;
11898#ifdef FEAT_SYN_HL
11899 int id;
11900 char_u *what;
11901 char_u *mode;
11902 char_u modebuf[NUMBUFLEN];
11903 int modec;
11904
11905 id = (int)get_tv_number(&argvars[0]);
11906 what = get_tv_string(&argvars[1]);
11907 if (argvars[2].v_type != VAR_UNKNOWN)
11908 {
11909 mode = get_tv_string_buf(&argvars[2], modebuf);
11910 modec = TOLOWER_ASC(mode[0]);
11911 if (modec != 't' && modec != 'c' && modec != 'g')
11912 modec = 0; /* replace invalid with current */
11913 }
11914 else
11915 {
11916#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11917 if (USE_24BIT)
11918 modec = 'g';
11919 else
11920#endif
11921 if (t_colors > 1)
11922 modec = 'c';
11923 else
11924 modec = 't';
11925 }
11926
11927
11928 switch (TOLOWER_ASC(what[0]))
11929 {
11930 case 'b':
11931 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11932 p = highlight_color(id, what, modec);
11933 else /* bold */
11934 p = highlight_has_attr(id, HL_BOLD, modec);
11935 break;
11936
11937 case 'f': /* fg[#] or font */
11938 p = highlight_color(id, what, modec);
11939 break;
11940
11941 case 'i':
11942 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11943 p = highlight_has_attr(id, HL_INVERSE, modec);
11944 else /* italic */
11945 p = highlight_has_attr(id, HL_ITALIC, modec);
11946 break;
11947
11948 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011949 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011950 break;
11951
11952 case 'r': /* reverse */
11953 p = highlight_has_attr(id, HL_INVERSE, modec);
11954 break;
11955
11956 case 's':
11957 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11958 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011959 /* strikeout */
11960 else if (TOLOWER_ASC(what[1]) == 't' &&
11961 TOLOWER_ASC(what[2]) == 'r')
11962 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011963 else /* standout */
11964 p = highlight_has_attr(id, HL_STANDOUT, modec);
11965 break;
11966
11967 case 'u':
11968 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11969 /* underline */
11970 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11971 else
11972 /* undercurl */
11973 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11974 break;
11975 }
11976
11977 if (p != NULL)
11978 p = vim_strsave(p);
11979#endif
11980 rettv->v_type = VAR_STRING;
11981 rettv->vval.v_string = p;
11982}
11983
11984/*
11985 * "synIDtrans(id)" function
11986 */
11987 static void
11988f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11989{
11990 int id;
11991
11992#ifdef FEAT_SYN_HL
11993 id = (int)get_tv_number(&argvars[0]);
11994
11995 if (id > 0)
11996 id = syn_get_final_id(id);
11997 else
11998#endif
11999 id = 0;
12000
12001 rettv->vval.v_number = id;
12002}
12003
12004/*
12005 * "synconcealed(lnum, col)" function
12006 */
12007 static void
12008f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12009{
12010#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12011 linenr_T lnum;
12012 colnr_T col;
12013 int syntax_flags = 0;
12014 int cchar;
12015 int matchid = 0;
12016 char_u str[NUMBUFLEN];
12017#endif
12018
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012019 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012020
12021#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12022 lnum = get_tv_lnum(argvars); /* -1 on type error */
12023 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12024
12025 vim_memset(str, NUL, sizeof(str));
12026
12027 if (rettv_list_alloc(rettv) != FAIL)
12028 {
12029 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12030 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12031 && curwin->w_p_cole > 0)
12032 {
12033 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12034 syntax_flags = get_syntax_info(&matchid);
12035
12036 /* get the conceal character */
12037 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12038 {
12039 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012040 if (cchar == NUL && curwin->w_p_cole == 1)
12041 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012042 if (cchar != NUL)
12043 {
12044# ifdef FEAT_MBYTE
12045 if (has_mbyte)
12046 (*mb_char2bytes)(cchar, str);
12047 else
12048# endif
12049 str[0] = cchar;
12050 }
12051 }
12052 }
12053
12054 list_append_number(rettv->vval.v_list,
12055 (syntax_flags & HL_CONCEAL) != 0);
12056 /* -1 to auto-determine strlen */
12057 list_append_string(rettv->vval.v_list, str, -1);
12058 list_append_number(rettv->vval.v_list, matchid);
12059 }
12060#endif
12061}
12062
12063/*
12064 * "synstack(lnum, col)" function
12065 */
12066 static void
12067f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12068{
12069#ifdef FEAT_SYN_HL
12070 linenr_T lnum;
12071 colnr_T col;
12072 int i;
12073 int id;
12074#endif
12075
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012076 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012077
12078#ifdef FEAT_SYN_HL
12079 lnum = get_tv_lnum(argvars); /* -1 on type error */
12080 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12081
12082 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12083 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12084 && rettv_list_alloc(rettv) != FAIL)
12085 {
12086 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12087 for (i = 0; ; ++i)
12088 {
12089 id = syn_get_stack_item(i);
12090 if (id < 0)
12091 break;
12092 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12093 break;
12094 }
12095 }
12096#endif
12097}
12098
12099 static void
12100get_cmd_output_as_rettv(
12101 typval_T *argvars,
12102 typval_T *rettv,
12103 int retlist)
12104{
12105 char_u *res = NULL;
12106 char_u *p;
12107 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012108 int err = FALSE;
12109 FILE *fd;
12110 list_T *list = NULL;
12111 int flags = SHELL_SILENT;
12112
12113 rettv->v_type = VAR_STRING;
12114 rettv->vval.v_string = NULL;
12115 if (check_restricted() || check_secure())
12116 goto errret;
12117
12118 if (argvars[1].v_type != VAR_UNKNOWN)
12119 {
12120 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012121 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012122 * command.
12123 */
12124 if ((infile = vim_tempname('i', TRUE)) == NULL)
12125 {
12126 EMSG(_(e_notmp));
12127 goto errret;
12128 }
12129
12130 fd = mch_fopen((char *)infile, WRITEBIN);
12131 if (fd == NULL)
12132 {
12133 EMSG2(_(e_notopen), infile);
12134 goto errret;
12135 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012136 if (argvars[1].v_type == VAR_NUMBER)
12137 {
12138 linenr_T lnum;
12139 buf_T *buf;
12140
12141 buf = buflist_findnr(argvars[1].vval.v_number);
12142 if (buf == NULL)
12143 {
12144 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012145 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012146 goto errret;
12147 }
12148
12149 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12150 {
12151 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12152 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12153 {
12154 err = TRUE;
12155 break;
12156 }
12157 if (putc(NL, fd) == EOF)
12158 {
12159 err = TRUE;
12160 break;
12161 }
12162 }
12163 }
12164 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012165 {
12166 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12167 err = TRUE;
12168 }
12169 else
12170 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012171 size_t len;
12172 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012173
12174 p = get_tv_string_buf_chk(&argvars[1], buf);
12175 if (p == NULL)
12176 {
12177 fclose(fd);
12178 goto errret; /* type error; errmsg already given */
12179 }
12180 len = STRLEN(p);
12181 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12182 err = TRUE;
12183 }
12184 if (fclose(fd) != 0)
12185 err = TRUE;
12186 if (err)
12187 {
12188 EMSG(_("E677: Error writing temp file"));
12189 goto errret;
12190 }
12191 }
12192
12193 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12194 * echoes typeahead, that messes up the display. */
12195 if (!msg_silent)
12196 flags += SHELL_COOKED;
12197
12198 if (retlist)
12199 {
12200 int len;
12201 listitem_T *li;
12202 char_u *s = NULL;
12203 char_u *start;
12204 char_u *end;
12205 int i;
12206
12207 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12208 if (res == NULL)
12209 goto errret;
12210
12211 list = list_alloc();
12212 if (list == NULL)
12213 goto errret;
12214
12215 for (i = 0; i < len; ++i)
12216 {
12217 start = res + i;
12218 while (i < len && res[i] != NL)
12219 ++i;
12220 end = res + i;
12221
12222 s = alloc((unsigned)(end - start + 1));
12223 if (s == NULL)
12224 goto errret;
12225
12226 for (p = s; start < end; ++p, ++start)
12227 *p = *start == NUL ? NL : *start;
12228 *p = NUL;
12229
12230 li = listitem_alloc();
12231 if (li == NULL)
12232 {
12233 vim_free(s);
12234 goto errret;
12235 }
12236 li->li_tv.v_type = VAR_STRING;
12237 li->li_tv.v_lock = 0;
12238 li->li_tv.vval.v_string = s;
12239 list_append(list, li);
12240 }
12241
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012242 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012243 list = NULL;
12244 }
12245 else
12246 {
12247 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12248#ifdef USE_CR
12249 /* translate <CR> into <NL> */
12250 if (res != NULL)
12251 {
12252 char_u *s;
12253
12254 for (s = res; *s; ++s)
12255 {
12256 if (*s == CAR)
12257 *s = NL;
12258 }
12259 }
12260#else
12261# ifdef USE_CRNL
12262 /* translate <CR><NL> into <NL> */
12263 if (res != NULL)
12264 {
12265 char_u *s, *d;
12266
12267 d = res;
12268 for (s = res; *s; ++s)
12269 {
12270 if (s[0] == CAR && s[1] == NL)
12271 ++s;
12272 *d++ = *s;
12273 }
12274 *d = NUL;
12275 }
12276# endif
12277#endif
12278 rettv->vval.v_string = res;
12279 res = NULL;
12280 }
12281
12282errret:
12283 if (infile != NULL)
12284 {
12285 mch_remove(infile);
12286 vim_free(infile);
12287 }
12288 if (res != NULL)
12289 vim_free(res);
12290 if (list != NULL)
12291 list_free(list);
12292}
12293
12294/*
12295 * "system()" function
12296 */
12297 static void
12298f_system(typval_T *argvars, typval_T *rettv)
12299{
12300 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12301}
12302
12303/*
12304 * "systemlist()" function
12305 */
12306 static void
12307f_systemlist(typval_T *argvars, typval_T *rettv)
12308{
12309 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12310}
12311
12312/*
12313 * "tabpagebuflist()" function
12314 */
12315 static void
12316f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12317{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012318 tabpage_T *tp;
12319 win_T *wp = NULL;
12320
12321 if (argvars[0].v_type == VAR_UNKNOWN)
12322 wp = firstwin;
12323 else
12324 {
12325 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12326 if (tp != NULL)
12327 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12328 }
12329 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12330 {
12331 for (; wp != NULL; wp = wp->w_next)
12332 if (list_append_number(rettv->vval.v_list,
12333 wp->w_buffer->b_fnum) == FAIL)
12334 break;
12335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012336}
12337
12338
12339/*
12340 * "tabpagenr()" function
12341 */
12342 static void
12343f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12344{
12345 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012346 char_u *arg;
12347
12348 if (argvars[0].v_type != VAR_UNKNOWN)
12349 {
12350 arg = get_tv_string_chk(&argvars[0]);
12351 nr = 0;
12352 if (arg != NULL)
12353 {
12354 if (STRCMP(arg, "$") == 0)
12355 nr = tabpage_index(NULL) - 1;
12356 else
12357 EMSG2(_(e_invexpr2), arg);
12358 }
12359 }
12360 else
12361 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012362 rettv->vval.v_number = nr;
12363}
12364
12365
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012366static int get_winnr(tabpage_T *tp, typval_T *argvar);
12367
12368/*
12369 * Common code for tabpagewinnr() and winnr().
12370 */
12371 static int
12372get_winnr(tabpage_T *tp, typval_T *argvar)
12373{
12374 win_T *twin;
12375 int nr = 1;
12376 win_T *wp;
12377 char_u *arg;
12378
12379 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12380 if (argvar->v_type != VAR_UNKNOWN)
12381 {
12382 arg = get_tv_string_chk(argvar);
12383 if (arg == NULL)
12384 nr = 0; /* type error; errmsg already given */
12385 else if (STRCMP(arg, "$") == 0)
12386 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12387 else if (STRCMP(arg, "#") == 0)
12388 {
12389 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12390 if (twin == NULL)
12391 nr = 0;
12392 }
12393 else
12394 {
12395 EMSG2(_(e_invexpr2), arg);
12396 nr = 0;
12397 }
12398 }
12399
12400 if (nr > 0)
12401 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12402 wp != twin; wp = wp->w_next)
12403 {
12404 if (wp == NULL)
12405 {
12406 /* didn't find it in this tabpage */
12407 nr = 0;
12408 break;
12409 }
12410 ++nr;
12411 }
12412 return nr;
12413}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012414
12415/*
12416 * "tabpagewinnr()" function
12417 */
12418 static void
12419f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12420{
12421 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012422 tabpage_T *tp;
12423
12424 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12425 if (tp == NULL)
12426 nr = 0;
12427 else
12428 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012429 rettv->vval.v_number = nr;
12430}
12431
12432
12433/*
12434 * "tagfiles()" function
12435 */
12436 static void
12437f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12438{
12439 char_u *fname;
12440 tagname_T tn;
12441 int first;
12442
12443 if (rettv_list_alloc(rettv) == FAIL)
12444 return;
12445 fname = alloc(MAXPATHL);
12446 if (fname == NULL)
12447 return;
12448
12449 for (first = TRUE; ; first = FALSE)
12450 if (get_tagfname(&tn, first, fname) == FAIL
12451 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12452 break;
12453 tagname_free(&tn);
12454 vim_free(fname);
12455}
12456
12457/*
12458 * "taglist()" function
12459 */
12460 static void
12461f_taglist(typval_T *argvars, typval_T *rettv)
12462{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012463 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012464 char_u *tag_pattern;
12465
12466 tag_pattern = get_tv_string(&argvars[0]);
12467
12468 rettv->vval.v_number = FALSE;
12469 if (*tag_pattern == NUL)
12470 return;
12471
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012472 if (argvars[1].v_type != VAR_UNKNOWN)
12473 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012474 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012475 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012476}
12477
12478/*
12479 * "tempname()" function
12480 */
12481 static void
12482f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12483{
12484 static int x = 'A';
12485
12486 rettv->v_type = VAR_STRING;
12487 rettv->vval.v_string = vim_tempname(x, FALSE);
12488
12489 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12490 * names. Skip 'I' and 'O', they are used for shell redirection. */
12491 do
12492 {
12493 if (x == 'Z')
12494 x = '0';
12495 else if (x == '9')
12496 x = 'A';
12497 else
12498 {
12499#ifdef EBCDIC
12500 if (x == 'I')
12501 x = 'J';
12502 else if (x == 'R')
12503 x = 'S';
12504 else
12505#endif
12506 ++x;
12507 }
12508 } while (x == 'I' || x == 'O');
12509}
12510
12511#ifdef FEAT_FLOAT
12512/*
12513 * "tan()" function
12514 */
12515 static void
12516f_tan(typval_T *argvars, typval_T *rettv)
12517{
12518 float_T f = 0.0;
12519
12520 rettv->v_type = VAR_FLOAT;
12521 if (get_float_arg(argvars, &f) == OK)
12522 rettv->vval.v_float = tan(f);
12523 else
12524 rettv->vval.v_float = 0.0;
12525}
12526
12527/*
12528 * "tanh()" function
12529 */
12530 static void
12531f_tanh(typval_T *argvars, typval_T *rettv)
12532{
12533 float_T f = 0.0;
12534
12535 rettv->v_type = VAR_FLOAT;
12536 if (get_float_arg(argvars, &f) == OK)
12537 rettv->vval.v_float = tanh(f);
12538 else
12539 rettv->vval.v_float = 0.0;
12540}
12541#endif
12542
12543/*
12544 * "test_alloc_fail(id, countdown, repeat)" function
12545 */
12546 static void
12547f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12548{
12549 if (argvars[0].v_type != VAR_NUMBER
12550 || argvars[0].vval.v_number <= 0
12551 || argvars[1].v_type != VAR_NUMBER
12552 || argvars[1].vval.v_number < 0
12553 || argvars[2].v_type != VAR_NUMBER)
12554 EMSG(_(e_invarg));
12555 else
12556 {
12557 alloc_fail_id = argvars[0].vval.v_number;
12558 if (alloc_fail_id >= aid_last)
12559 EMSG(_(e_invarg));
12560 alloc_fail_countdown = argvars[1].vval.v_number;
12561 alloc_fail_repeat = argvars[2].vval.v_number;
12562 did_outofmem_msg = FALSE;
12563 }
12564}
12565
12566/*
12567 * "test_autochdir()"
12568 */
12569 static void
12570f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12571{
12572#if defined(FEAT_AUTOCHDIR)
12573 test_autochdir = TRUE;
12574#endif
12575}
12576
12577/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012578 * "test_feedinput()"
12579 */
12580 static void
12581f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12582{
12583#ifdef USE_INPUT_BUF
12584 char_u *val = get_tv_string_chk(&argvars[0]);
12585
12586 if (val != NULL)
12587 {
12588 trash_input_buf();
12589 add_to_input_buf_csi(val, (int)STRLEN(val));
12590 }
12591#endif
12592}
12593
12594/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012595 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012596 */
12597 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012598f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012599{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012600 char_u *name = (char_u *)"";
12601 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012602 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012603
12604 if (argvars[0].v_type != VAR_STRING
12605 || (argvars[1].v_type) != VAR_NUMBER)
12606 EMSG(_(e_invarg));
12607 else
12608 {
12609 name = get_tv_string_chk(&argvars[0]);
12610 val = (int)get_tv_number(&argvars[1]);
12611
12612 if (STRCMP(name, (char_u *)"redraw") == 0)
12613 disable_redraw_for_testing = val;
12614 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12615 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012616 else if (STRCMP(name, (char_u *)"starting") == 0)
12617 {
12618 if (val)
12619 {
12620 if (save_starting < 0)
12621 save_starting = starting;
12622 starting = 0;
12623 }
12624 else
12625 {
12626 starting = save_starting;
12627 save_starting = -1;
12628 }
12629 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012630 else if (STRCMP(name, (char_u *)"ALL") == 0)
12631 {
12632 disable_char_avail_for_testing = FALSE;
12633 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012634 if (save_starting >= 0)
12635 {
12636 starting = save_starting;
12637 save_starting = -1;
12638 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012639 }
12640 else
12641 EMSG2(_(e_invarg2), name);
12642 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012643}
12644
12645/*
12646 * "test_garbagecollect_now()" function
12647 */
12648 static void
12649f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12650{
12651 /* This is dangerous, any Lists and Dicts used internally may be freed
12652 * while still in use. */
12653 garbage_collect(TRUE);
12654}
12655
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012656/*
12657 * "test_ignore_error()" function
12658 */
12659 static void
12660f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12661{
12662 ignore_error_for_testing(get_tv_string(&argvars[0]));
12663}
12664
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012665#ifdef FEAT_JOB_CHANNEL
12666 static void
12667f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12668{
12669 rettv->v_type = VAR_CHANNEL;
12670 rettv->vval.v_channel = NULL;
12671}
12672#endif
12673
12674 static void
12675f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12676{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012677 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012678}
12679
12680#ifdef FEAT_JOB_CHANNEL
12681 static void
12682f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12683{
12684 rettv->v_type = VAR_JOB;
12685 rettv->vval.v_job = NULL;
12686}
12687#endif
12688
12689 static void
12690f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12691{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012692 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012693}
12694
12695 static void
12696f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12697{
12698 rettv->v_type = VAR_PARTIAL;
12699 rettv->vval.v_partial = NULL;
12700}
12701
12702 static void
12703f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12704{
12705 rettv->v_type = VAR_STRING;
12706 rettv->vval.v_string = NULL;
12707}
12708
12709 static void
12710f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12711{
12712 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12713}
12714
12715#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12716/*
12717 * Get a callback from "arg". It can be a Funcref or a function name.
12718 * When "arg" is zero return an empty string.
12719 * Return NULL for an invalid argument.
12720 */
12721 char_u *
12722get_callback(typval_T *arg, partial_T **pp)
12723{
12724 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12725 {
12726 *pp = arg->vval.v_partial;
12727 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012728 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012729 }
12730 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012731 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012732 {
12733 func_ref(arg->vval.v_string);
12734 return arg->vval.v_string;
12735 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012736 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12737 return (char_u *)"";
12738 EMSG(_("E921: Invalid callback argument"));
12739 return NULL;
12740}
12741
12742/*
12743 * Unref/free "callback" and "partial" retured by get_callback().
12744 */
12745 void
12746free_callback(char_u *callback, partial_T *partial)
12747{
12748 if (partial != NULL)
12749 partial_unref(partial);
12750 else if (callback != NULL)
12751 {
12752 func_unref(callback);
12753 vim_free(callback);
12754 }
12755}
12756#endif
12757
12758#ifdef FEAT_TIMERS
12759/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012760 * "timer_info([timer])" function
12761 */
12762 static void
12763f_timer_info(typval_T *argvars, typval_T *rettv)
12764{
12765 timer_T *timer = NULL;
12766
12767 if (rettv_list_alloc(rettv) != OK)
12768 return;
12769 if (argvars[0].v_type != VAR_UNKNOWN)
12770 {
12771 if (argvars[0].v_type != VAR_NUMBER)
12772 EMSG(_(e_number_exp));
12773 else
12774 {
12775 timer = find_timer((int)get_tv_number(&argvars[0]));
12776 if (timer != NULL)
12777 add_timer_info(rettv, timer);
12778 }
12779 }
12780 else
12781 add_timer_info_all(rettv);
12782}
12783
12784/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012785 * "timer_pause(timer, paused)" function
12786 */
12787 static void
12788f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12789{
12790 timer_T *timer = NULL;
12791 int paused = (int)get_tv_number(&argvars[1]);
12792
12793 if (argvars[0].v_type != VAR_NUMBER)
12794 EMSG(_(e_number_exp));
12795 else
12796 {
12797 timer = find_timer((int)get_tv_number(&argvars[0]));
12798 if (timer != NULL)
12799 timer->tr_paused = paused;
12800 }
12801}
12802
12803/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012804 * "timer_start(time, callback [, options])" function
12805 */
12806 static void
12807f_timer_start(typval_T *argvars, typval_T *rettv)
12808{
Bram Moolenaar75537a92016-09-05 22:45:28 +020012809 long msec = (long)get_tv_number(&argvars[0]);
12810 timer_T *timer;
12811 int repeat = 0;
12812 char_u *callback;
12813 dict_T *dict;
12814 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012815
Bram Moolenaar75537a92016-09-05 22:45:28 +020012816 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012817 if (check_secure())
12818 return;
12819 if (argvars[2].v_type != VAR_UNKNOWN)
12820 {
12821 if (argvars[2].v_type != VAR_DICT
12822 || (dict = argvars[2].vval.v_dict) == NULL)
12823 {
12824 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12825 return;
12826 }
12827 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12828 repeat = get_dict_number(dict, (char_u *)"repeat");
12829 }
12830
Bram Moolenaar75537a92016-09-05 22:45:28 +020012831 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012832 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012833 return;
12834
12835 timer = create_timer(msec, repeat);
12836 if (timer == NULL)
12837 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012838 else
12839 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020012840 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020012841 timer->tr_callback = vim_strsave(callback);
12842 else
12843 /* pointer into the partial */
12844 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012845 timer->tr_partial = partial;
12846 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012847 }
12848}
12849
12850/*
12851 * "timer_stop(timer)" function
12852 */
12853 static void
12854f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12855{
12856 timer_T *timer;
12857
12858 if (argvars[0].v_type != VAR_NUMBER)
12859 {
12860 EMSG(_(e_number_exp));
12861 return;
12862 }
12863 timer = find_timer((int)get_tv_number(&argvars[0]));
12864 if (timer != NULL)
12865 stop_timer(timer);
12866}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012867
12868/*
12869 * "timer_stopall()" function
12870 */
12871 static void
12872f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12873{
12874 stop_all_timers();
12875}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012876#endif
12877
12878/*
12879 * "tolower(string)" function
12880 */
12881 static void
12882f_tolower(typval_T *argvars, typval_T *rettv)
12883{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012884 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010012885 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012886}
12887
12888/*
12889 * "toupper(string)" function
12890 */
12891 static void
12892f_toupper(typval_T *argvars, typval_T *rettv)
12893{
12894 rettv->v_type = VAR_STRING;
12895 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12896}
12897
12898/*
12899 * "tr(string, fromstr, tostr)" function
12900 */
12901 static void
12902f_tr(typval_T *argvars, typval_T *rettv)
12903{
12904 char_u *in_str;
12905 char_u *fromstr;
12906 char_u *tostr;
12907 char_u *p;
12908#ifdef FEAT_MBYTE
12909 int inlen;
12910 int fromlen;
12911 int tolen;
12912 int idx;
12913 char_u *cpstr;
12914 int cplen;
12915 int first = TRUE;
12916#endif
12917 char_u buf[NUMBUFLEN];
12918 char_u buf2[NUMBUFLEN];
12919 garray_T ga;
12920
12921 in_str = get_tv_string(&argvars[0]);
12922 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12923 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12924
12925 /* Default return value: empty string. */
12926 rettv->v_type = VAR_STRING;
12927 rettv->vval.v_string = NULL;
12928 if (fromstr == NULL || tostr == NULL)
12929 return; /* type error; errmsg already given */
12930 ga_init2(&ga, (int)sizeof(char), 80);
12931
12932#ifdef FEAT_MBYTE
12933 if (!has_mbyte)
12934#endif
12935 /* not multi-byte: fromstr and tostr must be the same length */
12936 if (STRLEN(fromstr) != STRLEN(tostr))
12937 {
12938#ifdef FEAT_MBYTE
12939error:
12940#endif
12941 EMSG2(_(e_invarg2), fromstr);
12942 ga_clear(&ga);
12943 return;
12944 }
12945
12946 /* fromstr and tostr have to contain the same number of chars */
12947 while (*in_str != NUL)
12948 {
12949#ifdef FEAT_MBYTE
12950 if (has_mbyte)
12951 {
12952 inlen = (*mb_ptr2len)(in_str);
12953 cpstr = in_str;
12954 cplen = inlen;
12955 idx = 0;
12956 for (p = fromstr; *p != NUL; p += fromlen)
12957 {
12958 fromlen = (*mb_ptr2len)(p);
12959 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12960 {
12961 for (p = tostr; *p != NUL; p += tolen)
12962 {
12963 tolen = (*mb_ptr2len)(p);
12964 if (idx-- == 0)
12965 {
12966 cplen = tolen;
12967 cpstr = p;
12968 break;
12969 }
12970 }
12971 if (*p == NUL) /* tostr is shorter than fromstr */
12972 goto error;
12973 break;
12974 }
12975 ++idx;
12976 }
12977
12978 if (first && cpstr == in_str)
12979 {
12980 /* Check that fromstr and tostr have the same number of
12981 * (multi-byte) characters. Done only once when a character
12982 * of in_str doesn't appear in fromstr. */
12983 first = FALSE;
12984 for (p = tostr; *p != NUL; p += tolen)
12985 {
12986 tolen = (*mb_ptr2len)(p);
12987 --idx;
12988 }
12989 if (idx != 0)
12990 goto error;
12991 }
12992
12993 (void)ga_grow(&ga, cplen);
12994 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12995 ga.ga_len += cplen;
12996
12997 in_str += inlen;
12998 }
12999 else
13000#endif
13001 {
13002 /* When not using multi-byte chars we can do it faster. */
13003 p = vim_strchr(fromstr, *in_str);
13004 if (p != NULL)
13005 ga_append(&ga, tostr[p - fromstr]);
13006 else
13007 ga_append(&ga, *in_str);
13008 ++in_str;
13009 }
13010 }
13011
13012 /* add a terminating NUL */
13013 (void)ga_grow(&ga, 1);
13014 ga_append(&ga, NUL);
13015
13016 rettv->vval.v_string = ga.ga_data;
13017}
13018
13019#ifdef FEAT_FLOAT
13020/*
13021 * "trunc({float})" function
13022 */
13023 static void
13024f_trunc(typval_T *argvars, typval_T *rettv)
13025{
13026 float_T f = 0.0;
13027
13028 rettv->v_type = VAR_FLOAT;
13029 if (get_float_arg(argvars, &f) == OK)
13030 /* trunc() is not in C90, use floor() or ceil() instead. */
13031 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13032 else
13033 rettv->vval.v_float = 0.0;
13034}
13035#endif
13036
13037/*
13038 * "type(expr)" function
13039 */
13040 static void
13041f_type(typval_T *argvars, typval_T *rettv)
13042{
13043 int n = -1;
13044
13045 switch (argvars[0].v_type)
13046 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013047 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13048 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013049 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013050 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13051 case VAR_LIST: n = VAR_TYPE_LIST; break;
13052 case VAR_DICT: n = VAR_TYPE_DICT; break;
13053 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013054 case VAR_SPECIAL:
13055 if (argvars[0].vval.v_number == VVAL_FALSE
13056 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013057 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013058 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013059 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013060 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013061 case VAR_JOB: n = VAR_TYPE_JOB; break;
13062 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013063 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013064 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013065 n = -1;
13066 break;
13067 }
13068 rettv->vval.v_number = n;
13069}
13070
13071/*
13072 * "undofile(name)" function
13073 */
13074 static void
13075f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13076{
13077 rettv->v_type = VAR_STRING;
13078#ifdef FEAT_PERSISTENT_UNDO
13079 {
13080 char_u *fname = get_tv_string(&argvars[0]);
13081
13082 if (*fname == NUL)
13083 {
13084 /* If there is no file name there will be no undo file. */
13085 rettv->vval.v_string = NULL;
13086 }
13087 else
13088 {
13089 char_u *ffname = FullName_save(fname, FALSE);
13090
13091 if (ffname != NULL)
13092 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13093 vim_free(ffname);
13094 }
13095 }
13096#else
13097 rettv->vval.v_string = NULL;
13098#endif
13099}
13100
13101/*
13102 * "undotree()" function
13103 */
13104 static void
13105f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13106{
13107 if (rettv_dict_alloc(rettv) == OK)
13108 {
13109 dict_T *dict = rettv->vval.v_dict;
13110 list_T *list;
13111
13112 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13113 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13114 dict_add_nr_str(dict, "save_last",
13115 (long)curbuf->b_u_save_nr_last, NULL);
13116 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13117 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13118 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13119
13120 list = list_alloc();
13121 if (list != NULL)
13122 {
13123 u_eval_tree(curbuf->b_u_oldhead, list);
13124 dict_add_list(dict, "entries", list);
13125 }
13126 }
13127}
13128
13129/*
13130 * "values(dict)" function
13131 */
13132 static void
13133f_values(typval_T *argvars, typval_T *rettv)
13134{
13135 dict_list(argvars, rettv, 1);
13136}
13137
13138/*
13139 * "virtcol(string)" function
13140 */
13141 static void
13142f_virtcol(typval_T *argvars, typval_T *rettv)
13143{
13144 colnr_T vcol = 0;
13145 pos_T *fp;
13146 int fnum = curbuf->b_fnum;
13147
13148 fp = var2fpos(&argvars[0], FALSE, &fnum);
13149 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13150 && fnum == curbuf->b_fnum)
13151 {
13152 getvvcol(curwin, fp, NULL, NULL, &vcol);
13153 ++vcol;
13154 }
13155
13156 rettv->vval.v_number = vcol;
13157}
13158
13159/*
13160 * "visualmode()" function
13161 */
13162 static void
13163f_visualmode(typval_T *argvars, typval_T *rettv)
13164{
13165 char_u str[2];
13166
13167 rettv->v_type = VAR_STRING;
13168 str[0] = curbuf->b_visual_mode_eval;
13169 str[1] = NUL;
13170 rettv->vval.v_string = vim_strsave(str);
13171
13172 /* A non-zero number or non-empty string argument: reset mode. */
13173 if (non_zero_arg(&argvars[0]))
13174 curbuf->b_visual_mode_eval = NUL;
13175}
13176
13177/*
13178 * "wildmenumode()" function
13179 */
13180 static void
13181f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13182{
13183#ifdef FEAT_WILDMENU
13184 if (wild_menu_showing)
13185 rettv->vval.v_number = 1;
13186#endif
13187}
13188
13189/*
13190 * "winbufnr(nr)" function
13191 */
13192 static void
13193f_winbufnr(typval_T *argvars, typval_T *rettv)
13194{
13195 win_T *wp;
13196
13197 wp = find_win_by_nr(&argvars[0], NULL);
13198 if (wp == NULL)
13199 rettv->vval.v_number = -1;
13200 else
13201 rettv->vval.v_number = wp->w_buffer->b_fnum;
13202}
13203
13204/*
13205 * "wincol()" function
13206 */
13207 static void
13208f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13209{
13210 validate_cursor();
13211 rettv->vval.v_number = curwin->w_wcol + 1;
13212}
13213
13214/*
13215 * "winheight(nr)" function
13216 */
13217 static void
13218f_winheight(typval_T *argvars, typval_T *rettv)
13219{
13220 win_T *wp;
13221
13222 wp = find_win_by_nr(&argvars[0], NULL);
13223 if (wp == NULL)
13224 rettv->vval.v_number = -1;
13225 else
13226 rettv->vval.v_number = wp->w_height;
13227}
13228
13229/*
13230 * "winline()" function
13231 */
13232 static void
13233f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13234{
13235 validate_cursor();
13236 rettv->vval.v_number = curwin->w_wrow + 1;
13237}
13238
13239/*
13240 * "winnr()" function
13241 */
13242 static void
13243f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13244{
13245 int nr = 1;
13246
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013247 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013248 rettv->vval.v_number = nr;
13249}
13250
13251/*
13252 * "winrestcmd()" function
13253 */
13254 static void
13255f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13256{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013257 win_T *wp;
13258 int winnr = 1;
13259 garray_T ga;
13260 char_u buf[50];
13261
13262 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013263 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013264 {
13265 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13266 ga_concat(&ga, buf);
13267 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13268 ga_concat(&ga, buf);
13269 ++winnr;
13270 }
13271 ga_append(&ga, NUL);
13272
13273 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013274 rettv->v_type = VAR_STRING;
13275}
13276
13277/*
13278 * "winrestview()" function
13279 */
13280 static void
13281f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13282{
13283 dict_T *dict;
13284
13285 if (argvars[0].v_type != VAR_DICT
13286 || (dict = argvars[0].vval.v_dict) == NULL)
13287 EMSG(_(e_invarg));
13288 else
13289 {
13290 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13291 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13292 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13293 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13294#ifdef FEAT_VIRTUALEDIT
13295 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13296 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13297#endif
13298 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13299 {
13300 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13301 curwin->w_set_curswant = FALSE;
13302 }
13303
13304 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13305 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13306#ifdef FEAT_DIFF
13307 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13308 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13309#endif
13310 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13311 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13312 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13313 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13314
13315 check_cursor();
13316 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013317 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013318 changed_window_setting();
13319
13320 if (curwin->w_topline <= 0)
13321 curwin->w_topline = 1;
13322 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13323 curwin->w_topline = curbuf->b_ml.ml_line_count;
13324#ifdef FEAT_DIFF
13325 check_topfill(curwin, TRUE);
13326#endif
13327 }
13328}
13329
13330/*
13331 * "winsaveview()" function
13332 */
13333 static void
13334f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13335{
13336 dict_T *dict;
13337
13338 if (rettv_dict_alloc(rettv) == FAIL)
13339 return;
13340 dict = rettv->vval.v_dict;
13341
13342 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13343 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13344#ifdef FEAT_VIRTUALEDIT
13345 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13346#endif
13347 update_curswant();
13348 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13349
13350 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13351#ifdef FEAT_DIFF
13352 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13353#endif
13354 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13355 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13356}
13357
13358/*
13359 * "winwidth(nr)" function
13360 */
13361 static void
13362f_winwidth(typval_T *argvars, typval_T *rettv)
13363{
13364 win_T *wp;
13365
13366 wp = find_win_by_nr(&argvars[0], NULL);
13367 if (wp == NULL)
13368 rettv->vval.v_number = -1;
13369 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013370 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013371}
13372
13373/*
13374 * "wordcount()" function
13375 */
13376 static void
13377f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13378{
13379 if (rettv_dict_alloc(rettv) == FAIL)
13380 return;
13381 cursor_pos_info(rettv->vval.v_dict);
13382}
13383
13384/*
13385 * "writefile()" function
13386 */
13387 static void
13388f_writefile(typval_T *argvars, typval_T *rettv)
13389{
13390 int binary = FALSE;
13391 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013392#ifdef HAVE_FSYNC
13393 int do_fsync = p_fs;
13394#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013395 char_u *fname;
13396 FILE *fd;
13397 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013398 listitem_T *li;
13399 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013400
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013401 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013402 if (check_restricted() || check_secure())
13403 return;
13404
13405 if (argvars[0].v_type != VAR_LIST)
13406 {
13407 EMSG2(_(e_listarg), "writefile()");
13408 return;
13409 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013410 list = argvars[0].vval.v_list;
13411 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013412 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013413 for (li = list->lv_first; li != NULL; li = li->li_next)
13414 if (get_tv_string_chk(&li->li_tv) == NULL)
13415 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013416
13417 if (argvars[2].v_type != VAR_UNKNOWN)
13418 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013419 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13420
13421 if (arg2 == NULL)
13422 return;
13423 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013424 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013425 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013426 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013427#ifdef HAVE_FSYNC
13428 if (vim_strchr(arg2, 's') != NULL)
13429 do_fsync = TRUE;
13430 else if (vim_strchr(arg2, 'S') != NULL)
13431 do_fsync = FALSE;
13432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013433 }
13434
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013435 fname = get_tv_string_chk(&argvars[1]);
13436 if (fname == NULL)
13437 return;
13438
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013439 /* Always open the file in binary mode, library functions have a mind of
13440 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013441 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13442 append ? APPENDBIN : WRITEBIN)) == NULL)
13443 {
13444 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13445 ret = -1;
13446 }
13447 else
13448 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013449 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013450 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013451#ifdef HAVE_FSYNC
13452 else if (do_fsync && fsync(fileno(fd)) != 0)
13453 EMSG(_(e_fsync));
13454#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013455 fclose(fd);
13456 }
13457
13458 rettv->vval.v_number = ret;
13459}
13460
13461/*
13462 * "xor(expr, expr)" function
13463 */
13464 static void
13465f_xor(typval_T *argvars, typval_T *rettv)
13466{
13467 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13468 ^ get_tv_number_chk(&argvars[1], NULL);
13469}
13470
13471
13472#endif /* FEAT_EVAL */