blob: 2be7fe1bf2e6b6feb3f0f8a8761847ea138a5aa5 [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,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002024 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002025 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);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002048 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002049 && (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 Moolenaar69905d12017-08-13 18:14:47 +02005231#ifdef FEAT_TERMINAL
5232 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5233#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005234#ifdef FEAT_QUICKFIX
5235 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5236 dict_add_nr_str(dict, "loclist",
5237 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5238#endif
5239
Bram Moolenaar30567352016-08-27 21:25:44 +02005240 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005241 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005242
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005243 return dict;
5244}
5245#endif
5246
5247/*
5248 * "getwininfo()" function
5249 */
5250 static void
5251f_getwininfo(typval_T *argvars, typval_T *rettv)
5252{
5253#ifdef FEAT_WINDOWS
5254 tabpage_T *tp;
5255 win_T *wp = NULL, *wparg = NULL;
5256 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005257 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005258#endif
5259
5260 if (rettv_list_alloc(rettv) != OK)
5261 return;
5262
5263#ifdef FEAT_WINDOWS
5264 if (argvars[0].v_type != VAR_UNKNOWN)
5265 {
5266 wparg = win_id2wp(argvars);
5267 if (wparg == NULL)
5268 return;
5269 }
5270
5271 /* Collect information about either all the windows across all the tab
5272 * pages or one particular window.
5273 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005274 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005275 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005276 tabnr++;
5277 winnr = 0;
5278 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005279 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005280 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005281 if (wparg != NULL && wp != wparg)
5282 continue;
5283 d = get_win_info(wp, tabnr, winnr);
5284 if (d != NULL)
5285 list_append_dict(rettv->vval.v_list, d);
5286 if (wparg != NULL)
5287 /* found information about a specific window */
5288 return;
5289 }
5290 }
5291#endif
5292}
5293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005295 * "win_findbuf()" function
5296 */
5297 static void
5298f_win_findbuf(typval_T *argvars, typval_T *rettv)
5299{
5300 if (rettv_list_alloc(rettv) != FAIL)
5301 win_findbuf(argvars, rettv->vval.v_list);
5302}
5303
5304/*
5305 * "win_getid()" function
5306 */
5307 static void
5308f_win_getid(typval_T *argvars, typval_T *rettv)
5309{
5310 rettv->vval.v_number = win_getid(argvars);
5311}
5312
5313/*
5314 * "win_gotoid()" function
5315 */
5316 static void
5317f_win_gotoid(typval_T *argvars, typval_T *rettv)
5318{
5319 rettv->vval.v_number = win_gotoid(argvars);
5320}
5321
5322/*
5323 * "win_id2tabwin()" function
5324 */
5325 static void
5326f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5327{
5328 if (rettv_list_alloc(rettv) != FAIL)
5329 win_id2tabwin(argvars, rettv->vval.v_list);
5330}
5331
5332/*
5333 * "win_id2win()" function
5334 */
5335 static void
5336f_win_id2win(typval_T *argvars, typval_T *rettv)
5337{
5338 rettv->vval.v_number = win_id2win(argvars);
5339}
5340
5341/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005342 * "getwinposx()" function
5343 */
5344 static void
5345f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5346{
5347 rettv->vval.v_number = -1;
5348#ifdef FEAT_GUI
5349 if (gui.in_use)
5350 {
5351 int x, y;
5352
5353 if (gui_mch_get_winpos(&x, &y) == OK)
5354 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005355 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005356 }
5357#endif
5358#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5359 {
5360 int x, y;
5361
5362 if (term_get_winpos(&x, &y) == OK)
5363 rettv->vval.v_number = x;
5364 }
5365#endif
5366}
5367
5368/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005369 * "getwinposy()" function
5370 */
5371 static void
5372f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5373{
5374 rettv->vval.v_number = -1;
5375#ifdef FEAT_GUI
5376 if (gui.in_use)
5377 {
5378 int x, y;
5379
5380 if (gui_mch_get_winpos(&x, &y) == OK)
5381 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005382 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005383 }
5384#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005385#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5386 {
5387 int x, y;
5388
5389 if (term_get_winpos(&x, &y) == OK)
5390 rettv->vval.v_number = y;
5391 }
5392#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005393}
5394
5395/*
5396 * "getwinvar()" function
5397 */
5398 static void
5399f_getwinvar(typval_T *argvars, typval_T *rettv)
5400{
5401 getwinvar(argvars, rettv, 0);
5402}
5403
5404/*
5405 * "glob()" function
5406 */
5407 static void
5408f_glob(typval_T *argvars, typval_T *rettv)
5409{
5410 int options = WILD_SILENT|WILD_USE_NL;
5411 expand_T xpc;
5412 int error = FALSE;
5413
5414 /* When the optional second argument is non-zero, don't remove matches
5415 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5416 rettv->v_type = VAR_STRING;
5417 if (argvars[1].v_type != VAR_UNKNOWN)
5418 {
5419 if (get_tv_number_chk(&argvars[1], &error))
5420 options |= WILD_KEEP_ALL;
5421 if (argvars[2].v_type != VAR_UNKNOWN)
5422 {
5423 if (get_tv_number_chk(&argvars[2], &error))
5424 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005425 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005426 }
5427 if (argvars[3].v_type != VAR_UNKNOWN
5428 && get_tv_number_chk(&argvars[3], &error))
5429 options |= WILD_ALLLINKS;
5430 }
5431 }
5432 if (!error)
5433 {
5434 ExpandInit(&xpc);
5435 xpc.xp_context = EXPAND_FILES;
5436 if (p_wic)
5437 options += WILD_ICASE;
5438 if (rettv->v_type == VAR_STRING)
5439 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5440 NULL, options, WILD_ALL);
5441 else if (rettv_list_alloc(rettv) != FAIL)
5442 {
5443 int i;
5444
5445 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5446 NULL, options, WILD_ALL_KEEP);
5447 for (i = 0; i < xpc.xp_numfiles; i++)
5448 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5449
5450 ExpandCleanup(&xpc);
5451 }
5452 }
5453 else
5454 rettv->vval.v_string = NULL;
5455}
5456
5457/*
5458 * "globpath()" function
5459 */
5460 static void
5461f_globpath(typval_T *argvars, typval_T *rettv)
5462{
5463 int flags = 0;
5464 char_u buf1[NUMBUFLEN];
5465 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5466 int error = FALSE;
5467 garray_T ga;
5468 int i;
5469
5470 /* When the optional second argument is non-zero, don't remove matches
5471 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5472 rettv->v_type = VAR_STRING;
5473 if (argvars[2].v_type != VAR_UNKNOWN)
5474 {
5475 if (get_tv_number_chk(&argvars[2], &error))
5476 flags |= WILD_KEEP_ALL;
5477 if (argvars[3].v_type != VAR_UNKNOWN)
5478 {
5479 if (get_tv_number_chk(&argvars[3], &error))
5480 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005481 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005482 }
5483 if (argvars[4].v_type != VAR_UNKNOWN
5484 && get_tv_number_chk(&argvars[4], &error))
5485 flags |= WILD_ALLLINKS;
5486 }
5487 }
5488 if (file != NULL && !error)
5489 {
5490 ga_init2(&ga, (int)sizeof(char_u *), 10);
5491 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5492 if (rettv->v_type == VAR_STRING)
5493 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5494 else if (rettv_list_alloc(rettv) != FAIL)
5495 for (i = 0; i < ga.ga_len; ++i)
5496 list_append_string(rettv->vval.v_list,
5497 ((char_u **)(ga.ga_data))[i], -1);
5498 ga_clear_strings(&ga);
5499 }
5500 else
5501 rettv->vval.v_string = NULL;
5502}
5503
5504/*
5505 * "glob2regpat()" function
5506 */
5507 static void
5508f_glob2regpat(typval_T *argvars, typval_T *rettv)
5509{
5510 char_u *pat = get_tv_string_chk(&argvars[0]);
5511
5512 rettv->v_type = VAR_STRING;
5513 rettv->vval.v_string = (pat == NULL)
5514 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5515}
5516
5517/* for VIM_VERSION_ defines */
5518#include "version.h"
5519
5520/*
5521 * "has()" function
5522 */
5523 static void
5524f_has(typval_T *argvars, typval_T *rettv)
5525{
5526 int i;
5527 char_u *name;
5528 int n = FALSE;
5529 static char *(has_list[]) =
5530 {
5531#ifdef AMIGA
5532 "amiga",
5533# ifdef FEAT_ARP
5534 "arp",
5535# endif
5536#endif
5537#ifdef __BEOS__
5538 "beos",
5539#endif
5540#ifdef MACOS
5541 "mac",
5542#endif
5543#if defined(MACOS_X_UNIX)
5544 "macunix", /* built with 'darwin' enabled */
5545#endif
5546#if defined(__APPLE__) && __APPLE__ == 1
5547 "osx", /* built with or without 'darwin' enabled */
5548#endif
5549#ifdef __QNX__
5550 "qnx",
5551#endif
5552#ifdef UNIX
5553 "unix",
5554#endif
5555#ifdef VMS
5556 "vms",
5557#endif
5558#ifdef WIN32
5559 "win32",
5560#endif
5561#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5562 "win32unix",
5563#endif
5564#if defined(WIN64) || defined(_WIN64)
5565 "win64",
5566#endif
5567#ifdef EBCDIC
5568 "ebcdic",
5569#endif
5570#ifndef CASE_INSENSITIVE_FILENAME
5571 "fname_case",
5572#endif
5573#ifdef HAVE_ACL
5574 "acl",
5575#endif
5576#ifdef FEAT_ARABIC
5577 "arabic",
5578#endif
5579#ifdef FEAT_AUTOCMD
5580 "autocmd",
5581#endif
5582#ifdef FEAT_BEVAL
5583 "balloon_eval",
5584# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5585 "balloon_multiline",
5586# endif
5587#endif
5588#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5589 "builtin_terms",
5590# ifdef ALL_BUILTIN_TCAPS
5591 "all_builtin_terms",
5592# endif
5593#endif
5594#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5595 || defined(FEAT_GUI_W32) \
5596 || defined(FEAT_GUI_MOTIF))
5597 "browsefilter",
5598#endif
5599#ifdef FEAT_BYTEOFF
5600 "byte_offset",
5601#endif
5602#ifdef FEAT_JOB_CHANNEL
5603 "channel",
5604#endif
5605#ifdef FEAT_CINDENT
5606 "cindent",
5607#endif
5608#ifdef FEAT_CLIENTSERVER
5609 "clientserver",
5610#endif
5611#ifdef FEAT_CLIPBOARD
5612 "clipboard",
5613#endif
5614#ifdef FEAT_CMDL_COMPL
5615 "cmdline_compl",
5616#endif
5617#ifdef FEAT_CMDHIST
5618 "cmdline_hist",
5619#endif
5620#ifdef FEAT_COMMENTS
5621 "comments",
5622#endif
5623#ifdef FEAT_CONCEAL
5624 "conceal",
5625#endif
5626#ifdef FEAT_CRYPT
5627 "cryptv",
5628 "crypt-blowfish",
5629 "crypt-blowfish2",
5630#endif
5631#ifdef FEAT_CSCOPE
5632 "cscope",
5633#endif
5634#ifdef FEAT_CURSORBIND
5635 "cursorbind",
5636#endif
5637#ifdef CURSOR_SHAPE
5638 "cursorshape",
5639#endif
5640#ifdef DEBUG
5641 "debug",
5642#endif
5643#ifdef FEAT_CON_DIALOG
5644 "dialog_con",
5645#endif
5646#ifdef FEAT_GUI_DIALOG
5647 "dialog_gui",
5648#endif
5649#ifdef FEAT_DIFF
5650 "diff",
5651#endif
5652#ifdef FEAT_DIGRAPHS
5653 "digraphs",
5654#endif
5655#ifdef FEAT_DIRECTX
5656 "directx",
5657#endif
5658#ifdef FEAT_DND
5659 "dnd",
5660#endif
5661#ifdef FEAT_EMACS_TAGS
5662 "emacs_tags",
5663#endif
5664 "eval", /* always present, of course! */
5665 "ex_extra", /* graduated feature */
5666#ifdef FEAT_SEARCH_EXTRA
5667 "extra_search",
5668#endif
5669#ifdef FEAT_FKMAP
5670 "farsi",
5671#endif
5672#ifdef FEAT_SEARCHPATH
5673 "file_in_path",
5674#endif
5675#ifdef FEAT_FILTERPIPE
5676 "filterpipe",
5677#endif
5678#ifdef FEAT_FIND_ID
5679 "find_in_path",
5680#endif
5681#ifdef FEAT_FLOAT
5682 "float",
5683#endif
5684#ifdef FEAT_FOLDING
5685 "folding",
5686#endif
5687#ifdef FEAT_FOOTER
5688 "footer",
5689#endif
5690#if !defined(USE_SYSTEM) && defined(UNIX)
5691 "fork",
5692#endif
5693#ifdef FEAT_GETTEXT
5694 "gettext",
5695#endif
5696#ifdef FEAT_GUI
5697 "gui",
5698#endif
5699#ifdef FEAT_GUI_ATHENA
5700# ifdef FEAT_GUI_NEXTAW
5701 "gui_neXtaw",
5702# else
5703 "gui_athena",
5704# endif
5705#endif
5706#ifdef FEAT_GUI_GTK
5707 "gui_gtk",
5708# ifdef USE_GTK3
5709 "gui_gtk3",
5710# else
5711 "gui_gtk2",
5712# endif
5713#endif
5714#ifdef FEAT_GUI_GNOME
5715 "gui_gnome",
5716#endif
5717#ifdef FEAT_GUI_MAC
5718 "gui_mac",
5719#endif
5720#ifdef FEAT_GUI_MOTIF
5721 "gui_motif",
5722#endif
5723#ifdef FEAT_GUI_PHOTON
5724 "gui_photon",
5725#endif
5726#ifdef FEAT_GUI_W32
5727 "gui_win32",
5728#endif
5729#ifdef FEAT_HANGULIN
5730 "hangul_input",
5731#endif
5732#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5733 "iconv",
5734#endif
5735#ifdef FEAT_INS_EXPAND
5736 "insert_expand",
5737#endif
5738#ifdef FEAT_JOB_CHANNEL
5739 "job",
5740#endif
5741#ifdef FEAT_JUMPLIST
5742 "jumplist",
5743#endif
5744#ifdef FEAT_KEYMAP
5745 "keymap",
5746#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005747 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005748#ifdef FEAT_LANGMAP
5749 "langmap",
5750#endif
5751#ifdef FEAT_LIBCALL
5752 "libcall",
5753#endif
5754#ifdef FEAT_LINEBREAK
5755 "linebreak",
5756#endif
5757#ifdef FEAT_LISP
5758 "lispindent",
5759#endif
5760#ifdef FEAT_LISTCMDS
5761 "listcmds",
5762#endif
5763#ifdef FEAT_LOCALMAP
5764 "localmap",
5765#endif
5766#ifdef FEAT_LUA
5767# ifndef DYNAMIC_LUA
5768 "lua",
5769# endif
5770#endif
5771#ifdef FEAT_MENU
5772 "menu",
5773#endif
5774#ifdef FEAT_SESSION
5775 "mksession",
5776#endif
5777#ifdef FEAT_MODIFY_FNAME
5778 "modify_fname",
5779#endif
5780#ifdef FEAT_MOUSE
5781 "mouse",
5782#endif
5783#ifdef FEAT_MOUSESHAPE
5784 "mouseshape",
5785#endif
5786#if defined(UNIX) || defined(VMS)
5787# ifdef FEAT_MOUSE_DEC
5788 "mouse_dec",
5789# endif
5790# ifdef FEAT_MOUSE_GPM
5791 "mouse_gpm",
5792# endif
5793# ifdef FEAT_MOUSE_JSB
5794 "mouse_jsbterm",
5795# endif
5796# ifdef FEAT_MOUSE_NET
5797 "mouse_netterm",
5798# endif
5799# ifdef FEAT_MOUSE_PTERM
5800 "mouse_pterm",
5801# endif
5802# ifdef FEAT_MOUSE_SGR
5803 "mouse_sgr",
5804# endif
5805# ifdef FEAT_SYSMOUSE
5806 "mouse_sysmouse",
5807# endif
5808# ifdef FEAT_MOUSE_URXVT
5809 "mouse_urxvt",
5810# endif
5811# ifdef FEAT_MOUSE_XTERM
5812 "mouse_xterm",
5813# endif
5814#endif
5815#ifdef FEAT_MBYTE
5816 "multi_byte",
5817#endif
5818#ifdef FEAT_MBYTE_IME
5819 "multi_byte_ime",
5820#endif
5821#ifdef FEAT_MULTI_LANG
5822 "multi_lang",
5823#endif
5824#ifdef FEAT_MZSCHEME
5825#ifndef DYNAMIC_MZSCHEME
5826 "mzscheme",
5827#endif
5828#endif
5829#ifdef FEAT_NUM64
5830 "num64",
5831#endif
5832#ifdef FEAT_OLE
5833 "ole",
5834#endif
5835 "packages",
5836#ifdef FEAT_PATH_EXTRA
5837 "path_extra",
5838#endif
5839#ifdef FEAT_PERL
5840#ifndef DYNAMIC_PERL
5841 "perl",
5842#endif
5843#endif
5844#ifdef FEAT_PERSISTENT_UNDO
5845 "persistent_undo",
5846#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005847#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005848 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005849 "pythonx",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005851#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005852 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005853 "pythonx",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005854#endif
5855#ifdef FEAT_POSTSCRIPT
5856 "postscript",
5857#endif
5858#ifdef FEAT_PRINTER
5859 "printer",
5860#endif
5861#ifdef FEAT_PROFILE
5862 "profile",
5863#endif
5864#ifdef FEAT_RELTIME
5865 "reltime",
5866#endif
5867#ifdef FEAT_QUICKFIX
5868 "quickfix",
5869#endif
5870#ifdef FEAT_RIGHTLEFT
5871 "rightleft",
5872#endif
5873#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5874 "ruby",
5875#endif
5876#ifdef FEAT_SCROLLBIND
5877 "scrollbind",
5878#endif
5879#ifdef FEAT_CMDL_INFO
5880 "showcmd",
5881 "cmdline_info",
5882#endif
5883#ifdef FEAT_SIGNS
5884 "signs",
5885#endif
5886#ifdef FEAT_SMARTINDENT
5887 "smartindent",
5888#endif
5889#ifdef STARTUPTIME
5890 "startuptime",
5891#endif
5892#ifdef FEAT_STL_OPT
5893 "statusline",
5894#endif
5895#ifdef FEAT_SUN_WORKSHOP
5896 "sun_workshop",
5897#endif
5898#ifdef FEAT_NETBEANS_INTG
5899 "netbeans_intg",
5900#endif
5901#ifdef FEAT_SPELL
5902 "spell",
5903#endif
5904#ifdef FEAT_SYN_HL
5905 "syntax",
5906#endif
5907#if defined(USE_SYSTEM) || !defined(UNIX)
5908 "system",
5909#endif
5910#ifdef FEAT_TAG_BINS
5911 "tag_binary",
5912#endif
5913#ifdef FEAT_TAG_OLDSTATIC
5914 "tag_old_static",
5915#endif
5916#ifdef FEAT_TAG_ANYWHITE
5917 "tag_any_white",
5918#endif
5919#ifdef FEAT_TCL
5920# ifndef DYNAMIC_TCL
5921 "tcl",
5922# endif
5923#endif
5924#ifdef FEAT_TERMGUICOLORS
5925 "termguicolors",
5926#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +02005927#ifdef FEAT_TERMINAL
5928 "terminal",
5929#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005930#ifdef TERMINFO
5931 "terminfo",
5932#endif
5933#ifdef FEAT_TERMRESPONSE
5934 "termresponse",
5935#endif
5936#ifdef FEAT_TEXTOBJ
5937 "textobjects",
5938#endif
5939#ifdef HAVE_TGETENT
5940 "tgetent",
5941#endif
5942#ifdef FEAT_TIMERS
5943 "timers",
5944#endif
5945#ifdef FEAT_TITLE
5946 "title",
5947#endif
5948#ifdef FEAT_TOOLBAR
5949 "toolbar",
5950#endif
5951#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5952 "unnamedplus",
5953#endif
5954#ifdef FEAT_USR_CMDS
5955 "user-commands", /* was accidentally included in 5.4 */
5956 "user_commands",
5957#endif
5958#ifdef FEAT_VIMINFO
5959 "viminfo",
5960#endif
5961#ifdef FEAT_WINDOWS
5962 "vertsplit",
5963#endif
5964#ifdef FEAT_VIRTUALEDIT
5965 "virtualedit",
5966#endif
5967 "visual",
5968#ifdef FEAT_VISUALEXTRA
5969 "visualextra",
5970#endif
5971#ifdef FEAT_VREPLACE
5972 "vreplace",
5973#endif
5974#ifdef FEAT_WILDIGN
5975 "wildignore",
5976#endif
5977#ifdef FEAT_WILDMENU
5978 "wildmenu",
5979#endif
5980#ifdef FEAT_WINDOWS
5981 "windows",
5982#endif
5983#ifdef FEAT_WAK
5984 "winaltkeys",
5985#endif
5986#ifdef FEAT_WRITEBACKUP
5987 "writebackup",
5988#endif
5989#ifdef FEAT_XIM
5990 "xim",
5991#endif
5992#ifdef FEAT_XFONTSET
5993 "xfontset",
5994#endif
5995#ifdef FEAT_XPM_W32
5996 "xpm",
5997 "xpm_w32", /* for backward compatibility */
5998#else
5999# if defined(HAVE_XPM)
6000 "xpm",
6001# endif
6002#endif
6003#ifdef USE_XSMP
6004 "xsmp",
6005#endif
6006#ifdef USE_XSMP_INTERACT
6007 "xsmp_interact",
6008#endif
6009#ifdef FEAT_XCLIPBOARD
6010 "xterm_clipboard",
6011#endif
6012#ifdef FEAT_XTERM_SAVE
6013 "xterm_save",
6014#endif
6015#if defined(UNIX) && defined(FEAT_X11)
6016 "X11",
6017#endif
6018 NULL
6019 };
6020
6021 name = get_tv_string(&argvars[0]);
6022 for (i = 0; has_list[i] != NULL; ++i)
6023 if (STRICMP(name, has_list[i]) == 0)
6024 {
6025 n = TRUE;
6026 break;
6027 }
6028
6029 if (n == FALSE)
6030 {
6031 if (STRNICMP(name, "patch", 5) == 0)
6032 {
6033 if (name[5] == '-'
6034 && STRLEN(name) >= 11
6035 && vim_isdigit(name[6])
6036 && vim_isdigit(name[8])
6037 && vim_isdigit(name[10]))
6038 {
6039 int major = atoi((char *)name + 6);
6040 int minor = atoi((char *)name + 8);
6041
6042 /* Expect "patch-9.9.01234". */
6043 n = (major < VIM_VERSION_MAJOR
6044 || (major == VIM_VERSION_MAJOR
6045 && (minor < VIM_VERSION_MINOR
6046 || (minor == VIM_VERSION_MINOR
6047 && has_patch(atoi((char *)name + 10))))));
6048 }
6049 else
6050 n = has_patch(atoi((char *)name + 5));
6051 }
6052 else if (STRICMP(name, "vim_starting") == 0)
6053 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006054 else if (STRICMP(name, "ttyin") == 0)
6055 n = mch_input_isatty();
6056 else if (STRICMP(name, "ttyout") == 0)
6057 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006058#ifdef FEAT_MBYTE
6059 else if (STRICMP(name, "multi_byte_encoding") == 0)
6060 n = has_mbyte;
6061#endif
6062#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6063 else if (STRICMP(name, "balloon_multiline") == 0)
6064 n = multiline_balloon_available();
6065#endif
6066#ifdef DYNAMIC_TCL
6067 else if (STRICMP(name, "tcl") == 0)
6068 n = tcl_enabled(FALSE);
6069#endif
6070#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6071 else if (STRICMP(name, "iconv") == 0)
6072 n = iconv_enabled(FALSE);
6073#endif
6074#ifdef DYNAMIC_LUA
6075 else if (STRICMP(name, "lua") == 0)
6076 n = lua_enabled(FALSE);
6077#endif
6078#ifdef DYNAMIC_MZSCHEME
6079 else if (STRICMP(name, "mzscheme") == 0)
6080 n = mzscheme_enabled(FALSE);
6081#endif
6082#ifdef DYNAMIC_RUBY
6083 else if (STRICMP(name, "ruby") == 0)
6084 n = ruby_enabled(FALSE);
6085#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006086#ifdef DYNAMIC_PYTHON
6087 else if (STRICMP(name, "python") == 0)
6088 n = python_enabled(FALSE);
6089#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090#ifdef DYNAMIC_PYTHON3
6091 else if (STRICMP(name, "python3") == 0)
6092 n = python3_enabled(FALSE);
6093#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006094#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6095 else if (STRICMP(name, "pythonx") == 0)
6096 {
6097# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6098 if (p_pyx == 0)
6099 n = python3_enabled(FALSE) || python_enabled(FALSE);
6100 else if (p_pyx == 3)
6101 n = python3_enabled(FALSE);
6102 else if (p_pyx == 2)
6103 n = python_enabled(FALSE);
6104# elif defined(DYNAMIC_PYTHON)
6105 n = python_enabled(FALSE);
6106# elif defined(DYNAMIC_PYTHON3)
6107 n = python3_enabled(FALSE);
6108# endif
6109 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006110#endif
6111#ifdef DYNAMIC_PERL
6112 else if (STRICMP(name, "perl") == 0)
6113 n = perl_enabled(FALSE);
6114#endif
6115#ifdef FEAT_GUI
6116 else if (STRICMP(name, "gui_running") == 0)
6117 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006118# ifdef FEAT_BROWSE
6119 else if (STRICMP(name, "browse") == 0)
6120 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6121# endif
6122#endif
6123#ifdef FEAT_SYN_HL
6124 else if (STRICMP(name, "syntax_items") == 0)
6125 n = syntax_present(curwin);
6126#endif
6127#if defined(WIN3264)
6128 else if (STRICMP(name, "win95") == 0)
Bram Moolenaarcea912a2016-10-12 14:20:24 +02006129 n = FALSE; /* Win9x is no more supported. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006130#endif
6131#ifdef FEAT_NETBEANS_INTG
6132 else if (STRICMP(name, "netbeans_enabled") == 0)
6133 n = netbeans_active();
6134#endif
6135 }
6136
6137 rettv->vval.v_number = n;
6138}
6139
6140/*
6141 * "has_key()" function
6142 */
6143 static void
6144f_has_key(typval_T *argvars, typval_T *rettv)
6145{
6146 if (argvars[0].v_type != VAR_DICT)
6147 {
6148 EMSG(_(e_dictreq));
6149 return;
6150 }
6151 if (argvars[0].vval.v_dict == NULL)
6152 return;
6153
6154 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6155 get_tv_string(&argvars[1]), -1) != NULL;
6156}
6157
6158/*
6159 * "haslocaldir()" function
6160 */
6161 static void
6162f_haslocaldir(typval_T *argvars, typval_T *rettv)
6163{
6164 win_T *wp = NULL;
6165
6166 wp = find_tabwin(&argvars[0], &argvars[1]);
6167 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6168}
6169
6170/*
6171 * "hasmapto()" function
6172 */
6173 static void
6174f_hasmapto(typval_T *argvars, typval_T *rettv)
6175{
6176 char_u *name;
6177 char_u *mode;
6178 char_u buf[NUMBUFLEN];
6179 int abbr = FALSE;
6180
6181 name = get_tv_string(&argvars[0]);
6182 if (argvars[1].v_type == VAR_UNKNOWN)
6183 mode = (char_u *)"nvo";
6184 else
6185 {
6186 mode = get_tv_string_buf(&argvars[1], buf);
6187 if (argvars[2].v_type != VAR_UNKNOWN)
6188 abbr = (int)get_tv_number(&argvars[2]);
6189 }
6190
6191 if (map_to_exists(name, mode, abbr))
6192 rettv->vval.v_number = TRUE;
6193 else
6194 rettv->vval.v_number = FALSE;
6195}
6196
6197/*
6198 * "histadd()" function
6199 */
6200 static void
6201f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6202{
6203#ifdef FEAT_CMDHIST
6204 int histype;
6205 char_u *str;
6206 char_u buf[NUMBUFLEN];
6207#endif
6208
6209 rettv->vval.v_number = FALSE;
6210 if (check_restricted() || check_secure())
6211 return;
6212#ifdef FEAT_CMDHIST
6213 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6214 histype = str != NULL ? get_histtype(str) : -1;
6215 if (histype >= 0)
6216 {
6217 str = get_tv_string_buf(&argvars[1], buf);
6218 if (*str != NUL)
6219 {
6220 init_history();
6221 add_to_history(histype, str, FALSE, NUL);
6222 rettv->vval.v_number = TRUE;
6223 return;
6224 }
6225 }
6226#endif
6227}
6228
6229/*
6230 * "histdel()" function
6231 */
6232 static void
6233f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6234{
6235#ifdef FEAT_CMDHIST
6236 int n;
6237 char_u buf[NUMBUFLEN];
6238 char_u *str;
6239
6240 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6241 if (str == NULL)
6242 n = 0;
6243 else if (argvars[1].v_type == VAR_UNKNOWN)
6244 /* only one argument: clear entire history */
6245 n = clr_history(get_histtype(str));
6246 else if (argvars[1].v_type == VAR_NUMBER)
6247 /* index given: remove that entry */
6248 n = del_history_idx(get_histtype(str),
6249 (int)get_tv_number(&argvars[1]));
6250 else
6251 /* string given: remove all matching entries */
6252 n = del_history_entry(get_histtype(str),
6253 get_tv_string_buf(&argvars[1], buf));
6254 rettv->vval.v_number = n;
6255#endif
6256}
6257
6258/*
6259 * "histget()" function
6260 */
6261 static void
6262f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6263{
6264#ifdef FEAT_CMDHIST
6265 int type;
6266 int idx;
6267 char_u *str;
6268
6269 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6270 if (str == NULL)
6271 rettv->vval.v_string = NULL;
6272 else
6273 {
6274 type = get_histtype(str);
6275 if (argvars[1].v_type == VAR_UNKNOWN)
6276 idx = get_history_idx(type);
6277 else
6278 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6279 /* -1 on type error */
6280 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6281 }
6282#else
6283 rettv->vval.v_string = NULL;
6284#endif
6285 rettv->v_type = VAR_STRING;
6286}
6287
6288/*
6289 * "histnr()" function
6290 */
6291 static void
6292f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6293{
6294 int i;
6295
6296#ifdef FEAT_CMDHIST
6297 char_u *history = get_tv_string_chk(&argvars[0]);
6298
6299 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6300 if (i >= HIST_CMD && i < HIST_COUNT)
6301 i = get_history_idx(i);
6302 else
6303#endif
6304 i = -1;
6305 rettv->vval.v_number = i;
6306}
6307
6308/*
6309 * "highlightID(name)" function
6310 */
6311 static void
6312f_hlID(typval_T *argvars, typval_T *rettv)
6313{
6314 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6315}
6316
6317/*
6318 * "highlight_exists()" function
6319 */
6320 static void
6321f_hlexists(typval_T *argvars, typval_T *rettv)
6322{
6323 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6324}
6325
6326/*
6327 * "hostname()" function
6328 */
6329 static void
6330f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6331{
6332 char_u hostname[256];
6333
6334 mch_get_host_name(hostname, 256);
6335 rettv->v_type = VAR_STRING;
6336 rettv->vval.v_string = vim_strsave(hostname);
6337}
6338
6339/*
6340 * iconv() function
6341 */
6342 static void
6343f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6344{
6345#ifdef FEAT_MBYTE
6346 char_u buf1[NUMBUFLEN];
6347 char_u buf2[NUMBUFLEN];
6348 char_u *from, *to, *str;
6349 vimconv_T vimconv;
6350#endif
6351
6352 rettv->v_type = VAR_STRING;
6353 rettv->vval.v_string = NULL;
6354
6355#ifdef FEAT_MBYTE
6356 str = get_tv_string(&argvars[0]);
6357 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6358 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6359 vimconv.vc_type = CONV_NONE;
6360 convert_setup(&vimconv, from, to);
6361
6362 /* If the encodings are equal, no conversion needed. */
6363 if (vimconv.vc_type == CONV_NONE)
6364 rettv->vval.v_string = vim_strsave(str);
6365 else
6366 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6367
6368 convert_setup(&vimconv, NULL, NULL);
6369 vim_free(from);
6370 vim_free(to);
6371#endif
6372}
6373
6374/*
6375 * "indent()" function
6376 */
6377 static void
6378f_indent(typval_T *argvars, typval_T *rettv)
6379{
6380 linenr_T lnum;
6381
6382 lnum = get_tv_lnum(argvars);
6383 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6384 rettv->vval.v_number = get_indent_lnum(lnum);
6385 else
6386 rettv->vval.v_number = -1;
6387}
6388
6389/*
6390 * "index()" function
6391 */
6392 static void
6393f_index(typval_T *argvars, typval_T *rettv)
6394{
6395 list_T *l;
6396 listitem_T *item;
6397 long idx = 0;
6398 int ic = FALSE;
6399
6400 rettv->vval.v_number = -1;
6401 if (argvars[0].v_type != VAR_LIST)
6402 {
6403 EMSG(_(e_listreq));
6404 return;
6405 }
6406 l = argvars[0].vval.v_list;
6407 if (l != NULL)
6408 {
6409 item = l->lv_first;
6410 if (argvars[2].v_type != VAR_UNKNOWN)
6411 {
6412 int error = FALSE;
6413
6414 /* Start at specified item. Use the cached index that list_find()
6415 * sets, so that a negative number also works. */
6416 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6417 idx = l->lv_idx;
6418 if (argvars[3].v_type != VAR_UNKNOWN)
6419 ic = (int)get_tv_number_chk(&argvars[3], &error);
6420 if (error)
6421 item = NULL;
6422 }
6423
6424 for ( ; item != NULL; item = item->li_next, ++idx)
6425 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6426 {
6427 rettv->vval.v_number = idx;
6428 break;
6429 }
6430 }
6431}
6432
6433static int inputsecret_flag = 0;
6434
6435/*
6436 * "input()" function
6437 * Also handles inputsecret() when inputsecret is set.
6438 */
6439 static void
6440f_input(typval_T *argvars, typval_T *rettv)
6441{
6442 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6443}
6444
6445/*
6446 * "inputdialog()" function
6447 */
6448 static void
6449f_inputdialog(typval_T *argvars, typval_T *rettv)
6450{
6451#if defined(FEAT_GUI_TEXTDIALOG)
6452 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6453 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6454 {
6455 char_u *message;
6456 char_u buf[NUMBUFLEN];
6457 char_u *defstr = (char_u *)"";
6458
6459 message = get_tv_string_chk(&argvars[0]);
6460 if (argvars[1].v_type != VAR_UNKNOWN
6461 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6462 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6463 else
6464 IObuff[0] = NUL;
6465 if (message != NULL && defstr != NULL
6466 && do_dialog(VIM_QUESTION, NULL, message,
6467 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6468 rettv->vval.v_string = vim_strsave(IObuff);
6469 else
6470 {
6471 if (message != NULL && defstr != NULL
6472 && argvars[1].v_type != VAR_UNKNOWN
6473 && argvars[2].v_type != VAR_UNKNOWN)
6474 rettv->vval.v_string = vim_strsave(
6475 get_tv_string_buf(&argvars[2], buf));
6476 else
6477 rettv->vval.v_string = NULL;
6478 }
6479 rettv->v_type = VAR_STRING;
6480 }
6481 else
6482#endif
6483 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6484}
6485
6486/*
6487 * "inputlist()" function
6488 */
6489 static void
6490f_inputlist(typval_T *argvars, typval_T *rettv)
6491{
6492 listitem_T *li;
6493 int selected;
6494 int mouse_used;
6495
6496#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006497 /* While starting up, there is no place to enter text. When running tests
6498 * with --not-a-term we assume feedkeys() will be used. */
6499 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500 return;
6501#endif
6502 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6503 {
6504 EMSG2(_(e_listarg), "inputlist()");
6505 return;
6506 }
6507
6508 msg_start();
6509 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6510 lines_left = Rows; /* avoid more prompt */
6511 msg_scroll = TRUE;
6512 msg_clr_eos();
6513
6514 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6515 {
6516 msg_puts(get_tv_string(&li->li_tv));
6517 msg_putchar('\n');
6518 }
6519
6520 /* Ask for choice. */
6521 selected = prompt_for_number(&mouse_used);
6522 if (mouse_used)
6523 selected -= lines_left;
6524
6525 rettv->vval.v_number = selected;
6526}
6527
6528
6529static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6530
6531/*
6532 * "inputrestore()" function
6533 */
6534 static void
6535f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6536{
6537 if (ga_userinput.ga_len > 0)
6538 {
6539 --ga_userinput.ga_len;
6540 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6541 + ga_userinput.ga_len);
6542 /* default return is zero == OK */
6543 }
6544 else if (p_verbose > 1)
6545 {
6546 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6547 rettv->vval.v_number = 1; /* Failed */
6548 }
6549}
6550
6551/*
6552 * "inputsave()" function
6553 */
6554 static void
6555f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6556{
6557 /* Add an entry to the stack of typeahead storage. */
6558 if (ga_grow(&ga_userinput, 1) == OK)
6559 {
6560 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6561 + ga_userinput.ga_len);
6562 ++ga_userinput.ga_len;
6563 /* default return is zero == OK */
6564 }
6565 else
6566 rettv->vval.v_number = 1; /* Failed */
6567}
6568
6569/*
6570 * "inputsecret()" function
6571 */
6572 static void
6573f_inputsecret(typval_T *argvars, typval_T *rettv)
6574{
6575 ++cmdline_star;
6576 ++inputsecret_flag;
6577 f_input(argvars, rettv);
6578 --cmdline_star;
6579 --inputsecret_flag;
6580}
6581
6582/*
6583 * "insert()" function
6584 */
6585 static void
6586f_insert(typval_T *argvars, typval_T *rettv)
6587{
6588 long before = 0;
6589 listitem_T *item;
6590 list_T *l;
6591 int error = FALSE;
6592
6593 if (argvars[0].v_type != VAR_LIST)
6594 EMSG2(_(e_listarg), "insert()");
6595 else if ((l = argvars[0].vval.v_list) != NULL
6596 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6597 {
6598 if (argvars[2].v_type != VAR_UNKNOWN)
6599 before = (long)get_tv_number_chk(&argvars[2], &error);
6600 if (error)
6601 return; /* type error; errmsg already given */
6602
6603 if (before == l->lv_len)
6604 item = NULL;
6605 else
6606 {
6607 item = list_find(l, before);
6608 if (item == NULL)
6609 {
6610 EMSGN(_(e_listidx), before);
6611 l = NULL;
6612 }
6613 }
6614 if (l != NULL)
6615 {
6616 list_insert_tv(l, &argvars[1], item);
6617 copy_tv(&argvars[0], rettv);
6618 }
6619 }
6620}
6621
6622/*
6623 * "invert(expr)" function
6624 */
6625 static void
6626f_invert(typval_T *argvars, typval_T *rettv)
6627{
6628 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6629}
6630
6631/*
6632 * "isdirectory()" function
6633 */
6634 static void
6635f_isdirectory(typval_T *argvars, typval_T *rettv)
6636{
6637 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6638}
6639
6640/*
6641 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6642 * or it refers to a List or Dictionary that is locked.
6643 */
6644 static int
6645tv_islocked(typval_T *tv)
6646{
6647 return (tv->v_lock & VAR_LOCKED)
6648 || (tv->v_type == VAR_LIST
6649 && tv->vval.v_list != NULL
6650 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6651 || (tv->v_type == VAR_DICT
6652 && tv->vval.v_dict != NULL
6653 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6654}
6655
6656/*
6657 * "islocked()" function
6658 */
6659 static void
6660f_islocked(typval_T *argvars, typval_T *rettv)
6661{
6662 lval_T lv;
6663 char_u *end;
6664 dictitem_T *di;
6665
6666 rettv->vval.v_number = -1;
6667 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006668 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006669 if (end != NULL && lv.ll_name != NULL)
6670 {
6671 if (*end != NUL)
6672 EMSG(_(e_trailing));
6673 else
6674 {
6675 if (lv.ll_tv == NULL)
6676 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006677 di = find_var(lv.ll_name, NULL, TRUE);
6678 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006679 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006680 /* Consider a variable locked when:
6681 * 1. the variable itself is locked
6682 * 2. the value of the variable is locked.
6683 * 3. the List or Dict value is locked.
6684 */
6685 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6686 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006687 }
6688 }
6689 else if (lv.ll_range)
6690 EMSG(_("E786: Range not allowed"));
6691 else if (lv.ll_newkey != NULL)
6692 EMSG2(_(e_dictkey), lv.ll_newkey);
6693 else if (lv.ll_list != NULL)
6694 /* List item. */
6695 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6696 else
6697 /* Dictionary item. */
6698 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6699 }
6700 }
6701
6702 clear_lval(&lv);
6703}
6704
6705#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6706/*
6707 * "isnan()" function
6708 */
6709 static void
6710f_isnan(typval_T *argvars, typval_T *rettv)
6711{
6712 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6713 && isnan(argvars[0].vval.v_float);
6714}
6715#endif
6716
6717/*
6718 * "items(dict)" function
6719 */
6720 static void
6721f_items(typval_T *argvars, typval_T *rettv)
6722{
6723 dict_list(argvars, rettv, 2);
6724}
6725
6726#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6727/*
6728 * Get the job from the argument.
6729 * Returns NULL if the job is invalid.
6730 */
6731 static job_T *
6732get_job_arg(typval_T *tv)
6733{
6734 job_T *job;
6735
6736 if (tv->v_type != VAR_JOB)
6737 {
6738 EMSG2(_(e_invarg2), get_tv_string(tv));
6739 return NULL;
6740 }
6741 job = tv->vval.v_job;
6742
6743 if (job == NULL)
6744 EMSG(_("E916: not a valid job"));
6745 return job;
6746}
6747
6748/*
6749 * "job_getchannel()" function
6750 */
6751 static void
6752f_job_getchannel(typval_T *argvars, typval_T *rettv)
6753{
6754 job_T *job = get_job_arg(&argvars[0]);
6755
6756 if (job != NULL)
6757 {
6758 rettv->v_type = VAR_CHANNEL;
6759 rettv->vval.v_channel = job->jv_channel;
6760 if (job->jv_channel != NULL)
6761 ++job->jv_channel->ch_refcount;
6762 }
6763}
6764
6765/*
6766 * "job_info()" function
6767 */
6768 static void
6769f_job_info(typval_T *argvars, typval_T *rettv)
6770{
6771 job_T *job = get_job_arg(&argvars[0]);
6772
6773 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6774 job_info(job, rettv->vval.v_dict);
6775}
6776
6777/*
6778 * "job_setoptions()" function
6779 */
6780 static void
6781f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6782{
6783 job_T *job = get_job_arg(&argvars[0]);
6784 jobopt_T opt;
6785
6786 if (job == NULL)
6787 return;
6788 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02006789 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006790 job_set_options(job, &opt);
6791 free_job_options(&opt);
6792}
6793
6794/*
6795 * "job_start()" function
6796 */
6797 static void
6798f_job_start(typval_T *argvars, typval_T *rettv)
6799{
6800 rettv->v_type = VAR_JOB;
6801 if (check_restricted() || check_secure())
6802 return;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006803 rettv->vval.v_job = job_start(argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804}
6805
6806/*
6807 * "job_status()" function
6808 */
6809 static void
6810f_job_status(typval_T *argvars, typval_T *rettv)
6811{
6812 job_T *job = get_job_arg(&argvars[0]);
6813
6814 if (job != NULL)
6815 {
6816 rettv->v_type = VAR_STRING;
6817 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6818 }
6819}
6820
6821/*
6822 * "job_stop()" function
6823 */
6824 static void
6825f_job_stop(typval_T *argvars, typval_T *rettv)
6826{
6827 job_T *job = get_job_arg(&argvars[0]);
6828
6829 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006830 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831}
6832#endif
6833
6834/*
6835 * "join()" function
6836 */
6837 static void
6838f_join(typval_T *argvars, typval_T *rettv)
6839{
6840 garray_T ga;
6841 char_u *sep;
6842
6843 if (argvars[0].v_type != VAR_LIST)
6844 {
6845 EMSG(_(e_listreq));
6846 return;
6847 }
6848 if (argvars[0].vval.v_list == NULL)
6849 return;
6850 if (argvars[1].v_type == VAR_UNKNOWN)
6851 sep = (char_u *)" ";
6852 else
6853 sep = get_tv_string_chk(&argvars[1]);
6854
6855 rettv->v_type = VAR_STRING;
6856
6857 if (sep != NULL)
6858 {
6859 ga_init2(&ga, (int)sizeof(char), 80);
6860 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6861 ga_append(&ga, NUL);
6862 rettv->vval.v_string = (char_u *)ga.ga_data;
6863 }
6864 else
6865 rettv->vval.v_string = NULL;
6866}
6867
6868/*
6869 * "js_decode()" function
6870 */
6871 static void
6872f_js_decode(typval_T *argvars, typval_T *rettv)
6873{
6874 js_read_T reader;
6875
6876 reader.js_buf = get_tv_string(&argvars[0]);
6877 reader.js_fill = NULL;
6878 reader.js_used = 0;
6879 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6880 EMSG(_(e_invarg));
6881}
6882
6883/*
6884 * "js_encode()" function
6885 */
6886 static void
6887f_js_encode(typval_T *argvars, typval_T *rettv)
6888{
6889 rettv->v_type = VAR_STRING;
6890 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6891}
6892
6893/*
6894 * "json_decode()" function
6895 */
6896 static void
6897f_json_decode(typval_T *argvars, typval_T *rettv)
6898{
6899 js_read_T reader;
6900
6901 reader.js_buf = get_tv_string(&argvars[0]);
6902 reader.js_fill = NULL;
6903 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01006904 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006905}
6906
6907/*
6908 * "json_encode()" function
6909 */
6910 static void
6911f_json_encode(typval_T *argvars, typval_T *rettv)
6912{
6913 rettv->v_type = VAR_STRING;
6914 rettv->vval.v_string = json_encode(&argvars[0], 0);
6915}
6916
6917/*
6918 * "keys()" function
6919 */
6920 static void
6921f_keys(typval_T *argvars, typval_T *rettv)
6922{
6923 dict_list(argvars, rettv, 0);
6924}
6925
6926/*
6927 * "last_buffer_nr()" function.
6928 */
6929 static void
6930f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6931{
6932 int n = 0;
6933 buf_T *buf;
6934
Bram Moolenaar29323592016-07-24 22:04:11 +02006935 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 if (n < buf->b_fnum)
6937 n = buf->b_fnum;
6938
6939 rettv->vval.v_number = n;
6940}
6941
6942/*
6943 * "len()" function
6944 */
6945 static void
6946f_len(typval_T *argvars, typval_T *rettv)
6947{
6948 switch (argvars[0].v_type)
6949 {
6950 case VAR_STRING:
6951 case VAR_NUMBER:
6952 rettv->vval.v_number = (varnumber_T)STRLEN(
6953 get_tv_string(&argvars[0]));
6954 break;
6955 case VAR_LIST:
6956 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6957 break;
6958 case VAR_DICT:
6959 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6960 break;
6961 case VAR_UNKNOWN:
6962 case VAR_SPECIAL:
6963 case VAR_FLOAT:
6964 case VAR_FUNC:
6965 case VAR_PARTIAL:
6966 case VAR_JOB:
6967 case VAR_CHANNEL:
6968 EMSG(_("E701: Invalid type for len()"));
6969 break;
6970 }
6971}
6972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006973 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006974libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975{
6976#ifdef FEAT_LIBCALL
6977 char_u *string_in;
6978 char_u **string_result;
6979 int nr_result;
6980#endif
6981
6982 rettv->v_type = type;
6983 if (type != VAR_NUMBER)
6984 rettv->vval.v_string = NULL;
6985
6986 if (check_restricted() || check_secure())
6987 return;
6988
6989#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006990 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6992 {
6993 string_in = NULL;
6994 if (argvars[2].v_type == VAR_STRING)
6995 string_in = argvars[2].vval.v_string;
6996 if (type == VAR_NUMBER)
6997 string_result = NULL;
6998 else
6999 string_result = &rettv->vval.v_string;
7000 if (mch_libcall(argvars[0].vval.v_string,
7001 argvars[1].vval.v_string,
7002 string_in,
7003 argvars[2].vval.v_number,
7004 string_result,
7005 &nr_result) == OK
7006 && type == VAR_NUMBER)
7007 rettv->vval.v_number = nr_result;
7008 }
7009#endif
7010}
7011
7012/*
7013 * "libcall()" function
7014 */
7015 static void
7016f_libcall(typval_T *argvars, typval_T *rettv)
7017{
7018 libcall_common(argvars, rettv, VAR_STRING);
7019}
7020
7021/*
7022 * "libcallnr()" function
7023 */
7024 static void
7025f_libcallnr(typval_T *argvars, typval_T *rettv)
7026{
7027 libcall_common(argvars, rettv, VAR_NUMBER);
7028}
7029
7030/*
7031 * "line(string)" function
7032 */
7033 static void
7034f_line(typval_T *argvars, typval_T *rettv)
7035{
7036 linenr_T lnum = 0;
7037 pos_T *fp;
7038 int fnum;
7039
7040 fp = var2fpos(&argvars[0], TRUE, &fnum);
7041 if (fp != NULL)
7042 lnum = fp->lnum;
7043 rettv->vval.v_number = lnum;
7044}
7045
7046/*
7047 * "line2byte(lnum)" function
7048 */
7049 static void
7050f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7051{
7052#ifndef FEAT_BYTEOFF
7053 rettv->vval.v_number = -1;
7054#else
7055 linenr_T lnum;
7056
7057 lnum = get_tv_lnum(argvars);
7058 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7059 rettv->vval.v_number = -1;
7060 else
7061 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7062 if (rettv->vval.v_number >= 0)
7063 ++rettv->vval.v_number;
7064#endif
7065}
7066
7067/*
7068 * "lispindent(lnum)" function
7069 */
7070 static void
7071f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7072{
7073#ifdef FEAT_LISP
7074 pos_T pos;
7075 linenr_T lnum;
7076
7077 pos = curwin->w_cursor;
7078 lnum = get_tv_lnum(argvars);
7079 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7080 {
7081 curwin->w_cursor.lnum = lnum;
7082 rettv->vval.v_number = get_lisp_indent();
7083 curwin->w_cursor = pos;
7084 }
7085 else
7086#endif
7087 rettv->vval.v_number = -1;
7088}
7089
7090/*
7091 * "localtime()" function
7092 */
7093 static void
7094f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7095{
7096 rettv->vval.v_number = (varnumber_T)time(NULL);
7097}
7098
7099static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7100
7101 static void
7102get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7103{
7104 char_u *keys;
7105 char_u *which;
7106 char_u buf[NUMBUFLEN];
7107 char_u *keys_buf = NULL;
7108 char_u *rhs;
7109 int mode;
7110 int abbr = FALSE;
7111 int get_dict = FALSE;
7112 mapblock_T *mp;
7113 int buffer_local;
7114
7115 /* return empty string for failure */
7116 rettv->v_type = VAR_STRING;
7117 rettv->vval.v_string = NULL;
7118
7119 keys = get_tv_string(&argvars[0]);
7120 if (*keys == NUL)
7121 return;
7122
7123 if (argvars[1].v_type != VAR_UNKNOWN)
7124 {
7125 which = get_tv_string_buf_chk(&argvars[1], buf);
7126 if (argvars[2].v_type != VAR_UNKNOWN)
7127 {
7128 abbr = (int)get_tv_number(&argvars[2]);
7129 if (argvars[3].v_type != VAR_UNKNOWN)
7130 get_dict = (int)get_tv_number(&argvars[3]);
7131 }
7132 }
7133 else
7134 which = (char_u *)"";
7135 if (which == NULL)
7136 return;
7137
7138 mode = get_map_mode(&which, 0);
7139
7140 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7141 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7142 vim_free(keys_buf);
7143
7144 if (!get_dict)
7145 {
7146 /* Return a string. */
7147 if (rhs != NULL)
7148 rettv->vval.v_string = str2special_save(rhs, FALSE);
7149
7150 }
7151 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7152 {
7153 /* Return a dictionary. */
7154 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7155 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7156 dict_T *dict = rettv->vval.v_dict;
7157
7158 dict_add_nr_str(dict, "lhs", 0L, lhs);
7159 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7160 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7161 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7162 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7163 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7164 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7165 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7166 dict_add_nr_str(dict, "mode", 0L, mapmode);
7167
7168 vim_free(lhs);
7169 vim_free(mapmode);
7170 }
7171}
7172
7173#ifdef FEAT_FLOAT
7174/*
7175 * "log()" function
7176 */
7177 static void
7178f_log(typval_T *argvars, typval_T *rettv)
7179{
7180 float_T f = 0.0;
7181
7182 rettv->v_type = VAR_FLOAT;
7183 if (get_float_arg(argvars, &f) == OK)
7184 rettv->vval.v_float = log(f);
7185 else
7186 rettv->vval.v_float = 0.0;
7187}
7188
7189/*
7190 * "log10()" function
7191 */
7192 static void
7193f_log10(typval_T *argvars, typval_T *rettv)
7194{
7195 float_T f = 0.0;
7196
7197 rettv->v_type = VAR_FLOAT;
7198 if (get_float_arg(argvars, &f) == OK)
7199 rettv->vval.v_float = log10(f);
7200 else
7201 rettv->vval.v_float = 0.0;
7202}
7203#endif
7204
7205#ifdef FEAT_LUA
7206/*
7207 * "luaeval()" function
7208 */
7209 static void
7210f_luaeval(typval_T *argvars, typval_T *rettv)
7211{
7212 char_u *str;
7213 char_u buf[NUMBUFLEN];
7214
7215 str = get_tv_string_buf(&argvars[0], buf);
7216 do_luaeval(str, argvars + 1, rettv);
7217}
7218#endif
7219
7220/*
7221 * "map()" function
7222 */
7223 static void
7224f_map(typval_T *argvars, typval_T *rettv)
7225{
7226 filter_map(argvars, rettv, TRUE);
7227}
7228
7229/*
7230 * "maparg()" function
7231 */
7232 static void
7233f_maparg(typval_T *argvars, typval_T *rettv)
7234{
7235 get_maparg(argvars, rettv, TRUE);
7236}
7237
7238/*
7239 * "mapcheck()" function
7240 */
7241 static void
7242f_mapcheck(typval_T *argvars, typval_T *rettv)
7243{
7244 get_maparg(argvars, rettv, FALSE);
7245}
7246
7247static void find_some_match(typval_T *argvars, typval_T *rettv, int start);
7248
7249 static void
7250find_some_match(typval_T *argvars, typval_T *rettv, int type)
7251{
7252 char_u *str = NULL;
7253 long len = 0;
7254 char_u *expr = NULL;
7255 char_u *pat;
7256 regmatch_T regmatch;
7257 char_u patbuf[NUMBUFLEN];
7258 char_u strbuf[NUMBUFLEN];
7259 char_u *save_cpo;
7260 long start = 0;
7261 long nth = 1;
7262 colnr_T startcol = 0;
7263 int match = 0;
7264 list_T *l = NULL;
7265 listitem_T *li = NULL;
7266 long idx = 0;
7267 char_u *tofree = NULL;
7268
7269 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7270 save_cpo = p_cpo;
7271 p_cpo = (char_u *)"";
7272
7273 rettv->vval.v_number = -1;
7274 if (type == 3 || type == 4)
7275 {
7276 /* type 3: return empty list when there are no matches.
7277 * type 4: return ["", -1, -1, -1] */
7278 if (rettv_list_alloc(rettv) == FAIL)
7279 goto theend;
7280 if (type == 4
7281 && (list_append_string(rettv->vval.v_list,
7282 (char_u *)"", 0) == FAIL
7283 || list_append_number(rettv->vval.v_list,
7284 (varnumber_T)-1) == FAIL
7285 || list_append_number(rettv->vval.v_list,
7286 (varnumber_T)-1) == FAIL
7287 || list_append_number(rettv->vval.v_list,
7288 (varnumber_T)-1) == FAIL))
7289 {
7290 list_free(rettv->vval.v_list);
7291 rettv->vval.v_list = NULL;
7292 goto theend;
7293 }
7294 }
7295 else if (type == 2)
7296 {
7297 rettv->v_type = VAR_STRING;
7298 rettv->vval.v_string = NULL;
7299 }
7300
7301 if (argvars[0].v_type == VAR_LIST)
7302 {
7303 if ((l = argvars[0].vval.v_list) == NULL)
7304 goto theend;
7305 li = l->lv_first;
7306 }
7307 else
7308 {
7309 expr = str = get_tv_string(&argvars[0]);
7310 len = (long)STRLEN(str);
7311 }
7312
7313 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7314 if (pat == NULL)
7315 goto theend;
7316
7317 if (argvars[2].v_type != VAR_UNKNOWN)
7318 {
7319 int error = FALSE;
7320
7321 start = (long)get_tv_number_chk(&argvars[2], &error);
7322 if (error)
7323 goto theend;
7324 if (l != NULL)
7325 {
7326 li = list_find(l, start);
7327 if (li == NULL)
7328 goto theend;
7329 idx = l->lv_idx; /* use the cached index */
7330 }
7331 else
7332 {
7333 if (start < 0)
7334 start = 0;
7335 if (start > len)
7336 goto theend;
7337 /* When "count" argument is there ignore matches before "start",
7338 * otherwise skip part of the string. Differs when pattern is "^"
7339 * or "\<". */
7340 if (argvars[3].v_type != VAR_UNKNOWN)
7341 startcol = start;
7342 else
7343 {
7344 str += start;
7345 len -= start;
7346 }
7347 }
7348
7349 if (argvars[3].v_type != VAR_UNKNOWN)
7350 nth = (long)get_tv_number_chk(&argvars[3], &error);
7351 if (error)
7352 goto theend;
7353 }
7354
7355 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7356 if (regmatch.regprog != NULL)
7357 {
7358 regmatch.rm_ic = p_ic;
7359
7360 for (;;)
7361 {
7362 if (l != NULL)
7363 {
7364 if (li == NULL)
7365 {
7366 match = FALSE;
7367 break;
7368 }
7369 vim_free(tofree);
7370 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7371 if (str == NULL)
7372 break;
7373 }
7374
7375 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7376
7377 if (match && --nth <= 0)
7378 break;
7379 if (l == NULL && !match)
7380 break;
7381
7382 /* Advance to just after the match. */
7383 if (l != NULL)
7384 {
7385 li = li->li_next;
7386 ++idx;
7387 }
7388 else
7389 {
7390#ifdef FEAT_MBYTE
7391 startcol = (colnr_T)(regmatch.startp[0]
7392 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7393#else
7394 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7395#endif
7396 if (startcol > (colnr_T)len
7397 || str + startcol <= regmatch.startp[0])
7398 {
7399 match = FALSE;
7400 break;
7401 }
7402 }
7403 }
7404
7405 if (match)
7406 {
7407 if (type == 4)
7408 {
7409 listitem_T *li1 = rettv->vval.v_list->lv_first;
7410 listitem_T *li2 = li1->li_next;
7411 listitem_T *li3 = li2->li_next;
7412 listitem_T *li4 = li3->li_next;
7413
7414 vim_free(li1->li_tv.vval.v_string);
7415 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7416 (int)(regmatch.endp[0] - regmatch.startp[0]));
7417 li3->li_tv.vval.v_number =
7418 (varnumber_T)(regmatch.startp[0] - expr);
7419 li4->li_tv.vval.v_number =
7420 (varnumber_T)(regmatch.endp[0] - expr);
7421 if (l != NULL)
7422 li2->li_tv.vval.v_number = (varnumber_T)idx;
7423 }
7424 else if (type == 3)
7425 {
7426 int i;
7427
7428 /* return list with matched string and submatches */
7429 for (i = 0; i < NSUBEXP; ++i)
7430 {
7431 if (regmatch.endp[i] == NULL)
7432 {
7433 if (list_append_string(rettv->vval.v_list,
7434 (char_u *)"", 0) == FAIL)
7435 break;
7436 }
7437 else if (list_append_string(rettv->vval.v_list,
7438 regmatch.startp[i],
7439 (int)(regmatch.endp[i] - regmatch.startp[i]))
7440 == FAIL)
7441 break;
7442 }
7443 }
7444 else if (type == 2)
7445 {
7446 /* return matched string */
7447 if (l != NULL)
7448 copy_tv(&li->li_tv, rettv);
7449 else
7450 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7451 (int)(regmatch.endp[0] - regmatch.startp[0]));
7452 }
7453 else if (l != NULL)
7454 rettv->vval.v_number = idx;
7455 else
7456 {
7457 if (type != 0)
7458 rettv->vval.v_number =
7459 (varnumber_T)(regmatch.startp[0] - str);
7460 else
7461 rettv->vval.v_number =
7462 (varnumber_T)(regmatch.endp[0] - str);
7463 rettv->vval.v_number += (varnumber_T)(str - expr);
7464 }
7465 }
7466 vim_regfree(regmatch.regprog);
7467 }
7468
7469 if (type == 4 && l == NULL)
7470 /* matchstrpos() without a list: drop the second item. */
7471 listitem_remove(rettv->vval.v_list,
7472 rettv->vval.v_list->lv_first->li_next);
7473
7474theend:
7475 vim_free(tofree);
7476 p_cpo = save_cpo;
7477}
7478
7479/*
7480 * "match()" function
7481 */
7482 static void
7483f_match(typval_T *argvars, typval_T *rettv)
7484{
7485 find_some_match(argvars, rettv, 1);
7486}
7487
7488/*
7489 * "matchadd()" function
7490 */
7491 static void
7492f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7493{
7494#ifdef FEAT_SEARCH_EXTRA
7495 char_u buf[NUMBUFLEN];
7496 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7497 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7498 int prio = 10; /* default priority */
7499 int id = -1;
7500 int error = FALSE;
7501 char_u *conceal_char = NULL;
7502
7503 rettv->vval.v_number = -1;
7504
7505 if (grp == NULL || pat == NULL)
7506 return;
7507 if (argvars[2].v_type != VAR_UNKNOWN)
7508 {
7509 prio = (int)get_tv_number_chk(&argvars[2], &error);
7510 if (argvars[3].v_type != VAR_UNKNOWN)
7511 {
7512 id = (int)get_tv_number_chk(&argvars[3], &error);
7513 if (argvars[4].v_type != VAR_UNKNOWN)
7514 {
7515 if (argvars[4].v_type != VAR_DICT)
7516 {
7517 EMSG(_(e_dictreq));
7518 return;
7519 }
7520 if (dict_find(argvars[4].vval.v_dict,
7521 (char_u *)"conceal", -1) != NULL)
7522 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7523 (char_u *)"conceal", FALSE);
7524 }
7525 }
7526 }
7527 if (error == TRUE)
7528 return;
7529 if (id >= 1 && id <= 3)
7530 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007531 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 return;
7533 }
7534
7535 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7536 conceal_char);
7537#endif
7538}
7539
7540/*
7541 * "matchaddpos()" function
7542 */
7543 static void
7544f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7545{
7546#ifdef FEAT_SEARCH_EXTRA
7547 char_u buf[NUMBUFLEN];
7548 char_u *group;
7549 int prio = 10;
7550 int id = -1;
7551 int error = FALSE;
7552 list_T *l;
7553 char_u *conceal_char = NULL;
7554
7555 rettv->vval.v_number = -1;
7556
7557 group = get_tv_string_buf_chk(&argvars[0], buf);
7558 if (group == NULL)
7559 return;
7560
7561 if (argvars[1].v_type != VAR_LIST)
7562 {
7563 EMSG2(_(e_listarg), "matchaddpos()");
7564 return;
7565 }
7566 l = argvars[1].vval.v_list;
7567 if (l == NULL)
7568 return;
7569
7570 if (argvars[2].v_type != VAR_UNKNOWN)
7571 {
7572 prio = (int)get_tv_number_chk(&argvars[2], &error);
7573 if (argvars[3].v_type != VAR_UNKNOWN)
7574 {
7575 id = (int)get_tv_number_chk(&argvars[3], &error);
7576 if (argvars[4].v_type != VAR_UNKNOWN)
7577 {
7578 if (argvars[4].v_type != VAR_DICT)
7579 {
7580 EMSG(_(e_dictreq));
7581 return;
7582 }
7583 if (dict_find(argvars[4].vval.v_dict,
7584 (char_u *)"conceal", -1) != NULL)
7585 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7586 (char_u *)"conceal", FALSE);
7587 }
7588 }
7589 }
7590 if (error == TRUE)
7591 return;
7592
7593 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7594 if (id == 1 || id == 2)
7595 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007596 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007597 return;
7598 }
7599
7600 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7601 conceal_char);
7602#endif
7603}
7604
7605/*
7606 * "matcharg()" function
7607 */
7608 static void
7609f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7610{
7611 if (rettv_list_alloc(rettv) == OK)
7612 {
7613#ifdef FEAT_SEARCH_EXTRA
7614 int id = (int)get_tv_number(&argvars[0]);
7615 matchitem_T *m;
7616
7617 if (id >= 1 && id <= 3)
7618 {
7619 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7620 {
7621 list_append_string(rettv->vval.v_list,
7622 syn_id2name(m->hlg_id), -1);
7623 list_append_string(rettv->vval.v_list, m->pattern, -1);
7624 }
7625 else
7626 {
7627 list_append_string(rettv->vval.v_list, NULL, -1);
7628 list_append_string(rettv->vval.v_list, NULL, -1);
7629 }
7630 }
7631#endif
7632 }
7633}
7634
7635/*
7636 * "matchdelete()" function
7637 */
7638 static void
7639f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7640{
7641#ifdef FEAT_SEARCH_EXTRA
7642 rettv->vval.v_number = match_delete(curwin,
7643 (int)get_tv_number(&argvars[0]), TRUE);
7644#endif
7645}
7646
7647/*
7648 * "matchend()" function
7649 */
7650 static void
7651f_matchend(typval_T *argvars, typval_T *rettv)
7652{
7653 find_some_match(argvars, rettv, 0);
7654}
7655
7656/*
7657 * "matchlist()" function
7658 */
7659 static void
7660f_matchlist(typval_T *argvars, typval_T *rettv)
7661{
7662 find_some_match(argvars, rettv, 3);
7663}
7664
7665/*
7666 * "matchstr()" function
7667 */
7668 static void
7669f_matchstr(typval_T *argvars, typval_T *rettv)
7670{
7671 find_some_match(argvars, rettv, 2);
7672}
7673
7674/*
7675 * "matchstrpos()" function
7676 */
7677 static void
7678f_matchstrpos(typval_T *argvars, typval_T *rettv)
7679{
7680 find_some_match(argvars, rettv, 4);
7681}
7682
7683static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7684
7685 static void
7686max_min(typval_T *argvars, typval_T *rettv, int domax)
7687{
7688 varnumber_T n = 0;
7689 varnumber_T i;
7690 int error = FALSE;
7691
7692 if (argvars[0].v_type == VAR_LIST)
7693 {
7694 list_T *l;
7695 listitem_T *li;
7696
7697 l = argvars[0].vval.v_list;
7698 if (l != NULL)
7699 {
7700 li = l->lv_first;
7701 if (li != NULL)
7702 {
7703 n = get_tv_number_chk(&li->li_tv, &error);
7704 for (;;)
7705 {
7706 li = li->li_next;
7707 if (li == NULL)
7708 break;
7709 i = get_tv_number_chk(&li->li_tv, &error);
7710 if (domax ? i > n : i < n)
7711 n = i;
7712 }
7713 }
7714 }
7715 }
7716 else if (argvars[0].v_type == VAR_DICT)
7717 {
7718 dict_T *d;
7719 int first = TRUE;
7720 hashitem_T *hi;
7721 int todo;
7722
7723 d = argvars[0].vval.v_dict;
7724 if (d != NULL)
7725 {
7726 todo = (int)d->dv_hashtab.ht_used;
7727 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7728 {
7729 if (!HASHITEM_EMPTY(hi))
7730 {
7731 --todo;
7732 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7733 if (first)
7734 {
7735 n = i;
7736 first = FALSE;
7737 }
7738 else if (domax ? i > n : i < n)
7739 n = i;
7740 }
7741 }
7742 }
7743 }
7744 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007745 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746 rettv->vval.v_number = error ? 0 : n;
7747}
7748
7749/*
7750 * "max()" function
7751 */
7752 static void
7753f_max(typval_T *argvars, typval_T *rettv)
7754{
7755 max_min(argvars, rettv, TRUE);
7756}
7757
7758/*
7759 * "min()" function
7760 */
7761 static void
7762f_min(typval_T *argvars, typval_T *rettv)
7763{
7764 max_min(argvars, rettv, FALSE);
7765}
7766
7767static int mkdir_recurse(char_u *dir, int prot);
7768
7769/*
7770 * Create the directory in which "dir" is located, and higher levels when
7771 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007772 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007773 */
7774 static int
7775mkdir_recurse(char_u *dir, int prot)
7776{
7777 char_u *p;
7778 char_u *updir;
7779 int r = FAIL;
7780
7781 /* Get end of directory name in "dir".
7782 * We're done when it's "/" or "c:/". */
7783 p = gettail_sep(dir);
7784 if (p <= get_past_head(dir))
7785 return OK;
7786
7787 /* If the directory exists we're done. Otherwise: create it.*/
7788 updir = vim_strnsave(dir, (int)(p - dir));
7789 if (updir == NULL)
7790 return FAIL;
7791 if (mch_isdir(updir))
7792 r = OK;
7793 else if (mkdir_recurse(updir, prot) == OK)
7794 r = vim_mkdir_emsg(updir, prot);
7795 vim_free(updir);
7796 return r;
7797}
7798
7799#ifdef vim_mkdir
7800/*
7801 * "mkdir()" function
7802 */
7803 static void
7804f_mkdir(typval_T *argvars, typval_T *rettv)
7805{
7806 char_u *dir;
7807 char_u buf[NUMBUFLEN];
7808 int prot = 0755;
7809
7810 rettv->vval.v_number = FAIL;
7811 if (check_restricted() || check_secure())
7812 return;
7813
7814 dir = get_tv_string_buf(&argvars[0], buf);
7815 if (*dir == NUL)
7816 rettv->vval.v_number = FAIL;
7817 else
7818 {
7819 if (*gettail(dir) == NUL)
7820 /* remove trailing slashes */
7821 *gettail_sep(dir) = NUL;
7822
7823 if (argvars[1].v_type != VAR_UNKNOWN)
7824 {
7825 if (argvars[2].v_type != VAR_UNKNOWN)
7826 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7827 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7828 mkdir_recurse(dir, prot);
7829 }
7830 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7831 }
7832}
7833#endif
7834
7835/*
7836 * "mode()" function
7837 */
7838 static void
7839f_mode(typval_T *argvars, typval_T *rettv)
7840{
7841 char_u buf[3];
7842
7843 buf[1] = NUL;
7844 buf[2] = NUL;
7845
7846 if (time_for_testing == 93784)
7847 {
7848 /* Testing the two-character code. */
7849 buf[0] = 'x';
7850 buf[1] = '!';
7851 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007852#ifdef FEAT_TERMINAL
7853 else if (term_use_loop())
7854 buf[0] = 't';
7855#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856 else if (VIsual_active)
7857 {
7858 if (VIsual_select)
7859 buf[0] = VIsual_mode + 's' - 'v';
7860 else
7861 buf[0] = VIsual_mode;
7862 }
7863 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7864 || State == CONFIRM)
7865 {
7866 buf[0] = 'r';
7867 if (State == ASKMORE)
7868 buf[1] = 'm';
7869 else if (State == CONFIRM)
7870 buf[1] = '?';
7871 }
7872 else if (State == EXTERNCMD)
7873 buf[0] = '!';
7874 else if (State & INSERT)
7875 {
7876#ifdef FEAT_VREPLACE
7877 if (State & VREPLACE_FLAG)
7878 {
7879 buf[0] = 'R';
7880 buf[1] = 'v';
7881 }
7882 else
7883#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01007884 {
7885 if (State & REPLACE_FLAG)
7886 buf[0] = 'R';
7887 else
7888 buf[0] = 'i';
7889#ifdef FEAT_INS_EXPAND
7890 if (ins_compl_active())
7891 buf[1] = 'c';
7892 else if (ctrl_x_mode == 1)
7893 buf[1] = 'x';
7894#endif
7895 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007896 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007897 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007898 {
7899 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007900 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007901 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007902 else if (exmode_active == EXMODE_NORMAL)
7903 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 }
7905 else
7906 {
7907 buf[0] = 'n';
7908 if (finish_op)
7909 buf[1] = 'o';
7910 }
7911
7912 /* Clear out the minor mode when the argument is not a non-zero number or
7913 * non-empty string. */
7914 if (!non_zero_arg(&argvars[0]))
7915 buf[1] = NUL;
7916
7917 rettv->vval.v_string = vim_strsave(buf);
7918 rettv->v_type = VAR_STRING;
7919}
7920
7921#if defined(FEAT_MZSCHEME) || defined(PROTO)
7922/*
7923 * "mzeval()" function
7924 */
7925 static void
7926f_mzeval(typval_T *argvars, typval_T *rettv)
7927{
7928 char_u *str;
7929 char_u buf[NUMBUFLEN];
7930
7931 str = get_tv_string_buf(&argvars[0], buf);
7932 do_mzeval(str, rettv);
7933}
7934
7935 void
7936mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7937{
7938 typval_T argvars[3];
7939
7940 argvars[0].v_type = VAR_STRING;
7941 argvars[0].vval.v_string = name;
7942 copy_tv(args, &argvars[1]);
7943 argvars[2].v_type = VAR_UNKNOWN;
7944 f_call(argvars, rettv);
7945 clear_tv(&argvars[1]);
7946}
7947#endif
7948
7949/*
7950 * "nextnonblank()" function
7951 */
7952 static void
7953f_nextnonblank(typval_T *argvars, typval_T *rettv)
7954{
7955 linenr_T lnum;
7956
7957 for (lnum = get_tv_lnum(argvars); ; ++lnum)
7958 {
7959 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7960 {
7961 lnum = 0;
7962 break;
7963 }
7964 if (*skipwhite(ml_get(lnum)) != NUL)
7965 break;
7966 }
7967 rettv->vval.v_number = lnum;
7968}
7969
7970/*
7971 * "nr2char()" function
7972 */
7973 static void
7974f_nr2char(typval_T *argvars, typval_T *rettv)
7975{
7976 char_u buf[NUMBUFLEN];
7977
7978#ifdef FEAT_MBYTE
7979 if (has_mbyte)
7980 {
7981 int utf8 = 0;
7982
7983 if (argvars[1].v_type != VAR_UNKNOWN)
7984 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
7985 if (utf8)
7986 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7987 else
7988 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7989 }
7990 else
7991#endif
7992 {
7993 buf[0] = (char_u)get_tv_number(&argvars[0]);
7994 buf[1] = NUL;
7995 }
7996 rettv->v_type = VAR_STRING;
7997 rettv->vval.v_string = vim_strsave(buf);
7998}
7999
8000/*
8001 * "or(expr, expr)" function
8002 */
8003 static void
8004f_or(typval_T *argvars, typval_T *rettv)
8005{
8006 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8007 | get_tv_number_chk(&argvars[1], NULL);
8008}
8009
8010/*
8011 * "pathshorten()" function
8012 */
8013 static void
8014f_pathshorten(typval_T *argvars, typval_T *rettv)
8015{
8016 char_u *p;
8017
8018 rettv->v_type = VAR_STRING;
8019 p = get_tv_string_chk(&argvars[0]);
8020 if (p == NULL)
8021 rettv->vval.v_string = NULL;
8022 else
8023 {
8024 p = vim_strsave(p);
8025 rettv->vval.v_string = p;
8026 if (p != NULL)
8027 shorten_dir(p);
8028 }
8029}
8030
8031#ifdef FEAT_PERL
8032/*
8033 * "perleval()" function
8034 */
8035 static void
8036f_perleval(typval_T *argvars, typval_T *rettv)
8037{
8038 char_u *str;
8039 char_u buf[NUMBUFLEN];
8040
8041 str = get_tv_string_buf(&argvars[0], buf);
8042 do_perleval(str, rettv);
8043}
8044#endif
8045
8046#ifdef FEAT_FLOAT
8047/*
8048 * "pow()" function
8049 */
8050 static void
8051f_pow(typval_T *argvars, typval_T *rettv)
8052{
8053 float_T fx = 0.0, fy = 0.0;
8054
8055 rettv->v_type = VAR_FLOAT;
8056 if (get_float_arg(argvars, &fx) == OK
8057 && get_float_arg(&argvars[1], &fy) == OK)
8058 rettv->vval.v_float = pow(fx, fy);
8059 else
8060 rettv->vval.v_float = 0.0;
8061}
8062#endif
8063
8064/*
8065 * "prevnonblank()" function
8066 */
8067 static void
8068f_prevnonblank(typval_T *argvars, typval_T *rettv)
8069{
8070 linenr_T lnum;
8071
8072 lnum = get_tv_lnum(argvars);
8073 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8074 lnum = 0;
8075 else
8076 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8077 --lnum;
8078 rettv->vval.v_number = lnum;
8079}
8080
8081/* This dummy va_list is here because:
8082 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8083 * - locally in the function results in a "used before set" warning
8084 * - using va_start() to initialize it gives "function with fixed args" error */
8085static va_list ap;
8086
8087/*
8088 * "printf()" function
8089 */
8090 static void
8091f_printf(typval_T *argvars, typval_T *rettv)
8092{
8093 char_u buf[NUMBUFLEN];
8094 int len;
8095 char_u *s;
8096 int saved_did_emsg = did_emsg;
8097 char *fmt;
8098
8099 rettv->v_type = VAR_STRING;
8100 rettv->vval.v_string = NULL;
8101
8102 /* Get the required length, allocate the buffer and do it for real. */
8103 did_emsg = FALSE;
8104 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008105 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106 if (!did_emsg)
8107 {
8108 s = alloc(len + 1);
8109 if (s != NULL)
8110 {
8111 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008112 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8113 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008114 }
8115 }
8116 did_emsg |= saved_did_emsg;
8117}
8118
8119/*
8120 * "pumvisible()" function
8121 */
8122 static void
8123f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8124{
8125#ifdef FEAT_INS_EXPAND
8126 if (pum_visible())
8127 rettv->vval.v_number = 1;
8128#endif
8129}
8130
8131#ifdef FEAT_PYTHON3
8132/*
8133 * "py3eval()" function
8134 */
8135 static void
8136f_py3eval(typval_T *argvars, typval_T *rettv)
8137{
8138 char_u *str;
8139 char_u buf[NUMBUFLEN];
8140
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008141 if (p_pyx == 0)
8142 p_pyx = 3;
8143
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008144 str = get_tv_string_buf(&argvars[0], buf);
8145 do_py3eval(str, rettv);
8146}
8147#endif
8148
8149#ifdef FEAT_PYTHON
8150/*
8151 * "pyeval()" function
8152 */
8153 static void
8154f_pyeval(typval_T *argvars, typval_T *rettv)
8155{
8156 char_u *str;
8157 char_u buf[NUMBUFLEN];
8158
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008159 if (p_pyx == 0)
8160 p_pyx = 2;
8161
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008162 str = get_tv_string_buf(&argvars[0], buf);
8163 do_pyeval(str, rettv);
8164}
8165#endif
8166
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008167#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8168/*
8169 * "pyxeval()" function
8170 */
8171 static void
8172f_pyxeval(typval_T *argvars, typval_T *rettv)
8173{
8174# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8175 init_pyxversion();
8176 if (p_pyx == 2)
8177 f_pyeval(argvars, rettv);
8178 else
8179 f_py3eval(argvars, rettv);
8180# elif defined(FEAT_PYTHON)
8181 f_pyeval(argvars, rettv);
8182# elif defined(FEAT_PYTHON3)
8183 f_py3eval(argvars, rettv);
8184# endif
8185}
8186#endif
8187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188/*
8189 * "range()" function
8190 */
8191 static void
8192f_range(typval_T *argvars, typval_T *rettv)
8193{
8194 varnumber_T start;
8195 varnumber_T end;
8196 varnumber_T stride = 1;
8197 varnumber_T i;
8198 int error = FALSE;
8199
8200 start = get_tv_number_chk(&argvars[0], &error);
8201 if (argvars[1].v_type == VAR_UNKNOWN)
8202 {
8203 end = start - 1;
8204 start = 0;
8205 }
8206 else
8207 {
8208 end = get_tv_number_chk(&argvars[1], &error);
8209 if (argvars[2].v_type != VAR_UNKNOWN)
8210 stride = get_tv_number_chk(&argvars[2], &error);
8211 }
8212
8213 if (error)
8214 return; /* type error; errmsg already given */
8215 if (stride == 0)
8216 EMSG(_("E726: Stride is zero"));
8217 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8218 EMSG(_("E727: Start past end"));
8219 else
8220 {
8221 if (rettv_list_alloc(rettv) == OK)
8222 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8223 if (list_append_number(rettv->vval.v_list,
8224 (varnumber_T)i) == FAIL)
8225 break;
8226 }
8227}
8228
8229/*
8230 * "readfile()" function
8231 */
8232 static void
8233f_readfile(typval_T *argvars, typval_T *rettv)
8234{
8235 int binary = FALSE;
8236 int failed = FALSE;
8237 char_u *fname;
8238 FILE *fd;
8239 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8240 int io_size = sizeof(buf);
8241 int readlen; /* size of last fread() */
8242 char_u *prev = NULL; /* previously read bytes, if any */
8243 long prevlen = 0; /* length of data in prev */
8244 long prevsize = 0; /* size of prev buffer */
8245 long maxline = MAXLNUM;
8246 long cnt = 0;
8247 char_u *p; /* position in buf */
8248 char_u *start; /* start of current line */
8249
8250 if (argvars[1].v_type != VAR_UNKNOWN)
8251 {
8252 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8253 binary = TRUE;
8254 if (argvars[2].v_type != VAR_UNKNOWN)
8255 maxline = (long)get_tv_number(&argvars[2]);
8256 }
8257
8258 if (rettv_list_alloc(rettv) == FAIL)
8259 return;
8260
8261 /* Always open the file in binary mode, library functions have a mind of
8262 * their own about CR-LF conversion. */
8263 fname = get_tv_string(&argvars[0]);
8264 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8265 {
8266 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8267 return;
8268 }
8269
8270 while (cnt < maxline || maxline < 0)
8271 {
8272 readlen = (int)fread(buf, 1, io_size, fd);
8273
8274 /* This for loop processes what was read, but is also entered at end
8275 * of file so that either:
8276 * - an incomplete line gets written
8277 * - a "binary" file gets an empty line at the end if it ends in a
8278 * newline. */
8279 for (p = buf, start = buf;
8280 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8281 ++p)
8282 {
8283 if (*p == '\n' || readlen <= 0)
8284 {
8285 listitem_T *li;
8286 char_u *s = NULL;
8287 long_u len = p - start;
8288
8289 /* Finished a line. Remove CRs before NL. */
8290 if (readlen > 0 && !binary)
8291 {
8292 while (len > 0 && start[len - 1] == '\r')
8293 --len;
8294 /* removal may cross back to the "prev" string */
8295 if (len == 0)
8296 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8297 --prevlen;
8298 }
8299 if (prevlen == 0)
8300 s = vim_strnsave(start, (int)len);
8301 else
8302 {
8303 /* Change "prev" buffer to be the right size. This way
8304 * the bytes are only copied once, and very long lines are
8305 * allocated only once. */
8306 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8307 {
8308 mch_memmove(s + prevlen, start, len);
8309 s[prevlen + len] = NUL;
8310 prev = NULL; /* the list will own the string */
8311 prevlen = prevsize = 0;
8312 }
8313 }
8314 if (s == NULL)
8315 {
8316 do_outofmem_msg((long_u) prevlen + len + 1);
8317 failed = TRUE;
8318 break;
8319 }
8320
8321 if ((li = listitem_alloc()) == NULL)
8322 {
8323 vim_free(s);
8324 failed = TRUE;
8325 break;
8326 }
8327 li->li_tv.v_type = VAR_STRING;
8328 li->li_tv.v_lock = 0;
8329 li->li_tv.vval.v_string = s;
8330 list_append(rettv->vval.v_list, li);
8331
8332 start = p + 1; /* step over newline */
8333 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8334 break;
8335 }
8336 else if (*p == NUL)
8337 *p = '\n';
8338#ifdef FEAT_MBYTE
8339 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8340 * when finding the BF and check the previous two bytes. */
8341 else if (*p == 0xbf && enc_utf8 && !binary)
8342 {
8343 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8344 * + 1, these may be in the "prev" string. */
8345 char_u back1 = p >= buf + 1 ? p[-1]
8346 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8347 char_u back2 = p >= buf + 2 ? p[-2]
8348 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8349 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8350
8351 if (back2 == 0xef && back1 == 0xbb)
8352 {
8353 char_u *dest = p - 2;
8354
8355 /* Usually a BOM is at the beginning of a file, and so at
8356 * the beginning of a line; then we can just step over it.
8357 */
8358 if (start == dest)
8359 start = p + 1;
8360 else
8361 {
8362 /* have to shuffle buf to close gap */
8363 int adjust_prevlen = 0;
8364
8365 if (dest < buf)
8366 {
8367 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8368 dest = buf;
8369 }
8370 if (readlen > p - buf + 1)
8371 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8372 readlen -= 3 - adjust_prevlen;
8373 prevlen -= adjust_prevlen;
8374 p = dest - 1;
8375 }
8376 }
8377 }
8378#endif
8379 } /* for */
8380
8381 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8382 break;
8383 if (start < p)
8384 {
8385 /* There's part of a line in buf, store it in "prev". */
8386 if (p - start + prevlen >= prevsize)
8387 {
8388 /* need bigger "prev" buffer */
8389 char_u *newprev;
8390
8391 /* A common use case is ordinary text files and "prev" gets a
8392 * fragment of a line, so the first allocation is made
8393 * small, to avoid repeatedly 'allocing' large and
8394 * 'reallocing' small. */
8395 if (prevsize == 0)
8396 prevsize = (long)(p - start);
8397 else
8398 {
8399 long grow50pc = (prevsize * 3) / 2;
8400 long growmin = (long)((p - start) * 2 + prevlen);
8401 prevsize = grow50pc > growmin ? grow50pc : growmin;
8402 }
8403 newprev = prev == NULL ? alloc(prevsize)
8404 : vim_realloc(prev, prevsize);
8405 if (newprev == NULL)
8406 {
8407 do_outofmem_msg((long_u)prevsize);
8408 failed = TRUE;
8409 break;
8410 }
8411 prev = newprev;
8412 }
8413 /* Add the line part to end of "prev". */
8414 mch_memmove(prev + prevlen, start, p - start);
8415 prevlen += (long)(p - start);
8416 }
8417 } /* while */
8418
8419 /*
8420 * For a negative line count use only the lines at the end of the file,
8421 * free the rest.
8422 */
8423 if (!failed && maxline < 0)
8424 while (cnt > -maxline)
8425 {
8426 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8427 --cnt;
8428 }
8429
8430 if (failed)
8431 {
8432 list_free(rettv->vval.v_list);
8433 /* readfile doc says an empty list is returned on error */
8434 rettv->vval.v_list = list_alloc();
8435 }
8436
8437 vim_free(prev);
8438 fclose(fd);
8439}
8440
8441#if defined(FEAT_RELTIME)
8442static int list2proftime(typval_T *arg, proftime_T *tm);
8443
8444/*
8445 * Convert a List to proftime_T.
8446 * Return FAIL when there is something wrong.
8447 */
8448 static int
8449list2proftime(typval_T *arg, proftime_T *tm)
8450{
8451 long n1, n2;
8452 int error = FALSE;
8453
8454 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8455 || arg->vval.v_list->lv_len != 2)
8456 return FAIL;
8457 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8458 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8459# ifdef WIN3264
8460 tm->HighPart = n1;
8461 tm->LowPart = n2;
8462# else
8463 tm->tv_sec = n1;
8464 tm->tv_usec = n2;
8465# endif
8466 return error ? FAIL : OK;
8467}
8468#endif /* FEAT_RELTIME */
8469
8470/*
8471 * "reltime()" function
8472 */
8473 static void
8474f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8475{
8476#ifdef FEAT_RELTIME
8477 proftime_T res;
8478 proftime_T start;
8479
8480 if (argvars[0].v_type == VAR_UNKNOWN)
8481 {
8482 /* No arguments: get current time. */
8483 profile_start(&res);
8484 }
8485 else if (argvars[1].v_type == VAR_UNKNOWN)
8486 {
8487 if (list2proftime(&argvars[0], &res) == FAIL)
8488 return;
8489 profile_end(&res);
8490 }
8491 else
8492 {
8493 /* Two arguments: compute the difference. */
8494 if (list2proftime(&argvars[0], &start) == FAIL
8495 || list2proftime(&argvars[1], &res) == FAIL)
8496 return;
8497 profile_sub(&res, &start);
8498 }
8499
8500 if (rettv_list_alloc(rettv) == OK)
8501 {
8502 long n1, n2;
8503
8504# ifdef WIN3264
8505 n1 = res.HighPart;
8506 n2 = res.LowPart;
8507# else
8508 n1 = res.tv_sec;
8509 n2 = res.tv_usec;
8510# endif
8511 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8512 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8513 }
8514#endif
8515}
8516
8517#ifdef FEAT_FLOAT
8518/*
8519 * "reltimefloat()" function
8520 */
8521 static void
8522f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8523{
8524# ifdef FEAT_RELTIME
8525 proftime_T tm;
8526# endif
8527
8528 rettv->v_type = VAR_FLOAT;
8529 rettv->vval.v_float = 0;
8530# ifdef FEAT_RELTIME
8531 if (list2proftime(&argvars[0], &tm) == OK)
8532 rettv->vval.v_float = profile_float(&tm);
8533# endif
8534}
8535#endif
8536
8537/*
8538 * "reltimestr()" function
8539 */
8540 static void
8541f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8542{
8543#ifdef FEAT_RELTIME
8544 proftime_T tm;
8545#endif
8546
8547 rettv->v_type = VAR_STRING;
8548 rettv->vval.v_string = NULL;
8549#ifdef FEAT_RELTIME
8550 if (list2proftime(&argvars[0], &tm) == OK)
8551 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8552#endif
8553}
8554
8555#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8556static void make_connection(void);
8557static int check_connection(void);
8558
8559 static void
8560make_connection(void)
8561{
8562 if (X_DISPLAY == NULL
8563# ifdef FEAT_GUI
8564 && !gui.in_use
8565# endif
8566 )
8567 {
8568 x_force_connect = TRUE;
8569 setup_term_clip();
8570 x_force_connect = FALSE;
8571 }
8572}
8573
8574 static int
8575check_connection(void)
8576{
8577 make_connection();
8578 if (X_DISPLAY == NULL)
8579 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008580 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008581 return FAIL;
8582 }
8583 return OK;
8584}
8585#endif
8586
8587#ifdef FEAT_CLIENTSERVER
8588 static void
8589remote_common(typval_T *argvars, typval_T *rettv, int expr)
8590{
8591 char_u *server_name;
8592 char_u *keys;
8593 char_u *r = NULL;
8594 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008595 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596# ifdef WIN32
8597 HWND w;
8598# else
8599 Window w;
8600# endif
8601
8602 if (check_restricted() || check_secure())
8603 return;
8604
8605# ifdef FEAT_X11
8606 if (check_connection() == FAIL)
8607 return;
8608# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008609 if (argvars[2].v_type != VAR_UNKNOWN
8610 && argvars[3].v_type != VAR_UNKNOWN)
8611 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008612
8613 server_name = get_tv_string_chk(&argvars[0]);
8614 if (server_name == NULL)
8615 return; /* type error; errmsg already given */
8616 keys = get_tv_string_buf(&argvars[1], buf);
8617# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008618 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008619# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008620 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8621 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008622# endif
8623 {
8624 if (r != NULL)
8625 EMSG(r); /* sending worked but evaluation failed */
8626 else
8627 EMSG2(_("E241: Unable to send to %s"), server_name);
8628 return;
8629 }
8630
8631 rettv->vval.v_string = r;
8632
8633 if (argvars[2].v_type != VAR_UNKNOWN)
8634 {
8635 dictitem_T v;
8636 char_u str[30];
8637 char_u *idvar;
8638
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008639 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008640 if (idvar != NULL && *idvar != NUL)
8641 {
8642 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8643 v.di_tv.v_type = VAR_STRING;
8644 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008645 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008646 vim_free(v.di_tv.vval.v_string);
8647 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008648 }
8649}
8650#endif
8651
8652/*
8653 * "remote_expr()" function
8654 */
8655 static void
8656f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8657{
8658 rettv->v_type = VAR_STRING;
8659 rettv->vval.v_string = NULL;
8660#ifdef FEAT_CLIENTSERVER
8661 remote_common(argvars, rettv, TRUE);
8662#endif
8663}
8664
8665/*
8666 * "remote_foreground()" function
8667 */
8668 static void
8669f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8670{
8671#ifdef FEAT_CLIENTSERVER
8672# ifdef WIN32
8673 /* On Win32 it's done in this application. */
8674 {
8675 char_u *server_name = get_tv_string_chk(&argvars[0]);
8676
8677 if (server_name != NULL)
8678 serverForeground(server_name);
8679 }
8680# else
8681 /* Send a foreground() expression to the server. */
8682 argvars[1].v_type = VAR_STRING;
8683 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8684 argvars[2].v_type = VAR_UNKNOWN;
8685 remote_common(argvars, rettv, TRUE);
8686 vim_free(argvars[1].vval.v_string);
8687# endif
8688#endif
8689}
8690
8691 static void
8692f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8693{
8694#ifdef FEAT_CLIENTSERVER
8695 dictitem_T v;
8696 char_u *s = NULL;
8697# ifdef WIN32
8698 long_u n = 0;
8699# endif
8700 char_u *serverid;
8701
8702 if (check_restricted() || check_secure())
8703 {
8704 rettv->vval.v_number = -1;
8705 return;
8706 }
8707 serverid = get_tv_string_chk(&argvars[0]);
8708 if (serverid == NULL)
8709 {
8710 rettv->vval.v_number = -1;
8711 return; /* type error; errmsg already given */
8712 }
8713# ifdef WIN32
8714 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8715 if (n == 0)
8716 rettv->vval.v_number = -1;
8717 else
8718 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008719 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 rettv->vval.v_number = (s != NULL);
8721 }
8722# else
8723 if (check_connection() == FAIL)
8724 return;
8725
8726 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8727 serverStrToWin(serverid), &s);
8728# endif
8729
8730 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8731 {
8732 char_u *retvar;
8733
8734 v.di_tv.v_type = VAR_STRING;
8735 v.di_tv.vval.v_string = vim_strsave(s);
8736 retvar = get_tv_string_chk(&argvars[1]);
8737 if (retvar != NULL)
8738 set_var(retvar, &v.di_tv, FALSE);
8739 vim_free(v.di_tv.vval.v_string);
8740 }
8741#else
8742 rettv->vval.v_number = -1;
8743#endif
8744}
8745
8746 static void
8747f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8748{
8749 char_u *r = NULL;
8750
8751#ifdef FEAT_CLIENTSERVER
8752 char_u *serverid = get_tv_string_chk(&argvars[0]);
8753
8754 if (serverid != NULL && !check_restricted() && !check_secure())
8755 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008756 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008757# ifdef WIN32
8758 /* The server's HWND is encoded in the 'id' parameter */
8759 long_u n = 0;
8760# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008761
8762 if (argvars[1].v_type != VAR_UNKNOWN)
8763 timeout = get_tv_number(&argvars[1]);
8764
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008765# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008766 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8767 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008768 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008769 if (r == NULL)
8770# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008771 if (check_connection() == FAIL
8772 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8773 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008774# endif
8775 EMSG(_("E277: Unable to read a server reply"));
8776 }
8777#endif
8778 rettv->v_type = VAR_STRING;
8779 rettv->vval.v_string = r;
8780}
8781
8782/*
8783 * "remote_send()" function
8784 */
8785 static void
8786f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8787{
8788 rettv->v_type = VAR_STRING;
8789 rettv->vval.v_string = NULL;
8790#ifdef FEAT_CLIENTSERVER
8791 remote_common(argvars, rettv, FALSE);
8792#endif
8793}
8794
8795/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008796 * "remote_startserver()" function
8797 */
8798 static void
8799f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8800{
8801#ifdef FEAT_CLIENTSERVER
8802 char_u *server = get_tv_string_chk(&argvars[0]);
8803
8804 if (server == NULL)
8805 return; /* type error; errmsg already given */
8806 if (serverName != NULL)
8807 EMSG(_("E941: already started a server"));
8808 else
8809 {
8810# ifdef FEAT_X11
8811 if (check_connection() == OK)
8812 serverRegisterName(X_DISPLAY, server);
8813# else
8814 serverSetName(server);
8815# endif
8816 }
8817#else
8818 EMSG(_("E942: +clientserver feature not available"));
8819#endif
8820}
8821
8822/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008823 * "remove()" function
8824 */
8825 static void
8826f_remove(typval_T *argvars, typval_T *rettv)
8827{
8828 list_T *l;
8829 listitem_T *item, *item2;
8830 listitem_T *li;
8831 long idx;
8832 long end;
8833 char_u *key;
8834 dict_T *d;
8835 dictitem_T *di;
8836 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8837
8838 if (argvars[0].v_type == VAR_DICT)
8839 {
8840 if (argvars[2].v_type != VAR_UNKNOWN)
8841 EMSG2(_(e_toomanyarg), "remove()");
8842 else if ((d = argvars[0].vval.v_dict) != NULL
8843 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8844 {
8845 key = get_tv_string_chk(&argvars[1]);
8846 if (key != NULL)
8847 {
8848 di = dict_find(d, key, -1);
8849 if (di == NULL)
8850 EMSG2(_(e_dictkey), key);
8851 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8852 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8853 {
8854 *rettv = di->di_tv;
8855 init_tv(&di->di_tv);
8856 dictitem_remove(d, di);
8857 }
8858 }
8859 }
8860 }
8861 else if (argvars[0].v_type != VAR_LIST)
8862 EMSG2(_(e_listdictarg), "remove()");
8863 else if ((l = argvars[0].vval.v_list) != NULL
8864 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8865 {
8866 int error = FALSE;
8867
8868 idx = (long)get_tv_number_chk(&argvars[1], &error);
8869 if (error)
8870 ; /* type error: do nothing, errmsg already given */
8871 else if ((item = list_find(l, idx)) == NULL)
8872 EMSGN(_(e_listidx), idx);
8873 else
8874 {
8875 if (argvars[2].v_type == VAR_UNKNOWN)
8876 {
8877 /* Remove one item, return its value. */
8878 vimlist_remove(l, item, item);
8879 *rettv = item->li_tv;
8880 vim_free(item);
8881 }
8882 else
8883 {
8884 /* Remove range of items, return list with values. */
8885 end = (long)get_tv_number_chk(&argvars[2], &error);
8886 if (error)
8887 ; /* type error: do nothing */
8888 else if ((item2 = list_find(l, end)) == NULL)
8889 EMSGN(_(e_listidx), end);
8890 else
8891 {
8892 int cnt = 0;
8893
8894 for (li = item; li != NULL; li = li->li_next)
8895 {
8896 ++cnt;
8897 if (li == item2)
8898 break;
8899 }
8900 if (li == NULL) /* didn't find "item2" after "item" */
8901 EMSG(_(e_invrange));
8902 else
8903 {
8904 vimlist_remove(l, item, item2);
8905 if (rettv_list_alloc(rettv) == OK)
8906 {
8907 l = rettv->vval.v_list;
8908 l->lv_first = item;
8909 l->lv_last = item2;
8910 item->li_prev = NULL;
8911 item2->li_next = NULL;
8912 l->lv_len = cnt;
8913 }
8914 }
8915 }
8916 }
8917 }
8918 }
8919}
8920
8921/*
8922 * "rename({from}, {to})" function
8923 */
8924 static void
8925f_rename(typval_T *argvars, typval_T *rettv)
8926{
8927 char_u buf[NUMBUFLEN];
8928
8929 if (check_restricted() || check_secure())
8930 rettv->vval.v_number = -1;
8931 else
8932 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8933 get_tv_string_buf(&argvars[1], buf));
8934}
8935
8936/*
8937 * "repeat()" function
8938 */
8939 static void
8940f_repeat(typval_T *argvars, typval_T *rettv)
8941{
8942 char_u *p;
8943 int n;
8944 int slen;
8945 int len;
8946 char_u *r;
8947 int i;
8948
8949 n = (int)get_tv_number(&argvars[1]);
8950 if (argvars[0].v_type == VAR_LIST)
8951 {
8952 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8953 while (n-- > 0)
8954 if (list_extend(rettv->vval.v_list,
8955 argvars[0].vval.v_list, NULL) == FAIL)
8956 break;
8957 }
8958 else
8959 {
8960 p = get_tv_string(&argvars[0]);
8961 rettv->v_type = VAR_STRING;
8962 rettv->vval.v_string = NULL;
8963
8964 slen = (int)STRLEN(p);
8965 len = slen * n;
8966 if (len <= 0)
8967 return;
8968
8969 r = alloc(len + 1);
8970 if (r != NULL)
8971 {
8972 for (i = 0; i < n; i++)
8973 mch_memmove(r + i * slen, p, (size_t)slen);
8974 r[len] = NUL;
8975 }
8976
8977 rettv->vval.v_string = r;
8978 }
8979}
8980
8981/*
8982 * "resolve()" function
8983 */
8984 static void
8985f_resolve(typval_T *argvars, typval_T *rettv)
8986{
8987 char_u *p;
8988#ifdef HAVE_READLINK
8989 char_u *buf = NULL;
8990#endif
8991
8992 p = get_tv_string(&argvars[0]);
8993#ifdef FEAT_SHORTCUT
8994 {
8995 char_u *v = NULL;
8996
8997 v = mch_resolve_shortcut(p);
8998 if (v != NULL)
8999 rettv->vval.v_string = v;
9000 else
9001 rettv->vval.v_string = vim_strsave(p);
9002 }
9003#else
9004# ifdef HAVE_READLINK
9005 {
9006 char_u *cpy;
9007 int len;
9008 char_u *remain = NULL;
9009 char_u *q;
9010 int is_relative_to_current = FALSE;
9011 int has_trailing_pathsep = FALSE;
9012 int limit = 100;
9013
9014 p = vim_strsave(p);
9015
9016 if (p[0] == '.' && (vim_ispathsep(p[1])
9017 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9018 is_relative_to_current = TRUE;
9019
9020 len = STRLEN(p);
9021 if (len > 0 && after_pathsep(p, p + len))
9022 {
9023 has_trailing_pathsep = TRUE;
9024 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9025 }
9026
9027 q = getnextcomp(p);
9028 if (*q != NUL)
9029 {
9030 /* Separate the first path component in "p", and keep the
9031 * remainder (beginning with the path separator). */
9032 remain = vim_strsave(q - 1);
9033 q[-1] = NUL;
9034 }
9035
9036 buf = alloc(MAXPATHL + 1);
9037 if (buf == NULL)
9038 goto fail;
9039
9040 for (;;)
9041 {
9042 for (;;)
9043 {
9044 len = readlink((char *)p, (char *)buf, MAXPATHL);
9045 if (len <= 0)
9046 break;
9047 buf[len] = NUL;
9048
9049 if (limit-- == 0)
9050 {
9051 vim_free(p);
9052 vim_free(remain);
9053 EMSG(_("E655: Too many symbolic links (cycle?)"));
9054 rettv->vval.v_string = NULL;
9055 goto fail;
9056 }
9057
9058 /* Ensure that the result will have a trailing path separator
9059 * if the argument has one. */
9060 if (remain == NULL && has_trailing_pathsep)
9061 add_pathsep(buf);
9062
9063 /* Separate the first path component in the link value and
9064 * concatenate the remainders. */
9065 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9066 if (*q != NUL)
9067 {
9068 if (remain == NULL)
9069 remain = vim_strsave(q - 1);
9070 else
9071 {
9072 cpy = concat_str(q - 1, remain);
9073 if (cpy != NULL)
9074 {
9075 vim_free(remain);
9076 remain = cpy;
9077 }
9078 }
9079 q[-1] = NUL;
9080 }
9081
9082 q = gettail(p);
9083 if (q > p && *q == NUL)
9084 {
9085 /* Ignore trailing path separator. */
9086 q[-1] = NUL;
9087 q = gettail(p);
9088 }
9089 if (q > p && !mch_isFullName(buf))
9090 {
9091 /* symlink is relative to directory of argument */
9092 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9093 if (cpy != NULL)
9094 {
9095 STRCPY(cpy, p);
9096 STRCPY(gettail(cpy), buf);
9097 vim_free(p);
9098 p = cpy;
9099 }
9100 }
9101 else
9102 {
9103 vim_free(p);
9104 p = vim_strsave(buf);
9105 }
9106 }
9107
9108 if (remain == NULL)
9109 break;
9110
9111 /* Append the first path component of "remain" to "p". */
9112 q = getnextcomp(remain + 1);
9113 len = q - remain - (*q != NUL);
9114 cpy = vim_strnsave(p, STRLEN(p) + len);
9115 if (cpy != NULL)
9116 {
9117 STRNCAT(cpy, remain, len);
9118 vim_free(p);
9119 p = cpy;
9120 }
9121 /* Shorten "remain". */
9122 if (*q != NUL)
9123 STRMOVE(remain, q - 1);
9124 else
9125 {
9126 vim_free(remain);
9127 remain = NULL;
9128 }
9129 }
9130
9131 /* If the result is a relative path name, make it explicitly relative to
9132 * the current directory if and only if the argument had this form. */
9133 if (!vim_ispathsep(*p))
9134 {
9135 if (is_relative_to_current
9136 && *p != NUL
9137 && !(p[0] == '.'
9138 && (p[1] == NUL
9139 || vim_ispathsep(p[1])
9140 || (p[1] == '.'
9141 && (p[2] == NUL
9142 || vim_ispathsep(p[2]))))))
9143 {
9144 /* Prepend "./". */
9145 cpy = concat_str((char_u *)"./", p);
9146 if (cpy != NULL)
9147 {
9148 vim_free(p);
9149 p = cpy;
9150 }
9151 }
9152 else if (!is_relative_to_current)
9153 {
9154 /* Strip leading "./". */
9155 q = p;
9156 while (q[0] == '.' && vim_ispathsep(q[1]))
9157 q += 2;
9158 if (q > p)
9159 STRMOVE(p, p + 2);
9160 }
9161 }
9162
9163 /* Ensure that the result will have no trailing path separator
9164 * if the argument had none. But keep "/" or "//". */
9165 if (!has_trailing_pathsep)
9166 {
9167 q = p + STRLEN(p);
9168 if (after_pathsep(p, q))
9169 *gettail_sep(p) = NUL;
9170 }
9171
9172 rettv->vval.v_string = p;
9173 }
9174# else
9175 rettv->vval.v_string = vim_strsave(p);
9176# endif
9177#endif
9178
9179 simplify_filename(rettv->vval.v_string);
9180
9181#ifdef HAVE_READLINK
9182fail:
9183 vim_free(buf);
9184#endif
9185 rettv->v_type = VAR_STRING;
9186}
9187
9188/*
9189 * "reverse({list})" function
9190 */
9191 static void
9192f_reverse(typval_T *argvars, typval_T *rettv)
9193{
9194 list_T *l;
9195 listitem_T *li, *ni;
9196
9197 if (argvars[0].v_type != VAR_LIST)
9198 EMSG2(_(e_listarg), "reverse()");
9199 else if ((l = argvars[0].vval.v_list) != NULL
9200 && !tv_check_lock(l->lv_lock,
9201 (char_u *)N_("reverse() argument"), TRUE))
9202 {
9203 li = l->lv_last;
9204 l->lv_first = l->lv_last = NULL;
9205 l->lv_len = 0;
9206 while (li != NULL)
9207 {
9208 ni = li->li_prev;
9209 list_append(l, li);
9210 li = ni;
9211 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009212 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009213 l->lv_idx = l->lv_len - l->lv_idx - 1;
9214 }
9215}
9216
9217#define SP_NOMOVE 0x01 /* don't move cursor */
9218#define SP_REPEAT 0x02 /* repeat to find outer pair */
9219#define SP_RETCOUNT 0x04 /* return matchcount */
9220#define SP_SETPCMARK 0x08 /* set previous context mark */
9221#define SP_START 0x10 /* accept match at start position */
9222#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9223#define SP_END 0x40 /* leave cursor at end of match */
9224#define SP_COLUMN 0x80 /* start at cursor column */
9225
9226static int get_search_arg(typval_T *varp, int *flagsp);
9227
9228/*
9229 * Get flags for a search function.
9230 * Possibly sets "p_ws".
9231 * Returns BACKWARD, FORWARD or zero (for an error).
9232 */
9233 static int
9234get_search_arg(typval_T *varp, int *flagsp)
9235{
9236 int dir = FORWARD;
9237 char_u *flags;
9238 char_u nbuf[NUMBUFLEN];
9239 int mask;
9240
9241 if (varp->v_type != VAR_UNKNOWN)
9242 {
9243 flags = get_tv_string_buf_chk(varp, nbuf);
9244 if (flags == NULL)
9245 return 0; /* type error; errmsg already given */
9246 while (*flags != NUL)
9247 {
9248 switch (*flags)
9249 {
9250 case 'b': dir = BACKWARD; break;
9251 case 'w': p_ws = TRUE; break;
9252 case 'W': p_ws = FALSE; break;
9253 default: mask = 0;
9254 if (flagsp != NULL)
9255 switch (*flags)
9256 {
9257 case 'c': mask = SP_START; break;
9258 case 'e': mask = SP_END; break;
9259 case 'm': mask = SP_RETCOUNT; break;
9260 case 'n': mask = SP_NOMOVE; break;
9261 case 'p': mask = SP_SUBPAT; break;
9262 case 'r': mask = SP_REPEAT; break;
9263 case 's': mask = SP_SETPCMARK; break;
9264 case 'z': mask = SP_COLUMN; break;
9265 }
9266 if (mask == 0)
9267 {
9268 EMSG2(_(e_invarg2), flags);
9269 dir = 0;
9270 }
9271 else
9272 *flagsp |= mask;
9273 }
9274 if (dir == 0)
9275 break;
9276 ++flags;
9277 }
9278 }
9279 return dir;
9280}
9281
9282/*
9283 * Shared by search() and searchpos() functions.
9284 */
9285 static int
9286search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9287{
9288 int flags;
9289 char_u *pat;
9290 pos_T pos;
9291 pos_T save_cursor;
9292 int save_p_ws = p_ws;
9293 int dir;
9294 int retval = 0; /* default: FAIL */
9295 long lnum_stop = 0;
9296 proftime_T tm;
9297#ifdef FEAT_RELTIME
9298 long time_limit = 0;
9299#endif
9300 int options = SEARCH_KEEP;
9301 int subpatnum;
9302
9303 pat = get_tv_string(&argvars[0]);
9304 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9305 if (dir == 0)
9306 goto theend;
9307 flags = *flagsp;
9308 if (flags & SP_START)
9309 options |= SEARCH_START;
9310 if (flags & SP_END)
9311 options |= SEARCH_END;
9312 if (flags & SP_COLUMN)
9313 options |= SEARCH_COL;
9314
9315 /* Optional arguments: line number to stop searching and timeout. */
9316 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9317 {
9318 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9319 if (lnum_stop < 0)
9320 goto theend;
9321#ifdef FEAT_RELTIME
9322 if (argvars[3].v_type != VAR_UNKNOWN)
9323 {
9324 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9325 if (time_limit < 0)
9326 goto theend;
9327 }
9328#endif
9329 }
9330
9331#ifdef FEAT_RELTIME
9332 /* Set the time limit, if there is one. */
9333 profile_setlimit(time_limit, &tm);
9334#endif
9335
9336 /*
9337 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9338 * Check to make sure only those flags are set.
9339 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9340 * flags cannot be set. Check for that condition also.
9341 */
9342 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9343 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9344 {
9345 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9346 goto theend;
9347 }
9348
9349 pos = save_cursor = curwin->w_cursor;
9350 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009351 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009352 if (subpatnum != FAIL)
9353 {
9354 if (flags & SP_SUBPAT)
9355 retval = subpatnum;
9356 else
9357 retval = pos.lnum;
9358 if (flags & SP_SETPCMARK)
9359 setpcmark();
9360 curwin->w_cursor = pos;
9361 if (match_pos != NULL)
9362 {
9363 /* Store the match cursor position */
9364 match_pos->lnum = pos.lnum;
9365 match_pos->col = pos.col + 1;
9366 }
9367 /* "/$" will put the cursor after the end of the line, may need to
9368 * correct that here */
9369 check_cursor();
9370 }
9371
9372 /* If 'n' flag is used: restore cursor position. */
9373 if (flags & SP_NOMOVE)
9374 curwin->w_cursor = save_cursor;
9375 else
9376 curwin->w_set_curswant = TRUE;
9377theend:
9378 p_ws = save_p_ws;
9379
9380 return retval;
9381}
9382
9383#ifdef FEAT_FLOAT
9384
9385/*
9386 * round() is not in C90, use ceil() or floor() instead.
9387 */
9388 float_T
9389vim_round(float_T f)
9390{
9391 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9392}
9393
9394/*
9395 * "round({float})" function
9396 */
9397 static void
9398f_round(typval_T *argvars, typval_T *rettv)
9399{
9400 float_T f = 0.0;
9401
9402 rettv->v_type = VAR_FLOAT;
9403 if (get_float_arg(argvars, &f) == OK)
9404 rettv->vval.v_float = vim_round(f);
9405 else
9406 rettv->vval.v_float = 0.0;
9407}
9408#endif
9409
9410/*
9411 * "screenattr()" function
9412 */
9413 static void
9414f_screenattr(typval_T *argvars, typval_T *rettv)
9415{
9416 int row;
9417 int col;
9418 int c;
9419
9420 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9421 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9422 if (row < 0 || row >= screen_Rows
9423 || col < 0 || col >= screen_Columns)
9424 c = -1;
9425 else
9426 c = ScreenAttrs[LineOffset[row] + col];
9427 rettv->vval.v_number = c;
9428}
9429
9430/*
9431 * "screenchar()" function
9432 */
9433 static void
9434f_screenchar(typval_T *argvars, typval_T *rettv)
9435{
9436 int row;
9437 int col;
9438 int off;
9439 int c;
9440
9441 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9442 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9443 if (row < 0 || row >= screen_Rows
9444 || col < 0 || col >= screen_Columns)
9445 c = -1;
9446 else
9447 {
9448 off = LineOffset[row] + col;
9449#ifdef FEAT_MBYTE
9450 if (enc_utf8 && ScreenLinesUC[off] != 0)
9451 c = ScreenLinesUC[off];
9452 else
9453#endif
9454 c = ScreenLines[off];
9455 }
9456 rettv->vval.v_number = c;
9457}
9458
9459/*
9460 * "screencol()" function
9461 *
9462 * First column is 1 to be consistent with virtcol().
9463 */
9464 static void
9465f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9466{
9467 rettv->vval.v_number = screen_screencol() + 1;
9468}
9469
9470/*
9471 * "screenrow()" function
9472 */
9473 static void
9474f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9475{
9476 rettv->vval.v_number = screen_screenrow() + 1;
9477}
9478
9479/*
9480 * "search()" function
9481 */
9482 static void
9483f_search(typval_T *argvars, typval_T *rettv)
9484{
9485 int flags = 0;
9486
9487 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9488}
9489
9490/*
9491 * "searchdecl()" function
9492 */
9493 static void
9494f_searchdecl(typval_T *argvars, typval_T *rettv)
9495{
9496 int locally = 1;
9497 int thisblock = 0;
9498 int error = FALSE;
9499 char_u *name;
9500
9501 rettv->vval.v_number = 1; /* default: FAIL */
9502
9503 name = get_tv_string_chk(&argvars[0]);
9504 if (argvars[1].v_type != VAR_UNKNOWN)
9505 {
9506 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9507 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9508 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9509 }
9510 if (!error && name != NULL)
9511 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9512 locally, thisblock, SEARCH_KEEP) == FAIL;
9513}
9514
9515/*
9516 * Used by searchpair() and searchpairpos()
9517 */
9518 static int
9519searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9520{
9521 char_u *spat, *mpat, *epat;
9522 char_u *skip;
9523 int save_p_ws = p_ws;
9524 int dir;
9525 int flags = 0;
9526 char_u nbuf1[NUMBUFLEN];
9527 char_u nbuf2[NUMBUFLEN];
9528 char_u nbuf3[NUMBUFLEN];
9529 int retval = 0; /* default: FAIL */
9530 long lnum_stop = 0;
9531 long time_limit = 0;
9532
9533 /* Get the three pattern arguments: start, middle, end. */
9534 spat = get_tv_string_chk(&argvars[0]);
9535 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9536 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9537 if (spat == NULL || mpat == NULL || epat == NULL)
9538 goto theend; /* type error */
9539
9540 /* Handle the optional fourth argument: flags */
9541 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9542 if (dir == 0)
9543 goto theend;
9544
9545 /* Don't accept SP_END or SP_SUBPAT.
9546 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9547 */
9548 if ((flags & (SP_END | SP_SUBPAT)) != 0
9549 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9550 {
9551 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9552 goto theend;
9553 }
9554
9555 /* Using 'r' implies 'W', otherwise it doesn't work. */
9556 if (flags & SP_REPEAT)
9557 p_ws = FALSE;
9558
9559 /* Optional fifth argument: skip expression */
9560 if (argvars[3].v_type == VAR_UNKNOWN
9561 || argvars[4].v_type == VAR_UNKNOWN)
9562 skip = (char_u *)"";
9563 else
9564 {
9565 skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
9566 if (argvars[5].v_type != VAR_UNKNOWN)
9567 {
9568 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9569 if (lnum_stop < 0)
9570 goto theend;
9571#ifdef FEAT_RELTIME
9572 if (argvars[6].v_type != VAR_UNKNOWN)
9573 {
9574 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9575 if (time_limit < 0)
9576 goto theend;
9577 }
9578#endif
9579 }
9580 }
9581 if (skip == NULL)
9582 goto theend; /* type error */
9583
9584 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9585 match_pos, lnum_stop, time_limit);
9586
9587theend:
9588 p_ws = save_p_ws;
9589
9590 return retval;
9591}
9592
9593/*
9594 * "searchpair()" function
9595 */
9596 static void
9597f_searchpair(typval_T *argvars, typval_T *rettv)
9598{
9599 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9600}
9601
9602/*
9603 * "searchpairpos()" function
9604 */
9605 static void
9606f_searchpairpos(typval_T *argvars, typval_T *rettv)
9607{
9608 pos_T match_pos;
9609 int lnum = 0;
9610 int col = 0;
9611
9612 if (rettv_list_alloc(rettv) == FAIL)
9613 return;
9614
9615 if (searchpair_cmn(argvars, &match_pos) > 0)
9616 {
9617 lnum = match_pos.lnum;
9618 col = match_pos.col;
9619 }
9620
9621 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9622 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9623}
9624
9625/*
9626 * Search for a start/middle/end thing.
9627 * Used by searchpair(), see its documentation for the details.
9628 * Returns 0 or -1 for no match,
9629 */
9630 long
9631do_searchpair(
9632 char_u *spat, /* start pattern */
9633 char_u *mpat, /* middle pattern */
9634 char_u *epat, /* end pattern */
9635 int dir, /* BACKWARD or FORWARD */
9636 char_u *skip, /* skip expression */
9637 int flags, /* SP_SETPCMARK and other SP_ values */
9638 pos_T *match_pos,
9639 linenr_T lnum_stop, /* stop at this line if not zero */
9640 long time_limit UNUSED) /* stop after this many msec */
9641{
9642 char_u *save_cpo;
9643 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9644 long retval = 0;
9645 pos_T pos;
9646 pos_T firstpos;
9647 pos_T foundpos;
9648 pos_T save_cursor;
9649 pos_T save_pos;
9650 int n;
9651 int r;
9652 int nest = 1;
9653 int err;
9654 int options = SEARCH_KEEP;
9655 proftime_T tm;
9656
9657 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9658 save_cpo = p_cpo;
9659 p_cpo = empty_option;
9660
9661#ifdef FEAT_RELTIME
9662 /* Set the time limit, if there is one. */
9663 profile_setlimit(time_limit, &tm);
9664#endif
9665
9666 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9667 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009668 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9669 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009670 if (pat2 == NULL || pat3 == NULL)
9671 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009672 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009673 if (*mpat == NUL)
9674 STRCPY(pat3, pat2);
9675 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009676 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009677 spat, epat, mpat);
9678 if (flags & SP_START)
9679 options |= SEARCH_START;
9680
9681 save_cursor = curwin->w_cursor;
9682 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009683 CLEAR_POS(&firstpos);
9684 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009685 pat = pat3;
9686 for (;;)
9687 {
9688 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009689 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009690 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009691 /* didn't find it or found the first match again: FAIL */
9692 break;
9693
9694 if (firstpos.lnum == 0)
9695 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009696 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009697 {
9698 /* Found the same position again. Can happen with a pattern that
9699 * has "\zs" at the end and searching backwards. Advance one
9700 * character and try again. */
9701 if (dir == BACKWARD)
9702 decl(&pos);
9703 else
9704 incl(&pos);
9705 }
9706 foundpos = pos;
9707
9708 /* clear the start flag to avoid getting stuck here */
9709 options &= ~SEARCH_START;
9710
9711 /* If the skip pattern matches, ignore this match. */
9712 if (*skip != NUL)
9713 {
9714 save_pos = curwin->w_cursor;
9715 curwin->w_cursor = pos;
9716 r = eval_to_bool(skip, &err, NULL, FALSE);
9717 curwin->w_cursor = save_pos;
9718 if (err)
9719 {
9720 /* Evaluating {skip} caused an error, break here. */
9721 curwin->w_cursor = save_cursor;
9722 retval = -1;
9723 break;
9724 }
9725 if (r)
9726 continue;
9727 }
9728
9729 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9730 {
9731 /* Found end when searching backwards or start when searching
9732 * forward: nested pair. */
9733 ++nest;
9734 pat = pat2; /* nested, don't search for middle */
9735 }
9736 else
9737 {
9738 /* Found end when searching forward or start when searching
9739 * backward: end of (nested) pair; or found middle in outer pair. */
9740 if (--nest == 1)
9741 pat = pat3; /* outer level, search for middle */
9742 }
9743
9744 if (nest == 0)
9745 {
9746 /* Found the match: return matchcount or line number. */
9747 if (flags & SP_RETCOUNT)
9748 ++retval;
9749 else
9750 retval = pos.lnum;
9751 if (flags & SP_SETPCMARK)
9752 setpcmark();
9753 curwin->w_cursor = pos;
9754 if (!(flags & SP_REPEAT))
9755 break;
9756 nest = 1; /* search for next unmatched */
9757 }
9758 }
9759
9760 if (match_pos != NULL)
9761 {
9762 /* Store the match cursor position */
9763 match_pos->lnum = curwin->w_cursor.lnum;
9764 match_pos->col = curwin->w_cursor.col + 1;
9765 }
9766
9767 /* If 'n' flag is used or search failed: restore cursor position. */
9768 if ((flags & SP_NOMOVE) || retval == 0)
9769 curwin->w_cursor = save_cursor;
9770
9771theend:
9772 vim_free(pat2);
9773 vim_free(pat3);
9774 if (p_cpo == empty_option)
9775 p_cpo = save_cpo;
9776 else
9777 /* Darn, evaluating the {skip} expression changed the value. */
9778 free_string_option(save_cpo);
9779
9780 return retval;
9781}
9782
9783/*
9784 * "searchpos()" function
9785 */
9786 static void
9787f_searchpos(typval_T *argvars, typval_T *rettv)
9788{
9789 pos_T match_pos;
9790 int lnum = 0;
9791 int col = 0;
9792 int n;
9793 int flags = 0;
9794
9795 if (rettv_list_alloc(rettv) == FAIL)
9796 return;
9797
9798 n = search_cmn(argvars, &match_pos, &flags);
9799 if (n > 0)
9800 {
9801 lnum = match_pos.lnum;
9802 col = match_pos.col;
9803 }
9804
9805 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9806 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9807 if (flags & SP_SUBPAT)
9808 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9809}
9810
9811 static void
9812f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9813{
9814#ifdef FEAT_CLIENTSERVER
9815 char_u buf[NUMBUFLEN];
9816 char_u *server = get_tv_string_chk(&argvars[0]);
9817 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9818
9819 rettv->vval.v_number = -1;
9820 if (server == NULL || reply == NULL)
9821 return;
9822 if (check_restricted() || check_secure())
9823 return;
9824# ifdef FEAT_X11
9825 if (check_connection() == FAIL)
9826 return;
9827# endif
9828
9829 if (serverSendReply(server, reply) < 0)
9830 {
9831 EMSG(_("E258: Unable to send to client"));
9832 return;
9833 }
9834 rettv->vval.v_number = 0;
9835#else
9836 rettv->vval.v_number = -1;
9837#endif
9838}
9839
9840 static void
9841f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9842{
9843 char_u *r = NULL;
9844
9845#ifdef FEAT_CLIENTSERVER
9846# ifdef WIN32
9847 r = serverGetVimNames();
9848# else
9849 make_connection();
9850 if (X_DISPLAY != NULL)
9851 r = serverGetVimNames(X_DISPLAY);
9852# endif
9853#endif
9854 rettv->v_type = VAR_STRING;
9855 rettv->vval.v_string = r;
9856}
9857
9858/*
9859 * "setbufvar()" function
9860 */
9861 static void
9862f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9863{
9864 buf_T *buf;
9865 char_u *varname, *bufvarname;
9866 typval_T *varp;
9867 char_u nbuf[NUMBUFLEN];
9868
9869 if (check_restricted() || check_secure())
9870 return;
9871 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
9872 varname = get_tv_string_chk(&argvars[1]);
9873 buf = get_buf_tv(&argvars[0], FALSE);
9874 varp = &argvars[2];
9875
9876 if (buf != NULL && varname != NULL && varp != NULL)
9877 {
9878 if (*varname == '&')
9879 {
9880 long numval;
9881 char_u *strval;
9882 int error = FALSE;
9883 aco_save_T aco;
9884
9885 /* set curbuf to be our buf, temporarily */
9886 aucmd_prepbuf(&aco, buf);
9887
9888 ++varname;
9889 numval = (long)get_tv_number_chk(varp, &error);
9890 strval = get_tv_string_buf_chk(varp, nbuf);
9891 if (!error && strval != NULL)
9892 set_option_value(varname, numval, strval, OPT_LOCAL);
9893
9894 /* reset notion of buffer */
9895 aucmd_restbuf(&aco);
9896 }
9897 else
9898 {
9899 buf_T *save_curbuf = curbuf;
9900
9901 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
9902 if (bufvarname != NULL)
9903 {
9904 curbuf = buf;
9905 STRCPY(bufvarname, "b:");
9906 STRCPY(bufvarname + 2, varname);
9907 set_var(bufvarname, varp, TRUE);
9908 vim_free(bufvarname);
9909 curbuf = save_curbuf;
9910 }
9911 }
9912 }
9913}
9914
9915 static void
9916f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9917{
9918 dict_T *d;
9919 dictitem_T *di;
9920 char_u *csearch;
9921
9922 if (argvars[0].v_type != VAR_DICT)
9923 {
9924 EMSG(_(e_dictreq));
9925 return;
9926 }
9927
9928 if ((d = argvars[0].vval.v_dict) != NULL)
9929 {
9930 csearch = get_dict_string(d, (char_u *)"char", FALSE);
9931 if (csearch != NULL)
9932 {
9933#ifdef FEAT_MBYTE
9934 if (enc_utf8)
9935 {
9936 int pcc[MAX_MCO];
9937 int c = utfc_ptr2char(csearch, pcc);
9938
9939 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9940 }
9941 else
9942#endif
9943 set_last_csearch(PTR2CHAR(csearch),
9944 csearch, MB_PTR2LEN(csearch));
9945 }
9946
9947 di = dict_find(d, (char_u *)"forward", -1);
9948 if (di != NULL)
9949 set_csearch_direction((int)get_tv_number(&di->di_tv)
9950 ? FORWARD : BACKWARD);
9951
9952 di = dict_find(d, (char_u *)"until", -1);
9953 if (di != NULL)
9954 set_csearch_until(!!get_tv_number(&di->di_tv));
9955 }
9956}
9957
9958/*
9959 * "setcmdpos()" function
9960 */
9961 static void
9962f_setcmdpos(typval_T *argvars, typval_T *rettv)
9963{
9964 int pos = (int)get_tv_number(&argvars[0]) - 1;
9965
9966 if (pos >= 0)
9967 rettv->vval.v_number = set_cmdline_pos(pos);
9968}
9969
9970/*
9971 * "setfperm({fname}, {mode})" function
9972 */
9973 static void
9974f_setfperm(typval_T *argvars, typval_T *rettv)
9975{
9976 char_u *fname;
9977 char_u modebuf[NUMBUFLEN];
9978 char_u *mode_str;
9979 int i;
9980 int mask;
9981 int mode = 0;
9982
9983 rettv->vval.v_number = 0;
9984 fname = get_tv_string_chk(&argvars[0]);
9985 if (fname == NULL)
9986 return;
9987 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
9988 if (mode_str == NULL)
9989 return;
9990 if (STRLEN(mode_str) != 9)
9991 {
9992 EMSG2(_(e_invarg2), mode_str);
9993 return;
9994 }
9995
9996 mask = 1;
9997 for (i = 8; i >= 0; --i)
9998 {
9999 if (mode_str[i] != '-')
10000 mode |= mask;
10001 mask = mask << 1;
10002 }
10003 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10004}
10005
10006/*
10007 * "setline()" function
10008 */
10009 static void
10010f_setline(typval_T *argvars, typval_T *rettv)
10011{
10012 linenr_T lnum;
10013 char_u *line = NULL;
10014 list_T *l = NULL;
10015 listitem_T *li = NULL;
10016 long added = 0;
10017 linenr_T lcount = curbuf->b_ml.ml_line_count;
10018
10019 lnum = get_tv_lnum(&argvars[0]);
10020 if (argvars[1].v_type == VAR_LIST)
10021 {
10022 l = argvars[1].vval.v_list;
10023 li = l->lv_first;
10024 }
10025 else
10026 line = get_tv_string_chk(&argvars[1]);
10027
10028 /* default result is zero == OK */
10029 for (;;)
10030 {
10031 if (l != NULL)
10032 {
10033 /* list argument, get next string */
10034 if (li == NULL)
10035 break;
10036 line = get_tv_string_chk(&li->li_tv);
10037 li = li->li_next;
10038 }
10039
10040 rettv->vval.v_number = 1; /* FAIL */
10041 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10042 break;
10043
10044 /* When coming here from Insert mode, sync undo, so that this can be
10045 * undone separately from what was previously inserted. */
10046 if (u_sync_once == 2)
10047 {
10048 u_sync_once = 1; /* notify that u_sync() was called */
10049 u_sync(TRUE);
10050 }
10051
10052 if (lnum <= curbuf->b_ml.ml_line_count)
10053 {
10054 /* existing line, replace it */
10055 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10056 {
10057 changed_bytes(lnum, 0);
10058 if (lnum == curwin->w_cursor.lnum)
10059 check_cursor_col();
10060 rettv->vval.v_number = 0; /* OK */
10061 }
10062 }
10063 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10064 {
10065 /* lnum is one past the last line, append the line */
10066 ++added;
10067 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10068 rettv->vval.v_number = 0; /* OK */
10069 }
10070
10071 if (l == NULL) /* only one string argument */
10072 break;
10073 ++lnum;
10074 }
10075
10076 if (added > 0)
10077 appended_lines_mark(lcount, added);
10078}
10079
Bram Moolenaard823fa92016-08-12 16:29:27 +020010080static 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 +020010081
10082/*
10083 * Used by "setqflist()" and "setloclist()" functions
10084 */
10085 static void
10086set_qf_ll_list(
10087 win_T *wp UNUSED,
10088 typval_T *list_arg UNUSED,
10089 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010090 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010091 typval_T *rettv)
10092{
10093#ifdef FEAT_QUICKFIX
10094 static char *e_invact = N_("E927: Invalid action: '%s'");
10095 char_u *act;
10096 int action = 0;
10097#endif
10098
10099 rettv->vval.v_number = -1;
10100
10101#ifdef FEAT_QUICKFIX
10102 if (list_arg->v_type != VAR_LIST)
10103 EMSG(_(e_listreq));
10104 else
10105 {
10106 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010107 dict_T *d = NULL;
10108 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010109
10110 if (action_arg->v_type == VAR_STRING)
10111 {
10112 act = get_tv_string_chk(action_arg);
10113 if (act == NULL)
10114 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010115 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10116 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010117 action = *act;
10118 else
10119 EMSG2(_(e_invact), act);
10120 }
10121 else if (action_arg->v_type == VAR_UNKNOWN)
10122 action = ' ';
10123 else
10124 EMSG(_(e_stringreq));
10125
Bram Moolenaard823fa92016-08-12 16:29:27 +020010126 if (action_arg->v_type != VAR_UNKNOWN
10127 && what_arg->v_type != VAR_UNKNOWN)
10128 {
10129 if (what_arg->v_type == VAR_DICT)
10130 d = what_arg->vval.v_dict;
10131 else
10132 {
10133 EMSG(_(e_dictreq));
10134 valid_dict = FALSE;
10135 }
10136 }
10137
10138 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10139 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010140 rettv->vval.v_number = 0;
10141 }
10142#endif
10143}
10144
10145/*
10146 * "setloclist()" function
10147 */
10148 static void
10149f_setloclist(typval_T *argvars, typval_T *rettv)
10150{
10151 win_T *win;
10152
10153 rettv->vval.v_number = -1;
10154
10155 win = find_win_by_nr(&argvars[0], NULL);
10156 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010157 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010158}
10159
10160/*
10161 * "setmatches()" function
10162 */
10163 static void
10164f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10165{
10166#ifdef FEAT_SEARCH_EXTRA
10167 list_T *l;
10168 listitem_T *li;
10169 dict_T *d;
10170 list_T *s = NULL;
10171
10172 rettv->vval.v_number = -1;
10173 if (argvars[0].v_type != VAR_LIST)
10174 {
10175 EMSG(_(e_listreq));
10176 return;
10177 }
10178 if ((l = argvars[0].vval.v_list) != NULL)
10179 {
10180
10181 /* To some extent make sure that we are dealing with a list from
10182 * "getmatches()". */
10183 li = l->lv_first;
10184 while (li != NULL)
10185 {
10186 if (li->li_tv.v_type != VAR_DICT
10187 || (d = li->li_tv.vval.v_dict) == NULL)
10188 {
10189 EMSG(_(e_invarg));
10190 return;
10191 }
10192 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10193 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10194 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10195 && dict_find(d, (char_u *)"priority", -1) != NULL
10196 && dict_find(d, (char_u *)"id", -1) != NULL))
10197 {
10198 EMSG(_(e_invarg));
10199 return;
10200 }
10201 li = li->li_next;
10202 }
10203
10204 clear_matches(curwin);
10205 li = l->lv_first;
10206 while (li != NULL)
10207 {
10208 int i = 0;
10209 char_u buf[5];
10210 dictitem_T *di;
10211 char_u *group;
10212 int priority;
10213 int id;
10214 char_u *conceal;
10215
10216 d = li->li_tv.vval.v_dict;
10217 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10218 {
10219 if (s == NULL)
10220 {
10221 s = list_alloc();
10222 if (s == NULL)
10223 return;
10224 }
10225
10226 /* match from matchaddpos() */
10227 for (i = 1; i < 9; i++)
10228 {
10229 sprintf((char *)buf, (char *)"pos%d", i);
10230 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10231 {
10232 if (di->di_tv.v_type != VAR_LIST)
10233 return;
10234
10235 list_append_tv(s, &di->di_tv);
10236 s->lv_refcount++;
10237 }
10238 else
10239 break;
10240 }
10241 }
10242
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010243 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 priority = (int)get_dict_number(d, (char_u *)"priority");
10245 id = (int)get_dict_number(d, (char_u *)"id");
10246 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010247 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010248 : NULL;
10249 if (i == 0)
10250 {
10251 match_add(curwin, group,
10252 get_dict_string(d, (char_u *)"pattern", FALSE),
10253 priority, id, NULL, conceal);
10254 }
10255 else
10256 {
10257 match_add(curwin, group, NULL, priority, id, s, conceal);
10258 list_unref(s);
10259 s = NULL;
10260 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010261 vim_free(group);
10262 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010263
10264 li = li->li_next;
10265 }
10266 rettv->vval.v_number = 0;
10267 }
10268#endif
10269}
10270
10271/*
10272 * "setpos()" function
10273 */
10274 static void
10275f_setpos(typval_T *argvars, typval_T *rettv)
10276{
10277 pos_T pos;
10278 int fnum;
10279 char_u *name;
10280 colnr_T curswant = -1;
10281
10282 rettv->vval.v_number = -1;
10283 name = get_tv_string_chk(argvars);
10284 if (name != NULL)
10285 {
10286 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10287 {
10288 if (--pos.col < 0)
10289 pos.col = 0;
10290 if (name[0] == '.' && name[1] == NUL)
10291 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010292 /* set cursor; "fnum" is ignored */
10293 curwin->w_cursor = pos;
10294 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010295 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010296 curwin->w_curswant = curswant - 1;
10297 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010298 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010299 check_cursor();
10300 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010301 }
10302 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10303 {
10304 /* set mark */
10305 if (setmark_pos(name[1], &pos, fnum) == OK)
10306 rettv->vval.v_number = 0;
10307 }
10308 else
10309 EMSG(_(e_invarg));
10310 }
10311 }
10312}
10313
10314/*
10315 * "setqflist()" function
10316 */
10317 static void
10318f_setqflist(typval_T *argvars, typval_T *rettv)
10319{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010320 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010321}
10322
10323/*
10324 * "setreg()" function
10325 */
10326 static void
10327f_setreg(typval_T *argvars, typval_T *rettv)
10328{
10329 int regname;
10330 char_u *strregname;
10331 char_u *stropt;
10332 char_u *strval;
10333 int append;
10334 char_u yank_type;
10335 long block_len;
10336
10337 block_len = -1;
10338 yank_type = MAUTO;
10339 append = FALSE;
10340
10341 strregname = get_tv_string_chk(argvars);
10342 rettv->vval.v_number = 1; /* FAIL is default */
10343
10344 if (strregname == NULL)
10345 return; /* type error; errmsg already given */
10346 regname = *strregname;
10347 if (regname == 0 || regname == '@')
10348 regname = '"';
10349
10350 if (argvars[2].v_type != VAR_UNKNOWN)
10351 {
10352 stropt = get_tv_string_chk(&argvars[2]);
10353 if (stropt == NULL)
10354 return; /* type error */
10355 for (; *stropt != NUL; ++stropt)
10356 switch (*stropt)
10357 {
10358 case 'a': case 'A': /* append */
10359 append = TRUE;
10360 break;
10361 case 'v': case 'c': /* character-wise selection */
10362 yank_type = MCHAR;
10363 break;
10364 case 'V': case 'l': /* line-wise selection */
10365 yank_type = MLINE;
10366 break;
10367 case 'b': case Ctrl_V: /* block-wise selection */
10368 yank_type = MBLOCK;
10369 if (VIM_ISDIGIT(stropt[1]))
10370 {
10371 ++stropt;
10372 block_len = getdigits(&stropt) - 1;
10373 --stropt;
10374 }
10375 break;
10376 }
10377 }
10378
10379 if (argvars[1].v_type == VAR_LIST)
10380 {
10381 char_u **lstval;
10382 char_u **allocval;
10383 char_u buf[NUMBUFLEN];
10384 char_u **curval;
10385 char_u **curallocval;
10386 list_T *ll = argvars[1].vval.v_list;
10387 listitem_T *li;
10388 int len;
10389
10390 /* If the list is NULL handle like an empty list. */
10391 len = ll == NULL ? 0 : ll->lv_len;
10392
10393 /* First half: use for pointers to result lines; second half: use for
10394 * pointers to allocated copies. */
10395 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10396 if (lstval == NULL)
10397 return;
10398 curval = lstval;
10399 allocval = lstval + len + 2;
10400 curallocval = allocval;
10401
10402 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10403 li = li->li_next)
10404 {
10405 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10406 if (strval == NULL)
10407 goto free_lstval;
10408 if (strval == buf)
10409 {
10410 /* Need to make a copy, next get_tv_string_buf_chk() will
10411 * overwrite the string. */
10412 strval = vim_strsave(buf);
10413 if (strval == NULL)
10414 goto free_lstval;
10415 *curallocval++ = strval;
10416 }
10417 *curval++ = strval;
10418 }
10419 *curval++ = NULL;
10420
10421 write_reg_contents_lst(regname, lstval, -1,
10422 append, yank_type, block_len);
10423free_lstval:
10424 while (curallocval > allocval)
10425 vim_free(*--curallocval);
10426 vim_free(lstval);
10427 }
10428 else
10429 {
10430 strval = get_tv_string_chk(&argvars[1]);
10431 if (strval == NULL)
10432 return;
10433 write_reg_contents_ex(regname, strval, -1,
10434 append, yank_type, block_len);
10435 }
10436 rettv->vval.v_number = 0;
10437}
10438
10439/*
10440 * "settabvar()" function
10441 */
10442 static void
10443f_settabvar(typval_T *argvars, typval_T *rettv)
10444{
10445#ifdef FEAT_WINDOWS
10446 tabpage_T *save_curtab;
10447 tabpage_T *tp;
10448#endif
10449 char_u *varname, *tabvarname;
10450 typval_T *varp;
10451
10452 rettv->vval.v_number = 0;
10453
10454 if (check_restricted() || check_secure())
10455 return;
10456
10457#ifdef FEAT_WINDOWS
10458 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
10459#endif
10460 varname = get_tv_string_chk(&argvars[1]);
10461 varp = &argvars[2];
10462
10463 if (varname != NULL && varp != NULL
10464#ifdef FEAT_WINDOWS
10465 && tp != NULL
10466#endif
10467 )
10468 {
10469#ifdef FEAT_WINDOWS
10470 save_curtab = curtab;
10471 goto_tabpage_tp(tp, FALSE, FALSE);
10472#endif
10473
10474 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10475 if (tabvarname != NULL)
10476 {
10477 STRCPY(tabvarname, "t:");
10478 STRCPY(tabvarname + 2, varname);
10479 set_var(tabvarname, varp, TRUE);
10480 vim_free(tabvarname);
10481 }
10482
10483#ifdef FEAT_WINDOWS
10484 /* Restore current tabpage */
10485 if (valid_tabpage(save_curtab))
10486 goto_tabpage_tp(save_curtab, FALSE, FALSE);
10487#endif
10488 }
10489}
10490
10491/*
10492 * "settabwinvar()" function
10493 */
10494 static void
10495f_settabwinvar(typval_T *argvars, typval_T *rettv)
10496{
10497 setwinvar(argvars, rettv, 1);
10498}
10499
10500/*
10501 * "setwinvar()" function
10502 */
10503 static void
10504f_setwinvar(typval_T *argvars, typval_T *rettv)
10505{
10506 setwinvar(argvars, rettv, 0);
10507}
10508
10509#ifdef FEAT_CRYPT
10510/*
10511 * "sha256({string})" function
10512 */
10513 static void
10514f_sha256(typval_T *argvars, typval_T *rettv)
10515{
10516 char_u *p;
10517
10518 p = get_tv_string(&argvars[0]);
10519 rettv->vval.v_string = vim_strsave(
10520 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10521 rettv->v_type = VAR_STRING;
10522}
10523#endif /* FEAT_CRYPT */
10524
10525/*
10526 * "shellescape({string})" function
10527 */
10528 static void
10529f_shellescape(typval_T *argvars, typval_T *rettv)
10530{
Bram Moolenaar20615522017-06-05 18:46:26 +020010531 int do_special = non_zero_arg(&argvars[1]);
10532
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010533 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010534 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010535 rettv->v_type = VAR_STRING;
10536}
10537
10538/*
10539 * shiftwidth() function
10540 */
10541 static void
10542f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10543{
10544 rettv->vval.v_number = get_sw_value(curbuf);
10545}
10546
10547/*
10548 * "simplify()" function
10549 */
10550 static void
10551f_simplify(typval_T *argvars, typval_T *rettv)
10552{
10553 char_u *p;
10554
10555 p = get_tv_string(&argvars[0]);
10556 rettv->vval.v_string = vim_strsave(p);
10557 simplify_filename(rettv->vval.v_string); /* simplify in place */
10558 rettv->v_type = VAR_STRING;
10559}
10560
10561#ifdef FEAT_FLOAT
10562/*
10563 * "sin()" function
10564 */
10565 static void
10566f_sin(typval_T *argvars, typval_T *rettv)
10567{
10568 float_T f = 0.0;
10569
10570 rettv->v_type = VAR_FLOAT;
10571 if (get_float_arg(argvars, &f) == OK)
10572 rettv->vval.v_float = sin(f);
10573 else
10574 rettv->vval.v_float = 0.0;
10575}
10576
10577/*
10578 * "sinh()" function
10579 */
10580 static void
10581f_sinh(typval_T *argvars, typval_T *rettv)
10582{
10583 float_T f = 0.0;
10584
10585 rettv->v_type = VAR_FLOAT;
10586 if (get_float_arg(argvars, &f) == OK)
10587 rettv->vval.v_float = sinh(f);
10588 else
10589 rettv->vval.v_float = 0.0;
10590}
10591#endif
10592
10593static int
10594#ifdef __BORLANDC__
10595 _RTLENTRYF
10596#endif
10597 item_compare(const void *s1, const void *s2);
10598static int
10599#ifdef __BORLANDC__
10600 _RTLENTRYF
10601#endif
10602 item_compare2(const void *s1, const void *s2);
10603
10604/* struct used in the array that's given to qsort() */
10605typedef struct
10606{
10607 listitem_T *item;
10608 int idx;
10609} sortItem_T;
10610
10611/* struct storing information about current sort */
10612typedef struct
10613{
10614 int item_compare_ic;
10615 int item_compare_numeric;
10616 int item_compare_numbers;
10617#ifdef FEAT_FLOAT
10618 int item_compare_float;
10619#endif
10620 char_u *item_compare_func;
10621 partial_T *item_compare_partial;
10622 dict_T *item_compare_selfdict;
10623 int item_compare_func_err;
10624 int item_compare_keep_zero;
10625} sortinfo_T;
10626static sortinfo_T *sortinfo = NULL;
10627static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10628#define ITEM_COMPARE_FAIL 999
10629
10630/*
10631 * Compare functions for f_sort() and f_uniq() below.
10632 */
10633 static int
10634#ifdef __BORLANDC__
10635_RTLENTRYF
10636#endif
10637item_compare(const void *s1, const void *s2)
10638{
10639 sortItem_T *si1, *si2;
10640 typval_T *tv1, *tv2;
10641 char_u *p1, *p2;
10642 char_u *tofree1 = NULL, *tofree2 = NULL;
10643 int res;
10644 char_u numbuf1[NUMBUFLEN];
10645 char_u numbuf2[NUMBUFLEN];
10646
10647 si1 = (sortItem_T *)s1;
10648 si2 = (sortItem_T *)s2;
10649 tv1 = &si1->item->li_tv;
10650 tv2 = &si2->item->li_tv;
10651
10652 if (sortinfo->item_compare_numbers)
10653 {
10654 varnumber_T v1 = get_tv_number(tv1);
10655 varnumber_T v2 = get_tv_number(tv2);
10656
10657 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10658 }
10659
10660#ifdef FEAT_FLOAT
10661 if (sortinfo->item_compare_float)
10662 {
10663 float_T v1 = get_tv_float(tv1);
10664 float_T v2 = get_tv_float(tv2);
10665
10666 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10667 }
10668#endif
10669
10670 /* tv2string() puts quotes around a string and allocates memory. Don't do
10671 * that for string variables. Use a single quote when comparing with a
10672 * non-string to do what the docs promise. */
10673 if (tv1->v_type == VAR_STRING)
10674 {
10675 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10676 p1 = (char_u *)"'";
10677 else
10678 p1 = tv1->vval.v_string;
10679 }
10680 else
10681 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10682 if (tv2->v_type == VAR_STRING)
10683 {
10684 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10685 p2 = (char_u *)"'";
10686 else
10687 p2 = tv2->vval.v_string;
10688 }
10689 else
10690 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10691 if (p1 == NULL)
10692 p1 = (char_u *)"";
10693 if (p2 == NULL)
10694 p2 = (char_u *)"";
10695 if (!sortinfo->item_compare_numeric)
10696 {
10697 if (sortinfo->item_compare_ic)
10698 res = STRICMP(p1, p2);
10699 else
10700 res = STRCMP(p1, p2);
10701 }
10702 else
10703 {
10704 double n1, n2;
10705 n1 = strtod((char *)p1, (char **)&p1);
10706 n2 = strtod((char *)p2, (char **)&p2);
10707 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10708 }
10709
10710 /* When the result would be zero, compare the item indexes. Makes the
10711 * sort stable. */
10712 if (res == 0 && !sortinfo->item_compare_keep_zero)
10713 res = si1->idx > si2->idx ? 1 : -1;
10714
10715 vim_free(tofree1);
10716 vim_free(tofree2);
10717 return res;
10718}
10719
10720 static int
10721#ifdef __BORLANDC__
10722_RTLENTRYF
10723#endif
10724item_compare2(const void *s1, const void *s2)
10725{
10726 sortItem_T *si1, *si2;
10727 int res;
10728 typval_T rettv;
10729 typval_T argv[3];
10730 int dummy;
10731 char_u *func_name;
10732 partial_T *partial = sortinfo->item_compare_partial;
10733
10734 /* shortcut after failure in previous call; compare all items equal */
10735 if (sortinfo->item_compare_func_err)
10736 return 0;
10737
10738 si1 = (sortItem_T *)s1;
10739 si2 = (sortItem_T *)s2;
10740
10741 if (partial == NULL)
10742 func_name = sortinfo->item_compare_func;
10743 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010744 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010745
10746 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10747 * in the copy without changing the original list items. */
10748 copy_tv(&si1->item->li_tv, &argv[0]);
10749 copy_tv(&si2->item->li_tv, &argv[1]);
10750
10751 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10752 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010753 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010754 partial, sortinfo->item_compare_selfdict);
10755 clear_tv(&argv[0]);
10756 clear_tv(&argv[1]);
10757
10758 if (res == FAIL)
10759 res = ITEM_COMPARE_FAIL;
10760 else
10761 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10762 if (sortinfo->item_compare_func_err)
10763 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10764 clear_tv(&rettv);
10765
10766 /* When the result would be zero, compare the pointers themselves. Makes
10767 * the sort stable. */
10768 if (res == 0 && !sortinfo->item_compare_keep_zero)
10769 res = si1->idx > si2->idx ? 1 : -1;
10770
10771 return res;
10772}
10773
10774/*
10775 * "sort({list})" function
10776 */
10777 static void
10778do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10779{
10780 list_T *l;
10781 listitem_T *li;
10782 sortItem_T *ptrs;
10783 sortinfo_T *old_sortinfo;
10784 sortinfo_T info;
10785 long len;
10786 long i;
10787
10788 /* Pointer to current info struct used in compare function. Save and
10789 * restore the current one for nested calls. */
10790 old_sortinfo = sortinfo;
10791 sortinfo = &info;
10792
10793 if (argvars[0].v_type != VAR_LIST)
10794 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10795 else
10796 {
10797 l = argvars[0].vval.v_list;
10798 if (l == NULL || tv_check_lock(l->lv_lock,
10799 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10800 TRUE))
10801 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010802 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010803
10804 len = list_len(l);
10805 if (len <= 1)
10806 goto theend; /* short list sorts pretty quickly */
10807
10808 info.item_compare_ic = FALSE;
10809 info.item_compare_numeric = FALSE;
10810 info.item_compare_numbers = FALSE;
10811#ifdef FEAT_FLOAT
10812 info.item_compare_float = FALSE;
10813#endif
10814 info.item_compare_func = NULL;
10815 info.item_compare_partial = NULL;
10816 info.item_compare_selfdict = NULL;
10817 if (argvars[1].v_type != VAR_UNKNOWN)
10818 {
10819 /* optional second argument: {func} */
10820 if (argvars[1].v_type == VAR_FUNC)
10821 info.item_compare_func = argvars[1].vval.v_string;
10822 else if (argvars[1].v_type == VAR_PARTIAL)
10823 info.item_compare_partial = argvars[1].vval.v_partial;
10824 else
10825 {
10826 int error = FALSE;
10827
10828 i = (long)get_tv_number_chk(&argvars[1], &error);
10829 if (error)
10830 goto theend; /* type error; errmsg already given */
10831 if (i == 1)
10832 info.item_compare_ic = TRUE;
10833 else if (argvars[1].v_type != VAR_NUMBER)
10834 info.item_compare_func = get_tv_string(&argvars[1]);
10835 else if (i != 0)
10836 {
10837 EMSG(_(e_invarg));
10838 goto theend;
10839 }
10840 if (info.item_compare_func != NULL)
10841 {
10842 if (*info.item_compare_func == NUL)
10843 {
10844 /* empty string means default sort */
10845 info.item_compare_func = NULL;
10846 }
10847 else if (STRCMP(info.item_compare_func, "n") == 0)
10848 {
10849 info.item_compare_func = NULL;
10850 info.item_compare_numeric = TRUE;
10851 }
10852 else if (STRCMP(info.item_compare_func, "N") == 0)
10853 {
10854 info.item_compare_func = NULL;
10855 info.item_compare_numbers = TRUE;
10856 }
10857#ifdef FEAT_FLOAT
10858 else if (STRCMP(info.item_compare_func, "f") == 0)
10859 {
10860 info.item_compare_func = NULL;
10861 info.item_compare_float = TRUE;
10862 }
10863#endif
10864 else if (STRCMP(info.item_compare_func, "i") == 0)
10865 {
10866 info.item_compare_func = NULL;
10867 info.item_compare_ic = TRUE;
10868 }
10869 }
10870 }
10871
10872 if (argvars[2].v_type != VAR_UNKNOWN)
10873 {
10874 /* optional third argument: {dict} */
10875 if (argvars[2].v_type != VAR_DICT)
10876 {
10877 EMSG(_(e_dictreq));
10878 goto theend;
10879 }
10880 info.item_compare_selfdict = argvars[2].vval.v_dict;
10881 }
10882 }
10883
10884 /* Make an array with each entry pointing to an item in the List. */
10885 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
10886 if (ptrs == NULL)
10887 goto theend;
10888
10889 i = 0;
10890 if (sort)
10891 {
10892 /* sort(): ptrs will be the list to sort */
10893 for (li = l->lv_first; li != NULL; li = li->li_next)
10894 {
10895 ptrs[i].item = li;
10896 ptrs[i].idx = i;
10897 ++i;
10898 }
10899
10900 info.item_compare_func_err = FALSE;
10901 info.item_compare_keep_zero = FALSE;
10902 /* test the compare function */
10903 if ((info.item_compare_func != NULL
10904 || info.item_compare_partial != NULL)
10905 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
10906 == ITEM_COMPARE_FAIL)
10907 EMSG(_("E702: Sort compare function failed"));
10908 else
10909 {
10910 /* Sort the array with item pointers. */
10911 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
10912 info.item_compare_func == NULL
10913 && info.item_compare_partial == NULL
10914 ? item_compare : item_compare2);
10915
10916 if (!info.item_compare_func_err)
10917 {
10918 /* Clear the List and append the items in sorted order. */
10919 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
10920 l->lv_len = 0;
10921 for (i = 0; i < len; ++i)
10922 list_append(l, ptrs[i].item);
10923 }
10924 }
10925 }
10926 else
10927 {
10928 int (*item_compare_func_ptr)(const void *, const void *);
10929
10930 /* f_uniq(): ptrs will be a stack of items to remove */
10931 info.item_compare_func_err = FALSE;
10932 info.item_compare_keep_zero = TRUE;
10933 item_compare_func_ptr = info.item_compare_func != NULL
10934 || info.item_compare_partial != NULL
10935 ? item_compare2 : item_compare;
10936
10937 for (li = l->lv_first; li != NULL && li->li_next != NULL;
10938 li = li->li_next)
10939 {
10940 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
10941 == 0)
10942 ptrs[i++].item = li;
10943 if (info.item_compare_func_err)
10944 {
10945 EMSG(_("E882: Uniq compare function failed"));
10946 break;
10947 }
10948 }
10949
10950 if (!info.item_compare_func_err)
10951 {
10952 while (--i >= 0)
10953 {
10954 li = ptrs[i].item->li_next;
10955 ptrs[i].item->li_next = li->li_next;
10956 if (li->li_next != NULL)
10957 li->li_next->li_prev = ptrs[i].item;
10958 else
10959 l->lv_last = ptrs[i].item;
10960 list_fix_watch(l, li);
10961 listitem_free(li);
10962 l->lv_len--;
10963 }
10964 }
10965 }
10966
10967 vim_free(ptrs);
10968 }
10969theend:
10970 sortinfo = old_sortinfo;
10971}
10972
10973/*
10974 * "sort({list})" function
10975 */
10976 static void
10977f_sort(typval_T *argvars, typval_T *rettv)
10978{
10979 do_sort_uniq(argvars, rettv, TRUE);
10980}
10981
10982/*
10983 * "uniq({list})" function
10984 */
10985 static void
10986f_uniq(typval_T *argvars, typval_T *rettv)
10987{
10988 do_sort_uniq(argvars, rettv, FALSE);
10989}
10990
10991/*
10992 * "soundfold({word})" function
10993 */
10994 static void
10995f_soundfold(typval_T *argvars, typval_T *rettv)
10996{
10997 char_u *s;
10998
10999 rettv->v_type = VAR_STRING;
11000 s = get_tv_string(&argvars[0]);
11001#ifdef FEAT_SPELL
11002 rettv->vval.v_string = eval_soundfold(s);
11003#else
11004 rettv->vval.v_string = vim_strsave(s);
11005#endif
11006}
11007
11008/*
11009 * "spellbadword()" function
11010 */
11011 static void
11012f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11013{
11014 char_u *word = (char_u *)"";
11015 hlf_T attr = HLF_COUNT;
11016 int len = 0;
11017
11018 if (rettv_list_alloc(rettv) == FAIL)
11019 return;
11020
11021#ifdef FEAT_SPELL
11022 if (argvars[0].v_type == VAR_UNKNOWN)
11023 {
11024 /* Find the start and length of the badly spelled word. */
11025 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11026 if (len != 0)
11027 word = ml_get_cursor();
11028 }
11029 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11030 {
11031 char_u *str = get_tv_string_chk(&argvars[0]);
11032 int capcol = -1;
11033
11034 if (str != NULL)
11035 {
11036 /* Check the argument for spelling. */
11037 while (*str != NUL)
11038 {
11039 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11040 if (attr != HLF_COUNT)
11041 {
11042 word = str;
11043 break;
11044 }
11045 str += len;
11046 }
11047 }
11048 }
11049#endif
11050
11051 list_append_string(rettv->vval.v_list, word, len);
11052 list_append_string(rettv->vval.v_list, (char_u *)(
11053 attr == HLF_SPB ? "bad" :
11054 attr == HLF_SPR ? "rare" :
11055 attr == HLF_SPL ? "local" :
11056 attr == HLF_SPC ? "caps" :
11057 ""), -1);
11058}
11059
11060/*
11061 * "spellsuggest()" function
11062 */
11063 static void
11064f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11065{
11066#ifdef FEAT_SPELL
11067 char_u *str;
11068 int typeerr = FALSE;
11069 int maxcount;
11070 garray_T ga;
11071 int i;
11072 listitem_T *li;
11073 int need_capital = FALSE;
11074#endif
11075
11076 if (rettv_list_alloc(rettv) == FAIL)
11077 return;
11078
11079#ifdef FEAT_SPELL
11080 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11081 {
11082 str = get_tv_string(&argvars[0]);
11083 if (argvars[1].v_type != VAR_UNKNOWN)
11084 {
11085 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11086 if (maxcount <= 0)
11087 return;
11088 if (argvars[2].v_type != VAR_UNKNOWN)
11089 {
11090 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11091 if (typeerr)
11092 return;
11093 }
11094 }
11095 else
11096 maxcount = 25;
11097
11098 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11099
11100 for (i = 0; i < ga.ga_len; ++i)
11101 {
11102 str = ((char_u **)ga.ga_data)[i];
11103
11104 li = listitem_alloc();
11105 if (li == NULL)
11106 vim_free(str);
11107 else
11108 {
11109 li->li_tv.v_type = VAR_STRING;
11110 li->li_tv.v_lock = 0;
11111 li->li_tv.vval.v_string = str;
11112 list_append(rettv->vval.v_list, li);
11113 }
11114 }
11115 ga_clear(&ga);
11116 }
11117#endif
11118}
11119
11120 static void
11121f_split(typval_T *argvars, typval_T *rettv)
11122{
11123 char_u *str;
11124 char_u *end;
11125 char_u *pat = NULL;
11126 regmatch_T regmatch;
11127 char_u patbuf[NUMBUFLEN];
11128 char_u *save_cpo;
11129 int match;
11130 colnr_T col = 0;
11131 int keepempty = FALSE;
11132 int typeerr = FALSE;
11133
11134 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11135 save_cpo = p_cpo;
11136 p_cpo = (char_u *)"";
11137
11138 str = get_tv_string(&argvars[0]);
11139 if (argvars[1].v_type != VAR_UNKNOWN)
11140 {
11141 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11142 if (pat == NULL)
11143 typeerr = TRUE;
11144 if (argvars[2].v_type != VAR_UNKNOWN)
11145 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11146 }
11147 if (pat == NULL || *pat == NUL)
11148 pat = (char_u *)"[\\x01- ]\\+";
11149
11150 if (rettv_list_alloc(rettv) == FAIL)
11151 return;
11152 if (typeerr)
11153 return;
11154
11155 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11156 if (regmatch.regprog != NULL)
11157 {
11158 regmatch.rm_ic = FALSE;
11159 while (*str != NUL || keepempty)
11160 {
11161 if (*str == NUL)
11162 match = FALSE; /* empty item at the end */
11163 else
11164 match = vim_regexec_nl(&regmatch, str, col);
11165 if (match)
11166 end = regmatch.startp[0];
11167 else
11168 end = str + STRLEN(str);
11169 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11170 && *str != NUL && match && end < regmatch.endp[0]))
11171 {
11172 if (list_append_string(rettv->vval.v_list, str,
11173 (int)(end - str)) == FAIL)
11174 break;
11175 }
11176 if (!match)
11177 break;
11178 /* Advance to just after the match. */
11179 if (regmatch.endp[0] > str)
11180 col = 0;
11181 else
11182 {
11183 /* Don't get stuck at the same match. */
11184#ifdef FEAT_MBYTE
11185 col = (*mb_ptr2len)(regmatch.endp[0]);
11186#else
11187 col = 1;
11188#endif
11189 }
11190 str = regmatch.endp[0];
11191 }
11192
11193 vim_regfree(regmatch.regprog);
11194 }
11195
11196 p_cpo = save_cpo;
11197}
11198
11199#ifdef FEAT_FLOAT
11200/*
11201 * "sqrt()" function
11202 */
11203 static void
11204f_sqrt(typval_T *argvars, typval_T *rettv)
11205{
11206 float_T f = 0.0;
11207
11208 rettv->v_type = VAR_FLOAT;
11209 if (get_float_arg(argvars, &f) == OK)
11210 rettv->vval.v_float = sqrt(f);
11211 else
11212 rettv->vval.v_float = 0.0;
11213}
11214
11215/*
11216 * "str2float()" function
11217 */
11218 static void
11219f_str2float(typval_T *argvars, typval_T *rettv)
11220{
11221 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011222 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011223
Bram Moolenaar08243d22017-01-10 16:12:29 +010011224 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011225 p = skipwhite(p + 1);
11226 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011227 if (isneg)
11228 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011229 rettv->v_type = VAR_FLOAT;
11230}
11231#endif
11232
11233/*
11234 * "str2nr()" function
11235 */
11236 static void
11237f_str2nr(typval_T *argvars, typval_T *rettv)
11238{
11239 int base = 10;
11240 char_u *p;
11241 varnumber_T n;
11242 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011243 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011244
11245 if (argvars[1].v_type != VAR_UNKNOWN)
11246 {
11247 base = (int)get_tv_number(&argvars[1]);
11248 if (base != 2 && base != 8 && base != 10 && base != 16)
11249 {
11250 EMSG(_(e_invarg));
11251 return;
11252 }
11253 }
11254
11255 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011256 isneg = (*p == '-');
11257 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011258 p = skipwhite(p + 1);
11259 switch (base)
11260 {
11261 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11262 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11263 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11264 default: what = 0;
11265 }
11266 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011267 if (isneg)
11268 rettv->vval.v_number = -n;
11269 else
11270 rettv->vval.v_number = n;
11271
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011272}
11273
11274#ifdef HAVE_STRFTIME
11275/*
11276 * "strftime({format}[, {time}])" function
11277 */
11278 static void
11279f_strftime(typval_T *argvars, typval_T *rettv)
11280{
11281 char_u result_buf[256];
11282 struct tm *curtime;
11283 time_t seconds;
11284 char_u *p;
11285
11286 rettv->v_type = VAR_STRING;
11287
11288 p = get_tv_string(&argvars[0]);
11289 if (argvars[1].v_type == VAR_UNKNOWN)
11290 seconds = time(NULL);
11291 else
11292 seconds = (time_t)get_tv_number(&argvars[1]);
11293 curtime = localtime(&seconds);
11294 /* MSVC returns NULL for an invalid value of seconds. */
11295 if (curtime == NULL)
11296 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11297 else
11298 {
11299# ifdef FEAT_MBYTE
11300 vimconv_T conv;
11301 char_u *enc;
11302
11303 conv.vc_type = CONV_NONE;
11304 enc = enc_locale();
11305 convert_setup(&conv, p_enc, enc);
11306 if (conv.vc_type != CONV_NONE)
11307 p = string_convert(&conv, p, NULL);
11308# endif
11309 if (p != NULL)
11310 (void)strftime((char *)result_buf, sizeof(result_buf),
11311 (char *)p, curtime);
11312 else
11313 result_buf[0] = NUL;
11314
11315# ifdef FEAT_MBYTE
11316 if (conv.vc_type != CONV_NONE)
11317 vim_free(p);
11318 convert_setup(&conv, enc, p_enc);
11319 if (conv.vc_type != CONV_NONE)
11320 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11321 else
11322# endif
11323 rettv->vval.v_string = vim_strsave(result_buf);
11324
11325# ifdef FEAT_MBYTE
11326 /* Release conversion descriptors */
11327 convert_setup(&conv, NULL, NULL);
11328 vim_free(enc);
11329# endif
11330 }
11331}
11332#endif
11333
11334/*
11335 * "strgetchar()" function
11336 */
11337 static void
11338f_strgetchar(typval_T *argvars, typval_T *rettv)
11339{
11340 char_u *str;
11341 int len;
11342 int error = FALSE;
11343 int charidx;
11344
11345 rettv->vval.v_number = -1;
11346 str = get_tv_string_chk(&argvars[0]);
11347 if (str == NULL)
11348 return;
11349 len = (int)STRLEN(str);
11350 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11351 if (error)
11352 return;
11353#ifdef FEAT_MBYTE
11354 {
11355 int byteidx = 0;
11356
11357 while (charidx >= 0 && byteidx < len)
11358 {
11359 if (charidx == 0)
11360 {
11361 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11362 break;
11363 }
11364 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011365 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011366 }
11367 }
11368#else
11369 if (charidx < len)
11370 rettv->vval.v_number = str[charidx];
11371#endif
11372}
11373
11374/*
11375 * "stridx()" function
11376 */
11377 static void
11378f_stridx(typval_T *argvars, typval_T *rettv)
11379{
11380 char_u buf[NUMBUFLEN];
11381 char_u *needle;
11382 char_u *haystack;
11383 char_u *save_haystack;
11384 char_u *pos;
11385 int start_idx;
11386
11387 needle = get_tv_string_chk(&argvars[1]);
11388 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11389 rettv->vval.v_number = -1;
11390 if (needle == NULL || haystack == NULL)
11391 return; /* type error; errmsg already given */
11392
11393 if (argvars[2].v_type != VAR_UNKNOWN)
11394 {
11395 int error = FALSE;
11396
11397 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11398 if (error || start_idx >= (int)STRLEN(haystack))
11399 return;
11400 if (start_idx >= 0)
11401 haystack += start_idx;
11402 }
11403
11404 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11405 if (pos != NULL)
11406 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11407}
11408
11409/*
11410 * "string()" function
11411 */
11412 static void
11413f_string(typval_T *argvars, typval_T *rettv)
11414{
11415 char_u *tofree;
11416 char_u numbuf[NUMBUFLEN];
11417
11418 rettv->v_type = VAR_STRING;
11419 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11420 get_copyID());
11421 /* Make a copy if we have a value but it's not in allocated memory. */
11422 if (rettv->vval.v_string != NULL && tofree == NULL)
11423 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11424}
11425
11426/*
11427 * "strlen()" function
11428 */
11429 static void
11430f_strlen(typval_T *argvars, typval_T *rettv)
11431{
11432 rettv->vval.v_number = (varnumber_T)(STRLEN(
11433 get_tv_string(&argvars[0])));
11434}
11435
11436/*
11437 * "strchars()" function
11438 */
11439 static void
11440f_strchars(typval_T *argvars, typval_T *rettv)
11441{
11442 char_u *s = get_tv_string(&argvars[0]);
11443 int skipcc = 0;
11444#ifdef FEAT_MBYTE
11445 varnumber_T len = 0;
11446 int (*func_mb_ptr2char_adv)(char_u **pp);
11447#endif
11448
11449 if (argvars[1].v_type != VAR_UNKNOWN)
11450 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11451 if (skipcc < 0 || skipcc > 1)
11452 EMSG(_(e_invarg));
11453 else
11454 {
11455#ifdef FEAT_MBYTE
11456 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11457 while (*s != NUL)
11458 {
11459 func_mb_ptr2char_adv(&s);
11460 ++len;
11461 }
11462 rettv->vval.v_number = len;
11463#else
11464 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11465#endif
11466 }
11467}
11468
11469/*
11470 * "strdisplaywidth()" function
11471 */
11472 static void
11473f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11474{
11475 char_u *s = get_tv_string(&argvars[0]);
11476 int col = 0;
11477
11478 if (argvars[1].v_type != VAR_UNKNOWN)
11479 col = (int)get_tv_number(&argvars[1]);
11480
11481 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11482}
11483
11484/*
11485 * "strwidth()" function
11486 */
11487 static void
11488f_strwidth(typval_T *argvars, typval_T *rettv)
11489{
11490 char_u *s = get_tv_string(&argvars[0]);
11491
11492 rettv->vval.v_number = (varnumber_T)(
11493#ifdef FEAT_MBYTE
11494 mb_string2cells(s, -1)
11495#else
11496 STRLEN(s)
11497#endif
11498 );
11499}
11500
11501/*
11502 * "strcharpart()" function
11503 */
11504 static void
11505f_strcharpart(typval_T *argvars, typval_T *rettv)
11506{
11507#ifdef FEAT_MBYTE
11508 char_u *p;
11509 int nchar;
11510 int nbyte = 0;
11511 int charlen;
11512 int len = 0;
11513 int slen;
11514 int error = FALSE;
11515
11516 p = get_tv_string(&argvars[0]);
11517 slen = (int)STRLEN(p);
11518
11519 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11520 if (!error)
11521 {
11522 if (nchar > 0)
11523 while (nchar > 0 && nbyte < slen)
11524 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011525 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011526 --nchar;
11527 }
11528 else
11529 nbyte = nchar;
11530 if (argvars[2].v_type != VAR_UNKNOWN)
11531 {
11532 charlen = (int)get_tv_number(&argvars[2]);
11533 while (charlen > 0 && nbyte + len < slen)
11534 {
11535 int off = nbyte + len;
11536
11537 if (off < 0)
11538 len += 1;
11539 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011540 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011541 --charlen;
11542 }
11543 }
11544 else
11545 len = slen - nbyte; /* default: all bytes that are available. */
11546 }
11547
11548 /*
11549 * Only return the overlap between the specified part and the actual
11550 * string.
11551 */
11552 if (nbyte < 0)
11553 {
11554 len += nbyte;
11555 nbyte = 0;
11556 }
11557 else if (nbyte > slen)
11558 nbyte = slen;
11559 if (len < 0)
11560 len = 0;
11561 else if (nbyte + len > slen)
11562 len = slen - nbyte;
11563
11564 rettv->v_type = VAR_STRING;
11565 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11566#else
11567 f_strpart(argvars, rettv);
11568#endif
11569}
11570
11571/*
11572 * "strpart()" function
11573 */
11574 static void
11575f_strpart(typval_T *argvars, typval_T *rettv)
11576{
11577 char_u *p;
11578 int n;
11579 int len;
11580 int slen;
11581 int error = FALSE;
11582
11583 p = get_tv_string(&argvars[0]);
11584 slen = (int)STRLEN(p);
11585
11586 n = (int)get_tv_number_chk(&argvars[1], &error);
11587 if (error)
11588 len = 0;
11589 else if (argvars[2].v_type != VAR_UNKNOWN)
11590 len = (int)get_tv_number(&argvars[2]);
11591 else
11592 len = slen - n; /* default len: all bytes that are available. */
11593
11594 /*
11595 * Only return the overlap between the specified part and the actual
11596 * string.
11597 */
11598 if (n < 0)
11599 {
11600 len += n;
11601 n = 0;
11602 }
11603 else if (n > slen)
11604 n = slen;
11605 if (len < 0)
11606 len = 0;
11607 else if (n + len > slen)
11608 len = slen - n;
11609
11610 rettv->v_type = VAR_STRING;
11611 rettv->vval.v_string = vim_strnsave(p + n, len);
11612}
11613
11614/*
11615 * "strridx()" function
11616 */
11617 static void
11618f_strridx(typval_T *argvars, typval_T *rettv)
11619{
11620 char_u buf[NUMBUFLEN];
11621 char_u *needle;
11622 char_u *haystack;
11623 char_u *rest;
11624 char_u *lastmatch = NULL;
11625 int haystack_len, end_idx;
11626
11627 needle = get_tv_string_chk(&argvars[1]);
11628 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11629
11630 rettv->vval.v_number = -1;
11631 if (needle == NULL || haystack == NULL)
11632 return; /* type error; errmsg already given */
11633
11634 haystack_len = (int)STRLEN(haystack);
11635 if (argvars[2].v_type != VAR_UNKNOWN)
11636 {
11637 /* Third argument: upper limit for index */
11638 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11639 if (end_idx < 0)
11640 return; /* can never find a match */
11641 }
11642 else
11643 end_idx = haystack_len;
11644
11645 if (*needle == NUL)
11646 {
11647 /* Empty string matches past the end. */
11648 lastmatch = haystack + end_idx;
11649 }
11650 else
11651 {
11652 for (rest = haystack; *rest != '\0'; ++rest)
11653 {
11654 rest = (char_u *)strstr((char *)rest, (char *)needle);
11655 if (rest == NULL || rest > haystack + end_idx)
11656 break;
11657 lastmatch = rest;
11658 }
11659 }
11660
11661 if (lastmatch == NULL)
11662 rettv->vval.v_number = -1;
11663 else
11664 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11665}
11666
11667/*
11668 * "strtrans()" function
11669 */
11670 static void
11671f_strtrans(typval_T *argvars, typval_T *rettv)
11672{
11673 rettv->v_type = VAR_STRING;
11674 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11675}
11676
11677/*
11678 * "submatch()" function
11679 */
11680 static void
11681f_submatch(typval_T *argvars, typval_T *rettv)
11682{
11683 int error = FALSE;
11684 int no;
11685 int retList = 0;
11686
11687 no = (int)get_tv_number_chk(&argvars[0], &error);
11688 if (error)
11689 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011690 if (no < 0 || no >= NSUBEXP)
11691 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010011692 EMSGN(_("E935: invalid submatch number: %d"), no);
11693 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011694 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011695 if (argvars[1].v_type != VAR_UNKNOWN)
11696 retList = (int)get_tv_number_chk(&argvars[1], &error);
11697 if (error)
11698 return;
11699
11700 if (retList == 0)
11701 {
11702 rettv->v_type = VAR_STRING;
11703 rettv->vval.v_string = reg_submatch(no);
11704 }
11705 else
11706 {
11707 rettv->v_type = VAR_LIST;
11708 rettv->vval.v_list = reg_submatch_list(no);
11709 }
11710}
11711
11712/*
11713 * "substitute()" function
11714 */
11715 static void
11716f_substitute(typval_T *argvars, typval_T *rettv)
11717{
11718 char_u patbuf[NUMBUFLEN];
11719 char_u subbuf[NUMBUFLEN];
11720 char_u flagsbuf[NUMBUFLEN];
11721
11722 char_u *str = get_tv_string_chk(&argvars[0]);
11723 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011724 char_u *sub = NULL;
11725 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011726 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11727
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011728 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11729 expr = &argvars[2];
11730 else
11731 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11732
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011733 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011734 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11735 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011736 rettv->vval.v_string = NULL;
11737 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011738 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011739}
11740
11741/*
11742 * "synID(lnum, col, trans)" function
11743 */
11744 static void
11745f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11746{
11747 int id = 0;
11748#ifdef FEAT_SYN_HL
11749 linenr_T lnum;
11750 colnr_T col;
11751 int trans;
11752 int transerr = FALSE;
11753
11754 lnum = get_tv_lnum(argvars); /* -1 on type error */
11755 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11756 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11757
11758 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11759 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11760 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11761#endif
11762
11763 rettv->vval.v_number = id;
11764}
11765
11766/*
11767 * "synIDattr(id, what [, mode])" function
11768 */
11769 static void
11770f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11771{
11772 char_u *p = NULL;
11773#ifdef FEAT_SYN_HL
11774 int id;
11775 char_u *what;
11776 char_u *mode;
11777 char_u modebuf[NUMBUFLEN];
11778 int modec;
11779
11780 id = (int)get_tv_number(&argvars[0]);
11781 what = get_tv_string(&argvars[1]);
11782 if (argvars[2].v_type != VAR_UNKNOWN)
11783 {
11784 mode = get_tv_string_buf(&argvars[2], modebuf);
11785 modec = TOLOWER_ASC(mode[0]);
11786 if (modec != 't' && modec != 'c' && modec != 'g')
11787 modec = 0; /* replace invalid with current */
11788 }
11789 else
11790 {
11791#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11792 if (USE_24BIT)
11793 modec = 'g';
11794 else
11795#endif
11796 if (t_colors > 1)
11797 modec = 'c';
11798 else
11799 modec = 't';
11800 }
11801
11802
11803 switch (TOLOWER_ASC(what[0]))
11804 {
11805 case 'b':
11806 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11807 p = highlight_color(id, what, modec);
11808 else /* bold */
11809 p = highlight_has_attr(id, HL_BOLD, modec);
11810 break;
11811
11812 case 'f': /* fg[#] or font */
11813 p = highlight_color(id, what, modec);
11814 break;
11815
11816 case 'i':
11817 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11818 p = highlight_has_attr(id, HL_INVERSE, modec);
11819 else /* italic */
11820 p = highlight_has_attr(id, HL_ITALIC, modec);
11821 break;
11822
11823 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011824 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011825 break;
11826
11827 case 'r': /* reverse */
11828 p = highlight_has_attr(id, HL_INVERSE, modec);
11829 break;
11830
11831 case 's':
11832 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11833 p = highlight_color(id, what, modec);
11834 else /* standout */
11835 p = highlight_has_attr(id, HL_STANDOUT, modec);
11836 break;
11837
11838 case 'u':
11839 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11840 /* underline */
11841 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11842 else
11843 /* undercurl */
11844 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11845 break;
11846 }
11847
11848 if (p != NULL)
11849 p = vim_strsave(p);
11850#endif
11851 rettv->v_type = VAR_STRING;
11852 rettv->vval.v_string = p;
11853}
11854
11855/*
11856 * "synIDtrans(id)" function
11857 */
11858 static void
11859f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11860{
11861 int id;
11862
11863#ifdef FEAT_SYN_HL
11864 id = (int)get_tv_number(&argvars[0]);
11865
11866 if (id > 0)
11867 id = syn_get_final_id(id);
11868 else
11869#endif
11870 id = 0;
11871
11872 rettv->vval.v_number = id;
11873}
11874
11875/*
11876 * "synconcealed(lnum, col)" function
11877 */
11878 static void
11879f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11880{
11881#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11882 linenr_T lnum;
11883 colnr_T col;
11884 int syntax_flags = 0;
11885 int cchar;
11886 int matchid = 0;
11887 char_u str[NUMBUFLEN];
11888#endif
11889
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011890 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011891
11892#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11893 lnum = get_tv_lnum(argvars); /* -1 on type error */
11894 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11895
11896 vim_memset(str, NUL, sizeof(str));
11897
11898 if (rettv_list_alloc(rettv) != FAIL)
11899 {
11900 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11901 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11902 && curwin->w_p_cole > 0)
11903 {
11904 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11905 syntax_flags = get_syntax_info(&matchid);
11906
11907 /* get the conceal character */
11908 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11909 {
11910 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011911 if (cchar == NUL && curwin->w_p_cole == 1)
11912 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011913 if (cchar != NUL)
11914 {
11915# ifdef FEAT_MBYTE
11916 if (has_mbyte)
11917 (*mb_char2bytes)(cchar, str);
11918 else
11919# endif
11920 str[0] = cchar;
11921 }
11922 }
11923 }
11924
11925 list_append_number(rettv->vval.v_list,
11926 (syntax_flags & HL_CONCEAL) != 0);
11927 /* -1 to auto-determine strlen */
11928 list_append_string(rettv->vval.v_list, str, -1);
11929 list_append_number(rettv->vval.v_list, matchid);
11930 }
11931#endif
11932}
11933
11934/*
11935 * "synstack(lnum, col)" function
11936 */
11937 static void
11938f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11939{
11940#ifdef FEAT_SYN_HL
11941 linenr_T lnum;
11942 colnr_T col;
11943 int i;
11944 int id;
11945#endif
11946
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011947 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011948
11949#ifdef FEAT_SYN_HL
11950 lnum = get_tv_lnum(argvars); /* -1 on type error */
11951 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11952
11953 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11954 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11955 && rettv_list_alloc(rettv) != FAIL)
11956 {
11957 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11958 for (i = 0; ; ++i)
11959 {
11960 id = syn_get_stack_item(i);
11961 if (id < 0)
11962 break;
11963 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11964 break;
11965 }
11966 }
11967#endif
11968}
11969
11970 static void
11971get_cmd_output_as_rettv(
11972 typval_T *argvars,
11973 typval_T *rettv,
11974 int retlist)
11975{
11976 char_u *res = NULL;
11977 char_u *p;
11978 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011979 int err = FALSE;
11980 FILE *fd;
11981 list_T *list = NULL;
11982 int flags = SHELL_SILENT;
11983
11984 rettv->v_type = VAR_STRING;
11985 rettv->vval.v_string = NULL;
11986 if (check_restricted() || check_secure())
11987 goto errret;
11988
11989 if (argvars[1].v_type != VAR_UNKNOWN)
11990 {
11991 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011992 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011993 * command.
11994 */
11995 if ((infile = vim_tempname('i', TRUE)) == NULL)
11996 {
11997 EMSG(_(e_notmp));
11998 goto errret;
11999 }
12000
12001 fd = mch_fopen((char *)infile, WRITEBIN);
12002 if (fd == NULL)
12003 {
12004 EMSG2(_(e_notopen), infile);
12005 goto errret;
12006 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012007 if (argvars[1].v_type == VAR_NUMBER)
12008 {
12009 linenr_T lnum;
12010 buf_T *buf;
12011
12012 buf = buflist_findnr(argvars[1].vval.v_number);
12013 if (buf == NULL)
12014 {
12015 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012016 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012017 goto errret;
12018 }
12019
12020 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12021 {
12022 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12023 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12024 {
12025 err = TRUE;
12026 break;
12027 }
12028 if (putc(NL, fd) == EOF)
12029 {
12030 err = TRUE;
12031 break;
12032 }
12033 }
12034 }
12035 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012036 {
12037 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12038 err = TRUE;
12039 }
12040 else
12041 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012042 size_t len;
12043 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012044
12045 p = get_tv_string_buf_chk(&argvars[1], buf);
12046 if (p == NULL)
12047 {
12048 fclose(fd);
12049 goto errret; /* type error; errmsg already given */
12050 }
12051 len = STRLEN(p);
12052 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12053 err = TRUE;
12054 }
12055 if (fclose(fd) != 0)
12056 err = TRUE;
12057 if (err)
12058 {
12059 EMSG(_("E677: Error writing temp file"));
12060 goto errret;
12061 }
12062 }
12063
12064 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12065 * echoes typeahead, that messes up the display. */
12066 if (!msg_silent)
12067 flags += SHELL_COOKED;
12068
12069 if (retlist)
12070 {
12071 int len;
12072 listitem_T *li;
12073 char_u *s = NULL;
12074 char_u *start;
12075 char_u *end;
12076 int i;
12077
12078 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12079 if (res == NULL)
12080 goto errret;
12081
12082 list = list_alloc();
12083 if (list == NULL)
12084 goto errret;
12085
12086 for (i = 0; i < len; ++i)
12087 {
12088 start = res + i;
12089 while (i < len && res[i] != NL)
12090 ++i;
12091 end = res + i;
12092
12093 s = alloc((unsigned)(end - start + 1));
12094 if (s == NULL)
12095 goto errret;
12096
12097 for (p = s; start < end; ++p, ++start)
12098 *p = *start == NUL ? NL : *start;
12099 *p = NUL;
12100
12101 li = listitem_alloc();
12102 if (li == NULL)
12103 {
12104 vim_free(s);
12105 goto errret;
12106 }
12107 li->li_tv.v_type = VAR_STRING;
12108 li->li_tv.v_lock = 0;
12109 li->li_tv.vval.v_string = s;
12110 list_append(list, li);
12111 }
12112
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012113 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012114 list = NULL;
12115 }
12116 else
12117 {
12118 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12119#ifdef USE_CR
12120 /* translate <CR> into <NL> */
12121 if (res != NULL)
12122 {
12123 char_u *s;
12124
12125 for (s = res; *s; ++s)
12126 {
12127 if (*s == CAR)
12128 *s = NL;
12129 }
12130 }
12131#else
12132# ifdef USE_CRNL
12133 /* translate <CR><NL> into <NL> */
12134 if (res != NULL)
12135 {
12136 char_u *s, *d;
12137
12138 d = res;
12139 for (s = res; *s; ++s)
12140 {
12141 if (s[0] == CAR && s[1] == NL)
12142 ++s;
12143 *d++ = *s;
12144 }
12145 *d = NUL;
12146 }
12147# endif
12148#endif
12149 rettv->vval.v_string = res;
12150 res = NULL;
12151 }
12152
12153errret:
12154 if (infile != NULL)
12155 {
12156 mch_remove(infile);
12157 vim_free(infile);
12158 }
12159 if (res != NULL)
12160 vim_free(res);
12161 if (list != NULL)
12162 list_free(list);
12163}
12164
12165/*
12166 * "system()" function
12167 */
12168 static void
12169f_system(typval_T *argvars, typval_T *rettv)
12170{
12171 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12172}
12173
12174/*
12175 * "systemlist()" function
12176 */
12177 static void
12178f_systemlist(typval_T *argvars, typval_T *rettv)
12179{
12180 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12181}
12182
12183/*
12184 * "tabpagebuflist()" function
12185 */
12186 static void
12187f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12188{
12189#ifdef FEAT_WINDOWS
12190 tabpage_T *tp;
12191 win_T *wp = NULL;
12192
12193 if (argvars[0].v_type == VAR_UNKNOWN)
12194 wp = firstwin;
12195 else
12196 {
12197 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12198 if (tp != NULL)
12199 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12200 }
12201 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12202 {
12203 for (; wp != NULL; wp = wp->w_next)
12204 if (list_append_number(rettv->vval.v_list,
12205 wp->w_buffer->b_fnum) == FAIL)
12206 break;
12207 }
12208#endif
12209}
12210
12211
12212/*
12213 * "tabpagenr()" function
12214 */
12215 static void
12216f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12217{
12218 int nr = 1;
12219#ifdef FEAT_WINDOWS
12220 char_u *arg;
12221
12222 if (argvars[0].v_type != VAR_UNKNOWN)
12223 {
12224 arg = get_tv_string_chk(&argvars[0]);
12225 nr = 0;
12226 if (arg != NULL)
12227 {
12228 if (STRCMP(arg, "$") == 0)
12229 nr = tabpage_index(NULL) - 1;
12230 else
12231 EMSG2(_(e_invexpr2), arg);
12232 }
12233 }
12234 else
12235 nr = tabpage_index(curtab);
12236#endif
12237 rettv->vval.v_number = nr;
12238}
12239
12240
12241#ifdef FEAT_WINDOWS
12242static int get_winnr(tabpage_T *tp, typval_T *argvar);
12243
12244/*
12245 * Common code for tabpagewinnr() and winnr().
12246 */
12247 static int
12248get_winnr(tabpage_T *tp, typval_T *argvar)
12249{
12250 win_T *twin;
12251 int nr = 1;
12252 win_T *wp;
12253 char_u *arg;
12254
12255 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12256 if (argvar->v_type != VAR_UNKNOWN)
12257 {
12258 arg = get_tv_string_chk(argvar);
12259 if (arg == NULL)
12260 nr = 0; /* type error; errmsg already given */
12261 else if (STRCMP(arg, "$") == 0)
12262 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12263 else if (STRCMP(arg, "#") == 0)
12264 {
12265 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12266 if (twin == NULL)
12267 nr = 0;
12268 }
12269 else
12270 {
12271 EMSG2(_(e_invexpr2), arg);
12272 nr = 0;
12273 }
12274 }
12275
12276 if (nr > 0)
12277 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12278 wp != twin; wp = wp->w_next)
12279 {
12280 if (wp == NULL)
12281 {
12282 /* didn't find it in this tabpage */
12283 nr = 0;
12284 break;
12285 }
12286 ++nr;
12287 }
12288 return nr;
12289}
12290#endif
12291
12292/*
12293 * "tabpagewinnr()" function
12294 */
12295 static void
12296f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12297{
12298 int nr = 1;
12299#ifdef FEAT_WINDOWS
12300 tabpage_T *tp;
12301
12302 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12303 if (tp == NULL)
12304 nr = 0;
12305 else
12306 nr = get_winnr(tp, &argvars[1]);
12307#endif
12308 rettv->vval.v_number = nr;
12309}
12310
12311
12312/*
12313 * "tagfiles()" function
12314 */
12315 static void
12316f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12317{
12318 char_u *fname;
12319 tagname_T tn;
12320 int first;
12321
12322 if (rettv_list_alloc(rettv) == FAIL)
12323 return;
12324 fname = alloc(MAXPATHL);
12325 if (fname == NULL)
12326 return;
12327
12328 for (first = TRUE; ; first = FALSE)
12329 if (get_tagfname(&tn, first, fname) == FAIL
12330 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12331 break;
12332 tagname_free(&tn);
12333 vim_free(fname);
12334}
12335
12336/*
12337 * "taglist()" function
12338 */
12339 static void
12340f_taglist(typval_T *argvars, typval_T *rettv)
12341{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012342 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012343 char_u *tag_pattern;
12344
12345 tag_pattern = get_tv_string(&argvars[0]);
12346
12347 rettv->vval.v_number = FALSE;
12348 if (*tag_pattern == NUL)
12349 return;
12350
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012351 if (argvars[1].v_type != VAR_UNKNOWN)
12352 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012353 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012354 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012355}
12356
12357/*
12358 * "tempname()" function
12359 */
12360 static void
12361f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12362{
12363 static int x = 'A';
12364
12365 rettv->v_type = VAR_STRING;
12366 rettv->vval.v_string = vim_tempname(x, FALSE);
12367
12368 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12369 * names. Skip 'I' and 'O', they are used for shell redirection. */
12370 do
12371 {
12372 if (x == 'Z')
12373 x = '0';
12374 else if (x == '9')
12375 x = 'A';
12376 else
12377 {
12378#ifdef EBCDIC
12379 if (x == 'I')
12380 x = 'J';
12381 else if (x == 'R')
12382 x = 'S';
12383 else
12384#endif
12385 ++x;
12386 }
12387 } while (x == 'I' || x == 'O');
12388}
12389
12390#ifdef FEAT_FLOAT
12391/*
12392 * "tan()" function
12393 */
12394 static void
12395f_tan(typval_T *argvars, typval_T *rettv)
12396{
12397 float_T f = 0.0;
12398
12399 rettv->v_type = VAR_FLOAT;
12400 if (get_float_arg(argvars, &f) == OK)
12401 rettv->vval.v_float = tan(f);
12402 else
12403 rettv->vval.v_float = 0.0;
12404}
12405
12406/*
12407 * "tanh()" function
12408 */
12409 static void
12410f_tanh(typval_T *argvars, typval_T *rettv)
12411{
12412 float_T f = 0.0;
12413
12414 rettv->v_type = VAR_FLOAT;
12415 if (get_float_arg(argvars, &f) == OK)
12416 rettv->vval.v_float = tanh(f);
12417 else
12418 rettv->vval.v_float = 0.0;
12419}
12420#endif
12421
12422/*
12423 * "test_alloc_fail(id, countdown, repeat)" function
12424 */
12425 static void
12426f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12427{
12428 if (argvars[0].v_type != VAR_NUMBER
12429 || argvars[0].vval.v_number <= 0
12430 || argvars[1].v_type != VAR_NUMBER
12431 || argvars[1].vval.v_number < 0
12432 || argvars[2].v_type != VAR_NUMBER)
12433 EMSG(_(e_invarg));
12434 else
12435 {
12436 alloc_fail_id = argvars[0].vval.v_number;
12437 if (alloc_fail_id >= aid_last)
12438 EMSG(_(e_invarg));
12439 alloc_fail_countdown = argvars[1].vval.v_number;
12440 alloc_fail_repeat = argvars[2].vval.v_number;
12441 did_outofmem_msg = FALSE;
12442 }
12443}
12444
12445/*
12446 * "test_autochdir()"
12447 */
12448 static void
12449f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12450{
12451#if defined(FEAT_AUTOCHDIR)
12452 test_autochdir = TRUE;
12453#endif
12454}
12455
12456/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012457 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012458 */
12459 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012460f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012461{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012462 char_u *name = (char_u *)"";
12463 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012464 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012465
12466 if (argvars[0].v_type != VAR_STRING
12467 || (argvars[1].v_type) != VAR_NUMBER)
12468 EMSG(_(e_invarg));
12469 else
12470 {
12471 name = get_tv_string_chk(&argvars[0]);
12472 val = (int)get_tv_number(&argvars[1]);
12473
12474 if (STRCMP(name, (char_u *)"redraw") == 0)
12475 disable_redraw_for_testing = val;
12476 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12477 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012478 else if (STRCMP(name, (char_u *)"starting") == 0)
12479 {
12480 if (val)
12481 {
12482 if (save_starting < 0)
12483 save_starting = starting;
12484 starting = 0;
12485 }
12486 else
12487 {
12488 starting = save_starting;
12489 save_starting = -1;
12490 }
12491 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012492 else if (STRCMP(name, (char_u *)"ALL") == 0)
12493 {
12494 disable_char_avail_for_testing = FALSE;
12495 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012496 if (save_starting >= 0)
12497 {
12498 starting = save_starting;
12499 save_starting = -1;
12500 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012501 }
12502 else
12503 EMSG2(_(e_invarg2), name);
12504 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012505}
12506
12507/*
12508 * "test_garbagecollect_now()" function
12509 */
12510 static void
12511f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12512{
12513 /* This is dangerous, any Lists and Dicts used internally may be freed
12514 * while still in use. */
12515 garbage_collect(TRUE);
12516}
12517
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012518/*
12519 * "test_ignore_error()" function
12520 */
12521 static void
12522f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12523{
12524 ignore_error_for_testing(get_tv_string(&argvars[0]));
12525}
12526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012527#ifdef FEAT_JOB_CHANNEL
12528 static void
12529f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12530{
12531 rettv->v_type = VAR_CHANNEL;
12532 rettv->vval.v_channel = NULL;
12533}
12534#endif
12535
12536 static void
12537f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12538{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012539 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012540}
12541
12542#ifdef FEAT_JOB_CHANNEL
12543 static void
12544f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12545{
12546 rettv->v_type = VAR_JOB;
12547 rettv->vval.v_job = NULL;
12548}
12549#endif
12550
12551 static void
12552f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12553{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012554 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012555}
12556
12557 static void
12558f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12559{
12560 rettv->v_type = VAR_PARTIAL;
12561 rettv->vval.v_partial = NULL;
12562}
12563
12564 static void
12565f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12566{
12567 rettv->v_type = VAR_STRING;
12568 rettv->vval.v_string = NULL;
12569}
12570
12571 static void
12572f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12573{
12574 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12575}
12576
12577#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12578/*
12579 * Get a callback from "arg". It can be a Funcref or a function name.
12580 * When "arg" is zero return an empty string.
12581 * Return NULL for an invalid argument.
12582 */
12583 char_u *
12584get_callback(typval_T *arg, partial_T **pp)
12585{
12586 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12587 {
12588 *pp = arg->vval.v_partial;
12589 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012590 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012591 }
12592 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012593 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012594 {
12595 func_ref(arg->vval.v_string);
12596 return arg->vval.v_string;
12597 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012598 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12599 return (char_u *)"";
12600 EMSG(_("E921: Invalid callback argument"));
12601 return NULL;
12602}
12603
12604/*
12605 * Unref/free "callback" and "partial" retured by get_callback().
12606 */
12607 void
12608free_callback(char_u *callback, partial_T *partial)
12609{
12610 if (partial != NULL)
12611 partial_unref(partial);
12612 else if (callback != NULL)
12613 {
12614 func_unref(callback);
12615 vim_free(callback);
12616 }
12617}
12618#endif
12619
12620#ifdef FEAT_TIMERS
12621/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012622 * "timer_info([timer])" function
12623 */
12624 static void
12625f_timer_info(typval_T *argvars, typval_T *rettv)
12626{
12627 timer_T *timer = NULL;
12628
12629 if (rettv_list_alloc(rettv) != OK)
12630 return;
12631 if (argvars[0].v_type != VAR_UNKNOWN)
12632 {
12633 if (argvars[0].v_type != VAR_NUMBER)
12634 EMSG(_(e_number_exp));
12635 else
12636 {
12637 timer = find_timer((int)get_tv_number(&argvars[0]));
12638 if (timer != NULL)
12639 add_timer_info(rettv, timer);
12640 }
12641 }
12642 else
12643 add_timer_info_all(rettv);
12644}
12645
12646/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012647 * "timer_pause(timer, paused)" function
12648 */
12649 static void
12650f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12651{
12652 timer_T *timer = NULL;
12653 int paused = (int)get_tv_number(&argvars[1]);
12654
12655 if (argvars[0].v_type != VAR_NUMBER)
12656 EMSG(_(e_number_exp));
12657 else
12658 {
12659 timer = find_timer((int)get_tv_number(&argvars[0]));
12660 if (timer != NULL)
12661 timer->tr_paused = paused;
12662 }
12663}
12664
12665/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012666 * "timer_start(time, callback [, options])" function
12667 */
12668 static void
12669f_timer_start(typval_T *argvars, typval_T *rettv)
12670{
Bram Moolenaar75537a92016-09-05 22:45:28 +020012671 long msec = (long)get_tv_number(&argvars[0]);
12672 timer_T *timer;
12673 int repeat = 0;
12674 char_u *callback;
12675 dict_T *dict;
12676 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012677
Bram Moolenaar75537a92016-09-05 22:45:28 +020012678 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012679 if (check_secure())
12680 return;
12681 if (argvars[2].v_type != VAR_UNKNOWN)
12682 {
12683 if (argvars[2].v_type != VAR_DICT
12684 || (dict = argvars[2].vval.v_dict) == NULL)
12685 {
12686 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12687 return;
12688 }
12689 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12690 repeat = get_dict_number(dict, (char_u *)"repeat");
12691 }
12692
Bram Moolenaar75537a92016-09-05 22:45:28 +020012693 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012694 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012695 return;
12696
12697 timer = create_timer(msec, repeat);
12698 if (timer == NULL)
12699 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012700 else
12701 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020012702 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020012703 timer->tr_callback = vim_strsave(callback);
12704 else
12705 /* pointer into the partial */
12706 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012707 timer->tr_partial = partial;
12708 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012709 }
12710}
12711
12712/*
12713 * "timer_stop(timer)" function
12714 */
12715 static void
12716f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12717{
12718 timer_T *timer;
12719
12720 if (argvars[0].v_type != VAR_NUMBER)
12721 {
12722 EMSG(_(e_number_exp));
12723 return;
12724 }
12725 timer = find_timer((int)get_tv_number(&argvars[0]));
12726 if (timer != NULL)
12727 stop_timer(timer);
12728}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012729
12730/*
12731 * "timer_stopall()" function
12732 */
12733 static void
12734f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12735{
12736 stop_all_timers();
12737}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012738#endif
12739
12740/*
12741 * "tolower(string)" function
12742 */
12743 static void
12744f_tolower(typval_T *argvars, typval_T *rettv)
12745{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012746 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010012747 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012748}
12749
12750/*
12751 * "toupper(string)" function
12752 */
12753 static void
12754f_toupper(typval_T *argvars, typval_T *rettv)
12755{
12756 rettv->v_type = VAR_STRING;
12757 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12758}
12759
12760/*
12761 * "tr(string, fromstr, tostr)" function
12762 */
12763 static void
12764f_tr(typval_T *argvars, typval_T *rettv)
12765{
12766 char_u *in_str;
12767 char_u *fromstr;
12768 char_u *tostr;
12769 char_u *p;
12770#ifdef FEAT_MBYTE
12771 int inlen;
12772 int fromlen;
12773 int tolen;
12774 int idx;
12775 char_u *cpstr;
12776 int cplen;
12777 int first = TRUE;
12778#endif
12779 char_u buf[NUMBUFLEN];
12780 char_u buf2[NUMBUFLEN];
12781 garray_T ga;
12782
12783 in_str = get_tv_string(&argvars[0]);
12784 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12785 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12786
12787 /* Default return value: empty string. */
12788 rettv->v_type = VAR_STRING;
12789 rettv->vval.v_string = NULL;
12790 if (fromstr == NULL || tostr == NULL)
12791 return; /* type error; errmsg already given */
12792 ga_init2(&ga, (int)sizeof(char), 80);
12793
12794#ifdef FEAT_MBYTE
12795 if (!has_mbyte)
12796#endif
12797 /* not multi-byte: fromstr and tostr must be the same length */
12798 if (STRLEN(fromstr) != STRLEN(tostr))
12799 {
12800#ifdef FEAT_MBYTE
12801error:
12802#endif
12803 EMSG2(_(e_invarg2), fromstr);
12804 ga_clear(&ga);
12805 return;
12806 }
12807
12808 /* fromstr and tostr have to contain the same number of chars */
12809 while (*in_str != NUL)
12810 {
12811#ifdef FEAT_MBYTE
12812 if (has_mbyte)
12813 {
12814 inlen = (*mb_ptr2len)(in_str);
12815 cpstr = in_str;
12816 cplen = inlen;
12817 idx = 0;
12818 for (p = fromstr; *p != NUL; p += fromlen)
12819 {
12820 fromlen = (*mb_ptr2len)(p);
12821 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12822 {
12823 for (p = tostr; *p != NUL; p += tolen)
12824 {
12825 tolen = (*mb_ptr2len)(p);
12826 if (idx-- == 0)
12827 {
12828 cplen = tolen;
12829 cpstr = p;
12830 break;
12831 }
12832 }
12833 if (*p == NUL) /* tostr is shorter than fromstr */
12834 goto error;
12835 break;
12836 }
12837 ++idx;
12838 }
12839
12840 if (first && cpstr == in_str)
12841 {
12842 /* Check that fromstr and tostr have the same number of
12843 * (multi-byte) characters. Done only once when a character
12844 * of in_str doesn't appear in fromstr. */
12845 first = FALSE;
12846 for (p = tostr; *p != NUL; p += tolen)
12847 {
12848 tolen = (*mb_ptr2len)(p);
12849 --idx;
12850 }
12851 if (idx != 0)
12852 goto error;
12853 }
12854
12855 (void)ga_grow(&ga, cplen);
12856 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12857 ga.ga_len += cplen;
12858
12859 in_str += inlen;
12860 }
12861 else
12862#endif
12863 {
12864 /* When not using multi-byte chars we can do it faster. */
12865 p = vim_strchr(fromstr, *in_str);
12866 if (p != NULL)
12867 ga_append(&ga, tostr[p - fromstr]);
12868 else
12869 ga_append(&ga, *in_str);
12870 ++in_str;
12871 }
12872 }
12873
12874 /* add a terminating NUL */
12875 (void)ga_grow(&ga, 1);
12876 ga_append(&ga, NUL);
12877
12878 rettv->vval.v_string = ga.ga_data;
12879}
12880
12881#ifdef FEAT_FLOAT
12882/*
12883 * "trunc({float})" function
12884 */
12885 static void
12886f_trunc(typval_T *argvars, typval_T *rettv)
12887{
12888 float_T f = 0.0;
12889
12890 rettv->v_type = VAR_FLOAT;
12891 if (get_float_arg(argvars, &f) == OK)
12892 /* trunc() is not in C90, use floor() or ceil() instead. */
12893 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12894 else
12895 rettv->vval.v_float = 0.0;
12896}
12897#endif
12898
12899/*
12900 * "type(expr)" function
12901 */
12902 static void
12903f_type(typval_T *argvars, typval_T *rettv)
12904{
12905 int n = -1;
12906
12907 switch (argvars[0].v_type)
12908 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012909 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12910 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012911 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012912 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12913 case VAR_LIST: n = VAR_TYPE_LIST; break;
12914 case VAR_DICT: n = VAR_TYPE_DICT; break;
12915 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012916 case VAR_SPECIAL:
12917 if (argvars[0].vval.v_number == VVAL_FALSE
12918 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012919 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012920 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012921 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012922 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012923 case VAR_JOB: n = VAR_TYPE_JOB; break;
12924 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012925 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012926 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012927 n = -1;
12928 break;
12929 }
12930 rettv->vval.v_number = n;
12931}
12932
12933/*
12934 * "undofile(name)" function
12935 */
12936 static void
12937f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12938{
12939 rettv->v_type = VAR_STRING;
12940#ifdef FEAT_PERSISTENT_UNDO
12941 {
12942 char_u *fname = get_tv_string(&argvars[0]);
12943
12944 if (*fname == NUL)
12945 {
12946 /* If there is no file name there will be no undo file. */
12947 rettv->vval.v_string = NULL;
12948 }
12949 else
12950 {
12951 char_u *ffname = FullName_save(fname, FALSE);
12952
12953 if (ffname != NULL)
12954 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12955 vim_free(ffname);
12956 }
12957 }
12958#else
12959 rettv->vval.v_string = NULL;
12960#endif
12961}
12962
12963/*
12964 * "undotree()" function
12965 */
12966 static void
12967f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12968{
12969 if (rettv_dict_alloc(rettv) == OK)
12970 {
12971 dict_T *dict = rettv->vval.v_dict;
12972 list_T *list;
12973
12974 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
12975 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
12976 dict_add_nr_str(dict, "save_last",
12977 (long)curbuf->b_u_save_nr_last, NULL);
12978 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
12979 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
12980 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
12981
12982 list = list_alloc();
12983 if (list != NULL)
12984 {
12985 u_eval_tree(curbuf->b_u_oldhead, list);
12986 dict_add_list(dict, "entries", list);
12987 }
12988 }
12989}
12990
12991/*
12992 * "values(dict)" function
12993 */
12994 static void
12995f_values(typval_T *argvars, typval_T *rettv)
12996{
12997 dict_list(argvars, rettv, 1);
12998}
12999
13000/*
13001 * "virtcol(string)" function
13002 */
13003 static void
13004f_virtcol(typval_T *argvars, typval_T *rettv)
13005{
13006 colnr_T vcol = 0;
13007 pos_T *fp;
13008 int fnum = curbuf->b_fnum;
13009
13010 fp = var2fpos(&argvars[0], FALSE, &fnum);
13011 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13012 && fnum == curbuf->b_fnum)
13013 {
13014 getvvcol(curwin, fp, NULL, NULL, &vcol);
13015 ++vcol;
13016 }
13017
13018 rettv->vval.v_number = vcol;
13019}
13020
13021/*
13022 * "visualmode()" function
13023 */
13024 static void
13025f_visualmode(typval_T *argvars, typval_T *rettv)
13026{
13027 char_u str[2];
13028
13029 rettv->v_type = VAR_STRING;
13030 str[0] = curbuf->b_visual_mode_eval;
13031 str[1] = NUL;
13032 rettv->vval.v_string = vim_strsave(str);
13033
13034 /* A non-zero number or non-empty string argument: reset mode. */
13035 if (non_zero_arg(&argvars[0]))
13036 curbuf->b_visual_mode_eval = NUL;
13037}
13038
13039/*
13040 * "wildmenumode()" function
13041 */
13042 static void
13043f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13044{
13045#ifdef FEAT_WILDMENU
13046 if (wild_menu_showing)
13047 rettv->vval.v_number = 1;
13048#endif
13049}
13050
13051/*
13052 * "winbufnr(nr)" function
13053 */
13054 static void
13055f_winbufnr(typval_T *argvars, typval_T *rettv)
13056{
13057 win_T *wp;
13058
13059 wp = find_win_by_nr(&argvars[0], NULL);
13060 if (wp == NULL)
13061 rettv->vval.v_number = -1;
13062 else
13063 rettv->vval.v_number = wp->w_buffer->b_fnum;
13064}
13065
13066/*
13067 * "wincol()" function
13068 */
13069 static void
13070f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13071{
13072 validate_cursor();
13073 rettv->vval.v_number = curwin->w_wcol + 1;
13074}
13075
13076/*
13077 * "winheight(nr)" function
13078 */
13079 static void
13080f_winheight(typval_T *argvars, typval_T *rettv)
13081{
13082 win_T *wp;
13083
13084 wp = find_win_by_nr(&argvars[0], NULL);
13085 if (wp == NULL)
13086 rettv->vval.v_number = -1;
13087 else
13088 rettv->vval.v_number = wp->w_height;
13089}
13090
13091/*
13092 * "winline()" function
13093 */
13094 static void
13095f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13096{
13097 validate_cursor();
13098 rettv->vval.v_number = curwin->w_wrow + 1;
13099}
13100
13101/*
13102 * "winnr()" function
13103 */
13104 static void
13105f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13106{
13107 int nr = 1;
13108
13109#ifdef FEAT_WINDOWS
13110 nr = get_winnr(curtab, &argvars[0]);
13111#endif
13112 rettv->vval.v_number = nr;
13113}
13114
13115/*
13116 * "winrestcmd()" function
13117 */
13118 static void
13119f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13120{
13121#ifdef FEAT_WINDOWS
13122 win_T *wp;
13123 int winnr = 1;
13124 garray_T ga;
13125 char_u buf[50];
13126
13127 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013128 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013129 {
13130 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13131 ga_concat(&ga, buf);
13132 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13133 ga_concat(&ga, buf);
13134 ++winnr;
13135 }
13136 ga_append(&ga, NUL);
13137
13138 rettv->vval.v_string = ga.ga_data;
13139#else
13140 rettv->vval.v_string = NULL;
13141#endif
13142 rettv->v_type = VAR_STRING;
13143}
13144
13145/*
13146 * "winrestview()" function
13147 */
13148 static void
13149f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13150{
13151 dict_T *dict;
13152
13153 if (argvars[0].v_type != VAR_DICT
13154 || (dict = argvars[0].vval.v_dict) == NULL)
13155 EMSG(_(e_invarg));
13156 else
13157 {
13158 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13159 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13160 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13161 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13162#ifdef FEAT_VIRTUALEDIT
13163 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13164 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13165#endif
13166 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13167 {
13168 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13169 curwin->w_set_curswant = FALSE;
13170 }
13171
13172 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13173 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13174#ifdef FEAT_DIFF
13175 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13176 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13177#endif
13178 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13179 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13180 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13181 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13182
13183 check_cursor();
13184 win_new_height(curwin, curwin->w_height);
13185# ifdef FEAT_WINDOWS
13186 win_new_width(curwin, W_WIDTH(curwin));
13187# endif
13188 changed_window_setting();
13189
13190 if (curwin->w_topline <= 0)
13191 curwin->w_topline = 1;
13192 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13193 curwin->w_topline = curbuf->b_ml.ml_line_count;
13194#ifdef FEAT_DIFF
13195 check_topfill(curwin, TRUE);
13196#endif
13197 }
13198}
13199
13200/*
13201 * "winsaveview()" function
13202 */
13203 static void
13204f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13205{
13206 dict_T *dict;
13207
13208 if (rettv_dict_alloc(rettv) == FAIL)
13209 return;
13210 dict = rettv->vval.v_dict;
13211
13212 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13213 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13214#ifdef FEAT_VIRTUALEDIT
13215 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13216#endif
13217 update_curswant();
13218 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13219
13220 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13221#ifdef FEAT_DIFF
13222 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13223#endif
13224 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13225 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13226}
13227
13228/*
13229 * "winwidth(nr)" function
13230 */
13231 static void
13232f_winwidth(typval_T *argvars, typval_T *rettv)
13233{
13234 win_T *wp;
13235
13236 wp = find_win_by_nr(&argvars[0], NULL);
13237 if (wp == NULL)
13238 rettv->vval.v_number = -1;
13239 else
13240#ifdef FEAT_WINDOWS
13241 rettv->vval.v_number = wp->w_width;
13242#else
13243 rettv->vval.v_number = Columns;
13244#endif
13245}
13246
13247/*
13248 * "wordcount()" function
13249 */
13250 static void
13251f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13252{
13253 if (rettv_dict_alloc(rettv) == FAIL)
13254 return;
13255 cursor_pos_info(rettv->vval.v_dict);
13256}
13257
13258/*
13259 * "writefile()" function
13260 */
13261 static void
13262f_writefile(typval_T *argvars, typval_T *rettv)
13263{
13264 int binary = FALSE;
13265 int append = FALSE;
13266 char_u *fname;
13267 FILE *fd;
13268 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013269 listitem_T *li;
13270 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013271
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013272 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013273 if (check_restricted() || check_secure())
13274 return;
13275
13276 if (argvars[0].v_type != VAR_LIST)
13277 {
13278 EMSG2(_(e_listarg), "writefile()");
13279 return;
13280 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013281 list = argvars[0].vval.v_list;
13282 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013283 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013284 for (li = list->lv_first; li != NULL; li = li->li_next)
13285 if (get_tv_string_chk(&li->li_tv) == NULL)
13286 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013287
13288 if (argvars[2].v_type != VAR_UNKNOWN)
13289 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013290 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13291
13292 if (arg2 == NULL)
13293 return;
13294 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013295 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013296 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013297 append = TRUE;
13298 }
13299
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013300 fname = get_tv_string_chk(&argvars[1]);
13301 if (fname == NULL)
13302 return;
13303
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013304 /* Always open the file in binary mode, library functions have a mind of
13305 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013306 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13307 append ? APPENDBIN : WRITEBIN)) == NULL)
13308 {
13309 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13310 ret = -1;
13311 }
13312 else
13313 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013314 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013315 ret = -1;
13316 fclose(fd);
13317 }
13318
13319 rettv->vval.v_number = ret;
13320}
13321
13322/*
13323 * "xor(expr, expr)" function
13324 */
13325 static void
13326f_xor(typval_T *argvars, typval_T *rettv)
13327{
13328 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13329 ^ get_tv_number_chk(&argvars[1], NULL);
13330}
13331
13332
13333#endif /* FEAT_EVAL */