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