blob: 3d657f73e638b82449ab037efc113f2a01c7cc07 [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 }
7852 else if (VIsual_active)
7853 {
7854 if (VIsual_select)
7855 buf[0] = VIsual_mode + 's' - 'v';
7856 else
7857 buf[0] = VIsual_mode;
7858 }
7859 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7860 || State == CONFIRM)
7861 {
7862 buf[0] = 'r';
7863 if (State == ASKMORE)
7864 buf[1] = 'm';
7865 else if (State == CONFIRM)
7866 buf[1] = '?';
7867 }
7868 else if (State == EXTERNCMD)
7869 buf[0] = '!';
7870 else if (State & INSERT)
7871 {
7872#ifdef FEAT_VREPLACE
7873 if (State & VREPLACE_FLAG)
7874 {
7875 buf[0] = 'R';
7876 buf[1] = 'v';
7877 }
7878 else
7879#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01007880 {
7881 if (State & REPLACE_FLAG)
7882 buf[0] = 'R';
7883 else
7884 buf[0] = 'i';
7885#ifdef FEAT_INS_EXPAND
7886 if (ins_compl_active())
7887 buf[1] = 'c';
7888 else if (ctrl_x_mode == 1)
7889 buf[1] = 'x';
7890#endif
7891 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007893 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007894 {
7895 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007896 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007898 else if (exmode_active == EXMODE_NORMAL)
7899 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900 }
7901 else
7902 {
7903 buf[0] = 'n';
7904 if (finish_op)
7905 buf[1] = 'o';
7906 }
7907
7908 /* Clear out the minor mode when the argument is not a non-zero number or
7909 * non-empty string. */
7910 if (!non_zero_arg(&argvars[0]))
7911 buf[1] = NUL;
7912
7913 rettv->vval.v_string = vim_strsave(buf);
7914 rettv->v_type = VAR_STRING;
7915}
7916
7917#if defined(FEAT_MZSCHEME) || defined(PROTO)
7918/*
7919 * "mzeval()" function
7920 */
7921 static void
7922f_mzeval(typval_T *argvars, typval_T *rettv)
7923{
7924 char_u *str;
7925 char_u buf[NUMBUFLEN];
7926
7927 str = get_tv_string_buf(&argvars[0], buf);
7928 do_mzeval(str, rettv);
7929}
7930
7931 void
7932mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7933{
7934 typval_T argvars[3];
7935
7936 argvars[0].v_type = VAR_STRING;
7937 argvars[0].vval.v_string = name;
7938 copy_tv(args, &argvars[1]);
7939 argvars[2].v_type = VAR_UNKNOWN;
7940 f_call(argvars, rettv);
7941 clear_tv(&argvars[1]);
7942}
7943#endif
7944
7945/*
7946 * "nextnonblank()" function
7947 */
7948 static void
7949f_nextnonblank(typval_T *argvars, typval_T *rettv)
7950{
7951 linenr_T lnum;
7952
7953 for (lnum = get_tv_lnum(argvars); ; ++lnum)
7954 {
7955 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7956 {
7957 lnum = 0;
7958 break;
7959 }
7960 if (*skipwhite(ml_get(lnum)) != NUL)
7961 break;
7962 }
7963 rettv->vval.v_number = lnum;
7964}
7965
7966/*
7967 * "nr2char()" function
7968 */
7969 static void
7970f_nr2char(typval_T *argvars, typval_T *rettv)
7971{
7972 char_u buf[NUMBUFLEN];
7973
7974#ifdef FEAT_MBYTE
7975 if (has_mbyte)
7976 {
7977 int utf8 = 0;
7978
7979 if (argvars[1].v_type != VAR_UNKNOWN)
7980 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
7981 if (utf8)
7982 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7983 else
7984 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7985 }
7986 else
7987#endif
7988 {
7989 buf[0] = (char_u)get_tv_number(&argvars[0]);
7990 buf[1] = NUL;
7991 }
7992 rettv->v_type = VAR_STRING;
7993 rettv->vval.v_string = vim_strsave(buf);
7994}
7995
7996/*
7997 * "or(expr, expr)" function
7998 */
7999 static void
8000f_or(typval_T *argvars, typval_T *rettv)
8001{
8002 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8003 | get_tv_number_chk(&argvars[1], NULL);
8004}
8005
8006/*
8007 * "pathshorten()" function
8008 */
8009 static void
8010f_pathshorten(typval_T *argvars, typval_T *rettv)
8011{
8012 char_u *p;
8013
8014 rettv->v_type = VAR_STRING;
8015 p = get_tv_string_chk(&argvars[0]);
8016 if (p == NULL)
8017 rettv->vval.v_string = NULL;
8018 else
8019 {
8020 p = vim_strsave(p);
8021 rettv->vval.v_string = p;
8022 if (p != NULL)
8023 shorten_dir(p);
8024 }
8025}
8026
8027#ifdef FEAT_PERL
8028/*
8029 * "perleval()" function
8030 */
8031 static void
8032f_perleval(typval_T *argvars, typval_T *rettv)
8033{
8034 char_u *str;
8035 char_u buf[NUMBUFLEN];
8036
8037 str = get_tv_string_buf(&argvars[0], buf);
8038 do_perleval(str, rettv);
8039}
8040#endif
8041
8042#ifdef FEAT_FLOAT
8043/*
8044 * "pow()" function
8045 */
8046 static void
8047f_pow(typval_T *argvars, typval_T *rettv)
8048{
8049 float_T fx = 0.0, fy = 0.0;
8050
8051 rettv->v_type = VAR_FLOAT;
8052 if (get_float_arg(argvars, &fx) == OK
8053 && get_float_arg(&argvars[1], &fy) == OK)
8054 rettv->vval.v_float = pow(fx, fy);
8055 else
8056 rettv->vval.v_float = 0.0;
8057}
8058#endif
8059
8060/*
8061 * "prevnonblank()" function
8062 */
8063 static void
8064f_prevnonblank(typval_T *argvars, typval_T *rettv)
8065{
8066 linenr_T lnum;
8067
8068 lnum = get_tv_lnum(argvars);
8069 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8070 lnum = 0;
8071 else
8072 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8073 --lnum;
8074 rettv->vval.v_number = lnum;
8075}
8076
8077/* This dummy va_list is here because:
8078 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8079 * - locally in the function results in a "used before set" warning
8080 * - using va_start() to initialize it gives "function with fixed args" error */
8081static va_list ap;
8082
8083/*
8084 * "printf()" function
8085 */
8086 static void
8087f_printf(typval_T *argvars, typval_T *rettv)
8088{
8089 char_u buf[NUMBUFLEN];
8090 int len;
8091 char_u *s;
8092 int saved_did_emsg = did_emsg;
8093 char *fmt;
8094
8095 rettv->v_type = VAR_STRING;
8096 rettv->vval.v_string = NULL;
8097
8098 /* Get the required length, allocate the buffer and do it for real. */
8099 did_emsg = FALSE;
8100 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008101 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102 if (!did_emsg)
8103 {
8104 s = alloc(len + 1);
8105 if (s != NULL)
8106 {
8107 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008108 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8109 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008110 }
8111 }
8112 did_emsg |= saved_did_emsg;
8113}
8114
8115/*
8116 * "pumvisible()" function
8117 */
8118 static void
8119f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8120{
8121#ifdef FEAT_INS_EXPAND
8122 if (pum_visible())
8123 rettv->vval.v_number = 1;
8124#endif
8125}
8126
8127#ifdef FEAT_PYTHON3
8128/*
8129 * "py3eval()" function
8130 */
8131 static void
8132f_py3eval(typval_T *argvars, typval_T *rettv)
8133{
8134 char_u *str;
8135 char_u buf[NUMBUFLEN];
8136
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008137 if (p_pyx == 0)
8138 p_pyx = 3;
8139
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140 str = get_tv_string_buf(&argvars[0], buf);
8141 do_py3eval(str, rettv);
8142}
8143#endif
8144
8145#ifdef FEAT_PYTHON
8146/*
8147 * "pyeval()" function
8148 */
8149 static void
8150f_pyeval(typval_T *argvars, typval_T *rettv)
8151{
8152 char_u *str;
8153 char_u buf[NUMBUFLEN];
8154
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008155 if (p_pyx == 0)
8156 p_pyx = 2;
8157
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158 str = get_tv_string_buf(&argvars[0], buf);
8159 do_pyeval(str, rettv);
8160}
8161#endif
8162
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8164/*
8165 * "pyxeval()" function
8166 */
8167 static void
8168f_pyxeval(typval_T *argvars, typval_T *rettv)
8169{
8170# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8171 init_pyxversion();
8172 if (p_pyx == 2)
8173 f_pyeval(argvars, rettv);
8174 else
8175 f_py3eval(argvars, rettv);
8176# elif defined(FEAT_PYTHON)
8177 f_pyeval(argvars, rettv);
8178# elif defined(FEAT_PYTHON3)
8179 f_py3eval(argvars, rettv);
8180# endif
8181}
8182#endif
8183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184/*
8185 * "range()" function
8186 */
8187 static void
8188f_range(typval_T *argvars, typval_T *rettv)
8189{
8190 varnumber_T start;
8191 varnumber_T end;
8192 varnumber_T stride = 1;
8193 varnumber_T i;
8194 int error = FALSE;
8195
8196 start = get_tv_number_chk(&argvars[0], &error);
8197 if (argvars[1].v_type == VAR_UNKNOWN)
8198 {
8199 end = start - 1;
8200 start = 0;
8201 }
8202 else
8203 {
8204 end = get_tv_number_chk(&argvars[1], &error);
8205 if (argvars[2].v_type != VAR_UNKNOWN)
8206 stride = get_tv_number_chk(&argvars[2], &error);
8207 }
8208
8209 if (error)
8210 return; /* type error; errmsg already given */
8211 if (stride == 0)
8212 EMSG(_("E726: Stride is zero"));
8213 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8214 EMSG(_("E727: Start past end"));
8215 else
8216 {
8217 if (rettv_list_alloc(rettv) == OK)
8218 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8219 if (list_append_number(rettv->vval.v_list,
8220 (varnumber_T)i) == FAIL)
8221 break;
8222 }
8223}
8224
8225/*
8226 * "readfile()" function
8227 */
8228 static void
8229f_readfile(typval_T *argvars, typval_T *rettv)
8230{
8231 int binary = FALSE;
8232 int failed = FALSE;
8233 char_u *fname;
8234 FILE *fd;
8235 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8236 int io_size = sizeof(buf);
8237 int readlen; /* size of last fread() */
8238 char_u *prev = NULL; /* previously read bytes, if any */
8239 long prevlen = 0; /* length of data in prev */
8240 long prevsize = 0; /* size of prev buffer */
8241 long maxline = MAXLNUM;
8242 long cnt = 0;
8243 char_u *p; /* position in buf */
8244 char_u *start; /* start of current line */
8245
8246 if (argvars[1].v_type != VAR_UNKNOWN)
8247 {
8248 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8249 binary = TRUE;
8250 if (argvars[2].v_type != VAR_UNKNOWN)
8251 maxline = (long)get_tv_number(&argvars[2]);
8252 }
8253
8254 if (rettv_list_alloc(rettv) == FAIL)
8255 return;
8256
8257 /* Always open the file in binary mode, library functions have a mind of
8258 * their own about CR-LF conversion. */
8259 fname = get_tv_string(&argvars[0]);
8260 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8261 {
8262 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8263 return;
8264 }
8265
8266 while (cnt < maxline || maxline < 0)
8267 {
8268 readlen = (int)fread(buf, 1, io_size, fd);
8269
8270 /* This for loop processes what was read, but is also entered at end
8271 * of file so that either:
8272 * - an incomplete line gets written
8273 * - a "binary" file gets an empty line at the end if it ends in a
8274 * newline. */
8275 for (p = buf, start = buf;
8276 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8277 ++p)
8278 {
8279 if (*p == '\n' || readlen <= 0)
8280 {
8281 listitem_T *li;
8282 char_u *s = NULL;
8283 long_u len = p - start;
8284
8285 /* Finished a line. Remove CRs before NL. */
8286 if (readlen > 0 && !binary)
8287 {
8288 while (len > 0 && start[len - 1] == '\r')
8289 --len;
8290 /* removal may cross back to the "prev" string */
8291 if (len == 0)
8292 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8293 --prevlen;
8294 }
8295 if (prevlen == 0)
8296 s = vim_strnsave(start, (int)len);
8297 else
8298 {
8299 /* Change "prev" buffer to be the right size. This way
8300 * the bytes are only copied once, and very long lines are
8301 * allocated only once. */
8302 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8303 {
8304 mch_memmove(s + prevlen, start, len);
8305 s[prevlen + len] = NUL;
8306 prev = NULL; /* the list will own the string */
8307 prevlen = prevsize = 0;
8308 }
8309 }
8310 if (s == NULL)
8311 {
8312 do_outofmem_msg((long_u) prevlen + len + 1);
8313 failed = TRUE;
8314 break;
8315 }
8316
8317 if ((li = listitem_alloc()) == NULL)
8318 {
8319 vim_free(s);
8320 failed = TRUE;
8321 break;
8322 }
8323 li->li_tv.v_type = VAR_STRING;
8324 li->li_tv.v_lock = 0;
8325 li->li_tv.vval.v_string = s;
8326 list_append(rettv->vval.v_list, li);
8327
8328 start = p + 1; /* step over newline */
8329 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8330 break;
8331 }
8332 else if (*p == NUL)
8333 *p = '\n';
8334#ifdef FEAT_MBYTE
8335 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8336 * when finding the BF and check the previous two bytes. */
8337 else if (*p == 0xbf && enc_utf8 && !binary)
8338 {
8339 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8340 * + 1, these may be in the "prev" string. */
8341 char_u back1 = p >= buf + 1 ? p[-1]
8342 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8343 char_u back2 = p >= buf + 2 ? p[-2]
8344 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8345 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8346
8347 if (back2 == 0xef && back1 == 0xbb)
8348 {
8349 char_u *dest = p - 2;
8350
8351 /* Usually a BOM is at the beginning of a file, and so at
8352 * the beginning of a line; then we can just step over it.
8353 */
8354 if (start == dest)
8355 start = p + 1;
8356 else
8357 {
8358 /* have to shuffle buf to close gap */
8359 int adjust_prevlen = 0;
8360
8361 if (dest < buf)
8362 {
8363 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8364 dest = buf;
8365 }
8366 if (readlen > p - buf + 1)
8367 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8368 readlen -= 3 - adjust_prevlen;
8369 prevlen -= adjust_prevlen;
8370 p = dest - 1;
8371 }
8372 }
8373 }
8374#endif
8375 } /* for */
8376
8377 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8378 break;
8379 if (start < p)
8380 {
8381 /* There's part of a line in buf, store it in "prev". */
8382 if (p - start + prevlen >= prevsize)
8383 {
8384 /* need bigger "prev" buffer */
8385 char_u *newprev;
8386
8387 /* A common use case is ordinary text files and "prev" gets a
8388 * fragment of a line, so the first allocation is made
8389 * small, to avoid repeatedly 'allocing' large and
8390 * 'reallocing' small. */
8391 if (prevsize == 0)
8392 prevsize = (long)(p - start);
8393 else
8394 {
8395 long grow50pc = (prevsize * 3) / 2;
8396 long growmin = (long)((p - start) * 2 + prevlen);
8397 prevsize = grow50pc > growmin ? grow50pc : growmin;
8398 }
8399 newprev = prev == NULL ? alloc(prevsize)
8400 : vim_realloc(prev, prevsize);
8401 if (newprev == NULL)
8402 {
8403 do_outofmem_msg((long_u)prevsize);
8404 failed = TRUE;
8405 break;
8406 }
8407 prev = newprev;
8408 }
8409 /* Add the line part to end of "prev". */
8410 mch_memmove(prev + prevlen, start, p - start);
8411 prevlen += (long)(p - start);
8412 }
8413 } /* while */
8414
8415 /*
8416 * For a negative line count use only the lines at the end of the file,
8417 * free the rest.
8418 */
8419 if (!failed && maxline < 0)
8420 while (cnt > -maxline)
8421 {
8422 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8423 --cnt;
8424 }
8425
8426 if (failed)
8427 {
8428 list_free(rettv->vval.v_list);
8429 /* readfile doc says an empty list is returned on error */
8430 rettv->vval.v_list = list_alloc();
8431 }
8432
8433 vim_free(prev);
8434 fclose(fd);
8435}
8436
8437#if defined(FEAT_RELTIME)
8438static int list2proftime(typval_T *arg, proftime_T *tm);
8439
8440/*
8441 * Convert a List to proftime_T.
8442 * Return FAIL when there is something wrong.
8443 */
8444 static int
8445list2proftime(typval_T *arg, proftime_T *tm)
8446{
8447 long n1, n2;
8448 int error = FALSE;
8449
8450 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8451 || arg->vval.v_list->lv_len != 2)
8452 return FAIL;
8453 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8454 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8455# ifdef WIN3264
8456 tm->HighPart = n1;
8457 tm->LowPart = n2;
8458# else
8459 tm->tv_sec = n1;
8460 tm->tv_usec = n2;
8461# endif
8462 return error ? FAIL : OK;
8463}
8464#endif /* FEAT_RELTIME */
8465
8466/*
8467 * "reltime()" function
8468 */
8469 static void
8470f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8471{
8472#ifdef FEAT_RELTIME
8473 proftime_T res;
8474 proftime_T start;
8475
8476 if (argvars[0].v_type == VAR_UNKNOWN)
8477 {
8478 /* No arguments: get current time. */
8479 profile_start(&res);
8480 }
8481 else if (argvars[1].v_type == VAR_UNKNOWN)
8482 {
8483 if (list2proftime(&argvars[0], &res) == FAIL)
8484 return;
8485 profile_end(&res);
8486 }
8487 else
8488 {
8489 /* Two arguments: compute the difference. */
8490 if (list2proftime(&argvars[0], &start) == FAIL
8491 || list2proftime(&argvars[1], &res) == FAIL)
8492 return;
8493 profile_sub(&res, &start);
8494 }
8495
8496 if (rettv_list_alloc(rettv) == OK)
8497 {
8498 long n1, n2;
8499
8500# ifdef WIN3264
8501 n1 = res.HighPart;
8502 n2 = res.LowPart;
8503# else
8504 n1 = res.tv_sec;
8505 n2 = res.tv_usec;
8506# endif
8507 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8508 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8509 }
8510#endif
8511}
8512
8513#ifdef FEAT_FLOAT
8514/*
8515 * "reltimefloat()" function
8516 */
8517 static void
8518f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8519{
8520# ifdef FEAT_RELTIME
8521 proftime_T tm;
8522# endif
8523
8524 rettv->v_type = VAR_FLOAT;
8525 rettv->vval.v_float = 0;
8526# ifdef FEAT_RELTIME
8527 if (list2proftime(&argvars[0], &tm) == OK)
8528 rettv->vval.v_float = profile_float(&tm);
8529# endif
8530}
8531#endif
8532
8533/*
8534 * "reltimestr()" function
8535 */
8536 static void
8537f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8538{
8539#ifdef FEAT_RELTIME
8540 proftime_T tm;
8541#endif
8542
8543 rettv->v_type = VAR_STRING;
8544 rettv->vval.v_string = NULL;
8545#ifdef FEAT_RELTIME
8546 if (list2proftime(&argvars[0], &tm) == OK)
8547 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8548#endif
8549}
8550
8551#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8552static void make_connection(void);
8553static int check_connection(void);
8554
8555 static void
8556make_connection(void)
8557{
8558 if (X_DISPLAY == NULL
8559# ifdef FEAT_GUI
8560 && !gui.in_use
8561# endif
8562 )
8563 {
8564 x_force_connect = TRUE;
8565 setup_term_clip();
8566 x_force_connect = FALSE;
8567 }
8568}
8569
8570 static int
8571check_connection(void)
8572{
8573 make_connection();
8574 if (X_DISPLAY == NULL)
8575 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008576 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008577 return FAIL;
8578 }
8579 return OK;
8580}
8581#endif
8582
8583#ifdef FEAT_CLIENTSERVER
8584 static void
8585remote_common(typval_T *argvars, typval_T *rettv, int expr)
8586{
8587 char_u *server_name;
8588 char_u *keys;
8589 char_u *r = NULL;
8590 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008591 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008592# ifdef WIN32
8593 HWND w;
8594# else
8595 Window w;
8596# endif
8597
8598 if (check_restricted() || check_secure())
8599 return;
8600
8601# ifdef FEAT_X11
8602 if (check_connection() == FAIL)
8603 return;
8604# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008605 if (argvars[2].v_type != VAR_UNKNOWN
8606 && argvars[3].v_type != VAR_UNKNOWN)
8607 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608
8609 server_name = get_tv_string_chk(&argvars[0]);
8610 if (server_name == NULL)
8611 return; /* type error; errmsg already given */
8612 keys = get_tv_string_buf(&argvars[1], buf);
8613# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008614 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008615# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008616 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8617 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008618# endif
8619 {
8620 if (r != NULL)
8621 EMSG(r); /* sending worked but evaluation failed */
8622 else
8623 EMSG2(_("E241: Unable to send to %s"), server_name);
8624 return;
8625 }
8626
8627 rettv->vval.v_string = r;
8628
8629 if (argvars[2].v_type != VAR_UNKNOWN)
8630 {
8631 dictitem_T v;
8632 char_u str[30];
8633 char_u *idvar;
8634
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008635 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008636 if (idvar != NULL && *idvar != NUL)
8637 {
8638 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8639 v.di_tv.v_type = VAR_STRING;
8640 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008641 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008642 vim_free(v.di_tv.vval.v_string);
8643 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644 }
8645}
8646#endif
8647
8648/*
8649 * "remote_expr()" function
8650 */
8651 static void
8652f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8653{
8654 rettv->v_type = VAR_STRING;
8655 rettv->vval.v_string = NULL;
8656#ifdef FEAT_CLIENTSERVER
8657 remote_common(argvars, rettv, TRUE);
8658#endif
8659}
8660
8661/*
8662 * "remote_foreground()" function
8663 */
8664 static void
8665f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8666{
8667#ifdef FEAT_CLIENTSERVER
8668# ifdef WIN32
8669 /* On Win32 it's done in this application. */
8670 {
8671 char_u *server_name = get_tv_string_chk(&argvars[0]);
8672
8673 if (server_name != NULL)
8674 serverForeground(server_name);
8675 }
8676# else
8677 /* Send a foreground() expression to the server. */
8678 argvars[1].v_type = VAR_STRING;
8679 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8680 argvars[2].v_type = VAR_UNKNOWN;
8681 remote_common(argvars, rettv, TRUE);
8682 vim_free(argvars[1].vval.v_string);
8683# endif
8684#endif
8685}
8686
8687 static void
8688f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8689{
8690#ifdef FEAT_CLIENTSERVER
8691 dictitem_T v;
8692 char_u *s = NULL;
8693# ifdef WIN32
8694 long_u n = 0;
8695# endif
8696 char_u *serverid;
8697
8698 if (check_restricted() || check_secure())
8699 {
8700 rettv->vval.v_number = -1;
8701 return;
8702 }
8703 serverid = get_tv_string_chk(&argvars[0]);
8704 if (serverid == NULL)
8705 {
8706 rettv->vval.v_number = -1;
8707 return; /* type error; errmsg already given */
8708 }
8709# ifdef WIN32
8710 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8711 if (n == 0)
8712 rettv->vval.v_number = -1;
8713 else
8714 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008715 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008716 rettv->vval.v_number = (s != NULL);
8717 }
8718# else
8719 if (check_connection() == FAIL)
8720 return;
8721
8722 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8723 serverStrToWin(serverid), &s);
8724# endif
8725
8726 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8727 {
8728 char_u *retvar;
8729
8730 v.di_tv.v_type = VAR_STRING;
8731 v.di_tv.vval.v_string = vim_strsave(s);
8732 retvar = get_tv_string_chk(&argvars[1]);
8733 if (retvar != NULL)
8734 set_var(retvar, &v.di_tv, FALSE);
8735 vim_free(v.di_tv.vval.v_string);
8736 }
8737#else
8738 rettv->vval.v_number = -1;
8739#endif
8740}
8741
8742 static void
8743f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8744{
8745 char_u *r = NULL;
8746
8747#ifdef FEAT_CLIENTSERVER
8748 char_u *serverid = get_tv_string_chk(&argvars[0]);
8749
8750 if (serverid != NULL && !check_restricted() && !check_secure())
8751 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008752 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008753# ifdef WIN32
8754 /* The server's HWND is encoded in the 'id' parameter */
8755 long_u n = 0;
8756# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008757
8758 if (argvars[1].v_type != VAR_UNKNOWN)
8759 timeout = get_tv_number(&argvars[1]);
8760
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008761# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008762 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8763 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008764 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008765 if (r == NULL)
8766# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008767 if (check_connection() == FAIL
8768 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8769 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008770# endif
8771 EMSG(_("E277: Unable to read a server reply"));
8772 }
8773#endif
8774 rettv->v_type = VAR_STRING;
8775 rettv->vval.v_string = r;
8776}
8777
8778/*
8779 * "remote_send()" function
8780 */
8781 static void
8782f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8783{
8784 rettv->v_type = VAR_STRING;
8785 rettv->vval.v_string = NULL;
8786#ifdef FEAT_CLIENTSERVER
8787 remote_common(argvars, rettv, FALSE);
8788#endif
8789}
8790
8791/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008792 * "remote_startserver()" function
8793 */
8794 static void
8795f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8796{
8797#ifdef FEAT_CLIENTSERVER
8798 char_u *server = get_tv_string_chk(&argvars[0]);
8799
8800 if (server == NULL)
8801 return; /* type error; errmsg already given */
8802 if (serverName != NULL)
8803 EMSG(_("E941: already started a server"));
8804 else
8805 {
8806# ifdef FEAT_X11
8807 if (check_connection() == OK)
8808 serverRegisterName(X_DISPLAY, server);
8809# else
8810 serverSetName(server);
8811# endif
8812 }
8813#else
8814 EMSG(_("E942: +clientserver feature not available"));
8815#endif
8816}
8817
8818/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008819 * "remove()" function
8820 */
8821 static void
8822f_remove(typval_T *argvars, typval_T *rettv)
8823{
8824 list_T *l;
8825 listitem_T *item, *item2;
8826 listitem_T *li;
8827 long idx;
8828 long end;
8829 char_u *key;
8830 dict_T *d;
8831 dictitem_T *di;
8832 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8833
8834 if (argvars[0].v_type == VAR_DICT)
8835 {
8836 if (argvars[2].v_type != VAR_UNKNOWN)
8837 EMSG2(_(e_toomanyarg), "remove()");
8838 else if ((d = argvars[0].vval.v_dict) != NULL
8839 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8840 {
8841 key = get_tv_string_chk(&argvars[1]);
8842 if (key != NULL)
8843 {
8844 di = dict_find(d, key, -1);
8845 if (di == NULL)
8846 EMSG2(_(e_dictkey), key);
8847 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8848 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8849 {
8850 *rettv = di->di_tv;
8851 init_tv(&di->di_tv);
8852 dictitem_remove(d, di);
8853 }
8854 }
8855 }
8856 }
8857 else if (argvars[0].v_type != VAR_LIST)
8858 EMSG2(_(e_listdictarg), "remove()");
8859 else if ((l = argvars[0].vval.v_list) != NULL
8860 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8861 {
8862 int error = FALSE;
8863
8864 idx = (long)get_tv_number_chk(&argvars[1], &error);
8865 if (error)
8866 ; /* type error: do nothing, errmsg already given */
8867 else if ((item = list_find(l, idx)) == NULL)
8868 EMSGN(_(e_listidx), idx);
8869 else
8870 {
8871 if (argvars[2].v_type == VAR_UNKNOWN)
8872 {
8873 /* Remove one item, return its value. */
8874 vimlist_remove(l, item, item);
8875 *rettv = item->li_tv;
8876 vim_free(item);
8877 }
8878 else
8879 {
8880 /* Remove range of items, return list with values. */
8881 end = (long)get_tv_number_chk(&argvars[2], &error);
8882 if (error)
8883 ; /* type error: do nothing */
8884 else if ((item2 = list_find(l, end)) == NULL)
8885 EMSGN(_(e_listidx), end);
8886 else
8887 {
8888 int cnt = 0;
8889
8890 for (li = item; li != NULL; li = li->li_next)
8891 {
8892 ++cnt;
8893 if (li == item2)
8894 break;
8895 }
8896 if (li == NULL) /* didn't find "item2" after "item" */
8897 EMSG(_(e_invrange));
8898 else
8899 {
8900 vimlist_remove(l, item, item2);
8901 if (rettv_list_alloc(rettv) == OK)
8902 {
8903 l = rettv->vval.v_list;
8904 l->lv_first = item;
8905 l->lv_last = item2;
8906 item->li_prev = NULL;
8907 item2->li_next = NULL;
8908 l->lv_len = cnt;
8909 }
8910 }
8911 }
8912 }
8913 }
8914 }
8915}
8916
8917/*
8918 * "rename({from}, {to})" function
8919 */
8920 static void
8921f_rename(typval_T *argvars, typval_T *rettv)
8922{
8923 char_u buf[NUMBUFLEN];
8924
8925 if (check_restricted() || check_secure())
8926 rettv->vval.v_number = -1;
8927 else
8928 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8929 get_tv_string_buf(&argvars[1], buf));
8930}
8931
8932/*
8933 * "repeat()" function
8934 */
8935 static void
8936f_repeat(typval_T *argvars, typval_T *rettv)
8937{
8938 char_u *p;
8939 int n;
8940 int slen;
8941 int len;
8942 char_u *r;
8943 int i;
8944
8945 n = (int)get_tv_number(&argvars[1]);
8946 if (argvars[0].v_type == VAR_LIST)
8947 {
8948 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8949 while (n-- > 0)
8950 if (list_extend(rettv->vval.v_list,
8951 argvars[0].vval.v_list, NULL) == FAIL)
8952 break;
8953 }
8954 else
8955 {
8956 p = get_tv_string(&argvars[0]);
8957 rettv->v_type = VAR_STRING;
8958 rettv->vval.v_string = NULL;
8959
8960 slen = (int)STRLEN(p);
8961 len = slen * n;
8962 if (len <= 0)
8963 return;
8964
8965 r = alloc(len + 1);
8966 if (r != NULL)
8967 {
8968 for (i = 0; i < n; i++)
8969 mch_memmove(r + i * slen, p, (size_t)slen);
8970 r[len] = NUL;
8971 }
8972
8973 rettv->vval.v_string = r;
8974 }
8975}
8976
8977/*
8978 * "resolve()" function
8979 */
8980 static void
8981f_resolve(typval_T *argvars, typval_T *rettv)
8982{
8983 char_u *p;
8984#ifdef HAVE_READLINK
8985 char_u *buf = NULL;
8986#endif
8987
8988 p = get_tv_string(&argvars[0]);
8989#ifdef FEAT_SHORTCUT
8990 {
8991 char_u *v = NULL;
8992
8993 v = mch_resolve_shortcut(p);
8994 if (v != NULL)
8995 rettv->vval.v_string = v;
8996 else
8997 rettv->vval.v_string = vim_strsave(p);
8998 }
8999#else
9000# ifdef HAVE_READLINK
9001 {
9002 char_u *cpy;
9003 int len;
9004 char_u *remain = NULL;
9005 char_u *q;
9006 int is_relative_to_current = FALSE;
9007 int has_trailing_pathsep = FALSE;
9008 int limit = 100;
9009
9010 p = vim_strsave(p);
9011
9012 if (p[0] == '.' && (vim_ispathsep(p[1])
9013 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9014 is_relative_to_current = TRUE;
9015
9016 len = STRLEN(p);
9017 if (len > 0 && after_pathsep(p, p + len))
9018 {
9019 has_trailing_pathsep = TRUE;
9020 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9021 }
9022
9023 q = getnextcomp(p);
9024 if (*q != NUL)
9025 {
9026 /* Separate the first path component in "p", and keep the
9027 * remainder (beginning with the path separator). */
9028 remain = vim_strsave(q - 1);
9029 q[-1] = NUL;
9030 }
9031
9032 buf = alloc(MAXPATHL + 1);
9033 if (buf == NULL)
9034 goto fail;
9035
9036 for (;;)
9037 {
9038 for (;;)
9039 {
9040 len = readlink((char *)p, (char *)buf, MAXPATHL);
9041 if (len <= 0)
9042 break;
9043 buf[len] = NUL;
9044
9045 if (limit-- == 0)
9046 {
9047 vim_free(p);
9048 vim_free(remain);
9049 EMSG(_("E655: Too many symbolic links (cycle?)"));
9050 rettv->vval.v_string = NULL;
9051 goto fail;
9052 }
9053
9054 /* Ensure that the result will have a trailing path separator
9055 * if the argument has one. */
9056 if (remain == NULL && has_trailing_pathsep)
9057 add_pathsep(buf);
9058
9059 /* Separate the first path component in the link value and
9060 * concatenate the remainders. */
9061 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9062 if (*q != NUL)
9063 {
9064 if (remain == NULL)
9065 remain = vim_strsave(q - 1);
9066 else
9067 {
9068 cpy = concat_str(q - 1, remain);
9069 if (cpy != NULL)
9070 {
9071 vim_free(remain);
9072 remain = cpy;
9073 }
9074 }
9075 q[-1] = NUL;
9076 }
9077
9078 q = gettail(p);
9079 if (q > p && *q == NUL)
9080 {
9081 /* Ignore trailing path separator. */
9082 q[-1] = NUL;
9083 q = gettail(p);
9084 }
9085 if (q > p && !mch_isFullName(buf))
9086 {
9087 /* symlink is relative to directory of argument */
9088 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9089 if (cpy != NULL)
9090 {
9091 STRCPY(cpy, p);
9092 STRCPY(gettail(cpy), buf);
9093 vim_free(p);
9094 p = cpy;
9095 }
9096 }
9097 else
9098 {
9099 vim_free(p);
9100 p = vim_strsave(buf);
9101 }
9102 }
9103
9104 if (remain == NULL)
9105 break;
9106
9107 /* Append the first path component of "remain" to "p". */
9108 q = getnextcomp(remain + 1);
9109 len = q - remain - (*q != NUL);
9110 cpy = vim_strnsave(p, STRLEN(p) + len);
9111 if (cpy != NULL)
9112 {
9113 STRNCAT(cpy, remain, len);
9114 vim_free(p);
9115 p = cpy;
9116 }
9117 /* Shorten "remain". */
9118 if (*q != NUL)
9119 STRMOVE(remain, q - 1);
9120 else
9121 {
9122 vim_free(remain);
9123 remain = NULL;
9124 }
9125 }
9126
9127 /* If the result is a relative path name, make it explicitly relative to
9128 * the current directory if and only if the argument had this form. */
9129 if (!vim_ispathsep(*p))
9130 {
9131 if (is_relative_to_current
9132 && *p != NUL
9133 && !(p[0] == '.'
9134 && (p[1] == NUL
9135 || vim_ispathsep(p[1])
9136 || (p[1] == '.'
9137 && (p[2] == NUL
9138 || vim_ispathsep(p[2]))))))
9139 {
9140 /* Prepend "./". */
9141 cpy = concat_str((char_u *)"./", p);
9142 if (cpy != NULL)
9143 {
9144 vim_free(p);
9145 p = cpy;
9146 }
9147 }
9148 else if (!is_relative_to_current)
9149 {
9150 /* Strip leading "./". */
9151 q = p;
9152 while (q[0] == '.' && vim_ispathsep(q[1]))
9153 q += 2;
9154 if (q > p)
9155 STRMOVE(p, p + 2);
9156 }
9157 }
9158
9159 /* Ensure that the result will have no trailing path separator
9160 * if the argument had none. But keep "/" or "//". */
9161 if (!has_trailing_pathsep)
9162 {
9163 q = p + STRLEN(p);
9164 if (after_pathsep(p, q))
9165 *gettail_sep(p) = NUL;
9166 }
9167
9168 rettv->vval.v_string = p;
9169 }
9170# else
9171 rettv->vval.v_string = vim_strsave(p);
9172# endif
9173#endif
9174
9175 simplify_filename(rettv->vval.v_string);
9176
9177#ifdef HAVE_READLINK
9178fail:
9179 vim_free(buf);
9180#endif
9181 rettv->v_type = VAR_STRING;
9182}
9183
9184/*
9185 * "reverse({list})" function
9186 */
9187 static void
9188f_reverse(typval_T *argvars, typval_T *rettv)
9189{
9190 list_T *l;
9191 listitem_T *li, *ni;
9192
9193 if (argvars[0].v_type != VAR_LIST)
9194 EMSG2(_(e_listarg), "reverse()");
9195 else if ((l = argvars[0].vval.v_list) != NULL
9196 && !tv_check_lock(l->lv_lock,
9197 (char_u *)N_("reverse() argument"), TRUE))
9198 {
9199 li = l->lv_last;
9200 l->lv_first = l->lv_last = NULL;
9201 l->lv_len = 0;
9202 while (li != NULL)
9203 {
9204 ni = li->li_prev;
9205 list_append(l, li);
9206 li = ni;
9207 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009208 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009209 l->lv_idx = l->lv_len - l->lv_idx - 1;
9210 }
9211}
9212
9213#define SP_NOMOVE 0x01 /* don't move cursor */
9214#define SP_REPEAT 0x02 /* repeat to find outer pair */
9215#define SP_RETCOUNT 0x04 /* return matchcount */
9216#define SP_SETPCMARK 0x08 /* set previous context mark */
9217#define SP_START 0x10 /* accept match at start position */
9218#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9219#define SP_END 0x40 /* leave cursor at end of match */
9220#define SP_COLUMN 0x80 /* start at cursor column */
9221
9222static int get_search_arg(typval_T *varp, int *flagsp);
9223
9224/*
9225 * Get flags for a search function.
9226 * Possibly sets "p_ws".
9227 * Returns BACKWARD, FORWARD or zero (for an error).
9228 */
9229 static int
9230get_search_arg(typval_T *varp, int *flagsp)
9231{
9232 int dir = FORWARD;
9233 char_u *flags;
9234 char_u nbuf[NUMBUFLEN];
9235 int mask;
9236
9237 if (varp->v_type != VAR_UNKNOWN)
9238 {
9239 flags = get_tv_string_buf_chk(varp, nbuf);
9240 if (flags == NULL)
9241 return 0; /* type error; errmsg already given */
9242 while (*flags != NUL)
9243 {
9244 switch (*flags)
9245 {
9246 case 'b': dir = BACKWARD; break;
9247 case 'w': p_ws = TRUE; break;
9248 case 'W': p_ws = FALSE; break;
9249 default: mask = 0;
9250 if (flagsp != NULL)
9251 switch (*flags)
9252 {
9253 case 'c': mask = SP_START; break;
9254 case 'e': mask = SP_END; break;
9255 case 'm': mask = SP_RETCOUNT; break;
9256 case 'n': mask = SP_NOMOVE; break;
9257 case 'p': mask = SP_SUBPAT; break;
9258 case 'r': mask = SP_REPEAT; break;
9259 case 's': mask = SP_SETPCMARK; break;
9260 case 'z': mask = SP_COLUMN; break;
9261 }
9262 if (mask == 0)
9263 {
9264 EMSG2(_(e_invarg2), flags);
9265 dir = 0;
9266 }
9267 else
9268 *flagsp |= mask;
9269 }
9270 if (dir == 0)
9271 break;
9272 ++flags;
9273 }
9274 }
9275 return dir;
9276}
9277
9278/*
9279 * Shared by search() and searchpos() functions.
9280 */
9281 static int
9282search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9283{
9284 int flags;
9285 char_u *pat;
9286 pos_T pos;
9287 pos_T save_cursor;
9288 int save_p_ws = p_ws;
9289 int dir;
9290 int retval = 0; /* default: FAIL */
9291 long lnum_stop = 0;
9292 proftime_T tm;
9293#ifdef FEAT_RELTIME
9294 long time_limit = 0;
9295#endif
9296 int options = SEARCH_KEEP;
9297 int subpatnum;
9298
9299 pat = get_tv_string(&argvars[0]);
9300 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9301 if (dir == 0)
9302 goto theend;
9303 flags = *flagsp;
9304 if (flags & SP_START)
9305 options |= SEARCH_START;
9306 if (flags & SP_END)
9307 options |= SEARCH_END;
9308 if (flags & SP_COLUMN)
9309 options |= SEARCH_COL;
9310
9311 /* Optional arguments: line number to stop searching and timeout. */
9312 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9313 {
9314 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9315 if (lnum_stop < 0)
9316 goto theend;
9317#ifdef FEAT_RELTIME
9318 if (argvars[3].v_type != VAR_UNKNOWN)
9319 {
9320 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9321 if (time_limit < 0)
9322 goto theend;
9323 }
9324#endif
9325 }
9326
9327#ifdef FEAT_RELTIME
9328 /* Set the time limit, if there is one. */
9329 profile_setlimit(time_limit, &tm);
9330#endif
9331
9332 /*
9333 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9334 * Check to make sure only those flags are set.
9335 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9336 * flags cannot be set. Check for that condition also.
9337 */
9338 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9339 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9340 {
9341 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9342 goto theend;
9343 }
9344
9345 pos = save_cursor = curwin->w_cursor;
9346 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009347 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009348 if (subpatnum != FAIL)
9349 {
9350 if (flags & SP_SUBPAT)
9351 retval = subpatnum;
9352 else
9353 retval = pos.lnum;
9354 if (flags & SP_SETPCMARK)
9355 setpcmark();
9356 curwin->w_cursor = pos;
9357 if (match_pos != NULL)
9358 {
9359 /* Store the match cursor position */
9360 match_pos->lnum = pos.lnum;
9361 match_pos->col = pos.col + 1;
9362 }
9363 /* "/$" will put the cursor after the end of the line, may need to
9364 * correct that here */
9365 check_cursor();
9366 }
9367
9368 /* If 'n' flag is used: restore cursor position. */
9369 if (flags & SP_NOMOVE)
9370 curwin->w_cursor = save_cursor;
9371 else
9372 curwin->w_set_curswant = TRUE;
9373theend:
9374 p_ws = save_p_ws;
9375
9376 return retval;
9377}
9378
9379#ifdef FEAT_FLOAT
9380
9381/*
9382 * round() is not in C90, use ceil() or floor() instead.
9383 */
9384 float_T
9385vim_round(float_T f)
9386{
9387 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9388}
9389
9390/*
9391 * "round({float})" function
9392 */
9393 static void
9394f_round(typval_T *argvars, typval_T *rettv)
9395{
9396 float_T f = 0.0;
9397
9398 rettv->v_type = VAR_FLOAT;
9399 if (get_float_arg(argvars, &f) == OK)
9400 rettv->vval.v_float = vim_round(f);
9401 else
9402 rettv->vval.v_float = 0.0;
9403}
9404#endif
9405
9406/*
9407 * "screenattr()" function
9408 */
9409 static void
9410f_screenattr(typval_T *argvars, typval_T *rettv)
9411{
9412 int row;
9413 int col;
9414 int c;
9415
9416 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9417 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9418 if (row < 0 || row >= screen_Rows
9419 || col < 0 || col >= screen_Columns)
9420 c = -1;
9421 else
9422 c = ScreenAttrs[LineOffset[row] + col];
9423 rettv->vval.v_number = c;
9424}
9425
9426/*
9427 * "screenchar()" function
9428 */
9429 static void
9430f_screenchar(typval_T *argvars, typval_T *rettv)
9431{
9432 int row;
9433 int col;
9434 int off;
9435 int c;
9436
9437 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9438 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9439 if (row < 0 || row >= screen_Rows
9440 || col < 0 || col >= screen_Columns)
9441 c = -1;
9442 else
9443 {
9444 off = LineOffset[row] + col;
9445#ifdef FEAT_MBYTE
9446 if (enc_utf8 && ScreenLinesUC[off] != 0)
9447 c = ScreenLinesUC[off];
9448 else
9449#endif
9450 c = ScreenLines[off];
9451 }
9452 rettv->vval.v_number = c;
9453}
9454
9455/*
9456 * "screencol()" function
9457 *
9458 * First column is 1 to be consistent with virtcol().
9459 */
9460 static void
9461f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9462{
9463 rettv->vval.v_number = screen_screencol() + 1;
9464}
9465
9466/*
9467 * "screenrow()" function
9468 */
9469 static void
9470f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9471{
9472 rettv->vval.v_number = screen_screenrow() + 1;
9473}
9474
9475/*
9476 * "search()" function
9477 */
9478 static void
9479f_search(typval_T *argvars, typval_T *rettv)
9480{
9481 int flags = 0;
9482
9483 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9484}
9485
9486/*
9487 * "searchdecl()" function
9488 */
9489 static void
9490f_searchdecl(typval_T *argvars, typval_T *rettv)
9491{
9492 int locally = 1;
9493 int thisblock = 0;
9494 int error = FALSE;
9495 char_u *name;
9496
9497 rettv->vval.v_number = 1; /* default: FAIL */
9498
9499 name = get_tv_string_chk(&argvars[0]);
9500 if (argvars[1].v_type != VAR_UNKNOWN)
9501 {
9502 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9503 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9504 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9505 }
9506 if (!error && name != NULL)
9507 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9508 locally, thisblock, SEARCH_KEEP) == FAIL;
9509}
9510
9511/*
9512 * Used by searchpair() and searchpairpos()
9513 */
9514 static int
9515searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9516{
9517 char_u *spat, *mpat, *epat;
9518 char_u *skip;
9519 int save_p_ws = p_ws;
9520 int dir;
9521 int flags = 0;
9522 char_u nbuf1[NUMBUFLEN];
9523 char_u nbuf2[NUMBUFLEN];
9524 char_u nbuf3[NUMBUFLEN];
9525 int retval = 0; /* default: FAIL */
9526 long lnum_stop = 0;
9527 long time_limit = 0;
9528
9529 /* Get the three pattern arguments: start, middle, end. */
9530 spat = get_tv_string_chk(&argvars[0]);
9531 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9532 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9533 if (spat == NULL || mpat == NULL || epat == NULL)
9534 goto theend; /* type error */
9535
9536 /* Handle the optional fourth argument: flags */
9537 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9538 if (dir == 0)
9539 goto theend;
9540
9541 /* Don't accept SP_END or SP_SUBPAT.
9542 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9543 */
9544 if ((flags & (SP_END | SP_SUBPAT)) != 0
9545 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9546 {
9547 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9548 goto theend;
9549 }
9550
9551 /* Using 'r' implies 'W', otherwise it doesn't work. */
9552 if (flags & SP_REPEAT)
9553 p_ws = FALSE;
9554
9555 /* Optional fifth argument: skip expression */
9556 if (argvars[3].v_type == VAR_UNKNOWN
9557 || argvars[4].v_type == VAR_UNKNOWN)
9558 skip = (char_u *)"";
9559 else
9560 {
9561 skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
9562 if (argvars[5].v_type != VAR_UNKNOWN)
9563 {
9564 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9565 if (lnum_stop < 0)
9566 goto theend;
9567#ifdef FEAT_RELTIME
9568 if (argvars[6].v_type != VAR_UNKNOWN)
9569 {
9570 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9571 if (time_limit < 0)
9572 goto theend;
9573 }
9574#endif
9575 }
9576 }
9577 if (skip == NULL)
9578 goto theend; /* type error */
9579
9580 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9581 match_pos, lnum_stop, time_limit);
9582
9583theend:
9584 p_ws = save_p_ws;
9585
9586 return retval;
9587}
9588
9589/*
9590 * "searchpair()" function
9591 */
9592 static void
9593f_searchpair(typval_T *argvars, typval_T *rettv)
9594{
9595 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9596}
9597
9598/*
9599 * "searchpairpos()" function
9600 */
9601 static void
9602f_searchpairpos(typval_T *argvars, typval_T *rettv)
9603{
9604 pos_T match_pos;
9605 int lnum = 0;
9606 int col = 0;
9607
9608 if (rettv_list_alloc(rettv) == FAIL)
9609 return;
9610
9611 if (searchpair_cmn(argvars, &match_pos) > 0)
9612 {
9613 lnum = match_pos.lnum;
9614 col = match_pos.col;
9615 }
9616
9617 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9618 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9619}
9620
9621/*
9622 * Search for a start/middle/end thing.
9623 * Used by searchpair(), see its documentation for the details.
9624 * Returns 0 or -1 for no match,
9625 */
9626 long
9627do_searchpair(
9628 char_u *spat, /* start pattern */
9629 char_u *mpat, /* middle pattern */
9630 char_u *epat, /* end pattern */
9631 int dir, /* BACKWARD or FORWARD */
9632 char_u *skip, /* skip expression */
9633 int flags, /* SP_SETPCMARK and other SP_ values */
9634 pos_T *match_pos,
9635 linenr_T lnum_stop, /* stop at this line if not zero */
9636 long time_limit UNUSED) /* stop after this many msec */
9637{
9638 char_u *save_cpo;
9639 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9640 long retval = 0;
9641 pos_T pos;
9642 pos_T firstpos;
9643 pos_T foundpos;
9644 pos_T save_cursor;
9645 pos_T save_pos;
9646 int n;
9647 int r;
9648 int nest = 1;
9649 int err;
9650 int options = SEARCH_KEEP;
9651 proftime_T tm;
9652
9653 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9654 save_cpo = p_cpo;
9655 p_cpo = empty_option;
9656
9657#ifdef FEAT_RELTIME
9658 /* Set the time limit, if there is one. */
9659 profile_setlimit(time_limit, &tm);
9660#endif
9661
9662 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9663 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009664 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9665 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009666 if (pat2 == NULL || pat3 == NULL)
9667 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009668 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009669 if (*mpat == NUL)
9670 STRCPY(pat3, pat2);
9671 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009672 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009673 spat, epat, mpat);
9674 if (flags & SP_START)
9675 options |= SEARCH_START;
9676
9677 save_cursor = curwin->w_cursor;
9678 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009679 CLEAR_POS(&firstpos);
9680 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009681 pat = pat3;
9682 for (;;)
9683 {
9684 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009685 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009686 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009687 /* didn't find it or found the first match again: FAIL */
9688 break;
9689
9690 if (firstpos.lnum == 0)
9691 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009692 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009693 {
9694 /* Found the same position again. Can happen with a pattern that
9695 * has "\zs" at the end and searching backwards. Advance one
9696 * character and try again. */
9697 if (dir == BACKWARD)
9698 decl(&pos);
9699 else
9700 incl(&pos);
9701 }
9702 foundpos = pos;
9703
9704 /* clear the start flag to avoid getting stuck here */
9705 options &= ~SEARCH_START;
9706
9707 /* If the skip pattern matches, ignore this match. */
9708 if (*skip != NUL)
9709 {
9710 save_pos = curwin->w_cursor;
9711 curwin->w_cursor = pos;
9712 r = eval_to_bool(skip, &err, NULL, FALSE);
9713 curwin->w_cursor = save_pos;
9714 if (err)
9715 {
9716 /* Evaluating {skip} caused an error, break here. */
9717 curwin->w_cursor = save_cursor;
9718 retval = -1;
9719 break;
9720 }
9721 if (r)
9722 continue;
9723 }
9724
9725 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9726 {
9727 /* Found end when searching backwards or start when searching
9728 * forward: nested pair. */
9729 ++nest;
9730 pat = pat2; /* nested, don't search for middle */
9731 }
9732 else
9733 {
9734 /* Found end when searching forward or start when searching
9735 * backward: end of (nested) pair; or found middle in outer pair. */
9736 if (--nest == 1)
9737 pat = pat3; /* outer level, search for middle */
9738 }
9739
9740 if (nest == 0)
9741 {
9742 /* Found the match: return matchcount or line number. */
9743 if (flags & SP_RETCOUNT)
9744 ++retval;
9745 else
9746 retval = pos.lnum;
9747 if (flags & SP_SETPCMARK)
9748 setpcmark();
9749 curwin->w_cursor = pos;
9750 if (!(flags & SP_REPEAT))
9751 break;
9752 nest = 1; /* search for next unmatched */
9753 }
9754 }
9755
9756 if (match_pos != NULL)
9757 {
9758 /* Store the match cursor position */
9759 match_pos->lnum = curwin->w_cursor.lnum;
9760 match_pos->col = curwin->w_cursor.col + 1;
9761 }
9762
9763 /* If 'n' flag is used or search failed: restore cursor position. */
9764 if ((flags & SP_NOMOVE) || retval == 0)
9765 curwin->w_cursor = save_cursor;
9766
9767theend:
9768 vim_free(pat2);
9769 vim_free(pat3);
9770 if (p_cpo == empty_option)
9771 p_cpo = save_cpo;
9772 else
9773 /* Darn, evaluating the {skip} expression changed the value. */
9774 free_string_option(save_cpo);
9775
9776 return retval;
9777}
9778
9779/*
9780 * "searchpos()" function
9781 */
9782 static void
9783f_searchpos(typval_T *argvars, typval_T *rettv)
9784{
9785 pos_T match_pos;
9786 int lnum = 0;
9787 int col = 0;
9788 int n;
9789 int flags = 0;
9790
9791 if (rettv_list_alloc(rettv) == FAIL)
9792 return;
9793
9794 n = search_cmn(argvars, &match_pos, &flags);
9795 if (n > 0)
9796 {
9797 lnum = match_pos.lnum;
9798 col = match_pos.col;
9799 }
9800
9801 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9802 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9803 if (flags & SP_SUBPAT)
9804 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9805}
9806
9807 static void
9808f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9809{
9810#ifdef FEAT_CLIENTSERVER
9811 char_u buf[NUMBUFLEN];
9812 char_u *server = get_tv_string_chk(&argvars[0]);
9813 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9814
9815 rettv->vval.v_number = -1;
9816 if (server == NULL || reply == NULL)
9817 return;
9818 if (check_restricted() || check_secure())
9819 return;
9820# ifdef FEAT_X11
9821 if (check_connection() == FAIL)
9822 return;
9823# endif
9824
9825 if (serverSendReply(server, reply) < 0)
9826 {
9827 EMSG(_("E258: Unable to send to client"));
9828 return;
9829 }
9830 rettv->vval.v_number = 0;
9831#else
9832 rettv->vval.v_number = -1;
9833#endif
9834}
9835
9836 static void
9837f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9838{
9839 char_u *r = NULL;
9840
9841#ifdef FEAT_CLIENTSERVER
9842# ifdef WIN32
9843 r = serverGetVimNames();
9844# else
9845 make_connection();
9846 if (X_DISPLAY != NULL)
9847 r = serverGetVimNames(X_DISPLAY);
9848# endif
9849#endif
9850 rettv->v_type = VAR_STRING;
9851 rettv->vval.v_string = r;
9852}
9853
9854/*
9855 * "setbufvar()" function
9856 */
9857 static void
9858f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9859{
9860 buf_T *buf;
9861 char_u *varname, *bufvarname;
9862 typval_T *varp;
9863 char_u nbuf[NUMBUFLEN];
9864
9865 if (check_restricted() || check_secure())
9866 return;
9867 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
9868 varname = get_tv_string_chk(&argvars[1]);
9869 buf = get_buf_tv(&argvars[0], FALSE);
9870 varp = &argvars[2];
9871
9872 if (buf != NULL && varname != NULL && varp != NULL)
9873 {
9874 if (*varname == '&')
9875 {
9876 long numval;
9877 char_u *strval;
9878 int error = FALSE;
9879 aco_save_T aco;
9880
9881 /* set curbuf to be our buf, temporarily */
9882 aucmd_prepbuf(&aco, buf);
9883
9884 ++varname;
9885 numval = (long)get_tv_number_chk(varp, &error);
9886 strval = get_tv_string_buf_chk(varp, nbuf);
9887 if (!error && strval != NULL)
9888 set_option_value(varname, numval, strval, OPT_LOCAL);
9889
9890 /* reset notion of buffer */
9891 aucmd_restbuf(&aco);
9892 }
9893 else
9894 {
9895 buf_T *save_curbuf = curbuf;
9896
9897 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
9898 if (bufvarname != NULL)
9899 {
9900 curbuf = buf;
9901 STRCPY(bufvarname, "b:");
9902 STRCPY(bufvarname + 2, varname);
9903 set_var(bufvarname, varp, TRUE);
9904 vim_free(bufvarname);
9905 curbuf = save_curbuf;
9906 }
9907 }
9908 }
9909}
9910
9911 static void
9912f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9913{
9914 dict_T *d;
9915 dictitem_T *di;
9916 char_u *csearch;
9917
9918 if (argvars[0].v_type != VAR_DICT)
9919 {
9920 EMSG(_(e_dictreq));
9921 return;
9922 }
9923
9924 if ((d = argvars[0].vval.v_dict) != NULL)
9925 {
9926 csearch = get_dict_string(d, (char_u *)"char", FALSE);
9927 if (csearch != NULL)
9928 {
9929#ifdef FEAT_MBYTE
9930 if (enc_utf8)
9931 {
9932 int pcc[MAX_MCO];
9933 int c = utfc_ptr2char(csearch, pcc);
9934
9935 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9936 }
9937 else
9938#endif
9939 set_last_csearch(PTR2CHAR(csearch),
9940 csearch, MB_PTR2LEN(csearch));
9941 }
9942
9943 di = dict_find(d, (char_u *)"forward", -1);
9944 if (di != NULL)
9945 set_csearch_direction((int)get_tv_number(&di->di_tv)
9946 ? FORWARD : BACKWARD);
9947
9948 di = dict_find(d, (char_u *)"until", -1);
9949 if (di != NULL)
9950 set_csearch_until(!!get_tv_number(&di->di_tv));
9951 }
9952}
9953
9954/*
9955 * "setcmdpos()" function
9956 */
9957 static void
9958f_setcmdpos(typval_T *argvars, typval_T *rettv)
9959{
9960 int pos = (int)get_tv_number(&argvars[0]) - 1;
9961
9962 if (pos >= 0)
9963 rettv->vval.v_number = set_cmdline_pos(pos);
9964}
9965
9966/*
9967 * "setfperm({fname}, {mode})" function
9968 */
9969 static void
9970f_setfperm(typval_T *argvars, typval_T *rettv)
9971{
9972 char_u *fname;
9973 char_u modebuf[NUMBUFLEN];
9974 char_u *mode_str;
9975 int i;
9976 int mask;
9977 int mode = 0;
9978
9979 rettv->vval.v_number = 0;
9980 fname = get_tv_string_chk(&argvars[0]);
9981 if (fname == NULL)
9982 return;
9983 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
9984 if (mode_str == NULL)
9985 return;
9986 if (STRLEN(mode_str) != 9)
9987 {
9988 EMSG2(_(e_invarg2), mode_str);
9989 return;
9990 }
9991
9992 mask = 1;
9993 for (i = 8; i >= 0; --i)
9994 {
9995 if (mode_str[i] != '-')
9996 mode |= mask;
9997 mask = mask << 1;
9998 }
9999 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10000}
10001
10002/*
10003 * "setline()" function
10004 */
10005 static void
10006f_setline(typval_T *argvars, typval_T *rettv)
10007{
10008 linenr_T lnum;
10009 char_u *line = NULL;
10010 list_T *l = NULL;
10011 listitem_T *li = NULL;
10012 long added = 0;
10013 linenr_T lcount = curbuf->b_ml.ml_line_count;
10014
10015 lnum = get_tv_lnum(&argvars[0]);
10016 if (argvars[1].v_type == VAR_LIST)
10017 {
10018 l = argvars[1].vval.v_list;
10019 li = l->lv_first;
10020 }
10021 else
10022 line = get_tv_string_chk(&argvars[1]);
10023
10024 /* default result is zero == OK */
10025 for (;;)
10026 {
10027 if (l != NULL)
10028 {
10029 /* list argument, get next string */
10030 if (li == NULL)
10031 break;
10032 line = get_tv_string_chk(&li->li_tv);
10033 li = li->li_next;
10034 }
10035
10036 rettv->vval.v_number = 1; /* FAIL */
10037 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10038 break;
10039
10040 /* When coming here from Insert mode, sync undo, so that this can be
10041 * undone separately from what was previously inserted. */
10042 if (u_sync_once == 2)
10043 {
10044 u_sync_once = 1; /* notify that u_sync() was called */
10045 u_sync(TRUE);
10046 }
10047
10048 if (lnum <= curbuf->b_ml.ml_line_count)
10049 {
10050 /* existing line, replace it */
10051 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10052 {
10053 changed_bytes(lnum, 0);
10054 if (lnum == curwin->w_cursor.lnum)
10055 check_cursor_col();
10056 rettv->vval.v_number = 0; /* OK */
10057 }
10058 }
10059 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10060 {
10061 /* lnum is one past the last line, append the line */
10062 ++added;
10063 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10064 rettv->vval.v_number = 0; /* OK */
10065 }
10066
10067 if (l == NULL) /* only one string argument */
10068 break;
10069 ++lnum;
10070 }
10071
10072 if (added > 0)
10073 appended_lines_mark(lcount, added);
10074}
10075
Bram Moolenaard823fa92016-08-12 16:29:27 +020010076static 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 +020010077
10078/*
10079 * Used by "setqflist()" and "setloclist()" functions
10080 */
10081 static void
10082set_qf_ll_list(
10083 win_T *wp UNUSED,
10084 typval_T *list_arg UNUSED,
10085 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010086 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010087 typval_T *rettv)
10088{
10089#ifdef FEAT_QUICKFIX
10090 static char *e_invact = N_("E927: Invalid action: '%s'");
10091 char_u *act;
10092 int action = 0;
10093#endif
10094
10095 rettv->vval.v_number = -1;
10096
10097#ifdef FEAT_QUICKFIX
10098 if (list_arg->v_type != VAR_LIST)
10099 EMSG(_(e_listreq));
10100 else
10101 {
10102 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010103 dict_T *d = NULL;
10104 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010105
10106 if (action_arg->v_type == VAR_STRING)
10107 {
10108 act = get_tv_string_chk(action_arg);
10109 if (act == NULL)
10110 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010111 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10112 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010113 action = *act;
10114 else
10115 EMSG2(_(e_invact), act);
10116 }
10117 else if (action_arg->v_type == VAR_UNKNOWN)
10118 action = ' ';
10119 else
10120 EMSG(_(e_stringreq));
10121
Bram Moolenaard823fa92016-08-12 16:29:27 +020010122 if (action_arg->v_type != VAR_UNKNOWN
10123 && what_arg->v_type != VAR_UNKNOWN)
10124 {
10125 if (what_arg->v_type == VAR_DICT)
10126 d = what_arg->vval.v_dict;
10127 else
10128 {
10129 EMSG(_(e_dictreq));
10130 valid_dict = FALSE;
10131 }
10132 }
10133
10134 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10135 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010136 rettv->vval.v_number = 0;
10137 }
10138#endif
10139}
10140
10141/*
10142 * "setloclist()" function
10143 */
10144 static void
10145f_setloclist(typval_T *argvars, typval_T *rettv)
10146{
10147 win_T *win;
10148
10149 rettv->vval.v_number = -1;
10150
10151 win = find_win_by_nr(&argvars[0], NULL);
10152 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010153 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010154}
10155
10156/*
10157 * "setmatches()" function
10158 */
10159 static void
10160f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10161{
10162#ifdef FEAT_SEARCH_EXTRA
10163 list_T *l;
10164 listitem_T *li;
10165 dict_T *d;
10166 list_T *s = NULL;
10167
10168 rettv->vval.v_number = -1;
10169 if (argvars[0].v_type != VAR_LIST)
10170 {
10171 EMSG(_(e_listreq));
10172 return;
10173 }
10174 if ((l = argvars[0].vval.v_list) != NULL)
10175 {
10176
10177 /* To some extent make sure that we are dealing with a list from
10178 * "getmatches()". */
10179 li = l->lv_first;
10180 while (li != NULL)
10181 {
10182 if (li->li_tv.v_type != VAR_DICT
10183 || (d = li->li_tv.vval.v_dict) == NULL)
10184 {
10185 EMSG(_(e_invarg));
10186 return;
10187 }
10188 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10189 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10190 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10191 && dict_find(d, (char_u *)"priority", -1) != NULL
10192 && dict_find(d, (char_u *)"id", -1) != NULL))
10193 {
10194 EMSG(_(e_invarg));
10195 return;
10196 }
10197 li = li->li_next;
10198 }
10199
10200 clear_matches(curwin);
10201 li = l->lv_first;
10202 while (li != NULL)
10203 {
10204 int i = 0;
10205 char_u buf[5];
10206 dictitem_T *di;
10207 char_u *group;
10208 int priority;
10209 int id;
10210 char_u *conceal;
10211
10212 d = li->li_tv.vval.v_dict;
10213 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10214 {
10215 if (s == NULL)
10216 {
10217 s = list_alloc();
10218 if (s == NULL)
10219 return;
10220 }
10221
10222 /* match from matchaddpos() */
10223 for (i = 1; i < 9; i++)
10224 {
10225 sprintf((char *)buf, (char *)"pos%d", i);
10226 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10227 {
10228 if (di->di_tv.v_type != VAR_LIST)
10229 return;
10230
10231 list_append_tv(s, &di->di_tv);
10232 s->lv_refcount++;
10233 }
10234 else
10235 break;
10236 }
10237 }
10238
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010239 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010240 priority = (int)get_dict_number(d, (char_u *)"priority");
10241 id = (int)get_dict_number(d, (char_u *)"id");
10242 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010243 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 : NULL;
10245 if (i == 0)
10246 {
10247 match_add(curwin, group,
10248 get_dict_string(d, (char_u *)"pattern", FALSE),
10249 priority, id, NULL, conceal);
10250 }
10251 else
10252 {
10253 match_add(curwin, group, NULL, priority, id, s, conceal);
10254 list_unref(s);
10255 s = NULL;
10256 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010257 vim_free(group);
10258 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010259
10260 li = li->li_next;
10261 }
10262 rettv->vval.v_number = 0;
10263 }
10264#endif
10265}
10266
10267/*
10268 * "setpos()" function
10269 */
10270 static void
10271f_setpos(typval_T *argvars, typval_T *rettv)
10272{
10273 pos_T pos;
10274 int fnum;
10275 char_u *name;
10276 colnr_T curswant = -1;
10277
10278 rettv->vval.v_number = -1;
10279 name = get_tv_string_chk(argvars);
10280 if (name != NULL)
10281 {
10282 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10283 {
10284 if (--pos.col < 0)
10285 pos.col = 0;
10286 if (name[0] == '.' && name[1] == NUL)
10287 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010288 /* set cursor; "fnum" is ignored */
10289 curwin->w_cursor = pos;
10290 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010291 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010292 curwin->w_curswant = curswant - 1;
10293 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010294 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010295 check_cursor();
10296 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010297 }
10298 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10299 {
10300 /* set mark */
10301 if (setmark_pos(name[1], &pos, fnum) == OK)
10302 rettv->vval.v_number = 0;
10303 }
10304 else
10305 EMSG(_(e_invarg));
10306 }
10307 }
10308}
10309
10310/*
10311 * "setqflist()" function
10312 */
10313 static void
10314f_setqflist(typval_T *argvars, typval_T *rettv)
10315{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010316 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010317}
10318
10319/*
10320 * "setreg()" function
10321 */
10322 static void
10323f_setreg(typval_T *argvars, typval_T *rettv)
10324{
10325 int regname;
10326 char_u *strregname;
10327 char_u *stropt;
10328 char_u *strval;
10329 int append;
10330 char_u yank_type;
10331 long block_len;
10332
10333 block_len = -1;
10334 yank_type = MAUTO;
10335 append = FALSE;
10336
10337 strregname = get_tv_string_chk(argvars);
10338 rettv->vval.v_number = 1; /* FAIL is default */
10339
10340 if (strregname == NULL)
10341 return; /* type error; errmsg already given */
10342 regname = *strregname;
10343 if (regname == 0 || regname == '@')
10344 regname = '"';
10345
10346 if (argvars[2].v_type != VAR_UNKNOWN)
10347 {
10348 stropt = get_tv_string_chk(&argvars[2]);
10349 if (stropt == NULL)
10350 return; /* type error */
10351 for (; *stropt != NUL; ++stropt)
10352 switch (*stropt)
10353 {
10354 case 'a': case 'A': /* append */
10355 append = TRUE;
10356 break;
10357 case 'v': case 'c': /* character-wise selection */
10358 yank_type = MCHAR;
10359 break;
10360 case 'V': case 'l': /* line-wise selection */
10361 yank_type = MLINE;
10362 break;
10363 case 'b': case Ctrl_V: /* block-wise selection */
10364 yank_type = MBLOCK;
10365 if (VIM_ISDIGIT(stropt[1]))
10366 {
10367 ++stropt;
10368 block_len = getdigits(&stropt) - 1;
10369 --stropt;
10370 }
10371 break;
10372 }
10373 }
10374
10375 if (argvars[1].v_type == VAR_LIST)
10376 {
10377 char_u **lstval;
10378 char_u **allocval;
10379 char_u buf[NUMBUFLEN];
10380 char_u **curval;
10381 char_u **curallocval;
10382 list_T *ll = argvars[1].vval.v_list;
10383 listitem_T *li;
10384 int len;
10385
10386 /* If the list is NULL handle like an empty list. */
10387 len = ll == NULL ? 0 : ll->lv_len;
10388
10389 /* First half: use for pointers to result lines; second half: use for
10390 * pointers to allocated copies. */
10391 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10392 if (lstval == NULL)
10393 return;
10394 curval = lstval;
10395 allocval = lstval + len + 2;
10396 curallocval = allocval;
10397
10398 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10399 li = li->li_next)
10400 {
10401 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10402 if (strval == NULL)
10403 goto free_lstval;
10404 if (strval == buf)
10405 {
10406 /* Need to make a copy, next get_tv_string_buf_chk() will
10407 * overwrite the string. */
10408 strval = vim_strsave(buf);
10409 if (strval == NULL)
10410 goto free_lstval;
10411 *curallocval++ = strval;
10412 }
10413 *curval++ = strval;
10414 }
10415 *curval++ = NULL;
10416
10417 write_reg_contents_lst(regname, lstval, -1,
10418 append, yank_type, block_len);
10419free_lstval:
10420 while (curallocval > allocval)
10421 vim_free(*--curallocval);
10422 vim_free(lstval);
10423 }
10424 else
10425 {
10426 strval = get_tv_string_chk(&argvars[1]);
10427 if (strval == NULL)
10428 return;
10429 write_reg_contents_ex(regname, strval, -1,
10430 append, yank_type, block_len);
10431 }
10432 rettv->vval.v_number = 0;
10433}
10434
10435/*
10436 * "settabvar()" function
10437 */
10438 static void
10439f_settabvar(typval_T *argvars, typval_T *rettv)
10440{
10441#ifdef FEAT_WINDOWS
10442 tabpage_T *save_curtab;
10443 tabpage_T *tp;
10444#endif
10445 char_u *varname, *tabvarname;
10446 typval_T *varp;
10447
10448 rettv->vval.v_number = 0;
10449
10450 if (check_restricted() || check_secure())
10451 return;
10452
10453#ifdef FEAT_WINDOWS
10454 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
10455#endif
10456 varname = get_tv_string_chk(&argvars[1]);
10457 varp = &argvars[2];
10458
10459 if (varname != NULL && varp != NULL
10460#ifdef FEAT_WINDOWS
10461 && tp != NULL
10462#endif
10463 )
10464 {
10465#ifdef FEAT_WINDOWS
10466 save_curtab = curtab;
10467 goto_tabpage_tp(tp, FALSE, FALSE);
10468#endif
10469
10470 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10471 if (tabvarname != NULL)
10472 {
10473 STRCPY(tabvarname, "t:");
10474 STRCPY(tabvarname + 2, varname);
10475 set_var(tabvarname, varp, TRUE);
10476 vim_free(tabvarname);
10477 }
10478
10479#ifdef FEAT_WINDOWS
10480 /* Restore current tabpage */
10481 if (valid_tabpage(save_curtab))
10482 goto_tabpage_tp(save_curtab, FALSE, FALSE);
10483#endif
10484 }
10485}
10486
10487/*
10488 * "settabwinvar()" function
10489 */
10490 static void
10491f_settabwinvar(typval_T *argvars, typval_T *rettv)
10492{
10493 setwinvar(argvars, rettv, 1);
10494}
10495
10496/*
10497 * "setwinvar()" function
10498 */
10499 static void
10500f_setwinvar(typval_T *argvars, typval_T *rettv)
10501{
10502 setwinvar(argvars, rettv, 0);
10503}
10504
10505#ifdef FEAT_CRYPT
10506/*
10507 * "sha256({string})" function
10508 */
10509 static void
10510f_sha256(typval_T *argvars, typval_T *rettv)
10511{
10512 char_u *p;
10513
10514 p = get_tv_string(&argvars[0]);
10515 rettv->vval.v_string = vim_strsave(
10516 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10517 rettv->v_type = VAR_STRING;
10518}
10519#endif /* FEAT_CRYPT */
10520
10521/*
10522 * "shellescape({string})" function
10523 */
10524 static void
10525f_shellescape(typval_T *argvars, typval_T *rettv)
10526{
Bram Moolenaar20615522017-06-05 18:46:26 +020010527 int do_special = non_zero_arg(&argvars[1]);
10528
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010529 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010530 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010531 rettv->v_type = VAR_STRING;
10532}
10533
10534/*
10535 * shiftwidth() function
10536 */
10537 static void
10538f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10539{
10540 rettv->vval.v_number = get_sw_value(curbuf);
10541}
10542
10543/*
10544 * "simplify()" function
10545 */
10546 static void
10547f_simplify(typval_T *argvars, typval_T *rettv)
10548{
10549 char_u *p;
10550
10551 p = get_tv_string(&argvars[0]);
10552 rettv->vval.v_string = vim_strsave(p);
10553 simplify_filename(rettv->vval.v_string); /* simplify in place */
10554 rettv->v_type = VAR_STRING;
10555}
10556
10557#ifdef FEAT_FLOAT
10558/*
10559 * "sin()" function
10560 */
10561 static void
10562f_sin(typval_T *argvars, typval_T *rettv)
10563{
10564 float_T f = 0.0;
10565
10566 rettv->v_type = VAR_FLOAT;
10567 if (get_float_arg(argvars, &f) == OK)
10568 rettv->vval.v_float = sin(f);
10569 else
10570 rettv->vval.v_float = 0.0;
10571}
10572
10573/*
10574 * "sinh()" function
10575 */
10576 static void
10577f_sinh(typval_T *argvars, typval_T *rettv)
10578{
10579 float_T f = 0.0;
10580
10581 rettv->v_type = VAR_FLOAT;
10582 if (get_float_arg(argvars, &f) == OK)
10583 rettv->vval.v_float = sinh(f);
10584 else
10585 rettv->vval.v_float = 0.0;
10586}
10587#endif
10588
10589static int
10590#ifdef __BORLANDC__
10591 _RTLENTRYF
10592#endif
10593 item_compare(const void *s1, const void *s2);
10594static int
10595#ifdef __BORLANDC__
10596 _RTLENTRYF
10597#endif
10598 item_compare2(const void *s1, const void *s2);
10599
10600/* struct used in the array that's given to qsort() */
10601typedef struct
10602{
10603 listitem_T *item;
10604 int idx;
10605} sortItem_T;
10606
10607/* struct storing information about current sort */
10608typedef struct
10609{
10610 int item_compare_ic;
10611 int item_compare_numeric;
10612 int item_compare_numbers;
10613#ifdef FEAT_FLOAT
10614 int item_compare_float;
10615#endif
10616 char_u *item_compare_func;
10617 partial_T *item_compare_partial;
10618 dict_T *item_compare_selfdict;
10619 int item_compare_func_err;
10620 int item_compare_keep_zero;
10621} sortinfo_T;
10622static sortinfo_T *sortinfo = NULL;
10623static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10624#define ITEM_COMPARE_FAIL 999
10625
10626/*
10627 * Compare functions for f_sort() and f_uniq() below.
10628 */
10629 static int
10630#ifdef __BORLANDC__
10631_RTLENTRYF
10632#endif
10633item_compare(const void *s1, const void *s2)
10634{
10635 sortItem_T *si1, *si2;
10636 typval_T *tv1, *tv2;
10637 char_u *p1, *p2;
10638 char_u *tofree1 = NULL, *tofree2 = NULL;
10639 int res;
10640 char_u numbuf1[NUMBUFLEN];
10641 char_u numbuf2[NUMBUFLEN];
10642
10643 si1 = (sortItem_T *)s1;
10644 si2 = (sortItem_T *)s2;
10645 tv1 = &si1->item->li_tv;
10646 tv2 = &si2->item->li_tv;
10647
10648 if (sortinfo->item_compare_numbers)
10649 {
10650 varnumber_T v1 = get_tv_number(tv1);
10651 varnumber_T v2 = get_tv_number(tv2);
10652
10653 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10654 }
10655
10656#ifdef FEAT_FLOAT
10657 if (sortinfo->item_compare_float)
10658 {
10659 float_T v1 = get_tv_float(tv1);
10660 float_T v2 = get_tv_float(tv2);
10661
10662 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10663 }
10664#endif
10665
10666 /* tv2string() puts quotes around a string and allocates memory. Don't do
10667 * that for string variables. Use a single quote when comparing with a
10668 * non-string to do what the docs promise. */
10669 if (tv1->v_type == VAR_STRING)
10670 {
10671 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10672 p1 = (char_u *)"'";
10673 else
10674 p1 = tv1->vval.v_string;
10675 }
10676 else
10677 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10678 if (tv2->v_type == VAR_STRING)
10679 {
10680 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10681 p2 = (char_u *)"'";
10682 else
10683 p2 = tv2->vval.v_string;
10684 }
10685 else
10686 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10687 if (p1 == NULL)
10688 p1 = (char_u *)"";
10689 if (p2 == NULL)
10690 p2 = (char_u *)"";
10691 if (!sortinfo->item_compare_numeric)
10692 {
10693 if (sortinfo->item_compare_ic)
10694 res = STRICMP(p1, p2);
10695 else
10696 res = STRCMP(p1, p2);
10697 }
10698 else
10699 {
10700 double n1, n2;
10701 n1 = strtod((char *)p1, (char **)&p1);
10702 n2 = strtod((char *)p2, (char **)&p2);
10703 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10704 }
10705
10706 /* When the result would be zero, compare the item indexes. Makes the
10707 * sort stable. */
10708 if (res == 0 && !sortinfo->item_compare_keep_zero)
10709 res = si1->idx > si2->idx ? 1 : -1;
10710
10711 vim_free(tofree1);
10712 vim_free(tofree2);
10713 return res;
10714}
10715
10716 static int
10717#ifdef __BORLANDC__
10718_RTLENTRYF
10719#endif
10720item_compare2(const void *s1, const void *s2)
10721{
10722 sortItem_T *si1, *si2;
10723 int res;
10724 typval_T rettv;
10725 typval_T argv[3];
10726 int dummy;
10727 char_u *func_name;
10728 partial_T *partial = sortinfo->item_compare_partial;
10729
10730 /* shortcut after failure in previous call; compare all items equal */
10731 if (sortinfo->item_compare_func_err)
10732 return 0;
10733
10734 si1 = (sortItem_T *)s1;
10735 si2 = (sortItem_T *)s2;
10736
10737 if (partial == NULL)
10738 func_name = sortinfo->item_compare_func;
10739 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010740 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010741
10742 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10743 * in the copy without changing the original list items. */
10744 copy_tv(&si1->item->li_tv, &argv[0]);
10745 copy_tv(&si2->item->li_tv, &argv[1]);
10746
10747 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10748 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010749 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010750 partial, sortinfo->item_compare_selfdict);
10751 clear_tv(&argv[0]);
10752 clear_tv(&argv[1]);
10753
10754 if (res == FAIL)
10755 res = ITEM_COMPARE_FAIL;
10756 else
10757 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10758 if (sortinfo->item_compare_func_err)
10759 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10760 clear_tv(&rettv);
10761
10762 /* When the result would be zero, compare the pointers themselves. Makes
10763 * the sort stable. */
10764 if (res == 0 && !sortinfo->item_compare_keep_zero)
10765 res = si1->idx > si2->idx ? 1 : -1;
10766
10767 return res;
10768}
10769
10770/*
10771 * "sort({list})" function
10772 */
10773 static void
10774do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10775{
10776 list_T *l;
10777 listitem_T *li;
10778 sortItem_T *ptrs;
10779 sortinfo_T *old_sortinfo;
10780 sortinfo_T info;
10781 long len;
10782 long i;
10783
10784 /* Pointer to current info struct used in compare function. Save and
10785 * restore the current one for nested calls. */
10786 old_sortinfo = sortinfo;
10787 sortinfo = &info;
10788
10789 if (argvars[0].v_type != VAR_LIST)
10790 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10791 else
10792 {
10793 l = argvars[0].vval.v_list;
10794 if (l == NULL || tv_check_lock(l->lv_lock,
10795 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10796 TRUE))
10797 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010798 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010799
10800 len = list_len(l);
10801 if (len <= 1)
10802 goto theend; /* short list sorts pretty quickly */
10803
10804 info.item_compare_ic = FALSE;
10805 info.item_compare_numeric = FALSE;
10806 info.item_compare_numbers = FALSE;
10807#ifdef FEAT_FLOAT
10808 info.item_compare_float = FALSE;
10809#endif
10810 info.item_compare_func = NULL;
10811 info.item_compare_partial = NULL;
10812 info.item_compare_selfdict = NULL;
10813 if (argvars[1].v_type != VAR_UNKNOWN)
10814 {
10815 /* optional second argument: {func} */
10816 if (argvars[1].v_type == VAR_FUNC)
10817 info.item_compare_func = argvars[1].vval.v_string;
10818 else if (argvars[1].v_type == VAR_PARTIAL)
10819 info.item_compare_partial = argvars[1].vval.v_partial;
10820 else
10821 {
10822 int error = FALSE;
10823
10824 i = (long)get_tv_number_chk(&argvars[1], &error);
10825 if (error)
10826 goto theend; /* type error; errmsg already given */
10827 if (i == 1)
10828 info.item_compare_ic = TRUE;
10829 else if (argvars[1].v_type != VAR_NUMBER)
10830 info.item_compare_func = get_tv_string(&argvars[1]);
10831 else if (i != 0)
10832 {
10833 EMSG(_(e_invarg));
10834 goto theend;
10835 }
10836 if (info.item_compare_func != NULL)
10837 {
10838 if (*info.item_compare_func == NUL)
10839 {
10840 /* empty string means default sort */
10841 info.item_compare_func = NULL;
10842 }
10843 else if (STRCMP(info.item_compare_func, "n") == 0)
10844 {
10845 info.item_compare_func = NULL;
10846 info.item_compare_numeric = TRUE;
10847 }
10848 else if (STRCMP(info.item_compare_func, "N") == 0)
10849 {
10850 info.item_compare_func = NULL;
10851 info.item_compare_numbers = TRUE;
10852 }
10853#ifdef FEAT_FLOAT
10854 else if (STRCMP(info.item_compare_func, "f") == 0)
10855 {
10856 info.item_compare_func = NULL;
10857 info.item_compare_float = TRUE;
10858 }
10859#endif
10860 else if (STRCMP(info.item_compare_func, "i") == 0)
10861 {
10862 info.item_compare_func = NULL;
10863 info.item_compare_ic = TRUE;
10864 }
10865 }
10866 }
10867
10868 if (argvars[2].v_type != VAR_UNKNOWN)
10869 {
10870 /* optional third argument: {dict} */
10871 if (argvars[2].v_type != VAR_DICT)
10872 {
10873 EMSG(_(e_dictreq));
10874 goto theend;
10875 }
10876 info.item_compare_selfdict = argvars[2].vval.v_dict;
10877 }
10878 }
10879
10880 /* Make an array with each entry pointing to an item in the List. */
10881 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
10882 if (ptrs == NULL)
10883 goto theend;
10884
10885 i = 0;
10886 if (sort)
10887 {
10888 /* sort(): ptrs will be the list to sort */
10889 for (li = l->lv_first; li != NULL; li = li->li_next)
10890 {
10891 ptrs[i].item = li;
10892 ptrs[i].idx = i;
10893 ++i;
10894 }
10895
10896 info.item_compare_func_err = FALSE;
10897 info.item_compare_keep_zero = FALSE;
10898 /* test the compare function */
10899 if ((info.item_compare_func != NULL
10900 || info.item_compare_partial != NULL)
10901 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
10902 == ITEM_COMPARE_FAIL)
10903 EMSG(_("E702: Sort compare function failed"));
10904 else
10905 {
10906 /* Sort the array with item pointers. */
10907 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
10908 info.item_compare_func == NULL
10909 && info.item_compare_partial == NULL
10910 ? item_compare : item_compare2);
10911
10912 if (!info.item_compare_func_err)
10913 {
10914 /* Clear the List and append the items in sorted order. */
10915 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
10916 l->lv_len = 0;
10917 for (i = 0; i < len; ++i)
10918 list_append(l, ptrs[i].item);
10919 }
10920 }
10921 }
10922 else
10923 {
10924 int (*item_compare_func_ptr)(const void *, const void *);
10925
10926 /* f_uniq(): ptrs will be a stack of items to remove */
10927 info.item_compare_func_err = FALSE;
10928 info.item_compare_keep_zero = TRUE;
10929 item_compare_func_ptr = info.item_compare_func != NULL
10930 || info.item_compare_partial != NULL
10931 ? item_compare2 : item_compare;
10932
10933 for (li = l->lv_first; li != NULL && li->li_next != NULL;
10934 li = li->li_next)
10935 {
10936 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
10937 == 0)
10938 ptrs[i++].item = li;
10939 if (info.item_compare_func_err)
10940 {
10941 EMSG(_("E882: Uniq compare function failed"));
10942 break;
10943 }
10944 }
10945
10946 if (!info.item_compare_func_err)
10947 {
10948 while (--i >= 0)
10949 {
10950 li = ptrs[i].item->li_next;
10951 ptrs[i].item->li_next = li->li_next;
10952 if (li->li_next != NULL)
10953 li->li_next->li_prev = ptrs[i].item;
10954 else
10955 l->lv_last = ptrs[i].item;
10956 list_fix_watch(l, li);
10957 listitem_free(li);
10958 l->lv_len--;
10959 }
10960 }
10961 }
10962
10963 vim_free(ptrs);
10964 }
10965theend:
10966 sortinfo = old_sortinfo;
10967}
10968
10969/*
10970 * "sort({list})" function
10971 */
10972 static void
10973f_sort(typval_T *argvars, typval_T *rettv)
10974{
10975 do_sort_uniq(argvars, rettv, TRUE);
10976}
10977
10978/*
10979 * "uniq({list})" function
10980 */
10981 static void
10982f_uniq(typval_T *argvars, typval_T *rettv)
10983{
10984 do_sort_uniq(argvars, rettv, FALSE);
10985}
10986
10987/*
10988 * "soundfold({word})" function
10989 */
10990 static void
10991f_soundfold(typval_T *argvars, typval_T *rettv)
10992{
10993 char_u *s;
10994
10995 rettv->v_type = VAR_STRING;
10996 s = get_tv_string(&argvars[0]);
10997#ifdef FEAT_SPELL
10998 rettv->vval.v_string = eval_soundfold(s);
10999#else
11000 rettv->vval.v_string = vim_strsave(s);
11001#endif
11002}
11003
11004/*
11005 * "spellbadword()" function
11006 */
11007 static void
11008f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11009{
11010 char_u *word = (char_u *)"";
11011 hlf_T attr = HLF_COUNT;
11012 int len = 0;
11013
11014 if (rettv_list_alloc(rettv) == FAIL)
11015 return;
11016
11017#ifdef FEAT_SPELL
11018 if (argvars[0].v_type == VAR_UNKNOWN)
11019 {
11020 /* Find the start and length of the badly spelled word. */
11021 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11022 if (len != 0)
11023 word = ml_get_cursor();
11024 }
11025 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11026 {
11027 char_u *str = get_tv_string_chk(&argvars[0]);
11028 int capcol = -1;
11029
11030 if (str != NULL)
11031 {
11032 /* Check the argument for spelling. */
11033 while (*str != NUL)
11034 {
11035 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11036 if (attr != HLF_COUNT)
11037 {
11038 word = str;
11039 break;
11040 }
11041 str += len;
11042 }
11043 }
11044 }
11045#endif
11046
11047 list_append_string(rettv->vval.v_list, word, len);
11048 list_append_string(rettv->vval.v_list, (char_u *)(
11049 attr == HLF_SPB ? "bad" :
11050 attr == HLF_SPR ? "rare" :
11051 attr == HLF_SPL ? "local" :
11052 attr == HLF_SPC ? "caps" :
11053 ""), -1);
11054}
11055
11056/*
11057 * "spellsuggest()" function
11058 */
11059 static void
11060f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11061{
11062#ifdef FEAT_SPELL
11063 char_u *str;
11064 int typeerr = FALSE;
11065 int maxcount;
11066 garray_T ga;
11067 int i;
11068 listitem_T *li;
11069 int need_capital = FALSE;
11070#endif
11071
11072 if (rettv_list_alloc(rettv) == FAIL)
11073 return;
11074
11075#ifdef FEAT_SPELL
11076 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11077 {
11078 str = get_tv_string(&argvars[0]);
11079 if (argvars[1].v_type != VAR_UNKNOWN)
11080 {
11081 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11082 if (maxcount <= 0)
11083 return;
11084 if (argvars[2].v_type != VAR_UNKNOWN)
11085 {
11086 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11087 if (typeerr)
11088 return;
11089 }
11090 }
11091 else
11092 maxcount = 25;
11093
11094 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11095
11096 for (i = 0; i < ga.ga_len; ++i)
11097 {
11098 str = ((char_u **)ga.ga_data)[i];
11099
11100 li = listitem_alloc();
11101 if (li == NULL)
11102 vim_free(str);
11103 else
11104 {
11105 li->li_tv.v_type = VAR_STRING;
11106 li->li_tv.v_lock = 0;
11107 li->li_tv.vval.v_string = str;
11108 list_append(rettv->vval.v_list, li);
11109 }
11110 }
11111 ga_clear(&ga);
11112 }
11113#endif
11114}
11115
11116 static void
11117f_split(typval_T *argvars, typval_T *rettv)
11118{
11119 char_u *str;
11120 char_u *end;
11121 char_u *pat = NULL;
11122 regmatch_T regmatch;
11123 char_u patbuf[NUMBUFLEN];
11124 char_u *save_cpo;
11125 int match;
11126 colnr_T col = 0;
11127 int keepempty = FALSE;
11128 int typeerr = FALSE;
11129
11130 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11131 save_cpo = p_cpo;
11132 p_cpo = (char_u *)"";
11133
11134 str = get_tv_string(&argvars[0]);
11135 if (argvars[1].v_type != VAR_UNKNOWN)
11136 {
11137 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11138 if (pat == NULL)
11139 typeerr = TRUE;
11140 if (argvars[2].v_type != VAR_UNKNOWN)
11141 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11142 }
11143 if (pat == NULL || *pat == NUL)
11144 pat = (char_u *)"[\\x01- ]\\+";
11145
11146 if (rettv_list_alloc(rettv) == FAIL)
11147 return;
11148 if (typeerr)
11149 return;
11150
11151 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11152 if (regmatch.regprog != NULL)
11153 {
11154 regmatch.rm_ic = FALSE;
11155 while (*str != NUL || keepempty)
11156 {
11157 if (*str == NUL)
11158 match = FALSE; /* empty item at the end */
11159 else
11160 match = vim_regexec_nl(&regmatch, str, col);
11161 if (match)
11162 end = regmatch.startp[0];
11163 else
11164 end = str + STRLEN(str);
11165 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11166 && *str != NUL && match && end < regmatch.endp[0]))
11167 {
11168 if (list_append_string(rettv->vval.v_list, str,
11169 (int)(end - str)) == FAIL)
11170 break;
11171 }
11172 if (!match)
11173 break;
11174 /* Advance to just after the match. */
11175 if (regmatch.endp[0] > str)
11176 col = 0;
11177 else
11178 {
11179 /* Don't get stuck at the same match. */
11180#ifdef FEAT_MBYTE
11181 col = (*mb_ptr2len)(regmatch.endp[0]);
11182#else
11183 col = 1;
11184#endif
11185 }
11186 str = regmatch.endp[0];
11187 }
11188
11189 vim_regfree(regmatch.regprog);
11190 }
11191
11192 p_cpo = save_cpo;
11193}
11194
11195#ifdef FEAT_FLOAT
11196/*
11197 * "sqrt()" function
11198 */
11199 static void
11200f_sqrt(typval_T *argvars, typval_T *rettv)
11201{
11202 float_T f = 0.0;
11203
11204 rettv->v_type = VAR_FLOAT;
11205 if (get_float_arg(argvars, &f) == OK)
11206 rettv->vval.v_float = sqrt(f);
11207 else
11208 rettv->vval.v_float = 0.0;
11209}
11210
11211/*
11212 * "str2float()" function
11213 */
11214 static void
11215f_str2float(typval_T *argvars, typval_T *rettv)
11216{
11217 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011218 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011219
Bram Moolenaar08243d22017-01-10 16:12:29 +010011220 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011221 p = skipwhite(p + 1);
11222 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011223 if (isneg)
11224 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011225 rettv->v_type = VAR_FLOAT;
11226}
11227#endif
11228
11229/*
11230 * "str2nr()" function
11231 */
11232 static void
11233f_str2nr(typval_T *argvars, typval_T *rettv)
11234{
11235 int base = 10;
11236 char_u *p;
11237 varnumber_T n;
11238 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011239 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011240
11241 if (argvars[1].v_type != VAR_UNKNOWN)
11242 {
11243 base = (int)get_tv_number(&argvars[1]);
11244 if (base != 2 && base != 8 && base != 10 && base != 16)
11245 {
11246 EMSG(_(e_invarg));
11247 return;
11248 }
11249 }
11250
11251 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011252 isneg = (*p == '-');
11253 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011254 p = skipwhite(p + 1);
11255 switch (base)
11256 {
11257 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11258 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11259 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11260 default: what = 0;
11261 }
11262 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011263 if (isneg)
11264 rettv->vval.v_number = -n;
11265 else
11266 rettv->vval.v_number = n;
11267
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011268}
11269
11270#ifdef HAVE_STRFTIME
11271/*
11272 * "strftime({format}[, {time}])" function
11273 */
11274 static void
11275f_strftime(typval_T *argvars, typval_T *rettv)
11276{
11277 char_u result_buf[256];
11278 struct tm *curtime;
11279 time_t seconds;
11280 char_u *p;
11281
11282 rettv->v_type = VAR_STRING;
11283
11284 p = get_tv_string(&argvars[0]);
11285 if (argvars[1].v_type == VAR_UNKNOWN)
11286 seconds = time(NULL);
11287 else
11288 seconds = (time_t)get_tv_number(&argvars[1]);
11289 curtime = localtime(&seconds);
11290 /* MSVC returns NULL for an invalid value of seconds. */
11291 if (curtime == NULL)
11292 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11293 else
11294 {
11295# ifdef FEAT_MBYTE
11296 vimconv_T conv;
11297 char_u *enc;
11298
11299 conv.vc_type = CONV_NONE;
11300 enc = enc_locale();
11301 convert_setup(&conv, p_enc, enc);
11302 if (conv.vc_type != CONV_NONE)
11303 p = string_convert(&conv, p, NULL);
11304# endif
11305 if (p != NULL)
11306 (void)strftime((char *)result_buf, sizeof(result_buf),
11307 (char *)p, curtime);
11308 else
11309 result_buf[0] = NUL;
11310
11311# ifdef FEAT_MBYTE
11312 if (conv.vc_type != CONV_NONE)
11313 vim_free(p);
11314 convert_setup(&conv, enc, p_enc);
11315 if (conv.vc_type != CONV_NONE)
11316 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11317 else
11318# endif
11319 rettv->vval.v_string = vim_strsave(result_buf);
11320
11321# ifdef FEAT_MBYTE
11322 /* Release conversion descriptors */
11323 convert_setup(&conv, NULL, NULL);
11324 vim_free(enc);
11325# endif
11326 }
11327}
11328#endif
11329
11330/*
11331 * "strgetchar()" function
11332 */
11333 static void
11334f_strgetchar(typval_T *argvars, typval_T *rettv)
11335{
11336 char_u *str;
11337 int len;
11338 int error = FALSE;
11339 int charidx;
11340
11341 rettv->vval.v_number = -1;
11342 str = get_tv_string_chk(&argvars[0]);
11343 if (str == NULL)
11344 return;
11345 len = (int)STRLEN(str);
11346 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11347 if (error)
11348 return;
11349#ifdef FEAT_MBYTE
11350 {
11351 int byteidx = 0;
11352
11353 while (charidx >= 0 && byteidx < len)
11354 {
11355 if (charidx == 0)
11356 {
11357 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11358 break;
11359 }
11360 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011361 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011362 }
11363 }
11364#else
11365 if (charidx < len)
11366 rettv->vval.v_number = str[charidx];
11367#endif
11368}
11369
11370/*
11371 * "stridx()" function
11372 */
11373 static void
11374f_stridx(typval_T *argvars, typval_T *rettv)
11375{
11376 char_u buf[NUMBUFLEN];
11377 char_u *needle;
11378 char_u *haystack;
11379 char_u *save_haystack;
11380 char_u *pos;
11381 int start_idx;
11382
11383 needle = get_tv_string_chk(&argvars[1]);
11384 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11385 rettv->vval.v_number = -1;
11386 if (needle == NULL || haystack == NULL)
11387 return; /* type error; errmsg already given */
11388
11389 if (argvars[2].v_type != VAR_UNKNOWN)
11390 {
11391 int error = FALSE;
11392
11393 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11394 if (error || start_idx >= (int)STRLEN(haystack))
11395 return;
11396 if (start_idx >= 0)
11397 haystack += start_idx;
11398 }
11399
11400 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11401 if (pos != NULL)
11402 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11403}
11404
11405/*
11406 * "string()" function
11407 */
11408 static void
11409f_string(typval_T *argvars, typval_T *rettv)
11410{
11411 char_u *tofree;
11412 char_u numbuf[NUMBUFLEN];
11413
11414 rettv->v_type = VAR_STRING;
11415 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11416 get_copyID());
11417 /* Make a copy if we have a value but it's not in allocated memory. */
11418 if (rettv->vval.v_string != NULL && tofree == NULL)
11419 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11420}
11421
11422/*
11423 * "strlen()" function
11424 */
11425 static void
11426f_strlen(typval_T *argvars, typval_T *rettv)
11427{
11428 rettv->vval.v_number = (varnumber_T)(STRLEN(
11429 get_tv_string(&argvars[0])));
11430}
11431
11432/*
11433 * "strchars()" function
11434 */
11435 static void
11436f_strchars(typval_T *argvars, typval_T *rettv)
11437{
11438 char_u *s = get_tv_string(&argvars[0]);
11439 int skipcc = 0;
11440#ifdef FEAT_MBYTE
11441 varnumber_T len = 0;
11442 int (*func_mb_ptr2char_adv)(char_u **pp);
11443#endif
11444
11445 if (argvars[1].v_type != VAR_UNKNOWN)
11446 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11447 if (skipcc < 0 || skipcc > 1)
11448 EMSG(_(e_invarg));
11449 else
11450 {
11451#ifdef FEAT_MBYTE
11452 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11453 while (*s != NUL)
11454 {
11455 func_mb_ptr2char_adv(&s);
11456 ++len;
11457 }
11458 rettv->vval.v_number = len;
11459#else
11460 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11461#endif
11462 }
11463}
11464
11465/*
11466 * "strdisplaywidth()" function
11467 */
11468 static void
11469f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11470{
11471 char_u *s = get_tv_string(&argvars[0]);
11472 int col = 0;
11473
11474 if (argvars[1].v_type != VAR_UNKNOWN)
11475 col = (int)get_tv_number(&argvars[1]);
11476
11477 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11478}
11479
11480/*
11481 * "strwidth()" function
11482 */
11483 static void
11484f_strwidth(typval_T *argvars, typval_T *rettv)
11485{
11486 char_u *s = get_tv_string(&argvars[0]);
11487
11488 rettv->vval.v_number = (varnumber_T)(
11489#ifdef FEAT_MBYTE
11490 mb_string2cells(s, -1)
11491#else
11492 STRLEN(s)
11493#endif
11494 );
11495}
11496
11497/*
11498 * "strcharpart()" function
11499 */
11500 static void
11501f_strcharpart(typval_T *argvars, typval_T *rettv)
11502{
11503#ifdef FEAT_MBYTE
11504 char_u *p;
11505 int nchar;
11506 int nbyte = 0;
11507 int charlen;
11508 int len = 0;
11509 int slen;
11510 int error = FALSE;
11511
11512 p = get_tv_string(&argvars[0]);
11513 slen = (int)STRLEN(p);
11514
11515 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11516 if (!error)
11517 {
11518 if (nchar > 0)
11519 while (nchar > 0 && nbyte < slen)
11520 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011521 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011522 --nchar;
11523 }
11524 else
11525 nbyte = nchar;
11526 if (argvars[2].v_type != VAR_UNKNOWN)
11527 {
11528 charlen = (int)get_tv_number(&argvars[2]);
11529 while (charlen > 0 && nbyte + len < slen)
11530 {
11531 int off = nbyte + len;
11532
11533 if (off < 0)
11534 len += 1;
11535 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011536 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011537 --charlen;
11538 }
11539 }
11540 else
11541 len = slen - nbyte; /* default: all bytes that are available. */
11542 }
11543
11544 /*
11545 * Only return the overlap between the specified part and the actual
11546 * string.
11547 */
11548 if (nbyte < 0)
11549 {
11550 len += nbyte;
11551 nbyte = 0;
11552 }
11553 else if (nbyte > slen)
11554 nbyte = slen;
11555 if (len < 0)
11556 len = 0;
11557 else if (nbyte + len > slen)
11558 len = slen - nbyte;
11559
11560 rettv->v_type = VAR_STRING;
11561 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11562#else
11563 f_strpart(argvars, rettv);
11564#endif
11565}
11566
11567/*
11568 * "strpart()" function
11569 */
11570 static void
11571f_strpart(typval_T *argvars, typval_T *rettv)
11572{
11573 char_u *p;
11574 int n;
11575 int len;
11576 int slen;
11577 int error = FALSE;
11578
11579 p = get_tv_string(&argvars[0]);
11580 slen = (int)STRLEN(p);
11581
11582 n = (int)get_tv_number_chk(&argvars[1], &error);
11583 if (error)
11584 len = 0;
11585 else if (argvars[2].v_type != VAR_UNKNOWN)
11586 len = (int)get_tv_number(&argvars[2]);
11587 else
11588 len = slen - n; /* default len: all bytes that are available. */
11589
11590 /*
11591 * Only return the overlap between the specified part and the actual
11592 * string.
11593 */
11594 if (n < 0)
11595 {
11596 len += n;
11597 n = 0;
11598 }
11599 else if (n > slen)
11600 n = slen;
11601 if (len < 0)
11602 len = 0;
11603 else if (n + len > slen)
11604 len = slen - n;
11605
11606 rettv->v_type = VAR_STRING;
11607 rettv->vval.v_string = vim_strnsave(p + n, len);
11608}
11609
11610/*
11611 * "strridx()" function
11612 */
11613 static void
11614f_strridx(typval_T *argvars, typval_T *rettv)
11615{
11616 char_u buf[NUMBUFLEN];
11617 char_u *needle;
11618 char_u *haystack;
11619 char_u *rest;
11620 char_u *lastmatch = NULL;
11621 int haystack_len, end_idx;
11622
11623 needle = get_tv_string_chk(&argvars[1]);
11624 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11625
11626 rettv->vval.v_number = -1;
11627 if (needle == NULL || haystack == NULL)
11628 return; /* type error; errmsg already given */
11629
11630 haystack_len = (int)STRLEN(haystack);
11631 if (argvars[2].v_type != VAR_UNKNOWN)
11632 {
11633 /* Third argument: upper limit for index */
11634 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11635 if (end_idx < 0)
11636 return; /* can never find a match */
11637 }
11638 else
11639 end_idx = haystack_len;
11640
11641 if (*needle == NUL)
11642 {
11643 /* Empty string matches past the end. */
11644 lastmatch = haystack + end_idx;
11645 }
11646 else
11647 {
11648 for (rest = haystack; *rest != '\0'; ++rest)
11649 {
11650 rest = (char_u *)strstr((char *)rest, (char *)needle);
11651 if (rest == NULL || rest > haystack + end_idx)
11652 break;
11653 lastmatch = rest;
11654 }
11655 }
11656
11657 if (lastmatch == NULL)
11658 rettv->vval.v_number = -1;
11659 else
11660 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11661}
11662
11663/*
11664 * "strtrans()" function
11665 */
11666 static void
11667f_strtrans(typval_T *argvars, typval_T *rettv)
11668{
11669 rettv->v_type = VAR_STRING;
11670 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11671}
11672
11673/*
11674 * "submatch()" function
11675 */
11676 static void
11677f_submatch(typval_T *argvars, typval_T *rettv)
11678{
11679 int error = FALSE;
11680 int no;
11681 int retList = 0;
11682
11683 no = (int)get_tv_number_chk(&argvars[0], &error);
11684 if (error)
11685 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011686 if (no < 0 || no >= NSUBEXP)
11687 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010011688 EMSGN(_("E935: invalid submatch number: %d"), no);
11689 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011690 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011691 if (argvars[1].v_type != VAR_UNKNOWN)
11692 retList = (int)get_tv_number_chk(&argvars[1], &error);
11693 if (error)
11694 return;
11695
11696 if (retList == 0)
11697 {
11698 rettv->v_type = VAR_STRING;
11699 rettv->vval.v_string = reg_submatch(no);
11700 }
11701 else
11702 {
11703 rettv->v_type = VAR_LIST;
11704 rettv->vval.v_list = reg_submatch_list(no);
11705 }
11706}
11707
11708/*
11709 * "substitute()" function
11710 */
11711 static void
11712f_substitute(typval_T *argvars, typval_T *rettv)
11713{
11714 char_u patbuf[NUMBUFLEN];
11715 char_u subbuf[NUMBUFLEN];
11716 char_u flagsbuf[NUMBUFLEN];
11717
11718 char_u *str = get_tv_string_chk(&argvars[0]);
11719 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011720 char_u *sub = NULL;
11721 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011722 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11723
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011724 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11725 expr = &argvars[2];
11726 else
11727 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11728
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011729 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011730 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11731 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011732 rettv->vval.v_string = NULL;
11733 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011734 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011735}
11736
11737/*
11738 * "synID(lnum, col, trans)" function
11739 */
11740 static void
11741f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11742{
11743 int id = 0;
11744#ifdef FEAT_SYN_HL
11745 linenr_T lnum;
11746 colnr_T col;
11747 int trans;
11748 int transerr = FALSE;
11749
11750 lnum = get_tv_lnum(argvars); /* -1 on type error */
11751 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11752 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11753
11754 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11755 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11756 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11757#endif
11758
11759 rettv->vval.v_number = id;
11760}
11761
11762/*
11763 * "synIDattr(id, what [, mode])" function
11764 */
11765 static void
11766f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11767{
11768 char_u *p = NULL;
11769#ifdef FEAT_SYN_HL
11770 int id;
11771 char_u *what;
11772 char_u *mode;
11773 char_u modebuf[NUMBUFLEN];
11774 int modec;
11775
11776 id = (int)get_tv_number(&argvars[0]);
11777 what = get_tv_string(&argvars[1]);
11778 if (argvars[2].v_type != VAR_UNKNOWN)
11779 {
11780 mode = get_tv_string_buf(&argvars[2], modebuf);
11781 modec = TOLOWER_ASC(mode[0]);
11782 if (modec != 't' && modec != 'c' && modec != 'g')
11783 modec = 0; /* replace invalid with current */
11784 }
11785 else
11786 {
11787#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11788 if (USE_24BIT)
11789 modec = 'g';
11790 else
11791#endif
11792 if (t_colors > 1)
11793 modec = 'c';
11794 else
11795 modec = 't';
11796 }
11797
11798
11799 switch (TOLOWER_ASC(what[0]))
11800 {
11801 case 'b':
11802 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11803 p = highlight_color(id, what, modec);
11804 else /* bold */
11805 p = highlight_has_attr(id, HL_BOLD, modec);
11806 break;
11807
11808 case 'f': /* fg[#] or font */
11809 p = highlight_color(id, what, modec);
11810 break;
11811
11812 case 'i':
11813 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11814 p = highlight_has_attr(id, HL_INVERSE, modec);
11815 else /* italic */
11816 p = highlight_has_attr(id, HL_ITALIC, modec);
11817 break;
11818
11819 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011820 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011821 break;
11822
11823 case 'r': /* reverse */
11824 p = highlight_has_attr(id, HL_INVERSE, modec);
11825 break;
11826
11827 case 's':
11828 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11829 p = highlight_color(id, what, modec);
11830 else /* standout */
11831 p = highlight_has_attr(id, HL_STANDOUT, modec);
11832 break;
11833
11834 case 'u':
11835 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11836 /* underline */
11837 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11838 else
11839 /* undercurl */
11840 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11841 break;
11842 }
11843
11844 if (p != NULL)
11845 p = vim_strsave(p);
11846#endif
11847 rettv->v_type = VAR_STRING;
11848 rettv->vval.v_string = p;
11849}
11850
11851/*
11852 * "synIDtrans(id)" function
11853 */
11854 static void
11855f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11856{
11857 int id;
11858
11859#ifdef FEAT_SYN_HL
11860 id = (int)get_tv_number(&argvars[0]);
11861
11862 if (id > 0)
11863 id = syn_get_final_id(id);
11864 else
11865#endif
11866 id = 0;
11867
11868 rettv->vval.v_number = id;
11869}
11870
11871/*
11872 * "synconcealed(lnum, col)" function
11873 */
11874 static void
11875f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11876{
11877#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11878 linenr_T lnum;
11879 colnr_T col;
11880 int syntax_flags = 0;
11881 int cchar;
11882 int matchid = 0;
11883 char_u str[NUMBUFLEN];
11884#endif
11885
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011886 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011887
11888#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11889 lnum = get_tv_lnum(argvars); /* -1 on type error */
11890 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11891
11892 vim_memset(str, NUL, sizeof(str));
11893
11894 if (rettv_list_alloc(rettv) != FAIL)
11895 {
11896 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11897 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11898 && curwin->w_p_cole > 0)
11899 {
11900 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11901 syntax_flags = get_syntax_info(&matchid);
11902
11903 /* get the conceal character */
11904 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11905 {
11906 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011907 if (cchar == NUL && curwin->w_p_cole == 1)
11908 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011909 if (cchar != NUL)
11910 {
11911# ifdef FEAT_MBYTE
11912 if (has_mbyte)
11913 (*mb_char2bytes)(cchar, str);
11914 else
11915# endif
11916 str[0] = cchar;
11917 }
11918 }
11919 }
11920
11921 list_append_number(rettv->vval.v_list,
11922 (syntax_flags & HL_CONCEAL) != 0);
11923 /* -1 to auto-determine strlen */
11924 list_append_string(rettv->vval.v_list, str, -1);
11925 list_append_number(rettv->vval.v_list, matchid);
11926 }
11927#endif
11928}
11929
11930/*
11931 * "synstack(lnum, col)" function
11932 */
11933 static void
11934f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11935{
11936#ifdef FEAT_SYN_HL
11937 linenr_T lnum;
11938 colnr_T col;
11939 int i;
11940 int id;
11941#endif
11942
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011943 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011944
11945#ifdef FEAT_SYN_HL
11946 lnum = get_tv_lnum(argvars); /* -1 on type error */
11947 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11948
11949 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11950 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11951 && rettv_list_alloc(rettv) != FAIL)
11952 {
11953 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11954 for (i = 0; ; ++i)
11955 {
11956 id = syn_get_stack_item(i);
11957 if (id < 0)
11958 break;
11959 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11960 break;
11961 }
11962 }
11963#endif
11964}
11965
11966 static void
11967get_cmd_output_as_rettv(
11968 typval_T *argvars,
11969 typval_T *rettv,
11970 int retlist)
11971{
11972 char_u *res = NULL;
11973 char_u *p;
11974 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011975 int err = FALSE;
11976 FILE *fd;
11977 list_T *list = NULL;
11978 int flags = SHELL_SILENT;
11979
11980 rettv->v_type = VAR_STRING;
11981 rettv->vval.v_string = NULL;
11982 if (check_restricted() || check_secure())
11983 goto errret;
11984
11985 if (argvars[1].v_type != VAR_UNKNOWN)
11986 {
11987 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011988 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011989 * command.
11990 */
11991 if ((infile = vim_tempname('i', TRUE)) == NULL)
11992 {
11993 EMSG(_(e_notmp));
11994 goto errret;
11995 }
11996
11997 fd = mch_fopen((char *)infile, WRITEBIN);
11998 if (fd == NULL)
11999 {
12000 EMSG2(_(e_notopen), infile);
12001 goto errret;
12002 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012003 if (argvars[1].v_type == VAR_NUMBER)
12004 {
12005 linenr_T lnum;
12006 buf_T *buf;
12007
12008 buf = buflist_findnr(argvars[1].vval.v_number);
12009 if (buf == NULL)
12010 {
12011 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012012 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012013 goto errret;
12014 }
12015
12016 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12017 {
12018 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12019 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12020 {
12021 err = TRUE;
12022 break;
12023 }
12024 if (putc(NL, fd) == EOF)
12025 {
12026 err = TRUE;
12027 break;
12028 }
12029 }
12030 }
12031 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012032 {
12033 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12034 err = TRUE;
12035 }
12036 else
12037 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012038 size_t len;
12039 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012040
12041 p = get_tv_string_buf_chk(&argvars[1], buf);
12042 if (p == NULL)
12043 {
12044 fclose(fd);
12045 goto errret; /* type error; errmsg already given */
12046 }
12047 len = STRLEN(p);
12048 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12049 err = TRUE;
12050 }
12051 if (fclose(fd) != 0)
12052 err = TRUE;
12053 if (err)
12054 {
12055 EMSG(_("E677: Error writing temp file"));
12056 goto errret;
12057 }
12058 }
12059
12060 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12061 * echoes typeahead, that messes up the display. */
12062 if (!msg_silent)
12063 flags += SHELL_COOKED;
12064
12065 if (retlist)
12066 {
12067 int len;
12068 listitem_T *li;
12069 char_u *s = NULL;
12070 char_u *start;
12071 char_u *end;
12072 int i;
12073
12074 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12075 if (res == NULL)
12076 goto errret;
12077
12078 list = list_alloc();
12079 if (list == NULL)
12080 goto errret;
12081
12082 for (i = 0; i < len; ++i)
12083 {
12084 start = res + i;
12085 while (i < len && res[i] != NL)
12086 ++i;
12087 end = res + i;
12088
12089 s = alloc((unsigned)(end - start + 1));
12090 if (s == NULL)
12091 goto errret;
12092
12093 for (p = s; start < end; ++p, ++start)
12094 *p = *start == NUL ? NL : *start;
12095 *p = NUL;
12096
12097 li = listitem_alloc();
12098 if (li == NULL)
12099 {
12100 vim_free(s);
12101 goto errret;
12102 }
12103 li->li_tv.v_type = VAR_STRING;
12104 li->li_tv.v_lock = 0;
12105 li->li_tv.vval.v_string = s;
12106 list_append(list, li);
12107 }
12108
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012109 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012110 list = NULL;
12111 }
12112 else
12113 {
12114 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12115#ifdef USE_CR
12116 /* translate <CR> into <NL> */
12117 if (res != NULL)
12118 {
12119 char_u *s;
12120
12121 for (s = res; *s; ++s)
12122 {
12123 if (*s == CAR)
12124 *s = NL;
12125 }
12126 }
12127#else
12128# ifdef USE_CRNL
12129 /* translate <CR><NL> into <NL> */
12130 if (res != NULL)
12131 {
12132 char_u *s, *d;
12133
12134 d = res;
12135 for (s = res; *s; ++s)
12136 {
12137 if (s[0] == CAR && s[1] == NL)
12138 ++s;
12139 *d++ = *s;
12140 }
12141 *d = NUL;
12142 }
12143# endif
12144#endif
12145 rettv->vval.v_string = res;
12146 res = NULL;
12147 }
12148
12149errret:
12150 if (infile != NULL)
12151 {
12152 mch_remove(infile);
12153 vim_free(infile);
12154 }
12155 if (res != NULL)
12156 vim_free(res);
12157 if (list != NULL)
12158 list_free(list);
12159}
12160
12161/*
12162 * "system()" function
12163 */
12164 static void
12165f_system(typval_T *argvars, typval_T *rettv)
12166{
12167 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12168}
12169
12170/*
12171 * "systemlist()" function
12172 */
12173 static void
12174f_systemlist(typval_T *argvars, typval_T *rettv)
12175{
12176 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12177}
12178
12179/*
12180 * "tabpagebuflist()" function
12181 */
12182 static void
12183f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12184{
12185#ifdef FEAT_WINDOWS
12186 tabpage_T *tp;
12187 win_T *wp = NULL;
12188
12189 if (argvars[0].v_type == VAR_UNKNOWN)
12190 wp = firstwin;
12191 else
12192 {
12193 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12194 if (tp != NULL)
12195 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12196 }
12197 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12198 {
12199 for (; wp != NULL; wp = wp->w_next)
12200 if (list_append_number(rettv->vval.v_list,
12201 wp->w_buffer->b_fnum) == FAIL)
12202 break;
12203 }
12204#endif
12205}
12206
12207
12208/*
12209 * "tabpagenr()" function
12210 */
12211 static void
12212f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12213{
12214 int nr = 1;
12215#ifdef FEAT_WINDOWS
12216 char_u *arg;
12217
12218 if (argvars[0].v_type != VAR_UNKNOWN)
12219 {
12220 arg = get_tv_string_chk(&argvars[0]);
12221 nr = 0;
12222 if (arg != NULL)
12223 {
12224 if (STRCMP(arg, "$") == 0)
12225 nr = tabpage_index(NULL) - 1;
12226 else
12227 EMSG2(_(e_invexpr2), arg);
12228 }
12229 }
12230 else
12231 nr = tabpage_index(curtab);
12232#endif
12233 rettv->vval.v_number = nr;
12234}
12235
12236
12237#ifdef FEAT_WINDOWS
12238static int get_winnr(tabpage_T *tp, typval_T *argvar);
12239
12240/*
12241 * Common code for tabpagewinnr() and winnr().
12242 */
12243 static int
12244get_winnr(tabpage_T *tp, typval_T *argvar)
12245{
12246 win_T *twin;
12247 int nr = 1;
12248 win_T *wp;
12249 char_u *arg;
12250
12251 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12252 if (argvar->v_type != VAR_UNKNOWN)
12253 {
12254 arg = get_tv_string_chk(argvar);
12255 if (arg == NULL)
12256 nr = 0; /* type error; errmsg already given */
12257 else if (STRCMP(arg, "$") == 0)
12258 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12259 else if (STRCMP(arg, "#") == 0)
12260 {
12261 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12262 if (twin == NULL)
12263 nr = 0;
12264 }
12265 else
12266 {
12267 EMSG2(_(e_invexpr2), arg);
12268 nr = 0;
12269 }
12270 }
12271
12272 if (nr > 0)
12273 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12274 wp != twin; wp = wp->w_next)
12275 {
12276 if (wp == NULL)
12277 {
12278 /* didn't find it in this tabpage */
12279 nr = 0;
12280 break;
12281 }
12282 ++nr;
12283 }
12284 return nr;
12285}
12286#endif
12287
12288/*
12289 * "tabpagewinnr()" function
12290 */
12291 static void
12292f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12293{
12294 int nr = 1;
12295#ifdef FEAT_WINDOWS
12296 tabpage_T *tp;
12297
12298 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12299 if (tp == NULL)
12300 nr = 0;
12301 else
12302 nr = get_winnr(tp, &argvars[1]);
12303#endif
12304 rettv->vval.v_number = nr;
12305}
12306
12307
12308/*
12309 * "tagfiles()" function
12310 */
12311 static void
12312f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12313{
12314 char_u *fname;
12315 tagname_T tn;
12316 int first;
12317
12318 if (rettv_list_alloc(rettv) == FAIL)
12319 return;
12320 fname = alloc(MAXPATHL);
12321 if (fname == NULL)
12322 return;
12323
12324 for (first = TRUE; ; first = FALSE)
12325 if (get_tagfname(&tn, first, fname) == FAIL
12326 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12327 break;
12328 tagname_free(&tn);
12329 vim_free(fname);
12330}
12331
12332/*
12333 * "taglist()" function
12334 */
12335 static void
12336f_taglist(typval_T *argvars, typval_T *rettv)
12337{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012338 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012339 char_u *tag_pattern;
12340
12341 tag_pattern = get_tv_string(&argvars[0]);
12342
12343 rettv->vval.v_number = FALSE;
12344 if (*tag_pattern == NUL)
12345 return;
12346
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012347 if (argvars[1].v_type != VAR_UNKNOWN)
12348 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012349 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012350 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012351}
12352
12353/*
12354 * "tempname()" function
12355 */
12356 static void
12357f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12358{
12359 static int x = 'A';
12360
12361 rettv->v_type = VAR_STRING;
12362 rettv->vval.v_string = vim_tempname(x, FALSE);
12363
12364 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12365 * names. Skip 'I' and 'O', they are used for shell redirection. */
12366 do
12367 {
12368 if (x == 'Z')
12369 x = '0';
12370 else if (x == '9')
12371 x = 'A';
12372 else
12373 {
12374#ifdef EBCDIC
12375 if (x == 'I')
12376 x = 'J';
12377 else if (x == 'R')
12378 x = 'S';
12379 else
12380#endif
12381 ++x;
12382 }
12383 } while (x == 'I' || x == 'O');
12384}
12385
12386#ifdef FEAT_FLOAT
12387/*
12388 * "tan()" function
12389 */
12390 static void
12391f_tan(typval_T *argvars, typval_T *rettv)
12392{
12393 float_T f = 0.0;
12394
12395 rettv->v_type = VAR_FLOAT;
12396 if (get_float_arg(argvars, &f) == OK)
12397 rettv->vval.v_float = tan(f);
12398 else
12399 rettv->vval.v_float = 0.0;
12400}
12401
12402/*
12403 * "tanh()" function
12404 */
12405 static void
12406f_tanh(typval_T *argvars, typval_T *rettv)
12407{
12408 float_T f = 0.0;
12409
12410 rettv->v_type = VAR_FLOAT;
12411 if (get_float_arg(argvars, &f) == OK)
12412 rettv->vval.v_float = tanh(f);
12413 else
12414 rettv->vval.v_float = 0.0;
12415}
12416#endif
12417
12418/*
12419 * "test_alloc_fail(id, countdown, repeat)" function
12420 */
12421 static void
12422f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12423{
12424 if (argvars[0].v_type != VAR_NUMBER
12425 || argvars[0].vval.v_number <= 0
12426 || argvars[1].v_type != VAR_NUMBER
12427 || argvars[1].vval.v_number < 0
12428 || argvars[2].v_type != VAR_NUMBER)
12429 EMSG(_(e_invarg));
12430 else
12431 {
12432 alloc_fail_id = argvars[0].vval.v_number;
12433 if (alloc_fail_id >= aid_last)
12434 EMSG(_(e_invarg));
12435 alloc_fail_countdown = argvars[1].vval.v_number;
12436 alloc_fail_repeat = argvars[2].vval.v_number;
12437 did_outofmem_msg = FALSE;
12438 }
12439}
12440
12441/*
12442 * "test_autochdir()"
12443 */
12444 static void
12445f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12446{
12447#if defined(FEAT_AUTOCHDIR)
12448 test_autochdir = TRUE;
12449#endif
12450}
12451
12452/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012453 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012454 */
12455 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012456f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012457{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012458 char_u *name = (char_u *)"";
12459 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012460 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012461
12462 if (argvars[0].v_type != VAR_STRING
12463 || (argvars[1].v_type) != VAR_NUMBER)
12464 EMSG(_(e_invarg));
12465 else
12466 {
12467 name = get_tv_string_chk(&argvars[0]);
12468 val = (int)get_tv_number(&argvars[1]);
12469
12470 if (STRCMP(name, (char_u *)"redraw") == 0)
12471 disable_redraw_for_testing = val;
12472 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12473 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012474 else if (STRCMP(name, (char_u *)"starting") == 0)
12475 {
12476 if (val)
12477 {
12478 if (save_starting < 0)
12479 save_starting = starting;
12480 starting = 0;
12481 }
12482 else
12483 {
12484 starting = save_starting;
12485 save_starting = -1;
12486 }
12487 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012488 else if (STRCMP(name, (char_u *)"ALL") == 0)
12489 {
12490 disable_char_avail_for_testing = FALSE;
12491 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012492 if (save_starting >= 0)
12493 {
12494 starting = save_starting;
12495 save_starting = -1;
12496 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012497 }
12498 else
12499 EMSG2(_(e_invarg2), name);
12500 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012501}
12502
12503/*
12504 * "test_garbagecollect_now()" function
12505 */
12506 static void
12507f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12508{
12509 /* This is dangerous, any Lists and Dicts used internally may be freed
12510 * while still in use. */
12511 garbage_collect(TRUE);
12512}
12513
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012514/*
12515 * "test_ignore_error()" function
12516 */
12517 static void
12518f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12519{
12520 ignore_error_for_testing(get_tv_string(&argvars[0]));
12521}
12522
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012523#ifdef FEAT_JOB_CHANNEL
12524 static void
12525f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12526{
12527 rettv->v_type = VAR_CHANNEL;
12528 rettv->vval.v_channel = NULL;
12529}
12530#endif
12531
12532 static void
12533f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12534{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012535 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012536}
12537
12538#ifdef FEAT_JOB_CHANNEL
12539 static void
12540f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12541{
12542 rettv->v_type = VAR_JOB;
12543 rettv->vval.v_job = NULL;
12544}
12545#endif
12546
12547 static void
12548f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12549{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012550 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012551}
12552
12553 static void
12554f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12555{
12556 rettv->v_type = VAR_PARTIAL;
12557 rettv->vval.v_partial = NULL;
12558}
12559
12560 static void
12561f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12562{
12563 rettv->v_type = VAR_STRING;
12564 rettv->vval.v_string = NULL;
12565}
12566
12567 static void
12568f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12569{
12570 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12571}
12572
12573#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12574/*
12575 * Get a callback from "arg". It can be a Funcref or a function name.
12576 * When "arg" is zero return an empty string.
12577 * Return NULL for an invalid argument.
12578 */
12579 char_u *
12580get_callback(typval_T *arg, partial_T **pp)
12581{
12582 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12583 {
12584 *pp = arg->vval.v_partial;
12585 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012586 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012587 }
12588 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012589 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012590 {
12591 func_ref(arg->vval.v_string);
12592 return arg->vval.v_string;
12593 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012594 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12595 return (char_u *)"";
12596 EMSG(_("E921: Invalid callback argument"));
12597 return NULL;
12598}
12599
12600/*
12601 * Unref/free "callback" and "partial" retured by get_callback().
12602 */
12603 void
12604free_callback(char_u *callback, partial_T *partial)
12605{
12606 if (partial != NULL)
12607 partial_unref(partial);
12608 else if (callback != NULL)
12609 {
12610 func_unref(callback);
12611 vim_free(callback);
12612 }
12613}
12614#endif
12615
12616#ifdef FEAT_TIMERS
12617/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012618 * "timer_info([timer])" function
12619 */
12620 static void
12621f_timer_info(typval_T *argvars, typval_T *rettv)
12622{
12623 timer_T *timer = NULL;
12624
12625 if (rettv_list_alloc(rettv) != OK)
12626 return;
12627 if (argvars[0].v_type != VAR_UNKNOWN)
12628 {
12629 if (argvars[0].v_type != VAR_NUMBER)
12630 EMSG(_(e_number_exp));
12631 else
12632 {
12633 timer = find_timer((int)get_tv_number(&argvars[0]));
12634 if (timer != NULL)
12635 add_timer_info(rettv, timer);
12636 }
12637 }
12638 else
12639 add_timer_info_all(rettv);
12640}
12641
12642/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012643 * "timer_pause(timer, paused)" function
12644 */
12645 static void
12646f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12647{
12648 timer_T *timer = NULL;
12649 int paused = (int)get_tv_number(&argvars[1]);
12650
12651 if (argvars[0].v_type != VAR_NUMBER)
12652 EMSG(_(e_number_exp));
12653 else
12654 {
12655 timer = find_timer((int)get_tv_number(&argvars[0]));
12656 if (timer != NULL)
12657 timer->tr_paused = paused;
12658 }
12659}
12660
12661/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012662 * "timer_start(time, callback [, options])" function
12663 */
12664 static void
12665f_timer_start(typval_T *argvars, typval_T *rettv)
12666{
Bram Moolenaar75537a92016-09-05 22:45:28 +020012667 long msec = (long)get_tv_number(&argvars[0]);
12668 timer_T *timer;
12669 int repeat = 0;
12670 char_u *callback;
12671 dict_T *dict;
12672 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012673
Bram Moolenaar75537a92016-09-05 22:45:28 +020012674 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012675 if (check_secure())
12676 return;
12677 if (argvars[2].v_type != VAR_UNKNOWN)
12678 {
12679 if (argvars[2].v_type != VAR_DICT
12680 || (dict = argvars[2].vval.v_dict) == NULL)
12681 {
12682 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12683 return;
12684 }
12685 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12686 repeat = get_dict_number(dict, (char_u *)"repeat");
12687 }
12688
Bram Moolenaar75537a92016-09-05 22:45:28 +020012689 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012690 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012691 return;
12692
12693 timer = create_timer(msec, repeat);
12694 if (timer == NULL)
12695 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012696 else
12697 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020012698 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020012699 timer->tr_callback = vim_strsave(callback);
12700 else
12701 /* pointer into the partial */
12702 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012703 timer->tr_partial = partial;
12704 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012705 }
12706}
12707
12708/*
12709 * "timer_stop(timer)" function
12710 */
12711 static void
12712f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12713{
12714 timer_T *timer;
12715
12716 if (argvars[0].v_type != VAR_NUMBER)
12717 {
12718 EMSG(_(e_number_exp));
12719 return;
12720 }
12721 timer = find_timer((int)get_tv_number(&argvars[0]));
12722 if (timer != NULL)
12723 stop_timer(timer);
12724}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012725
12726/*
12727 * "timer_stopall()" function
12728 */
12729 static void
12730f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12731{
12732 stop_all_timers();
12733}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012734#endif
12735
12736/*
12737 * "tolower(string)" function
12738 */
12739 static void
12740f_tolower(typval_T *argvars, typval_T *rettv)
12741{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012742 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010012743 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012744}
12745
12746/*
12747 * "toupper(string)" function
12748 */
12749 static void
12750f_toupper(typval_T *argvars, typval_T *rettv)
12751{
12752 rettv->v_type = VAR_STRING;
12753 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12754}
12755
12756/*
12757 * "tr(string, fromstr, tostr)" function
12758 */
12759 static void
12760f_tr(typval_T *argvars, typval_T *rettv)
12761{
12762 char_u *in_str;
12763 char_u *fromstr;
12764 char_u *tostr;
12765 char_u *p;
12766#ifdef FEAT_MBYTE
12767 int inlen;
12768 int fromlen;
12769 int tolen;
12770 int idx;
12771 char_u *cpstr;
12772 int cplen;
12773 int first = TRUE;
12774#endif
12775 char_u buf[NUMBUFLEN];
12776 char_u buf2[NUMBUFLEN];
12777 garray_T ga;
12778
12779 in_str = get_tv_string(&argvars[0]);
12780 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12781 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12782
12783 /* Default return value: empty string. */
12784 rettv->v_type = VAR_STRING;
12785 rettv->vval.v_string = NULL;
12786 if (fromstr == NULL || tostr == NULL)
12787 return; /* type error; errmsg already given */
12788 ga_init2(&ga, (int)sizeof(char), 80);
12789
12790#ifdef FEAT_MBYTE
12791 if (!has_mbyte)
12792#endif
12793 /* not multi-byte: fromstr and tostr must be the same length */
12794 if (STRLEN(fromstr) != STRLEN(tostr))
12795 {
12796#ifdef FEAT_MBYTE
12797error:
12798#endif
12799 EMSG2(_(e_invarg2), fromstr);
12800 ga_clear(&ga);
12801 return;
12802 }
12803
12804 /* fromstr and tostr have to contain the same number of chars */
12805 while (*in_str != NUL)
12806 {
12807#ifdef FEAT_MBYTE
12808 if (has_mbyte)
12809 {
12810 inlen = (*mb_ptr2len)(in_str);
12811 cpstr = in_str;
12812 cplen = inlen;
12813 idx = 0;
12814 for (p = fromstr; *p != NUL; p += fromlen)
12815 {
12816 fromlen = (*mb_ptr2len)(p);
12817 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12818 {
12819 for (p = tostr; *p != NUL; p += tolen)
12820 {
12821 tolen = (*mb_ptr2len)(p);
12822 if (idx-- == 0)
12823 {
12824 cplen = tolen;
12825 cpstr = p;
12826 break;
12827 }
12828 }
12829 if (*p == NUL) /* tostr is shorter than fromstr */
12830 goto error;
12831 break;
12832 }
12833 ++idx;
12834 }
12835
12836 if (first && cpstr == in_str)
12837 {
12838 /* Check that fromstr and tostr have the same number of
12839 * (multi-byte) characters. Done only once when a character
12840 * of in_str doesn't appear in fromstr. */
12841 first = FALSE;
12842 for (p = tostr; *p != NUL; p += tolen)
12843 {
12844 tolen = (*mb_ptr2len)(p);
12845 --idx;
12846 }
12847 if (idx != 0)
12848 goto error;
12849 }
12850
12851 (void)ga_grow(&ga, cplen);
12852 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12853 ga.ga_len += cplen;
12854
12855 in_str += inlen;
12856 }
12857 else
12858#endif
12859 {
12860 /* When not using multi-byte chars we can do it faster. */
12861 p = vim_strchr(fromstr, *in_str);
12862 if (p != NULL)
12863 ga_append(&ga, tostr[p - fromstr]);
12864 else
12865 ga_append(&ga, *in_str);
12866 ++in_str;
12867 }
12868 }
12869
12870 /* add a terminating NUL */
12871 (void)ga_grow(&ga, 1);
12872 ga_append(&ga, NUL);
12873
12874 rettv->vval.v_string = ga.ga_data;
12875}
12876
12877#ifdef FEAT_FLOAT
12878/*
12879 * "trunc({float})" function
12880 */
12881 static void
12882f_trunc(typval_T *argvars, typval_T *rettv)
12883{
12884 float_T f = 0.0;
12885
12886 rettv->v_type = VAR_FLOAT;
12887 if (get_float_arg(argvars, &f) == OK)
12888 /* trunc() is not in C90, use floor() or ceil() instead. */
12889 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12890 else
12891 rettv->vval.v_float = 0.0;
12892}
12893#endif
12894
12895/*
12896 * "type(expr)" function
12897 */
12898 static void
12899f_type(typval_T *argvars, typval_T *rettv)
12900{
12901 int n = -1;
12902
12903 switch (argvars[0].v_type)
12904 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012905 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12906 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012907 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012908 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12909 case VAR_LIST: n = VAR_TYPE_LIST; break;
12910 case VAR_DICT: n = VAR_TYPE_DICT; break;
12911 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012912 case VAR_SPECIAL:
12913 if (argvars[0].vval.v_number == VVAL_FALSE
12914 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012915 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012916 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012917 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012918 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012919 case VAR_JOB: n = VAR_TYPE_JOB; break;
12920 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012921 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012922 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012923 n = -1;
12924 break;
12925 }
12926 rettv->vval.v_number = n;
12927}
12928
12929/*
12930 * "undofile(name)" function
12931 */
12932 static void
12933f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12934{
12935 rettv->v_type = VAR_STRING;
12936#ifdef FEAT_PERSISTENT_UNDO
12937 {
12938 char_u *fname = get_tv_string(&argvars[0]);
12939
12940 if (*fname == NUL)
12941 {
12942 /* If there is no file name there will be no undo file. */
12943 rettv->vval.v_string = NULL;
12944 }
12945 else
12946 {
12947 char_u *ffname = FullName_save(fname, FALSE);
12948
12949 if (ffname != NULL)
12950 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12951 vim_free(ffname);
12952 }
12953 }
12954#else
12955 rettv->vval.v_string = NULL;
12956#endif
12957}
12958
12959/*
12960 * "undotree()" function
12961 */
12962 static void
12963f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12964{
12965 if (rettv_dict_alloc(rettv) == OK)
12966 {
12967 dict_T *dict = rettv->vval.v_dict;
12968 list_T *list;
12969
12970 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
12971 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
12972 dict_add_nr_str(dict, "save_last",
12973 (long)curbuf->b_u_save_nr_last, NULL);
12974 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
12975 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
12976 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
12977
12978 list = list_alloc();
12979 if (list != NULL)
12980 {
12981 u_eval_tree(curbuf->b_u_oldhead, list);
12982 dict_add_list(dict, "entries", list);
12983 }
12984 }
12985}
12986
12987/*
12988 * "values(dict)" function
12989 */
12990 static void
12991f_values(typval_T *argvars, typval_T *rettv)
12992{
12993 dict_list(argvars, rettv, 1);
12994}
12995
12996/*
12997 * "virtcol(string)" function
12998 */
12999 static void
13000f_virtcol(typval_T *argvars, typval_T *rettv)
13001{
13002 colnr_T vcol = 0;
13003 pos_T *fp;
13004 int fnum = curbuf->b_fnum;
13005
13006 fp = var2fpos(&argvars[0], FALSE, &fnum);
13007 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13008 && fnum == curbuf->b_fnum)
13009 {
13010 getvvcol(curwin, fp, NULL, NULL, &vcol);
13011 ++vcol;
13012 }
13013
13014 rettv->vval.v_number = vcol;
13015}
13016
13017/*
13018 * "visualmode()" function
13019 */
13020 static void
13021f_visualmode(typval_T *argvars, typval_T *rettv)
13022{
13023 char_u str[2];
13024
13025 rettv->v_type = VAR_STRING;
13026 str[0] = curbuf->b_visual_mode_eval;
13027 str[1] = NUL;
13028 rettv->vval.v_string = vim_strsave(str);
13029
13030 /* A non-zero number or non-empty string argument: reset mode. */
13031 if (non_zero_arg(&argvars[0]))
13032 curbuf->b_visual_mode_eval = NUL;
13033}
13034
13035/*
13036 * "wildmenumode()" function
13037 */
13038 static void
13039f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13040{
13041#ifdef FEAT_WILDMENU
13042 if (wild_menu_showing)
13043 rettv->vval.v_number = 1;
13044#endif
13045}
13046
13047/*
13048 * "winbufnr(nr)" function
13049 */
13050 static void
13051f_winbufnr(typval_T *argvars, typval_T *rettv)
13052{
13053 win_T *wp;
13054
13055 wp = find_win_by_nr(&argvars[0], NULL);
13056 if (wp == NULL)
13057 rettv->vval.v_number = -1;
13058 else
13059 rettv->vval.v_number = wp->w_buffer->b_fnum;
13060}
13061
13062/*
13063 * "wincol()" function
13064 */
13065 static void
13066f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13067{
13068 validate_cursor();
13069 rettv->vval.v_number = curwin->w_wcol + 1;
13070}
13071
13072/*
13073 * "winheight(nr)" function
13074 */
13075 static void
13076f_winheight(typval_T *argvars, typval_T *rettv)
13077{
13078 win_T *wp;
13079
13080 wp = find_win_by_nr(&argvars[0], NULL);
13081 if (wp == NULL)
13082 rettv->vval.v_number = -1;
13083 else
13084 rettv->vval.v_number = wp->w_height;
13085}
13086
13087/*
13088 * "winline()" function
13089 */
13090 static void
13091f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13092{
13093 validate_cursor();
13094 rettv->vval.v_number = curwin->w_wrow + 1;
13095}
13096
13097/*
13098 * "winnr()" function
13099 */
13100 static void
13101f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13102{
13103 int nr = 1;
13104
13105#ifdef FEAT_WINDOWS
13106 nr = get_winnr(curtab, &argvars[0]);
13107#endif
13108 rettv->vval.v_number = nr;
13109}
13110
13111/*
13112 * "winrestcmd()" function
13113 */
13114 static void
13115f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13116{
13117#ifdef FEAT_WINDOWS
13118 win_T *wp;
13119 int winnr = 1;
13120 garray_T ga;
13121 char_u buf[50];
13122
13123 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013124 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013125 {
13126 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13127 ga_concat(&ga, buf);
13128 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13129 ga_concat(&ga, buf);
13130 ++winnr;
13131 }
13132 ga_append(&ga, NUL);
13133
13134 rettv->vval.v_string = ga.ga_data;
13135#else
13136 rettv->vval.v_string = NULL;
13137#endif
13138 rettv->v_type = VAR_STRING;
13139}
13140
13141/*
13142 * "winrestview()" function
13143 */
13144 static void
13145f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13146{
13147 dict_T *dict;
13148
13149 if (argvars[0].v_type != VAR_DICT
13150 || (dict = argvars[0].vval.v_dict) == NULL)
13151 EMSG(_(e_invarg));
13152 else
13153 {
13154 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13155 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13156 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13157 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13158#ifdef FEAT_VIRTUALEDIT
13159 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13160 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13161#endif
13162 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13163 {
13164 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13165 curwin->w_set_curswant = FALSE;
13166 }
13167
13168 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13169 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13170#ifdef FEAT_DIFF
13171 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13172 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13173#endif
13174 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13175 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13176 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13177 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13178
13179 check_cursor();
13180 win_new_height(curwin, curwin->w_height);
13181# ifdef FEAT_WINDOWS
13182 win_new_width(curwin, W_WIDTH(curwin));
13183# endif
13184 changed_window_setting();
13185
13186 if (curwin->w_topline <= 0)
13187 curwin->w_topline = 1;
13188 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13189 curwin->w_topline = curbuf->b_ml.ml_line_count;
13190#ifdef FEAT_DIFF
13191 check_topfill(curwin, TRUE);
13192#endif
13193 }
13194}
13195
13196/*
13197 * "winsaveview()" function
13198 */
13199 static void
13200f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13201{
13202 dict_T *dict;
13203
13204 if (rettv_dict_alloc(rettv) == FAIL)
13205 return;
13206 dict = rettv->vval.v_dict;
13207
13208 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13209 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13210#ifdef FEAT_VIRTUALEDIT
13211 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13212#endif
13213 update_curswant();
13214 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13215
13216 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13217#ifdef FEAT_DIFF
13218 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13219#endif
13220 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13221 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13222}
13223
13224/*
13225 * "winwidth(nr)" function
13226 */
13227 static void
13228f_winwidth(typval_T *argvars, typval_T *rettv)
13229{
13230 win_T *wp;
13231
13232 wp = find_win_by_nr(&argvars[0], NULL);
13233 if (wp == NULL)
13234 rettv->vval.v_number = -1;
13235 else
13236#ifdef FEAT_WINDOWS
13237 rettv->vval.v_number = wp->w_width;
13238#else
13239 rettv->vval.v_number = Columns;
13240#endif
13241}
13242
13243/*
13244 * "wordcount()" function
13245 */
13246 static void
13247f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13248{
13249 if (rettv_dict_alloc(rettv) == FAIL)
13250 return;
13251 cursor_pos_info(rettv->vval.v_dict);
13252}
13253
13254/*
13255 * "writefile()" function
13256 */
13257 static void
13258f_writefile(typval_T *argvars, typval_T *rettv)
13259{
13260 int binary = FALSE;
13261 int append = FALSE;
13262 char_u *fname;
13263 FILE *fd;
13264 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013265 listitem_T *li;
13266 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013267
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013268 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013269 if (check_restricted() || check_secure())
13270 return;
13271
13272 if (argvars[0].v_type != VAR_LIST)
13273 {
13274 EMSG2(_(e_listarg), "writefile()");
13275 return;
13276 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013277 list = argvars[0].vval.v_list;
13278 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013279 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013280 for (li = list->lv_first; li != NULL; li = li->li_next)
13281 if (get_tv_string_chk(&li->li_tv) == NULL)
13282 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013283
13284 if (argvars[2].v_type != VAR_UNKNOWN)
13285 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013286 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13287
13288 if (arg2 == NULL)
13289 return;
13290 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013291 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013292 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013293 append = TRUE;
13294 }
13295
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013296 fname = get_tv_string_chk(&argvars[1]);
13297 if (fname == NULL)
13298 return;
13299
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013300 /* Always open the file in binary mode, library functions have a mind of
13301 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013302 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13303 append ? APPENDBIN : WRITEBIN)) == NULL)
13304 {
13305 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13306 ret = -1;
13307 }
13308 else
13309 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013310 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013311 ret = -1;
13312 fclose(fd);
13313 }
13314
13315 rettv->vval.v_number = ret;
13316}
13317
13318/*
13319 * "xor(expr, expr)" function
13320 */
13321 static void
13322f_xor(typval_T *argvars, typval_T *rettv)
13323{
13324 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13325 ^ get_tv_number_chk(&argvars[1], NULL);
13326}
13327
13328
13329#endif /* FEAT_EVAL */