blob: 77a4fc2c05e82ae0bd3e142cbbf8ddf410866f21 [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
Bram Moolenaard0573012017-10-28 21:11:06 +020027#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028# 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);
Bram Moolenaar246fe032017-11-19 19:56:27 +010064static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010065#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_browse(typval_T *argvars, typval_T *rettv);
67static void f_browsedir(typval_T *argvars, typval_T *rettv);
68static void f_bufexists(typval_T *argvars, typval_T *rettv);
69static void f_buflisted(typval_T *argvars, typval_T *rettv);
70static void f_bufloaded(typval_T *argvars, typval_T *rettv);
71static void f_bufname(typval_T *argvars, typval_T *rettv);
72static void f_bufnr(typval_T *argvars, typval_T *rettv);
73static void f_bufwinid(typval_T *argvars, typval_T *rettv);
74static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
75static void f_byte2line(typval_T *argvars, typval_T *rettv);
76static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
77static void f_byteidx(typval_T *argvars, typval_T *rettv);
78static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
79static void f_call(typval_T *argvars, typval_T *rettv);
80#ifdef FEAT_FLOAT
81static void f_ceil(typval_T *argvars, typval_T *rettv);
82#endif
83#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010084static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020086static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020087static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
88static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
89static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
90static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
91static void f_ch_info(typval_T *argvars, typval_T *rettv);
92static void f_ch_log(typval_T *argvars, typval_T *rettv);
93static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
94static void f_ch_open(typval_T *argvars, typval_T *rettv);
95static void f_ch_read(typval_T *argvars, typval_T *rettv);
96static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
97static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
98static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
99static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
100static void f_ch_status(typval_T *argvars, typval_T *rettv);
101#endif
102static void f_changenr(typval_T *argvars, typval_T *rettv);
103static void f_char2nr(typval_T *argvars, typval_T *rettv);
104static void f_cindent(typval_T *argvars, typval_T *rettv);
105static void f_clearmatches(typval_T *argvars, typval_T *rettv);
106static void f_col(typval_T *argvars, typval_T *rettv);
107#if defined(FEAT_INS_EXPAND)
108static void f_complete(typval_T *argvars, typval_T *rettv);
109static void f_complete_add(typval_T *argvars, typval_T *rettv);
110static void f_complete_check(typval_T *argvars, typval_T *rettv);
111#endif
112static void f_confirm(typval_T *argvars, typval_T *rettv);
113static void f_copy(typval_T *argvars, typval_T *rettv);
114#ifdef FEAT_FLOAT
115static void f_cos(typval_T *argvars, typval_T *rettv);
116static void f_cosh(typval_T *argvars, typval_T *rettv);
117#endif
118static void f_count(typval_T *argvars, typval_T *rettv);
119static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
120static void f_cursor(typval_T *argsvars, typval_T *rettv);
121static void f_deepcopy(typval_T *argvars, typval_T *rettv);
122static void f_delete(typval_T *argvars, typval_T *rettv);
123static void f_did_filetype(typval_T *argvars, typval_T *rettv);
124static void f_diff_filler(typval_T *argvars, typval_T *rettv);
125static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
126static void f_empty(typval_T *argvars, typval_T *rettv);
127static void f_escape(typval_T *argvars, typval_T *rettv);
128static void f_eval(typval_T *argvars, typval_T *rettv);
129static void f_eventhandler(typval_T *argvars, typval_T *rettv);
130static void f_executable(typval_T *argvars, typval_T *rettv);
131static void f_execute(typval_T *argvars, typval_T *rettv);
132static void f_exepath(typval_T *argvars, typval_T *rettv);
133static void f_exists(typval_T *argvars, typval_T *rettv);
134#ifdef FEAT_FLOAT
135static void f_exp(typval_T *argvars, typval_T *rettv);
136#endif
137static void f_expand(typval_T *argvars, typval_T *rettv);
138static void f_extend(typval_T *argvars, typval_T *rettv);
139static void f_feedkeys(typval_T *argvars, typval_T *rettv);
140static void f_filereadable(typval_T *argvars, typval_T *rettv);
141static void f_filewritable(typval_T *argvars, typval_T *rettv);
142static void f_filter(typval_T *argvars, typval_T *rettv);
143static void f_finddir(typval_T *argvars, typval_T *rettv);
144static void f_findfile(typval_T *argvars, typval_T *rettv);
145#ifdef FEAT_FLOAT
146static void f_float2nr(typval_T *argvars, typval_T *rettv);
147static void f_floor(typval_T *argvars, typval_T *rettv);
148static void f_fmod(typval_T *argvars, typval_T *rettv);
149#endif
150static void f_fnameescape(typval_T *argvars, typval_T *rettv);
151static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
152static void f_foldclosed(typval_T *argvars, typval_T *rettv);
153static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
154static void f_foldlevel(typval_T *argvars, typval_T *rettv);
155static void f_foldtext(typval_T *argvars, typval_T *rettv);
156static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
157static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200158static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200159static void f_function(typval_T *argvars, typval_T *rettv);
160static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
161static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200162static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200163static void f_getbufline(typval_T *argvars, typval_T *rettv);
164static void f_getbufvar(typval_T *argvars, typval_T *rettv);
165static void f_getchar(typval_T *argvars, typval_T *rettv);
166static void f_getcharmod(typval_T *argvars, typval_T *rettv);
167static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
168static void f_getcmdline(typval_T *argvars, typval_T *rettv);
169#if defined(FEAT_CMDL_COMPL)
170static void f_getcompletion(typval_T *argvars, typval_T *rettv);
171#endif
172static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
173static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
174static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
175static void f_getcwd(typval_T *argvars, typval_T *rettv);
176static void f_getfontname(typval_T *argvars, typval_T *rettv);
177static void f_getfperm(typval_T *argvars, typval_T *rettv);
178static void f_getfsize(typval_T *argvars, typval_T *rettv);
179static void f_getftime(typval_T *argvars, typval_T *rettv);
180static void f_getftype(typval_T *argvars, typval_T *rettv);
181static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200182static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200183static void f_getmatches(typval_T *argvars, typval_T *rettv);
184static void f_getpid(typval_T *argvars, typval_T *rettv);
185static void f_getcurpos(typval_T *argvars, typval_T *rettv);
186static void f_getpos(typval_T *argvars, typval_T *rettv);
187static void f_getqflist(typval_T *argvars, typval_T *rettv);
188static void f_getreg(typval_T *argvars, typval_T *rettv);
189static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200190static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_gettabvar(typval_T *argvars, typval_T *rettv);
192static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200193static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getwinposx(typval_T *argvars, typval_T *rettv);
195static void f_getwinposy(typval_T *argvars, typval_T *rettv);
196static void f_getwinvar(typval_T *argvars, typval_T *rettv);
197static void f_glob(typval_T *argvars, typval_T *rettv);
198static void f_globpath(typval_T *argvars, typval_T *rettv);
199static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
200static void f_has(typval_T *argvars, typval_T *rettv);
201static void f_has_key(typval_T *argvars, typval_T *rettv);
202static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
203static void f_hasmapto(typval_T *argvars, typval_T *rettv);
204static void f_histadd(typval_T *argvars, typval_T *rettv);
205static void f_histdel(typval_T *argvars, typval_T *rettv);
206static void f_histget(typval_T *argvars, typval_T *rettv);
207static void f_histnr(typval_T *argvars, typval_T *rettv);
208static void f_hlID(typval_T *argvars, typval_T *rettv);
209static void f_hlexists(typval_T *argvars, typval_T *rettv);
210static void f_hostname(typval_T *argvars, typval_T *rettv);
211static void f_iconv(typval_T *argvars, typval_T *rettv);
212static void f_indent(typval_T *argvars, typval_T *rettv);
213static void f_index(typval_T *argvars, typval_T *rettv);
214static void f_input(typval_T *argvars, typval_T *rettv);
215static void f_inputdialog(typval_T *argvars, typval_T *rettv);
216static void f_inputlist(typval_T *argvars, typval_T *rettv);
217static void f_inputrestore(typval_T *argvars, typval_T *rettv);
218static void f_inputsave(typval_T *argvars, typval_T *rettv);
219static void f_inputsecret(typval_T *argvars, typval_T *rettv);
220static void f_insert(typval_T *argvars, typval_T *rettv);
221static void f_invert(typval_T *argvars, typval_T *rettv);
222static void f_isdirectory(typval_T *argvars, typval_T *rettv);
223static void f_islocked(typval_T *argvars, typval_T *rettv);
224#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
225static void f_isnan(typval_T *argvars, typval_T *rettv);
226#endif
227static void f_items(typval_T *argvars, typval_T *rettv);
228#ifdef FEAT_JOB_CHANNEL
229static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
230static void f_job_info(typval_T *argvars, typval_T *rettv);
231static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
232static void f_job_start(typval_T *argvars, typval_T *rettv);
233static void f_job_stop(typval_T *argvars, typval_T *rettv);
234static void f_job_status(typval_T *argvars, typval_T *rettv);
235#endif
236static void f_join(typval_T *argvars, typval_T *rettv);
237static void f_js_decode(typval_T *argvars, typval_T *rettv);
238static void f_js_encode(typval_T *argvars, typval_T *rettv);
239static void f_json_decode(typval_T *argvars, typval_T *rettv);
240static void f_json_encode(typval_T *argvars, typval_T *rettv);
241static void f_keys(typval_T *argvars, typval_T *rettv);
242static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
243static void f_len(typval_T *argvars, typval_T *rettv);
244static void f_libcall(typval_T *argvars, typval_T *rettv);
245static void f_libcallnr(typval_T *argvars, typval_T *rettv);
246static void f_line(typval_T *argvars, typval_T *rettv);
247static void f_line2byte(typval_T *argvars, typval_T *rettv);
248static void f_lispindent(typval_T *argvars, typval_T *rettv);
249static void f_localtime(typval_T *argvars, typval_T *rettv);
250#ifdef FEAT_FLOAT
251static void f_log(typval_T *argvars, typval_T *rettv);
252static void f_log10(typval_T *argvars, typval_T *rettv);
253#endif
254#ifdef FEAT_LUA
255static void f_luaeval(typval_T *argvars, typval_T *rettv);
256#endif
257static void f_map(typval_T *argvars, typval_T *rettv);
258static void f_maparg(typval_T *argvars, typval_T *rettv);
259static void f_mapcheck(typval_T *argvars, typval_T *rettv);
260static void f_match(typval_T *argvars, typval_T *rettv);
261static void f_matchadd(typval_T *argvars, typval_T *rettv);
262static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
263static void f_matcharg(typval_T *argvars, typval_T *rettv);
264static void f_matchdelete(typval_T *argvars, typval_T *rettv);
265static void f_matchend(typval_T *argvars, typval_T *rettv);
266static void f_matchlist(typval_T *argvars, typval_T *rettv);
267static void f_matchstr(typval_T *argvars, typval_T *rettv);
268static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
269static void f_max(typval_T *argvars, typval_T *rettv);
270static void f_min(typval_T *argvars, typval_T *rettv);
271#ifdef vim_mkdir
272static void f_mkdir(typval_T *argvars, typval_T *rettv);
273#endif
274static void f_mode(typval_T *argvars, typval_T *rettv);
275#ifdef FEAT_MZSCHEME
276static void f_mzeval(typval_T *argvars, typval_T *rettv);
277#endif
278static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
279static void f_nr2char(typval_T *argvars, typval_T *rettv);
280static void f_or(typval_T *argvars, typval_T *rettv);
281static void f_pathshorten(typval_T *argvars, typval_T *rettv);
282#ifdef FEAT_PERL
283static void f_perleval(typval_T *argvars, typval_T *rettv);
284#endif
285#ifdef FEAT_FLOAT
286static void f_pow(typval_T *argvars, typval_T *rettv);
287#endif
288static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
289static void f_printf(typval_T *argvars, typval_T *rettv);
290static void f_pumvisible(typval_T *argvars, typval_T *rettv);
291#ifdef FEAT_PYTHON3
292static void f_py3eval(typval_T *argvars, typval_T *rettv);
293#endif
294#ifdef FEAT_PYTHON
295static void f_pyeval(typval_T *argvars, typval_T *rettv);
296#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100297#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
298static void f_pyxeval(typval_T *argvars, typval_T *rettv);
299#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200300static void f_range(typval_T *argvars, typval_T *rettv);
301static void f_readfile(typval_T *argvars, typval_T *rettv);
302static void f_reltime(typval_T *argvars, typval_T *rettv);
303#ifdef FEAT_FLOAT
304static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
305#endif
306static void f_reltimestr(typval_T *argvars, typval_T *rettv);
307static void f_remote_expr(typval_T *argvars, typval_T *rettv);
308static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
309static void f_remote_peek(typval_T *argvars, typval_T *rettv);
310static void f_remote_read(typval_T *argvars, typval_T *rettv);
311static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100312static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200313static void f_remove(typval_T *argvars, typval_T *rettv);
314static void f_rename(typval_T *argvars, typval_T *rettv);
315static void f_repeat(typval_T *argvars, typval_T *rettv);
316static void f_resolve(typval_T *argvars, typval_T *rettv);
317static void f_reverse(typval_T *argvars, typval_T *rettv);
318#ifdef FEAT_FLOAT
319static void f_round(typval_T *argvars, typval_T *rettv);
320#endif
321static void f_screenattr(typval_T *argvars, typval_T *rettv);
322static void f_screenchar(typval_T *argvars, typval_T *rettv);
323static void f_screencol(typval_T *argvars, typval_T *rettv);
324static void f_screenrow(typval_T *argvars, typval_T *rettv);
325static void f_search(typval_T *argvars, typval_T *rettv);
326static void f_searchdecl(typval_T *argvars, typval_T *rettv);
327static void f_searchpair(typval_T *argvars, typval_T *rettv);
328static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
329static void f_searchpos(typval_T *argvars, typval_T *rettv);
330static void f_server2client(typval_T *argvars, typval_T *rettv);
331static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200332static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200333static void f_setbufvar(typval_T *argvars, typval_T *rettv);
334static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
335static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
336static void f_setfperm(typval_T *argvars, typval_T *rettv);
337static void f_setline(typval_T *argvars, typval_T *rettv);
338static void f_setloclist(typval_T *argvars, typval_T *rettv);
339static void f_setmatches(typval_T *argvars, typval_T *rettv);
340static void f_setpos(typval_T *argvars, typval_T *rettv);
341static void f_setqflist(typval_T *argvars, typval_T *rettv);
342static void f_setreg(typval_T *argvars, typval_T *rettv);
343static void f_settabvar(typval_T *argvars, typval_T *rettv);
344static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
345static void f_setwinvar(typval_T *argvars, typval_T *rettv);
346#ifdef FEAT_CRYPT
347static void f_sha256(typval_T *argvars, typval_T *rettv);
348#endif /* FEAT_CRYPT */
349static void f_shellescape(typval_T *argvars, typval_T *rettv);
350static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
351static void f_simplify(typval_T *argvars, typval_T *rettv);
352#ifdef FEAT_FLOAT
353static void f_sin(typval_T *argvars, typval_T *rettv);
354static void f_sinh(typval_T *argvars, typval_T *rettv);
355#endif
356static void f_sort(typval_T *argvars, typval_T *rettv);
357static void f_soundfold(typval_T *argvars, typval_T *rettv);
358static void f_spellbadword(typval_T *argvars, typval_T *rettv);
359static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
360static void f_split(typval_T *argvars, typval_T *rettv);
361#ifdef FEAT_FLOAT
362static void f_sqrt(typval_T *argvars, typval_T *rettv);
363static void f_str2float(typval_T *argvars, typval_T *rettv);
364#endif
365static void f_str2nr(typval_T *argvars, typval_T *rettv);
366static void f_strchars(typval_T *argvars, typval_T *rettv);
367#ifdef HAVE_STRFTIME
368static void f_strftime(typval_T *argvars, typval_T *rettv);
369#endif
370static void f_strgetchar(typval_T *argvars, typval_T *rettv);
371static void f_stridx(typval_T *argvars, typval_T *rettv);
372static void f_string(typval_T *argvars, typval_T *rettv);
373static void f_strlen(typval_T *argvars, typval_T *rettv);
374static void f_strcharpart(typval_T *argvars, typval_T *rettv);
375static void f_strpart(typval_T *argvars, typval_T *rettv);
376static void f_strridx(typval_T *argvars, typval_T *rettv);
377static void f_strtrans(typval_T *argvars, typval_T *rettv);
378static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
379static void f_strwidth(typval_T *argvars, typval_T *rettv);
380static void f_submatch(typval_T *argvars, typval_T *rettv);
381static void f_substitute(typval_T *argvars, typval_T *rettv);
382static void f_synID(typval_T *argvars, typval_T *rettv);
383static void f_synIDattr(typval_T *argvars, typval_T *rettv);
384static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
385static void f_synstack(typval_T *argvars, typval_T *rettv);
386static void f_synconcealed(typval_T *argvars, typval_T *rettv);
387static void f_system(typval_T *argvars, typval_T *rettv);
388static void f_systemlist(typval_T *argvars, typval_T *rettv);
389static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
390static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
391static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
392static void f_taglist(typval_T *argvars, typval_T *rettv);
393static void f_tagfiles(typval_T *argvars, typval_T *rettv);
394static void f_tempname(typval_T *argvars, typval_T *rettv);
395static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
396static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200397static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100398static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200399static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100400static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401#ifdef FEAT_JOB_CHANNEL
402static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
403#endif
404static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
405#ifdef FEAT_JOB_CHANNEL
406static void f_test_null_job(typval_T *argvars, typval_T *rettv);
407#endif
408static void f_test_null_list(typval_T *argvars, typval_T *rettv);
409static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
410static void f_test_null_string(typval_T *argvars, typval_T *rettv);
411static void f_test_settime(typval_T *argvars, typval_T *rettv);
412#ifdef FEAT_FLOAT
413static void f_tan(typval_T *argvars, typval_T *rettv);
414static void f_tanh(typval_T *argvars, typval_T *rettv);
415#endif
416#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200417static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200418static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419static void f_timer_start(typval_T *argvars, typval_T *rettv);
420static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200421static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200422#endif
423static void f_tolower(typval_T *argvars, typval_T *rettv);
424static void f_toupper(typval_T *argvars, typval_T *rettv);
425static void f_tr(typval_T *argvars, typval_T *rettv);
426#ifdef FEAT_FLOAT
427static void f_trunc(typval_T *argvars, typval_T *rettv);
428#endif
429static void f_type(typval_T *argvars, typval_T *rettv);
430static void f_undofile(typval_T *argvars, typval_T *rettv);
431static void f_undotree(typval_T *argvars, typval_T *rettv);
432static void f_uniq(typval_T *argvars, typval_T *rettv);
433static void f_values(typval_T *argvars, typval_T *rettv);
434static void f_virtcol(typval_T *argvars, typval_T *rettv);
435static void f_visualmode(typval_T *argvars, typval_T *rettv);
436static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
437static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
438static void f_win_getid(typval_T *argvars, typval_T *rettv);
439static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
440static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
441static void f_win_id2win(typval_T *argvars, typval_T *rettv);
442static void f_winbufnr(typval_T *argvars, typval_T *rettv);
443static void f_wincol(typval_T *argvars, typval_T *rettv);
444static void f_winheight(typval_T *argvars, typval_T *rettv);
445static void f_winline(typval_T *argvars, typval_T *rettv);
446static void f_winnr(typval_T *argvars, typval_T *rettv);
447static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
448static void f_winrestview(typval_T *argvars, typval_T *rettv);
449static void f_winsaveview(typval_T *argvars, typval_T *rettv);
450static void f_winwidth(typval_T *argvars, typval_T *rettv);
451static void f_writefile(typval_T *argvars, typval_T *rettv);
452static void f_wordcount(typval_T *argvars, typval_T *rettv);
453static void f_xor(typval_T *argvars, typval_T *rettv);
454
455/*
456 * Array with names and number of arguments of all internal functions
457 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
458 */
459static struct fst
460{
461 char *f_name; /* function name */
462 char f_min_argc; /* minimal number of arguments */
463 char f_max_argc; /* maximal number of arguments */
464 void (*f_func)(typval_T *args, typval_T *rvar);
465 /* implementation of function */
466} functions[] =
467{
468#ifdef FEAT_FLOAT
469 {"abs", 1, 1, f_abs},
470 {"acos", 1, 1, f_acos}, /* WJMc */
471#endif
472 {"add", 2, 2, f_add},
473 {"and", 2, 2, f_and},
474 {"append", 2, 2, f_append},
475 {"argc", 0, 0, f_argc},
476 {"argidx", 0, 0, f_argidx},
477 {"arglistid", 0, 2, f_arglistid},
478 {"argv", 0, 1, f_argv},
479#ifdef FEAT_FLOAT
480 {"asin", 1, 1, f_asin}, /* WJMc */
481#endif
482 {"assert_equal", 2, 3, f_assert_equal},
483 {"assert_exception", 1, 2, f_assert_exception},
484 {"assert_fails", 1, 2, f_assert_fails},
485 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100486 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200487 {"assert_match", 2, 3, f_assert_match},
488 {"assert_notequal", 2, 3, f_assert_notequal},
489 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100490 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200491 {"assert_true", 1, 2, f_assert_true},
492#ifdef FEAT_FLOAT
493 {"atan", 1, 1, f_atan},
494 {"atan2", 2, 2, f_atan2},
495#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100496#ifdef FEAT_BEVAL
497 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar246fe032017-11-19 19:56:27 +0100498 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar59716a22017-03-01 20:32:44 +0100499#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200500 {"browse", 4, 4, f_browse},
501 {"browsedir", 2, 2, f_browsedir},
502 {"bufexists", 1, 1, f_bufexists},
503 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
504 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
505 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
506 {"buflisted", 1, 1, f_buflisted},
507 {"bufloaded", 1, 1, f_bufloaded},
508 {"bufname", 1, 1, f_bufname},
509 {"bufnr", 1, 2, f_bufnr},
510 {"bufwinid", 1, 1, f_bufwinid},
511 {"bufwinnr", 1, 1, f_bufwinnr},
512 {"byte2line", 1, 1, f_byte2line},
513 {"byteidx", 2, 2, f_byteidx},
514 {"byteidxcomp", 2, 2, f_byteidxcomp},
515 {"call", 2, 3, f_call},
516#ifdef FEAT_FLOAT
517 {"ceil", 1, 1, f_ceil},
518#endif
519#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100520 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200521 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200522 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200523 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
524 {"ch_evalraw", 2, 3, f_ch_evalraw},
525 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
526 {"ch_getjob", 1, 1, f_ch_getjob},
527 {"ch_info", 1, 1, f_ch_info},
528 {"ch_log", 1, 2, f_ch_log},
529 {"ch_logfile", 1, 2, f_ch_logfile},
530 {"ch_open", 1, 2, f_ch_open},
531 {"ch_read", 1, 2, f_ch_read},
532 {"ch_readraw", 1, 2, f_ch_readraw},
533 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
534 {"ch_sendraw", 2, 3, f_ch_sendraw},
535 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200536 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537#endif
538 {"changenr", 0, 0, f_changenr},
539 {"char2nr", 1, 2, f_char2nr},
540 {"cindent", 1, 1, f_cindent},
541 {"clearmatches", 0, 0, f_clearmatches},
542 {"col", 1, 1, f_col},
543#if defined(FEAT_INS_EXPAND)
544 {"complete", 2, 2, f_complete},
545 {"complete_add", 1, 1, f_complete_add},
546 {"complete_check", 0, 0, f_complete_check},
547#endif
548 {"confirm", 1, 4, f_confirm},
549 {"copy", 1, 1, f_copy},
550#ifdef FEAT_FLOAT
551 {"cos", 1, 1, f_cos},
552 {"cosh", 1, 1, f_cosh},
553#endif
554 {"count", 2, 4, f_count},
555 {"cscope_connection",0,3, f_cscope_connection},
556 {"cursor", 1, 3, f_cursor},
557 {"deepcopy", 1, 2, f_deepcopy},
558 {"delete", 1, 2, f_delete},
559 {"did_filetype", 0, 0, f_did_filetype},
560 {"diff_filler", 1, 1, f_diff_filler},
561 {"diff_hlID", 2, 2, f_diff_hlID},
562 {"empty", 1, 1, f_empty},
563 {"escape", 2, 2, f_escape},
564 {"eval", 1, 1, f_eval},
565 {"eventhandler", 0, 0, f_eventhandler},
566 {"executable", 1, 1, f_executable},
567 {"execute", 1, 2, f_execute},
568 {"exepath", 1, 1, f_exepath},
569 {"exists", 1, 1, f_exists},
570#ifdef FEAT_FLOAT
571 {"exp", 1, 1, f_exp},
572#endif
573 {"expand", 1, 3, f_expand},
574 {"extend", 2, 3, f_extend},
575 {"feedkeys", 1, 2, f_feedkeys},
576 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
577 {"filereadable", 1, 1, f_filereadable},
578 {"filewritable", 1, 1, f_filewritable},
579 {"filter", 2, 2, f_filter},
580 {"finddir", 1, 3, f_finddir},
581 {"findfile", 1, 3, f_findfile},
582#ifdef FEAT_FLOAT
583 {"float2nr", 1, 1, f_float2nr},
584 {"floor", 1, 1, f_floor},
585 {"fmod", 2, 2, f_fmod},
586#endif
587 {"fnameescape", 1, 1, f_fnameescape},
588 {"fnamemodify", 2, 2, f_fnamemodify},
589 {"foldclosed", 1, 1, f_foldclosed},
590 {"foldclosedend", 1, 1, f_foldclosedend},
591 {"foldlevel", 1, 1, f_foldlevel},
592 {"foldtext", 0, 0, f_foldtext},
593 {"foldtextresult", 1, 1, f_foldtextresult},
594 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200595 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200596 {"function", 1, 3, f_function},
597 {"garbagecollect", 0, 1, f_garbagecollect},
598 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200599 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600 {"getbufline", 2, 3, f_getbufline},
601 {"getbufvar", 2, 3, f_getbufvar},
602 {"getchar", 0, 1, f_getchar},
603 {"getcharmod", 0, 0, f_getcharmod},
604 {"getcharsearch", 0, 0, f_getcharsearch},
605 {"getcmdline", 0, 0, f_getcmdline},
606 {"getcmdpos", 0, 0, f_getcmdpos},
607 {"getcmdtype", 0, 0, f_getcmdtype},
608 {"getcmdwintype", 0, 0, f_getcmdwintype},
609#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200610 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200611#endif
612 {"getcurpos", 0, 0, f_getcurpos},
613 {"getcwd", 0, 2, f_getcwd},
614 {"getfontname", 0, 1, f_getfontname},
615 {"getfperm", 1, 1, f_getfperm},
616 {"getfsize", 1, 1, f_getfsize},
617 {"getftime", 1, 1, f_getftime},
618 {"getftype", 1, 1, f_getftype},
619 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200620 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200621 {"getmatches", 0, 0, f_getmatches},
622 {"getpid", 0, 0, f_getpid},
623 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200624 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625 {"getreg", 0, 3, f_getreg},
626 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200627 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200628 {"gettabvar", 2, 3, f_gettabvar},
629 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200630 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200631 {"getwinposx", 0, 0, f_getwinposx},
632 {"getwinposy", 0, 0, f_getwinposy},
633 {"getwinvar", 2, 3, f_getwinvar},
634 {"glob", 1, 4, f_glob},
635 {"glob2regpat", 1, 1, f_glob2regpat},
636 {"globpath", 2, 5, f_globpath},
637 {"has", 1, 1, f_has},
638 {"has_key", 2, 2, f_has_key},
639 {"haslocaldir", 0, 2, f_haslocaldir},
640 {"hasmapto", 1, 3, f_hasmapto},
641 {"highlightID", 1, 1, f_hlID}, /* obsolete */
642 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
643 {"histadd", 2, 2, f_histadd},
644 {"histdel", 1, 2, f_histdel},
645 {"histget", 1, 2, f_histget},
646 {"histnr", 1, 1, f_histnr},
647 {"hlID", 1, 1, f_hlID},
648 {"hlexists", 1, 1, f_hlexists},
649 {"hostname", 0, 0, f_hostname},
650 {"iconv", 3, 3, f_iconv},
651 {"indent", 1, 1, f_indent},
652 {"index", 2, 4, f_index},
653 {"input", 1, 3, f_input},
654 {"inputdialog", 1, 3, f_inputdialog},
655 {"inputlist", 1, 1, f_inputlist},
656 {"inputrestore", 0, 0, f_inputrestore},
657 {"inputsave", 0, 0, f_inputsave},
658 {"inputsecret", 1, 2, f_inputsecret},
659 {"insert", 2, 3, f_insert},
660 {"invert", 1, 1, f_invert},
661 {"isdirectory", 1, 1, f_isdirectory},
662 {"islocked", 1, 1, f_islocked},
663#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
664 {"isnan", 1, 1, f_isnan},
665#endif
666 {"items", 1, 1, f_items},
667#ifdef FEAT_JOB_CHANNEL
668 {"job_getchannel", 1, 1, f_job_getchannel},
669 {"job_info", 1, 1, f_job_info},
670 {"job_setoptions", 2, 2, f_job_setoptions},
671 {"job_start", 1, 2, f_job_start},
672 {"job_status", 1, 1, f_job_status},
673 {"job_stop", 1, 2, f_job_stop},
674#endif
675 {"join", 1, 2, f_join},
676 {"js_decode", 1, 1, f_js_decode},
677 {"js_encode", 1, 1, f_js_encode},
678 {"json_decode", 1, 1, f_json_decode},
679 {"json_encode", 1, 1, f_json_encode},
680 {"keys", 1, 1, f_keys},
681 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
682 {"len", 1, 1, f_len},
683 {"libcall", 3, 3, f_libcall},
684 {"libcallnr", 3, 3, f_libcallnr},
685 {"line", 1, 1, f_line},
686 {"line2byte", 1, 1, f_line2byte},
687 {"lispindent", 1, 1, f_lispindent},
688 {"localtime", 0, 0, f_localtime},
689#ifdef FEAT_FLOAT
690 {"log", 1, 1, f_log},
691 {"log10", 1, 1, f_log10},
692#endif
693#ifdef FEAT_LUA
694 {"luaeval", 1, 2, f_luaeval},
695#endif
696 {"map", 2, 2, f_map},
697 {"maparg", 1, 4, f_maparg},
698 {"mapcheck", 1, 3, f_mapcheck},
699 {"match", 2, 4, f_match},
700 {"matchadd", 2, 5, f_matchadd},
701 {"matchaddpos", 2, 5, f_matchaddpos},
702 {"matcharg", 1, 1, f_matcharg},
703 {"matchdelete", 1, 1, f_matchdelete},
704 {"matchend", 2, 4, f_matchend},
705 {"matchlist", 2, 4, f_matchlist},
706 {"matchstr", 2, 4, f_matchstr},
707 {"matchstrpos", 2, 4, f_matchstrpos},
708 {"max", 1, 1, f_max},
709 {"min", 1, 1, f_min},
710#ifdef vim_mkdir
711 {"mkdir", 1, 3, f_mkdir},
712#endif
713 {"mode", 0, 1, f_mode},
714#ifdef FEAT_MZSCHEME
715 {"mzeval", 1, 1, f_mzeval},
716#endif
717 {"nextnonblank", 1, 1, f_nextnonblank},
718 {"nr2char", 1, 2, f_nr2char},
719 {"or", 2, 2, f_or},
720 {"pathshorten", 1, 1, f_pathshorten},
721#ifdef FEAT_PERL
722 {"perleval", 1, 1, f_perleval},
723#endif
724#ifdef FEAT_FLOAT
725 {"pow", 2, 2, f_pow},
726#endif
727 {"prevnonblank", 1, 1, f_prevnonblank},
728 {"printf", 2, 19, f_printf},
729 {"pumvisible", 0, 0, f_pumvisible},
730#ifdef FEAT_PYTHON3
731 {"py3eval", 1, 1, f_py3eval},
732#endif
733#ifdef FEAT_PYTHON
734 {"pyeval", 1, 1, f_pyeval},
735#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100736#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
737 {"pyxeval", 1, 1, f_pyxeval},
738#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200739 {"range", 1, 3, f_range},
740 {"readfile", 1, 3, f_readfile},
741 {"reltime", 0, 2, f_reltime},
742#ifdef FEAT_FLOAT
743 {"reltimefloat", 1, 1, f_reltimefloat},
744#endif
745 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100746 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747 {"remote_foreground", 1, 1, f_remote_foreground},
748 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100749 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200750 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100751 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200752 {"remove", 2, 3, f_remove},
753 {"rename", 2, 2, f_rename},
754 {"repeat", 2, 2, f_repeat},
755 {"resolve", 1, 1, f_resolve},
756 {"reverse", 1, 1, f_reverse},
757#ifdef FEAT_FLOAT
758 {"round", 1, 1, f_round},
759#endif
760 {"screenattr", 2, 2, f_screenattr},
761 {"screenchar", 2, 2, f_screenchar},
762 {"screencol", 0, 0, f_screencol},
763 {"screenrow", 0, 0, f_screenrow},
764 {"search", 1, 4, f_search},
765 {"searchdecl", 1, 3, f_searchdecl},
766 {"searchpair", 3, 7, f_searchpair},
767 {"searchpairpos", 3, 7, f_searchpairpos},
768 {"searchpos", 1, 4, f_searchpos},
769 {"server2client", 2, 2, f_server2client},
770 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200771 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772 {"setbufvar", 3, 3, f_setbufvar},
773 {"setcharsearch", 1, 1, f_setcharsearch},
774 {"setcmdpos", 1, 1, f_setcmdpos},
775 {"setfperm", 2, 2, f_setfperm},
776 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200777 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778 {"setmatches", 1, 1, f_setmatches},
779 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200780 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200781 {"setreg", 2, 3, f_setreg},
782 {"settabvar", 3, 3, f_settabvar},
783 {"settabwinvar", 4, 4, f_settabwinvar},
784 {"setwinvar", 3, 3, f_setwinvar},
785#ifdef FEAT_CRYPT
786 {"sha256", 1, 1, f_sha256},
787#endif
788 {"shellescape", 1, 2, f_shellescape},
789 {"shiftwidth", 0, 0, f_shiftwidth},
790 {"simplify", 1, 1, f_simplify},
791#ifdef FEAT_FLOAT
792 {"sin", 1, 1, f_sin},
793 {"sinh", 1, 1, f_sinh},
794#endif
795 {"sort", 1, 3, f_sort},
796 {"soundfold", 1, 1, f_soundfold},
797 {"spellbadword", 0, 1, f_spellbadword},
798 {"spellsuggest", 1, 3, f_spellsuggest},
799 {"split", 1, 3, f_split},
800#ifdef FEAT_FLOAT
801 {"sqrt", 1, 1, f_sqrt},
802 {"str2float", 1, 1, f_str2float},
803#endif
804 {"str2nr", 1, 2, f_str2nr},
805 {"strcharpart", 2, 3, f_strcharpart},
806 {"strchars", 1, 2, f_strchars},
807 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
808#ifdef HAVE_STRFTIME
809 {"strftime", 1, 2, f_strftime},
810#endif
811 {"strgetchar", 2, 2, f_strgetchar},
812 {"stridx", 2, 3, f_stridx},
813 {"string", 1, 1, f_string},
814 {"strlen", 1, 1, f_strlen},
815 {"strpart", 2, 3, f_strpart},
816 {"strridx", 2, 3, f_strridx},
817 {"strtrans", 1, 1, f_strtrans},
818 {"strwidth", 1, 1, f_strwidth},
819 {"submatch", 1, 2, f_submatch},
820 {"substitute", 4, 4, f_substitute},
821 {"synID", 3, 3, f_synID},
822 {"synIDattr", 2, 3, f_synIDattr},
823 {"synIDtrans", 1, 1, f_synIDtrans},
824 {"synconcealed", 2, 2, f_synconcealed},
825 {"synstack", 2, 2, f_synstack},
826 {"system", 1, 2, f_system},
827 {"systemlist", 1, 2, f_systemlist},
828 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
829 {"tabpagenr", 0, 1, f_tabpagenr},
830 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
831 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100832 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200833#ifdef FEAT_FLOAT
834 {"tan", 1, 1, f_tan},
835 {"tanh", 1, 1, f_tanh},
836#endif
837 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200838#ifdef FEAT_TERMINAL
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200839 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200840 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200841 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200842 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200843 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200844 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200845 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200846 {"term_getstatus", 1, 1, f_term_getstatus},
847 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200848 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200849 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200850 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200851 {"term_sendkeys", 2, 2, f_term_sendkeys},
852 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200853 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200854#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200855 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
856 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200857 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200858 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100859 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200860#ifdef FEAT_JOB_CHANNEL
861 {"test_null_channel", 0, 0, f_test_null_channel},
862#endif
863 {"test_null_dict", 0, 0, f_test_null_dict},
864#ifdef FEAT_JOB_CHANNEL
865 {"test_null_job", 0, 0, f_test_null_job},
866#endif
867 {"test_null_list", 0, 0, f_test_null_list},
868 {"test_null_partial", 0, 0, f_test_null_partial},
869 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100870 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200871 {"test_settime", 1, 1, f_test_settime},
872#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200873 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200874 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200875 {"timer_start", 2, 3, f_timer_start},
876 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200877 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200878#endif
879 {"tolower", 1, 1, f_tolower},
880 {"toupper", 1, 1, f_toupper},
881 {"tr", 3, 3, f_tr},
882#ifdef FEAT_FLOAT
883 {"trunc", 1, 1, f_trunc},
884#endif
885 {"type", 1, 1, f_type},
886 {"undofile", 1, 1, f_undofile},
887 {"undotree", 0, 0, f_undotree},
888 {"uniq", 1, 3, f_uniq},
889 {"values", 1, 1, f_values},
890 {"virtcol", 1, 1, f_virtcol},
891 {"visualmode", 0, 1, f_visualmode},
892 {"wildmenumode", 0, 0, f_wildmenumode},
893 {"win_findbuf", 1, 1, f_win_findbuf},
894 {"win_getid", 0, 2, f_win_getid},
895 {"win_gotoid", 1, 1, f_win_gotoid},
896 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
897 {"win_id2win", 1, 1, f_win_id2win},
898 {"winbufnr", 1, 1, f_winbufnr},
899 {"wincol", 0, 0, f_wincol},
900 {"winheight", 1, 1, f_winheight},
901 {"winline", 0, 0, f_winline},
902 {"winnr", 0, 1, f_winnr},
903 {"winrestcmd", 0, 0, f_winrestcmd},
904 {"winrestview", 1, 1, f_winrestview},
905 {"winsaveview", 0, 0, f_winsaveview},
906 {"winwidth", 1, 1, f_winwidth},
907 {"wordcount", 0, 0, f_wordcount},
908 {"writefile", 2, 3, f_writefile},
909 {"xor", 2, 2, f_xor},
910};
911
912#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
913
914/*
915 * Function given to ExpandGeneric() to obtain the list of internal
916 * or user defined function names.
917 */
918 char_u *
919get_function_name(expand_T *xp, int idx)
920{
921 static int intidx = -1;
922 char_u *name;
923
924 if (idx == 0)
925 intidx = -1;
926 if (intidx < 0)
927 {
928 name = get_user_func_name(xp, idx);
929 if (name != NULL)
930 return name;
931 }
932 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
933 {
934 STRCPY(IObuff, functions[intidx].f_name);
935 STRCAT(IObuff, "(");
936 if (functions[intidx].f_max_argc == 0)
937 STRCAT(IObuff, ")");
938 return IObuff;
939 }
940
941 return NULL;
942}
943
944/*
945 * Function given to ExpandGeneric() to obtain the list of internal or
946 * user defined variable or function names.
947 */
948 char_u *
949get_expr_name(expand_T *xp, int idx)
950{
951 static int intidx = -1;
952 char_u *name;
953
954 if (idx == 0)
955 intidx = -1;
956 if (intidx < 0)
957 {
958 name = get_function_name(xp, idx);
959 if (name != NULL)
960 return name;
961 }
962 return get_user_var_name(xp, ++intidx);
963}
964
965#endif /* FEAT_CMDL_COMPL */
966
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200967/*
968 * Find internal function in table above.
969 * Return index, or -1 if not found
970 */
971 int
972find_internal_func(
973 char_u *name) /* name of the function */
974{
975 int first = 0;
976 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
977 int cmp;
978 int x;
979
980 /*
981 * Find the function name in the table. Binary search.
982 */
983 while (first <= last)
984 {
985 x = first + ((unsigned)(last - first) >> 1);
986 cmp = STRCMP(name, functions[x].f_name);
987 if (cmp < 0)
988 last = x - 1;
989 else if (cmp > 0)
990 first = x + 1;
991 else
992 return x;
993 }
994 return -1;
995}
996
997 int
998call_internal_func(
999 char_u *name,
1000 int argcount,
1001 typval_T *argvars,
1002 typval_T *rettv)
1003{
1004 int i;
1005
1006 i = find_internal_func(name);
1007 if (i < 0)
1008 return ERROR_UNKNOWN;
1009 if (argcount < functions[i].f_min_argc)
1010 return ERROR_TOOFEW;
1011 if (argcount > functions[i].f_max_argc)
1012 return ERROR_TOOMANY;
1013 argvars[argcount].v_type = VAR_UNKNOWN;
1014 functions[i].f_func(argvars, rettv);
1015 return ERROR_NONE;
1016}
1017
1018/*
1019 * Return TRUE for a non-zero Number and a non-empty String.
1020 */
1021 static int
1022non_zero_arg(typval_T *argvars)
1023{
1024 return ((argvars[0].v_type == VAR_NUMBER
1025 && argvars[0].vval.v_number != 0)
1026 || (argvars[0].v_type == VAR_SPECIAL
1027 && argvars[0].vval.v_number == VVAL_TRUE)
1028 || (argvars[0].v_type == VAR_STRING
1029 && argvars[0].vval.v_string != NULL
1030 && *argvars[0].vval.v_string != NUL));
1031}
1032
1033/*
1034 * Get the lnum from the first argument.
1035 * Also accepts ".", "$", etc., but that only works for the current buffer.
1036 * Returns -1 on error.
1037 */
1038 static linenr_T
1039get_tv_lnum(typval_T *argvars)
1040{
1041 typval_T rettv;
1042 linenr_T lnum;
1043
1044 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1045 if (lnum == 0) /* no valid number, try using line() */
1046 {
1047 rettv.v_type = VAR_NUMBER;
1048 f_line(argvars, &rettv);
1049 lnum = (linenr_T)rettv.vval.v_number;
1050 clear_tv(&rettv);
1051 }
1052 return lnum;
1053}
1054
1055#ifdef FEAT_FLOAT
1056static int get_float_arg(typval_T *argvars, float_T *f);
1057
1058/*
1059 * Get the float value of "argvars[0]" into "f".
1060 * Returns FAIL when the argument is not a Number or Float.
1061 */
1062 static int
1063get_float_arg(typval_T *argvars, float_T *f)
1064{
1065 if (argvars[0].v_type == VAR_FLOAT)
1066 {
1067 *f = argvars[0].vval.v_float;
1068 return OK;
1069 }
1070 if (argvars[0].v_type == VAR_NUMBER)
1071 {
1072 *f = (float_T)argvars[0].vval.v_number;
1073 return OK;
1074 }
1075 EMSG(_("E808: Number or Float required"));
1076 return FAIL;
1077}
1078
1079/*
1080 * "abs(expr)" function
1081 */
1082 static void
1083f_abs(typval_T *argvars, typval_T *rettv)
1084{
1085 if (argvars[0].v_type == VAR_FLOAT)
1086 {
1087 rettv->v_type = VAR_FLOAT;
1088 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1089 }
1090 else
1091 {
1092 varnumber_T n;
1093 int error = FALSE;
1094
1095 n = get_tv_number_chk(&argvars[0], &error);
1096 if (error)
1097 rettv->vval.v_number = -1;
1098 else if (n > 0)
1099 rettv->vval.v_number = n;
1100 else
1101 rettv->vval.v_number = -n;
1102 }
1103}
1104
1105/*
1106 * "acos()" function
1107 */
1108 static void
1109f_acos(typval_T *argvars, typval_T *rettv)
1110{
1111 float_T f = 0.0;
1112
1113 rettv->v_type = VAR_FLOAT;
1114 if (get_float_arg(argvars, &f) == OK)
1115 rettv->vval.v_float = acos(f);
1116 else
1117 rettv->vval.v_float = 0.0;
1118}
1119#endif
1120
1121/*
1122 * "add(list, item)" function
1123 */
1124 static void
1125f_add(typval_T *argvars, typval_T *rettv)
1126{
1127 list_T *l;
1128
1129 rettv->vval.v_number = 1; /* Default: Failed */
1130 if (argvars[0].v_type == VAR_LIST)
1131 {
1132 if ((l = argvars[0].vval.v_list) != NULL
1133 && !tv_check_lock(l->lv_lock,
1134 (char_u *)N_("add() argument"), TRUE)
1135 && list_append_tv(l, &argvars[1]) == OK)
1136 copy_tv(&argvars[0], rettv);
1137 }
1138 else
1139 EMSG(_(e_listreq));
1140}
1141
1142/*
1143 * "and(expr, expr)" function
1144 */
1145 static void
1146f_and(typval_T *argvars, typval_T *rettv)
1147{
1148 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1149 & get_tv_number_chk(&argvars[1], NULL);
1150}
1151
1152/*
1153 * "append(lnum, string/list)" function
1154 */
1155 static void
1156f_append(typval_T *argvars, typval_T *rettv)
1157{
1158 long lnum;
1159 char_u *line;
1160 list_T *l = NULL;
1161 listitem_T *li = NULL;
1162 typval_T *tv;
1163 long added = 0;
1164
1165 /* When coming here from Insert mode, sync undo, so that this can be
1166 * undone separately from what was previously inserted. */
1167 if (u_sync_once == 2)
1168 {
1169 u_sync_once = 1; /* notify that u_sync() was called */
1170 u_sync(TRUE);
1171 }
1172
1173 lnum = get_tv_lnum(argvars);
1174 if (lnum >= 0
1175 && lnum <= curbuf->b_ml.ml_line_count
1176 && u_save(lnum, lnum + 1) == OK)
1177 {
1178 if (argvars[1].v_type == VAR_LIST)
1179 {
1180 l = argvars[1].vval.v_list;
1181 if (l == NULL)
1182 return;
1183 li = l->lv_first;
1184 }
1185 for (;;)
1186 {
1187 if (l == NULL)
1188 tv = &argvars[1]; /* append a string */
1189 else if (li == NULL)
1190 break; /* end of list */
1191 else
1192 tv = &li->li_tv; /* append item from list */
1193 line = get_tv_string_chk(tv);
1194 if (line == NULL) /* type error */
1195 {
1196 rettv->vval.v_number = 1; /* Failed */
1197 break;
1198 }
1199 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1200 ++added;
1201 if (l == NULL)
1202 break;
1203 li = li->li_next;
1204 }
1205
1206 appended_lines_mark(lnum, added);
1207 if (curwin->w_cursor.lnum > lnum)
1208 curwin->w_cursor.lnum += added;
1209 }
1210 else
1211 rettv->vval.v_number = 1; /* Failed */
1212}
1213
1214/*
1215 * "argc()" function
1216 */
1217 static void
1218f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1219{
1220 rettv->vval.v_number = ARGCOUNT;
1221}
1222
1223/*
1224 * "argidx()" function
1225 */
1226 static void
1227f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1228{
1229 rettv->vval.v_number = curwin->w_arg_idx;
1230}
1231
1232/*
1233 * "arglistid()" function
1234 */
1235 static void
1236f_arglistid(typval_T *argvars, typval_T *rettv)
1237{
1238 win_T *wp;
1239
1240 rettv->vval.v_number = -1;
1241 wp = find_tabwin(&argvars[0], &argvars[1]);
1242 if (wp != NULL)
1243 rettv->vval.v_number = wp->w_alist->id;
1244}
1245
1246/*
1247 * "argv(nr)" function
1248 */
1249 static void
1250f_argv(typval_T *argvars, typval_T *rettv)
1251{
1252 int idx;
1253
1254 if (argvars[0].v_type != VAR_UNKNOWN)
1255 {
1256 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1257 if (idx >= 0 && idx < ARGCOUNT)
1258 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1259 else
1260 rettv->vval.v_string = NULL;
1261 rettv->v_type = VAR_STRING;
1262 }
1263 else if (rettv_list_alloc(rettv) == OK)
1264 for (idx = 0; idx < ARGCOUNT; ++idx)
1265 list_append_string(rettv->vval.v_list,
1266 alist_name(&ARGLIST[idx]), -1);
1267}
1268
1269/*
1270 * "assert_equal(expected, actual[, msg])" function
1271 */
1272 static void
1273f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1274{
1275 assert_equal_common(argvars, ASSERT_EQUAL);
1276}
1277
1278/*
1279 * "assert_notequal(expected, actual[, msg])" function
1280 */
1281 static void
1282f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1283{
1284 assert_equal_common(argvars, ASSERT_NOTEQUAL);
1285}
1286
1287/*
1288 * "assert_exception(string[, msg])" function
1289 */
1290 static void
1291f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1292{
1293 assert_exception(argvars);
1294}
1295
1296/*
1297 * "assert_fails(cmd [, error])" function
1298 */
1299 static void
1300f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1301{
1302 assert_fails(argvars);
1303}
1304
1305/*
1306 * "assert_false(actual[, msg])" function
1307 */
1308 static void
1309f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1310{
1311 assert_bool(argvars, FALSE);
1312}
1313
1314/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001315 * "assert_inrange(lower, upper[, msg])" function
1316 */
1317 static void
1318f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1319{
1320 assert_inrange(argvars);
1321}
1322
1323/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001324 * "assert_match(pattern, actual[, msg])" function
1325 */
1326 static void
1327f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1328{
1329 assert_match_common(argvars, ASSERT_MATCH);
1330}
1331
1332/*
1333 * "assert_notmatch(pattern, actual[, msg])" function
1334 */
1335 static void
1336f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1337{
1338 assert_match_common(argvars, ASSERT_NOTMATCH);
1339}
1340
1341/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001342 * "assert_report(msg)" function
1343 */
1344 static void
1345f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
1346{
1347 assert_report(argvars);
1348}
1349
1350/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001351 * "assert_true(actual[, msg])" function
1352 */
1353 static void
1354f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1355{
1356 assert_bool(argvars, TRUE);
1357}
1358
1359#ifdef FEAT_FLOAT
1360/*
1361 * "asin()" function
1362 */
1363 static void
1364f_asin(typval_T *argvars, typval_T *rettv)
1365{
1366 float_T f = 0.0;
1367
1368 rettv->v_type = VAR_FLOAT;
1369 if (get_float_arg(argvars, &f) == OK)
1370 rettv->vval.v_float = asin(f);
1371 else
1372 rettv->vval.v_float = 0.0;
1373}
1374
1375/*
1376 * "atan()" function
1377 */
1378 static void
1379f_atan(typval_T *argvars, typval_T *rettv)
1380{
1381 float_T f = 0.0;
1382
1383 rettv->v_type = VAR_FLOAT;
1384 if (get_float_arg(argvars, &f) == OK)
1385 rettv->vval.v_float = atan(f);
1386 else
1387 rettv->vval.v_float = 0.0;
1388}
1389
1390/*
1391 * "atan2()" function
1392 */
1393 static void
1394f_atan2(typval_T *argvars, typval_T *rettv)
1395{
1396 float_T fx = 0.0, fy = 0.0;
1397
1398 rettv->v_type = VAR_FLOAT;
1399 if (get_float_arg(argvars, &fx) == OK
1400 && get_float_arg(&argvars[1], &fy) == OK)
1401 rettv->vval.v_float = atan2(fx, fy);
1402 else
1403 rettv->vval.v_float = 0.0;
1404}
1405#endif
1406
1407/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001408 * "balloon_show()" function
1409 */
1410#ifdef FEAT_BEVAL
1411 static void
1412f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1413{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001414 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001415 {
1416 if (argvars[0].v_type == VAR_LIST
1417# ifdef FEAT_GUI
1418 && !gui.in_use
1419# endif
1420 )
1421 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1422 else
1423 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1424 }
1425}
1426
1427 static void
1428f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1429{
1430 if (rettv_list_alloc(rettv) == OK)
1431 {
1432 char_u *msg = get_tv_string_chk(&argvars[0]);
1433
1434 if (msg != NULL)
1435 {
1436 pumitem_T *array;
1437 int size = split_message(msg, &array);
1438 int i;
1439
1440 /* Skip the first and last item, they are always empty. */
1441 for (i = 1; i < size - 1; ++i)
1442 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
1443 vim_free(array);
1444 }
1445 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001446}
1447#endif
1448
1449/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001450 * "browse(save, title, initdir, default)" function
1451 */
1452 static void
1453f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1454{
1455#ifdef FEAT_BROWSE
1456 int save;
1457 char_u *title;
1458 char_u *initdir;
1459 char_u *defname;
1460 char_u buf[NUMBUFLEN];
1461 char_u buf2[NUMBUFLEN];
1462 int error = FALSE;
1463
1464 save = (int)get_tv_number_chk(&argvars[0], &error);
1465 title = get_tv_string_chk(&argvars[1]);
1466 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1467 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1468
1469 if (error || title == NULL || initdir == NULL || defname == NULL)
1470 rettv->vval.v_string = NULL;
1471 else
1472 rettv->vval.v_string =
1473 do_browse(save ? BROWSE_SAVE : 0,
1474 title, defname, NULL, initdir, NULL, curbuf);
1475#else
1476 rettv->vval.v_string = NULL;
1477#endif
1478 rettv->v_type = VAR_STRING;
1479}
1480
1481/*
1482 * "browsedir(title, initdir)" function
1483 */
1484 static void
1485f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1486{
1487#ifdef FEAT_BROWSE
1488 char_u *title;
1489 char_u *initdir;
1490 char_u buf[NUMBUFLEN];
1491
1492 title = get_tv_string_chk(&argvars[0]);
1493 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1494
1495 if (title == NULL || initdir == NULL)
1496 rettv->vval.v_string = NULL;
1497 else
1498 rettv->vval.v_string = do_browse(BROWSE_DIR,
1499 title, NULL, NULL, initdir, NULL, curbuf);
1500#else
1501 rettv->vval.v_string = NULL;
1502#endif
1503 rettv->v_type = VAR_STRING;
1504}
1505
1506static buf_T *find_buffer(typval_T *avar);
1507
1508/*
1509 * Find a buffer by number or exact name.
1510 */
1511 static buf_T *
1512find_buffer(typval_T *avar)
1513{
1514 buf_T *buf = NULL;
1515
1516 if (avar->v_type == VAR_NUMBER)
1517 buf = buflist_findnr((int)avar->vval.v_number);
1518 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1519 {
1520 buf = buflist_findname_exp(avar->vval.v_string);
1521 if (buf == NULL)
1522 {
1523 /* No full path name match, try a match with a URL or a "nofile"
1524 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001525 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001526 if (buf->b_fname != NULL
1527 && (path_with_url(buf->b_fname)
1528#ifdef FEAT_QUICKFIX
1529 || bt_nofile(buf)
1530#endif
1531 )
1532 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1533 break;
1534 }
1535 }
1536 return buf;
1537}
1538
1539/*
1540 * "bufexists(expr)" function
1541 */
1542 static void
1543f_bufexists(typval_T *argvars, typval_T *rettv)
1544{
1545 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1546}
1547
1548/*
1549 * "buflisted(expr)" function
1550 */
1551 static void
1552f_buflisted(typval_T *argvars, typval_T *rettv)
1553{
1554 buf_T *buf;
1555
1556 buf = find_buffer(&argvars[0]);
1557 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1558}
1559
1560/*
1561 * "bufloaded(expr)" function
1562 */
1563 static void
1564f_bufloaded(typval_T *argvars, typval_T *rettv)
1565{
1566 buf_T *buf;
1567
1568 buf = find_buffer(&argvars[0]);
1569 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1570}
1571
1572 buf_T *
1573buflist_find_by_name(char_u *name, int curtab_only)
1574{
1575 int save_magic;
1576 char_u *save_cpo;
1577 buf_T *buf;
1578
1579 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1580 save_magic = p_magic;
1581 p_magic = TRUE;
1582 save_cpo = p_cpo;
1583 p_cpo = (char_u *)"";
1584
1585 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1586 TRUE, FALSE, curtab_only));
1587
1588 p_magic = save_magic;
1589 p_cpo = save_cpo;
1590 return buf;
1591}
1592
1593/*
1594 * Get buffer by number or pattern.
1595 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001596 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597get_buf_tv(typval_T *tv, int curtab_only)
1598{
1599 char_u *name = tv->vval.v_string;
1600 buf_T *buf;
1601
1602 if (tv->v_type == VAR_NUMBER)
1603 return buflist_findnr((int)tv->vval.v_number);
1604 if (tv->v_type != VAR_STRING)
1605 return NULL;
1606 if (name == NULL || *name == NUL)
1607 return curbuf;
1608 if (name[0] == '$' && name[1] == NUL)
1609 return lastbuf;
1610
1611 buf = buflist_find_by_name(name, curtab_only);
1612
1613 /* If not found, try expanding the name, like done for bufexists(). */
1614 if (buf == NULL)
1615 buf = find_buffer(tv);
1616
1617 return buf;
1618}
1619
1620/*
1621 * "bufname(expr)" function
1622 */
1623 static void
1624f_bufname(typval_T *argvars, typval_T *rettv)
1625{
1626 buf_T *buf;
1627
1628 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1629 ++emsg_off;
1630 buf = get_buf_tv(&argvars[0], FALSE);
1631 rettv->v_type = VAR_STRING;
1632 if (buf != NULL && buf->b_fname != NULL)
1633 rettv->vval.v_string = vim_strsave(buf->b_fname);
1634 else
1635 rettv->vval.v_string = NULL;
1636 --emsg_off;
1637}
1638
1639/*
1640 * "bufnr(expr)" function
1641 */
1642 static void
1643f_bufnr(typval_T *argvars, typval_T *rettv)
1644{
1645 buf_T *buf;
1646 int error = FALSE;
1647 char_u *name;
1648
1649 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1650 ++emsg_off;
1651 buf = get_buf_tv(&argvars[0], FALSE);
1652 --emsg_off;
1653
1654 /* If the buffer isn't found and the second argument is not zero create a
1655 * new buffer. */
1656 if (buf == NULL
1657 && argvars[1].v_type != VAR_UNKNOWN
1658 && get_tv_number_chk(&argvars[1], &error) != 0
1659 && !error
1660 && (name = get_tv_string_chk(&argvars[0])) != NULL
1661 && !error)
1662 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1663
1664 if (buf != NULL)
1665 rettv->vval.v_number = buf->b_fnum;
1666 else
1667 rettv->vval.v_number = -1;
1668}
1669
1670 static void
1671buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1672{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673 win_T *wp;
1674 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 buf_T *buf;
1676
1677 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1678 ++emsg_off;
1679 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001680 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 {
1682 ++winnr;
1683 if (wp->w_buffer == buf)
1684 break;
1685 }
1686 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 --emsg_off;
1688}
1689
1690/*
1691 * "bufwinid(nr)" function
1692 */
1693 static void
1694f_bufwinid(typval_T *argvars, typval_T *rettv)
1695{
1696 buf_win_common(argvars, rettv, FALSE);
1697}
1698
1699/*
1700 * "bufwinnr(nr)" function
1701 */
1702 static void
1703f_bufwinnr(typval_T *argvars, typval_T *rettv)
1704{
1705 buf_win_common(argvars, rettv, TRUE);
1706}
1707
1708/*
1709 * "byte2line(byte)" function
1710 */
1711 static void
1712f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1713{
1714#ifndef FEAT_BYTEOFF
1715 rettv->vval.v_number = -1;
1716#else
1717 long boff = 0;
1718
1719 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1720 if (boff < 0)
1721 rettv->vval.v_number = -1;
1722 else
1723 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1724 (linenr_T)0, &boff);
1725#endif
1726}
1727
1728 static void
1729byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1730{
1731#ifdef FEAT_MBYTE
1732 char_u *t;
1733#endif
1734 char_u *str;
1735 varnumber_T idx;
1736
1737 str = get_tv_string_chk(&argvars[0]);
1738 idx = get_tv_number_chk(&argvars[1], NULL);
1739 rettv->vval.v_number = -1;
1740 if (str == NULL || idx < 0)
1741 return;
1742
1743#ifdef FEAT_MBYTE
1744 t = str;
1745 for ( ; idx > 0; idx--)
1746 {
1747 if (*t == NUL) /* EOL reached */
1748 return;
1749 if (enc_utf8 && comp)
1750 t += utf_ptr2len(t);
1751 else
1752 t += (*mb_ptr2len)(t);
1753 }
1754 rettv->vval.v_number = (varnumber_T)(t - str);
1755#else
1756 if ((size_t)idx <= STRLEN(str))
1757 rettv->vval.v_number = idx;
1758#endif
1759}
1760
1761/*
1762 * "byteidx()" function
1763 */
1764 static void
1765f_byteidx(typval_T *argvars, typval_T *rettv)
1766{
1767 byteidx(argvars, rettv, FALSE);
1768}
1769
1770/*
1771 * "byteidxcomp()" function
1772 */
1773 static void
1774f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1775{
1776 byteidx(argvars, rettv, TRUE);
1777}
1778
1779/*
1780 * "call(func, arglist [, dict])" function
1781 */
1782 static void
1783f_call(typval_T *argvars, typval_T *rettv)
1784{
1785 char_u *func;
1786 partial_T *partial = NULL;
1787 dict_T *selfdict = NULL;
1788
1789 if (argvars[1].v_type != VAR_LIST)
1790 {
1791 EMSG(_(e_listreq));
1792 return;
1793 }
1794 if (argvars[1].vval.v_list == NULL)
1795 return;
1796
1797 if (argvars[0].v_type == VAR_FUNC)
1798 func = argvars[0].vval.v_string;
1799 else if (argvars[0].v_type == VAR_PARTIAL)
1800 {
1801 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001802 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001803 }
1804 else
1805 func = get_tv_string(&argvars[0]);
1806 if (*func == NUL)
1807 return; /* type error or empty name */
1808
1809 if (argvars[2].v_type != VAR_UNKNOWN)
1810 {
1811 if (argvars[2].v_type != VAR_DICT)
1812 {
1813 EMSG(_(e_dictreq));
1814 return;
1815 }
1816 selfdict = argvars[2].vval.v_dict;
1817 }
1818
1819 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1820}
1821
1822#ifdef FEAT_FLOAT
1823/*
1824 * "ceil({float})" function
1825 */
1826 static void
1827f_ceil(typval_T *argvars, typval_T *rettv)
1828{
1829 float_T f = 0.0;
1830
1831 rettv->v_type = VAR_FLOAT;
1832 if (get_float_arg(argvars, &f) == OK)
1833 rettv->vval.v_float = ceil(f);
1834 else
1835 rettv->vval.v_float = 0.0;
1836}
1837#endif
1838
1839#ifdef FEAT_JOB_CHANNEL
1840/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001841 * "ch_canread()" function
1842 */
1843 static void
1844f_ch_canread(typval_T *argvars, typval_T *rettv)
1845{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001846 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001847
1848 rettv->vval.v_number = 0;
1849 if (channel != NULL)
1850 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1851 || channel_has_readahead(channel, PART_OUT)
1852 || channel_has_readahead(channel, PART_ERR);
1853}
1854
1855/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001856 * "ch_close()" function
1857 */
1858 static void
1859f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1860{
1861 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1862
1863 if (channel != NULL)
1864 {
1865 channel_close(channel, FALSE);
1866 channel_clear(channel);
1867 }
1868}
1869
1870/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001871 * "ch_close()" function
1872 */
1873 static void
1874f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1875{
1876 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1877
1878 if (channel != NULL)
1879 channel_close_in(channel);
1880}
1881
1882/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001883 * "ch_getbufnr()" function
1884 */
1885 static void
1886f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1887{
1888 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1889
1890 rettv->vval.v_number = -1;
1891 if (channel != NULL)
1892 {
1893 char_u *what = get_tv_string(&argvars[1]);
1894 int part;
1895
1896 if (STRCMP(what, "err") == 0)
1897 part = PART_ERR;
1898 else if (STRCMP(what, "out") == 0)
1899 part = PART_OUT;
1900 else if (STRCMP(what, "in") == 0)
1901 part = PART_IN;
1902 else
1903 part = PART_SOCK;
1904 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1905 rettv->vval.v_number =
1906 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1907 }
1908}
1909
1910/*
1911 * "ch_getjob()" function
1912 */
1913 static void
1914f_ch_getjob(typval_T *argvars, typval_T *rettv)
1915{
1916 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1917
1918 if (channel != NULL)
1919 {
1920 rettv->v_type = VAR_JOB;
1921 rettv->vval.v_job = channel->ch_job;
1922 if (channel->ch_job != NULL)
1923 ++channel->ch_job->jv_refcount;
1924 }
1925}
1926
1927/*
1928 * "ch_info()" function
1929 */
1930 static void
1931f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1932{
1933 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1934
1935 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1936 channel_info(channel, rettv->vval.v_dict);
1937}
1938
1939/*
1940 * "ch_log()" function
1941 */
1942 static void
1943f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1944{
1945 char_u *msg = get_tv_string(&argvars[0]);
1946 channel_T *channel = NULL;
1947
1948 if (argvars[1].v_type != VAR_UNKNOWN)
1949 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
1950
1951 ch_log(channel, (char *)msg);
1952}
1953
1954/*
1955 * "ch_logfile()" function
1956 */
1957 static void
1958f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
1959{
1960 char_u *fname;
1961 char_u *opt = (char_u *)"";
1962 char_u buf[NUMBUFLEN];
1963
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02001964 /* Don't open a file in restricted mode. */
1965 if (check_restricted() || check_secure())
1966 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001967 fname = get_tv_string(&argvars[0]);
1968 if (argvars[1].v_type == VAR_STRING)
1969 opt = get_tv_string_buf(&argvars[1], buf);
1970 ch_logfile(fname, opt);
1971}
1972
1973/*
1974 * "ch_open()" function
1975 */
1976 static void
1977f_ch_open(typval_T *argvars, typval_T *rettv)
1978{
1979 rettv->v_type = VAR_CHANNEL;
1980 if (check_restricted() || check_secure())
1981 return;
1982 rettv->vval.v_channel = channel_open_func(argvars);
1983}
1984
1985/*
1986 * "ch_read()" function
1987 */
1988 static void
1989f_ch_read(typval_T *argvars, typval_T *rettv)
1990{
1991 common_channel_read(argvars, rettv, FALSE);
1992}
1993
1994/*
1995 * "ch_readraw()" function
1996 */
1997 static void
1998f_ch_readraw(typval_T *argvars, typval_T *rettv)
1999{
2000 common_channel_read(argvars, rettv, TRUE);
2001}
2002
2003/*
2004 * "ch_evalexpr()" function
2005 */
2006 static void
2007f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2008{
2009 ch_expr_common(argvars, rettv, TRUE);
2010}
2011
2012/*
2013 * "ch_sendexpr()" function
2014 */
2015 static void
2016f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2017{
2018 ch_expr_common(argvars, rettv, FALSE);
2019}
2020
2021/*
2022 * "ch_evalraw()" function
2023 */
2024 static void
2025f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2026{
2027 ch_raw_common(argvars, rettv, TRUE);
2028}
2029
2030/*
2031 * "ch_sendraw()" function
2032 */
2033 static void
2034f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2035{
2036 ch_raw_common(argvars, rettv, FALSE);
2037}
2038
2039/*
2040 * "ch_setoptions()" function
2041 */
2042 static void
2043f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2044{
2045 channel_T *channel;
2046 jobopt_T opt;
2047
2048 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2049 if (channel == NULL)
2050 return;
2051 clear_job_options(&opt);
2052 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002053 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002054 channel_set_options(channel, &opt);
2055 free_job_options(&opt);
2056}
2057
2058/*
2059 * "ch_status()" function
2060 */
2061 static void
2062f_ch_status(typval_T *argvars, typval_T *rettv)
2063{
2064 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002065 jobopt_T opt;
2066 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002067
2068 /* return an empty string by default */
2069 rettv->v_type = VAR_STRING;
2070 rettv->vval.v_string = NULL;
2071
2072 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002073
2074 if (argvars[1].v_type != VAR_UNKNOWN)
2075 {
2076 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002077 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002078 && (opt.jo_set & JO_PART))
2079 part = opt.jo_part;
2080 }
2081
2082 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002083}
2084#endif
2085
2086/*
2087 * "changenr()" function
2088 */
2089 static void
2090f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2091{
2092 rettv->vval.v_number = curbuf->b_u_seq_cur;
2093}
2094
2095/*
2096 * "char2nr(string)" function
2097 */
2098 static void
2099f_char2nr(typval_T *argvars, typval_T *rettv)
2100{
2101#ifdef FEAT_MBYTE
2102 if (has_mbyte)
2103 {
2104 int utf8 = 0;
2105
2106 if (argvars[1].v_type != VAR_UNKNOWN)
2107 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2108
2109 if (utf8)
2110 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2111 else
2112 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2113 }
2114 else
2115#endif
2116 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2117}
2118
2119/*
2120 * "cindent(lnum)" function
2121 */
2122 static void
2123f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2124{
2125#ifdef FEAT_CINDENT
2126 pos_T pos;
2127 linenr_T lnum;
2128
2129 pos = curwin->w_cursor;
2130 lnum = get_tv_lnum(argvars);
2131 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2132 {
2133 curwin->w_cursor.lnum = lnum;
2134 rettv->vval.v_number = get_c_indent();
2135 curwin->w_cursor = pos;
2136 }
2137 else
2138#endif
2139 rettv->vval.v_number = -1;
2140}
2141
2142/*
2143 * "clearmatches()" function
2144 */
2145 static void
2146f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2147{
2148#ifdef FEAT_SEARCH_EXTRA
2149 clear_matches(curwin);
2150#endif
2151}
2152
2153/*
2154 * "col(string)" function
2155 */
2156 static void
2157f_col(typval_T *argvars, typval_T *rettv)
2158{
2159 colnr_T col = 0;
2160 pos_T *fp;
2161 int fnum = curbuf->b_fnum;
2162
2163 fp = var2fpos(&argvars[0], FALSE, &fnum);
2164 if (fp != NULL && fnum == curbuf->b_fnum)
2165 {
2166 if (fp->col == MAXCOL)
2167 {
2168 /* '> can be MAXCOL, get the length of the line then */
2169 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2170 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2171 else
2172 col = MAXCOL;
2173 }
2174 else
2175 {
2176 col = fp->col + 1;
2177#ifdef FEAT_VIRTUALEDIT
2178 /* col(".") when the cursor is on the NUL at the end of the line
2179 * because of "coladd" can be seen as an extra column. */
2180 if (virtual_active() && fp == &curwin->w_cursor)
2181 {
2182 char_u *p = ml_get_cursor();
2183
2184 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2185 curwin->w_virtcol - curwin->w_cursor.coladd))
2186 {
2187# ifdef FEAT_MBYTE
2188 int l;
2189
2190 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2191 col += l;
2192# else
2193 if (*p != NUL && p[1] == NUL)
2194 ++col;
2195# endif
2196 }
2197 }
2198#endif
2199 }
2200 }
2201 rettv->vval.v_number = col;
2202}
2203
2204#if defined(FEAT_INS_EXPAND)
2205/*
2206 * "complete()" function
2207 */
2208 static void
2209f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2210{
2211 int startcol;
2212
2213 if ((State & INSERT) == 0)
2214 {
2215 EMSG(_("E785: complete() can only be used in Insert mode"));
2216 return;
2217 }
2218
2219 /* Check for undo allowed here, because if something was already inserted
2220 * the line was already saved for undo and this check isn't done. */
2221 if (!undo_allowed())
2222 return;
2223
2224 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2225 {
2226 EMSG(_(e_invarg));
2227 return;
2228 }
2229
2230 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2231 if (startcol <= 0)
2232 return;
2233
2234 set_completion(startcol - 1, argvars[1].vval.v_list);
2235}
2236
2237/*
2238 * "complete_add()" function
2239 */
2240 static void
2241f_complete_add(typval_T *argvars, typval_T *rettv)
2242{
2243 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2244}
2245
2246/*
2247 * "complete_check()" function
2248 */
2249 static void
2250f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2251{
2252 int saved = RedrawingDisabled;
2253
2254 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002255 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256 rettv->vval.v_number = compl_interrupted;
2257 RedrawingDisabled = saved;
2258}
2259#endif
2260
2261/*
2262 * "confirm(message, buttons[, default [, type]])" function
2263 */
2264 static void
2265f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2266{
2267#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2268 char_u *message;
2269 char_u *buttons = NULL;
2270 char_u buf[NUMBUFLEN];
2271 char_u buf2[NUMBUFLEN];
2272 int def = 1;
2273 int type = VIM_GENERIC;
2274 char_u *typestr;
2275 int error = FALSE;
2276
2277 message = get_tv_string_chk(&argvars[0]);
2278 if (message == NULL)
2279 error = TRUE;
2280 if (argvars[1].v_type != VAR_UNKNOWN)
2281 {
2282 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2283 if (buttons == NULL)
2284 error = TRUE;
2285 if (argvars[2].v_type != VAR_UNKNOWN)
2286 {
2287 def = (int)get_tv_number_chk(&argvars[2], &error);
2288 if (argvars[3].v_type != VAR_UNKNOWN)
2289 {
2290 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2291 if (typestr == NULL)
2292 error = TRUE;
2293 else
2294 {
2295 switch (TOUPPER_ASC(*typestr))
2296 {
2297 case 'E': type = VIM_ERROR; break;
2298 case 'Q': type = VIM_QUESTION; break;
2299 case 'I': type = VIM_INFO; break;
2300 case 'W': type = VIM_WARNING; break;
2301 case 'G': type = VIM_GENERIC; break;
2302 }
2303 }
2304 }
2305 }
2306 }
2307
2308 if (buttons == NULL || *buttons == NUL)
2309 buttons = (char_u *)_("&Ok");
2310
2311 if (!error)
2312 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2313 def, NULL, FALSE);
2314#endif
2315}
2316
2317/*
2318 * "copy()" function
2319 */
2320 static void
2321f_copy(typval_T *argvars, typval_T *rettv)
2322{
2323 item_copy(&argvars[0], rettv, FALSE, 0);
2324}
2325
2326#ifdef FEAT_FLOAT
2327/*
2328 * "cos()" function
2329 */
2330 static void
2331f_cos(typval_T *argvars, typval_T *rettv)
2332{
2333 float_T f = 0.0;
2334
2335 rettv->v_type = VAR_FLOAT;
2336 if (get_float_arg(argvars, &f) == OK)
2337 rettv->vval.v_float = cos(f);
2338 else
2339 rettv->vval.v_float = 0.0;
2340}
2341
2342/*
2343 * "cosh()" function
2344 */
2345 static void
2346f_cosh(typval_T *argvars, typval_T *rettv)
2347{
2348 float_T f = 0.0;
2349
2350 rettv->v_type = VAR_FLOAT;
2351 if (get_float_arg(argvars, &f) == OK)
2352 rettv->vval.v_float = cosh(f);
2353 else
2354 rettv->vval.v_float = 0.0;
2355}
2356#endif
2357
2358/*
2359 * "count()" function
2360 */
2361 static void
2362f_count(typval_T *argvars, typval_T *rettv)
2363{
2364 long n = 0;
2365 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002366 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367
Bram Moolenaar9966b212017-07-28 16:46:57 +02002368 if (argvars[2].v_type != VAR_UNKNOWN)
2369 ic = (int)get_tv_number_chk(&argvars[2], &error);
2370
2371 if (argvars[0].v_type == VAR_STRING)
2372 {
2373 char_u *expr = get_tv_string_chk(&argvars[1]);
2374 char_u *p = argvars[0].vval.v_string;
2375 char_u *next;
2376
2377 if (!error && expr != NULL && p != NULL)
2378 {
2379 if (ic)
2380 {
2381 size_t len = STRLEN(expr);
2382
2383 while (*p != NUL)
2384 {
2385 if (MB_STRNICMP(p, expr, len) == 0)
2386 {
2387 ++n;
2388 p += len;
2389 }
2390 else
2391 MB_PTR_ADV(p);
2392 }
2393 }
2394 else
2395 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2396 != NULL)
2397 {
2398 ++n;
2399 p = next + STRLEN(expr);
2400 }
2401 }
2402
2403 }
2404 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002405 {
2406 listitem_T *li;
2407 list_T *l;
2408 long idx;
2409
2410 if ((l = argvars[0].vval.v_list) != NULL)
2411 {
2412 li = l->lv_first;
2413 if (argvars[2].v_type != VAR_UNKNOWN)
2414 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002415 if (argvars[3].v_type != VAR_UNKNOWN)
2416 {
2417 idx = (long)get_tv_number_chk(&argvars[3], &error);
2418 if (!error)
2419 {
2420 li = list_find(l, idx);
2421 if (li == NULL)
2422 EMSGN(_(e_listidx), idx);
2423 }
2424 }
2425 if (error)
2426 li = NULL;
2427 }
2428
2429 for ( ; li != NULL; li = li->li_next)
2430 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2431 ++n;
2432 }
2433 }
2434 else if (argvars[0].v_type == VAR_DICT)
2435 {
2436 int todo;
2437 dict_T *d;
2438 hashitem_T *hi;
2439
2440 if ((d = argvars[0].vval.v_dict) != NULL)
2441 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 if (argvars[2].v_type != VAR_UNKNOWN)
2443 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002444 if (argvars[3].v_type != VAR_UNKNOWN)
2445 EMSG(_(e_invarg));
2446 }
2447
2448 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2449 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2450 {
2451 if (!HASHITEM_EMPTY(hi))
2452 {
2453 --todo;
2454 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2455 ++n;
2456 }
2457 }
2458 }
2459 }
2460 else
2461 EMSG2(_(e_listdictarg), "count()");
2462 rettv->vval.v_number = n;
2463}
2464
2465/*
2466 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2467 *
2468 * Checks the existence of a cscope connection.
2469 */
2470 static void
2471f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2472{
2473#ifdef FEAT_CSCOPE
2474 int num = 0;
2475 char_u *dbpath = NULL;
2476 char_u *prepend = NULL;
2477 char_u buf[NUMBUFLEN];
2478
2479 if (argvars[0].v_type != VAR_UNKNOWN
2480 && argvars[1].v_type != VAR_UNKNOWN)
2481 {
2482 num = (int)get_tv_number(&argvars[0]);
2483 dbpath = get_tv_string(&argvars[1]);
2484 if (argvars[2].v_type != VAR_UNKNOWN)
2485 prepend = get_tv_string_buf(&argvars[2], buf);
2486 }
2487
2488 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2489#endif
2490}
2491
2492/*
2493 * "cursor(lnum, col)" function, or
2494 * "cursor(list)"
2495 *
2496 * Moves the cursor to the specified line and column.
2497 * Returns 0 when the position could be set, -1 otherwise.
2498 */
2499 static void
2500f_cursor(typval_T *argvars, typval_T *rettv)
2501{
2502 long line, col;
2503#ifdef FEAT_VIRTUALEDIT
2504 long coladd = 0;
2505#endif
2506 int set_curswant = TRUE;
2507
2508 rettv->vval.v_number = -1;
2509 if (argvars[1].v_type == VAR_UNKNOWN)
2510 {
2511 pos_T pos;
2512 colnr_T curswant = -1;
2513
2514 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2515 {
2516 EMSG(_(e_invarg));
2517 return;
2518 }
2519 line = pos.lnum;
2520 col = pos.col;
2521#ifdef FEAT_VIRTUALEDIT
2522 coladd = pos.coladd;
2523#endif
2524 if (curswant >= 0)
2525 {
2526 curwin->w_curswant = curswant - 1;
2527 set_curswant = FALSE;
2528 }
2529 }
2530 else
2531 {
2532 line = get_tv_lnum(argvars);
2533 col = (long)get_tv_number_chk(&argvars[1], NULL);
2534#ifdef FEAT_VIRTUALEDIT
2535 if (argvars[2].v_type != VAR_UNKNOWN)
2536 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2537#endif
2538 }
2539 if (line < 0 || col < 0
2540#ifdef FEAT_VIRTUALEDIT
2541 || coladd < 0
2542#endif
2543 )
2544 return; /* type error; errmsg already given */
2545 if (line > 0)
2546 curwin->w_cursor.lnum = line;
2547 if (col > 0)
2548 curwin->w_cursor.col = col - 1;
2549#ifdef FEAT_VIRTUALEDIT
2550 curwin->w_cursor.coladd = coladd;
2551#endif
2552
2553 /* Make sure the cursor is in a valid position. */
2554 check_cursor();
2555#ifdef FEAT_MBYTE
2556 /* Correct cursor for multi-byte character. */
2557 if (has_mbyte)
2558 mb_adjust_cursor();
2559#endif
2560
2561 curwin->w_set_curswant = set_curswant;
2562 rettv->vval.v_number = 0;
2563}
2564
2565/*
2566 * "deepcopy()" function
2567 */
2568 static void
2569f_deepcopy(typval_T *argvars, typval_T *rettv)
2570{
2571 int noref = 0;
2572 int copyID;
2573
2574 if (argvars[1].v_type != VAR_UNKNOWN)
2575 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2576 if (noref < 0 || noref > 1)
2577 EMSG(_(e_invarg));
2578 else
2579 {
2580 copyID = get_copyID();
2581 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2582 }
2583}
2584
2585/*
2586 * "delete()" function
2587 */
2588 static void
2589f_delete(typval_T *argvars, typval_T *rettv)
2590{
2591 char_u nbuf[NUMBUFLEN];
2592 char_u *name;
2593 char_u *flags;
2594
2595 rettv->vval.v_number = -1;
2596 if (check_restricted() || check_secure())
2597 return;
2598
2599 name = get_tv_string(&argvars[0]);
2600 if (name == NULL || *name == NUL)
2601 {
2602 EMSG(_(e_invarg));
2603 return;
2604 }
2605
2606 if (argvars[1].v_type != VAR_UNKNOWN)
2607 flags = get_tv_string_buf(&argvars[1], nbuf);
2608 else
2609 flags = (char_u *)"";
2610
2611 if (*flags == NUL)
2612 /* delete a file */
2613 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2614 else if (STRCMP(flags, "d") == 0)
2615 /* delete an empty directory */
2616 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2617 else if (STRCMP(flags, "rf") == 0)
2618 /* delete a directory recursively */
2619 rettv->vval.v_number = delete_recursive(name);
2620 else
2621 EMSG2(_(e_invexpr2), flags);
2622}
2623
2624/*
2625 * "did_filetype()" function
2626 */
2627 static void
2628f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2629{
2630#ifdef FEAT_AUTOCMD
2631 rettv->vval.v_number = did_filetype;
2632#endif
2633}
2634
2635/*
2636 * "diff_filler()" function
2637 */
2638 static void
2639f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2640{
2641#ifdef FEAT_DIFF
2642 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2643#endif
2644}
2645
2646/*
2647 * "diff_hlID()" function
2648 */
2649 static void
2650f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2651{
2652#ifdef FEAT_DIFF
2653 linenr_T lnum = get_tv_lnum(argvars);
2654 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002655 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 static int fnum = 0;
2657 static int change_start = 0;
2658 static int change_end = 0;
2659 static hlf_T hlID = (hlf_T)0;
2660 int filler_lines;
2661 int col;
2662
2663 if (lnum < 0) /* ignore type error in {lnum} arg */
2664 lnum = 0;
2665 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002666 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002667 || fnum != curbuf->b_fnum)
2668 {
2669 /* New line, buffer, change: need to get the values. */
2670 filler_lines = diff_check(curwin, lnum);
2671 if (filler_lines < 0)
2672 {
2673 if (filler_lines == -1)
2674 {
2675 change_start = MAXCOL;
2676 change_end = -1;
2677 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2678 hlID = HLF_ADD; /* added line */
2679 else
2680 hlID = HLF_CHD; /* changed line */
2681 }
2682 else
2683 hlID = HLF_ADD; /* added line */
2684 }
2685 else
2686 hlID = (hlf_T)0;
2687 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002688 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002689 fnum = curbuf->b_fnum;
2690 }
2691
2692 if (hlID == HLF_CHD || hlID == HLF_TXD)
2693 {
2694 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2695 if (col >= change_start && col <= change_end)
2696 hlID = HLF_TXD; /* changed text */
2697 else
2698 hlID = HLF_CHD; /* changed line */
2699 }
2700 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2701#endif
2702}
2703
2704/*
2705 * "empty({expr})" function
2706 */
2707 static void
2708f_empty(typval_T *argvars, typval_T *rettv)
2709{
2710 int n = FALSE;
2711
2712 switch (argvars[0].v_type)
2713 {
2714 case VAR_STRING:
2715 case VAR_FUNC:
2716 n = argvars[0].vval.v_string == NULL
2717 || *argvars[0].vval.v_string == NUL;
2718 break;
2719 case VAR_PARTIAL:
2720 n = FALSE;
2721 break;
2722 case VAR_NUMBER:
2723 n = argvars[0].vval.v_number == 0;
2724 break;
2725 case VAR_FLOAT:
2726#ifdef FEAT_FLOAT
2727 n = argvars[0].vval.v_float == 0.0;
2728 break;
2729#endif
2730 case VAR_LIST:
2731 n = argvars[0].vval.v_list == NULL
2732 || argvars[0].vval.v_list->lv_first == NULL;
2733 break;
2734 case VAR_DICT:
2735 n = argvars[0].vval.v_dict == NULL
2736 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2737 break;
2738 case VAR_SPECIAL:
2739 n = argvars[0].vval.v_number != VVAL_TRUE;
2740 break;
2741
2742 case VAR_JOB:
2743#ifdef FEAT_JOB_CHANNEL
2744 n = argvars[0].vval.v_job == NULL
2745 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2746 break;
2747#endif
2748 case VAR_CHANNEL:
2749#ifdef FEAT_JOB_CHANNEL
2750 n = argvars[0].vval.v_channel == NULL
2751 || !channel_is_open(argvars[0].vval.v_channel);
2752 break;
2753#endif
2754 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002755 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 n = TRUE;
2757 break;
2758 }
2759
2760 rettv->vval.v_number = n;
2761}
2762
2763/*
2764 * "escape({string}, {chars})" function
2765 */
2766 static void
2767f_escape(typval_T *argvars, typval_T *rettv)
2768{
2769 char_u buf[NUMBUFLEN];
2770
2771 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2772 get_tv_string_buf(&argvars[1], buf));
2773 rettv->v_type = VAR_STRING;
2774}
2775
2776/*
2777 * "eval()" function
2778 */
2779 static void
2780f_eval(typval_T *argvars, typval_T *rettv)
2781{
2782 char_u *s, *p;
2783
2784 s = get_tv_string_chk(&argvars[0]);
2785 if (s != NULL)
2786 s = skipwhite(s);
2787
2788 p = s;
2789 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2790 {
2791 if (p != NULL && !aborting())
2792 EMSG2(_(e_invexpr2), p);
2793 need_clr_eos = FALSE;
2794 rettv->v_type = VAR_NUMBER;
2795 rettv->vval.v_number = 0;
2796 }
2797 else if (*s != NUL)
2798 EMSG(_(e_trailing));
2799}
2800
2801/*
2802 * "eventhandler()" function
2803 */
2804 static void
2805f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2806{
2807 rettv->vval.v_number = vgetc_busy;
2808}
2809
2810/*
2811 * "executable()" function
2812 */
2813 static void
2814f_executable(typval_T *argvars, typval_T *rettv)
2815{
2816 char_u *name = get_tv_string(&argvars[0]);
2817
2818 /* Check in $PATH and also check directly if there is a directory name. */
2819 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2820 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2821}
2822
2823static garray_T redir_execute_ga;
2824
2825/*
2826 * Append "value[value_len]" to the execute() output.
2827 */
2828 void
2829execute_redir_str(char_u *value, int value_len)
2830{
2831 int len;
2832
2833 if (value_len == -1)
2834 len = (int)STRLEN(value); /* Append the entire string */
2835 else
2836 len = value_len; /* Append only "value_len" characters */
2837 if (ga_grow(&redir_execute_ga, len) == OK)
2838 {
2839 mch_memmove((char *)redir_execute_ga.ga_data
2840 + redir_execute_ga.ga_len, value, len);
2841 redir_execute_ga.ga_len += len;
2842 }
2843}
2844
2845/*
2846 * Get next line from a list.
2847 * Called by do_cmdline() to get the next line.
2848 * Returns allocated string, or NULL for end of function.
2849 */
2850
2851 static char_u *
2852get_list_line(
2853 int c UNUSED,
2854 void *cookie,
2855 int indent UNUSED)
2856{
2857 listitem_T **p = (listitem_T **)cookie;
2858 listitem_T *item = *p;
2859 char_u buf[NUMBUFLEN];
2860 char_u *s;
2861
2862 if (item == NULL)
2863 return NULL;
2864 s = get_tv_string_buf_chk(&item->li_tv, buf);
2865 *p = item->li_next;
2866 return s == NULL ? NULL : vim_strsave(s);
2867}
2868
2869/*
2870 * "execute()" function
2871 */
2872 static void
2873f_execute(typval_T *argvars, typval_T *rettv)
2874{
2875 char_u *cmd = NULL;
2876 list_T *list = NULL;
2877 int save_msg_silent = msg_silent;
2878 int save_emsg_silent = emsg_silent;
2879 int save_emsg_noredir = emsg_noredir;
2880 int save_redir_execute = redir_execute;
2881 garray_T save_ga;
2882
2883 rettv->vval.v_string = NULL;
2884 rettv->v_type = VAR_STRING;
2885
2886 if (argvars[0].v_type == VAR_LIST)
2887 {
2888 list = argvars[0].vval.v_list;
2889 if (list == NULL || list->lv_first == NULL)
2890 /* empty list, no commands, empty output */
2891 return;
2892 ++list->lv_refcount;
2893 }
2894 else
2895 {
2896 cmd = get_tv_string_chk(&argvars[0]);
2897 if (cmd == NULL)
2898 return;
2899 }
2900
2901 if (argvars[1].v_type != VAR_UNKNOWN)
2902 {
2903 char_u buf[NUMBUFLEN];
2904 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2905
2906 if (s == NULL)
2907 return;
2908 if (STRNCMP(s, "silent", 6) == 0)
2909 ++msg_silent;
2910 if (STRCMP(s, "silent!") == 0)
2911 {
2912 emsg_silent = TRUE;
2913 emsg_noredir = TRUE;
2914 }
2915 }
2916 else
2917 ++msg_silent;
2918
2919 if (redir_execute)
2920 save_ga = redir_execute_ga;
2921 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2922 redir_execute = TRUE;
2923
2924 if (cmd != NULL)
2925 do_cmdline_cmd(cmd);
2926 else
2927 {
2928 listitem_T *item = list->lv_first;
2929
2930 do_cmdline(NULL, get_list_line, (void *)&item,
2931 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2932 --list->lv_refcount;
2933 }
2934
Bram Moolenaard297f352017-01-29 20:31:21 +01002935 /* Need to append a NUL to the result. */
2936 if (ga_grow(&redir_execute_ga, 1) == OK)
2937 {
2938 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2939 rettv->vval.v_string = redir_execute_ga.ga_data;
2940 }
2941 else
2942 {
2943 ga_clear(&redir_execute_ga);
2944 rettv->vval.v_string = NULL;
2945 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002946 msg_silent = save_msg_silent;
2947 emsg_silent = save_emsg_silent;
2948 emsg_noredir = save_emsg_noredir;
2949
2950 redir_execute = save_redir_execute;
2951 if (redir_execute)
2952 redir_execute_ga = save_ga;
2953
2954 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
2955 * line. Put it back in the first column. */
2956 msg_col = 0;
2957}
2958
2959/*
2960 * "exepath()" function
2961 */
2962 static void
2963f_exepath(typval_T *argvars, typval_T *rettv)
2964{
2965 char_u *p = NULL;
2966
2967 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
2968 rettv->v_type = VAR_STRING;
2969 rettv->vval.v_string = p;
2970}
2971
2972/*
2973 * "exists()" function
2974 */
2975 static void
2976f_exists(typval_T *argvars, typval_T *rettv)
2977{
2978 char_u *p;
2979 char_u *name;
2980 int n = FALSE;
2981 int len = 0;
2982
2983 p = get_tv_string(&argvars[0]);
2984 if (*p == '$') /* environment variable */
2985 {
2986 /* first try "normal" environment variables (fast) */
2987 if (mch_getenv(p + 1) != NULL)
2988 n = TRUE;
2989 else
2990 {
2991 /* try expanding things like $VIM and ${HOME} */
2992 p = expand_env_save(p);
2993 if (p != NULL && *p != '$')
2994 n = TRUE;
2995 vim_free(p);
2996 }
2997 }
2998 else if (*p == '&' || *p == '+') /* option */
2999 {
3000 n = (get_option_tv(&p, NULL, TRUE) == OK);
3001 if (*skipwhite(p) != NUL)
3002 n = FALSE; /* trailing garbage */
3003 }
3004 else if (*p == '*') /* internal or user defined function */
3005 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003006 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003007 }
3008 else if (*p == ':')
3009 {
3010 n = cmd_exists(p + 1);
3011 }
3012 else if (*p == '#')
3013 {
3014#ifdef FEAT_AUTOCMD
3015 if (p[1] == '#')
3016 n = autocmd_supported(p + 2);
3017 else
3018 n = au_exists(p + 1);
3019#endif
3020 }
3021 else /* internal variable */
3022 {
3023 char_u *tofree;
3024 typval_T tv;
3025
3026 /* get_name_len() takes care of expanding curly braces */
3027 name = p;
3028 len = get_name_len(&p, &tofree, TRUE, FALSE);
3029 if (len > 0)
3030 {
3031 if (tofree != NULL)
3032 name = tofree;
3033 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
3034 if (n)
3035 {
3036 /* handle d.key, l[idx], f(expr) */
3037 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
3038 if (n)
3039 clear_tv(&tv);
3040 }
3041 }
3042 if (*p != NUL)
3043 n = FALSE;
3044
3045 vim_free(tofree);
3046 }
3047
3048 rettv->vval.v_number = n;
3049}
3050
3051#ifdef FEAT_FLOAT
3052/*
3053 * "exp()" function
3054 */
3055 static void
3056f_exp(typval_T *argvars, typval_T *rettv)
3057{
3058 float_T f = 0.0;
3059
3060 rettv->v_type = VAR_FLOAT;
3061 if (get_float_arg(argvars, &f) == OK)
3062 rettv->vval.v_float = exp(f);
3063 else
3064 rettv->vval.v_float = 0.0;
3065}
3066#endif
3067
3068/*
3069 * "expand()" function
3070 */
3071 static void
3072f_expand(typval_T *argvars, typval_T *rettv)
3073{
3074 char_u *s;
3075 int len;
3076 char_u *errormsg;
3077 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3078 expand_T xpc;
3079 int error = FALSE;
3080 char_u *result;
3081
3082 rettv->v_type = VAR_STRING;
3083 if (argvars[1].v_type != VAR_UNKNOWN
3084 && argvars[2].v_type != VAR_UNKNOWN
3085 && get_tv_number_chk(&argvars[2], &error)
3086 && !error)
3087 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003088 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003089 }
3090
3091 s = get_tv_string(&argvars[0]);
3092 if (*s == '%' || *s == '#' || *s == '<')
3093 {
3094 ++emsg_off;
3095 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3096 --emsg_off;
3097 if (rettv->v_type == VAR_LIST)
3098 {
3099 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3100 list_append_string(rettv->vval.v_list, result, -1);
3101 else
3102 vim_free(result);
3103 }
3104 else
3105 rettv->vval.v_string = result;
3106 }
3107 else
3108 {
3109 /* When the optional second argument is non-zero, don't remove matches
3110 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3111 if (argvars[1].v_type != VAR_UNKNOWN
3112 && get_tv_number_chk(&argvars[1], &error))
3113 options |= WILD_KEEP_ALL;
3114 if (!error)
3115 {
3116 ExpandInit(&xpc);
3117 xpc.xp_context = EXPAND_FILES;
3118 if (p_wic)
3119 options += WILD_ICASE;
3120 if (rettv->v_type == VAR_STRING)
3121 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3122 options, WILD_ALL);
3123 else if (rettv_list_alloc(rettv) != FAIL)
3124 {
3125 int i;
3126
3127 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3128 for (i = 0; i < xpc.xp_numfiles; i++)
3129 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3130 ExpandCleanup(&xpc);
3131 }
3132 }
3133 else
3134 rettv->vval.v_string = NULL;
3135 }
3136}
3137
3138/*
3139 * "extend(list, list [, idx])" function
3140 * "extend(dict, dict [, action])" function
3141 */
3142 static void
3143f_extend(typval_T *argvars, typval_T *rettv)
3144{
3145 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3146
3147 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3148 {
3149 list_T *l1, *l2;
3150 listitem_T *item;
3151 long before;
3152 int error = FALSE;
3153
3154 l1 = argvars[0].vval.v_list;
3155 l2 = argvars[1].vval.v_list;
3156 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3157 && l2 != NULL)
3158 {
3159 if (argvars[2].v_type != VAR_UNKNOWN)
3160 {
3161 before = (long)get_tv_number_chk(&argvars[2], &error);
3162 if (error)
3163 return; /* type error; errmsg already given */
3164
3165 if (before == l1->lv_len)
3166 item = NULL;
3167 else
3168 {
3169 item = list_find(l1, before);
3170 if (item == NULL)
3171 {
3172 EMSGN(_(e_listidx), before);
3173 return;
3174 }
3175 }
3176 }
3177 else
3178 item = NULL;
3179 list_extend(l1, l2, item);
3180
3181 copy_tv(&argvars[0], rettv);
3182 }
3183 }
3184 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3185 {
3186 dict_T *d1, *d2;
3187 char_u *action;
3188 int i;
3189
3190 d1 = argvars[0].vval.v_dict;
3191 d2 = argvars[1].vval.v_dict;
3192 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3193 && d2 != NULL)
3194 {
3195 /* Check the third argument. */
3196 if (argvars[2].v_type != VAR_UNKNOWN)
3197 {
3198 static char *(av[]) = {"keep", "force", "error"};
3199
3200 action = get_tv_string_chk(&argvars[2]);
3201 if (action == NULL)
3202 return; /* type error; errmsg already given */
3203 for (i = 0; i < 3; ++i)
3204 if (STRCMP(action, av[i]) == 0)
3205 break;
3206 if (i == 3)
3207 {
3208 EMSG2(_(e_invarg2), action);
3209 return;
3210 }
3211 }
3212 else
3213 action = (char_u *)"force";
3214
3215 dict_extend(d1, d2, action);
3216
3217 copy_tv(&argvars[0], rettv);
3218 }
3219 }
3220 else
3221 EMSG2(_(e_listdictarg), "extend()");
3222}
3223
3224/*
3225 * "feedkeys()" function
3226 */
3227 static void
3228f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3229{
3230 int remap = TRUE;
3231 int insert = FALSE;
3232 char_u *keys, *flags;
3233 char_u nbuf[NUMBUFLEN];
3234 int typed = FALSE;
3235 int execute = FALSE;
3236 int dangerous = FALSE;
3237 char_u *keys_esc;
3238
3239 /* This is not allowed in the sandbox. If the commands would still be
3240 * executed in the sandbox it would be OK, but it probably happens later,
3241 * when "sandbox" is no longer set. */
3242 if (check_secure())
3243 return;
3244
3245 keys = get_tv_string(&argvars[0]);
3246
3247 if (argvars[1].v_type != VAR_UNKNOWN)
3248 {
3249 flags = get_tv_string_buf(&argvars[1], nbuf);
3250 for ( ; *flags != NUL; ++flags)
3251 {
3252 switch (*flags)
3253 {
3254 case 'n': remap = FALSE; break;
3255 case 'm': remap = TRUE; break;
3256 case 't': typed = TRUE; break;
3257 case 'i': insert = TRUE; break;
3258 case 'x': execute = TRUE; break;
3259 case '!': dangerous = TRUE; break;
3260 }
3261 }
3262 }
3263
3264 if (*keys != NUL || execute)
3265 {
3266 /* Need to escape K_SPECIAL and CSI before putting the string in the
3267 * typeahead buffer. */
3268 keys_esc = vim_strsave_escape_csi(keys);
3269 if (keys_esc != NULL)
3270 {
3271 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3272 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3273 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003274 if (vgetc_busy
3275#ifdef FEAT_TIMERS
3276 || timer_busy
3277#endif
3278 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003279 typebuf_was_filled = TRUE;
3280 if (execute)
3281 {
3282 int save_msg_scroll = msg_scroll;
3283
3284 /* Avoid a 1 second delay when the keys start Insert mode. */
3285 msg_scroll = FALSE;
3286
Bram Moolenaar69fbc9e2017-09-14 20:37:57 +02003287#ifdef FEAT_TERMINAL
3288 if (term_use_loop())
3289 terminal_loop(FALSE);
3290 else
3291#endif
3292 {
3293 if (!dangerous)
3294 ++ex_normal_busy;
3295 exec_normal(TRUE);
3296 if (!dangerous)
3297 --ex_normal_busy;
3298 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299 msg_scroll |= save_msg_scroll;
3300 }
3301 }
3302 }
3303}
3304
3305/*
3306 * "filereadable()" function
3307 */
3308 static void
3309f_filereadable(typval_T *argvars, typval_T *rettv)
3310{
3311 int fd;
3312 char_u *p;
3313 int n;
3314
3315#ifndef O_NONBLOCK
3316# define O_NONBLOCK 0
3317#endif
3318 p = get_tv_string(&argvars[0]);
3319 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3320 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3321 {
3322 n = TRUE;
3323 close(fd);
3324 }
3325 else
3326 n = FALSE;
3327
3328 rettv->vval.v_number = n;
3329}
3330
3331/*
3332 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3333 * rights to write into.
3334 */
3335 static void
3336f_filewritable(typval_T *argvars, typval_T *rettv)
3337{
3338 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3339}
3340
3341 static void
3342findfilendir(
3343 typval_T *argvars UNUSED,
3344 typval_T *rettv,
3345 int find_what UNUSED)
3346{
3347#ifdef FEAT_SEARCHPATH
3348 char_u *fname;
3349 char_u *fresult = NULL;
3350 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3351 char_u *p;
3352 char_u pathbuf[NUMBUFLEN];
3353 int count = 1;
3354 int first = TRUE;
3355 int error = FALSE;
3356#endif
3357
3358 rettv->vval.v_string = NULL;
3359 rettv->v_type = VAR_STRING;
3360
3361#ifdef FEAT_SEARCHPATH
3362 fname = get_tv_string(&argvars[0]);
3363
3364 if (argvars[1].v_type != VAR_UNKNOWN)
3365 {
3366 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3367 if (p == NULL)
3368 error = TRUE;
3369 else
3370 {
3371 if (*p != NUL)
3372 path = p;
3373
3374 if (argvars[2].v_type != VAR_UNKNOWN)
3375 count = (int)get_tv_number_chk(&argvars[2], &error);
3376 }
3377 }
3378
3379 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3380 error = TRUE;
3381
3382 if (*fname != NUL && !error)
3383 {
3384 do
3385 {
3386 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3387 vim_free(fresult);
3388 fresult = find_file_in_path_option(first ? fname : NULL,
3389 first ? (int)STRLEN(fname) : 0,
3390 0, first, path,
3391 find_what,
3392 curbuf->b_ffname,
3393 find_what == FINDFILE_DIR
3394 ? (char_u *)"" : curbuf->b_p_sua);
3395 first = FALSE;
3396
3397 if (fresult != NULL && rettv->v_type == VAR_LIST)
3398 list_append_string(rettv->vval.v_list, fresult, -1);
3399
3400 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3401 }
3402
3403 if (rettv->v_type == VAR_STRING)
3404 rettv->vval.v_string = fresult;
3405#endif
3406}
3407
3408/*
3409 * "filter()" function
3410 */
3411 static void
3412f_filter(typval_T *argvars, typval_T *rettv)
3413{
3414 filter_map(argvars, rettv, FALSE);
3415}
3416
3417/*
3418 * "finddir({fname}[, {path}[, {count}]])" function
3419 */
3420 static void
3421f_finddir(typval_T *argvars, typval_T *rettv)
3422{
3423 findfilendir(argvars, rettv, FINDFILE_DIR);
3424}
3425
3426/*
3427 * "findfile({fname}[, {path}[, {count}]])" function
3428 */
3429 static void
3430f_findfile(typval_T *argvars, typval_T *rettv)
3431{
3432 findfilendir(argvars, rettv, FINDFILE_FILE);
3433}
3434
3435#ifdef FEAT_FLOAT
3436/*
3437 * "float2nr({float})" function
3438 */
3439 static void
3440f_float2nr(typval_T *argvars, typval_T *rettv)
3441{
3442 float_T f = 0.0;
3443
3444 if (get_float_arg(argvars, &f) == OK)
3445 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003446 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003447 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003448 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003449 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003450 else
3451 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003452 }
3453}
3454
3455/*
3456 * "floor({float})" function
3457 */
3458 static void
3459f_floor(typval_T *argvars, typval_T *rettv)
3460{
3461 float_T f = 0.0;
3462
3463 rettv->v_type = VAR_FLOAT;
3464 if (get_float_arg(argvars, &f) == OK)
3465 rettv->vval.v_float = floor(f);
3466 else
3467 rettv->vval.v_float = 0.0;
3468}
3469
3470/*
3471 * "fmod()" function
3472 */
3473 static void
3474f_fmod(typval_T *argvars, typval_T *rettv)
3475{
3476 float_T fx = 0.0, fy = 0.0;
3477
3478 rettv->v_type = VAR_FLOAT;
3479 if (get_float_arg(argvars, &fx) == OK
3480 && get_float_arg(&argvars[1], &fy) == OK)
3481 rettv->vval.v_float = fmod(fx, fy);
3482 else
3483 rettv->vval.v_float = 0.0;
3484}
3485#endif
3486
3487/*
3488 * "fnameescape({string})" function
3489 */
3490 static void
3491f_fnameescape(typval_T *argvars, typval_T *rettv)
3492{
3493 rettv->vval.v_string = vim_strsave_fnameescape(
3494 get_tv_string(&argvars[0]), FALSE);
3495 rettv->v_type = VAR_STRING;
3496}
3497
3498/*
3499 * "fnamemodify({fname}, {mods})" function
3500 */
3501 static void
3502f_fnamemodify(typval_T *argvars, typval_T *rettv)
3503{
3504 char_u *fname;
3505 char_u *mods;
3506 int usedlen = 0;
3507 int len;
3508 char_u *fbuf = NULL;
3509 char_u buf[NUMBUFLEN];
3510
3511 fname = get_tv_string_chk(&argvars[0]);
3512 mods = get_tv_string_buf_chk(&argvars[1], buf);
3513 if (fname == NULL || mods == NULL)
3514 fname = NULL;
3515 else
3516 {
3517 len = (int)STRLEN(fname);
3518 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3519 }
3520
3521 rettv->v_type = VAR_STRING;
3522 if (fname == NULL)
3523 rettv->vval.v_string = NULL;
3524 else
3525 rettv->vval.v_string = vim_strnsave(fname, len);
3526 vim_free(fbuf);
3527}
3528
3529static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3530
3531/*
3532 * "foldclosed()" function
3533 */
3534 static void
3535foldclosed_both(
3536 typval_T *argvars UNUSED,
3537 typval_T *rettv,
3538 int end UNUSED)
3539{
3540#ifdef FEAT_FOLDING
3541 linenr_T lnum;
3542 linenr_T first, last;
3543
3544 lnum = get_tv_lnum(argvars);
3545 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3546 {
3547 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3548 {
3549 if (end)
3550 rettv->vval.v_number = (varnumber_T)last;
3551 else
3552 rettv->vval.v_number = (varnumber_T)first;
3553 return;
3554 }
3555 }
3556#endif
3557 rettv->vval.v_number = -1;
3558}
3559
3560/*
3561 * "foldclosed()" function
3562 */
3563 static void
3564f_foldclosed(typval_T *argvars, typval_T *rettv)
3565{
3566 foldclosed_both(argvars, rettv, FALSE);
3567}
3568
3569/*
3570 * "foldclosedend()" function
3571 */
3572 static void
3573f_foldclosedend(typval_T *argvars, typval_T *rettv)
3574{
3575 foldclosed_both(argvars, rettv, TRUE);
3576}
3577
3578/*
3579 * "foldlevel()" function
3580 */
3581 static void
3582f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3583{
3584#ifdef FEAT_FOLDING
3585 linenr_T lnum;
3586
3587 lnum = get_tv_lnum(argvars);
3588 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3589 rettv->vval.v_number = foldLevel(lnum);
3590#endif
3591}
3592
3593/*
3594 * "foldtext()" function
3595 */
3596 static void
3597f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3598{
3599#ifdef FEAT_FOLDING
3600 linenr_T foldstart;
3601 linenr_T foldend;
3602 char_u *dashes;
3603 linenr_T lnum;
3604 char_u *s;
3605 char_u *r;
3606 int len;
3607 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003608 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003609#endif
3610
3611 rettv->v_type = VAR_STRING;
3612 rettv->vval.v_string = NULL;
3613#ifdef FEAT_FOLDING
3614 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3615 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3616 dashes = get_vim_var_str(VV_FOLDDASHES);
3617 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3618 && dashes != NULL)
3619 {
3620 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003621 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003622 if (!linewhite(lnum))
3623 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003624
3625 /* Find interesting text in this line. */
3626 s = skipwhite(ml_get(lnum));
3627 /* skip C comment-start */
3628 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3629 {
3630 s = skipwhite(s + 2);
3631 if (*skipwhite(s) == NUL
3632 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3633 {
3634 s = skipwhite(ml_get(lnum + 1));
3635 if (*s == '*')
3636 s = skipwhite(s + 1);
3637 }
3638 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003639 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003640 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003641 r = alloc((unsigned)(STRLEN(txt)
3642 + STRLEN(dashes) /* for %s */
3643 + 20 /* for %3ld */
3644 + STRLEN(s))); /* concatenated */
3645 if (r != NULL)
3646 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003647 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003648 len = (int)STRLEN(r);
3649 STRCAT(r, s);
3650 /* remove 'foldmarker' and 'commentstring' */
3651 foldtext_cleanup(r + len);
3652 rettv->vval.v_string = r;
3653 }
3654 }
3655#endif
3656}
3657
3658/*
3659 * "foldtextresult(lnum)" function
3660 */
3661 static void
3662f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3663{
3664#ifdef FEAT_FOLDING
3665 linenr_T lnum;
3666 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003667 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003668 foldinfo_T foldinfo;
3669 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003670 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003671#endif
3672
3673 rettv->v_type = VAR_STRING;
3674 rettv->vval.v_string = NULL;
3675#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003676 if (entered)
3677 return; /* reject recursive use */
3678 entered = TRUE;
3679
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003680 lnum = get_tv_lnum(argvars);
3681 /* treat illegal types and illegal string values for {lnum} the same */
3682 if (lnum < 0)
3683 lnum = 0;
3684 fold_count = foldedCount(curwin, lnum, &foldinfo);
3685 if (fold_count > 0)
3686 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003687 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3688 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003689 if (text == buf)
3690 text = vim_strsave(text);
3691 rettv->vval.v_string = text;
3692 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003693
3694 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003695#endif
3696}
3697
3698/*
3699 * "foreground()" function
3700 */
3701 static void
3702f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3703{
3704#ifdef FEAT_GUI
3705 if (gui.in_use)
3706 gui_mch_set_foreground();
3707#else
3708# ifdef WIN32
3709 win32_set_foreground();
3710# endif
3711#endif
3712}
3713
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003715common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003716{
3717 char_u *s;
3718 char_u *name;
3719 int use_string = FALSE;
3720 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003721 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722
3723 if (argvars[0].v_type == VAR_FUNC)
3724 {
3725 /* function(MyFunc, [arg], dict) */
3726 s = argvars[0].vval.v_string;
3727 }
3728 else if (argvars[0].v_type == VAR_PARTIAL
3729 && argvars[0].vval.v_partial != NULL)
3730 {
3731 /* function(dict.MyFunc, [arg]) */
3732 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003733 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003734 }
3735 else
3736 {
3737 /* function('MyFunc', [arg], dict) */
3738 s = get_tv_string(&argvars[0]);
3739 use_string = TRUE;
3740 }
3741
Bram Moolenaar843b8842016-08-21 14:36:15 +02003742 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003743 {
3744 name = s;
3745 trans_name = trans_function_name(&name, FALSE,
3746 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3747 if (*name != NUL)
3748 s = NULL;
3749 }
3750
Bram Moolenaar843b8842016-08-21 14:36:15 +02003751 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3752 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003753 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003754 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003755 else if (trans_name != NULL && (is_funcref
3756 ? find_func(trans_name) == NULL
3757 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003758 EMSG2(_("E700: Unknown function: %s"), s);
3759 else
3760 {
3761 int dict_idx = 0;
3762 int arg_idx = 0;
3763 list_T *list = NULL;
3764
3765 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3766 {
3767 char sid_buf[25];
3768 int off = *s == 's' ? 2 : 5;
3769
3770 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3771 * also be called from another script. Using trans_function_name()
3772 * would also work, but some plugins depend on the name being
3773 * printable text. */
3774 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3775 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3776 if (name != NULL)
3777 {
3778 STRCPY(name, sid_buf);
3779 STRCAT(name, s + off);
3780 }
3781 }
3782 else
3783 name = vim_strsave(s);
3784
3785 if (argvars[1].v_type != VAR_UNKNOWN)
3786 {
3787 if (argvars[2].v_type != VAR_UNKNOWN)
3788 {
3789 /* function(name, [args], dict) */
3790 arg_idx = 1;
3791 dict_idx = 2;
3792 }
3793 else if (argvars[1].v_type == VAR_DICT)
3794 /* function(name, dict) */
3795 dict_idx = 1;
3796 else
3797 /* function(name, [args]) */
3798 arg_idx = 1;
3799 if (dict_idx > 0)
3800 {
3801 if (argvars[dict_idx].v_type != VAR_DICT)
3802 {
3803 EMSG(_("E922: expected a dict"));
3804 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003805 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003806 }
3807 if (argvars[dict_idx].vval.v_dict == NULL)
3808 dict_idx = 0;
3809 }
3810 if (arg_idx > 0)
3811 {
3812 if (argvars[arg_idx].v_type != VAR_LIST)
3813 {
3814 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3815 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003816 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003817 }
3818 list = argvars[arg_idx].vval.v_list;
3819 if (list == NULL || list->lv_len == 0)
3820 arg_idx = 0;
3821 }
3822 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003823 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003824 {
3825 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3826
3827 /* result is a VAR_PARTIAL */
3828 if (pt == NULL)
3829 vim_free(name);
3830 else
3831 {
3832 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3833 {
3834 listitem_T *li;
3835 int i = 0;
3836 int arg_len = 0;
3837 int lv_len = 0;
3838
3839 if (arg_pt != NULL)
3840 arg_len = arg_pt->pt_argc;
3841 if (list != NULL)
3842 lv_len = list->lv_len;
3843 pt->pt_argc = arg_len + lv_len;
3844 pt->pt_argv = (typval_T *)alloc(
3845 sizeof(typval_T) * pt->pt_argc);
3846 if (pt->pt_argv == NULL)
3847 {
3848 vim_free(pt);
3849 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003850 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003851 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003852 for (i = 0; i < arg_len; i++)
3853 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3854 if (lv_len > 0)
3855 for (li = list->lv_first; li != NULL;
3856 li = li->li_next)
3857 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003858 }
3859
3860 /* For "function(dict.func, [], dict)" and "func" is a partial
3861 * use "dict". That is backwards compatible. */
3862 if (dict_idx > 0)
3863 {
3864 /* The dict is bound explicitly, pt_auto is FALSE. */
3865 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3866 ++pt->pt_dict->dv_refcount;
3867 }
3868 else if (arg_pt != NULL)
3869 {
3870 /* If the dict was bound automatically the result is also
3871 * bound automatically. */
3872 pt->pt_dict = arg_pt->pt_dict;
3873 pt->pt_auto = arg_pt->pt_auto;
3874 if (pt->pt_dict != NULL)
3875 ++pt->pt_dict->dv_refcount;
3876 }
3877
3878 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003879 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3880 {
3881 pt->pt_func = arg_pt->pt_func;
3882 func_ptr_ref(pt->pt_func);
3883 vim_free(name);
3884 }
3885 else if (is_funcref)
3886 {
3887 pt->pt_func = find_func(trans_name);
3888 func_ptr_ref(pt->pt_func);
3889 vim_free(name);
3890 }
3891 else
3892 {
3893 pt->pt_name = name;
3894 func_ref(name);
3895 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003896 }
3897 rettv->v_type = VAR_PARTIAL;
3898 rettv->vval.v_partial = pt;
3899 }
3900 else
3901 {
3902 /* result is a VAR_FUNC */
3903 rettv->v_type = VAR_FUNC;
3904 rettv->vval.v_string = name;
3905 func_ref(name);
3906 }
3907 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003908theend:
3909 vim_free(trans_name);
3910}
3911
3912/*
3913 * "funcref()" function
3914 */
3915 static void
3916f_funcref(typval_T *argvars, typval_T *rettv)
3917{
3918 common_function(argvars, rettv, TRUE);
3919}
3920
3921/*
3922 * "function()" function
3923 */
3924 static void
3925f_function(typval_T *argvars, typval_T *rettv)
3926{
3927 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003928}
3929
3930/*
3931 * "garbagecollect()" function
3932 */
3933 static void
3934f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3935{
3936 /* This is postponed until we are back at the toplevel, because we may be
3937 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3938 want_garbage_collect = TRUE;
3939
3940 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3941 garbage_collect_at_exit = TRUE;
3942}
3943
3944/*
3945 * "get()" function
3946 */
3947 static void
3948f_get(typval_T *argvars, typval_T *rettv)
3949{
3950 listitem_T *li;
3951 list_T *l;
3952 dictitem_T *di;
3953 dict_T *d;
3954 typval_T *tv = NULL;
3955
3956 if (argvars[0].v_type == VAR_LIST)
3957 {
3958 if ((l = argvars[0].vval.v_list) != NULL)
3959 {
3960 int error = FALSE;
3961
3962 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3963 if (!error && li != NULL)
3964 tv = &li->li_tv;
3965 }
3966 }
3967 else if (argvars[0].v_type == VAR_DICT)
3968 {
3969 if ((d = argvars[0].vval.v_dict) != NULL)
3970 {
3971 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3972 if (di != NULL)
3973 tv = &di->di_tv;
3974 }
3975 }
3976 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3977 {
3978 partial_T *pt;
3979 partial_T fref_pt;
3980
3981 if (argvars[0].v_type == VAR_PARTIAL)
3982 pt = argvars[0].vval.v_partial;
3983 else
3984 {
3985 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3986 fref_pt.pt_name = argvars[0].vval.v_string;
3987 pt = &fref_pt;
3988 }
3989
3990 if (pt != NULL)
3991 {
3992 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003993 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003994
3995 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3996 {
3997 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003998 n = partial_name(pt);
3999 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004000 rettv->vval.v_string = NULL;
4001 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004002 {
4003 rettv->vval.v_string = vim_strsave(n);
4004 if (rettv->v_type == VAR_FUNC)
4005 func_ref(rettv->vval.v_string);
4006 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007 }
4008 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004009 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004010 else if (STRCMP(what, "args") == 0)
4011 {
4012 rettv->v_type = VAR_LIST;
4013 if (rettv_list_alloc(rettv) == OK)
4014 {
4015 int i;
4016
4017 for (i = 0; i < pt->pt_argc; ++i)
4018 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4019 }
4020 }
4021 else
4022 EMSG2(_(e_invarg2), what);
4023 return;
4024 }
4025 }
4026 else
4027 EMSG2(_(e_listdictarg), "get()");
4028
4029 if (tv == NULL)
4030 {
4031 if (argvars[2].v_type != VAR_UNKNOWN)
4032 copy_tv(&argvars[2], rettv);
4033 }
4034 else
4035 copy_tv(tv, rettv);
4036}
4037
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004038#ifdef FEAT_SIGNS
4039/*
4040 * Returns information about signs placed in a buffer as list of dicts.
4041 */
4042 static void
4043get_buffer_signs(buf_T *buf, list_T *l)
4044{
4045 signlist_T *sign;
4046
4047 for (sign = buf->b_signlist; sign; sign = sign->next)
4048 {
4049 dict_T *d = dict_alloc();
4050
4051 if (d != NULL)
4052 {
4053 dict_add_nr_str(d, "id", sign->id, NULL);
4054 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004055 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004056
4057 list_append_dict(l, d);
4058 }
4059 }
4060}
4061#endif
4062
4063/*
4064 * Returns buffer options, variables and other attributes in a dictionary.
4065 */
4066 static dict_T *
4067get_buffer_info(buf_T *buf)
4068{
4069 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004070 tabpage_T *tp;
4071 win_T *wp;
4072 list_T *windows;
4073
4074 dict = dict_alloc();
4075 if (dict == NULL)
4076 return NULL;
4077
Bram Moolenaar33928832016-08-18 21:22:04 +02004078 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004079 dict_add_nr_str(dict, "name", 0L,
4080 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004081 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4082 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004083 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4084 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4085 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004086 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004087 dict_add_nr_str(dict, "hidden",
4088 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4089 NULL);
4090
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004091 /* Get a reference to buffer variables */
4092 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004093
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004094 /* List of windows displaying this buffer */
4095 windows = list_alloc();
4096 if (windows != NULL)
4097 {
4098 FOR_ALL_TAB_WINDOWS(tp, wp)
4099 if (wp->w_buffer == buf)
4100 list_append_number(windows, (varnumber_T)wp->w_id);
4101 dict_add_list(dict, "windows", windows);
4102 }
4103
4104#ifdef FEAT_SIGNS
4105 if (buf->b_signlist != NULL)
4106 {
4107 /* List of signs placed in this buffer */
4108 list_T *signs = list_alloc();
4109 if (signs != NULL)
4110 {
4111 get_buffer_signs(buf, signs);
4112 dict_add_list(dict, "signs", signs);
4113 }
4114 }
4115#endif
4116
4117 return dict;
4118}
4119
4120/*
4121 * "getbufinfo()" function
4122 */
4123 static void
4124f_getbufinfo(typval_T *argvars, typval_T *rettv)
4125{
4126 buf_T *buf = NULL;
4127 buf_T *argbuf = NULL;
4128 dict_T *d;
4129 int filtered = FALSE;
4130 int sel_buflisted = FALSE;
4131 int sel_bufloaded = FALSE;
4132
4133 if (rettv_list_alloc(rettv) != OK)
4134 return;
4135
4136 /* List of all the buffers or selected buffers */
4137 if (argvars[0].v_type == VAR_DICT)
4138 {
4139 dict_T *sel_d = argvars[0].vval.v_dict;
4140
4141 if (sel_d != NULL)
4142 {
4143 dictitem_T *di;
4144
4145 filtered = TRUE;
4146
4147 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4148 if (di != NULL && get_tv_number(&di->di_tv))
4149 sel_buflisted = TRUE;
4150
4151 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4152 if (di != NULL && get_tv_number(&di->di_tv))
4153 sel_bufloaded = TRUE;
4154 }
4155 }
4156 else if (argvars[0].v_type != VAR_UNKNOWN)
4157 {
4158 /* Information about one buffer. Argument specifies the buffer */
4159 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4160 ++emsg_off;
4161 argbuf = get_buf_tv(&argvars[0], FALSE);
4162 --emsg_off;
4163 if (argbuf == NULL)
4164 return;
4165 }
4166
4167 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004168 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004169 {
4170 if (argbuf != NULL && argbuf != buf)
4171 continue;
4172 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
4173 || (sel_buflisted && !buf->b_p_bl)))
4174 continue;
4175
4176 d = get_buffer_info(buf);
4177 if (d != NULL)
4178 list_append_dict(rettv->vval.v_list, d);
4179 if (argbuf != NULL)
4180 return;
4181 }
4182}
4183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004184static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4185
4186/*
4187 * Get line or list of lines from buffer "buf" into "rettv".
4188 * Return a range (from start to end) of lines in rettv from the specified
4189 * buffer.
4190 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4191 */
4192 static void
4193get_buffer_lines(
4194 buf_T *buf,
4195 linenr_T start,
4196 linenr_T end,
4197 int retlist,
4198 typval_T *rettv)
4199{
4200 char_u *p;
4201
4202 rettv->v_type = VAR_STRING;
4203 rettv->vval.v_string = NULL;
4204 if (retlist && rettv_list_alloc(rettv) == FAIL)
4205 return;
4206
4207 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4208 return;
4209
4210 if (!retlist)
4211 {
4212 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4213 p = ml_get_buf(buf, start, FALSE);
4214 else
4215 p = (char_u *)"";
4216 rettv->vval.v_string = vim_strsave(p);
4217 }
4218 else
4219 {
4220 if (end < start)
4221 return;
4222
4223 if (start < 1)
4224 start = 1;
4225 if (end > buf->b_ml.ml_line_count)
4226 end = buf->b_ml.ml_line_count;
4227 while (start <= end)
4228 if (list_append_string(rettv->vval.v_list,
4229 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4230 break;
4231 }
4232}
4233
4234/*
4235 * Get the lnum from the first argument.
4236 * Also accepts "$", then "buf" is used.
4237 * Returns 0 on error.
4238 */
4239 static linenr_T
4240get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4241{
4242 if (argvars[0].v_type == VAR_STRING
4243 && argvars[0].vval.v_string != NULL
4244 && argvars[0].vval.v_string[0] == '$'
4245 && buf != NULL)
4246 return buf->b_ml.ml_line_count;
4247 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4248}
4249
4250/*
4251 * "getbufline()" function
4252 */
4253 static void
4254f_getbufline(typval_T *argvars, typval_T *rettv)
4255{
4256 linenr_T lnum;
4257 linenr_T end;
4258 buf_T *buf;
4259
4260 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4261 ++emsg_off;
4262 buf = get_buf_tv(&argvars[0], FALSE);
4263 --emsg_off;
4264
4265 lnum = get_tv_lnum_buf(&argvars[1], buf);
4266 if (argvars[2].v_type == VAR_UNKNOWN)
4267 end = lnum;
4268 else
4269 end = get_tv_lnum_buf(&argvars[2], buf);
4270
4271 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4272}
4273
4274/*
4275 * "getbufvar()" function
4276 */
4277 static void
4278f_getbufvar(typval_T *argvars, typval_T *rettv)
4279{
4280 buf_T *buf;
4281 buf_T *save_curbuf;
4282 char_u *varname;
4283 dictitem_T *v;
4284 int done = FALSE;
4285
4286 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4287 varname = get_tv_string_chk(&argvars[1]);
4288 ++emsg_off;
4289 buf = get_buf_tv(&argvars[0], FALSE);
4290
4291 rettv->v_type = VAR_STRING;
4292 rettv->vval.v_string = NULL;
4293
4294 if (buf != NULL && varname != NULL)
4295 {
4296 /* set curbuf to be our buf, temporarily */
4297 save_curbuf = curbuf;
4298 curbuf = buf;
4299
Bram Moolenaar30567352016-08-27 21:25:44 +02004300 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004301 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004302 if (varname[1] == NUL)
4303 {
4304 /* get all buffer-local options in a dict */
4305 dict_T *opts = get_winbuf_options(TRUE);
4306
4307 if (opts != NULL)
4308 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004309 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004310 done = TRUE;
4311 }
4312 }
4313 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4314 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004315 done = TRUE;
4316 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004317 else
4318 {
4319 /* Look up the variable. */
4320 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4321 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4322 'b', varname, FALSE);
4323 if (v != NULL)
4324 {
4325 copy_tv(&v->di_tv, rettv);
4326 done = TRUE;
4327 }
4328 }
4329
4330 /* restore previous notion of curbuf */
4331 curbuf = save_curbuf;
4332 }
4333
4334 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4335 /* use the default value */
4336 copy_tv(&argvars[2], rettv);
4337
4338 --emsg_off;
4339}
4340
4341/*
4342 * "getchar()" function
4343 */
4344 static void
4345f_getchar(typval_T *argvars, typval_T *rettv)
4346{
4347 varnumber_T n;
4348 int error = FALSE;
4349
4350 /* Position the cursor. Needed after a message that ends in a space. */
4351 windgoto(msg_row, msg_col);
4352
4353 ++no_mapping;
4354 ++allow_keys;
4355 for (;;)
4356 {
4357 if (argvars[0].v_type == VAR_UNKNOWN)
4358 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004359 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004360 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4361 /* getchar(1): only check if char avail */
4362 n = vpeekc_any();
4363 else if (error || vpeekc_any() == NUL)
4364 /* illegal argument or getchar(0) and no char avail: return zero */
4365 n = 0;
4366 else
4367 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004368 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004369
4370 if (n == K_IGNORE)
4371 continue;
4372 break;
4373 }
4374 --no_mapping;
4375 --allow_keys;
4376
4377 set_vim_var_nr(VV_MOUSE_WIN, 0);
4378 set_vim_var_nr(VV_MOUSE_WINID, 0);
4379 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4380 set_vim_var_nr(VV_MOUSE_COL, 0);
4381
4382 rettv->vval.v_number = n;
4383 if (IS_SPECIAL(n) || mod_mask != 0)
4384 {
4385 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4386 int i = 0;
4387
4388 /* Turn a special key into three bytes, plus modifier. */
4389 if (mod_mask != 0)
4390 {
4391 temp[i++] = K_SPECIAL;
4392 temp[i++] = KS_MODIFIER;
4393 temp[i++] = mod_mask;
4394 }
4395 if (IS_SPECIAL(n))
4396 {
4397 temp[i++] = K_SPECIAL;
4398 temp[i++] = K_SECOND(n);
4399 temp[i++] = K_THIRD(n);
4400 }
4401#ifdef FEAT_MBYTE
4402 else if (has_mbyte)
4403 i += (*mb_char2bytes)(n, temp + i);
4404#endif
4405 else
4406 temp[i++] = n;
4407 temp[i++] = NUL;
4408 rettv->v_type = VAR_STRING;
4409 rettv->vval.v_string = vim_strsave(temp);
4410
4411#ifdef FEAT_MOUSE
4412 if (is_mouse_key(n))
4413 {
4414 int row = mouse_row;
4415 int col = mouse_col;
4416 win_T *win;
4417 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004418 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004419 int winnr = 1;
4420
4421 if (row >= 0 && col >= 0)
4422 {
4423 /* Find the window at the mouse coordinates and compute the
4424 * text position. */
4425 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004426 if (win == NULL)
4427 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004428 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004429 for (wp = firstwin; wp != win; wp = wp->w_next)
4430 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004431 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4432 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4433 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4434 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4435 }
4436 }
4437#endif
4438 }
4439}
4440
4441/*
4442 * "getcharmod()" function
4443 */
4444 static void
4445f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4446{
4447 rettv->vval.v_number = mod_mask;
4448}
4449
4450/*
4451 * "getcharsearch()" function
4452 */
4453 static void
4454f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4455{
4456 if (rettv_dict_alloc(rettv) != FAIL)
4457 {
4458 dict_T *dict = rettv->vval.v_dict;
4459
4460 dict_add_nr_str(dict, "char", 0L, last_csearch());
4461 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4462 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4463 }
4464}
4465
4466/*
4467 * "getcmdline()" function
4468 */
4469 static void
4470f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4471{
4472 rettv->v_type = VAR_STRING;
4473 rettv->vval.v_string = get_cmdline_str();
4474}
4475
4476/*
4477 * "getcmdpos()" function
4478 */
4479 static void
4480f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4481{
4482 rettv->vval.v_number = get_cmdline_pos() + 1;
4483}
4484
4485/*
4486 * "getcmdtype()" function
4487 */
4488 static void
4489f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4490{
4491 rettv->v_type = VAR_STRING;
4492 rettv->vval.v_string = alloc(2);
4493 if (rettv->vval.v_string != NULL)
4494 {
4495 rettv->vval.v_string[0] = get_cmdline_type();
4496 rettv->vval.v_string[1] = NUL;
4497 }
4498}
4499
4500/*
4501 * "getcmdwintype()" function
4502 */
4503 static void
4504f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4505{
4506 rettv->v_type = VAR_STRING;
4507 rettv->vval.v_string = NULL;
4508#ifdef FEAT_CMDWIN
4509 rettv->vval.v_string = alloc(2);
4510 if (rettv->vval.v_string != NULL)
4511 {
4512 rettv->vval.v_string[0] = cmdwin_type;
4513 rettv->vval.v_string[1] = NUL;
4514 }
4515#endif
4516}
4517
4518#if defined(FEAT_CMDL_COMPL)
4519/*
4520 * "getcompletion()" function
4521 */
4522 static void
4523f_getcompletion(typval_T *argvars, typval_T *rettv)
4524{
4525 char_u *pat;
4526 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004527 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004528 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4529 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004530
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004531 if (argvars[2].v_type != VAR_UNKNOWN)
4532 filtered = get_tv_number_chk(&argvars[2], NULL);
4533
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534 if (p_wic)
4535 options |= WILD_ICASE;
4536
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004537 /* For filtered results, 'wildignore' is used */
4538 if (!filtered)
4539 options |= WILD_KEEP_ALL;
4540
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004541 ExpandInit(&xpc);
4542 xpc.xp_pattern = get_tv_string(&argvars[0]);
4543 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4544 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4545 if (xpc.xp_context == EXPAND_NOTHING)
4546 {
4547 if (argvars[1].v_type == VAR_STRING)
4548 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4549 else
4550 EMSG(_(e_invarg));
4551 return;
4552 }
4553
4554# if defined(FEAT_MENU)
4555 if (xpc.xp_context == EXPAND_MENUS)
4556 {
4557 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4558 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4559 }
4560# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004561#ifdef FEAT_CSCOPE
4562 if (xpc.xp_context == EXPAND_CSCOPE)
4563 {
4564 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4565 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4566 }
4567#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004568#ifdef FEAT_SIGNS
4569 if (xpc.xp_context == EXPAND_SIGN)
4570 {
4571 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4572 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4573 }
4574#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004575
4576 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4577 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4578 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004579 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004580
4581 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4582
4583 for (i = 0; i < xpc.xp_numfiles; i++)
4584 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4585 }
4586 vim_free(pat);
4587 ExpandCleanup(&xpc);
4588}
4589#endif
4590
4591/*
4592 * "getcwd()" function
4593 */
4594 static void
4595f_getcwd(typval_T *argvars, typval_T *rettv)
4596{
4597 win_T *wp = NULL;
4598 char_u *cwd;
4599
4600 rettv->v_type = VAR_STRING;
4601 rettv->vval.v_string = NULL;
4602
4603 wp = find_tabwin(&argvars[0], &argvars[1]);
4604 if (wp != NULL)
4605 {
4606 if (wp->w_localdir != NULL)
4607 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4608 else if (globaldir != NULL)
4609 rettv->vval.v_string = vim_strsave(globaldir);
4610 else
4611 {
4612 cwd = alloc(MAXPATHL);
4613 if (cwd != NULL)
4614 {
4615 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4616 rettv->vval.v_string = vim_strsave(cwd);
4617 vim_free(cwd);
4618 }
4619 }
4620#ifdef BACKSLASH_IN_FILENAME
4621 if (rettv->vval.v_string != NULL)
4622 slash_adjust(rettv->vval.v_string);
4623#endif
4624 }
4625}
4626
4627/*
4628 * "getfontname()" function
4629 */
4630 static void
4631f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4632{
4633 rettv->v_type = VAR_STRING;
4634 rettv->vval.v_string = NULL;
4635#ifdef FEAT_GUI
4636 if (gui.in_use)
4637 {
4638 GuiFont font;
4639 char_u *name = NULL;
4640
4641 if (argvars[0].v_type == VAR_UNKNOWN)
4642 {
4643 /* Get the "Normal" font. Either the name saved by
4644 * hl_set_font_name() or from the font ID. */
4645 font = gui.norm_font;
4646 name = hl_get_font_name();
4647 }
4648 else
4649 {
4650 name = get_tv_string(&argvars[0]);
4651 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4652 return;
4653 font = gui_mch_get_font(name, FALSE);
4654 if (font == NOFONT)
4655 return; /* Invalid font name, return empty string. */
4656 }
4657 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4658 if (argvars[0].v_type != VAR_UNKNOWN)
4659 gui_mch_free_font(font);
4660 }
4661#endif
4662}
4663
4664/*
4665 * "getfperm({fname})" function
4666 */
4667 static void
4668f_getfperm(typval_T *argvars, typval_T *rettv)
4669{
4670 char_u *fname;
4671 stat_T st;
4672 char_u *perm = NULL;
4673 char_u flags[] = "rwx";
4674 int i;
4675
4676 fname = get_tv_string(&argvars[0]);
4677
4678 rettv->v_type = VAR_STRING;
4679 if (mch_stat((char *)fname, &st) >= 0)
4680 {
4681 perm = vim_strsave((char_u *)"---------");
4682 if (perm != NULL)
4683 {
4684 for (i = 0; i < 9; i++)
4685 {
4686 if (st.st_mode & (1 << (8 - i)))
4687 perm[i] = flags[i % 3];
4688 }
4689 }
4690 }
4691 rettv->vval.v_string = perm;
4692}
4693
4694/*
4695 * "getfsize({fname})" function
4696 */
4697 static void
4698f_getfsize(typval_T *argvars, typval_T *rettv)
4699{
4700 char_u *fname;
4701 stat_T st;
4702
4703 fname = get_tv_string(&argvars[0]);
4704
4705 rettv->v_type = VAR_NUMBER;
4706
4707 if (mch_stat((char *)fname, &st) >= 0)
4708 {
4709 if (mch_isdir(fname))
4710 rettv->vval.v_number = 0;
4711 else
4712 {
4713 rettv->vval.v_number = (varnumber_T)st.st_size;
4714
4715 /* non-perfect check for overflow */
4716 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4717 rettv->vval.v_number = -2;
4718 }
4719 }
4720 else
4721 rettv->vval.v_number = -1;
4722}
4723
4724/*
4725 * "getftime({fname})" function
4726 */
4727 static void
4728f_getftime(typval_T *argvars, typval_T *rettv)
4729{
4730 char_u *fname;
4731 stat_T st;
4732
4733 fname = get_tv_string(&argvars[0]);
4734
4735 if (mch_stat((char *)fname, &st) >= 0)
4736 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4737 else
4738 rettv->vval.v_number = -1;
4739}
4740
4741/*
4742 * "getftype({fname})" function
4743 */
4744 static void
4745f_getftype(typval_T *argvars, typval_T *rettv)
4746{
4747 char_u *fname;
4748 stat_T st;
4749 char_u *type = NULL;
4750 char *t;
4751
4752 fname = get_tv_string(&argvars[0]);
4753
4754 rettv->v_type = VAR_STRING;
4755 if (mch_lstat((char *)fname, &st) >= 0)
4756 {
4757#ifdef S_ISREG
4758 if (S_ISREG(st.st_mode))
4759 t = "file";
4760 else if (S_ISDIR(st.st_mode))
4761 t = "dir";
4762# ifdef S_ISLNK
4763 else if (S_ISLNK(st.st_mode))
4764 t = "link";
4765# endif
4766# ifdef S_ISBLK
4767 else if (S_ISBLK(st.st_mode))
4768 t = "bdev";
4769# endif
4770# ifdef S_ISCHR
4771 else if (S_ISCHR(st.st_mode))
4772 t = "cdev";
4773# endif
4774# ifdef S_ISFIFO
4775 else if (S_ISFIFO(st.st_mode))
4776 t = "fifo";
4777# endif
4778# ifdef S_ISSOCK
4779 else if (S_ISSOCK(st.st_mode))
4780 t = "fifo";
4781# endif
4782 else
4783 t = "other";
4784#else
4785# ifdef S_IFMT
4786 switch (st.st_mode & S_IFMT)
4787 {
4788 case S_IFREG: t = "file"; break;
4789 case S_IFDIR: t = "dir"; break;
4790# ifdef S_IFLNK
4791 case S_IFLNK: t = "link"; break;
4792# endif
4793# ifdef S_IFBLK
4794 case S_IFBLK: t = "bdev"; break;
4795# endif
4796# ifdef S_IFCHR
4797 case S_IFCHR: t = "cdev"; break;
4798# endif
4799# ifdef S_IFIFO
4800 case S_IFIFO: t = "fifo"; break;
4801# endif
4802# ifdef S_IFSOCK
4803 case S_IFSOCK: t = "socket"; break;
4804# endif
4805 default: t = "other";
4806 }
4807# else
4808 if (mch_isdir(fname))
4809 t = "dir";
4810 else
4811 t = "file";
4812# endif
4813#endif
4814 type = vim_strsave((char_u *)t);
4815 }
4816 rettv->vval.v_string = type;
4817}
4818
4819/*
4820 * "getline(lnum, [end])" function
4821 */
4822 static void
4823f_getline(typval_T *argvars, typval_T *rettv)
4824{
4825 linenr_T lnum;
4826 linenr_T end;
4827 int retlist;
4828
4829 lnum = get_tv_lnum(argvars);
4830 if (argvars[1].v_type == VAR_UNKNOWN)
4831 {
4832 end = 0;
4833 retlist = FALSE;
4834 }
4835 else
4836 {
4837 end = get_tv_lnum(&argvars[1]);
4838 retlist = TRUE;
4839 }
4840
4841 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4842}
4843
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004844#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004845 static void
4846get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4847{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004848 if (what_arg->v_type == VAR_UNKNOWN)
4849 {
4850 if (rettv_list_alloc(rettv) == OK)
4851 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004852 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004853 }
4854 else
4855 {
4856 if (rettv_dict_alloc(rettv) == OK)
4857 if (is_qf || (wp != NULL))
4858 {
4859 if (what_arg->v_type == VAR_DICT)
4860 {
4861 dict_T *d = what_arg->vval.v_dict;
4862
4863 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02004864 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004865 }
4866 else
4867 EMSG(_(e_dictreq));
4868 }
4869 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02004870}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004871#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02004872
4873/*
4874 * "getloclist()" function
4875 */
4876 static void
4877f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4878{
4879#ifdef FEAT_QUICKFIX
4880 win_T *wp;
4881
4882 wp = find_win_by_nr(&argvars[0], NULL);
4883 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
4884#endif
4885}
4886
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004887/*
4888 * "getmatches()" function
4889 */
4890 static void
4891f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4892{
4893#ifdef FEAT_SEARCH_EXTRA
4894 dict_T *dict;
4895 matchitem_T *cur = curwin->w_match_head;
4896 int i;
4897
4898 if (rettv_list_alloc(rettv) == OK)
4899 {
4900 while (cur != NULL)
4901 {
4902 dict = dict_alloc();
4903 if (dict == NULL)
4904 return;
4905 if (cur->match.regprog == NULL)
4906 {
4907 /* match added with matchaddpos() */
4908 for (i = 0; i < MAXPOSMATCH; ++i)
4909 {
4910 llpos_T *llpos;
4911 char buf[6];
4912 list_T *l;
4913
4914 llpos = &cur->pos.pos[i];
4915 if (llpos->lnum == 0)
4916 break;
4917 l = list_alloc();
4918 if (l == NULL)
4919 break;
4920 list_append_number(l, (varnumber_T)llpos->lnum);
4921 if (llpos->col > 0)
4922 {
4923 list_append_number(l, (varnumber_T)llpos->col);
4924 list_append_number(l, (varnumber_T)llpos->len);
4925 }
4926 sprintf(buf, "pos%d", i + 1);
4927 dict_add_list(dict, buf, l);
4928 }
4929 }
4930 else
4931 {
4932 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
4933 }
4934 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
4935 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
4936 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
4937# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
4938 if (cur->conceal_char)
4939 {
4940 char_u buf[MB_MAXBYTES + 1];
4941
4942 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
4943 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
4944 }
4945# endif
4946 list_append_dict(rettv->vval.v_list, dict);
4947 cur = cur->next;
4948 }
4949 }
4950#endif
4951}
4952
4953/*
4954 * "getpid()" function
4955 */
4956 static void
4957f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4958{
4959 rettv->vval.v_number = mch_get_pid();
4960}
4961
4962 static void
4963getpos_both(
4964 typval_T *argvars,
4965 typval_T *rettv,
4966 int getcurpos)
4967{
4968 pos_T *fp;
4969 list_T *l;
4970 int fnum = -1;
4971
4972 if (rettv_list_alloc(rettv) == OK)
4973 {
4974 l = rettv->vval.v_list;
4975 if (getcurpos)
4976 fp = &curwin->w_cursor;
4977 else
4978 fp = var2fpos(&argvars[0], TRUE, &fnum);
4979 if (fnum != -1)
4980 list_append_number(l, (varnumber_T)fnum);
4981 else
4982 list_append_number(l, (varnumber_T)0);
4983 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4984 : (varnumber_T)0);
4985 list_append_number(l, (fp != NULL)
4986 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4987 : (varnumber_T)0);
4988 list_append_number(l,
4989#ifdef FEAT_VIRTUALEDIT
4990 (fp != NULL) ? (varnumber_T)fp->coladd :
4991#endif
4992 (varnumber_T)0);
4993 if (getcurpos)
4994 {
4995 update_curswant();
4996 list_append_number(l, curwin->w_curswant == MAXCOL ?
4997 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
4998 }
4999 }
5000 else
5001 rettv->vval.v_number = FALSE;
5002}
5003
5004
5005/*
5006 * "getcurpos()" function
5007 */
5008 static void
5009f_getcurpos(typval_T *argvars, typval_T *rettv)
5010{
5011 getpos_both(argvars, rettv, TRUE);
5012}
5013
5014/*
5015 * "getpos(string)" function
5016 */
5017 static void
5018f_getpos(typval_T *argvars, typval_T *rettv)
5019{
5020 getpos_both(argvars, rettv, FALSE);
5021}
5022
5023/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005024 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 */
5026 static void
5027f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5028{
5029#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005030 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031#endif
5032}
5033
5034/*
5035 * "getreg()" function
5036 */
5037 static void
5038f_getreg(typval_T *argvars, typval_T *rettv)
5039{
5040 char_u *strregname;
5041 int regname;
5042 int arg2 = FALSE;
5043 int return_list = FALSE;
5044 int error = FALSE;
5045
5046 if (argvars[0].v_type != VAR_UNKNOWN)
5047 {
5048 strregname = get_tv_string_chk(&argvars[0]);
5049 error = strregname == NULL;
5050 if (argvars[1].v_type != VAR_UNKNOWN)
5051 {
5052 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5053 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5054 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5055 }
5056 }
5057 else
5058 strregname = get_vim_var_str(VV_REG);
5059
5060 if (error)
5061 return;
5062
5063 regname = (strregname == NULL ? '"' : *strregname);
5064 if (regname == 0)
5065 regname = '"';
5066
5067 if (return_list)
5068 {
5069 rettv->v_type = VAR_LIST;
5070 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5071 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5072 if (rettv->vval.v_list == NULL)
5073 (void)rettv_list_alloc(rettv);
5074 else
5075 ++rettv->vval.v_list->lv_refcount;
5076 }
5077 else
5078 {
5079 rettv->v_type = VAR_STRING;
5080 rettv->vval.v_string = get_reg_contents(regname,
5081 arg2 ? GREG_EXPR_SRC : 0);
5082 }
5083}
5084
5085/*
5086 * "getregtype()" function
5087 */
5088 static void
5089f_getregtype(typval_T *argvars, typval_T *rettv)
5090{
5091 char_u *strregname;
5092 int regname;
5093 char_u buf[NUMBUFLEN + 2];
5094 long reglen = 0;
5095
5096 if (argvars[0].v_type != VAR_UNKNOWN)
5097 {
5098 strregname = get_tv_string_chk(&argvars[0]);
5099 if (strregname == NULL) /* type error; errmsg already given */
5100 {
5101 rettv->v_type = VAR_STRING;
5102 rettv->vval.v_string = NULL;
5103 return;
5104 }
5105 }
5106 else
5107 /* Default to v:register */
5108 strregname = get_vim_var_str(VV_REG);
5109
5110 regname = (strregname == NULL ? '"' : *strregname);
5111 if (regname == 0)
5112 regname = '"';
5113
5114 buf[0] = NUL;
5115 buf[1] = NUL;
5116 switch (get_reg_type(regname, &reglen))
5117 {
5118 case MLINE: buf[0] = 'V'; break;
5119 case MCHAR: buf[0] = 'v'; break;
5120 case MBLOCK:
5121 buf[0] = Ctrl_V;
5122 sprintf((char *)buf + 1, "%ld", reglen + 1);
5123 break;
5124 }
5125 rettv->v_type = VAR_STRING;
5126 rettv->vval.v_string = vim_strsave(buf);
5127}
5128
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005129/*
5130 * Returns information (variables, options, etc.) about a tab page
5131 * as a dictionary.
5132 */
5133 static dict_T *
5134get_tabpage_info(tabpage_T *tp, int tp_idx)
5135{
5136 win_T *wp;
5137 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005138 list_T *l;
5139
5140 dict = dict_alloc();
5141 if (dict == NULL)
5142 return NULL;
5143
Bram Moolenaar33928832016-08-18 21:22:04 +02005144 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005145
5146 l = list_alloc();
5147 if (l != NULL)
5148 {
5149 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5150 wp; wp = wp->w_next)
5151 list_append_number(l, (varnumber_T)wp->w_id);
5152 dict_add_list(dict, "windows", l);
5153 }
5154
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005155 /* Make a reference to tabpage variables */
5156 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005157
5158 return dict;
5159}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005160
5161/*
5162 * "gettabinfo()" function
5163 */
5164 static void
5165f_gettabinfo(typval_T *argvars, typval_T *rettv)
5166{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005167 tabpage_T *tp, *tparg = NULL;
5168 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005169 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005170
5171 if (rettv_list_alloc(rettv) != OK)
5172 return;
5173
5174 if (argvars[0].v_type != VAR_UNKNOWN)
5175 {
5176 /* Information about one tab page */
5177 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5178 if (tparg == NULL)
5179 return;
5180 }
5181
5182 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005183 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005184 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005185 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005186 if (tparg != NULL && tp != tparg)
5187 continue;
5188 d = get_tabpage_info(tp, tpnr);
5189 if (d != NULL)
5190 list_append_dict(rettv->vval.v_list, d);
5191 if (tparg != NULL)
5192 return;
5193 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005194}
5195
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005196/*
5197 * "gettabvar()" function
5198 */
5199 static void
5200f_gettabvar(typval_T *argvars, typval_T *rettv)
5201{
5202 win_T *oldcurwin;
5203 tabpage_T *tp, *oldtabpage;
5204 dictitem_T *v;
5205 char_u *varname;
5206 int done = FALSE;
5207
5208 rettv->v_type = VAR_STRING;
5209 rettv->vval.v_string = NULL;
5210
5211 varname = get_tv_string_chk(&argvars[1]);
5212 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5213 if (tp != NULL && varname != NULL)
5214 {
5215 /* Set tp to be our tabpage, temporarily. Also set the window to the
5216 * first window in the tabpage, otherwise the window is not valid. */
5217 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005218 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5219 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005220 {
5221 /* look up the variable */
5222 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5223 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5224 if (v != NULL)
5225 {
5226 copy_tv(&v->di_tv, rettv);
5227 done = TRUE;
5228 }
5229 }
5230
5231 /* restore previous notion of curwin */
5232 restore_win(oldcurwin, oldtabpage, TRUE);
5233 }
5234
5235 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5236 copy_tv(&argvars[2], rettv);
5237}
5238
5239/*
5240 * "gettabwinvar()" function
5241 */
5242 static void
5243f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5244{
5245 getwinvar(argvars, rettv, 1);
5246}
5247
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005248/*
5249 * Returns information about a window as a dictionary.
5250 */
5251 static dict_T *
5252get_win_info(win_T *wp, short tpnr, short winnr)
5253{
5254 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005255
5256 dict = dict_alloc();
5257 if (dict == NULL)
5258 return NULL;
5259
Bram Moolenaar33928832016-08-18 21:22:04 +02005260 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5261 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005262 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5263 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005264#ifdef FEAT_MENU
5265 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5266#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005267 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005268 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005269
Bram Moolenaar69905d12017-08-13 18:14:47 +02005270#ifdef FEAT_TERMINAL
5271 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5272#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005273#ifdef FEAT_QUICKFIX
5274 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5275 dict_add_nr_str(dict, "loclist",
5276 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5277#endif
5278
Bram Moolenaar30567352016-08-27 21:25:44 +02005279 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005280 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005281
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005282 return dict;
5283}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005284
5285/*
5286 * "getwininfo()" function
5287 */
5288 static void
5289f_getwininfo(typval_T *argvars, typval_T *rettv)
5290{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005291 tabpage_T *tp;
5292 win_T *wp = NULL, *wparg = NULL;
5293 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005294 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005295
5296 if (rettv_list_alloc(rettv) != OK)
5297 return;
5298
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005299 if (argvars[0].v_type != VAR_UNKNOWN)
5300 {
5301 wparg = win_id2wp(argvars);
5302 if (wparg == NULL)
5303 return;
5304 }
5305
5306 /* Collect information about either all the windows across all the tab
5307 * pages or one particular window.
5308 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005309 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005310 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005311 tabnr++;
5312 winnr = 0;
5313 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005314 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005315 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005316 if (wparg != NULL && wp != wparg)
5317 continue;
5318 d = get_win_info(wp, tabnr, winnr);
5319 if (d != NULL)
5320 list_append_dict(rettv->vval.v_list, d);
5321 if (wparg != NULL)
5322 /* found information about a specific window */
5323 return;
5324 }
5325 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005326}
5327
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005328/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005329 * "win_findbuf()" function
5330 */
5331 static void
5332f_win_findbuf(typval_T *argvars, typval_T *rettv)
5333{
5334 if (rettv_list_alloc(rettv) != FAIL)
5335 win_findbuf(argvars, rettv->vval.v_list);
5336}
5337
5338/*
5339 * "win_getid()" function
5340 */
5341 static void
5342f_win_getid(typval_T *argvars, typval_T *rettv)
5343{
5344 rettv->vval.v_number = win_getid(argvars);
5345}
5346
5347/*
5348 * "win_gotoid()" function
5349 */
5350 static void
5351f_win_gotoid(typval_T *argvars, typval_T *rettv)
5352{
5353 rettv->vval.v_number = win_gotoid(argvars);
5354}
5355
5356/*
5357 * "win_id2tabwin()" function
5358 */
5359 static void
5360f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5361{
5362 if (rettv_list_alloc(rettv) != FAIL)
5363 win_id2tabwin(argvars, rettv->vval.v_list);
5364}
5365
5366/*
5367 * "win_id2win()" function
5368 */
5369 static void
5370f_win_id2win(typval_T *argvars, typval_T *rettv)
5371{
5372 rettv->vval.v_number = win_id2win(argvars);
5373}
5374
5375/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005376 * "getwinposx()" function
5377 */
5378 static void
5379f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5380{
5381 rettv->vval.v_number = -1;
5382#ifdef FEAT_GUI
5383 if (gui.in_use)
5384 {
5385 int x, y;
5386
5387 if (gui_mch_get_winpos(&x, &y) == OK)
5388 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005389 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005390 }
5391#endif
5392#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5393 {
5394 int x, y;
5395
5396 if (term_get_winpos(&x, &y) == OK)
5397 rettv->vval.v_number = x;
5398 }
5399#endif
5400}
5401
5402/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005403 * "getwinposy()" function
5404 */
5405 static void
5406f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5407{
5408 rettv->vval.v_number = -1;
5409#ifdef FEAT_GUI
5410 if (gui.in_use)
5411 {
5412 int x, y;
5413
5414 if (gui_mch_get_winpos(&x, &y) == OK)
5415 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005416 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 }
5418#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005419#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5420 {
5421 int x, y;
5422
5423 if (term_get_winpos(&x, &y) == OK)
5424 rettv->vval.v_number = y;
5425 }
5426#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005427}
5428
5429/*
5430 * "getwinvar()" function
5431 */
5432 static void
5433f_getwinvar(typval_T *argvars, typval_T *rettv)
5434{
5435 getwinvar(argvars, rettv, 0);
5436}
5437
5438/*
5439 * "glob()" function
5440 */
5441 static void
5442f_glob(typval_T *argvars, typval_T *rettv)
5443{
5444 int options = WILD_SILENT|WILD_USE_NL;
5445 expand_T xpc;
5446 int error = FALSE;
5447
5448 /* When the optional second argument is non-zero, don't remove matches
5449 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5450 rettv->v_type = VAR_STRING;
5451 if (argvars[1].v_type != VAR_UNKNOWN)
5452 {
5453 if (get_tv_number_chk(&argvars[1], &error))
5454 options |= WILD_KEEP_ALL;
5455 if (argvars[2].v_type != VAR_UNKNOWN)
5456 {
5457 if (get_tv_number_chk(&argvars[2], &error))
5458 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005459 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005460 }
5461 if (argvars[3].v_type != VAR_UNKNOWN
5462 && get_tv_number_chk(&argvars[3], &error))
5463 options |= WILD_ALLLINKS;
5464 }
5465 }
5466 if (!error)
5467 {
5468 ExpandInit(&xpc);
5469 xpc.xp_context = EXPAND_FILES;
5470 if (p_wic)
5471 options += WILD_ICASE;
5472 if (rettv->v_type == VAR_STRING)
5473 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5474 NULL, options, WILD_ALL);
5475 else if (rettv_list_alloc(rettv) != FAIL)
5476 {
5477 int i;
5478
5479 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5480 NULL, options, WILD_ALL_KEEP);
5481 for (i = 0; i < xpc.xp_numfiles; i++)
5482 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5483
5484 ExpandCleanup(&xpc);
5485 }
5486 }
5487 else
5488 rettv->vval.v_string = NULL;
5489}
5490
5491/*
5492 * "globpath()" function
5493 */
5494 static void
5495f_globpath(typval_T *argvars, typval_T *rettv)
5496{
5497 int flags = 0;
5498 char_u buf1[NUMBUFLEN];
5499 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5500 int error = FALSE;
5501 garray_T ga;
5502 int i;
5503
5504 /* When the optional second argument is non-zero, don't remove matches
5505 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5506 rettv->v_type = VAR_STRING;
5507 if (argvars[2].v_type != VAR_UNKNOWN)
5508 {
5509 if (get_tv_number_chk(&argvars[2], &error))
5510 flags |= WILD_KEEP_ALL;
5511 if (argvars[3].v_type != VAR_UNKNOWN)
5512 {
5513 if (get_tv_number_chk(&argvars[3], &error))
5514 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005515 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516 }
5517 if (argvars[4].v_type != VAR_UNKNOWN
5518 && get_tv_number_chk(&argvars[4], &error))
5519 flags |= WILD_ALLLINKS;
5520 }
5521 }
5522 if (file != NULL && !error)
5523 {
5524 ga_init2(&ga, (int)sizeof(char_u *), 10);
5525 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5526 if (rettv->v_type == VAR_STRING)
5527 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5528 else if (rettv_list_alloc(rettv) != FAIL)
5529 for (i = 0; i < ga.ga_len; ++i)
5530 list_append_string(rettv->vval.v_list,
5531 ((char_u **)(ga.ga_data))[i], -1);
5532 ga_clear_strings(&ga);
5533 }
5534 else
5535 rettv->vval.v_string = NULL;
5536}
5537
5538/*
5539 * "glob2regpat()" function
5540 */
5541 static void
5542f_glob2regpat(typval_T *argvars, typval_T *rettv)
5543{
5544 char_u *pat = get_tv_string_chk(&argvars[0]);
5545
5546 rettv->v_type = VAR_STRING;
5547 rettv->vval.v_string = (pat == NULL)
5548 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5549}
5550
5551/* for VIM_VERSION_ defines */
5552#include "version.h"
5553
5554/*
5555 * "has()" function
5556 */
5557 static void
5558f_has(typval_T *argvars, typval_T *rettv)
5559{
5560 int i;
5561 char_u *name;
5562 int n = FALSE;
5563 static char *(has_list[]) =
5564 {
5565#ifdef AMIGA
5566 "amiga",
5567# ifdef FEAT_ARP
5568 "arp",
5569# endif
5570#endif
5571#ifdef __BEOS__
5572 "beos",
5573#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005574#ifdef MACOS_X
5575 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5576 "osx", /* Mac OS X */
5577# ifdef MACOS_X_DARWIN
5578 "macunix", /* Mac OS X, with the darwin feature */
5579 "osxdarwin", /* synonym for macunix */
5580# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005581#endif
5582#ifdef __QNX__
5583 "qnx",
5584#endif
5585#ifdef UNIX
5586 "unix",
5587#endif
5588#ifdef VMS
5589 "vms",
5590#endif
5591#ifdef WIN32
5592 "win32",
5593#endif
5594#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5595 "win32unix",
5596#endif
5597#if defined(WIN64) || defined(_WIN64)
5598 "win64",
5599#endif
5600#ifdef EBCDIC
5601 "ebcdic",
5602#endif
5603#ifndef CASE_INSENSITIVE_FILENAME
5604 "fname_case",
5605#endif
5606#ifdef HAVE_ACL
5607 "acl",
5608#endif
5609#ifdef FEAT_ARABIC
5610 "arabic",
5611#endif
5612#ifdef FEAT_AUTOCMD
5613 "autocmd",
5614#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005615#ifdef FEAT_AUTOSERVERNAME
5616 "autoservername",
5617#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005618#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005619 "balloon_eval",
5620# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5621 "balloon_multiline",
5622# endif
5623#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005624#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005625 "balloon_eval_term",
5626#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005627#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5628 "builtin_terms",
5629# ifdef ALL_BUILTIN_TCAPS
5630 "all_builtin_terms",
5631# endif
5632#endif
5633#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5634 || defined(FEAT_GUI_W32) \
5635 || defined(FEAT_GUI_MOTIF))
5636 "browsefilter",
5637#endif
5638#ifdef FEAT_BYTEOFF
5639 "byte_offset",
5640#endif
5641#ifdef FEAT_JOB_CHANNEL
5642 "channel",
5643#endif
5644#ifdef FEAT_CINDENT
5645 "cindent",
5646#endif
5647#ifdef FEAT_CLIENTSERVER
5648 "clientserver",
5649#endif
5650#ifdef FEAT_CLIPBOARD
5651 "clipboard",
5652#endif
5653#ifdef FEAT_CMDL_COMPL
5654 "cmdline_compl",
5655#endif
5656#ifdef FEAT_CMDHIST
5657 "cmdline_hist",
5658#endif
5659#ifdef FEAT_COMMENTS
5660 "comments",
5661#endif
5662#ifdef FEAT_CONCEAL
5663 "conceal",
5664#endif
5665#ifdef FEAT_CRYPT
5666 "cryptv",
5667 "crypt-blowfish",
5668 "crypt-blowfish2",
5669#endif
5670#ifdef FEAT_CSCOPE
5671 "cscope",
5672#endif
5673#ifdef FEAT_CURSORBIND
5674 "cursorbind",
5675#endif
5676#ifdef CURSOR_SHAPE
5677 "cursorshape",
5678#endif
5679#ifdef DEBUG
5680 "debug",
5681#endif
5682#ifdef FEAT_CON_DIALOG
5683 "dialog_con",
5684#endif
5685#ifdef FEAT_GUI_DIALOG
5686 "dialog_gui",
5687#endif
5688#ifdef FEAT_DIFF
5689 "diff",
5690#endif
5691#ifdef FEAT_DIGRAPHS
5692 "digraphs",
5693#endif
5694#ifdef FEAT_DIRECTX
5695 "directx",
5696#endif
5697#ifdef FEAT_DND
5698 "dnd",
5699#endif
5700#ifdef FEAT_EMACS_TAGS
5701 "emacs_tags",
5702#endif
5703 "eval", /* always present, of course! */
5704 "ex_extra", /* graduated feature */
5705#ifdef FEAT_SEARCH_EXTRA
5706 "extra_search",
5707#endif
5708#ifdef FEAT_FKMAP
5709 "farsi",
5710#endif
5711#ifdef FEAT_SEARCHPATH
5712 "file_in_path",
5713#endif
5714#ifdef FEAT_FILTERPIPE
5715 "filterpipe",
5716#endif
5717#ifdef FEAT_FIND_ID
5718 "find_in_path",
5719#endif
5720#ifdef FEAT_FLOAT
5721 "float",
5722#endif
5723#ifdef FEAT_FOLDING
5724 "folding",
5725#endif
5726#ifdef FEAT_FOOTER
5727 "footer",
5728#endif
5729#if !defined(USE_SYSTEM) && defined(UNIX)
5730 "fork",
5731#endif
5732#ifdef FEAT_GETTEXT
5733 "gettext",
5734#endif
5735#ifdef FEAT_GUI
5736 "gui",
5737#endif
5738#ifdef FEAT_GUI_ATHENA
5739# ifdef FEAT_GUI_NEXTAW
5740 "gui_neXtaw",
5741# else
5742 "gui_athena",
5743# endif
5744#endif
5745#ifdef FEAT_GUI_GTK
5746 "gui_gtk",
5747# ifdef USE_GTK3
5748 "gui_gtk3",
5749# else
5750 "gui_gtk2",
5751# endif
5752#endif
5753#ifdef FEAT_GUI_GNOME
5754 "gui_gnome",
5755#endif
5756#ifdef FEAT_GUI_MAC
5757 "gui_mac",
5758#endif
5759#ifdef FEAT_GUI_MOTIF
5760 "gui_motif",
5761#endif
5762#ifdef FEAT_GUI_PHOTON
5763 "gui_photon",
5764#endif
5765#ifdef FEAT_GUI_W32
5766 "gui_win32",
5767#endif
5768#ifdef FEAT_HANGULIN
5769 "hangul_input",
5770#endif
5771#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5772 "iconv",
5773#endif
5774#ifdef FEAT_INS_EXPAND
5775 "insert_expand",
5776#endif
5777#ifdef FEAT_JOB_CHANNEL
5778 "job",
5779#endif
5780#ifdef FEAT_JUMPLIST
5781 "jumplist",
5782#endif
5783#ifdef FEAT_KEYMAP
5784 "keymap",
5785#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005786 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005787#ifdef FEAT_LANGMAP
5788 "langmap",
5789#endif
5790#ifdef FEAT_LIBCALL
5791 "libcall",
5792#endif
5793#ifdef FEAT_LINEBREAK
5794 "linebreak",
5795#endif
5796#ifdef FEAT_LISP
5797 "lispindent",
5798#endif
5799#ifdef FEAT_LISTCMDS
5800 "listcmds",
5801#endif
5802#ifdef FEAT_LOCALMAP
5803 "localmap",
5804#endif
5805#ifdef FEAT_LUA
5806# ifndef DYNAMIC_LUA
5807 "lua",
5808# endif
5809#endif
5810#ifdef FEAT_MENU
5811 "menu",
5812#endif
5813#ifdef FEAT_SESSION
5814 "mksession",
5815#endif
5816#ifdef FEAT_MODIFY_FNAME
5817 "modify_fname",
5818#endif
5819#ifdef FEAT_MOUSE
5820 "mouse",
5821#endif
5822#ifdef FEAT_MOUSESHAPE
5823 "mouseshape",
5824#endif
5825#if defined(UNIX) || defined(VMS)
5826# ifdef FEAT_MOUSE_DEC
5827 "mouse_dec",
5828# endif
5829# ifdef FEAT_MOUSE_GPM
5830 "mouse_gpm",
5831# endif
5832# ifdef FEAT_MOUSE_JSB
5833 "mouse_jsbterm",
5834# endif
5835# ifdef FEAT_MOUSE_NET
5836 "mouse_netterm",
5837# endif
5838# ifdef FEAT_MOUSE_PTERM
5839 "mouse_pterm",
5840# endif
5841# ifdef FEAT_MOUSE_SGR
5842 "mouse_sgr",
5843# endif
5844# ifdef FEAT_SYSMOUSE
5845 "mouse_sysmouse",
5846# endif
5847# ifdef FEAT_MOUSE_URXVT
5848 "mouse_urxvt",
5849# endif
5850# ifdef FEAT_MOUSE_XTERM
5851 "mouse_xterm",
5852# endif
5853#endif
5854#ifdef FEAT_MBYTE
5855 "multi_byte",
5856#endif
5857#ifdef FEAT_MBYTE_IME
5858 "multi_byte_ime",
5859#endif
5860#ifdef FEAT_MULTI_LANG
5861 "multi_lang",
5862#endif
5863#ifdef FEAT_MZSCHEME
5864#ifndef DYNAMIC_MZSCHEME
5865 "mzscheme",
5866#endif
5867#endif
5868#ifdef FEAT_NUM64
5869 "num64",
5870#endif
5871#ifdef FEAT_OLE
5872 "ole",
5873#endif
5874 "packages",
5875#ifdef FEAT_PATH_EXTRA
5876 "path_extra",
5877#endif
5878#ifdef FEAT_PERL
5879#ifndef DYNAMIC_PERL
5880 "perl",
5881#endif
5882#endif
5883#ifdef FEAT_PERSISTENT_UNDO
5884 "persistent_undo",
5885#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005886#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005887 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005888 "pythonx",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005889#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005890#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005891 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005892 "pythonx",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005893#endif
5894#ifdef FEAT_POSTSCRIPT
5895 "postscript",
5896#endif
5897#ifdef FEAT_PRINTER
5898 "printer",
5899#endif
5900#ifdef FEAT_PROFILE
5901 "profile",
5902#endif
5903#ifdef FEAT_RELTIME
5904 "reltime",
5905#endif
5906#ifdef FEAT_QUICKFIX
5907 "quickfix",
5908#endif
5909#ifdef FEAT_RIGHTLEFT
5910 "rightleft",
5911#endif
5912#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5913 "ruby",
5914#endif
5915#ifdef FEAT_SCROLLBIND
5916 "scrollbind",
5917#endif
5918#ifdef FEAT_CMDL_INFO
5919 "showcmd",
5920 "cmdline_info",
5921#endif
5922#ifdef FEAT_SIGNS
5923 "signs",
5924#endif
5925#ifdef FEAT_SMARTINDENT
5926 "smartindent",
5927#endif
5928#ifdef STARTUPTIME
5929 "startuptime",
5930#endif
5931#ifdef FEAT_STL_OPT
5932 "statusline",
5933#endif
5934#ifdef FEAT_SUN_WORKSHOP
5935 "sun_workshop",
5936#endif
5937#ifdef FEAT_NETBEANS_INTG
5938 "netbeans_intg",
5939#endif
5940#ifdef FEAT_SPELL
5941 "spell",
5942#endif
5943#ifdef FEAT_SYN_HL
5944 "syntax",
5945#endif
5946#if defined(USE_SYSTEM) || !defined(UNIX)
5947 "system",
5948#endif
5949#ifdef FEAT_TAG_BINS
5950 "tag_binary",
5951#endif
5952#ifdef FEAT_TAG_OLDSTATIC
5953 "tag_old_static",
5954#endif
5955#ifdef FEAT_TAG_ANYWHITE
5956 "tag_any_white",
5957#endif
5958#ifdef FEAT_TCL
5959# ifndef DYNAMIC_TCL
5960 "tcl",
5961# endif
5962#endif
5963#ifdef FEAT_TERMGUICOLORS
5964 "termguicolors",
5965#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02005966#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02005967 "terminal",
5968#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005969#ifdef TERMINFO
5970 "terminfo",
5971#endif
5972#ifdef FEAT_TERMRESPONSE
5973 "termresponse",
5974#endif
5975#ifdef FEAT_TEXTOBJ
5976 "textobjects",
5977#endif
5978#ifdef HAVE_TGETENT
5979 "tgetent",
5980#endif
5981#ifdef FEAT_TIMERS
5982 "timers",
5983#endif
5984#ifdef FEAT_TITLE
5985 "title",
5986#endif
5987#ifdef FEAT_TOOLBAR
5988 "toolbar",
5989#endif
5990#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5991 "unnamedplus",
5992#endif
5993#ifdef FEAT_USR_CMDS
5994 "user-commands", /* was accidentally included in 5.4 */
5995 "user_commands",
5996#endif
5997#ifdef FEAT_VIMINFO
5998 "viminfo",
5999#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006000 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006001#ifdef FEAT_VIRTUALEDIT
6002 "virtualedit",
6003#endif
6004 "visual",
6005#ifdef FEAT_VISUALEXTRA
6006 "visualextra",
6007#endif
6008#ifdef FEAT_VREPLACE
6009 "vreplace",
6010#endif
6011#ifdef FEAT_WILDIGN
6012 "wildignore",
6013#endif
6014#ifdef FEAT_WILDMENU
6015 "wildmenu",
6016#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006017 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018#ifdef FEAT_WAK
6019 "winaltkeys",
6020#endif
6021#ifdef FEAT_WRITEBACKUP
6022 "writebackup",
6023#endif
6024#ifdef FEAT_XIM
6025 "xim",
6026#endif
6027#ifdef FEAT_XFONTSET
6028 "xfontset",
6029#endif
6030#ifdef FEAT_XPM_W32
6031 "xpm",
6032 "xpm_w32", /* for backward compatibility */
6033#else
6034# if defined(HAVE_XPM)
6035 "xpm",
6036# endif
6037#endif
6038#ifdef USE_XSMP
6039 "xsmp",
6040#endif
6041#ifdef USE_XSMP_INTERACT
6042 "xsmp_interact",
6043#endif
6044#ifdef FEAT_XCLIPBOARD
6045 "xterm_clipboard",
6046#endif
6047#ifdef FEAT_XTERM_SAVE
6048 "xterm_save",
6049#endif
6050#if defined(UNIX) && defined(FEAT_X11)
6051 "X11",
6052#endif
6053 NULL
6054 };
6055
6056 name = get_tv_string(&argvars[0]);
6057 for (i = 0; has_list[i] != NULL; ++i)
6058 if (STRICMP(name, has_list[i]) == 0)
6059 {
6060 n = TRUE;
6061 break;
6062 }
6063
6064 if (n == FALSE)
6065 {
6066 if (STRNICMP(name, "patch", 5) == 0)
6067 {
6068 if (name[5] == '-'
6069 && STRLEN(name) >= 11
6070 && vim_isdigit(name[6])
6071 && vim_isdigit(name[8])
6072 && vim_isdigit(name[10]))
6073 {
6074 int major = atoi((char *)name + 6);
6075 int minor = atoi((char *)name + 8);
6076
6077 /* Expect "patch-9.9.01234". */
6078 n = (major < VIM_VERSION_MAJOR
6079 || (major == VIM_VERSION_MAJOR
6080 && (minor < VIM_VERSION_MINOR
6081 || (minor == VIM_VERSION_MINOR
6082 && has_patch(atoi((char *)name + 10))))));
6083 }
6084 else
6085 n = has_patch(atoi((char *)name + 5));
6086 }
6087 else if (STRICMP(name, "vim_starting") == 0)
6088 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006089 else if (STRICMP(name, "ttyin") == 0)
6090 n = mch_input_isatty();
6091 else if (STRICMP(name, "ttyout") == 0)
6092 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006093#ifdef FEAT_MBYTE
6094 else if (STRICMP(name, "multi_byte_encoding") == 0)
6095 n = has_mbyte;
6096#endif
6097#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6098 else if (STRICMP(name, "balloon_multiline") == 0)
6099 n = multiline_balloon_available();
6100#endif
6101#ifdef DYNAMIC_TCL
6102 else if (STRICMP(name, "tcl") == 0)
6103 n = tcl_enabled(FALSE);
6104#endif
6105#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6106 else if (STRICMP(name, "iconv") == 0)
6107 n = iconv_enabled(FALSE);
6108#endif
6109#ifdef DYNAMIC_LUA
6110 else if (STRICMP(name, "lua") == 0)
6111 n = lua_enabled(FALSE);
6112#endif
6113#ifdef DYNAMIC_MZSCHEME
6114 else if (STRICMP(name, "mzscheme") == 0)
6115 n = mzscheme_enabled(FALSE);
6116#endif
6117#ifdef DYNAMIC_RUBY
6118 else if (STRICMP(name, "ruby") == 0)
6119 n = ruby_enabled(FALSE);
6120#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006121#ifdef DYNAMIC_PYTHON
6122 else if (STRICMP(name, "python") == 0)
6123 n = python_enabled(FALSE);
6124#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006125#ifdef DYNAMIC_PYTHON3
6126 else if (STRICMP(name, "python3") == 0)
6127 n = python3_enabled(FALSE);
6128#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006129#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6130 else if (STRICMP(name, "pythonx") == 0)
6131 {
6132# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6133 if (p_pyx == 0)
6134 n = python3_enabled(FALSE) || python_enabled(FALSE);
6135 else if (p_pyx == 3)
6136 n = python3_enabled(FALSE);
6137 else if (p_pyx == 2)
6138 n = python_enabled(FALSE);
6139# elif defined(DYNAMIC_PYTHON)
6140 n = python_enabled(FALSE);
6141# elif defined(DYNAMIC_PYTHON3)
6142 n = python3_enabled(FALSE);
6143# endif
6144 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006145#endif
6146#ifdef DYNAMIC_PERL
6147 else if (STRICMP(name, "perl") == 0)
6148 n = perl_enabled(FALSE);
6149#endif
6150#ifdef FEAT_GUI
6151 else if (STRICMP(name, "gui_running") == 0)
6152 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006153# ifdef FEAT_BROWSE
6154 else if (STRICMP(name, "browse") == 0)
6155 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6156# endif
6157#endif
6158#ifdef FEAT_SYN_HL
6159 else if (STRICMP(name, "syntax_items") == 0)
6160 n = syntax_present(curwin);
6161#endif
6162#if defined(WIN3264)
6163 else if (STRICMP(name, "win95") == 0)
Bram Moolenaarcea912a2016-10-12 14:20:24 +02006164 n = FALSE; /* Win9x is no more supported. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006165#endif
6166#ifdef FEAT_NETBEANS_INTG
6167 else if (STRICMP(name, "netbeans_enabled") == 0)
6168 n = netbeans_active();
6169#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006170#if defined(FEAT_TERMINAL) && defined(WIN3264)
6171 else if (STRICMP(name, "terminal") == 0)
6172 n = terminal_enabled();
6173#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006174 }
6175
6176 rettv->vval.v_number = n;
6177}
6178
6179/*
6180 * "has_key()" function
6181 */
6182 static void
6183f_has_key(typval_T *argvars, typval_T *rettv)
6184{
6185 if (argvars[0].v_type != VAR_DICT)
6186 {
6187 EMSG(_(e_dictreq));
6188 return;
6189 }
6190 if (argvars[0].vval.v_dict == NULL)
6191 return;
6192
6193 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6194 get_tv_string(&argvars[1]), -1) != NULL;
6195}
6196
6197/*
6198 * "haslocaldir()" function
6199 */
6200 static void
6201f_haslocaldir(typval_T *argvars, typval_T *rettv)
6202{
6203 win_T *wp = NULL;
6204
6205 wp = find_tabwin(&argvars[0], &argvars[1]);
6206 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6207}
6208
6209/*
6210 * "hasmapto()" function
6211 */
6212 static void
6213f_hasmapto(typval_T *argvars, typval_T *rettv)
6214{
6215 char_u *name;
6216 char_u *mode;
6217 char_u buf[NUMBUFLEN];
6218 int abbr = FALSE;
6219
6220 name = get_tv_string(&argvars[0]);
6221 if (argvars[1].v_type == VAR_UNKNOWN)
6222 mode = (char_u *)"nvo";
6223 else
6224 {
6225 mode = get_tv_string_buf(&argvars[1], buf);
6226 if (argvars[2].v_type != VAR_UNKNOWN)
6227 abbr = (int)get_tv_number(&argvars[2]);
6228 }
6229
6230 if (map_to_exists(name, mode, abbr))
6231 rettv->vval.v_number = TRUE;
6232 else
6233 rettv->vval.v_number = FALSE;
6234}
6235
6236/*
6237 * "histadd()" function
6238 */
6239 static void
6240f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6241{
6242#ifdef FEAT_CMDHIST
6243 int histype;
6244 char_u *str;
6245 char_u buf[NUMBUFLEN];
6246#endif
6247
6248 rettv->vval.v_number = FALSE;
6249 if (check_restricted() || check_secure())
6250 return;
6251#ifdef FEAT_CMDHIST
6252 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6253 histype = str != NULL ? get_histtype(str) : -1;
6254 if (histype >= 0)
6255 {
6256 str = get_tv_string_buf(&argvars[1], buf);
6257 if (*str != NUL)
6258 {
6259 init_history();
6260 add_to_history(histype, str, FALSE, NUL);
6261 rettv->vval.v_number = TRUE;
6262 return;
6263 }
6264 }
6265#endif
6266}
6267
6268/*
6269 * "histdel()" function
6270 */
6271 static void
6272f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6273{
6274#ifdef FEAT_CMDHIST
6275 int n;
6276 char_u buf[NUMBUFLEN];
6277 char_u *str;
6278
6279 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6280 if (str == NULL)
6281 n = 0;
6282 else if (argvars[1].v_type == VAR_UNKNOWN)
6283 /* only one argument: clear entire history */
6284 n = clr_history(get_histtype(str));
6285 else if (argvars[1].v_type == VAR_NUMBER)
6286 /* index given: remove that entry */
6287 n = del_history_idx(get_histtype(str),
6288 (int)get_tv_number(&argvars[1]));
6289 else
6290 /* string given: remove all matching entries */
6291 n = del_history_entry(get_histtype(str),
6292 get_tv_string_buf(&argvars[1], buf));
6293 rettv->vval.v_number = n;
6294#endif
6295}
6296
6297/*
6298 * "histget()" function
6299 */
6300 static void
6301f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6302{
6303#ifdef FEAT_CMDHIST
6304 int type;
6305 int idx;
6306 char_u *str;
6307
6308 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6309 if (str == NULL)
6310 rettv->vval.v_string = NULL;
6311 else
6312 {
6313 type = get_histtype(str);
6314 if (argvars[1].v_type == VAR_UNKNOWN)
6315 idx = get_history_idx(type);
6316 else
6317 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6318 /* -1 on type error */
6319 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6320 }
6321#else
6322 rettv->vval.v_string = NULL;
6323#endif
6324 rettv->v_type = VAR_STRING;
6325}
6326
6327/*
6328 * "histnr()" function
6329 */
6330 static void
6331f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6332{
6333 int i;
6334
6335#ifdef FEAT_CMDHIST
6336 char_u *history = get_tv_string_chk(&argvars[0]);
6337
6338 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6339 if (i >= HIST_CMD && i < HIST_COUNT)
6340 i = get_history_idx(i);
6341 else
6342#endif
6343 i = -1;
6344 rettv->vval.v_number = i;
6345}
6346
6347/*
6348 * "highlightID(name)" function
6349 */
6350 static void
6351f_hlID(typval_T *argvars, typval_T *rettv)
6352{
6353 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6354}
6355
6356/*
6357 * "highlight_exists()" function
6358 */
6359 static void
6360f_hlexists(typval_T *argvars, typval_T *rettv)
6361{
6362 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6363}
6364
6365/*
6366 * "hostname()" function
6367 */
6368 static void
6369f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6370{
6371 char_u hostname[256];
6372
6373 mch_get_host_name(hostname, 256);
6374 rettv->v_type = VAR_STRING;
6375 rettv->vval.v_string = vim_strsave(hostname);
6376}
6377
6378/*
6379 * iconv() function
6380 */
6381 static void
6382f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6383{
6384#ifdef FEAT_MBYTE
6385 char_u buf1[NUMBUFLEN];
6386 char_u buf2[NUMBUFLEN];
6387 char_u *from, *to, *str;
6388 vimconv_T vimconv;
6389#endif
6390
6391 rettv->v_type = VAR_STRING;
6392 rettv->vval.v_string = NULL;
6393
6394#ifdef FEAT_MBYTE
6395 str = get_tv_string(&argvars[0]);
6396 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6397 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6398 vimconv.vc_type = CONV_NONE;
6399 convert_setup(&vimconv, from, to);
6400
6401 /* If the encodings are equal, no conversion needed. */
6402 if (vimconv.vc_type == CONV_NONE)
6403 rettv->vval.v_string = vim_strsave(str);
6404 else
6405 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6406
6407 convert_setup(&vimconv, NULL, NULL);
6408 vim_free(from);
6409 vim_free(to);
6410#endif
6411}
6412
6413/*
6414 * "indent()" function
6415 */
6416 static void
6417f_indent(typval_T *argvars, typval_T *rettv)
6418{
6419 linenr_T lnum;
6420
6421 lnum = get_tv_lnum(argvars);
6422 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6423 rettv->vval.v_number = get_indent_lnum(lnum);
6424 else
6425 rettv->vval.v_number = -1;
6426}
6427
6428/*
6429 * "index()" function
6430 */
6431 static void
6432f_index(typval_T *argvars, typval_T *rettv)
6433{
6434 list_T *l;
6435 listitem_T *item;
6436 long idx = 0;
6437 int ic = FALSE;
6438
6439 rettv->vval.v_number = -1;
6440 if (argvars[0].v_type != VAR_LIST)
6441 {
6442 EMSG(_(e_listreq));
6443 return;
6444 }
6445 l = argvars[0].vval.v_list;
6446 if (l != NULL)
6447 {
6448 item = l->lv_first;
6449 if (argvars[2].v_type != VAR_UNKNOWN)
6450 {
6451 int error = FALSE;
6452
6453 /* Start at specified item. Use the cached index that list_find()
6454 * sets, so that a negative number also works. */
6455 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6456 idx = l->lv_idx;
6457 if (argvars[3].v_type != VAR_UNKNOWN)
6458 ic = (int)get_tv_number_chk(&argvars[3], &error);
6459 if (error)
6460 item = NULL;
6461 }
6462
6463 for ( ; item != NULL; item = item->li_next, ++idx)
6464 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6465 {
6466 rettv->vval.v_number = idx;
6467 break;
6468 }
6469 }
6470}
6471
6472static int inputsecret_flag = 0;
6473
6474/*
6475 * "input()" function
6476 * Also handles inputsecret() when inputsecret is set.
6477 */
6478 static void
6479f_input(typval_T *argvars, typval_T *rettv)
6480{
6481 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6482}
6483
6484/*
6485 * "inputdialog()" function
6486 */
6487 static void
6488f_inputdialog(typval_T *argvars, typval_T *rettv)
6489{
6490#if defined(FEAT_GUI_TEXTDIALOG)
6491 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6492 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6493 {
6494 char_u *message;
6495 char_u buf[NUMBUFLEN];
6496 char_u *defstr = (char_u *)"";
6497
6498 message = get_tv_string_chk(&argvars[0]);
6499 if (argvars[1].v_type != VAR_UNKNOWN
6500 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6501 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6502 else
6503 IObuff[0] = NUL;
6504 if (message != NULL && defstr != NULL
6505 && do_dialog(VIM_QUESTION, NULL, message,
6506 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6507 rettv->vval.v_string = vim_strsave(IObuff);
6508 else
6509 {
6510 if (message != NULL && defstr != NULL
6511 && argvars[1].v_type != VAR_UNKNOWN
6512 && argvars[2].v_type != VAR_UNKNOWN)
6513 rettv->vval.v_string = vim_strsave(
6514 get_tv_string_buf(&argvars[2], buf));
6515 else
6516 rettv->vval.v_string = NULL;
6517 }
6518 rettv->v_type = VAR_STRING;
6519 }
6520 else
6521#endif
6522 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6523}
6524
6525/*
6526 * "inputlist()" function
6527 */
6528 static void
6529f_inputlist(typval_T *argvars, typval_T *rettv)
6530{
6531 listitem_T *li;
6532 int selected;
6533 int mouse_used;
6534
6535#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006536 /* While starting up, there is no place to enter text. When running tests
6537 * with --not-a-term we assume feedkeys() will be used. */
6538 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 return;
6540#endif
6541 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6542 {
6543 EMSG2(_(e_listarg), "inputlist()");
6544 return;
6545 }
6546
6547 msg_start();
6548 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6549 lines_left = Rows; /* avoid more prompt */
6550 msg_scroll = TRUE;
6551 msg_clr_eos();
6552
6553 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6554 {
6555 msg_puts(get_tv_string(&li->li_tv));
6556 msg_putchar('\n');
6557 }
6558
6559 /* Ask for choice. */
6560 selected = prompt_for_number(&mouse_used);
6561 if (mouse_used)
6562 selected -= lines_left;
6563
6564 rettv->vval.v_number = selected;
6565}
6566
6567
6568static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6569
6570/*
6571 * "inputrestore()" function
6572 */
6573 static void
6574f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6575{
6576 if (ga_userinput.ga_len > 0)
6577 {
6578 --ga_userinput.ga_len;
6579 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6580 + ga_userinput.ga_len);
6581 /* default return is zero == OK */
6582 }
6583 else if (p_verbose > 1)
6584 {
6585 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6586 rettv->vval.v_number = 1; /* Failed */
6587 }
6588}
6589
6590/*
6591 * "inputsave()" function
6592 */
6593 static void
6594f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6595{
6596 /* Add an entry to the stack of typeahead storage. */
6597 if (ga_grow(&ga_userinput, 1) == OK)
6598 {
6599 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6600 + ga_userinput.ga_len);
6601 ++ga_userinput.ga_len;
6602 /* default return is zero == OK */
6603 }
6604 else
6605 rettv->vval.v_number = 1; /* Failed */
6606}
6607
6608/*
6609 * "inputsecret()" function
6610 */
6611 static void
6612f_inputsecret(typval_T *argvars, typval_T *rettv)
6613{
6614 ++cmdline_star;
6615 ++inputsecret_flag;
6616 f_input(argvars, rettv);
6617 --cmdline_star;
6618 --inputsecret_flag;
6619}
6620
6621/*
6622 * "insert()" function
6623 */
6624 static void
6625f_insert(typval_T *argvars, typval_T *rettv)
6626{
6627 long before = 0;
6628 listitem_T *item;
6629 list_T *l;
6630 int error = FALSE;
6631
6632 if (argvars[0].v_type != VAR_LIST)
6633 EMSG2(_(e_listarg), "insert()");
6634 else if ((l = argvars[0].vval.v_list) != NULL
6635 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6636 {
6637 if (argvars[2].v_type != VAR_UNKNOWN)
6638 before = (long)get_tv_number_chk(&argvars[2], &error);
6639 if (error)
6640 return; /* type error; errmsg already given */
6641
6642 if (before == l->lv_len)
6643 item = NULL;
6644 else
6645 {
6646 item = list_find(l, before);
6647 if (item == NULL)
6648 {
6649 EMSGN(_(e_listidx), before);
6650 l = NULL;
6651 }
6652 }
6653 if (l != NULL)
6654 {
6655 list_insert_tv(l, &argvars[1], item);
6656 copy_tv(&argvars[0], rettv);
6657 }
6658 }
6659}
6660
6661/*
6662 * "invert(expr)" function
6663 */
6664 static void
6665f_invert(typval_T *argvars, typval_T *rettv)
6666{
6667 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6668}
6669
6670/*
6671 * "isdirectory()" function
6672 */
6673 static void
6674f_isdirectory(typval_T *argvars, typval_T *rettv)
6675{
6676 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6677}
6678
6679/*
6680 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6681 * or it refers to a List or Dictionary that is locked.
6682 */
6683 static int
6684tv_islocked(typval_T *tv)
6685{
6686 return (tv->v_lock & VAR_LOCKED)
6687 || (tv->v_type == VAR_LIST
6688 && tv->vval.v_list != NULL
6689 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6690 || (tv->v_type == VAR_DICT
6691 && tv->vval.v_dict != NULL
6692 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6693}
6694
6695/*
6696 * "islocked()" function
6697 */
6698 static void
6699f_islocked(typval_T *argvars, typval_T *rettv)
6700{
6701 lval_T lv;
6702 char_u *end;
6703 dictitem_T *di;
6704
6705 rettv->vval.v_number = -1;
6706 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006707 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006708 if (end != NULL && lv.ll_name != NULL)
6709 {
6710 if (*end != NUL)
6711 EMSG(_(e_trailing));
6712 else
6713 {
6714 if (lv.ll_tv == NULL)
6715 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006716 di = find_var(lv.ll_name, NULL, TRUE);
6717 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006719 /* Consider a variable locked when:
6720 * 1. the variable itself is locked
6721 * 2. the value of the variable is locked.
6722 * 3. the List or Dict value is locked.
6723 */
6724 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6725 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 }
6727 }
6728 else if (lv.ll_range)
6729 EMSG(_("E786: Range not allowed"));
6730 else if (lv.ll_newkey != NULL)
6731 EMSG2(_(e_dictkey), lv.ll_newkey);
6732 else if (lv.ll_list != NULL)
6733 /* List item. */
6734 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6735 else
6736 /* Dictionary item. */
6737 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6738 }
6739 }
6740
6741 clear_lval(&lv);
6742}
6743
6744#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6745/*
6746 * "isnan()" function
6747 */
6748 static void
6749f_isnan(typval_T *argvars, typval_T *rettv)
6750{
6751 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6752 && isnan(argvars[0].vval.v_float);
6753}
6754#endif
6755
6756/*
6757 * "items(dict)" function
6758 */
6759 static void
6760f_items(typval_T *argvars, typval_T *rettv)
6761{
6762 dict_list(argvars, rettv, 2);
6763}
6764
6765#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6766/*
6767 * Get the job from the argument.
6768 * Returns NULL if the job is invalid.
6769 */
6770 static job_T *
6771get_job_arg(typval_T *tv)
6772{
6773 job_T *job;
6774
6775 if (tv->v_type != VAR_JOB)
6776 {
6777 EMSG2(_(e_invarg2), get_tv_string(tv));
6778 return NULL;
6779 }
6780 job = tv->vval.v_job;
6781
6782 if (job == NULL)
6783 EMSG(_("E916: not a valid job"));
6784 return job;
6785}
6786
6787/*
6788 * "job_getchannel()" function
6789 */
6790 static void
6791f_job_getchannel(typval_T *argvars, typval_T *rettv)
6792{
6793 job_T *job = get_job_arg(&argvars[0]);
6794
6795 if (job != NULL)
6796 {
6797 rettv->v_type = VAR_CHANNEL;
6798 rettv->vval.v_channel = job->jv_channel;
6799 if (job->jv_channel != NULL)
6800 ++job->jv_channel->ch_refcount;
6801 }
6802}
6803
6804/*
6805 * "job_info()" function
6806 */
6807 static void
6808f_job_info(typval_T *argvars, typval_T *rettv)
6809{
6810 job_T *job = get_job_arg(&argvars[0]);
6811
6812 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6813 job_info(job, rettv->vval.v_dict);
6814}
6815
6816/*
6817 * "job_setoptions()" function
6818 */
6819 static void
6820f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6821{
6822 job_T *job = get_job_arg(&argvars[0]);
6823 jobopt_T opt;
6824
6825 if (job == NULL)
6826 return;
6827 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02006828 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006829 job_set_options(job, &opt);
6830 free_job_options(&opt);
6831}
6832
6833/*
6834 * "job_start()" function
6835 */
6836 static void
6837f_job_start(typval_T *argvars, typval_T *rettv)
6838{
6839 rettv->v_type = VAR_JOB;
6840 if (check_restricted() || check_secure())
6841 return;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006842 rettv->vval.v_job = job_start(argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006843}
6844
6845/*
6846 * "job_status()" function
6847 */
6848 static void
6849f_job_status(typval_T *argvars, typval_T *rettv)
6850{
6851 job_T *job = get_job_arg(&argvars[0]);
6852
6853 if (job != NULL)
6854 {
6855 rettv->v_type = VAR_STRING;
6856 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6857 }
6858}
6859
6860/*
6861 * "job_stop()" function
6862 */
6863 static void
6864f_job_stop(typval_T *argvars, typval_T *rettv)
6865{
6866 job_T *job = get_job_arg(&argvars[0]);
6867
6868 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006869 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870}
6871#endif
6872
6873/*
6874 * "join()" function
6875 */
6876 static void
6877f_join(typval_T *argvars, typval_T *rettv)
6878{
6879 garray_T ga;
6880 char_u *sep;
6881
6882 if (argvars[0].v_type != VAR_LIST)
6883 {
6884 EMSG(_(e_listreq));
6885 return;
6886 }
6887 if (argvars[0].vval.v_list == NULL)
6888 return;
6889 if (argvars[1].v_type == VAR_UNKNOWN)
6890 sep = (char_u *)" ";
6891 else
6892 sep = get_tv_string_chk(&argvars[1]);
6893
6894 rettv->v_type = VAR_STRING;
6895
6896 if (sep != NULL)
6897 {
6898 ga_init2(&ga, (int)sizeof(char), 80);
6899 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6900 ga_append(&ga, NUL);
6901 rettv->vval.v_string = (char_u *)ga.ga_data;
6902 }
6903 else
6904 rettv->vval.v_string = NULL;
6905}
6906
6907/*
6908 * "js_decode()" function
6909 */
6910 static void
6911f_js_decode(typval_T *argvars, typval_T *rettv)
6912{
6913 js_read_T reader;
6914
6915 reader.js_buf = get_tv_string(&argvars[0]);
6916 reader.js_fill = NULL;
6917 reader.js_used = 0;
6918 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6919 EMSG(_(e_invarg));
6920}
6921
6922/*
6923 * "js_encode()" function
6924 */
6925 static void
6926f_js_encode(typval_T *argvars, typval_T *rettv)
6927{
6928 rettv->v_type = VAR_STRING;
6929 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6930}
6931
6932/*
6933 * "json_decode()" function
6934 */
6935 static void
6936f_json_decode(typval_T *argvars, typval_T *rettv)
6937{
6938 js_read_T reader;
6939
6940 reader.js_buf = get_tv_string(&argvars[0]);
6941 reader.js_fill = NULL;
6942 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01006943 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006944}
6945
6946/*
6947 * "json_encode()" function
6948 */
6949 static void
6950f_json_encode(typval_T *argvars, typval_T *rettv)
6951{
6952 rettv->v_type = VAR_STRING;
6953 rettv->vval.v_string = json_encode(&argvars[0], 0);
6954}
6955
6956/*
6957 * "keys()" function
6958 */
6959 static void
6960f_keys(typval_T *argvars, typval_T *rettv)
6961{
6962 dict_list(argvars, rettv, 0);
6963}
6964
6965/*
6966 * "last_buffer_nr()" function.
6967 */
6968 static void
6969f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6970{
6971 int n = 0;
6972 buf_T *buf;
6973
Bram Moolenaar29323592016-07-24 22:04:11 +02006974 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 if (n < buf->b_fnum)
6976 n = buf->b_fnum;
6977
6978 rettv->vval.v_number = n;
6979}
6980
6981/*
6982 * "len()" function
6983 */
6984 static void
6985f_len(typval_T *argvars, typval_T *rettv)
6986{
6987 switch (argvars[0].v_type)
6988 {
6989 case VAR_STRING:
6990 case VAR_NUMBER:
6991 rettv->vval.v_number = (varnumber_T)STRLEN(
6992 get_tv_string(&argvars[0]));
6993 break;
6994 case VAR_LIST:
6995 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6996 break;
6997 case VAR_DICT:
6998 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6999 break;
7000 case VAR_UNKNOWN:
7001 case VAR_SPECIAL:
7002 case VAR_FLOAT:
7003 case VAR_FUNC:
7004 case VAR_PARTIAL:
7005 case VAR_JOB:
7006 case VAR_CHANNEL:
7007 EMSG(_("E701: Invalid type for len()"));
7008 break;
7009 }
7010}
7011
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007012 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007013libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007014{
7015#ifdef FEAT_LIBCALL
7016 char_u *string_in;
7017 char_u **string_result;
7018 int nr_result;
7019#endif
7020
7021 rettv->v_type = type;
7022 if (type != VAR_NUMBER)
7023 rettv->vval.v_string = NULL;
7024
7025 if (check_restricted() || check_secure())
7026 return;
7027
7028#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007029 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007030 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7031 {
7032 string_in = NULL;
7033 if (argvars[2].v_type == VAR_STRING)
7034 string_in = argvars[2].vval.v_string;
7035 if (type == VAR_NUMBER)
7036 string_result = NULL;
7037 else
7038 string_result = &rettv->vval.v_string;
7039 if (mch_libcall(argvars[0].vval.v_string,
7040 argvars[1].vval.v_string,
7041 string_in,
7042 argvars[2].vval.v_number,
7043 string_result,
7044 &nr_result) == OK
7045 && type == VAR_NUMBER)
7046 rettv->vval.v_number = nr_result;
7047 }
7048#endif
7049}
7050
7051/*
7052 * "libcall()" function
7053 */
7054 static void
7055f_libcall(typval_T *argvars, typval_T *rettv)
7056{
7057 libcall_common(argvars, rettv, VAR_STRING);
7058}
7059
7060/*
7061 * "libcallnr()" function
7062 */
7063 static void
7064f_libcallnr(typval_T *argvars, typval_T *rettv)
7065{
7066 libcall_common(argvars, rettv, VAR_NUMBER);
7067}
7068
7069/*
7070 * "line(string)" function
7071 */
7072 static void
7073f_line(typval_T *argvars, typval_T *rettv)
7074{
7075 linenr_T lnum = 0;
7076 pos_T *fp;
7077 int fnum;
7078
7079 fp = var2fpos(&argvars[0], TRUE, &fnum);
7080 if (fp != NULL)
7081 lnum = fp->lnum;
7082 rettv->vval.v_number = lnum;
7083}
7084
7085/*
7086 * "line2byte(lnum)" function
7087 */
7088 static void
7089f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7090{
7091#ifndef FEAT_BYTEOFF
7092 rettv->vval.v_number = -1;
7093#else
7094 linenr_T lnum;
7095
7096 lnum = get_tv_lnum(argvars);
7097 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7098 rettv->vval.v_number = -1;
7099 else
7100 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7101 if (rettv->vval.v_number >= 0)
7102 ++rettv->vval.v_number;
7103#endif
7104}
7105
7106/*
7107 * "lispindent(lnum)" function
7108 */
7109 static void
7110f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7111{
7112#ifdef FEAT_LISP
7113 pos_T pos;
7114 linenr_T lnum;
7115
7116 pos = curwin->w_cursor;
7117 lnum = get_tv_lnum(argvars);
7118 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7119 {
7120 curwin->w_cursor.lnum = lnum;
7121 rettv->vval.v_number = get_lisp_indent();
7122 curwin->w_cursor = pos;
7123 }
7124 else
7125#endif
7126 rettv->vval.v_number = -1;
7127}
7128
7129/*
7130 * "localtime()" function
7131 */
7132 static void
7133f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7134{
7135 rettv->vval.v_number = (varnumber_T)time(NULL);
7136}
7137
7138static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7139
7140 static void
7141get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7142{
7143 char_u *keys;
7144 char_u *which;
7145 char_u buf[NUMBUFLEN];
7146 char_u *keys_buf = NULL;
7147 char_u *rhs;
7148 int mode;
7149 int abbr = FALSE;
7150 int get_dict = FALSE;
7151 mapblock_T *mp;
7152 int buffer_local;
7153
7154 /* return empty string for failure */
7155 rettv->v_type = VAR_STRING;
7156 rettv->vval.v_string = NULL;
7157
7158 keys = get_tv_string(&argvars[0]);
7159 if (*keys == NUL)
7160 return;
7161
7162 if (argvars[1].v_type != VAR_UNKNOWN)
7163 {
7164 which = get_tv_string_buf_chk(&argvars[1], buf);
7165 if (argvars[2].v_type != VAR_UNKNOWN)
7166 {
7167 abbr = (int)get_tv_number(&argvars[2]);
7168 if (argvars[3].v_type != VAR_UNKNOWN)
7169 get_dict = (int)get_tv_number(&argvars[3]);
7170 }
7171 }
7172 else
7173 which = (char_u *)"";
7174 if (which == NULL)
7175 return;
7176
7177 mode = get_map_mode(&which, 0);
7178
7179 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7180 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7181 vim_free(keys_buf);
7182
7183 if (!get_dict)
7184 {
7185 /* Return a string. */
7186 if (rhs != NULL)
7187 rettv->vval.v_string = str2special_save(rhs, FALSE);
7188
7189 }
7190 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7191 {
7192 /* Return a dictionary. */
7193 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7194 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7195 dict_T *dict = rettv->vval.v_dict;
7196
7197 dict_add_nr_str(dict, "lhs", 0L, lhs);
7198 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7199 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7200 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7201 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7202 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7203 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7204 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7205 dict_add_nr_str(dict, "mode", 0L, mapmode);
7206
7207 vim_free(lhs);
7208 vim_free(mapmode);
7209 }
7210}
7211
7212#ifdef FEAT_FLOAT
7213/*
7214 * "log()" function
7215 */
7216 static void
7217f_log(typval_T *argvars, typval_T *rettv)
7218{
7219 float_T f = 0.0;
7220
7221 rettv->v_type = VAR_FLOAT;
7222 if (get_float_arg(argvars, &f) == OK)
7223 rettv->vval.v_float = log(f);
7224 else
7225 rettv->vval.v_float = 0.0;
7226}
7227
7228/*
7229 * "log10()" function
7230 */
7231 static void
7232f_log10(typval_T *argvars, typval_T *rettv)
7233{
7234 float_T f = 0.0;
7235
7236 rettv->v_type = VAR_FLOAT;
7237 if (get_float_arg(argvars, &f) == OK)
7238 rettv->vval.v_float = log10(f);
7239 else
7240 rettv->vval.v_float = 0.0;
7241}
7242#endif
7243
7244#ifdef FEAT_LUA
7245/*
7246 * "luaeval()" function
7247 */
7248 static void
7249f_luaeval(typval_T *argvars, typval_T *rettv)
7250{
7251 char_u *str;
7252 char_u buf[NUMBUFLEN];
7253
7254 str = get_tv_string_buf(&argvars[0], buf);
7255 do_luaeval(str, argvars + 1, rettv);
7256}
7257#endif
7258
7259/*
7260 * "map()" function
7261 */
7262 static void
7263f_map(typval_T *argvars, typval_T *rettv)
7264{
7265 filter_map(argvars, rettv, TRUE);
7266}
7267
7268/*
7269 * "maparg()" function
7270 */
7271 static void
7272f_maparg(typval_T *argvars, typval_T *rettv)
7273{
7274 get_maparg(argvars, rettv, TRUE);
7275}
7276
7277/*
7278 * "mapcheck()" function
7279 */
7280 static void
7281f_mapcheck(typval_T *argvars, typval_T *rettv)
7282{
7283 get_maparg(argvars, rettv, FALSE);
7284}
7285
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007286typedef enum
7287{
7288 MATCH_END, /* matchend() */
7289 MATCH_MATCH, /* match() */
7290 MATCH_STR, /* matchstr() */
7291 MATCH_LIST, /* matchlist() */
7292 MATCH_POS /* matchstrpos() */
7293} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294
7295 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007296find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007297{
7298 char_u *str = NULL;
7299 long len = 0;
7300 char_u *expr = NULL;
7301 char_u *pat;
7302 regmatch_T regmatch;
7303 char_u patbuf[NUMBUFLEN];
7304 char_u strbuf[NUMBUFLEN];
7305 char_u *save_cpo;
7306 long start = 0;
7307 long nth = 1;
7308 colnr_T startcol = 0;
7309 int match = 0;
7310 list_T *l = NULL;
7311 listitem_T *li = NULL;
7312 long idx = 0;
7313 char_u *tofree = NULL;
7314
7315 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7316 save_cpo = p_cpo;
7317 p_cpo = (char_u *)"";
7318
7319 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007320 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007321 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007322 /* type MATCH_LIST: return empty list when there are no matches.
7323 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324 if (rettv_list_alloc(rettv) == FAIL)
7325 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007326 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007327 && (list_append_string(rettv->vval.v_list,
7328 (char_u *)"", 0) == FAIL
7329 || list_append_number(rettv->vval.v_list,
7330 (varnumber_T)-1) == FAIL
7331 || list_append_number(rettv->vval.v_list,
7332 (varnumber_T)-1) == FAIL
7333 || list_append_number(rettv->vval.v_list,
7334 (varnumber_T)-1) == FAIL))
7335 {
7336 list_free(rettv->vval.v_list);
7337 rettv->vval.v_list = NULL;
7338 goto theend;
7339 }
7340 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007341 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342 {
7343 rettv->v_type = VAR_STRING;
7344 rettv->vval.v_string = NULL;
7345 }
7346
7347 if (argvars[0].v_type == VAR_LIST)
7348 {
7349 if ((l = argvars[0].vval.v_list) == NULL)
7350 goto theend;
7351 li = l->lv_first;
7352 }
7353 else
7354 {
7355 expr = str = get_tv_string(&argvars[0]);
7356 len = (long)STRLEN(str);
7357 }
7358
7359 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7360 if (pat == NULL)
7361 goto theend;
7362
7363 if (argvars[2].v_type != VAR_UNKNOWN)
7364 {
7365 int error = FALSE;
7366
7367 start = (long)get_tv_number_chk(&argvars[2], &error);
7368 if (error)
7369 goto theend;
7370 if (l != NULL)
7371 {
7372 li = list_find(l, start);
7373 if (li == NULL)
7374 goto theend;
7375 idx = l->lv_idx; /* use the cached index */
7376 }
7377 else
7378 {
7379 if (start < 0)
7380 start = 0;
7381 if (start > len)
7382 goto theend;
7383 /* When "count" argument is there ignore matches before "start",
7384 * otherwise skip part of the string. Differs when pattern is "^"
7385 * or "\<". */
7386 if (argvars[3].v_type != VAR_UNKNOWN)
7387 startcol = start;
7388 else
7389 {
7390 str += start;
7391 len -= start;
7392 }
7393 }
7394
7395 if (argvars[3].v_type != VAR_UNKNOWN)
7396 nth = (long)get_tv_number_chk(&argvars[3], &error);
7397 if (error)
7398 goto theend;
7399 }
7400
7401 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7402 if (regmatch.regprog != NULL)
7403 {
7404 regmatch.rm_ic = p_ic;
7405
7406 for (;;)
7407 {
7408 if (l != NULL)
7409 {
7410 if (li == NULL)
7411 {
7412 match = FALSE;
7413 break;
7414 }
7415 vim_free(tofree);
7416 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7417 if (str == NULL)
7418 break;
7419 }
7420
7421 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7422
7423 if (match && --nth <= 0)
7424 break;
7425 if (l == NULL && !match)
7426 break;
7427
7428 /* Advance to just after the match. */
7429 if (l != NULL)
7430 {
7431 li = li->li_next;
7432 ++idx;
7433 }
7434 else
7435 {
7436#ifdef FEAT_MBYTE
7437 startcol = (colnr_T)(regmatch.startp[0]
7438 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7439#else
7440 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7441#endif
7442 if (startcol > (colnr_T)len
7443 || str + startcol <= regmatch.startp[0])
7444 {
7445 match = FALSE;
7446 break;
7447 }
7448 }
7449 }
7450
7451 if (match)
7452 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007453 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007454 {
7455 listitem_T *li1 = rettv->vval.v_list->lv_first;
7456 listitem_T *li2 = li1->li_next;
7457 listitem_T *li3 = li2->li_next;
7458 listitem_T *li4 = li3->li_next;
7459
7460 vim_free(li1->li_tv.vval.v_string);
7461 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7462 (int)(regmatch.endp[0] - regmatch.startp[0]));
7463 li3->li_tv.vval.v_number =
7464 (varnumber_T)(regmatch.startp[0] - expr);
7465 li4->li_tv.vval.v_number =
7466 (varnumber_T)(regmatch.endp[0] - expr);
7467 if (l != NULL)
7468 li2->li_tv.vval.v_number = (varnumber_T)idx;
7469 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007470 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 {
7472 int i;
7473
7474 /* return list with matched string and submatches */
7475 for (i = 0; i < NSUBEXP; ++i)
7476 {
7477 if (regmatch.endp[i] == NULL)
7478 {
7479 if (list_append_string(rettv->vval.v_list,
7480 (char_u *)"", 0) == FAIL)
7481 break;
7482 }
7483 else if (list_append_string(rettv->vval.v_list,
7484 regmatch.startp[i],
7485 (int)(regmatch.endp[i] - regmatch.startp[i]))
7486 == FAIL)
7487 break;
7488 }
7489 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007490 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491 {
7492 /* return matched string */
7493 if (l != NULL)
7494 copy_tv(&li->li_tv, rettv);
7495 else
7496 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7497 (int)(regmatch.endp[0] - regmatch.startp[0]));
7498 }
7499 else if (l != NULL)
7500 rettv->vval.v_number = idx;
7501 else
7502 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007503 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 rettv->vval.v_number =
7505 (varnumber_T)(regmatch.startp[0] - str);
7506 else
7507 rettv->vval.v_number =
7508 (varnumber_T)(regmatch.endp[0] - str);
7509 rettv->vval.v_number += (varnumber_T)(str - expr);
7510 }
7511 }
7512 vim_regfree(regmatch.regprog);
7513 }
7514
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007515theend:
7516 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 /* matchstrpos() without a list: drop the second item. */
7518 listitem_remove(rettv->vval.v_list,
7519 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007520 vim_free(tofree);
7521 p_cpo = save_cpo;
7522}
7523
7524/*
7525 * "match()" function
7526 */
7527 static void
7528f_match(typval_T *argvars, typval_T *rettv)
7529{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007530 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531}
7532
7533/*
7534 * "matchadd()" function
7535 */
7536 static void
7537f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7538{
7539#ifdef FEAT_SEARCH_EXTRA
7540 char_u buf[NUMBUFLEN];
7541 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7542 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7543 int prio = 10; /* default priority */
7544 int id = -1;
7545 int error = FALSE;
7546 char_u *conceal_char = NULL;
7547
7548 rettv->vval.v_number = -1;
7549
7550 if (grp == NULL || pat == NULL)
7551 return;
7552 if (argvars[2].v_type != VAR_UNKNOWN)
7553 {
7554 prio = (int)get_tv_number_chk(&argvars[2], &error);
7555 if (argvars[3].v_type != VAR_UNKNOWN)
7556 {
7557 id = (int)get_tv_number_chk(&argvars[3], &error);
7558 if (argvars[4].v_type != VAR_UNKNOWN)
7559 {
7560 if (argvars[4].v_type != VAR_DICT)
7561 {
7562 EMSG(_(e_dictreq));
7563 return;
7564 }
7565 if (dict_find(argvars[4].vval.v_dict,
7566 (char_u *)"conceal", -1) != NULL)
7567 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7568 (char_u *)"conceal", FALSE);
7569 }
7570 }
7571 }
7572 if (error == TRUE)
7573 return;
7574 if (id >= 1 && id <= 3)
7575 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007576 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 return;
7578 }
7579
7580 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7581 conceal_char);
7582#endif
7583}
7584
7585/*
7586 * "matchaddpos()" function
7587 */
7588 static void
7589f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7590{
7591#ifdef FEAT_SEARCH_EXTRA
7592 char_u buf[NUMBUFLEN];
7593 char_u *group;
7594 int prio = 10;
7595 int id = -1;
7596 int error = FALSE;
7597 list_T *l;
7598 char_u *conceal_char = NULL;
7599
7600 rettv->vval.v_number = -1;
7601
7602 group = get_tv_string_buf_chk(&argvars[0], buf);
7603 if (group == NULL)
7604 return;
7605
7606 if (argvars[1].v_type != VAR_LIST)
7607 {
7608 EMSG2(_(e_listarg), "matchaddpos()");
7609 return;
7610 }
7611 l = argvars[1].vval.v_list;
7612 if (l == NULL)
7613 return;
7614
7615 if (argvars[2].v_type != VAR_UNKNOWN)
7616 {
7617 prio = (int)get_tv_number_chk(&argvars[2], &error);
7618 if (argvars[3].v_type != VAR_UNKNOWN)
7619 {
7620 id = (int)get_tv_number_chk(&argvars[3], &error);
7621 if (argvars[4].v_type != VAR_UNKNOWN)
7622 {
7623 if (argvars[4].v_type != VAR_DICT)
7624 {
7625 EMSG(_(e_dictreq));
7626 return;
7627 }
7628 if (dict_find(argvars[4].vval.v_dict,
7629 (char_u *)"conceal", -1) != NULL)
7630 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7631 (char_u *)"conceal", FALSE);
7632 }
7633 }
7634 }
7635 if (error == TRUE)
7636 return;
7637
7638 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7639 if (id == 1 || id == 2)
7640 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007641 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007642 return;
7643 }
7644
7645 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7646 conceal_char);
7647#endif
7648}
7649
7650/*
7651 * "matcharg()" function
7652 */
7653 static void
7654f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7655{
7656 if (rettv_list_alloc(rettv) == OK)
7657 {
7658#ifdef FEAT_SEARCH_EXTRA
7659 int id = (int)get_tv_number(&argvars[0]);
7660 matchitem_T *m;
7661
7662 if (id >= 1 && id <= 3)
7663 {
7664 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7665 {
7666 list_append_string(rettv->vval.v_list,
7667 syn_id2name(m->hlg_id), -1);
7668 list_append_string(rettv->vval.v_list, m->pattern, -1);
7669 }
7670 else
7671 {
7672 list_append_string(rettv->vval.v_list, NULL, -1);
7673 list_append_string(rettv->vval.v_list, NULL, -1);
7674 }
7675 }
7676#endif
7677 }
7678}
7679
7680/*
7681 * "matchdelete()" function
7682 */
7683 static void
7684f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7685{
7686#ifdef FEAT_SEARCH_EXTRA
7687 rettv->vval.v_number = match_delete(curwin,
7688 (int)get_tv_number(&argvars[0]), TRUE);
7689#endif
7690}
7691
7692/*
7693 * "matchend()" function
7694 */
7695 static void
7696f_matchend(typval_T *argvars, typval_T *rettv)
7697{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007698 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007699}
7700
7701/*
7702 * "matchlist()" function
7703 */
7704 static void
7705f_matchlist(typval_T *argvars, typval_T *rettv)
7706{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007707 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007708}
7709
7710/*
7711 * "matchstr()" function
7712 */
7713 static void
7714f_matchstr(typval_T *argvars, typval_T *rettv)
7715{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007716 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717}
7718
7719/*
7720 * "matchstrpos()" function
7721 */
7722 static void
7723f_matchstrpos(typval_T *argvars, typval_T *rettv)
7724{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007725 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726}
7727
7728static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7729
7730 static void
7731max_min(typval_T *argvars, typval_T *rettv, int domax)
7732{
7733 varnumber_T n = 0;
7734 varnumber_T i;
7735 int error = FALSE;
7736
7737 if (argvars[0].v_type == VAR_LIST)
7738 {
7739 list_T *l;
7740 listitem_T *li;
7741
7742 l = argvars[0].vval.v_list;
7743 if (l != NULL)
7744 {
7745 li = l->lv_first;
7746 if (li != NULL)
7747 {
7748 n = get_tv_number_chk(&li->li_tv, &error);
7749 for (;;)
7750 {
7751 li = li->li_next;
7752 if (li == NULL)
7753 break;
7754 i = get_tv_number_chk(&li->li_tv, &error);
7755 if (domax ? i > n : i < n)
7756 n = i;
7757 }
7758 }
7759 }
7760 }
7761 else if (argvars[0].v_type == VAR_DICT)
7762 {
7763 dict_T *d;
7764 int first = TRUE;
7765 hashitem_T *hi;
7766 int todo;
7767
7768 d = argvars[0].vval.v_dict;
7769 if (d != NULL)
7770 {
7771 todo = (int)d->dv_hashtab.ht_used;
7772 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7773 {
7774 if (!HASHITEM_EMPTY(hi))
7775 {
7776 --todo;
7777 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7778 if (first)
7779 {
7780 n = i;
7781 first = FALSE;
7782 }
7783 else if (domax ? i > n : i < n)
7784 n = i;
7785 }
7786 }
7787 }
7788 }
7789 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007790 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007791 rettv->vval.v_number = error ? 0 : n;
7792}
7793
7794/*
7795 * "max()" function
7796 */
7797 static void
7798f_max(typval_T *argvars, typval_T *rettv)
7799{
7800 max_min(argvars, rettv, TRUE);
7801}
7802
7803/*
7804 * "min()" function
7805 */
7806 static void
7807f_min(typval_T *argvars, typval_T *rettv)
7808{
7809 max_min(argvars, rettv, FALSE);
7810}
7811
7812static int mkdir_recurse(char_u *dir, int prot);
7813
7814/*
7815 * Create the directory in which "dir" is located, and higher levels when
7816 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007817 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007818 */
7819 static int
7820mkdir_recurse(char_u *dir, int prot)
7821{
7822 char_u *p;
7823 char_u *updir;
7824 int r = FAIL;
7825
7826 /* Get end of directory name in "dir".
7827 * We're done when it's "/" or "c:/". */
7828 p = gettail_sep(dir);
7829 if (p <= get_past_head(dir))
7830 return OK;
7831
7832 /* If the directory exists we're done. Otherwise: create it.*/
7833 updir = vim_strnsave(dir, (int)(p - dir));
7834 if (updir == NULL)
7835 return FAIL;
7836 if (mch_isdir(updir))
7837 r = OK;
7838 else if (mkdir_recurse(updir, prot) == OK)
7839 r = vim_mkdir_emsg(updir, prot);
7840 vim_free(updir);
7841 return r;
7842}
7843
7844#ifdef vim_mkdir
7845/*
7846 * "mkdir()" function
7847 */
7848 static void
7849f_mkdir(typval_T *argvars, typval_T *rettv)
7850{
7851 char_u *dir;
7852 char_u buf[NUMBUFLEN];
7853 int prot = 0755;
7854
7855 rettv->vval.v_number = FAIL;
7856 if (check_restricted() || check_secure())
7857 return;
7858
7859 dir = get_tv_string_buf(&argvars[0], buf);
7860 if (*dir == NUL)
7861 rettv->vval.v_number = FAIL;
7862 else
7863 {
7864 if (*gettail(dir) == NUL)
7865 /* remove trailing slashes */
7866 *gettail_sep(dir) = NUL;
7867
7868 if (argvars[1].v_type != VAR_UNKNOWN)
7869 {
7870 if (argvars[2].v_type != VAR_UNKNOWN)
7871 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7872 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7873 mkdir_recurse(dir, prot);
7874 }
7875 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7876 }
7877}
7878#endif
7879
7880/*
7881 * "mode()" function
7882 */
7883 static void
7884f_mode(typval_T *argvars, typval_T *rettv)
7885{
7886 char_u buf[3];
7887
7888 buf[1] = NUL;
7889 buf[2] = NUL;
7890
7891 if (time_for_testing == 93784)
7892 {
7893 /* Testing the two-character code. */
7894 buf[0] = 'x';
7895 buf[1] = '!';
7896 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007897#ifdef FEAT_TERMINAL
7898 else if (term_use_loop())
7899 buf[0] = 't';
7900#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007901 else if (VIsual_active)
7902 {
7903 if (VIsual_select)
7904 buf[0] = VIsual_mode + 's' - 'v';
7905 else
7906 buf[0] = VIsual_mode;
7907 }
7908 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7909 || State == CONFIRM)
7910 {
7911 buf[0] = 'r';
7912 if (State == ASKMORE)
7913 buf[1] = 'm';
7914 else if (State == CONFIRM)
7915 buf[1] = '?';
7916 }
7917 else if (State == EXTERNCMD)
7918 buf[0] = '!';
7919 else if (State & INSERT)
7920 {
7921#ifdef FEAT_VREPLACE
7922 if (State & VREPLACE_FLAG)
7923 {
7924 buf[0] = 'R';
7925 buf[1] = 'v';
7926 }
7927 else
7928#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01007929 {
7930 if (State & REPLACE_FLAG)
7931 buf[0] = 'R';
7932 else
7933 buf[0] = 'i';
7934#ifdef FEAT_INS_EXPAND
7935 if (ins_compl_active())
7936 buf[1] = 'c';
7937 else if (ctrl_x_mode == 1)
7938 buf[1] = 'x';
7939#endif
7940 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007941 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007942 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007943 {
7944 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007945 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007946 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007947 else if (exmode_active == EXMODE_NORMAL)
7948 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007949 }
7950 else
7951 {
7952 buf[0] = 'n';
7953 if (finish_op)
7954 buf[1] = 'o';
7955 }
7956
7957 /* Clear out the minor mode when the argument is not a non-zero number or
7958 * non-empty string. */
7959 if (!non_zero_arg(&argvars[0]))
7960 buf[1] = NUL;
7961
7962 rettv->vval.v_string = vim_strsave(buf);
7963 rettv->v_type = VAR_STRING;
7964}
7965
7966#if defined(FEAT_MZSCHEME) || defined(PROTO)
7967/*
7968 * "mzeval()" function
7969 */
7970 static void
7971f_mzeval(typval_T *argvars, typval_T *rettv)
7972{
7973 char_u *str;
7974 char_u buf[NUMBUFLEN];
7975
7976 str = get_tv_string_buf(&argvars[0], buf);
7977 do_mzeval(str, rettv);
7978}
7979
7980 void
7981mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7982{
7983 typval_T argvars[3];
7984
7985 argvars[0].v_type = VAR_STRING;
7986 argvars[0].vval.v_string = name;
7987 copy_tv(args, &argvars[1]);
7988 argvars[2].v_type = VAR_UNKNOWN;
7989 f_call(argvars, rettv);
7990 clear_tv(&argvars[1]);
7991}
7992#endif
7993
7994/*
7995 * "nextnonblank()" function
7996 */
7997 static void
7998f_nextnonblank(typval_T *argvars, typval_T *rettv)
7999{
8000 linenr_T lnum;
8001
8002 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8003 {
8004 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8005 {
8006 lnum = 0;
8007 break;
8008 }
8009 if (*skipwhite(ml_get(lnum)) != NUL)
8010 break;
8011 }
8012 rettv->vval.v_number = lnum;
8013}
8014
8015/*
8016 * "nr2char()" function
8017 */
8018 static void
8019f_nr2char(typval_T *argvars, typval_T *rettv)
8020{
8021 char_u buf[NUMBUFLEN];
8022
8023#ifdef FEAT_MBYTE
8024 if (has_mbyte)
8025 {
8026 int utf8 = 0;
8027
8028 if (argvars[1].v_type != VAR_UNKNOWN)
8029 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8030 if (utf8)
8031 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8032 else
8033 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8034 }
8035 else
8036#endif
8037 {
8038 buf[0] = (char_u)get_tv_number(&argvars[0]);
8039 buf[1] = NUL;
8040 }
8041 rettv->v_type = VAR_STRING;
8042 rettv->vval.v_string = vim_strsave(buf);
8043}
8044
8045/*
8046 * "or(expr, expr)" function
8047 */
8048 static void
8049f_or(typval_T *argvars, typval_T *rettv)
8050{
8051 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8052 | get_tv_number_chk(&argvars[1], NULL);
8053}
8054
8055/*
8056 * "pathshorten()" function
8057 */
8058 static void
8059f_pathshorten(typval_T *argvars, typval_T *rettv)
8060{
8061 char_u *p;
8062
8063 rettv->v_type = VAR_STRING;
8064 p = get_tv_string_chk(&argvars[0]);
8065 if (p == NULL)
8066 rettv->vval.v_string = NULL;
8067 else
8068 {
8069 p = vim_strsave(p);
8070 rettv->vval.v_string = p;
8071 if (p != NULL)
8072 shorten_dir(p);
8073 }
8074}
8075
8076#ifdef FEAT_PERL
8077/*
8078 * "perleval()" function
8079 */
8080 static void
8081f_perleval(typval_T *argvars, typval_T *rettv)
8082{
8083 char_u *str;
8084 char_u buf[NUMBUFLEN];
8085
8086 str = get_tv_string_buf(&argvars[0], buf);
8087 do_perleval(str, rettv);
8088}
8089#endif
8090
8091#ifdef FEAT_FLOAT
8092/*
8093 * "pow()" function
8094 */
8095 static void
8096f_pow(typval_T *argvars, typval_T *rettv)
8097{
8098 float_T fx = 0.0, fy = 0.0;
8099
8100 rettv->v_type = VAR_FLOAT;
8101 if (get_float_arg(argvars, &fx) == OK
8102 && get_float_arg(&argvars[1], &fy) == OK)
8103 rettv->vval.v_float = pow(fx, fy);
8104 else
8105 rettv->vval.v_float = 0.0;
8106}
8107#endif
8108
8109/*
8110 * "prevnonblank()" function
8111 */
8112 static void
8113f_prevnonblank(typval_T *argvars, typval_T *rettv)
8114{
8115 linenr_T lnum;
8116
8117 lnum = get_tv_lnum(argvars);
8118 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8119 lnum = 0;
8120 else
8121 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8122 --lnum;
8123 rettv->vval.v_number = lnum;
8124}
8125
8126/* This dummy va_list is here because:
8127 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8128 * - locally in the function results in a "used before set" warning
8129 * - using va_start() to initialize it gives "function with fixed args" error */
8130static va_list ap;
8131
8132/*
8133 * "printf()" function
8134 */
8135 static void
8136f_printf(typval_T *argvars, typval_T *rettv)
8137{
8138 char_u buf[NUMBUFLEN];
8139 int len;
8140 char_u *s;
8141 int saved_did_emsg = did_emsg;
8142 char *fmt;
8143
8144 rettv->v_type = VAR_STRING;
8145 rettv->vval.v_string = NULL;
8146
8147 /* Get the required length, allocate the buffer and do it for real. */
8148 did_emsg = FALSE;
8149 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008150 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008151 if (!did_emsg)
8152 {
8153 s = alloc(len + 1);
8154 if (s != NULL)
8155 {
8156 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008157 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8158 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 }
8160 }
8161 did_emsg |= saved_did_emsg;
8162}
8163
8164/*
8165 * "pumvisible()" function
8166 */
8167 static void
8168f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8169{
8170#ifdef FEAT_INS_EXPAND
8171 if (pum_visible())
8172 rettv->vval.v_number = 1;
8173#endif
8174}
8175
8176#ifdef FEAT_PYTHON3
8177/*
8178 * "py3eval()" function
8179 */
8180 static void
8181f_py3eval(typval_T *argvars, typval_T *rettv)
8182{
8183 char_u *str;
8184 char_u buf[NUMBUFLEN];
8185
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008186 if (p_pyx == 0)
8187 p_pyx = 3;
8188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008189 str = get_tv_string_buf(&argvars[0], buf);
8190 do_py3eval(str, rettv);
8191}
8192#endif
8193
8194#ifdef FEAT_PYTHON
8195/*
8196 * "pyeval()" function
8197 */
8198 static void
8199f_pyeval(typval_T *argvars, typval_T *rettv)
8200{
8201 char_u *str;
8202 char_u buf[NUMBUFLEN];
8203
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008204 if (p_pyx == 0)
8205 p_pyx = 2;
8206
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008207 str = get_tv_string_buf(&argvars[0], buf);
8208 do_pyeval(str, rettv);
8209}
8210#endif
8211
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008212#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8213/*
8214 * "pyxeval()" function
8215 */
8216 static void
8217f_pyxeval(typval_T *argvars, typval_T *rettv)
8218{
8219# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8220 init_pyxversion();
8221 if (p_pyx == 2)
8222 f_pyeval(argvars, rettv);
8223 else
8224 f_py3eval(argvars, rettv);
8225# elif defined(FEAT_PYTHON)
8226 f_pyeval(argvars, rettv);
8227# elif defined(FEAT_PYTHON3)
8228 f_py3eval(argvars, rettv);
8229# endif
8230}
8231#endif
8232
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008233/*
8234 * "range()" function
8235 */
8236 static void
8237f_range(typval_T *argvars, typval_T *rettv)
8238{
8239 varnumber_T start;
8240 varnumber_T end;
8241 varnumber_T stride = 1;
8242 varnumber_T i;
8243 int error = FALSE;
8244
8245 start = get_tv_number_chk(&argvars[0], &error);
8246 if (argvars[1].v_type == VAR_UNKNOWN)
8247 {
8248 end = start - 1;
8249 start = 0;
8250 }
8251 else
8252 {
8253 end = get_tv_number_chk(&argvars[1], &error);
8254 if (argvars[2].v_type != VAR_UNKNOWN)
8255 stride = get_tv_number_chk(&argvars[2], &error);
8256 }
8257
8258 if (error)
8259 return; /* type error; errmsg already given */
8260 if (stride == 0)
8261 EMSG(_("E726: Stride is zero"));
8262 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8263 EMSG(_("E727: Start past end"));
8264 else
8265 {
8266 if (rettv_list_alloc(rettv) == OK)
8267 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8268 if (list_append_number(rettv->vval.v_list,
8269 (varnumber_T)i) == FAIL)
8270 break;
8271 }
8272}
8273
8274/*
8275 * "readfile()" function
8276 */
8277 static void
8278f_readfile(typval_T *argvars, typval_T *rettv)
8279{
8280 int binary = FALSE;
8281 int failed = FALSE;
8282 char_u *fname;
8283 FILE *fd;
8284 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8285 int io_size = sizeof(buf);
8286 int readlen; /* size of last fread() */
8287 char_u *prev = NULL; /* previously read bytes, if any */
8288 long prevlen = 0; /* length of data in prev */
8289 long prevsize = 0; /* size of prev buffer */
8290 long maxline = MAXLNUM;
8291 long cnt = 0;
8292 char_u *p; /* position in buf */
8293 char_u *start; /* start of current line */
8294
8295 if (argvars[1].v_type != VAR_UNKNOWN)
8296 {
8297 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8298 binary = TRUE;
8299 if (argvars[2].v_type != VAR_UNKNOWN)
8300 maxline = (long)get_tv_number(&argvars[2]);
8301 }
8302
8303 if (rettv_list_alloc(rettv) == FAIL)
8304 return;
8305
8306 /* Always open the file in binary mode, library functions have a mind of
8307 * their own about CR-LF conversion. */
8308 fname = get_tv_string(&argvars[0]);
8309 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8310 {
8311 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8312 return;
8313 }
8314
8315 while (cnt < maxline || maxline < 0)
8316 {
8317 readlen = (int)fread(buf, 1, io_size, fd);
8318
8319 /* This for loop processes what was read, but is also entered at end
8320 * of file so that either:
8321 * - an incomplete line gets written
8322 * - a "binary" file gets an empty line at the end if it ends in a
8323 * newline. */
8324 for (p = buf, start = buf;
8325 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8326 ++p)
8327 {
8328 if (*p == '\n' || readlen <= 0)
8329 {
8330 listitem_T *li;
8331 char_u *s = NULL;
8332 long_u len = p - start;
8333
8334 /* Finished a line. Remove CRs before NL. */
8335 if (readlen > 0 && !binary)
8336 {
8337 while (len > 0 && start[len - 1] == '\r')
8338 --len;
8339 /* removal may cross back to the "prev" string */
8340 if (len == 0)
8341 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8342 --prevlen;
8343 }
8344 if (prevlen == 0)
8345 s = vim_strnsave(start, (int)len);
8346 else
8347 {
8348 /* Change "prev" buffer to be the right size. This way
8349 * the bytes are only copied once, and very long lines are
8350 * allocated only once. */
8351 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8352 {
8353 mch_memmove(s + prevlen, start, len);
8354 s[prevlen + len] = NUL;
8355 prev = NULL; /* the list will own the string */
8356 prevlen = prevsize = 0;
8357 }
8358 }
8359 if (s == NULL)
8360 {
8361 do_outofmem_msg((long_u) prevlen + len + 1);
8362 failed = TRUE;
8363 break;
8364 }
8365
8366 if ((li = listitem_alloc()) == NULL)
8367 {
8368 vim_free(s);
8369 failed = TRUE;
8370 break;
8371 }
8372 li->li_tv.v_type = VAR_STRING;
8373 li->li_tv.v_lock = 0;
8374 li->li_tv.vval.v_string = s;
8375 list_append(rettv->vval.v_list, li);
8376
8377 start = p + 1; /* step over newline */
8378 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8379 break;
8380 }
8381 else if (*p == NUL)
8382 *p = '\n';
8383#ifdef FEAT_MBYTE
8384 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8385 * when finding the BF and check the previous two bytes. */
8386 else if (*p == 0xbf && enc_utf8 && !binary)
8387 {
8388 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8389 * + 1, these may be in the "prev" string. */
8390 char_u back1 = p >= buf + 1 ? p[-1]
8391 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8392 char_u back2 = p >= buf + 2 ? p[-2]
8393 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8394 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8395
8396 if (back2 == 0xef && back1 == 0xbb)
8397 {
8398 char_u *dest = p - 2;
8399
8400 /* Usually a BOM is at the beginning of a file, and so at
8401 * the beginning of a line; then we can just step over it.
8402 */
8403 if (start == dest)
8404 start = p + 1;
8405 else
8406 {
8407 /* have to shuffle buf to close gap */
8408 int adjust_prevlen = 0;
8409
8410 if (dest < buf)
8411 {
8412 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8413 dest = buf;
8414 }
8415 if (readlen > p - buf + 1)
8416 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8417 readlen -= 3 - adjust_prevlen;
8418 prevlen -= adjust_prevlen;
8419 p = dest - 1;
8420 }
8421 }
8422 }
8423#endif
8424 } /* for */
8425
8426 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8427 break;
8428 if (start < p)
8429 {
8430 /* There's part of a line in buf, store it in "prev". */
8431 if (p - start + prevlen >= prevsize)
8432 {
8433 /* need bigger "prev" buffer */
8434 char_u *newprev;
8435
8436 /* A common use case is ordinary text files and "prev" gets a
8437 * fragment of a line, so the first allocation is made
8438 * small, to avoid repeatedly 'allocing' large and
8439 * 'reallocing' small. */
8440 if (prevsize == 0)
8441 prevsize = (long)(p - start);
8442 else
8443 {
8444 long grow50pc = (prevsize * 3) / 2;
8445 long growmin = (long)((p - start) * 2 + prevlen);
8446 prevsize = grow50pc > growmin ? grow50pc : growmin;
8447 }
8448 newprev = prev == NULL ? alloc(prevsize)
8449 : vim_realloc(prev, prevsize);
8450 if (newprev == NULL)
8451 {
8452 do_outofmem_msg((long_u)prevsize);
8453 failed = TRUE;
8454 break;
8455 }
8456 prev = newprev;
8457 }
8458 /* Add the line part to end of "prev". */
8459 mch_memmove(prev + prevlen, start, p - start);
8460 prevlen += (long)(p - start);
8461 }
8462 } /* while */
8463
8464 /*
8465 * For a negative line count use only the lines at the end of the file,
8466 * free the rest.
8467 */
8468 if (!failed && maxline < 0)
8469 while (cnt > -maxline)
8470 {
8471 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8472 --cnt;
8473 }
8474
8475 if (failed)
8476 {
8477 list_free(rettv->vval.v_list);
8478 /* readfile doc says an empty list is returned on error */
8479 rettv->vval.v_list = list_alloc();
8480 }
8481
8482 vim_free(prev);
8483 fclose(fd);
8484}
8485
8486#if defined(FEAT_RELTIME)
8487static int list2proftime(typval_T *arg, proftime_T *tm);
8488
8489/*
8490 * Convert a List to proftime_T.
8491 * Return FAIL when there is something wrong.
8492 */
8493 static int
8494list2proftime(typval_T *arg, proftime_T *tm)
8495{
8496 long n1, n2;
8497 int error = FALSE;
8498
8499 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8500 || arg->vval.v_list->lv_len != 2)
8501 return FAIL;
8502 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8503 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8504# ifdef WIN3264
8505 tm->HighPart = n1;
8506 tm->LowPart = n2;
8507# else
8508 tm->tv_sec = n1;
8509 tm->tv_usec = n2;
8510# endif
8511 return error ? FAIL : OK;
8512}
8513#endif /* FEAT_RELTIME */
8514
8515/*
8516 * "reltime()" function
8517 */
8518 static void
8519f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8520{
8521#ifdef FEAT_RELTIME
8522 proftime_T res;
8523 proftime_T start;
8524
8525 if (argvars[0].v_type == VAR_UNKNOWN)
8526 {
8527 /* No arguments: get current time. */
8528 profile_start(&res);
8529 }
8530 else if (argvars[1].v_type == VAR_UNKNOWN)
8531 {
8532 if (list2proftime(&argvars[0], &res) == FAIL)
8533 return;
8534 profile_end(&res);
8535 }
8536 else
8537 {
8538 /* Two arguments: compute the difference. */
8539 if (list2proftime(&argvars[0], &start) == FAIL
8540 || list2proftime(&argvars[1], &res) == FAIL)
8541 return;
8542 profile_sub(&res, &start);
8543 }
8544
8545 if (rettv_list_alloc(rettv) == OK)
8546 {
8547 long n1, n2;
8548
8549# ifdef WIN3264
8550 n1 = res.HighPart;
8551 n2 = res.LowPart;
8552# else
8553 n1 = res.tv_sec;
8554 n2 = res.tv_usec;
8555# endif
8556 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8557 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8558 }
8559#endif
8560}
8561
8562#ifdef FEAT_FLOAT
8563/*
8564 * "reltimefloat()" function
8565 */
8566 static void
8567f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8568{
8569# ifdef FEAT_RELTIME
8570 proftime_T tm;
8571# endif
8572
8573 rettv->v_type = VAR_FLOAT;
8574 rettv->vval.v_float = 0;
8575# ifdef FEAT_RELTIME
8576 if (list2proftime(&argvars[0], &tm) == OK)
8577 rettv->vval.v_float = profile_float(&tm);
8578# endif
8579}
8580#endif
8581
8582/*
8583 * "reltimestr()" function
8584 */
8585 static void
8586f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8587{
8588#ifdef FEAT_RELTIME
8589 proftime_T tm;
8590#endif
8591
8592 rettv->v_type = VAR_STRING;
8593 rettv->vval.v_string = NULL;
8594#ifdef FEAT_RELTIME
8595 if (list2proftime(&argvars[0], &tm) == OK)
8596 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8597#endif
8598}
8599
8600#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8601static void make_connection(void);
8602static int check_connection(void);
8603
8604 static void
8605make_connection(void)
8606{
8607 if (X_DISPLAY == NULL
8608# ifdef FEAT_GUI
8609 && !gui.in_use
8610# endif
8611 )
8612 {
8613 x_force_connect = TRUE;
8614 setup_term_clip();
8615 x_force_connect = FALSE;
8616 }
8617}
8618
8619 static int
8620check_connection(void)
8621{
8622 make_connection();
8623 if (X_DISPLAY == NULL)
8624 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008625 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008626 return FAIL;
8627 }
8628 return OK;
8629}
8630#endif
8631
8632#ifdef FEAT_CLIENTSERVER
8633 static void
8634remote_common(typval_T *argvars, typval_T *rettv, int expr)
8635{
8636 char_u *server_name;
8637 char_u *keys;
8638 char_u *r = NULL;
8639 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008640 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008641# ifdef WIN32
8642 HWND w;
8643# else
8644 Window w;
8645# endif
8646
8647 if (check_restricted() || check_secure())
8648 return;
8649
8650# ifdef FEAT_X11
8651 if (check_connection() == FAIL)
8652 return;
8653# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008654 if (argvars[2].v_type != VAR_UNKNOWN
8655 && argvars[3].v_type != VAR_UNKNOWN)
8656 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008657
8658 server_name = get_tv_string_chk(&argvars[0]);
8659 if (server_name == NULL)
8660 return; /* type error; errmsg already given */
8661 keys = get_tv_string_buf(&argvars[1], buf);
8662# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008663 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008664# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008665 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8666 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008667# endif
8668 {
8669 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008670 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008671 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008672 vim_free(r);
8673 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008674 else
8675 EMSG2(_("E241: Unable to send to %s"), server_name);
8676 return;
8677 }
8678
8679 rettv->vval.v_string = r;
8680
8681 if (argvars[2].v_type != VAR_UNKNOWN)
8682 {
8683 dictitem_T v;
8684 char_u str[30];
8685 char_u *idvar;
8686
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008687 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008688 if (idvar != NULL && *idvar != NUL)
8689 {
8690 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8691 v.di_tv.v_type = VAR_STRING;
8692 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008693 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008694 vim_free(v.di_tv.vval.v_string);
8695 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008696 }
8697}
8698#endif
8699
8700/*
8701 * "remote_expr()" function
8702 */
8703 static void
8704f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8705{
8706 rettv->v_type = VAR_STRING;
8707 rettv->vval.v_string = NULL;
8708#ifdef FEAT_CLIENTSERVER
8709 remote_common(argvars, rettv, TRUE);
8710#endif
8711}
8712
8713/*
8714 * "remote_foreground()" function
8715 */
8716 static void
8717f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8718{
8719#ifdef FEAT_CLIENTSERVER
8720# ifdef WIN32
8721 /* On Win32 it's done in this application. */
8722 {
8723 char_u *server_name = get_tv_string_chk(&argvars[0]);
8724
8725 if (server_name != NULL)
8726 serverForeground(server_name);
8727 }
8728# else
8729 /* Send a foreground() expression to the server. */
8730 argvars[1].v_type = VAR_STRING;
8731 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8732 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008733 rettv->v_type = VAR_STRING;
8734 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008735 remote_common(argvars, rettv, TRUE);
8736 vim_free(argvars[1].vval.v_string);
8737# endif
8738#endif
8739}
8740
8741 static void
8742f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8743{
8744#ifdef FEAT_CLIENTSERVER
8745 dictitem_T v;
8746 char_u *s = NULL;
8747# ifdef WIN32
8748 long_u n = 0;
8749# endif
8750 char_u *serverid;
8751
8752 if (check_restricted() || check_secure())
8753 {
8754 rettv->vval.v_number = -1;
8755 return;
8756 }
8757 serverid = get_tv_string_chk(&argvars[0]);
8758 if (serverid == NULL)
8759 {
8760 rettv->vval.v_number = -1;
8761 return; /* type error; errmsg already given */
8762 }
8763# ifdef WIN32
8764 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8765 if (n == 0)
8766 rettv->vval.v_number = -1;
8767 else
8768 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008769 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008770 rettv->vval.v_number = (s != NULL);
8771 }
8772# else
8773 if (check_connection() == FAIL)
8774 return;
8775
8776 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8777 serverStrToWin(serverid), &s);
8778# endif
8779
8780 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8781 {
8782 char_u *retvar;
8783
8784 v.di_tv.v_type = VAR_STRING;
8785 v.di_tv.vval.v_string = vim_strsave(s);
8786 retvar = get_tv_string_chk(&argvars[1]);
8787 if (retvar != NULL)
8788 set_var(retvar, &v.di_tv, FALSE);
8789 vim_free(v.di_tv.vval.v_string);
8790 }
8791#else
8792 rettv->vval.v_number = -1;
8793#endif
8794}
8795
8796 static void
8797f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8798{
8799 char_u *r = NULL;
8800
8801#ifdef FEAT_CLIENTSERVER
8802 char_u *serverid = get_tv_string_chk(&argvars[0]);
8803
8804 if (serverid != NULL && !check_restricted() && !check_secure())
8805 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008806 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008807# ifdef WIN32
8808 /* The server's HWND is encoded in the 'id' parameter */
8809 long_u n = 0;
8810# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008811
8812 if (argvars[1].v_type != VAR_UNKNOWN)
8813 timeout = get_tv_number(&argvars[1]);
8814
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008815# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008816 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8817 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008818 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008819 if (r == NULL)
8820# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008821 if (check_connection() == FAIL
8822 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8823 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008824# endif
8825 EMSG(_("E277: Unable to read a server reply"));
8826 }
8827#endif
8828 rettv->v_type = VAR_STRING;
8829 rettv->vval.v_string = r;
8830}
8831
8832/*
8833 * "remote_send()" function
8834 */
8835 static void
8836f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8837{
8838 rettv->v_type = VAR_STRING;
8839 rettv->vval.v_string = NULL;
8840#ifdef FEAT_CLIENTSERVER
8841 remote_common(argvars, rettv, FALSE);
8842#endif
8843}
8844
8845/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008846 * "remote_startserver()" function
8847 */
8848 static void
8849f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8850{
8851#ifdef FEAT_CLIENTSERVER
8852 char_u *server = get_tv_string_chk(&argvars[0]);
8853
8854 if (server == NULL)
8855 return; /* type error; errmsg already given */
8856 if (serverName != NULL)
8857 EMSG(_("E941: already started a server"));
8858 else
8859 {
8860# ifdef FEAT_X11
8861 if (check_connection() == OK)
8862 serverRegisterName(X_DISPLAY, server);
8863# else
8864 serverSetName(server);
8865# endif
8866 }
8867#else
8868 EMSG(_("E942: +clientserver feature not available"));
8869#endif
8870}
8871
8872/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008873 * "remove()" function
8874 */
8875 static void
8876f_remove(typval_T *argvars, typval_T *rettv)
8877{
8878 list_T *l;
8879 listitem_T *item, *item2;
8880 listitem_T *li;
8881 long idx;
8882 long end;
8883 char_u *key;
8884 dict_T *d;
8885 dictitem_T *di;
8886 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8887
8888 if (argvars[0].v_type == VAR_DICT)
8889 {
8890 if (argvars[2].v_type != VAR_UNKNOWN)
8891 EMSG2(_(e_toomanyarg), "remove()");
8892 else if ((d = argvars[0].vval.v_dict) != NULL
8893 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8894 {
8895 key = get_tv_string_chk(&argvars[1]);
8896 if (key != NULL)
8897 {
8898 di = dict_find(d, key, -1);
8899 if (di == NULL)
8900 EMSG2(_(e_dictkey), key);
8901 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8902 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8903 {
8904 *rettv = di->di_tv;
8905 init_tv(&di->di_tv);
8906 dictitem_remove(d, di);
8907 }
8908 }
8909 }
8910 }
8911 else if (argvars[0].v_type != VAR_LIST)
8912 EMSG2(_(e_listdictarg), "remove()");
8913 else if ((l = argvars[0].vval.v_list) != NULL
8914 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8915 {
8916 int error = FALSE;
8917
8918 idx = (long)get_tv_number_chk(&argvars[1], &error);
8919 if (error)
8920 ; /* type error: do nothing, errmsg already given */
8921 else if ((item = list_find(l, idx)) == NULL)
8922 EMSGN(_(e_listidx), idx);
8923 else
8924 {
8925 if (argvars[2].v_type == VAR_UNKNOWN)
8926 {
8927 /* Remove one item, return its value. */
8928 vimlist_remove(l, item, item);
8929 *rettv = item->li_tv;
8930 vim_free(item);
8931 }
8932 else
8933 {
8934 /* Remove range of items, return list with values. */
8935 end = (long)get_tv_number_chk(&argvars[2], &error);
8936 if (error)
8937 ; /* type error: do nothing */
8938 else if ((item2 = list_find(l, end)) == NULL)
8939 EMSGN(_(e_listidx), end);
8940 else
8941 {
8942 int cnt = 0;
8943
8944 for (li = item; li != NULL; li = li->li_next)
8945 {
8946 ++cnt;
8947 if (li == item2)
8948 break;
8949 }
8950 if (li == NULL) /* didn't find "item2" after "item" */
8951 EMSG(_(e_invrange));
8952 else
8953 {
8954 vimlist_remove(l, item, item2);
8955 if (rettv_list_alloc(rettv) == OK)
8956 {
8957 l = rettv->vval.v_list;
8958 l->lv_first = item;
8959 l->lv_last = item2;
8960 item->li_prev = NULL;
8961 item2->li_next = NULL;
8962 l->lv_len = cnt;
8963 }
8964 }
8965 }
8966 }
8967 }
8968 }
8969}
8970
8971/*
8972 * "rename({from}, {to})" function
8973 */
8974 static void
8975f_rename(typval_T *argvars, typval_T *rettv)
8976{
8977 char_u buf[NUMBUFLEN];
8978
8979 if (check_restricted() || check_secure())
8980 rettv->vval.v_number = -1;
8981 else
8982 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8983 get_tv_string_buf(&argvars[1], buf));
8984}
8985
8986/*
8987 * "repeat()" function
8988 */
8989 static void
8990f_repeat(typval_T *argvars, typval_T *rettv)
8991{
8992 char_u *p;
8993 int n;
8994 int slen;
8995 int len;
8996 char_u *r;
8997 int i;
8998
8999 n = (int)get_tv_number(&argvars[1]);
9000 if (argvars[0].v_type == VAR_LIST)
9001 {
9002 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9003 while (n-- > 0)
9004 if (list_extend(rettv->vval.v_list,
9005 argvars[0].vval.v_list, NULL) == FAIL)
9006 break;
9007 }
9008 else
9009 {
9010 p = get_tv_string(&argvars[0]);
9011 rettv->v_type = VAR_STRING;
9012 rettv->vval.v_string = NULL;
9013
9014 slen = (int)STRLEN(p);
9015 len = slen * n;
9016 if (len <= 0)
9017 return;
9018
9019 r = alloc(len + 1);
9020 if (r != NULL)
9021 {
9022 for (i = 0; i < n; i++)
9023 mch_memmove(r + i * slen, p, (size_t)slen);
9024 r[len] = NUL;
9025 }
9026
9027 rettv->vval.v_string = r;
9028 }
9029}
9030
9031/*
9032 * "resolve()" function
9033 */
9034 static void
9035f_resolve(typval_T *argvars, typval_T *rettv)
9036{
9037 char_u *p;
9038#ifdef HAVE_READLINK
9039 char_u *buf = NULL;
9040#endif
9041
9042 p = get_tv_string(&argvars[0]);
9043#ifdef FEAT_SHORTCUT
9044 {
9045 char_u *v = NULL;
9046
9047 v = mch_resolve_shortcut(p);
9048 if (v != NULL)
9049 rettv->vval.v_string = v;
9050 else
9051 rettv->vval.v_string = vim_strsave(p);
9052 }
9053#else
9054# ifdef HAVE_READLINK
9055 {
9056 char_u *cpy;
9057 int len;
9058 char_u *remain = NULL;
9059 char_u *q;
9060 int is_relative_to_current = FALSE;
9061 int has_trailing_pathsep = FALSE;
9062 int limit = 100;
9063
9064 p = vim_strsave(p);
9065
9066 if (p[0] == '.' && (vim_ispathsep(p[1])
9067 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9068 is_relative_to_current = TRUE;
9069
9070 len = STRLEN(p);
9071 if (len > 0 && after_pathsep(p, p + len))
9072 {
9073 has_trailing_pathsep = TRUE;
9074 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9075 }
9076
9077 q = getnextcomp(p);
9078 if (*q != NUL)
9079 {
9080 /* Separate the first path component in "p", and keep the
9081 * remainder (beginning with the path separator). */
9082 remain = vim_strsave(q - 1);
9083 q[-1] = NUL;
9084 }
9085
9086 buf = alloc(MAXPATHL + 1);
9087 if (buf == NULL)
9088 goto fail;
9089
9090 for (;;)
9091 {
9092 for (;;)
9093 {
9094 len = readlink((char *)p, (char *)buf, MAXPATHL);
9095 if (len <= 0)
9096 break;
9097 buf[len] = NUL;
9098
9099 if (limit-- == 0)
9100 {
9101 vim_free(p);
9102 vim_free(remain);
9103 EMSG(_("E655: Too many symbolic links (cycle?)"));
9104 rettv->vval.v_string = NULL;
9105 goto fail;
9106 }
9107
9108 /* Ensure that the result will have a trailing path separator
9109 * if the argument has one. */
9110 if (remain == NULL && has_trailing_pathsep)
9111 add_pathsep(buf);
9112
9113 /* Separate the first path component in the link value and
9114 * concatenate the remainders. */
9115 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9116 if (*q != NUL)
9117 {
9118 if (remain == NULL)
9119 remain = vim_strsave(q - 1);
9120 else
9121 {
9122 cpy = concat_str(q - 1, remain);
9123 if (cpy != NULL)
9124 {
9125 vim_free(remain);
9126 remain = cpy;
9127 }
9128 }
9129 q[-1] = NUL;
9130 }
9131
9132 q = gettail(p);
9133 if (q > p && *q == NUL)
9134 {
9135 /* Ignore trailing path separator. */
9136 q[-1] = NUL;
9137 q = gettail(p);
9138 }
9139 if (q > p && !mch_isFullName(buf))
9140 {
9141 /* symlink is relative to directory of argument */
9142 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9143 if (cpy != NULL)
9144 {
9145 STRCPY(cpy, p);
9146 STRCPY(gettail(cpy), buf);
9147 vim_free(p);
9148 p = cpy;
9149 }
9150 }
9151 else
9152 {
9153 vim_free(p);
9154 p = vim_strsave(buf);
9155 }
9156 }
9157
9158 if (remain == NULL)
9159 break;
9160
9161 /* Append the first path component of "remain" to "p". */
9162 q = getnextcomp(remain + 1);
9163 len = q - remain - (*q != NUL);
9164 cpy = vim_strnsave(p, STRLEN(p) + len);
9165 if (cpy != NULL)
9166 {
9167 STRNCAT(cpy, remain, len);
9168 vim_free(p);
9169 p = cpy;
9170 }
9171 /* Shorten "remain". */
9172 if (*q != NUL)
9173 STRMOVE(remain, q - 1);
9174 else
9175 {
9176 vim_free(remain);
9177 remain = NULL;
9178 }
9179 }
9180
9181 /* If the result is a relative path name, make it explicitly relative to
9182 * the current directory if and only if the argument had this form. */
9183 if (!vim_ispathsep(*p))
9184 {
9185 if (is_relative_to_current
9186 && *p != NUL
9187 && !(p[0] == '.'
9188 && (p[1] == NUL
9189 || vim_ispathsep(p[1])
9190 || (p[1] == '.'
9191 && (p[2] == NUL
9192 || vim_ispathsep(p[2]))))))
9193 {
9194 /* Prepend "./". */
9195 cpy = concat_str((char_u *)"./", p);
9196 if (cpy != NULL)
9197 {
9198 vim_free(p);
9199 p = cpy;
9200 }
9201 }
9202 else if (!is_relative_to_current)
9203 {
9204 /* Strip leading "./". */
9205 q = p;
9206 while (q[0] == '.' && vim_ispathsep(q[1]))
9207 q += 2;
9208 if (q > p)
9209 STRMOVE(p, p + 2);
9210 }
9211 }
9212
9213 /* Ensure that the result will have no trailing path separator
9214 * if the argument had none. But keep "/" or "//". */
9215 if (!has_trailing_pathsep)
9216 {
9217 q = p + STRLEN(p);
9218 if (after_pathsep(p, q))
9219 *gettail_sep(p) = NUL;
9220 }
9221
9222 rettv->vval.v_string = p;
9223 }
9224# else
9225 rettv->vval.v_string = vim_strsave(p);
9226# endif
9227#endif
9228
9229 simplify_filename(rettv->vval.v_string);
9230
9231#ifdef HAVE_READLINK
9232fail:
9233 vim_free(buf);
9234#endif
9235 rettv->v_type = VAR_STRING;
9236}
9237
9238/*
9239 * "reverse({list})" function
9240 */
9241 static void
9242f_reverse(typval_T *argvars, typval_T *rettv)
9243{
9244 list_T *l;
9245 listitem_T *li, *ni;
9246
9247 if (argvars[0].v_type != VAR_LIST)
9248 EMSG2(_(e_listarg), "reverse()");
9249 else if ((l = argvars[0].vval.v_list) != NULL
9250 && !tv_check_lock(l->lv_lock,
9251 (char_u *)N_("reverse() argument"), TRUE))
9252 {
9253 li = l->lv_last;
9254 l->lv_first = l->lv_last = NULL;
9255 l->lv_len = 0;
9256 while (li != NULL)
9257 {
9258 ni = li->li_prev;
9259 list_append(l, li);
9260 li = ni;
9261 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009262 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009263 l->lv_idx = l->lv_len - l->lv_idx - 1;
9264 }
9265}
9266
9267#define SP_NOMOVE 0x01 /* don't move cursor */
9268#define SP_REPEAT 0x02 /* repeat to find outer pair */
9269#define SP_RETCOUNT 0x04 /* return matchcount */
9270#define SP_SETPCMARK 0x08 /* set previous context mark */
9271#define SP_START 0x10 /* accept match at start position */
9272#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9273#define SP_END 0x40 /* leave cursor at end of match */
9274#define SP_COLUMN 0x80 /* start at cursor column */
9275
9276static int get_search_arg(typval_T *varp, int *flagsp);
9277
9278/*
9279 * Get flags for a search function.
9280 * Possibly sets "p_ws".
9281 * Returns BACKWARD, FORWARD or zero (for an error).
9282 */
9283 static int
9284get_search_arg(typval_T *varp, int *flagsp)
9285{
9286 int dir = FORWARD;
9287 char_u *flags;
9288 char_u nbuf[NUMBUFLEN];
9289 int mask;
9290
9291 if (varp->v_type != VAR_UNKNOWN)
9292 {
9293 flags = get_tv_string_buf_chk(varp, nbuf);
9294 if (flags == NULL)
9295 return 0; /* type error; errmsg already given */
9296 while (*flags != NUL)
9297 {
9298 switch (*flags)
9299 {
9300 case 'b': dir = BACKWARD; break;
9301 case 'w': p_ws = TRUE; break;
9302 case 'W': p_ws = FALSE; break;
9303 default: mask = 0;
9304 if (flagsp != NULL)
9305 switch (*flags)
9306 {
9307 case 'c': mask = SP_START; break;
9308 case 'e': mask = SP_END; break;
9309 case 'm': mask = SP_RETCOUNT; break;
9310 case 'n': mask = SP_NOMOVE; break;
9311 case 'p': mask = SP_SUBPAT; break;
9312 case 'r': mask = SP_REPEAT; break;
9313 case 's': mask = SP_SETPCMARK; break;
9314 case 'z': mask = SP_COLUMN; break;
9315 }
9316 if (mask == 0)
9317 {
9318 EMSG2(_(e_invarg2), flags);
9319 dir = 0;
9320 }
9321 else
9322 *flagsp |= mask;
9323 }
9324 if (dir == 0)
9325 break;
9326 ++flags;
9327 }
9328 }
9329 return dir;
9330}
9331
9332/*
9333 * Shared by search() and searchpos() functions.
9334 */
9335 static int
9336search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9337{
9338 int flags;
9339 char_u *pat;
9340 pos_T pos;
9341 pos_T save_cursor;
9342 int save_p_ws = p_ws;
9343 int dir;
9344 int retval = 0; /* default: FAIL */
9345 long lnum_stop = 0;
9346 proftime_T tm;
9347#ifdef FEAT_RELTIME
9348 long time_limit = 0;
9349#endif
9350 int options = SEARCH_KEEP;
9351 int subpatnum;
9352
9353 pat = get_tv_string(&argvars[0]);
9354 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9355 if (dir == 0)
9356 goto theend;
9357 flags = *flagsp;
9358 if (flags & SP_START)
9359 options |= SEARCH_START;
9360 if (flags & SP_END)
9361 options |= SEARCH_END;
9362 if (flags & SP_COLUMN)
9363 options |= SEARCH_COL;
9364
9365 /* Optional arguments: line number to stop searching and timeout. */
9366 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9367 {
9368 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9369 if (lnum_stop < 0)
9370 goto theend;
9371#ifdef FEAT_RELTIME
9372 if (argvars[3].v_type != VAR_UNKNOWN)
9373 {
9374 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9375 if (time_limit < 0)
9376 goto theend;
9377 }
9378#endif
9379 }
9380
9381#ifdef FEAT_RELTIME
9382 /* Set the time limit, if there is one. */
9383 profile_setlimit(time_limit, &tm);
9384#endif
9385
9386 /*
9387 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9388 * Check to make sure only those flags are set.
9389 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9390 * flags cannot be set. Check for that condition also.
9391 */
9392 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9393 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9394 {
9395 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9396 goto theend;
9397 }
9398
9399 pos = save_cursor = curwin->w_cursor;
9400 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009401 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009402 if (subpatnum != FAIL)
9403 {
9404 if (flags & SP_SUBPAT)
9405 retval = subpatnum;
9406 else
9407 retval = pos.lnum;
9408 if (flags & SP_SETPCMARK)
9409 setpcmark();
9410 curwin->w_cursor = pos;
9411 if (match_pos != NULL)
9412 {
9413 /* Store the match cursor position */
9414 match_pos->lnum = pos.lnum;
9415 match_pos->col = pos.col + 1;
9416 }
9417 /* "/$" will put the cursor after the end of the line, may need to
9418 * correct that here */
9419 check_cursor();
9420 }
9421
9422 /* If 'n' flag is used: restore cursor position. */
9423 if (flags & SP_NOMOVE)
9424 curwin->w_cursor = save_cursor;
9425 else
9426 curwin->w_set_curswant = TRUE;
9427theend:
9428 p_ws = save_p_ws;
9429
9430 return retval;
9431}
9432
9433#ifdef FEAT_FLOAT
9434
9435/*
9436 * round() is not in C90, use ceil() or floor() instead.
9437 */
9438 float_T
9439vim_round(float_T f)
9440{
9441 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9442}
9443
9444/*
9445 * "round({float})" function
9446 */
9447 static void
9448f_round(typval_T *argvars, typval_T *rettv)
9449{
9450 float_T f = 0.0;
9451
9452 rettv->v_type = VAR_FLOAT;
9453 if (get_float_arg(argvars, &f) == OK)
9454 rettv->vval.v_float = vim_round(f);
9455 else
9456 rettv->vval.v_float = 0.0;
9457}
9458#endif
9459
9460/*
9461 * "screenattr()" function
9462 */
9463 static void
9464f_screenattr(typval_T *argvars, typval_T *rettv)
9465{
9466 int row;
9467 int col;
9468 int c;
9469
9470 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9471 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9472 if (row < 0 || row >= screen_Rows
9473 || col < 0 || col >= screen_Columns)
9474 c = -1;
9475 else
9476 c = ScreenAttrs[LineOffset[row] + col];
9477 rettv->vval.v_number = c;
9478}
9479
9480/*
9481 * "screenchar()" function
9482 */
9483 static void
9484f_screenchar(typval_T *argvars, typval_T *rettv)
9485{
9486 int row;
9487 int col;
9488 int off;
9489 int c;
9490
9491 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9492 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9493 if (row < 0 || row >= screen_Rows
9494 || col < 0 || col >= screen_Columns)
9495 c = -1;
9496 else
9497 {
9498 off = LineOffset[row] + col;
9499#ifdef FEAT_MBYTE
9500 if (enc_utf8 && ScreenLinesUC[off] != 0)
9501 c = ScreenLinesUC[off];
9502 else
9503#endif
9504 c = ScreenLines[off];
9505 }
9506 rettv->vval.v_number = c;
9507}
9508
9509/*
9510 * "screencol()" function
9511 *
9512 * First column is 1 to be consistent with virtcol().
9513 */
9514 static void
9515f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9516{
9517 rettv->vval.v_number = screen_screencol() + 1;
9518}
9519
9520/*
9521 * "screenrow()" function
9522 */
9523 static void
9524f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9525{
9526 rettv->vval.v_number = screen_screenrow() + 1;
9527}
9528
9529/*
9530 * "search()" function
9531 */
9532 static void
9533f_search(typval_T *argvars, typval_T *rettv)
9534{
9535 int flags = 0;
9536
9537 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9538}
9539
9540/*
9541 * "searchdecl()" function
9542 */
9543 static void
9544f_searchdecl(typval_T *argvars, typval_T *rettv)
9545{
9546 int locally = 1;
9547 int thisblock = 0;
9548 int error = FALSE;
9549 char_u *name;
9550
9551 rettv->vval.v_number = 1; /* default: FAIL */
9552
9553 name = get_tv_string_chk(&argvars[0]);
9554 if (argvars[1].v_type != VAR_UNKNOWN)
9555 {
9556 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9557 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9558 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9559 }
9560 if (!error && name != NULL)
9561 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9562 locally, thisblock, SEARCH_KEEP) == FAIL;
9563}
9564
9565/*
9566 * Used by searchpair() and searchpairpos()
9567 */
9568 static int
9569searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9570{
9571 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009572 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009573 int save_p_ws = p_ws;
9574 int dir;
9575 int flags = 0;
9576 char_u nbuf1[NUMBUFLEN];
9577 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009578 int retval = 0; /* default: FAIL */
9579 long lnum_stop = 0;
9580 long time_limit = 0;
9581
9582 /* Get the three pattern arguments: start, middle, end. */
9583 spat = get_tv_string_chk(&argvars[0]);
9584 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9585 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9586 if (spat == NULL || mpat == NULL || epat == NULL)
9587 goto theend; /* type error */
9588
9589 /* Handle the optional fourth argument: flags */
9590 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9591 if (dir == 0)
9592 goto theend;
9593
9594 /* Don't accept SP_END or SP_SUBPAT.
9595 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9596 */
9597 if ((flags & (SP_END | SP_SUBPAT)) != 0
9598 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9599 {
9600 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9601 goto theend;
9602 }
9603
9604 /* Using 'r' implies 'W', otherwise it doesn't work. */
9605 if (flags & SP_REPEAT)
9606 p_ws = FALSE;
9607
9608 /* Optional fifth argument: skip expression */
9609 if (argvars[3].v_type == VAR_UNKNOWN
9610 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009611 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009612 else
9613 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009614 skip = &argvars[4];
9615 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9616 && skip->v_type != VAR_STRING)
9617 {
9618 /* Type error */
9619 goto theend;
9620 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009621 if (argvars[5].v_type != VAR_UNKNOWN)
9622 {
9623 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9624 if (lnum_stop < 0)
9625 goto theend;
9626#ifdef FEAT_RELTIME
9627 if (argvars[6].v_type != VAR_UNKNOWN)
9628 {
9629 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9630 if (time_limit < 0)
9631 goto theend;
9632 }
9633#endif
9634 }
9635 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009636
9637 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9638 match_pos, lnum_stop, time_limit);
9639
9640theend:
9641 p_ws = save_p_ws;
9642
9643 return retval;
9644}
9645
9646/*
9647 * "searchpair()" function
9648 */
9649 static void
9650f_searchpair(typval_T *argvars, typval_T *rettv)
9651{
9652 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9653}
9654
9655/*
9656 * "searchpairpos()" function
9657 */
9658 static void
9659f_searchpairpos(typval_T *argvars, typval_T *rettv)
9660{
9661 pos_T match_pos;
9662 int lnum = 0;
9663 int col = 0;
9664
9665 if (rettv_list_alloc(rettv) == FAIL)
9666 return;
9667
9668 if (searchpair_cmn(argvars, &match_pos) > 0)
9669 {
9670 lnum = match_pos.lnum;
9671 col = match_pos.col;
9672 }
9673
9674 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9675 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9676}
9677
9678/*
9679 * Search for a start/middle/end thing.
9680 * Used by searchpair(), see its documentation for the details.
9681 * Returns 0 or -1 for no match,
9682 */
9683 long
9684do_searchpair(
9685 char_u *spat, /* start pattern */
9686 char_u *mpat, /* middle pattern */
9687 char_u *epat, /* end pattern */
9688 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009689 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009690 int flags, /* SP_SETPCMARK and other SP_ values */
9691 pos_T *match_pos,
9692 linenr_T lnum_stop, /* stop at this line if not zero */
9693 long time_limit UNUSED) /* stop after this many msec */
9694{
9695 char_u *save_cpo;
9696 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9697 long retval = 0;
9698 pos_T pos;
9699 pos_T firstpos;
9700 pos_T foundpos;
9701 pos_T save_cursor;
9702 pos_T save_pos;
9703 int n;
9704 int r;
9705 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009706 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009707 int err;
9708 int options = SEARCH_KEEP;
9709 proftime_T tm;
9710
9711 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9712 save_cpo = p_cpo;
9713 p_cpo = empty_option;
9714
9715#ifdef FEAT_RELTIME
9716 /* Set the time limit, if there is one. */
9717 profile_setlimit(time_limit, &tm);
9718#endif
9719
9720 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9721 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009722 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9723 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009724 if (pat2 == NULL || pat3 == NULL)
9725 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009726 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009727 if (*mpat == NUL)
9728 STRCPY(pat3, pat2);
9729 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009730 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009731 spat, epat, mpat);
9732 if (flags & SP_START)
9733 options |= SEARCH_START;
9734
Bram Moolenaar48570482017-10-30 21:48:41 +01009735 if (skip != NULL)
9736 {
9737 /* Empty string means to not use the skip expression. */
9738 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9739 use_skip = skip->vval.v_string != NULL
9740 && *skip->vval.v_string != NUL;
9741 }
9742
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009743 save_cursor = curwin->w_cursor;
9744 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009745 CLEAR_POS(&firstpos);
9746 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009747 pat = pat3;
9748 for (;;)
9749 {
9750 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009751 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009752 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009753 /* didn't find it or found the first match again: FAIL */
9754 break;
9755
9756 if (firstpos.lnum == 0)
9757 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009758 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009759 {
9760 /* Found the same position again. Can happen with a pattern that
9761 * has "\zs" at the end and searching backwards. Advance one
9762 * character and try again. */
9763 if (dir == BACKWARD)
9764 decl(&pos);
9765 else
9766 incl(&pos);
9767 }
9768 foundpos = pos;
9769
9770 /* clear the start flag to avoid getting stuck here */
9771 options &= ~SEARCH_START;
9772
9773 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009774 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009775 {
9776 save_pos = curwin->w_cursor;
9777 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009778 err = FALSE;
9779 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009780 curwin->w_cursor = save_pos;
9781 if (err)
9782 {
9783 /* Evaluating {skip} caused an error, break here. */
9784 curwin->w_cursor = save_cursor;
9785 retval = -1;
9786 break;
9787 }
9788 if (r)
9789 continue;
9790 }
9791
9792 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9793 {
9794 /* Found end when searching backwards or start when searching
9795 * forward: nested pair. */
9796 ++nest;
9797 pat = pat2; /* nested, don't search for middle */
9798 }
9799 else
9800 {
9801 /* Found end when searching forward or start when searching
9802 * backward: end of (nested) pair; or found middle in outer pair. */
9803 if (--nest == 1)
9804 pat = pat3; /* outer level, search for middle */
9805 }
9806
9807 if (nest == 0)
9808 {
9809 /* Found the match: return matchcount or line number. */
9810 if (flags & SP_RETCOUNT)
9811 ++retval;
9812 else
9813 retval = pos.lnum;
9814 if (flags & SP_SETPCMARK)
9815 setpcmark();
9816 curwin->w_cursor = pos;
9817 if (!(flags & SP_REPEAT))
9818 break;
9819 nest = 1; /* search for next unmatched */
9820 }
9821 }
9822
9823 if (match_pos != NULL)
9824 {
9825 /* Store the match cursor position */
9826 match_pos->lnum = curwin->w_cursor.lnum;
9827 match_pos->col = curwin->w_cursor.col + 1;
9828 }
9829
9830 /* If 'n' flag is used or search failed: restore cursor position. */
9831 if ((flags & SP_NOMOVE) || retval == 0)
9832 curwin->w_cursor = save_cursor;
9833
9834theend:
9835 vim_free(pat2);
9836 vim_free(pat3);
9837 if (p_cpo == empty_option)
9838 p_cpo = save_cpo;
9839 else
9840 /* Darn, evaluating the {skip} expression changed the value. */
9841 free_string_option(save_cpo);
9842
9843 return retval;
9844}
9845
9846/*
9847 * "searchpos()" function
9848 */
9849 static void
9850f_searchpos(typval_T *argvars, typval_T *rettv)
9851{
9852 pos_T match_pos;
9853 int lnum = 0;
9854 int col = 0;
9855 int n;
9856 int flags = 0;
9857
9858 if (rettv_list_alloc(rettv) == FAIL)
9859 return;
9860
9861 n = search_cmn(argvars, &match_pos, &flags);
9862 if (n > 0)
9863 {
9864 lnum = match_pos.lnum;
9865 col = match_pos.col;
9866 }
9867
9868 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9869 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9870 if (flags & SP_SUBPAT)
9871 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9872}
9873
9874 static void
9875f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9876{
9877#ifdef FEAT_CLIENTSERVER
9878 char_u buf[NUMBUFLEN];
9879 char_u *server = get_tv_string_chk(&argvars[0]);
9880 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9881
9882 rettv->vval.v_number = -1;
9883 if (server == NULL || reply == NULL)
9884 return;
9885 if (check_restricted() || check_secure())
9886 return;
9887# ifdef FEAT_X11
9888 if (check_connection() == FAIL)
9889 return;
9890# endif
9891
9892 if (serverSendReply(server, reply) < 0)
9893 {
9894 EMSG(_("E258: Unable to send to client"));
9895 return;
9896 }
9897 rettv->vval.v_number = 0;
9898#else
9899 rettv->vval.v_number = -1;
9900#endif
9901}
9902
9903 static void
9904f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9905{
9906 char_u *r = NULL;
9907
9908#ifdef FEAT_CLIENTSERVER
9909# ifdef WIN32
9910 r = serverGetVimNames();
9911# else
9912 make_connection();
9913 if (X_DISPLAY != NULL)
9914 r = serverGetVimNames(X_DISPLAY);
9915# endif
9916#endif
9917 rettv->v_type = VAR_STRING;
9918 rettv->vval.v_string = r;
9919}
9920
9921/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009922 * Set line or list of lines in buffer "buf".
9923 */
9924 static void
9925set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
9926{
9927 char_u *line = NULL;
9928 list_T *l = NULL;
9929 listitem_T *li = NULL;
9930 long added = 0;
9931 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009932 buf_T *curbuf_save = NULL;
9933 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009934 int is_curbuf = buf == curbuf;
9935
Bram Moolenaar9d954202017-09-04 20:34:19 +02009936 /* When using the current buffer ml_mfp will be set if needed. Useful when
9937 * setline() is used on startup. For other buffers the buffer must be
9938 * loaded. */
9939 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009940 {
9941 rettv->vval.v_number = 1; /* FAIL */
9942 return;
9943 }
9944
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009945 if (!is_curbuf)
9946 {
9947 wininfo_T *wip;
9948
9949 curbuf_save = curbuf;
9950 curwin_save = curwin;
9951 curbuf = buf;
9952 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
9953 {
9954 if (wip->wi_win != NULL)
9955 {
9956 curwin = wip->wi_win;
9957 break;
9958 }
9959 }
9960 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009961
9962 lcount = curbuf->b_ml.ml_line_count;
9963
9964 if (lines->v_type == VAR_LIST)
9965 {
9966 l = lines->vval.v_list;
9967 li = l->lv_first;
9968 }
9969 else
9970 line = get_tv_string_chk(lines);
9971
9972 /* default result is zero == OK */
9973 for (;;)
9974 {
9975 if (l != NULL)
9976 {
9977 /* list argument, get next string */
9978 if (li == NULL)
9979 break;
9980 line = get_tv_string_chk(&li->li_tv);
9981 li = li->li_next;
9982 }
9983
9984 rettv->vval.v_number = 1; /* FAIL */
9985 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
9986 break;
9987
9988 /* When coming here from Insert mode, sync undo, so that this can be
9989 * undone separately from what was previously inserted. */
9990 if (u_sync_once == 2)
9991 {
9992 u_sync_once = 1; /* notify that u_sync() was called */
9993 u_sync(TRUE);
9994 }
9995
9996 if (lnum <= curbuf->b_ml.ml_line_count)
9997 {
9998 /* existing line, replace it */
9999 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10000 {
10001 changed_bytes(lnum, 0);
10002 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10003 check_cursor_col();
10004 rettv->vval.v_number = 0; /* OK */
10005 }
10006 }
10007 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10008 {
10009 /* lnum is one past the last line, append the line */
10010 ++added;
10011 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10012 rettv->vval.v_number = 0; /* OK */
10013 }
10014
10015 if (l == NULL) /* only one string argument */
10016 break;
10017 ++lnum;
10018 }
10019
10020 if (added > 0)
10021 appended_lines_mark(lcount, added);
10022
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010023 if (!is_curbuf)
10024 {
10025 curbuf = curbuf_save;
10026 curwin = curwin_save;
10027 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010028}
10029
10030/*
10031 * "setbufline()" function
10032 */
10033 static void
10034f_setbufline(argvars, rettv)
10035 typval_T *argvars;
10036 typval_T *rettv;
10037{
10038 linenr_T lnum;
10039 buf_T *buf;
10040
10041 buf = get_buf_tv(&argvars[0], FALSE);
10042 if (buf == NULL)
10043 rettv->vval.v_number = 1; /* FAIL */
10044 else
10045 {
10046 lnum = get_tv_lnum_buf(&argvars[1], buf);
10047
10048 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10049 }
10050}
10051
10052/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010053 * "setbufvar()" function
10054 */
10055 static void
10056f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10057{
10058 buf_T *buf;
10059 char_u *varname, *bufvarname;
10060 typval_T *varp;
10061 char_u nbuf[NUMBUFLEN];
10062
10063 if (check_restricted() || check_secure())
10064 return;
10065 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10066 varname = get_tv_string_chk(&argvars[1]);
10067 buf = get_buf_tv(&argvars[0], FALSE);
10068 varp = &argvars[2];
10069
10070 if (buf != NULL && varname != NULL && varp != NULL)
10071 {
10072 if (*varname == '&')
10073 {
10074 long numval;
10075 char_u *strval;
10076 int error = FALSE;
10077 aco_save_T aco;
10078
10079 /* set curbuf to be our buf, temporarily */
10080 aucmd_prepbuf(&aco, buf);
10081
10082 ++varname;
10083 numval = (long)get_tv_number_chk(varp, &error);
10084 strval = get_tv_string_buf_chk(varp, nbuf);
10085 if (!error && strval != NULL)
10086 set_option_value(varname, numval, strval, OPT_LOCAL);
10087
10088 /* reset notion of buffer */
10089 aucmd_restbuf(&aco);
10090 }
10091 else
10092 {
10093 buf_T *save_curbuf = curbuf;
10094
10095 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10096 if (bufvarname != NULL)
10097 {
10098 curbuf = buf;
10099 STRCPY(bufvarname, "b:");
10100 STRCPY(bufvarname + 2, varname);
10101 set_var(bufvarname, varp, TRUE);
10102 vim_free(bufvarname);
10103 curbuf = save_curbuf;
10104 }
10105 }
10106 }
10107}
10108
10109 static void
10110f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10111{
10112 dict_T *d;
10113 dictitem_T *di;
10114 char_u *csearch;
10115
10116 if (argvars[0].v_type != VAR_DICT)
10117 {
10118 EMSG(_(e_dictreq));
10119 return;
10120 }
10121
10122 if ((d = argvars[0].vval.v_dict) != NULL)
10123 {
10124 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10125 if (csearch != NULL)
10126 {
10127#ifdef FEAT_MBYTE
10128 if (enc_utf8)
10129 {
10130 int pcc[MAX_MCO];
10131 int c = utfc_ptr2char(csearch, pcc);
10132
10133 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10134 }
10135 else
10136#endif
10137 set_last_csearch(PTR2CHAR(csearch),
10138 csearch, MB_PTR2LEN(csearch));
10139 }
10140
10141 di = dict_find(d, (char_u *)"forward", -1);
10142 if (di != NULL)
10143 set_csearch_direction((int)get_tv_number(&di->di_tv)
10144 ? FORWARD : BACKWARD);
10145
10146 di = dict_find(d, (char_u *)"until", -1);
10147 if (di != NULL)
10148 set_csearch_until(!!get_tv_number(&di->di_tv));
10149 }
10150}
10151
10152/*
10153 * "setcmdpos()" function
10154 */
10155 static void
10156f_setcmdpos(typval_T *argvars, typval_T *rettv)
10157{
10158 int pos = (int)get_tv_number(&argvars[0]) - 1;
10159
10160 if (pos >= 0)
10161 rettv->vval.v_number = set_cmdline_pos(pos);
10162}
10163
10164/*
10165 * "setfperm({fname}, {mode})" function
10166 */
10167 static void
10168f_setfperm(typval_T *argvars, typval_T *rettv)
10169{
10170 char_u *fname;
10171 char_u modebuf[NUMBUFLEN];
10172 char_u *mode_str;
10173 int i;
10174 int mask;
10175 int mode = 0;
10176
10177 rettv->vval.v_number = 0;
10178 fname = get_tv_string_chk(&argvars[0]);
10179 if (fname == NULL)
10180 return;
10181 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10182 if (mode_str == NULL)
10183 return;
10184 if (STRLEN(mode_str) != 9)
10185 {
10186 EMSG2(_(e_invarg2), mode_str);
10187 return;
10188 }
10189
10190 mask = 1;
10191 for (i = 8; i >= 0; --i)
10192 {
10193 if (mode_str[i] != '-')
10194 mode |= mask;
10195 mask = mask << 1;
10196 }
10197 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10198}
10199
10200/*
10201 * "setline()" function
10202 */
10203 static void
10204f_setline(typval_T *argvars, typval_T *rettv)
10205{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010206 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010207
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010208 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010209}
10210
Bram Moolenaard823fa92016-08-12 16:29:27 +020010211static 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 +020010212
10213/*
10214 * Used by "setqflist()" and "setloclist()" functions
10215 */
10216 static void
10217set_qf_ll_list(
10218 win_T *wp UNUSED,
10219 typval_T *list_arg UNUSED,
10220 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010221 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010222 typval_T *rettv)
10223{
10224#ifdef FEAT_QUICKFIX
10225 static char *e_invact = N_("E927: Invalid action: '%s'");
10226 char_u *act;
10227 int action = 0;
10228#endif
10229
10230 rettv->vval.v_number = -1;
10231
10232#ifdef FEAT_QUICKFIX
10233 if (list_arg->v_type != VAR_LIST)
10234 EMSG(_(e_listreq));
10235 else
10236 {
10237 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010238 dict_T *d = NULL;
10239 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010240
10241 if (action_arg->v_type == VAR_STRING)
10242 {
10243 act = get_tv_string_chk(action_arg);
10244 if (act == NULL)
10245 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010246 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10247 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010248 action = *act;
10249 else
10250 EMSG2(_(e_invact), act);
10251 }
10252 else if (action_arg->v_type == VAR_UNKNOWN)
10253 action = ' ';
10254 else
10255 EMSG(_(e_stringreq));
10256
Bram Moolenaard823fa92016-08-12 16:29:27 +020010257 if (action_arg->v_type != VAR_UNKNOWN
10258 && what_arg->v_type != VAR_UNKNOWN)
10259 {
10260 if (what_arg->v_type == VAR_DICT)
10261 d = what_arg->vval.v_dict;
10262 else
10263 {
10264 EMSG(_(e_dictreq));
10265 valid_dict = FALSE;
10266 }
10267 }
10268
10269 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10270 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010271 rettv->vval.v_number = 0;
10272 }
10273#endif
10274}
10275
10276/*
10277 * "setloclist()" function
10278 */
10279 static void
10280f_setloclist(typval_T *argvars, typval_T *rettv)
10281{
10282 win_T *win;
10283
10284 rettv->vval.v_number = -1;
10285
10286 win = find_win_by_nr(&argvars[0], NULL);
10287 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010288 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010289}
10290
10291/*
10292 * "setmatches()" function
10293 */
10294 static void
10295f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10296{
10297#ifdef FEAT_SEARCH_EXTRA
10298 list_T *l;
10299 listitem_T *li;
10300 dict_T *d;
10301 list_T *s = NULL;
10302
10303 rettv->vval.v_number = -1;
10304 if (argvars[0].v_type != VAR_LIST)
10305 {
10306 EMSG(_(e_listreq));
10307 return;
10308 }
10309 if ((l = argvars[0].vval.v_list) != NULL)
10310 {
10311
10312 /* To some extent make sure that we are dealing with a list from
10313 * "getmatches()". */
10314 li = l->lv_first;
10315 while (li != NULL)
10316 {
10317 if (li->li_tv.v_type != VAR_DICT
10318 || (d = li->li_tv.vval.v_dict) == NULL)
10319 {
10320 EMSG(_(e_invarg));
10321 return;
10322 }
10323 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10324 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10325 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10326 && dict_find(d, (char_u *)"priority", -1) != NULL
10327 && dict_find(d, (char_u *)"id", -1) != NULL))
10328 {
10329 EMSG(_(e_invarg));
10330 return;
10331 }
10332 li = li->li_next;
10333 }
10334
10335 clear_matches(curwin);
10336 li = l->lv_first;
10337 while (li != NULL)
10338 {
10339 int i = 0;
10340 char_u buf[5];
10341 dictitem_T *di;
10342 char_u *group;
10343 int priority;
10344 int id;
10345 char_u *conceal;
10346
10347 d = li->li_tv.vval.v_dict;
10348 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10349 {
10350 if (s == NULL)
10351 {
10352 s = list_alloc();
10353 if (s == NULL)
10354 return;
10355 }
10356
10357 /* match from matchaddpos() */
10358 for (i = 1; i < 9; i++)
10359 {
10360 sprintf((char *)buf, (char *)"pos%d", i);
10361 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10362 {
10363 if (di->di_tv.v_type != VAR_LIST)
10364 return;
10365
10366 list_append_tv(s, &di->di_tv);
10367 s->lv_refcount++;
10368 }
10369 else
10370 break;
10371 }
10372 }
10373
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010374 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010375 priority = (int)get_dict_number(d, (char_u *)"priority");
10376 id = (int)get_dict_number(d, (char_u *)"id");
10377 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010378 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010379 : NULL;
10380 if (i == 0)
10381 {
10382 match_add(curwin, group,
10383 get_dict_string(d, (char_u *)"pattern", FALSE),
10384 priority, id, NULL, conceal);
10385 }
10386 else
10387 {
10388 match_add(curwin, group, NULL, priority, id, s, conceal);
10389 list_unref(s);
10390 s = NULL;
10391 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010392 vim_free(group);
10393 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010394
10395 li = li->li_next;
10396 }
10397 rettv->vval.v_number = 0;
10398 }
10399#endif
10400}
10401
10402/*
10403 * "setpos()" function
10404 */
10405 static void
10406f_setpos(typval_T *argvars, typval_T *rettv)
10407{
10408 pos_T pos;
10409 int fnum;
10410 char_u *name;
10411 colnr_T curswant = -1;
10412
10413 rettv->vval.v_number = -1;
10414 name = get_tv_string_chk(argvars);
10415 if (name != NULL)
10416 {
10417 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10418 {
10419 if (--pos.col < 0)
10420 pos.col = 0;
10421 if (name[0] == '.' && name[1] == NUL)
10422 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010423 /* set cursor; "fnum" is ignored */
10424 curwin->w_cursor = pos;
10425 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010426 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010427 curwin->w_curswant = curswant - 1;
10428 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010429 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010430 check_cursor();
10431 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010432 }
10433 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10434 {
10435 /* set mark */
10436 if (setmark_pos(name[1], &pos, fnum) == OK)
10437 rettv->vval.v_number = 0;
10438 }
10439 else
10440 EMSG(_(e_invarg));
10441 }
10442 }
10443}
10444
10445/*
10446 * "setqflist()" function
10447 */
10448 static void
10449f_setqflist(typval_T *argvars, typval_T *rettv)
10450{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010451 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010452}
10453
10454/*
10455 * "setreg()" function
10456 */
10457 static void
10458f_setreg(typval_T *argvars, typval_T *rettv)
10459{
10460 int regname;
10461 char_u *strregname;
10462 char_u *stropt;
10463 char_u *strval;
10464 int append;
10465 char_u yank_type;
10466 long block_len;
10467
10468 block_len = -1;
10469 yank_type = MAUTO;
10470 append = FALSE;
10471
10472 strregname = get_tv_string_chk(argvars);
10473 rettv->vval.v_number = 1; /* FAIL is default */
10474
10475 if (strregname == NULL)
10476 return; /* type error; errmsg already given */
10477 regname = *strregname;
10478 if (regname == 0 || regname == '@')
10479 regname = '"';
10480
10481 if (argvars[2].v_type != VAR_UNKNOWN)
10482 {
10483 stropt = get_tv_string_chk(&argvars[2]);
10484 if (stropt == NULL)
10485 return; /* type error */
10486 for (; *stropt != NUL; ++stropt)
10487 switch (*stropt)
10488 {
10489 case 'a': case 'A': /* append */
10490 append = TRUE;
10491 break;
10492 case 'v': case 'c': /* character-wise selection */
10493 yank_type = MCHAR;
10494 break;
10495 case 'V': case 'l': /* line-wise selection */
10496 yank_type = MLINE;
10497 break;
10498 case 'b': case Ctrl_V: /* block-wise selection */
10499 yank_type = MBLOCK;
10500 if (VIM_ISDIGIT(stropt[1]))
10501 {
10502 ++stropt;
10503 block_len = getdigits(&stropt) - 1;
10504 --stropt;
10505 }
10506 break;
10507 }
10508 }
10509
10510 if (argvars[1].v_type == VAR_LIST)
10511 {
10512 char_u **lstval;
10513 char_u **allocval;
10514 char_u buf[NUMBUFLEN];
10515 char_u **curval;
10516 char_u **curallocval;
10517 list_T *ll = argvars[1].vval.v_list;
10518 listitem_T *li;
10519 int len;
10520
10521 /* If the list is NULL handle like an empty list. */
10522 len = ll == NULL ? 0 : ll->lv_len;
10523
10524 /* First half: use for pointers to result lines; second half: use for
10525 * pointers to allocated copies. */
10526 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10527 if (lstval == NULL)
10528 return;
10529 curval = lstval;
10530 allocval = lstval + len + 2;
10531 curallocval = allocval;
10532
10533 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10534 li = li->li_next)
10535 {
10536 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10537 if (strval == NULL)
10538 goto free_lstval;
10539 if (strval == buf)
10540 {
10541 /* Need to make a copy, next get_tv_string_buf_chk() will
10542 * overwrite the string. */
10543 strval = vim_strsave(buf);
10544 if (strval == NULL)
10545 goto free_lstval;
10546 *curallocval++ = strval;
10547 }
10548 *curval++ = strval;
10549 }
10550 *curval++ = NULL;
10551
10552 write_reg_contents_lst(regname, lstval, -1,
10553 append, yank_type, block_len);
10554free_lstval:
10555 while (curallocval > allocval)
10556 vim_free(*--curallocval);
10557 vim_free(lstval);
10558 }
10559 else
10560 {
10561 strval = get_tv_string_chk(&argvars[1]);
10562 if (strval == NULL)
10563 return;
10564 write_reg_contents_ex(regname, strval, -1,
10565 append, yank_type, block_len);
10566 }
10567 rettv->vval.v_number = 0;
10568}
10569
10570/*
10571 * "settabvar()" function
10572 */
10573 static void
10574f_settabvar(typval_T *argvars, typval_T *rettv)
10575{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010576 tabpage_T *save_curtab;
10577 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010578 char_u *varname, *tabvarname;
10579 typval_T *varp;
10580
10581 rettv->vval.v_number = 0;
10582
10583 if (check_restricted() || check_secure())
10584 return;
10585
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010586 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010587 varname = get_tv_string_chk(&argvars[1]);
10588 varp = &argvars[2];
10589
Bram Moolenaar4033c552017-09-16 20:54:51 +020010590 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010591 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010592 save_curtab = curtab;
10593 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010594
10595 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10596 if (tabvarname != NULL)
10597 {
10598 STRCPY(tabvarname, "t:");
10599 STRCPY(tabvarname + 2, varname);
10600 set_var(tabvarname, varp, TRUE);
10601 vim_free(tabvarname);
10602 }
10603
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010604 /* Restore current tabpage */
10605 if (valid_tabpage(save_curtab))
10606 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010607 }
10608}
10609
10610/*
10611 * "settabwinvar()" function
10612 */
10613 static void
10614f_settabwinvar(typval_T *argvars, typval_T *rettv)
10615{
10616 setwinvar(argvars, rettv, 1);
10617}
10618
10619/*
10620 * "setwinvar()" function
10621 */
10622 static void
10623f_setwinvar(typval_T *argvars, typval_T *rettv)
10624{
10625 setwinvar(argvars, rettv, 0);
10626}
10627
10628#ifdef FEAT_CRYPT
10629/*
10630 * "sha256({string})" function
10631 */
10632 static void
10633f_sha256(typval_T *argvars, typval_T *rettv)
10634{
10635 char_u *p;
10636
10637 p = get_tv_string(&argvars[0]);
10638 rettv->vval.v_string = vim_strsave(
10639 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10640 rettv->v_type = VAR_STRING;
10641}
10642#endif /* FEAT_CRYPT */
10643
10644/*
10645 * "shellescape({string})" function
10646 */
10647 static void
10648f_shellescape(typval_T *argvars, typval_T *rettv)
10649{
Bram Moolenaar20615522017-06-05 18:46:26 +020010650 int do_special = non_zero_arg(&argvars[1]);
10651
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010652 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010653 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010654 rettv->v_type = VAR_STRING;
10655}
10656
10657/*
10658 * shiftwidth() function
10659 */
10660 static void
10661f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10662{
10663 rettv->vval.v_number = get_sw_value(curbuf);
10664}
10665
10666/*
10667 * "simplify()" function
10668 */
10669 static void
10670f_simplify(typval_T *argvars, typval_T *rettv)
10671{
10672 char_u *p;
10673
10674 p = get_tv_string(&argvars[0]);
10675 rettv->vval.v_string = vim_strsave(p);
10676 simplify_filename(rettv->vval.v_string); /* simplify in place */
10677 rettv->v_type = VAR_STRING;
10678}
10679
10680#ifdef FEAT_FLOAT
10681/*
10682 * "sin()" function
10683 */
10684 static void
10685f_sin(typval_T *argvars, typval_T *rettv)
10686{
10687 float_T f = 0.0;
10688
10689 rettv->v_type = VAR_FLOAT;
10690 if (get_float_arg(argvars, &f) == OK)
10691 rettv->vval.v_float = sin(f);
10692 else
10693 rettv->vval.v_float = 0.0;
10694}
10695
10696/*
10697 * "sinh()" function
10698 */
10699 static void
10700f_sinh(typval_T *argvars, typval_T *rettv)
10701{
10702 float_T f = 0.0;
10703
10704 rettv->v_type = VAR_FLOAT;
10705 if (get_float_arg(argvars, &f) == OK)
10706 rettv->vval.v_float = sinh(f);
10707 else
10708 rettv->vval.v_float = 0.0;
10709}
10710#endif
10711
10712static int
10713#ifdef __BORLANDC__
10714 _RTLENTRYF
10715#endif
10716 item_compare(const void *s1, const void *s2);
10717static int
10718#ifdef __BORLANDC__
10719 _RTLENTRYF
10720#endif
10721 item_compare2(const void *s1, const void *s2);
10722
10723/* struct used in the array that's given to qsort() */
10724typedef struct
10725{
10726 listitem_T *item;
10727 int idx;
10728} sortItem_T;
10729
10730/* struct storing information about current sort */
10731typedef struct
10732{
10733 int item_compare_ic;
10734 int item_compare_numeric;
10735 int item_compare_numbers;
10736#ifdef FEAT_FLOAT
10737 int item_compare_float;
10738#endif
10739 char_u *item_compare_func;
10740 partial_T *item_compare_partial;
10741 dict_T *item_compare_selfdict;
10742 int item_compare_func_err;
10743 int item_compare_keep_zero;
10744} sortinfo_T;
10745static sortinfo_T *sortinfo = NULL;
10746static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10747#define ITEM_COMPARE_FAIL 999
10748
10749/*
10750 * Compare functions for f_sort() and f_uniq() below.
10751 */
10752 static int
10753#ifdef __BORLANDC__
10754_RTLENTRYF
10755#endif
10756item_compare(const void *s1, const void *s2)
10757{
10758 sortItem_T *si1, *si2;
10759 typval_T *tv1, *tv2;
10760 char_u *p1, *p2;
10761 char_u *tofree1 = NULL, *tofree2 = NULL;
10762 int res;
10763 char_u numbuf1[NUMBUFLEN];
10764 char_u numbuf2[NUMBUFLEN];
10765
10766 si1 = (sortItem_T *)s1;
10767 si2 = (sortItem_T *)s2;
10768 tv1 = &si1->item->li_tv;
10769 tv2 = &si2->item->li_tv;
10770
10771 if (sortinfo->item_compare_numbers)
10772 {
10773 varnumber_T v1 = get_tv_number(tv1);
10774 varnumber_T v2 = get_tv_number(tv2);
10775
10776 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10777 }
10778
10779#ifdef FEAT_FLOAT
10780 if (sortinfo->item_compare_float)
10781 {
10782 float_T v1 = get_tv_float(tv1);
10783 float_T v2 = get_tv_float(tv2);
10784
10785 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10786 }
10787#endif
10788
10789 /* tv2string() puts quotes around a string and allocates memory. Don't do
10790 * that for string variables. Use a single quote when comparing with a
10791 * non-string to do what the docs promise. */
10792 if (tv1->v_type == VAR_STRING)
10793 {
10794 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10795 p1 = (char_u *)"'";
10796 else
10797 p1 = tv1->vval.v_string;
10798 }
10799 else
10800 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10801 if (tv2->v_type == VAR_STRING)
10802 {
10803 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10804 p2 = (char_u *)"'";
10805 else
10806 p2 = tv2->vval.v_string;
10807 }
10808 else
10809 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10810 if (p1 == NULL)
10811 p1 = (char_u *)"";
10812 if (p2 == NULL)
10813 p2 = (char_u *)"";
10814 if (!sortinfo->item_compare_numeric)
10815 {
10816 if (sortinfo->item_compare_ic)
10817 res = STRICMP(p1, p2);
10818 else
10819 res = STRCMP(p1, p2);
10820 }
10821 else
10822 {
10823 double n1, n2;
10824 n1 = strtod((char *)p1, (char **)&p1);
10825 n2 = strtod((char *)p2, (char **)&p2);
10826 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10827 }
10828
10829 /* When the result would be zero, compare the item indexes. Makes the
10830 * sort stable. */
10831 if (res == 0 && !sortinfo->item_compare_keep_zero)
10832 res = si1->idx > si2->idx ? 1 : -1;
10833
10834 vim_free(tofree1);
10835 vim_free(tofree2);
10836 return res;
10837}
10838
10839 static int
10840#ifdef __BORLANDC__
10841_RTLENTRYF
10842#endif
10843item_compare2(const void *s1, const void *s2)
10844{
10845 sortItem_T *si1, *si2;
10846 int res;
10847 typval_T rettv;
10848 typval_T argv[3];
10849 int dummy;
10850 char_u *func_name;
10851 partial_T *partial = sortinfo->item_compare_partial;
10852
10853 /* shortcut after failure in previous call; compare all items equal */
10854 if (sortinfo->item_compare_func_err)
10855 return 0;
10856
10857 si1 = (sortItem_T *)s1;
10858 si2 = (sortItem_T *)s2;
10859
10860 if (partial == NULL)
10861 func_name = sortinfo->item_compare_func;
10862 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010863 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010864
10865 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10866 * in the copy without changing the original list items. */
10867 copy_tv(&si1->item->li_tv, &argv[0]);
10868 copy_tv(&si2->item->li_tv, &argv[1]);
10869
10870 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10871 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010872 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010873 partial, sortinfo->item_compare_selfdict);
10874 clear_tv(&argv[0]);
10875 clear_tv(&argv[1]);
10876
10877 if (res == FAIL)
10878 res = ITEM_COMPARE_FAIL;
10879 else
10880 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10881 if (sortinfo->item_compare_func_err)
10882 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10883 clear_tv(&rettv);
10884
10885 /* When the result would be zero, compare the pointers themselves. Makes
10886 * the sort stable. */
10887 if (res == 0 && !sortinfo->item_compare_keep_zero)
10888 res = si1->idx > si2->idx ? 1 : -1;
10889
10890 return res;
10891}
10892
10893/*
10894 * "sort({list})" function
10895 */
10896 static void
10897do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10898{
10899 list_T *l;
10900 listitem_T *li;
10901 sortItem_T *ptrs;
10902 sortinfo_T *old_sortinfo;
10903 sortinfo_T info;
10904 long len;
10905 long i;
10906
10907 /* Pointer to current info struct used in compare function. Save and
10908 * restore the current one for nested calls. */
10909 old_sortinfo = sortinfo;
10910 sortinfo = &info;
10911
10912 if (argvars[0].v_type != VAR_LIST)
10913 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10914 else
10915 {
10916 l = argvars[0].vval.v_list;
10917 if (l == NULL || tv_check_lock(l->lv_lock,
10918 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10919 TRUE))
10920 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010921 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010922
10923 len = list_len(l);
10924 if (len <= 1)
10925 goto theend; /* short list sorts pretty quickly */
10926
10927 info.item_compare_ic = FALSE;
10928 info.item_compare_numeric = FALSE;
10929 info.item_compare_numbers = FALSE;
10930#ifdef FEAT_FLOAT
10931 info.item_compare_float = FALSE;
10932#endif
10933 info.item_compare_func = NULL;
10934 info.item_compare_partial = NULL;
10935 info.item_compare_selfdict = NULL;
10936 if (argvars[1].v_type != VAR_UNKNOWN)
10937 {
10938 /* optional second argument: {func} */
10939 if (argvars[1].v_type == VAR_FUNC)
10940 info.item_compare_func = argvars[1].vval.v_string;
10941 else if (argvars[1].v_type == VAR_PARTIAL)
10942 info.item_compare_partial = argvars[1].vval.v_partial;
10943 else
10944 {
10945 int error = FALSE;
10946
10947 i = (long)get_tv_number_chk(&argvars[1], &error);
10948 if (error)
10949 goto theend; /* type error; errmsg already given */
10950 if (i == 1)
10951 info.item_compare_ic = TRUE;
10952 else if (argvars[1].v_type != VAR_NUMBER)
10953 info.item_compare_func = get_tv_string(&argvars[1]);
10954 else if (i != 0)
10955 {
10956 EMSG(_(e_invarg));
10957 goto theend;
10958 }
10959 if (info.item_compare_func != NULL)
10960 {
10961 if (*info.item_compare_func == NUL)
10962 {
10963 /* empty string means default sort */
10964 info.item_compare_func = NULL;
10965 }
10966 else if (STRCMP(info.item_compare_func, "n") == 0)
10967 {
10968 info.item_compare_func = NULL;
10969 info.item_compare_numeric = TRUE;
10970 }
10971 else if (STRCMP(info.item_compare_func, "N") == 0)
10972 {
10973 info.item_compare_func = NULL;
10974 info.item_compare_numbers = TRUE;
10975 }
10976#ifdef FEAT_FLOAT
10977 else if (STRCMP(info.item_compare_func, "f") == 0)
10978 {
10979 info.item_compare_func = NULL;
10980 info.item_compare_float = TRUE;
10981 }
10982#endif
10983 else if (STRCMP(info.item_compare_func, "i") == 0)
10984 {
10985 info.item_compare_func = NULL;
10986 info.item_compare_ic = TRUE;
10987 }
10988 }
10989 }
10990
10991 if (argvars[2].v_type != VAR_UNKNOWN)
10992 {
10993 /* optional third argument: {dict} */
10994 if (argvars[2].v_type != VAR_DICT)
10995 {
10996 EMSG(_(e_dictreq));
10997 goto theend;
10998 }
10999 info.item_compare_selfdict = argvars[2].vval.v_dict;
11000 }
11001 }
11002
11003 /* Make an array with each entry pointing to an item in the List. */
11004 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11005 if (ptrs == NULL)
11006 goto theend;
11007
11008 i = 0;
11009 if (sort)
11010 {
11011 /* sort(): ptrs will be the list to sort */
11012 for (li = l->lv_first; li != NULL; li = li->li_next)
11013 {
11014 ptrs[i].item = li;
11015 ptrs[i].idx = i;
11016 ++i;
11017 }
11018
11019 info.item_compare_func_err = FALSE;
11020 info.item_compare_keep_zero = FALSE;
11021 /* test the compare function */
11022 if ((info.item_compare_func != NULL
11023 || info.item_compare_partial != NULL)
11024 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11025 == ITEM_COMPARE_FAIL)
11026 EMSG(_("E702: Sort compare function failed"));
11027 else
11028 {
11029 /* Sort the array with item pointers. */
11030 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11031 info.item_compare_func == NULL
11032 && info.item_compare_partial == NULL
11033 ? item_compare : item_compare2);
11034
11035 if (!info.item_compare_func_err)
11036 {
11037 /* Clear the List and append the items in sorted order. */
11038 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11039 l->lv_len = 0;
11040 for (i = 0; i < len; ++i)
11041 list_append(l, ptrs[i].item);
11042 }
11043 }
11044 }
11045 else
11046 {
11047 int (*item_compare_func_ptr)(const void *, const void *);
11048
11049 /* f_uniq(): ptrs will be a stack of items to remove */
11050 info.item_compare_func_err = FALSE;
11051 info.item_compare_keep_zero = TRUE;
11052 item_compare_func_ptr = info.item_compare_func != NULL
11053 || info.item_compare_partial != NULL
11054 ? item_compare2 : item_compare;
11055
11056 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11057 li = li->li_next)
11058 {
11059 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11060 == 0)
11061 ptrs[i++].item = li;
11062 if (info.item_compare_func_err)
11063 {
11064 EMSG(_("E882: Uniq compare function failed"));
11065 break;
11066 }
11067 }
11068
11069 if (!info.item_compare_func_err)
11070 {
11071 while (--i >= 0)
11072 {
11073 li = ptrs[i].item->li_next;
11074 ptrs[i].item->li_next = li->li_next;
11075 if (li->li_next != NULL)
11076 li->li_next->li_prev = ptrs[i].item;
11077 else
11078 l->lv_last = ptrs[i].item;
11079 list_fix_watch(l, li);
11080 listitem_free(li);
11081 l->lv_len--;
11082 }
11083 }
11084 }
11085
11086 vim_free(ptrs);
11087 }
11088theend:
11089 sortinfo = old_sortinfo;
11090}
11091
11092/*
11093 * "sort({list})" function
11094 */
11095 static void
11096f_sort(typval_T *argvars, typval_T *rettv)
11097{
11098 do_sort_uniq(argvars, rettv, TRUE);
11099}
11100
11101/*
11102 * "uniq({list})" function
11103 */
11104 static void
11105f_uniq(typval_T *argvars, typval_T *rettv)
11106{
11107 do_sort_uniq(argvars, rettv, FALSE);
11108}
11109
11110/*
11111 * "soundfold({word})" function
11112 */
11113 static void
11114f_soundfold(typval_T *argvars, typval_T *rettv)
11115{
11116 char_u *s;
11117
11118 rettv->v_type = VAR_STRING;
11119 s = get_tv_string(&argvars[0]);
11120#ifdef FEAT_SPELL
11121 rettv->vval.v_string = eval_soundfold(s);
11122#else
11123 rettv->vval.v_string = vim_strsave(s);
11124#endif
11125}
11126
11127/*
11128 * "spellbadword()" function
11129 */
11130 static void
11131f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11132{
11133 char_u *word = (char_u *)"";
11134 hlf_T attr = HLF_COUNT;
11135 int len = 0;
11136
11137 if (rettv_list_alloc(rettv) == FAIL)
11138 return;
11139
11140#ifdef FEAT_SPELL
11141 if (argvars[0].v_type == VAR_UNKNOWN)
11142 {
11143 /* Find the start and length of the badly spelled word. */
11144 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11145 if (len != 0)
11146 word = ml_get_cursor();
11147 }
11148 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11149 {
11150 char_u *str = get_tv_string_chk(&argvars[0]);
11151 int capcol = -1;
11152
11153 if (str != NULL)
11154 {
11155 /* Check the argument for spelling. */
11156 while (*str != NUL)
11157 {
11158 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11159 if (attr != HLF_COUNT)
11160 {
11161 word = str;
11162 break;
11163 }
11164 str += len;
11165 }
11166 }
11167 }
11168#endif
11169
11170 list_append_string(rettv->vval.v_list, word, len);
11171 list_append_string(rettv->vval.v_list, (char_u *)(
11172 attr == HLF_SPB ? "bad" :
11173 attr == HLF_SPR ? "rare" :
11174 attr == HLF_SPL ? "local" :
11175 attr == HLF_SPC ? "caps" :
11176 ""), -1);
11177}
11178
11179/*
11180 * "spellsuggest()" function
11181 */
11182 static void
11183f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11184{
11185#ifdef FEAT_SPELL
11186 char_u *str;
11187 int typeerr = FALSE;
11188 int maxcount;
11189 garray_T ga;
11190 int i;
11191 listitem_T *li;
11192 int need_capital = FALSE;
11193#endif
11194
11195 if (rettv_list_alloc(rettv) == FAIL)
11196 return;
11197
11198#ifdef FEAT_SPELL
11199 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11200 {
11201 str = get_tv_string(&argvars[0]);
11202 if (argvars[1].v_type != VAR_UNKNOWN)
11203 {
11204 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11205 if (maxcount <= 0)
11206 return;
11207 if (argvars[2].v_type != VAR_UNKNOWN)
11208 {
11209 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11210 if (typeerr)
11211 return;
11212 }
11213 }
11214 else
11215 maxcount = 25;
11216
11217 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11218
11219 for (i = 0; i < ga.ga_len; ++i)
11220 {
11221 str = ((char_u **)ga.ga_data)[i];
11222
11223 li = listitem_alloc();
11224 if (li == NULL)
11225 vim_free(str);
11226 else
11227 {
11228 li->li_tv.v_type = VAR_STRING;
11229 li->li_tv.v_lock = 0;
11230 li->li_tv.vval.v_string = str;
11231 list_append(rettv->vval.v_list, li);
11232 }
11233 }
11234 ga_clear(&ga);
11235 }
11236#endif
11237}
11238
11239 static void
11240f_split(typval_T *argvars, typval_T *rettv)
11241{
11242 char_u *str;
11243 char_u *end;
11244 char_u *pat = NULL;
11245 regmatch_T regmatch;
11246 char_u patbuf[NUMBUFLEN];
11247 char_u *save_cpo;
11248 int match;
11249 colnr_T col = 0;
11250 int keepempty = FALSE;
11251 int typeerr = FALSE;
11252
11253 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11254 save_cpo = p_cpo;
11255 p_cpo = (char_u *)"";
11256
11257 str = get_tv_string(&argvars[0]);
11258 if (argvars[1].v_type != VAR_UNKNOWN)
11259 {
11260 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11261 if (pat == NULL)
11262 typeerr = TRUE;
11263 if (argvars[2].v_type != VAR_UNKNOWN)
11264 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11265 }
11266 if (pat == NULL || *pat == NUL)
11267 pat = (char_u *)"[\\x01- ]\\+";
11268
11269 if (rettv_list_alloc(rettv) == FAIL)
11270 return;
11271 if (typeerr)
11272 return;
11273
11274 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11275 if (regmatch.regprog != NULL)
11276 {
11277 regmatch.rm_ic = FALSE;
11278 while (*str != NUL || keepempty)
11279 {
11280 if (*str == NUL)
11281 match = FALSE; /* empty item at the end */
11282 else
11283 match = vim_regexec_nl(&regmatch, str, col);
11284 if (match)
11285 end = regmatch.startp[0];
11286 else
11287 end = str + STRLEN(str);
11288 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11289 && *str != NUL && match && end < regmatch.endp[0]))
11290 {
11291 if (list_append_string(rettv->vval.v_list, str,
11292 (int)(end - str)) == FAIL)
11293 break;
11294 }
11295 if (!match)
11296 break;
11297 /* Advance to just after the match. */
11298 if (regmatch.endp[0] > str)
11299 col = 0;
11300 else
11301 {
11302 /* Don't get stuck at the same match. */
11303#ifdef FEAT_MBYTE
11304 col = (*mb_ptr2len)(regmatch.endp[0]);
11305#else
11306 col = 1;
11307#endif
11308 }
11309 str = regmatch.endp[0];
11310 }
11311
11312 vim_regfree(regmatch.regprog);
11313 }
11314
11315 p_cpo = save_cpo;
11316}
11317
11318#ifdef FEAT_FLOAT
11319/*
11320 * "sqrt()" function
11321 */
11322 static void
11323f_sqrt(typval_T *argvars, typval_T *rettv)
11324{
11325 float_T f = 0.0;
11326
11327 rettv->v_type = VAR_FLOAT;
11328 if (get_float_arg(argvars, &f) == OK)
11329 rettv->vval.v_float = sqrt(f);
11330 else
11331 rettv->vval.v_float = 0.0;
11332}
11333
11334/*
11335 * "str2float()" function
11336 */
11337 static void
11338f_str2float(typval_T *argvars, typval_T *rettv)
11339{
11340 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011341 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011342
Bram Moolenaar08243d22017-01-10 16:12:29 +010011343 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011344 p = skipwhite(p + 1);
11345 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011346 if (isneg)
11347 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011348 rettv->v_type = VAR_FLOAT;
11349}
11350#endif
11351
11352/*
11353 * "str2nr()" function
11354 */
11355 static void
11356f_str2nr(typval_T *argvars, typval_T *rettv)
11357{
11358 int base = 10;
11359 char_u *p;
11360 varnumber_T n;
11361 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011362 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011363
11364 if (argvars[1].v_type != VAR_UNKNOWN)
11365 {
11366 base = (int)get_tv_number(&argvars[1]);
11367 if (base != 2 && base != 8 && base != 10 && base != 16)
11368 {
11369 EMSG(_(e_invarg));
11370 return;
11371 }
11372 }
11373
11374 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011375 isneg = (*p == '-');
11376 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011377 p = skipwhite(p + 1);
11378 switch (base)
11379 {
11380 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11381 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11382 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11383 default: what = 0;
11384 }
11385 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011386 if (isneg)
11387 rettv->vval.v_number = -n;
11388 else
11389 rettv->vval.v_number = n;
11390
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011391}
11392
11393#ifdef HAVE_STRFTIME
11394/*
11395 * "strftime({format}[, {time}])" function
11396 */
11397 static void
11398f_strftime(typval_T *argvars, typval_T *rettv)
11399{
11400 char_u result_buf[256];
11401 struct tm *curtime;
11402 time_t seconds;
11403 char_u *p;
11404
11405 rettv->v_type = VAR_STRING;
11406
11407 p = get_tv_string(&argvars[0]);
11408 if (argvars[1].v_type == VAR_UNKNOWN)
11409 seconds = time(NULL);
11410 else
11411 seconds = (time_t)get_tv_number(&argvars[1]);
11412 curtime = localtime(&seconds);
11413 /* MSVC returns NULL for an invalid value of seconds. */
11414 if (curtime == NULL)
11415 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11416 else
11417 {
11418# ifdef FEAT_MBYTE
11419 vimconv_T conv;
11420 char_u *enc;
11421
11422 conv.vc_type = CONV_NONE;
11423 enc = enc_locale();
11424 convert_setup(&conv, p_enc, enc);
11425 if (conv.vc_type != CONV_NONE)
11426 p = string_convert(&conv, p, NULL);
11427# endif
11428 if (p != NULL)
11429 (void)strftime((char *)result_buf, sizeof(result_buf),
11430 (char *)p, curtime);
11431 else
11432 result_buf[0] = NUL;
11433
11434# ifdef FEAT_MBYTE
11435 if (conv.vc_type != CONV_NONE)
11436 vim_free(p);
11437 convert_setup(&conv, enc, p_enc);
11438 if (conv.vc_type != CONV_NONE)
11439 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11440 else
11441# endif
11442 rettv->vval.v_string = vim_strsave(result_buf);
11443
11444# ifdef FEAT_MBYTE
11445 /* Release conversion descriptors */
11446 convert_setup(&conv, NULL, NULL);
11447 vim_free(enc);
11448# endif
11449 }
11450}
11451#endif
11452
11453/*
11454 * "strgetchar()" function
11455 */
11456 static void
11457f_strgetchar(typval_T *argvars, typval_T *rettv)
11458{
11459 char_u *str;
11460 int len;
11461 int error = FALSE;
11462 int charidx;
11463
11464 rettv->vval.v_number = -1;
11465 str = get_tv_string_chk(&argvars[0]);
11466 if (str == NULL)
11467 return;
11468 len = (int)STRLEN(str);
11469 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11470 if (error)
11471 return;
11472#ifdef FEAT_MBYTE
11473 {
11474 int byteidx = 0;
11475
11476 while (charidx >= 0 && byteidx < len)
11477 {
11478 if (charidx == 0)
11479 {
11480 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11481 break;
11482 }
11483 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011484 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011485 }
11486 }
11487#else
11488 if (charidx < len)
11489 rettv->vval.v_number = str[charidx];
11490#endif
11491}
11492
11493/*
11494 * "stridx()" function
11495 */
11496 static void
11497f_stridx(typval_T *argvars, typval_T *rettv)
11498{
11499 char_u buf[NUMBUFLEN];
11500 char_u *needle;
11501 char_u *haystack;
11502 char_u *save_haystack;
11503 char_u *pos;
11504 int start_idx;
11505
11506 needle = get_tv_string_chk(&argvars[1]);
11507 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11508 rettv->vval.v_number = -1;
11509 if (needle == NULL || haystack == NULL)
11510 return; /* type error; errmsg already given */
11511
11512 if (argvars[2].v_type != VAR_UNKNOWN)
11513 {
11514 int error = FALSE;
11515
11516 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11517 if (error || start_idx >= (int)STRLEN(haystack))
11518 return;
11519 if (start_idx >= 0)
11520 haystack += start_idx;
11521 }
11522
11523 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11524 if (pos != NULL)
11525 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11526}
11527
11528/*
11529 * "string()" function
11530 */
11531 static void
11532f_string(typval_T *argvars, typval_T *rettv)
11533{
11534 char_u *tofree;
11535 char_u numbuf[NUMBUFLEN];
11536
11537 rettv->v_type = VAR_STRING;
11538 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11539 get_copyID());
11540 /* Make a copy if we have a value but it's not in allocated memory. */
11541 if (rettv->vval.v_string != NULL && tofree == NULL)
11542 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11543}
11544
11545/*
11546 * "strlen()" function
11547 */
11548 static void
11549f_strlen(typval_T *argvars, typval_T *rettv)
11550{
11551 rettv->vval.v_number = (varnumber_T)(STRLEN(
11552 get_tv_string(&argvars[0])));
11553}
11554
11555/*
11556 * "strchars()" function
11557 */
11558 static void
11559f_strchars(typval_T *argvars, typval_T *rettv)
11560{
11561 char_u *s = get_tv_string(&argvars[0]);
11562 int skipcc = 0;
11563#ifdef FEAT_MBYTE
11564 varnumber_T len = 0;
11565 int (*func_mb_ptr2char_adv)(char_u **pp);
11566#endif
11567
11568 if (argvars[1].v_type != VAR_UNKNOWN)
11569 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11570 if (skipcc < 0 || skipcc > 1)
11571 EMSG(_(e_invarg));
11572 else
11573 {
11574#ifdef FEAT_MBYTE
11575 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11576 while (*s != NUL)
11577 {
11578 func_mb_ptr2char_adv(&s);
11579 ++len;
11580 }
11581 rettv->vval.v_number = len;
11582#else
11583 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11584#endif
11585 }
11586}
11587
11588/*
11589 * "strdisplaywidth()" function
11590 */
11591 static void
11592f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11593{
11594 char_u *s = get_tv_string(&argvars[0]);
11595 int col = 0;
11596
11597 if (argvars[1].v_type != VAR_UNKNOWN)
11598 col = (int)get_tv_number(&argvars[1]);
11599
11600 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11601}
11602
11603/*
11604 * "strwidth()" function
11605 */
11606 static void
11607f_strwidth(typval_T *argvars, typval_T *rettv)
11608{
11609 char_u *s = get_tv_string(&argvars[0]);
11610
11611 rettv->vval.v_number = (varnumber_T)(
11612#ifdef FEAT_MBYTE
11613 mb_string2cells(s, -1)
11614#else
11615 STRLEN(s)
11616#endif
11617 );
11618}
11619
11620/*
11621 * "strcharpart()" function
11622 */
11623 static void
11624f_strcharpart(typval_T *argvars, typval_T *rettv)
11625{
11626#ifdef FEAT_MBYTE
11627 char_u *p;
11628 int nchar;
11629 int nbyte = 0;
11630 int charlen;
11631 int len = 0;
11632 int slen;
11633 int error = FALSE;
11634
11635 p = get_tv_string(&argvars[0]);
11636 slen = (int)STRLEN(p);
11637
11638 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11639 if (!error)
11640 {
11641 if (nchar > 0)
11642 while (nchar > 0 && nbyte < slen)
11643 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011644 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011645 --nchar;
11646 }
11647 else
11648 nbyte = nchar;
11649 if (argvars[2].v_type != VAR_UNKNOWN)
11650 {
11651 charlen = (int)get_tv_number(&argvars[2]);
11652 while (charlen > 0 && nbyte + len < slen)
11653 {
11654 int off = nbyte + len;
11655
11656 if (off < 0)
11657 len += 1;
11658 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011659 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011660 --charlen;
11661 }
11662 }
11663 else
11664 len = slen - nbyte; /* default: all bytes that are available. */
11665 }
11666
11667 /*
11668 * Only return the overlap between the specified part and the actual
11669 * string.
11670 */
11671 if (nbyte < 0)
11672 {
11673 len += nbyte;
11674 nbyte = 0;
11675 }
11676 else if (nbyte > slen)
11677 nbyte = slen;
11678 if (len < 0)
11679 len = 0;
11680 else if (nbyte + len > slen)
11681 len = slen - nbyte;
11682
11683 rettv->v_type = VAR_STRING;
11684 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11685#else
11686 f_strpart(argvars, rettv);
11687#endif
11688}
11689
11690/*
11691 * "strpart()" function
11692 */
11693 static void
11694f_strpart(typval_T *argvars, typval_T *rettv)
11695{
11696 char_u *p;
11697 int n;
11698 int len;
11699 int slen;
11700 int error = FALSE;
11701
11702 p = get_tv_string(&argvars[0]);
11703 slen = (int)STRLEN(p);
11704
11705 n = (int)get_tv_number_chk(&argvars[1], &error);
11706 if (error)
11707 len = 0;
11708 else if (argvars[2].v_type != VAR_UNKNOWN)
11709 len = (int)get_tv_number(&argvars[2]);
11710 else
11711 len = slen - n; /* default len: all bytes that are available. */
11712
11713 /*
11714 * Only return the overlap between the specified part and the actual
11715 * string.
11716 */
11717 if (n < 0)
11718 {
11719 len += n;
11720 n = 0;
11721 }
11722 else if (n > slen)
11723 n = slen;
11724 if (len < 0)
11725 len = 0;
11726 else if (n + len > slen)
11727 len = slen - n;
11728
11729 rettv->v_type = VAR_STRING;
11730 rettv->vval.v_string = vim_strnsave(p + n, len);
11731}
11732
11733/*
11734 * "strridx()" function
11735 */
11736 static void
11737f_strridx(typval_T *argvars, typval_T *rettv)
11738{
11739 char_u buf[NUMBUFLEN];
11740 char_u *needle;
11741 char_u *haystack;
11742 char_u *rest;
11743 char_u *lastmatch = NULL;
11744 int haystack_len, end_idx;
11745
11746 needle = get_tv_string_chk(&argvars[1]);
11747 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11748
11749 rettv->vval.v_number = -1;
11750 if (needle == NULL || haystack == NULL)
11751 return; /* type error; errmsg already given */
11752
11753 haystack_len = (int)STRLEN(haystack);
11754 if (argvars[2].v_type != VAR_UNKNOWN)
11755 {
11756 /* Third argument: upper limit for index */
11757 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11758 if (end_idx < 0)
11759 return; /* can never find a match */
11760 }
11761 else
11762 end_idx = haystack_len;
11763
11764 if (*needle == NUL)
11765 {
11766 /* Empty string matches past the end. */
11767 lastmatch = haystack + end_idx;
11768 }
11769 else
11770 {
11771 for (rest = haystack; *rest != '\0'; ++rest)
11772 {
11773 rest = (char_u *)strstr((char *)rest, (char *)needle);
11774 if (rest == NULL || rest > haystack + end_idx)
11775 break;
11776 lastmatch = rest;
11777 }
11778 }
11779
11780 if (lastmatch == NULL)
11781 rettv->vval.v_number = -1;
11782 else
11783 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11784}
11785
11786/*
11787 * "strtrans()" function
11788 */
11789 static void
11790f_strtrans(typval_T *argvars, typval_T *rettv)
11791{
11792 rettv->v_type = VAR_STRING;
11793 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11794}
11795
11796/*
11797 * "submatch()" function
11798 */
11799 static void
11800f_submatch(typval_T *argvars, typval_T *rettv)
11801{
11802 int error = FALSE;
11803 int no;
11804 int retList = 0;
11805
11806 no = (int)get_tv_number_chk(&argvars[0], &error);
11807 if (error)
11808 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011809 if (no < 0 || no >= NSUBEXP)
11810 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010011811 EMSGN(_("E935: invalid submatch number: %d"), no);
11812 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011813 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011814 if (argvars[1].v_type != VAR_UNKNOWN)
11815 retList = (int)get_tv_number_chk(&argvars[1], &error);
11816 if (error)
11817 return;
11818
11819 if (retList == 0)
11820 {
11821 rettv->v_type = VAR_STRING;
11822 rettv->vval.v_string = reg_submatch(no);
11823 }
11824 else
11825 {
11826 rettv->v_type = VAR_LIST;
11827 rettv->vval.v_list = reg_submatch_list(no);
11828 }
11829}
11830
11831/*
11832 * "substitute()" function
11833 */
11834 static void
11835f_substitute(typval_T *argvars, typval_T *rettv)
11836{
11837 char_u patbuf[NUMBUFLEN];
11838 char_u subbuf[NUMBUFLEN];
11839 char_u flagsbuf[NUMBUFLEN];
11840
11841 char_u *str = get_tv_string_chk(&argvars[0]);
11842 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011843 char_u *sub = NULL;
11844 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011845 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11846
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011847 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11848 expr = &argvars[2];
11849 else
11850 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11851
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011852 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011853 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11854 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011855 rettv->vval.v_string = NULL;
11856 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011857 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011858}
11859
11860/*
11861 * "synID(lnum, col, trans)" function
11862 */
11863 static void
11864f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11865{
11866 int id = 0;
11867#ifdef FEAT_SYN_HL
11868 linenr_T lnum;
11869 colnr_T col;
11870 int trans;
11871 int transerr = FALSE;
11872
11873 lnum = get_tv_lnum(argvars); /* -1 on type error */
11874 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11875 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11876
11877 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11878 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11879 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11880#endif
11881
11882 rettv->vval.v_number = id;
11883}
11884
11885/*
11886 * "synIDattr(id, what [, mode])" function
11887 */
11888 static void
11889f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11890{
11891 char_u *p = NULL;
11892#ifdef FEAT_SYN_HL
11893 int id;
11894 char_u *what;
11895 char_u *mode;
11896 char_u modebuf[NUMBUFLEN];
11897 int modec;
11898
11899 id = (int)get_tv_number(&argvars[0]);
11900 what = get_tv_string(&argvars[1]);
11901 if (argvars[2].v_type != VAR_UNKNOWN)
11902 {
11903 mode = get_tv_string_buf(&argvars[2], modebuf);
11904 modec = TOLOWER_ASC(mode[0]);
11905 if (modec != 't' && modec != 'c' && modec != 'g')
11906 modec = 0; /* replace invalid with current */
11907 }
11908 else
11909 {
11910#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11911 if (USE_24BIT)
11912 modec = 'g';
11913 else
11914#endif
11915 if (t_colors > 1)
11916 modec = 'c';
11917 else
11918 modec = 't';
11919 }
11920
11921
11922 switch (TOLOWER_ASC(what[0]))
11923 {
11924 case 'b':
11925 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11926 p = highlight_color(id, what, modec);
11927 else /* bold */
11928 p = highlight_has_attr(id, HL_BOLD, modec);
11929 break;
11930
11931 case 'f': /* fg[#] or font */
11932 p = highlight_color(id, what, modec);
11933 break;
11934
11935 case 'i':
11936 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11937 p = highlight_has_attr(id, HL_INVERSE, modec);
11938 else /* italic */
11939 p = highlight_has_attr(id, HL_ITALIC, modec);
11940 break;
11941
11942 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011943 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011944 break;
11945
11946 case 'r': /* reverse */
11947 p = highlight_has_attr(id, HL_INVERSE, modec);
11948 break;
11949
11950 case 's':
11951 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11952 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011953 /* strikeout */
11954 else if (TOLOWER_ASC(what[1]) == 't' &&
11955 TOLOWER_ASC(what[2]) == 'r')
11956 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011957 else /* standout */
11958 p = highlight_has_attr(id, HL_STANDOUT, modec);
11959 break;
11960
11961 case 'u':
11962 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11963 /* underline */
11964 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11965 else
11966 /* undercurl */
11967 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11968 break;
11969 }
11970
11971 if (p != NULL)
11972 p = vim_strsave(p);
11973#endif
11974 rettv->v_type = VAR_STRING;
11975 rettv->vval.v_string = p;
11976}
11977
11978/*
11979 * "synIDtrans(id)" function
11980 */
11981 static void
11982f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11983{
11984 int id;
11985
11986#ifdef FEAT_SYN_HL
11987 id = (int)get_tv_number(&argvars[0]);
11988
11989 if (id > 0)
11990 id = syn_get_final_id(id);
11991 else
11992#endif
11993 id = 0;
11994
11995 rettv->vval.v_number = id;
11996}
11997
11998/*
11999 * "synconcealed(lnum, col)" function
12000 */
12001 static void
12002f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12003{
12004#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12005 linenr_T lnum;
12006 colnr_T col;
12007 int syntax_flags = 0;
12008 int cchar;
12009 int matchid = 0;
12010 char_u str[NUMBUFLEN];
12011#endif
12012
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012013 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012014
12015#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12016 lnum = get_tv_lnum(argvars); /* -1 on type error */
12017 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12018
12019 vim_memset(str, NUL, sizeof(str));
12020
12021 if (rettv_list_alloc(rettv) != FAIL)
12022 {
12023 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12024 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12025 && curwin->w_p_cole > 0)
12026 {
12027 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12028 syntax_flags = get_syntax_info(&matchid);
12029
12030 /* get the conceal character */
12031 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12032 {
12033 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012034 if (cchar == NUL && curwin->w_p_cole == 1)
12035 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012036 if (cchar != NUL)
12037 {
12038# ifdef FEAT_MBYTE
12039 if (has_mbyte)
12040 (*mb_char2bytes)(cchar, str);
12041 else
12042# endif
12043 str[0] = cchar;
12044 }
12045 }
12046 }
12047
12048 list_append_number(rettv->vval.v_list,
12049 (syntax_flags & HL_CONCEAL) != 0);
12050 /* -1 to auto-determine strlen */
12051 list_append_string(rettv->vval.v_list, str, -1);
12052 list_append_number(rettv->vval.v_list, matchid);
12053 }
12054#endif
12055}
12056
12057/*
12058 * "synstack(lnum, col)" function
12059 */
12060 static void
12061f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12062{
12063#ifdef FEAT_SYN_HL
12064 linenr_T lnum;
12065 colnr_T col;
12066 int i;
12067 int id;
12068#endif
12069
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012070 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012071
12072#ifdef FEAT_SYN_HL
12073 lnum = get_tv_lnum(argvars); /* -1 on type error */
12074 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12075
12076 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12077 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12078 && rettv_list_alloc(rettv) != FAIL)
12079 {
12080 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12081 for (i = 0; ; ++i)
12082 {
12083 id = syn_get_stack_item(i);
12084 if (id < 0)
12085 break;
12086 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12087 break;
12088 }
12089 }
12090#endif
12091}
12092
12093 static void
12094get_cmd_output_as_rettv(
12095 typval_T *argvars,
12096 typval_T *rettv,
12097 int retlist)
12098{
12099 char_u *res = NULL;
12100 char_u *p;
12101 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012102 int err = FALSE;
12103 FILE *fd;
12104 list_T *list = NULL;
12105 int flags = SHELL_SILENT;
12106
12107 rettv->v_type = VAR_STRING;
12108 rettv->vval.v_string = NULL;
12109 if (check_restricted() || check_secure())
12110 goto errret;
12111
12112 if (argvars[1].v_type != VAR_UNKNOWN)
12113 {
12114 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012115 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012116 * command.
12117 */
12118 if ((infile = vim_tempname('i', TRUE)) == NULL)
12119 {
12120 EMSG(_(e_notmp));
12121 goto errret;
12122 }
12123
12124 fd = mch_fopen((char *)infile, WRITEBIN);
12125 if (fd == NULL)
12126 {
12127 EMSG2(_(e_notopen), infile);
12128 goto errret;
12129 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012130 if (argvars[1].v_type == VAR_NUMBER)
12131 {
12132 linenr_T lnum;
12133 buf_T *buf;
12134
12135 buf = buflist_findnr(argvars[1].vval.v_number);
12136 if (buf == NULL)
12137 {
12138 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012139 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012140 goto errret;
12141 }
12142
12143 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12144 {
12145 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12146 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12147 {
12148 err = TRUE;
12149 break;
12150 }
12151 if (putc(NL, fd) == EOF)
12152 {
12153 err = TRUE;
12154 break;
12155 }
12156 }
12157 }
12158 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012159 {
12160 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12161 err = TRUE;
12162 }
12163 else
12164 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012165 size_t len;
12166 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012167
12168 p = get_tv_string_buf_chk(&argvars[1], buf);
12169 if (p == NULL)
12170 {
12171 fclose(fd);
12172 goto errret; /* type error; errmsg already given */
12173 }
12174 len = STRLEN(p);
12175 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12176 err = TRUE;
12177 }
12178 if (fclose(fd) != 0)
12179 err = TRUE;
12180 if (err)
12181 {
12182 EMSG(_("E677: Error writing temp file"));
12183 goto errret;
12184 }
12185 }
12186
12187 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12188 * echoes typeahead, that messes up the display. */
12189 if (!msg_silent)
12190 flags += SHELL_COOKED;
12191
12192 if (retlist)
12193 {
12194 int len;
12195 listitem_T *li;
12196 char_u *s = NULL;
12197 char_u *start;
12198 char_u *end;
12199 int i;
12200
12201 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12202 if (res == NULL)
12203 goto errret;
12204
12205 list = list_alloc();
12206 if (list == NULL)
12207 goto errret;
12208
12209 for (i = 0; i < len; ++i)
12210 {
12211 start = res + i;
12212 while (i < len && res[i] != NL)
12213 ++i;
12214 end = res + i;
12215
12216 s = alloc((unsigned)(end - start + 1));
12217 if (s == NULL)
12218 goto errret;
12219
12220 for (p = s; start < end; ++p, ++start)
12221 *p = *start == NUL ? NL : *start;
12222 *p = NUL;
12223
12224 li = listitem_alloc();
12225 if (li == NULL)
12226 {
12227 vim_free(s);
12228 goto errret;
12229 }
12230 li->li_tv.v_type = VAR_STRING;
12231 li->li_tv.v_lock = 0;
12232 li->li_tv.vval.v_string = s;
12233 list_append(list, li);
12234 }
12235
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012236 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012237 list = NULL;
12238 }
12239 else
12240 {
12241 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12242#ifdef USE_CR
12243 /* translate <CR> into <NL> */
12244 if (res != NULL)
12245 {
12246 char_u *s;
12247
12248 for (s = res; *s; ++s)
12249 {
12250 if (*s == CAR)
12251 *s = NL;
12252 }
12253 }
12254#else
12255# ifdef USE_CRNL
12256 /* translate <CR><NL> into <NL> */
12257 if (res != NULL)
12258 {
12259 char_u *s, *d;
12260
12261 d = res;
12262 for (s = res; *s; ++s)
12263 {
12264 if (s[0] == CAR && s[1] == NL)
12265 ++s;
12266 *d++ = *s;
12267 }
12268 *d = NUL;
12269 }
12270# endif
12271#endif
12272 rettv->vval.v_string = res;
12273 res = NULL;
12274 }
12275
12276errret:
12277 if (infile != NULL)
12278 {
12279 mch_remove(infile);
12280 vim_free(infile);
12281 }
12282 if (res != NULL)
12283 vim_free(res);
12284 if (list != NULL)
12285 list_free(list);
12286}
12287
12288/*
12289 * "system()" function
12290 */
12291 static void
12292f_system(typval_T *argvars, typval_T *rettv)
12293{
12294 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12295}
12296
12297/*
12298 * "systemlist()" function
12299 */
12300 static void
12301f_systemlist(typval_T *argvars, typval_T *rettv)
12302{
12303 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12304}
12305
12306/*
12307 * "tabpagebuflist()" function
12308 */
12309 static void
12310f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12311{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012312 tabpage_T *tp;
12313 win_T *wp = NULL;
12314
12315 if (argvars[0].v_type == VAR_UNKNOWN)
12316 wp = firstwin;
12317 else
12318 {
12319 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12320 if (tp != NULL)
12321 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12322 }
12323 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12324 {
12325 for (; wp != NULL; wp = wp->w_next)
12326 if (list_append_number(rettv->vval.v_list,
12327 wp->w_buffer->b_fnum) == FAIL)
12328 break;
12329 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012330}
12331
12332
12333/*
12334 * "tabpagenr()" function
12335 */
12336 static void
12337f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12338{
12339 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012340 char_u *arg;
12341
12342 if (argvars[0].v_type != VAR_UNKNOWN)
12343 {
12344 arg = get_tv_string_chk(&argvars[0]);
12345 nr = 0;
12346 if (arg != NULL)
12347 {
12348 if (STRCMP(arg, "$") == 0)
12349 nr = tabpage_index(NULL) - 1;
12350 else
12351 EMSG2(_(e_invexpr2), arg);
12352 }
12353 }
12354 else
12355 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012356 rettv->vval.v_number = nr;
12357}
12358
12359
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012360static int get_winnr(tabpage_T *tp, typval_T *argvar);
12361
12362/*
12363 * Common code for tabpagewinnr() and winnr().
12364 */
12365 static int
12366get_winnr(tabpage_T *tp, typval_T *argvar)
12367{
12368 win_T *twin;
12369 int nr = 1;
12370 win_T *wp;
12371 char_u *arg;
12372
12373 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12374 if (argvar->v_type != VAR_UNKNOWN)
12375 {
12376 arg = get_tv_string_chk(argvar);
12377 if (arg == NULL)
12378 nr = 0; /* type error; errmsg already given */
12379 else if (STRCMP(arg, "$") == 0)
12380 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12381 else if (STRCMP(arg, "#") == 0)
12382 {
12383 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12384 if (twin == NULL)
12385 nr = 0;
12386 }
12387 else
12388 {
12389 EMSG2(_(e_invexpr2), arg);
12390 nr = 0;
12391 }
12392 }
12393
12394 if (nr > 0)
12395 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12396 wp != twin; wp = wp->w_next)
12397 {
12398 if (wp == NULL)
12399 {
12400 /* didn't find it in this tabpage */
12401 nr = 0;
12402 break;
12403 }
12404 ++nr;
12405 }
12406 return nr;
12407}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012408
12409/*
12410 * "tabpagewinnr()" function
12411 */
12412 static void
12413f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12414{
12415 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012416 tabpage_T *tp;
12417
12418 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12419 if (tp == NULL)
12420 nr = 0;
12421 else
12422 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012423 rettv->vval.v_number = nr;
12424}
12425
12426
12427/*
12428 * "tagfiles()" function
12429 */
12430 static void
12431f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12432{
12433 char_u *fname;
12434 tagname_T tn;
12435 int first;
12436
12437 if (rettv_list_alloc(rettv) == FAIL)
12438 return;
12439 fname = alloc(MAXPATHL);
12440 if (fname == NULL)
12441 return;
12442
12443 for (first = TRUE; ; first = FALSE)
12444 if (get_tagfname(&tn, first, fname) == FAIL
12445 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12446 break;
12447 tagname_free(&tn);
12448 vim_free(fname);
12449}
12450
12451/*
12452 * "taglist()" function
12453 */
12454 static void
12455f_taglist(typval_T *argvars, typval_T *rettv)
12456{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012457 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012458 char_u *tag_pattern;
12459
12460 tag_pattern = get_tv_string(&argvars[0]);
12461
12462 rettv->vval.v_number = FALSE;
12463 if (*tag_pattern == NUL)
12464 return;
12465
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012466 if (argvars[1].v_type != VAR_UNKNOWN)
12467 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012468 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012469 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012470}
12471
12472/*
12473 * "tempname()" function
12474 */
12475 static void
12476f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12477{
12478 static int x = 'A';
12479
12480 rettv->v_type = VAR_STRING;
12481 rettv->vval.v_string = vim_tempname(x, FALSE);
12482
12483 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12484 * names. Skip 'I' and 'O', they are used for shell redirection. */
12485 do
12486 {
12487 if (x == 'Z')
12488 x = '0';
12489 else if (x == '9')
12490 x = 'A';
12491 else
12492 {
12493#ifdef EBCDIC
12494 if (x == 'I')
12495 x = 'J';
12496 else if (x == 'R')
12497 x = 'S';
12498 else
12499#endif
12500 ++x;
12501 }
12502 } while (x == 'I' || x == 'O');
12503}
12504
12505#ifdef FEAT_FLOAT
12506/*
12507 * "tan()" function
12508 */
12509 static void
12510f_tan(typval_T *argvars, typval_T *rettv)
12511{
12512 float_T f = 0.0;
12513
12514 rettv->v_type = VAR_FLOAT;
12515 if (get_float_arg(argvars, &f) == OK)
12516 rettv->vval.v_float = tan(f);
12517 else
12518 rettv->vval.v_float = 0.0;
12519}
12520
12521/*
12522 * "tanh()" function
12523 */
12524 static void
12525f_tanh(typval_T *argvars, typval_T *rettv)
12526{
12527 float_T f = 0.0;
12528
12529 rettv->v_type = VAR_FLOAT;
12530 if (get_float_arg(argvars, &f) == OK)
12531 rettv->vval.v_float = tanh(f);
12532 else
12533 rettv->vval.v_float = 0.0;
12534}
12535#endif
12536
12537/*
12538 * "test_alloc_fail(id, countdown, repeat)" function
12539 */
12540 static void
12541f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12542{
12543 if (argvars[0].v_type != VAR_NUMBER
12544 || argvars[0].vval.v_number <= 0
12545 || argvars[1].v_type != VAR_NUMBER
12546 || argvars[1].vval.v_number < 0
12547 || argvars[2].v_type != VAR_NUMBER)
12548 EMSG(_(e_invarg));
12549 else
12550 {
12551 alloc_fail_id = argvars[0].vval.v_number;
12552 if (alloc_fail_id >= aid_last)
12553 EMSG(_(e_invarg));
12554 alloc_fail_countdown = argvars[1].vval.v_number;
12555 alloc_fail_repeat = argvars[2].vval.v_number;
12556 did_outofmem_msg = FALSE;
12557 }
12558}
12559
12560/*
12561 * "test_autochdir()"
12562 */
12563 static void
12564f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12565{
12566#if defined(FEAT_AUTOCHDIR)
12567 test_autochdir = TRUE;
12568#endif
12569}
12570
12571/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012572 * "test_feedinput()"
12573 */
12574 static void
12575f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12576{
12577#ifdef USE_INPUT_BUF
12578 char_u *val = get_tv_string_chk(&argvars[0]);
12579
12580 if (val != NULL)
12581 {
12582 trash_input_buf();
12583 add_to_input_buf_csi(val, (int)STRLEN(val));
12584 }
12585#endif
12586}
12587
12588/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012589 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012590 */
12591 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012592f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012593{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012594 char_u *name = (char_u *)"";
12595 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012596 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012597
12598 if (argvars[0].v_type != VAR_STRING
12599 || (argvars[1].v_type) != VAR_NUMBER)
12600 EMSG(_(e_invarg));
12601 else
12602 {
12603 name = get_tv_string_chk(&argvars[0]);
12604 val = (int)get_tv_number(&argvars[1]);
12605
12606 if (STRCMP(name, (char_u *)"redraw") == 0)
12607 disable_redraw_for_testing = val;
12608 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12609 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012610 else if (STRCMP(name, (char_u *)"starting") == 0)
12611 {
12612 if (val)
12613 {
12614 if (save_starting < 0)
12615 save_starting = starting;
12616 starting = 0;
12617 }
12618 else
12619 {
12620 starting = save_starting;
12621 save_starting = -1;
12622 }
12623 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012624 else if (STRCMP(name, (char_u *)"ALL") == 0)
12625 {
12626 disable_char_avail_for_testing = FALSE;
12627 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012628 if (save_starting >= 0)
12629 {
12630 starting = save_starting;
12631 save_starting = -1;
12632 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012633 }
12634 else
12635 EMSG2(_(e_invarg2), name);
12636 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012637}
12638
12639/*
12640 * "test_garbagecollect_now()" function
12641 */
12642 static void
12643f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12644{
12645 /* This is dangerous, any Lists and Dicts used internally may be freed
12646 * while still in use. */
12647 garbage_collect(TRUE);
12648}
12649
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012650/*
12651 * "test_ignore_error()" function
12652 */
12653 static void
12654f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12655{
12656 ignore_error_for_testing(get_tv_string(&argvars[0]));
12657}
12658
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012659#ifdef FEAT_JOB_CHANNEL
12660 static void
12661f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12662{
12663 rettv->v_type = VAR_CHANNEL;
12664 rettv->vval.v_channel = NULL;
12665}
12666#endif
12667
12668 static void
12669f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12670{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012671 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012672}
12673
12674#ifdef FEAT_JOB_CHANNEL
12675 static void
12676f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12677{
12678 rettv->v_type = VAR_JOB;
12679 rettv->vval.v_job = NULL;
12680}
12681#endif
12682
12683 static void
12684f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12685{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012686 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012687}
12688
12689 static void
12690f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12691{
12692 rettv->v_type = VAR_PARTIAL;
12693 rettv->vval.v_partial = NULL;
12694}
12695
12696 static void
12697f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12698{
12699 rettv->v_type = VAR_STRING;
12700 rettv->vval.v_string = NULL;
12701}
12702
12703 static void
12704f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12705{
12706 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12707}
12708
12709#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12710/*
12711 * Get a callback from "arg". It can be a Funcref or a function name.
12712 * When "arg" is zero return an empty string.
12713 * Return NULL for an invalid argument.
12714 */
12715 char_u *
12716get_callback(typval_T *arg, partial_T **pp)
12717{
12718 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12719 {
12720 *pp = arg->vval.v_partial;
12721 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012722 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012723 }
12724 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012725 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012726 {
12727 func_ref(arg->vval.v_string);
12728 return arg->vval.v_string;
12729 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012730 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12731 return (char_u *)"";
12732 EMSG(_("E921: Invalid callback argument"));
12733 return NULL;
12734}
12735
12736/*
12737 * Unref/free "callback" and "partial" retured by get_callback().
12738 */
12739 void
12740free_callback(char_u *callback, partial_T *partial)
12741{
12742 if (partial != NULL)
12743 partial_unref(partial);
12744 else if (callback != NULL)
12745 {
12746 func_unref(callback);
12747 vim_free(callback);
12748 }
12749}
12750#endif
12751
12752#ifdef FEAT_TIMERS
12753/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012754 * "timer_info([timer])" function
12755 */
12756 static void
12757f_timer_info(typval_T *argvars, typval_T *rettv)
12758{
12759 timer_T *timer = NULL;
12760
12761 if (rettv_list_alloc(rettv) != OK)
12762 return;
12763 if (argvars[0].v_type != VAR_UNKNOWN)
12764 {
12765 if (argvars[0].v_type != VAR_NUMBER)
12766 EMSG(_(e_number_exp));
12767 else
12768 {
12769 timer = find_timer((int)get_tv_number(&argvars[0]));
12770 if (timer != NULL)
12771 add_timer_info(rettv, timer);
12772 }
12773 }
12774 else
12775 add_timer_info_all(rettv);
12776}
12777
12778/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012779 * "timer_pause(timer, paused)" function
12780 */
12781 static void
12782f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12783{
12784 timer_T *timer = NULL;
12785 int paused = (int)get_tv_number(&argvars[1]);
12786
12787 if (argvars[0].v_type != VAR_NUMBER)
12788 EMSG(_(e_number_exp));
12789 else
12790 {
12791 timer = find_timer((int)get_tv_number(&argvars[0]));
12792 if (timer != NULL)
12793 timer->tr_paused = paused;
12794 }
12795}
12796
12797/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012798 * "timer_start(time, callback [, options])" function
12799 */
12800 static void
12801f_timer_start(typval_T *argvars, typval_T *rettv)
12802{
Bram Moolenaar75537a92016-09-05 22:45:28 +020012803 long msec = (long)get_tv_number(&argvars[0]);
12804 timer_T *timer;
12805 int repeat = 0;
12806 char_u *callback;
12807 dict_T *dict;
12808 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012809
Bram Moolenaar75537a92016-09-05 22:45:28 +020012810 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012811 if (check_secure())
12812 return;
12813 if (argvars[2].v_type != VAR_UNKNOWN)
12814 {
12815 if (argvars[2].v_type != VAR_DICT
12816 || (dict = argvars[2].vval.v_dict) == NULL)
12817 {
12818 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12819 return;
12820 }
12821 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12822 repeat = get_dict_number(dict, (char_u *)"repeat");
12823 }
12824
Bram Moolenaar75537a92016-09-05 22:45:28 +020012825 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012826 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012827 return;
12828
12829 timer = create_timer(msec, repeat);
12830 if (timer == NULL)
12831 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012832 else
12833 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020012834 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020012835 timer->tr_callback = vim_strsave(callback);
12836 else
12837 /* pointer into the partial */
12838 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012839 timer->tr_partial = partial;
12840 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012841 }
12842}
12843
12844/*
12845 * "timer_stop(timer)" function
12846 */
12847 static void
12848f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12849{
12850 timer_T *timer;
12851
12852 if (argvars[0].v_type != VAR_NUMBER)
12853 {
12854 EMSG(_(e_number_exp));
12855 return;
12856 }
12857 timer = find_timer((int)get_tv_number(&argvars[0]));
12858 if (timer != NULL)
12859 stop_timer(timer);
12860}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012861
12862/*
12863 * "timer_stopall()" function
12864 */
12865 static void
12866f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12867{
12868 stop_all_timers();
12869}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012870#endif
12871
12872/*
12873 * "tolower(string)" function
12874 */
12875 static void
12876f_tolower(typval_T *argvars, typval_T *rettv)
12877{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012878 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010012879 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012880}
12881
12882/*
12883 * "toupper(string)" function
12884 */
12885 static void
12886f_toupper(typval_T *argvars, typval_T *rettv)
12887{
12888 rettv->v_type = VAR_STRING;
12889 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12890}
12891
12892/*
12893 * "tr(string, fromstr, tostr)" function
12894 */
12895 static void
12896f_tr(typval_T *argvars, typval_T *rettv)
12897{
12898 char_u *in_str;
12899 char_u *fromstr;
12900 char_u *tostr;
12901 char_u *p;
12902#ifdef FEAT_MBYTE
12903 int inlen;
12904 int fromlen;
12905 int tolen;
12906 int idx;
12907 char_u *cpstr;
12908 int cplen;
12909 int first = TRUE;
12910#endif
12911 char_u buf[NUMBUFLEN];
12912 char_u buf2[NUMBUFLEN];
12913 garray_T ga;
12914
12915 in_str = get_tv_string(&argvars[0]);
12916 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12917 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12918
12919 /* Default return value: empty string. */
12920 rettv->v_type = VAR_STRING;
12921 rettv->vval.v_string = NULL;
12922 if (fromstr == NULL || tostr == NULL)
12923 return; /* type error; errmsg already given */
12924 ga_init2(&ga, (int)sizeof(char), 80);
12925
12926#ifdef FEAT_MBYTE
12927 if (!has_mbyte)
12928#endif
12929 /* not multi-byte: fromstr and tostr must be the same length */
12930 if (STRLEN(fromstr) != STRLEN(tostr))
12931 {
12932#ifdef FEAT_MBYTE
12933error:
12934#endif
12935 EMSG2(_(e_invarg2), fromstr);
12936 ga_clear(&ga);
12937 return;
12938 }
12939
12940 /* fromstr and tostr have to contain the same number of chars */
12941 while (*in_str != NUL)
12942 {
12943#ifdef FEAT_MBYTE
12944 if (has_mbyte)
12945 {
12946 inlen = (*mb_ptr2len)(in_str);
12947 cpstr = in_str;
12948 cplen = inlen;
12949 idx = 0;
12950 for (p = fromstr; *p != NUL; p += fromlen)
12951 {
12952 fromlen = (*mb_ptr2len)(p);
12953 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12954 {
12955 for (p = tostr; *p != NUL; p += tolen)
12956 {
12957 tolen = (*mb_ptr2len)(p);
12958 if (idx-- == 0)
12959 {
12960 cplen = tolen;
12961 cpstr = p;
12962 break;
12963 }
12964 }
12965 if (*p == NUL) /* tostr is shorter than fromstr */
12966 goto error;
12967 break;
12968 }
12969 ++idx;
12970 }
12971
12972 if (first && cpstr == in_str)
12973 {
12974 /* Check that fromstr and tostr have the same number of
12975 * (multi-byte) characters. Done only once when a character
12976 * of in_str doesn't appear in fromstr. */
12977 first = FALSE;
12978 for (p = tostr; *p != NUL; p += tolen)
12979 {
12980 tolen = (*mb_ptr2len)(p);
12981 --idx;
12982 }
12983 if (idx != 0)
12984 goto error;
12985 }
12986
12987 (void)ga_grow(&ga, cplen);
12988 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12989 ga.ga_len += cplen;
12990
12991 in_str += inlen;
12992 }
12993 else
12994#endif
12995 {
12996 /* When not using multi-byte chars we can do it faster. */
12997 p = vim_strchr(fromstr, *in_str);
12998 if (p != NULL)
12999 ga_append(&ga, tostr[p - fromstr]);
13000 else
13001 ga_append(&ga, *in_str);
13002 ++in_str;
13003 }
13004 }
13005
13006 /* add a terminating NUL */
13007 (void)ga_grow(&ga, 1);
13008 ga_append(&ga, NUL);
13009
13010 rettv->vval.v_string = ga.ga_data;
13011}
13012
13013#ifdef FEAT_FLOAT
13014/*
13015 * "trunc({float})" function
13016 */
13017 static void
13018f_trunc(typval_T *argvars, typval_T *rettv)
13019{
13020 float_T f = 0.0;
13021
13022 rettv->v_type = VAR_FLOAT;
13023 if (get_float_arg(argvars, &f) == OK)
13024 /* trunc() is not in C90, use floor() or ceil() instead. */
13025 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13026 else
13027 rettv->vval.v_float = 0.0;
13028}
13029#endif
13030
13031/*
13032 * "type(expr)" function
13033 */
13034 static void
13035f_type(typval_T *argvars, typval_T *rettv)
13036{
13037 int n = -1;
13038
13039 switch (argvars[0].v_type)
13040 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013041 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13042 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013043 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013044 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13045 case VAR_LIST: n = VAR_TYPE_LIST; break;
13046 case VAR_DICT: n = VAR_TYPE_DICT; break;
13047 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013048 case VAR_SPECIAL:
13049 if (argvars[0].vval.v_number == VVAL_FALSE
13050 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013051 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013052 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013053 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013054 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013055 case VAR_JOB: n = VAR_TYPE_JOB; break;
13056 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013057 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013058 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013059 n = -1;
13060 break;
13061 }
13062 rettv->vval.v_number = n;
13063}
13064
13065/*
13066 * "undofile(name)" function
13067 */
13068 static void
13069f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13070{
13071 rettv->v_type = VAR_STRING;
13072#ifdef FEAT_PERSISTENT_UNDO
13073 {
13074 char_u *fname = get_tv_string(&argvars[0]);
13075
13076 if (*fname == NUL)
13077 {
13078 /* If there is no file name there will be no undo file. */
13079 rettv->vval.v_string = NULL;
13080 }
13081 else
13082 {
13083 char_u *ffname = FullName_save(fname, FALSE);
13084
13085 if (ffname != NULL)
13086 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13087 vim_free(ffname);
13088 }
13089 }
13090#else
13091 rettv->vval.v_string = NULL;
13092#endif
13093}
13094
13095/*
13096 * "undotree()" function
13097 */
13098 static void
13099f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13100{
13101 if (rettv_dict_alloc(rettv) == OK)
13102 {
13103 dict_T *dict = rettv->vval.v_dict;
13104 list_T *list;
13105
13106 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13107 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13108 dict_add_nr_str(dict, "save_last",
13109 (long)curbuf->b_u_save_nr_last, NULL);
13110 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13111 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13112 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13113
13114 list = list_alloc();
13115 if (list != NULL)
13116 {
13117 u_eval_tree(curbuf->b_u_oldhead, list);
13118 dict_add_list(dict, "entries", list);
13119 }
13120 }
13121}
13122
13123/*
13124 * "values(dict)" function
13125 */
13126 static void
13127f_values(typval_T *argvars, typval_T *rettv)
13128{
13129 dict_list(argvars, rettv, 1);
13130}
13131
13132/*
13133 * "virtcol(string)" function
13134 */
13135 static void
13136f_virtcol(typval_T *argvars, typval_T *rettv)
13137{
13138 colnr_T vcol = 0;
13139 pos_T *fp;
13140 int fnum = curbuf->b_fnum;
13141
13142 fp = var2fpos(&argvars[0], FALSE, &fnum);
13143 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13144 && fnum == curbuf->b_fnum)
13145 {
13146 getvvcol(curwin, fp, NULL, NULL, &vcol);
13147 ++vcol;
13148 }
13149
13150 rettv->vval.v_number = vcol;
13151}
13152
13153/*
13154 * "visualmode()" function
13155 */
13156 static void
13157f_visualmode(typval_T *argvars, typval_T *rettv)
13158{
13159 char_u str[2];
13160
13161 rettv->v_type = VAR_STRING;
13162 str[0] = curbuf->b_visual_mode_eval;
13163 str[1] = NUL;
13164 rettv->vval.v_string = vim_strsave(str);
13165
13166 /* A non-zero number or non-empty string argument: reset mode. */
13167 if (non_zero_arg(&argvars[0]))
13168 curbuf->b_visual_mode_eval = NUL;
13169}
13170
13171/*
13172 * "wildmenumode()" function
13173 */
13174 static void
13175f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13176{
13177#ifdef FEAT_WILDMENU
13178 if (wild_menu_showing)
13179 rettv->vval.v_number = 1;
13180#endif
13181}
13182
13183/*
13184 * "winbufnr(nr)" function
13185 */
13186 static void
13187f_winbufnr(typval_T *argvars, typval_T *rettv)
13188{
13189 win_T *wp;
13190
13191 wp = find_win_by_nr(&argvars[0], NULL);
13192 if (wp == NULL)
13193 rettv->vval.v_number = -1;
13194 else
13195 rettv->vval.v_number = wp->w_buffer->b_fnum;
13196}
13197
13198/*
13199 * "wincol()" function
13200 */
13201 static void
13202f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13203{
13204 validate_cursor();
13205 rettv->vval.v_number = curwin->w_wcol + 1;
13206}
13207
13208/*
13209 * "winheight(nr)" function
13210 */
13211 static void
13212f_winheight(typval_T *argvars, typval_T *rettv)
13213{
13214 win_T *wp;
13215
13216 wp = find_win_by_nr(&argvars[0], NULL);
13217 if (wp == NULL)
13218 rettv->vval.v_number = -1;
13219 else
13220 rettv->vval.v_number = wp->w_height;
13221}
13222
13223/*
13224 * "winline()" function
13225 */
13226 static void
13227f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13228{
13229 validate_cursor();
13230 rettv->vval.v_number = curwin->w_wrow + 1;
13231}
13232
13233/*
13234 * "winnr()" function
13235 */
13236 static void
13237f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13238{
13239 int nr = 1;
13240
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013241 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013242 rettv->vval.v_number = nr;
13243}
13244
13245/*
13246 * "winrestcmd()" function
13247 */
13248 static void
13249f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13250{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013251 win_T *wp;
13252 int winnr = 1;
13253 garray_T ga;
13254 char_u buf[50];
13255
13256 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013257 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013258 {
13259 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13260 ga_concat(&ga, buf);
13261 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13262 ga_concat(&ga, buf);
13263 ++winnr;
13264 }
13265 ga_append(&ga, NUL);
13266
13267 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013268 rettv->v_type = VAR_STRING;
13269}
13270
13271/*
13272 * "winrestview()" function
13273 */
13274 static void
13275f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13276{
13277 dict_T *dict;
13278
13279 if (argvars[0].v_type != VAR_DICT
13280 || (dict = argvars[0].vval.v_dict) == NULL)
13281 EMSG(_(e_invarg));
13282 else
13283 {
13284 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13285 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13286 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13287 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13288#ifdef FEAT_VIRTUALEDIT
13289 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13290 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13291#endif
13292 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13293 {
13294 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13295 curwin->w_set_curswant = FALSE;
13296 }
13297
13298 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13299 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13300#ifdef FEAT_DIFF
13301 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13302 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13303#endif
13304 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13305 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13306 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13307 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13308
13309 check_cursor();
13310 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013311 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013312 changed_window_setting();
13313
13314 if (curwin->w_topline <= 0)
13315 curwin->w_topline = 1;
13316 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13317 curwin->w_topline = curbuf->b_ml.ml_line_count;
13318#ifdef FEAT_DIFF
13319 check_topfill(curwin, TRUE);
13320#endif
13321 }
13322}
13323
13324/*
13325 * "winsaveview()" function
13326 */
13327 static void
13328f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13329{
13330 dict_T *dict;
13331
13332 if (rettv_dict_alloc(rettv) == FAIL)
13333 return;
13334 dict = rettv->vval.v_dict;
13335
13336 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13337 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13338#ifdef FEAT_VIRTUALEDIT
13339 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13340#endif
13341 update_curswant();
13342 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13343
13344 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13345#ifdef FEAT_DIFF
13346 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13347#endif
13348 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13349 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13350}
13351
13352/*
13353 * "winwidth(nr)" function
13354 */
13355 static void
13356f_winwidth(typval_T *argvars, typval_T *rettv)
13357{
13358 win_T *wp;
13359
13360 wp = find_win_by_nr(&argvars[0], NULL);
13361 if (wp == NULL)
13362 rettv->vval.v_number = -1;
13363 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013364 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013365}
13366
13367/*
13368 * "wordcount()" function
13369 */
13370 static void
13371f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13372{
13373 if (rettv_dict_alloc(rettv) == FAIL)
13374 return;
13375 cursor_pos_info(rettv->vval.v_dict);
13376}
13377
13378/*
13379 * "writefile()" function
13380 */
13381 static void
13382f_writefile(typval_T *argvars, typval_T *rettv)
13383{
13384 int binary = FALSE;
13385 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013386#ifdef HAVE_FSYNC
13387 int do_fsync = p_fs;
13388#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013389 char_u *fname;
13390 FILE *fd;
13391 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013392 listitem_T *li;
13393 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013394
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013395 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013396 if (check_restricted() || check_secure())
13397 return;
13398
13399 if (argvars[0].v_type != VAR_LIST)
13400 {
13401 EMSG2(_(e_listarg), "writefile()");
13402 return;
13403 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013404 list = argvars[0].vval.v_list;
13405 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013406 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013407 for (li = list->lv_first; li != NULL; li = li->li_next)
13408 if (get_tv_string_chk(&li->li_tv) == NULL)
13409 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013410
13411 if (argvars[2].v_type != VAR_UNKNOWN)
13412 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013413 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13414
13415 if (arg2 == NULL)
13416 return;
13417 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013418 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013419 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013420 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013421#ifdef HAVE_FSYNC
13422 if (vim_strchr(arg2, 's') != NULL)
13423 do_fsync = TRUE;
13424 else if (vim_strchr(arg2, 'S') != NULL)
13425 do_fsync = FALSE;
13426#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013427 }
13428
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013429 fname = get_tv_string_chk(&argvars[1]);
13430 if (fname == NULL)
13431 return;
13432
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013433 /* Always open the file in binary mode, library functions have a mind of
13434 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013435 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13436 append ? APPENDBIN : WRITEBIN)) == NULL)
13437 {
13438 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13439 ret = -1;
13440 }
13441 else
13442 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013443 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013444 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013445#ifdef HAVE_FSYNC
13446 else if (do_fsync && fsync(fileno(fd)) != 0)
13447 EMSG(_(e_fsync));
13448#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013449 fclose(fd);
13450 }
13451
13452 rettv->vval.v_number = ret;
13453}
13454
13455/*
13456 * "xor(expr, expr)" function
13457 */
13458 static void
13459f_xor(typval_T *argvars, typval_T *rettv)
13460{
13461 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13462 ^ get_tv_number_chk(&argvars[1], NULL);
13463}
13464
13465
13466#endif /* FEAT_EVAL */