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