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