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