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