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