blob: f09be92af4dfcbdce7e3bec34533198b146a538f [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 Moolenaar669a8282017-11-19 20:13:05 +010064# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010065static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010066# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010067#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020068static void f_browse(typval_T *argvars, typval_T *rettv);
69static void f_browsedir(typval_T *argvars, typval_T *rettv);
70static void f_bufexists(typval_T *argvars, typval_T *rettv);
71static void f_buflisted(typval_T *argvars, typval_T *rettv);
72static void f_bufloaded(typval_T *argvars, typval_T *rettv);
73static void f_bufname(typval_T *argvars, typval_T *rettv);
74static void f_bufnr(typval_T *argvars, typval_T *rettv);
75static void f_bufwinid(typval_T *argvars, typval_T *rettv);
76static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
77static void f_byte2line(typval_T *argvars, typval_T *rettv);
78static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
79static void f_byteidx(typval_T *argvars, typval_T *rettv);
80static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
81static void f_call(typval_T *argvars, typval_T *rettv);
82#ifdef FEAT_FLOAT
83static void f_ceil(typval_T *argvars, typval_T *rettv);
84#endif
85#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010086static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020087static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020088static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
90static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
91static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
92static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
93static void f_ch_info(typval_T *argvars, typval_T *rettv);
94static void f_ch_log(typval_T *argvars, typval_T *rettv);
95static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
96static void f_ch_open(typval_T *argvars, typval_T *rettv);
97static void f_ch_read(typval_T *argvars, typval_T *rettv);
98static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
99static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
100static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
101static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
102static void f_ch_status(typval_T *argvars, typval_T *rettv);
103#endif
104static void f_changenr(typval_T *argvars, typval_T *rettv);
105static void f_char2nr(typval_T *argvars, typval_T *rettv);
106static void f_cindent(typval_T *argvars, typval_T *rettv);
107static void f_clearmatches(typval_T *argvars, typval_T *rettv);
108static void f_col(typval_T *argvars, typval_T *rettv);
109#if defined(FEAT_INS_EXPAND)
110static void f_complete(typval_T *argvars, typval_T *rettv);
111static void f_complete_add(typval_T *argvars, typval_T *rettv);
112static void f_complete_check(typval_T *argvars, typval_T *rettv);
113#endif
114static void f_confirm(typval_T *argvars, typval_T *rettv);
115static void f_copy(typval_T *argvars, typval_T *rettv);
116#ifdef FEAT_FLOAT
117static void f_cos(typval_T *argvars, typval_T *rettv);
118static void f_cosh(typval_T *argvars, typval_T *rettv);
119#endif
120static void f_count(typval_T *argvars, typval_T *rettv);
121static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
122static void f_cursor(typval_T *argsvars, typval_T *rettv);
123static void f_deepcopy(typval_T *argvars, typval_T *rettv);
124static void f_delete(typval_T *argvars, typval_T *rettv);
125static void f_did_filetype(typval_T *argvars, typval_T *rettv);
126static void f_diff_filler(typval_T *argvars, typval_T *rettv);
127static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
128static void f_empty(typval_T *argvars, typval_T *rettv);
129static void f_escape(typval_T *argvars, typval_T *rettv);
130static void f_eval(typval_T *argvars, typval_T *rettv);
131static void f_eventhandler(typval_T *argvars, typval_T *rettv);
132static void f_executable(typval_T *argvars, typval_T *rettv);
133static void f_execute(typval_T *argvars, typval_T *rettv);
134static void f_exepath(typval_T *argvars, typval_T *rettv);
135static void f_exists(typval_T *argvars, typval_T *rettv);
136#ifdef FEAT_FLOAT
137static void f_exp(typval_T *argvars, typval_T *rettv);
138#endif
139static void f_expand(typval_T *argvars, typval_T *rettv);
140static void f_extend(typval_T *argvars, typval_T *rettv);
141static void f_feedkeys(typval_T *argvars, typval_T *rettv);
142static void f_filereadable(typval_T *argvars, typval_T *rettv);
143static void f_filewritable(typval_T *argvars, typval_T *rettv);
144static void f_filter(typval_T *argvars, typval_T *rettv);
145static void f_finddir(typval_T *argvars, typval_T *rettv);
146static void f_findfile(typval_T *argvars, typval_T *rettv);
147#ifdef FEAT_FLOAT
148static void f_float2nr(typval_T *argvars, typval_T *rettv);
149static void f_floor(typval_T *argvars, typval_T *rettv);
150static void f_fmod(typval_T *argvars, typval_T *rettv);
151#endif
152static void f_fnameescape(typval_T *argvars, typval_T *rettv);
153static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
154static void f_foldclosed(typval_T *argvars, typval_T *rettv);
155static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
156static void f_foldlevel(typval_T *argvars, typval_T *rettv);
157static void f_foldtext(typval_T *argvars, typval_T *rettv);
158static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
159static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200160static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200161static void f_function(typval_T *argvars, typval_T *rettv);
162static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
163static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200164static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_getbufline(typval_T *argvars, typval_T *rettv);
166static void f_getbufvar(typval_T *argvars, typval_T *rettv);
167static void f_getchar(typval_T *argvars, typval_T *rettv);
168static void f_getcharmod(typval_T *argvars, typval_T *rettv);
169static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
170static void f_getcmdline(typval_T *argvars, typval_T *rettv);
171#if defined(FEAT_CMDL_COMPL)
172static void f_getcompletion(typval_T *argvars, typval_T *rettv);
173#endif
174static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
175static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
176static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
177static void f_getcwd(typval_T *argvars, typval_T *rettv);
178static void f_getfontname(typval_T *argvars, typval_T *rettv);
179static void f_getfperm(typval_T *argvars, typval_T *rettv);
180static void f_getfsize(typval_T *argvars, typval_T *rettv);
181static void f_getftime(typval_T *argvars, typval_T *rettv);
182static void f_getftype(typval_T *argvars, typval_T *rettv);
183static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200184static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_getmatches(typval_T *argvars, typval_T *rettv);
186static void f_getpid(typval_T *argvars, typval_T *rettv);
187static void f_getcurpos(typval_T *argvars, typval_T *rettv);
188static void f_getpos(typval_T *argvars, typval_T *rettv);
189static void f_getqflist(typval_T *argvars, typval_T *rettv);
190static void f_getreg(typval_T *argvars, typval_T *rettv);
191static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200192static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_gettabvar(typval_T *argvars, typval_T *rettv);
194static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200195static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_getwinposx(typval_T *argvars, typval_T *rettv);
197static void f_getwinposy(typval_T *argvars, typval_T *rettv);
198static void f_getwinvar(typval_T *argvars, typval_T *rettv);
199static void f_glob(typval_T *argvars, typval_T *rettv);
200static void f_globpath(typval_T *argvars, typval_T *rettv);
201static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
202static void f_has(typval_T *argvars, typval_T *rettv);
203static void f_has_key(typval_T *argvars, typval_T *rettv);
204static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
205static void f_hasmapto(typval_T *argvars, typval_T *rettv);
206static void f_histadd(typval_T *argvars, typval_T *rettv);
207static void f_histdel(typval_T *argvars, typval_T *rettv);
208static void f_histget(typval_T *argvars, typval_T *rettv);
209static void f_histnr(typval_T *argvars, typval_T *rettv);
210static void f_hlID(typval_T *argvars, typval_T *rettv);
211static void f_hlexists(typval_T *argvars, typval_T *rettv);
212static void f_hostname(typval_T *argvars, typval_T *rettv);
213static void f_iconv(typval_T *argvars, typval_T *rettv);
214static void f_indent(typval_T *argvars, typval_T *rettv);
215static void f_index(typval_T *argvars, typval_T *rettv);
216static void f_input(typval_T *argvars, typval_T *rettv);
217static void f_inputdialog(typval_T *argvars, typval_T *rettv);
218static void f_inputlist(typval_T *argvars, typval_T *rettv);
219static void f_inputrestore(typval_T *argvars, typval_T *rettv);
220static void f_inputsave(typval_T *argvars, typval_T *rettv);
221static void f_inputsecret(typval_T *argvars, typval_T *rettv);
222static void f_insert(typval_T *argvars, typval_T *rettv);
223static void f_invert(typval_T *argvars, typval_T *rettv);
224static void f_isdirectory(typval_T *argvars, typval_T *rettv);
225static void f_islocked(typval_T *argvars, typval_T *rettv);
226#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
227static void f_isnan(typval_T *argvars, typval_T *rettv);
228#endif
229static void f_items(typval_T *argvars, typval_T *rettv);
230#ifdef FEAT_JOB_CHANNEL
231static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
232static void f_job_info(typval_T *argvars, typval_T *rettv);
233static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
234static void f_job_start(typval_T *argvars, typval_T *rettv);
235static void f_job_stop(typval_T *argvars, typval_T *rettv);
236static void f_job_status(typval_T *argvars, typval_T *rettv);
237#endif
238static void f_join(typval_T *argvars, typval_T *rettv);
239static void f_js_decode(typval_T *argvars, typval_T *rettv);
240static void f_js_encode(typval_T *argvars, typval_T *rettv);
241static void f_json_decode(typval_T *argvars, typval_T *rettv);
242static void f_json_encode(typval_T *argvars, typval_T *rettv);
243static void f_keys(typval_T *argvars, typval_T *rettv);
244static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
245static void f_len(typval_T *argvars, typval_T *rettv);
246static void f_libcall(typval_T *argvars, typval_T *rettv);
247static void f_libcallnr(typval_T *argvars, typval_T *rettv);
248static void f_line(typval_T *argvars, typval_T *rettv);
249static void f_line2byte(typval_T *argvars, typval_T *rettv);
250static void f_lispindent(typval_T *argvars, typval_T *rettv);
251static void f_localtime(typval_T *argvars, typval_T *rettv);
252#ifdef FEAT_FLOAT
253static void f_log(typval_T *argvars, typval_T *rettv);
254static void f_log10(typval_T *argvars, typval_T *rettv);
255#endif
256#ifdef FEAT_LUA
257static void f_luaeval(typval_T *argvars, typval_T *rettv);
258#endif
259static void f_map(typval_T *argvars, typval_T *rettv);
260static void f_maparg(typval_T *argvars, typval_T *rettv);
261static void f_mapcheck(typval_T *argvars, typval_T *rettv);
262static void f_match(typval_T *argvars, typval_T *rettv);
263static void f_matchadd(typval_T *argvars, typval_T *rettv);
264static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
265static void f_matcharg(typval_T *argvars, typval_T *rettv);
266static void f_matchdelete(typval_T *argvars, typval_T *rettv);
267static void f_matchend(typval_T *argvars, typval_T *rettv);
268static void f_matchlist(typval_T *argvars, typval_T *rettv);
269static void f_matchstr(typval_T *argvars, typval_T *rettv);
270static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
271static void f_max(typval_T *argvars, typval_T *rettv);
272static void f_min(typval_T *argvars, typval_T *rettv);
273#ifdef vim_mkdir
274static void f_mkdir(typval_T *argvars, typval_T *rettv);
275#endif
276static void f_mode(typval_T *argvars, typval_T *rettv);
277#ifdef FEAT_MZSCHEME
278static void f_mzeval(typval_T *argvars, typval_T *rettv);
279#endif
280static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
281static void f_nr2char(typval_T *argvars, typval_T *rettv);
282static void f_or(typval_T *argvars, typval_T *rettv);
283static void f_pathshorten(typval_T *argvars, typval_T *rettv);
284#ifdef FEAT_PERL
285static void f_perleval(typval_T *argvars, typval_T *rettv);
286#endif
287#ifdef FEAT_FLOAT
288static void f_pow(typval_T *argvars, typval_T *rettv);
289#endif
290static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
291static void f_printf(typval_T *argvars, typval_T *rettv);
292static void f_pumvisible(typval_T *argvars, typval_T *rettv);
293#ifdef FEAT_PYTHON3
294static void f_py3eval(typval_T *argvars, typval_T *rettv);
295#endif
296#ifdef FEAT_PYTHON
297static void f_pyeval(typval_T *argvars, typval_T *rettv);
298#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100299#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
300static void f_pyxeval(typval_T *argvars, typval_T *rettv);
301#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_range(typval_T *argvars, typval_T *rettv);
303static void f_readfile(typval_T *argvars, typval_T *rettv);
304static void f_reltime(typval_T *argvars, typval_T *rettv);
305#ifdef FEAT_FLOAT
306static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
307#endif
308static void f_reltimestr(typval_T *argvars, typval_T *rettv);
309static void f_remote_expr(typval_T *argvars, typval_T *rettv);
310static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
311static void f_remote_peek(typval_T *argvars, typval_T *rettv);
312static void f_remote_read(typval_T *argvars, typval_T *rettv);
313static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100314static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315static void f_remove(typval_T *argvars, typval_T *rettv);
316static void f_rename(typval_T *argvars, typval_T *rettv);
317static void f_repeat(typval_T *argvars, typval_T *rettv);
318static void f_resolve(typval_T *argvars, typval_T *rettv);
319static void f_reverse(typval_T *argvars, typval_T *rettv);
320#ifdef FEAT_FLOAT
321static void f_round(typval_T *argvars, typval_T *rettv);
322#endif
323static void f_screenattr(typval_T *argvars, typval_T *rettv);
324static void f_screenchar(typval_T *argvars, typval_T *rettv);
325static void f_screencol(typval_T *argvars, typval_T *rettv);
326static void f_screenrow(typval_T *argvars, typval_T *rettv);
327static void f_search(typval_T *argvars, typval_T *rettv);
328static void f_searchdecl(typval_T *argvars, typval_T *rettv);
329static void f_searchpair(typval_T *argvars, typval_T *rettv);
330static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
331static void f_searchpos(typval_T *argvars, typval_T *rettv);
332static void f_server2client(typval_T *argvars, typval_T *rettv);
333static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200334static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200335static void f_setbufvar(typval_T *argvars, typval_T *rettv);
336static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
337static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
338static void f_setfperm(typval_T *argvars, typval_T *rettv);
339static void f_setline(typval_T *argvars, typval_T *rettv);
340static void f_setloclist(typval_T *argvars, typval_T *rettv);
341static void f_setmatches(typval_T *argvars, typval_T *rettv);
342static void f_setpos(typval_T *argvars, typval_T *rettv);
343static void f_setqflist(typval_T *argvars, typval_T *rettv);
344static void f_setreg(typval_T *argvars, typval_T *rettv);
345static void f_settabvar(typval_T *argvars, typval_T *rettv);
346static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
347static void f_setwinvar(typval_T *argvars, typval_T *rettv);
348#ifdef FEAT_CRYPT
349static void f_sha256(typval_T *argvars, typval_T *rettv);
350#endif /* FEAT_CRYPT */
351static void f_shellescape(typval_T *argvars, typval_T *rettv);
352static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
353static void f_simplify(typval_T *argvars, typval_T *rettv);
354#ifdef FEAT_FLOAT
355static void f_sin(typval_T *argvars, typval_T *rettv);
356static void f_sinh(typval_T *argvars, typval_T *rettv);
357#endif
358static void f_sort(typval_T *argvars, typval_T *rettv);
359static void f_soundfold(typval_T *argvars, typval_T *rettv);
360static void f_spellbadword(typval_T *argvars, typval_T *rettv);
361static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
362static void f_split(typval_T *argvars, typval_T *rettv);
363#ifdef FEAT_FLOAT
364static void f_sqrt(typval_T *argvars, typval_T *rettv);
365static void f_str2float(typval_T *argvars, typval_T *rettv);
366#endif
367static void f_str2nr(typval_T *argvars, typval_T *rettv);
368static void f_strchars(typval_T *argvars, typval_T *rettv);
369#ifdef HAVE_STRFTIME
370static void f_strftime(typval_T *argvars, typval_T *rettv);
371#endif
372static void f_strgetchar(typval_T *argvars, typval_T *rettv);
373static void f_stridx(typval_T *argvars, typval_T *rettv);
374static void f_string(typval_T *argvars, typval_T *rettv);
375static void f_strlen(typval_T *argvars, typval_T *rettv);
376static void f_strcharpart(typval_T *argvars, typval_T *rettv);
377static void f_strpart(typval_T *argvars, typval_T *rettv);
378static void f_strridx(typval_T *argvars, typval_T *rettv);
379static void f_strtrans(typval_T *argvars, typval_T *rettv);
380static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
381static void f_strwidth(typval_T *argvars, typval_T *rettv);
382static void f_submatch(typval_T *argvars, typval_T *rettv);
383static void f_substitute(typval_T *argvars, typval_T *rettv);
384static void f_synID(typval_T *argvars, typval_T *rettv);
385static void f_synIDattr(typval_T *argvars, typval_T *rettv);
386static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
387static void f_synstack(typval_T *argvars, typval_T *rettv);
388static void f_synconcealed(typval_T *argvars, typval_T *rettv);
389static void f_system(typval_T *argvars, typval_T *rettv);
390static void f_systemlist(typval_T *argvars, typval_T *rettv);
391static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
392static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
393static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
394static void f_taglist(typval_T *argvars, typval_T *rettv);
395static void f_tagfiles(typval_T *argvars, typval_T *rettv);
396static void f_tempname(typval_T *argvars, typval_T *rettv);
397static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
398static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200399static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100400static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100402static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200403#ifdef FEAT_JOB_CHANNEL
404static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
405#endif
406static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
407#ifdef FEAT_JOB_CHANNEL
408static void f_test_null_job(typval_T *argvars, typval_T *rettv);
409#endif
410static void f_test_null_list(typval_T *argvars, typval_T *rettv);
411static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
412static void f_test_null_string(typval_T *argvars, typval_T *rettv);
413static void f_test_settime(typval_T *argvars, typval_T *rettv);
414#ifdef FEAT_FLOAT
415static void f_tan(typval_T *argvars, typval_T *rettv);
416static void f_tanh(typval_T *argvars, typval_T *rettv);
417#endif
418#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200419static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200420static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421static void f_timer_start(typval_T *argvars, typval_T *rettv);
422static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200423static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200424#endif
425static void f_tolower(typval_T *argvars, typval_T *rettv);
426static void f_toupper(typval_T *argvars, typval_T *rettv);
427static void f_tr(typval_T *argvars, typval_T *rettv);
428#ifdef FEAT_FLOAT
429static void f_trunc(typval_T *argvars, typval_T *rettv);
430#endif
431static void f_type(typval_T *argvars, typval_T *rettv);
432static void f_undofile(typval_T *argvars, typval_T *rettv);
433static void f_undotree(typval_T *argvars, typval_T *rettv);
434static void f_uniq(typval_T *argvars, typval_T *rettv);
435static void f_values(typval_T *argvars, typval_T *rettv);
436static void f_virtcol(typval_T *argvars, typval_T *rettv);
437static void f_visualmode(typval_T *argvars, typval_T *rettv);
438static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
439static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
440static void f_win_getid(typval_T *argvars, typval_T *rettv);
441static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
442static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
443static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100444static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200445static void f_winbufnr(typval_T *argvars, typval_T *rettv);
446static void f_wincol(typval_T *argvars, typval_T *rettv);
447static void f_winheight(typval_T *argvars, typval_T *rettv);
448static void f_winline(typval_T *argvars, typval_T *rettv);
449static void f_winnr(typval_T *argvars, typval_T *rettv);
450static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
451static void f_winrestview(typval_T *argvars, typval_T *rettv);
452static void f_winsaveview(typval_T *argvars, typval_T *rettv);
453static void f_winwidth(typval_T *argvars, typval_T *rettv);
454static void f_writefile(typval_T *argvars, typval_T *rettv);
455static void f_wordcount(typval_T *argvars, typval_T *rettv);
456static void f_xor(typval_T *argvars, typval_T *rettv);
457
458/*
459 * Array with names and number of arguments of all internal functions
460 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
461 */
462static struct fst
463{
464 char *f_name; /* function name */
465 char f_min_argc; /* minimal number of arguments */
466 char f_max_argc; /* maximal number of arguments */
467 void (*f_func)(typval_T *args, typval_T *rvar);
468 /* implementation of function */
469} functions[] =
470{
471#ifdef FEAT_FLOAT
472 {"abs", 1, 1, f_abs},
473 {"acos", 1, 1, f_acos}, /* WJMc */
474#endif
475 {"add", 2, 2, f_add},
476 {"and", 2, 2, f_and},
477 {"append", 2, 2, f_append},
478 {"argc", 0, 0, f_argc},
479 {"argidx", 0, 0, f_argidx},
480 {"arglistid", 0, 2, f_arglistid},
481 {"argv", 0, 1, f_argv},
482#ifdef FEAT_FLOAT
483 {"asin", 1, 1, f_asin}, /* WJMc */
484#endif
485 {"assert_equal", 2, 3, f_assert_equal},
486 {"assert_exception", 1, 2, f_assert_exception},
487 {"assert_fails", 1, 2, f_assert_fails},
488 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100489 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200490 {"assert_match", 2, 3, f_assert_match},
491 {"assert_notequal", 2, 3, f_assert_notequal},
492 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100493 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200494 {"assert_true", 1, 2, f_assert_true},
495#ifdef FEAT_FLOAT
496 {"atan", 1, 1, f_atan},
497 {"atan2", 2, 2, f_atan2},
498#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100499#ifdef FEAT_BEVAL
500 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100501# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100502 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100503# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100504#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200505 {"browse", 4, 4, f_browse},
506 {"browsedir", 2, 2, f_browsedir},
507 {"bufexists", 1, 1, f_bufexists},
508 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
509 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
510 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
511 {"buflisted", 1, 1, f_buflisted},
512 {"bufloaded", 1, 1, f_bufloaded},
513 {"bufname", 1, 1, f_bufname},
514 {"bufnr", 1, 2, f_bufnr},
515 {"bufwinid", 1, 1, f_bufwinid},
516 {"bufwinnr", 1, 1, f_bufwinnr},
517 {"byte2line", 1, 1, f_byte2line},
518 {"byteidx", 2, 2, f_byteidx},
519 {"byteidxcomp", 2, 2, f_byteidxcomp},
520 {"call", 2, 3, f_call},
521#ifdef FEAT_FLOAT
522 {"ceil", 1, 1, f_ceil},
523#endif
524#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100525 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200527 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
529 {"ch_evalraw", 2, 3, f_ch_evalraw},
530 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
531 {"ch_getjob", 1, 1, f_ch_getjob},
532 {"ch_info", 1, 1, f_ch_info},
533 {"ch_log", 1, 2, f_ch_log},
534 {"ch_logfile", 1, 2, f_ch_logfile},
535 {"ch_open", 1, 2, f_ch_open},
536 {"ch_read", 1, 2, f_ch_read},
537 {"ch_readraw", 1, 2, f_ch_readraw},
538 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
539 {"ch_sendraw", 2, 3, f_ch_sendraw},
540 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200541 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200542#endif
543 {"changenr", 0, 0, f_changenr},
544 {"char2nr", 1, 2, f_char2nr},
545 {"cindent", 1, 1, f_cindent},
546 {"clearmatches", 0, 0, f_clearmatches},
547 {"col", 1, 1, f_col},
548#if defined(FEAT_INS_EXPAND)
549 {"complete", 2, 2, f_complete},
550 {"complete_add", 1, 1, f_complete_add},
551 {"complete_check", 0, 0, f_complete_check},
552#endif
553 {"confirm", 1, 4, f_confirm},
554 {"copy", 1, 1, f_copy},
555#ifdef FEAT_FLOAT
556 {"cos", 1, 1, f_cos},
557 {"cosh", 1, 1, f_cosh},
558#endif
559 {"count", 2, 4, f_count},
560 {"cscope_connection",0,3, f_cscope_connection},
561 {"cursor", 1, 3, f_cursor},
562 {"deepcopy", 1, 2, f_deepcopy},
563 {"delete", 1, 2, f_delete},
564 {"did_filetype", 0, 0, f_did_filetype},
565 {"diff_filler", 1, 1, f_diff_filler},
566 {"diff_hlID", 2, 2, f_diff_hlID},
567 {"empty", 1, 1, f_empty},
568 {"escape", 2, 2, f_escape},
569 {"eval", 1, 1, f_eval},
570 {"eventhandler", 0, 0, f_eventhandler},
571 {"executable", 1, 1, f_executable},
572 {"execute", 1, 2, f_execute},
573 {"exepath", 1, 1, f_exepath},
574 {"exists", 1, 1, f_exists},
575#ifdef FEAT_FLOAT
576 {"exp", 1, 1, f_exp},
577#endif
578 {"expand", 1, 3, f_expand},
579 {"extend", 2, 3, f_extend},
580 {"feedkeys", 1, 2, f_feedkeys},
581 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
582 {"filereadable", 1, 1, f_filereadable},
583 {"filewritable", 1, 1, f_filewritable},
584 {"filter", 2, 2, f_filter},
585 {"finddir", 1, 3, f_finddir},
586 {"findfile", 1, 3, f_findfile},
587#ifdef FEAT_FLOAT
588 {"float2nr", 1, 1, f_float2nr},
589 {"floor", 1, 1, f_floor},
590 {"fmod", 2, 2, f_fmod},
591#endif
592 {"fnameescape", 1, 1, f_fnameescape},
593 {"fnamemodify", 2, 2, f_fnamemodify},
594 {"foldclosed", 1, 1, f_foldclosed},
595 {"foldclosedend", 1, 1, f_foldclosedend},
596 {"foldlevel", 1, 1, f_foldlevel},
597 {"foldtext", 0, 0, f_foldtext},
598 {"foldtextresult", 1, 1, f_foldtextresult},
599 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200600 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601 {"function", 1, 3, f_function},
602 {"garbagecollect", 0, 1, f_garbagecollect},
603 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200604 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200605 {"getbufline", 2, 3, f_getbufline},
606 {"getbufvar", 2, 3, f_getbufvar},
607 {"getchar", 0, 1, f_getchar},
608 {"getcharmod", 0, 0, f_getcharmod},
609 {"getcharsearch", 0, 0, f_getcharsearch},
610 {"getcmdline", 0, 0, f_getcmdline},
611 {"getcmdpos", 0, 0, f_getcmdpos},
612 {"getcmdtype", 0, 0, f_getcmdtype},
613 {"getcmdwintype", 0, 0, f_getcmdwintype},
614#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200615 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200616#endif
617 {"getcurpos", 0, 0, f_getcurpos},
618 {"getcwd", 0, 2, f_getcwd},
619 {"getfontname", 0, 1, f_getfontname},
620 {"getfperm", 1, 1, f_getfperm},
621 {"getfsize", 1, 1, f_getfsize},
622 {"getftime", 1, 1, f_getftime},
623 {"getftype", 1, 1, f_getftype},
624 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200625 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200626 {"getmatches", 0, 0, f_getmatches},
627 {"getpid", 0, 0, f_getpid},
628 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200629 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200630 {"getreg", 0, 3, f_getreg},
631 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200632 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633 {"gettabvar", 2, 3, f_gettabvar},
634 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200635 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636 {"getwinposx", 0, 0, f_getwinposx},
637 {"getwinposy", 0, 0, f_getwinposy},
638 {"getwinvar", 2, 3, f_getwinvar},
639 {"glob", 1, 4, f_glob},
640 {"glob2regpat", 1, 1, f_glob2regpat},
641 {"globpath", 2, 5, f_globpath},
642 {"has", 1, 1, f_has},
643 {"has_key", 2, 2, f_has_key},
644 {"haslocaldir", 0, 2, f_haslocaldir},
645 {"hasmapto", 1, 3, f_hasmapto},
646 {"highlightID", 1, 1, f_hlID}, /* obsolete */
647 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
648 {"histadd", 2, 2, f_histadd},
649 {"histdel", 1, 2, f_histdel},
650 {"histget", 1, 2, f_histget},
651 {"histnr", 1, 1, f_histnr},
652 {"hlID", 1, 1, f_hlID},
653 {"hlexists", 1, 1, f_hlexists},
654 {"hostname", 0, 0, f_hostname},
655 {"iconv", 3, 3, f_iconv},
656 {"indent", 1, 1, f_indent},
657 {"index", 2, 4, f_index},
658 {"input", 1, 3, f_input},
659 {"inputdialog", 1, 3, f_inputdialog},
660 {"inputlist", 1, 1, f_inputlist},
661 {"inputrestore", 0, 0, f_inputrestore},
662 {"inputsave", 0, 0, f_inputsave},
663 {"inputsecret", 1, 2, f_inputsecret},
664 {"insert", 2, 3, f_insert},
665 {"invert", 1, 1, f_invert},
666 {"isdirectory", 1, 1, f_isdirectory},
667 {"islocked", 1, 1, f_islocked},
668#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
669 {"isnan", 1, 1, f_isnan},
670#endif
671 {"items", 1, 1, f_items},
672#ifdef FEAT_JOB_CHANNEL
673 {"job_getchannel", 1, 1, f_job_getchannel},
674 {"job_info", 1, 1, f_job_info},
675 {"job_setoptions", 2, 2, f_job_setoptions},
676 {"job_start", 1, 2, f_job_start},
677 {"job_status", 1, 1, f_job_status},
678 {"job_stop", 1, 2, f_job_stop},
679#endif
680 {"join", 1, 2, f_join},
681 {"js_decode", 1, 1, f_js_decode},
682 {"js_encode", 1, 1, f_js_encode},
683 {"json_decode", 1, 1, f_json_decode},
684 {"json_encode", 1, 1, f_json_encode},
685 {"keys", 1, 1, f_keys},
686 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
687 {"len", 1, 1, f_len},
688 {"libcall", 3, 3, f_libcall},
689 {"libcallnr", 3, 3, f_libcallnr},
690 {"line", 1, 1, f_line},
691 {"line2byte", 1, 1, f_line2byte},
692 {"lispindent", 1, 1, f_lispindent},
693 {"localtime", 0, 0, f_localtime},
694#ifdef FEAT_FLOAT
695 {"log", 1, 1, f_log},
696 {"log10", 1, 1, f_log10},
697#endif
698#ifdef FEAT_LUA
699 {"luaeval", 1, 2, f_luaeval},
700#endif
701 {"map", 2, 2, f_map},
702 {"maparg", 1, 4, f_maparg},
703 {"mapcheck", 1, 3, f_mapcheck},
704 {"match", 2, 4, f_match},
705 {"matchadd", 2, 5, f_matchadd},
706 {"matchaddpos", 2, 5, f_matchaddpos},
707 {"matcharg", 1, 1, f_matcharg},
708 {"matchdelete", 1, 1, f_matchdelete},
709 {"matchend", 2, 4, f_matchend},
710 {"matchlist", 2, 4, f_matchlist},
711 {"matchstr", 2, 4, f_matchstr},
712 {"matchstrpos", 2, 4, f_matchstrpos},
713 {"max", 1, 1, f_max},
714 {"min", 1, 1, f_min},
715#ifdef vim_mkdir
716 {"mkdir", 1, 3, f_mkdir},
717#endif
718 {"mode", 0, 1, f_mode},
719#ifdef FEAT_MZSCHEME
720 {"mzeval", 1, 1, f_mzeval},
721#endif
722 {"nextnonblank", 1, 1, f_nextnonblank},
723 {"nr2char", 1, 2, f_nr2char},
724 {"or", 2, 2, f_or},
725 {"pathshorten", 1, 1, f_pathshorten},
726#ifdef FEAT_PERL
727 {"perleval", 1, 1, f_perleval},
728#endif
729#ifdef FEAT_FLOAT
730 {"pow", 2, 2, f_pow},
731#endif
732 {"prevnonblank", 1, 1, f_prevnonblank},
733 {"printf", 2, 19, f_printf},
734 {"pumvisible", 0, 0, f_pumvisible},
735#ifdef FEAT_PYTHON3
736 {"py3eval", 1, 1, f_py3eval},
737#endif
738#ifdef FEAT_PYTHON
739 {"pyeval", 1, 1, f_pyeval},
740#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100741#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
742 {"pyxeval", 1, 1, f_pyxeval},
743#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744 {"range", 1, 3, f_range},
745 {"readfile", 1, 3, f_readfile},
746 {"reltime", 0, 2, f_reltime},
747#ifdef FEAT_FLOAT
748 {"reltimefloat", 1, 1, f_reltimefloat},
749#endif
750 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100751 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200752 {"remote_foreground", 1, 1, f_remote_foreground},
753 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100754 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200755 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100756 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757 {"remove", 2, 3, f_remove},
758 {"rename", 2, 2, f_rename},
759 {"repeat", 2, 2, f_repeat},
760 {"resolve", 1, 1, f_resolve},
761 {"reverse", 1, 1, f_reverse},
762#ifdef FEAT_FLOAT
763 {"round", 1, 1, f_round},
764#endif
765 {"screenattr", 2, 2, f_screenattr},
766 {"screenchar", 2, 2, f_screenchar},
767 {"screencol", 0, 0, f_screencol},
768 {"screenrow", 0, 0, f_screenrow},
769 {"search", 1, 4, f_search},
770 {"searchdecl", 1, 3, f_searchdecl},
771 {"searchpair", 3, 7, f_searchpair},
772 {"searchpairpos", 3, 7, f_searchpairpos},
773 {"searchpos", 1, 4, f_searchpos},
774 {"server2client", 2, 2, f_server2client},
775 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200776 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777 {"setbufvar", 3, 3, f_setbufvar},
778 {"setcharsearch", 1, 1, f_setcharsearch},
779 {"setcmdpos", 1, 1, f_setcmdpos},
780 {"setfperm", 2, 2, f_setfperm},
781 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200782 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783 {"setmatches", 1, 1, f_setmatches},
784 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200785 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200786 {"setreg", 2, 3, f_setreg},
787 {"settabvar", 3, 3, f_settabvar},
788 {"settabwinvar", 4, 4, f_settabwinvar},
789 {"setwinvar", 3, 3, f_setwinvar},
790#ifdef FEAT_CRYPT
791 {"sha256", 1, 1, f_sha256},
792#endif
793 {"shellescape", 1, 2, f_shellescape},
794 {"shiftwidth", 0, 0, f_shiftwidth},
795 {"simplify", 1, 1, f_simplify},
796#ifdef FEAT_FLOAT
797 {"sin", 1, 1, f_sin},
798 {"sinh", 1, 1, f_sinh},
799#endif
800 {"sort", 1, 3, f_sort},
801 {"soundfold", 1, 1, f_soundfold},
802 {"spellbadword", 0, 1, f_spellbadword},
803 {"spellsuggest", 1, 3, f_spellsuggest},
804 {"split", 1, 3, f_split},
805#ifdef FEAT_FLOAT
806 {"sqrt", 1, 1, f_sqrt},
807 {"str2float", 1, 1, f_str2float},
808#endif
809 {"str2nr", 1, 2, f_str2nr},
810 {"strcharpart", 2, 3, f_strcharpart},
811 {"strchars", 1, 2, f_strchars},
812 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
813#ifdef HAVE_STRFTIME
814 {"strftime", 1, 2, f_strftime},
815#endif
816 {"strgetchar", 2, 2, f_strgetchar},
817 {"stridx", 2, 3, f_stridx},
818 {"string", 1, 1, f_string},
819 {"strlen", 1, 1, f_strlen},
820 {"strpart", 2, 3, f_strpart},
821 {"strridx", 2, 3, f_strridx},
822 {"strtrans", 1, 1, f_strtrans},
823 {"strwidth", 1, 1, f_strwidth},
824 {"submatch", 1, 2, f_submatch},
825 {"substitute", 4, 4, f_substitute},
826 {"synID", 3, 3, f_synID},
827 {"synIDattr", 2, 3, f_synIDattr},
828 {"synIDtrans", 1, 1, f_synIDtrans},
829 {"synconcealed", 2, 2, f_synconcealed},
830 {"synstack", 2, 2, f_synstack},
831 {"system", 1, 2, f_system},
832 {"systemlist", 1, 2, f_systemlist},
833 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
834 {"tabpagenr", 0, 1, f_tabpagenr},
835 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
836 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100837 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200838#ifdef FEAT_FLOAT
839 {"tan", 1, 1, f_tan},
840 {"tanh", 1, 1, f_tanh},
841#endif
842 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200843#ifdef FEAT_TERMINAL
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200844 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200845 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200846 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200847 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200848 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200849 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200850 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200851 {"term_getstatus", 1, 1, f_term_getstatus},
852 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200853 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200854 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200855 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200856 {"term_sendkeys", 2, 2, f_term_sendkeys},
857 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200858 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200859#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200860 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
861 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200862 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200863 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100864 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200865#ifdef FEAT_JOB_CHANNEL
866 {"test_null_channel", 0, 0, f_test_null_channel},
867#endif
868 {"test_null_dict", 0, 0, f_test_null_dict},
869#ifdef FEAT_JOB_CHANNEL
870 {"test_null_job", 0, 0, f_test_null_job},
871#endif
872 {"test_null_list", 0, 0, f_test_null_list},
873 {"test_null_partial", 0, 0, f_test_null_partial},
874 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100875 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876 {"test_settime", 1, 1, f_test_settime},
877#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200878 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200879 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200880 {"timer_start", 2, 3, f_timer_start},
881 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200882 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883#endif
884 {"tolower", 1, 1, f_tolower},
885 {"toupper", 1, 1, f_toupper},
886 {"tr", 3, 3, f_tr},
887#ifdef FEAT_FLOAT
888 {"trunc", 1, 1, f_trunc},
889#endif
890 {"type", 1, 1, f_type},
891 {"undofile", 1, 1, f_undofile},
892 {"undotree", 0, 0, f_undotree},
893 {"uniq", 1, 3, f_uniq},
894 {"values", 1, 1, f_values},
895 {"virtcol", 1, 1, f_virtcol},
896 {"visualmode", 0, 1, f_visualmode},
897 {"wildmenumode", 0, 0, f_wildmenumode},
898 {"win_findbuf", 1, 1, f_win_findbuf},
899 {"win_getid", 0, 2, f_win_getid},
900 {"win_gotoid", 1, 1, f_win_gotoid},
901 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
902 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100903 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200904 {"winbufnr", 1, 1, f_winbufnr},
905 {"wincol", 0, 0, f_wincol},
906 {"winheight", 1, 1, f_winheight},
907 {"winline", 0, 0, f_winline},
908 {"winnr", 0, 1, f_winnr},
909 {"winrestcmd", 0, 0, f_winrestcmd},
910 {"winrestview", 1, 1, f_winrestview},
911 {"winsaveview", 0, 0, f_winsaveview},
912 {"winwidth", 1, 1, f_winwidth},
913 {"wordcount", 0, 0, f_wordcount},
914 {"writefile", 2, 3, f_writefile},
915 {"xor", 2, 2, f_xor},
916};
917
918#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
919
920/*
921 * Function given to ExpandGeneric() to obtain the list of internal
922 * or user defined function names.
923 */
924 char_u *
925get_function_name(expand_T *xp, int idx)
926{
927 static int intidx = -1;
928 char_u *name;
929
930 if (idx == 0)
931 intidx = -1;
932 if (intidx < 0)
933 {
934 name = get_user_func_name(xp, idx);
935 if (name != NULL)
936 return name;
937 }
938 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
939 {
940 STRCPY(IObuff, functions[intidx].f_name);
941 STRCAT(IObuff, "(");
942 if (functions[intidx].f_max_argc == 0)
943 STRCAT(IObuff, ")");
944 return IObuff;
945 }
946
947 return NULL;
948}
949
950/*
951 * Function given to ExpandGeneric() to obtain the list of internal or
952 * user defined variable or function names.
953 */
954 char_u *
955get_expr_name(expand_T *xp, int idx)
956{
957 static int intidx = -1;
958 char_u *name;
959
960 if (idx == 0)
961 intidx = -1;
962 if (intidx < 0)
963 {
964 name = get_function_name(xp, idx);
965 if (name != NULL)
966 return name;
967 }
968 return get_user_var_name(xp, ++intidx);
969}
970
971#endif /* FEAT_CMDL_COMPL */
972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973/*
974 * Find internal function in table above.
975 * Return index, or -1 if not found
976 */
977 int
978find_internal_func(
979 char_u *name) /* name of the function */
980{
981 int first = 0;
982 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
983 int cmp;
984 int x;
985
986 /*
987 * Find the function name in the table. Binary search.
988 */
989 while (first <= last)
990 {
991 x = first + ((unsigned)(last - first) >> 1);
992 cmp = STRCMP(name, functions[x].f_name);
993 if (cmp < 0)
994 last = x - 1;
995 else if (cmp > 0)
996 first = x + 1;
997 else
998 return x;
999 }
1000 return -1;
1001}
1002
1003 int
1004call_internal_func(
1005 char_u *name,
1006 int argcount,
1007 typval_T *argvars,
1008 typval_T *rettv)
1009{
1010 int i;
1011
1012 i = find_internal_func(name);
1013 if (i < 0)
1014 return ERROR_UNKNOWN;
1015 if (argcount < functions[i].f_min_argc)
1016 return ERROR_TOOFEW;
1017 if (argcount > functions[i].f_max_argc)
1018 return ERROR_TOOMANY;
1019 argvars[argcount].v_type = VAR_UNKNOWN;
1020 functions[i].f_func(argvars, rettv);
1021 return ERROR_NONE;
1022}
1023
1024/*
1025 * Return TRUE for a non-zero Number and a non-empty String.
1026 */
1027 static int
1028non_zero_arg(typval_T *argvars)
1029{
1030 return ((argvars[0].v_type == VAR_NUMBER
1031 && argvars[0].vval.v_number != 0)
1032 || (argvars[0].v_type == VAR_SPECIAL
1033 && argvars[0].vval.v_number == VVAL_TRUE)
1034 || (argvars[0].v_type == VAR_STRING
1035 && argvars[0].vval.v_string != NULL
1036 && *argvars[0].vval.v_string != NUL));
1037}
1038
1039/*
1040 * Get the lnum from the first argument.
1041 * Also accepts ".", "$", etc., but that only works for the current buffer.
1042 * Returns -1 on error.
1043 */
1044 static linenr_T
1045get_tv_lnum(typval_T *argvars)
1046{
1047 typval_T rettv;
1048 linenr_T lnum;
1049
1050 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1051 if (lnum == 0) /* no valid number, try using line() */
1052 {
1053 rettv.v_type = VAR_NUMBER;
1054 f_line(argvars, &rettv);
1055 lnum = (linenr_T)rettv.vval.v_number;
1056 clear_tv(&rettv);
1057 }
1058 return lnum;
1059}
1060
1061#ifdef FEAT_FLOAT
1062static int get_float_arg(typval_T *argvars, float_T *f);
1063
1064/*
1065 * Get the float value of "argvars[0]" into "f".
1066 * Returns FAIL when the argument is not a Number or Float.
1067 */
1068 static int
1069get_float_arg(typval_T *argvars, float_T *f)
1070{
1071 if (argvars[0].v_type == VAR_FLOAT)
1072 {
1073 *f = argvars[0].vval.v_float;
1074 return OK;
1075 }
1076 if (argvars[0].v_type == VAR_NUMBER)
1077 {
1078 *f = (float_T)argvars[0].vval.v_number;
1079 return OK;
1080 }
1081 EMSG(_("E808: Number or Float required"));
1082 return FAIL;
1083}
1084
1085/*
1086 * "abs(expr)" function
1087 */
1088 static void
1089f_abs(typval_T *argvars, typval_T *rettv)
1090{
1091 if (argvars[0].v_type == VAR_FLOAT)
1092 {
1093 rettv->v_type = VAR_FLOAT;
1094 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1095 }
1096 else
1097 {
1098 varnumber_T n;
1099 int error = FALSE;
1100
1101 n = get_tv_number_chk(&argvars[0], &error);
1102 if (error)
1103 rettv->vval.v_number = -1;
1104 else if (n > 0)
1105 rettv->vval.v_number = n;
1106 else
1107 rettv->vval.v_number = -n;
1108 }
1109}
1110
1111/*
1112 * "acos()" function
1113 */
1114 static void
1115f_acos(typval_T *argvars, typval_T *rettv)
1116{
1117 float_T f = 0.0;
1118
1119 rettv->v_type = VAR_FLOAT;
1120 if (get_float_arg(argvars, &f) == OK)
1121 rettv->vval.v_float = acos(f);
1122 else
1123 rettv->vval.v_float = 0.0;
1124}
1125#endif
1126
1127/*
1128 * "add(list, item)" function
1129 */
1130 static void
1131f_add(typval_T *argvars, typval_T *rettv)
1132{
1133 list_T *l;
1134
1135 rettv->vval.v_number = 1; /* Default: Failed */
1136 if (argvars[0].v_type == VAR_LIST)
1137 {
1138 if ((l = argvars[0].vval.v_list) != NULL
1139 && !tv_check_lock(l->lv_lock,
1140 (char_u *)N_("add() argument"), TRUE)
1141 && list_append_tv(l, &argvars[1]) == OK)
1142 copy_tv(&argvars[0], rettv);
1143 }
1144 else
1145 EMSG(_(e_listreq));
1146}
1147
1148/*
1149 * "and(expr, expr)" function
1150 */
1151 static void
1152f_and(typval_T *argvars, typval_T *rettv)
1153{
1154 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1155 & get_tv_number_chk(&argvars[1], NULL);
1156}
1157
1158/*
1159 * "append(lnum, string/list)" function
1160 */
1161 static void
1162f_append(typval_T *argvars, typval_T *rettv)
1163{
1164 long lnum;
1165 char_u *line;
1166 list_T *l = NULL;
1167 listitem_T *li = NULL;
1168 typval_T *tv;
1169 long added = 0;
1170
1171 /* When coming here from Insert mode, sync undo, so that this can be
1172 * undone separately from what was previously inserted. */
1173 if (u_sync_once == 2)
1174 {
1175 u_sync_once = 1; /* notify that u_sync() was called */
1176 u_sync(TRUE);
1177 }
1178
1179 lnum = get_tv_lnum(argvars);
1180 if (lnum >= 0
1181 && lnum <= curbuf->b_ml.ml_line_count
1182 && u_save(lnum, lnum + 1) == OK)
1183 {
1184 if (argvars[1].v_type == VAR_LIST)
1185 {
1186 l = argvars[1].vval.v_list;
1187 if (l == NULL)
1188 return;
1189 li = l->lv_first;
1190 }
1191 for (;;)
1192 {
1193 if (l == NULL)
1194 tv = &argvars[1]; /* append a string */
1195 else if (li == NULL)
1196 break; /* end of list */
1197 else
1198 tv = &li->li_tv; /* append item from list */
1199 line = get_tv_string_chk(tv);
1200 if (line == NULL) /* type error */
1201 {
1202 rettv->vval.v_number = 1; /* Failed */
1203 break;
1204 }
1205 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1206 ++added;
1207 if (l == NULL)
1208 break;
1209 li = li->li_next;
1210 }
1211
1212 appended_lines_mark(lnum, added);
1213 if (curwin->w_cursor.lnum > lnum)
1214 curwin->w_cursor.lnum += added;
1215 }
1216 else
1217 rettv->vval.v_number = 1; /* Failed */
1218}
1219
1220/*
1221 * "argc()" function
1222 */
1223 static void
1224f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1225{
1226 rettv->vval.v_number = ARGCOUNT;
1227}
1228
1229/*
1230 * "argidx()" function
1231 */
1232 static void
1233f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1234{
1235 rettv->vval.v_number = curwin->w_arg_idx;
1236}
1237
1238/*
1239 * "arglistid()" function
1240 */
1241 static void
1242f_arglistid(typval_T *argvars, typval_T *rettv)
1243{
1244 win_T *wp;
1245
1246 rettv->vval.v_number = -1;
1247 wp = find_tabwin(&argvars[0], &argvars[1]);
1248 if (wp != NULL)
1249 rettv->vval.v_number = wp->w_alist->id;
1250}
1251
1252/*
1253 * "argv(nr)" function
1254 */
1255 static void
1256f_argv(typval_T *argvars, typval_T *rettv)
1257{
1258 int idx;
1259
1260 if (argvars[0].v_type != VAR_UNKNOWN)
1261 {
1262 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1263 if (idx >= 0 && idx < ARGCOUNT)
1264 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1265 else
1266 rettv->vval.v_string = NULL;
1267 rettv->v_type = VAR_STRING;
1268 }
1269 else if (rettv_list_alloc(rettv) == OK)
1270 for (idx = 0; idx < ARGCOUNT; ++idx)
1271 list_append_string(rettv->vval.v_list,
1272 alist_name(&ARGLIST[idx]), -1);
1273}
1274
1275/*
1276 * "assert_equal(expected, actual[, msg])" function
1277 */
1278 static void
1279f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1280{
1281 assert_equal_common(argvars, ASSERT_EQUAL);
1282}
1283
1284/*
1285 * "assert_notequal(expected, actual[, msg])" function
1286 */
1287 static void
1288f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1289{
1290 assert_equal_common(argvars, ASSERT_NOTEQUAL);
1291}
1292
1293/*
1294 * "assert_exception(string[, msg])" function
1295 */
1296 static void
1297f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1298{
1299 assert_exception(argvars);
1300}
1301
1302/*
1303 * "assert_fails(cmd [, error])" function
1304 */
1305 static void
1306f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1307{
1308 assert_fails(argvars);
1309}
1310
1311/*
1312 * "assert_false(actual[, msg])" function
1313 */
1314 static void
1315f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1316{
1317 assert_bool(argvars, FALSE);
1318}
1319
1320/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001321 * "assert_inrange(lower, upper[, msg])" function
1322 */
1323 static void
1324f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1325{
1326 assert_inrange(argvars);
1327}
1328
1329/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001330 * "assert_match(pattern, actual[, msg])" function
1331 */
1332 static void
1333f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1334{
1335 assert_match_common(argvars, ASSERT_MATCH);
1336}
1337
1338/*
1339 * "assert_notmatch(pattern, actual[, msg])" function
1340 */
1341 static void
1342f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1343{
1344 assert_match_common(argvars, ASSERT_NOTMATCH);
1345}
1346
1347/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001348 * "assert_report(msg)" function
1349 */
1350 static void
1351f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
1352{
1353 assert_report(argvars);
1354}
1355
1356/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001357 * "assert_true(actual[, msg])" function
1358 */
1359 static void
1360f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1361{
1362 assert_bool(argvars, TRUE);
1363}
1364
1365#ifdef FEAT_FLOAT
1366/*
1367 * "asin()" function
1368 */
1369 static void
1370f_asin(typval_T *argvars, typval_T *rettv)
1371{
1372 float_T f = 0.0;
1373
1374 rettv->v_type = VAR_FLOAT;
1375 if (get_float_arg(argvars, &f) == OK)
1376 rettv->vval.v_float = asin(f);
1377 else
1378 rettv->vval.v_float = 0.0;
1379}
1380
1381/*
1382 * "atan()" function
1383 */
1384 static void
1385f_atan(typval_T *argvars, typval_T *rettv)
1386{
1387 float_T f = 0.0;
1388
1389 rettv->v_type = VAR_FLOAT;
1390 if (get_float_arg(argvars, &f) == OK)
1391 rettv->vval.v_float = atan(f);
1392 else
1393 rettv->vval.v_float = 0.0;
1394}
1395
1396/*
1397 * "atan2()" function
1398 */
1399 static void
1400f_atan2(typval_T *argvars, typval_T *rettv)
1401{
1402 float_T fx = 0.0, fy = 0.0;
1403
1404 rettv->v_type = VAR_FLOAT;
1405 if (get_float_arg(argvars, &fx) == OK
1406 && get_float_arg(&argvars[1], &fy) == OK)
1407 rettv->vval.v_float = atan2(fx, fy);
1408 else
1409 rettv->vval.v_float = 0.0;
1410}
1411#endif
1412
1413/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001414 * "balloon_show()" function
1415 */
1416#ifdef FEAT_BEVAL
1417 static void
1418f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1419{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001420 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001421 {
1422 if (argvars[0].v_type == VAR_LIST
1423# ifdef FEAT_GUI
1424 && !gui.in_use
1425# endif
1426 )
1427 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1428 else
1429 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1430 }
1431}
1432
Bram Moolenaar669a8282017-11-19 20:13:05 +01001433# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001434 static void
1435f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1436{
1437 if (rettv_list_alloc(rettv) == OK)
1438 {
1439 char_u *msg = get_tv_string_chk(&argvars[0]);
1440
1441 if (msg != NULL)
1442 {
1443 pumitem_T *array;
1444 int size = split_message(msg, &array);
1445 int i;
1446
1447 /* Skip the first and last item, they are always empty. */
1448 for (i = 1; i < size - 1; ++i)
1449 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001450 while (size > 0)
1451 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001452 vim_free(array);
1453 }
1454 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001455}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001456# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001457#endif
1458
1459/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001460 * "browse(save, title, initdir, default)" function
1461 */
1462 static void
1463f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1464{
1465#ifdef FEAT_BROWSE
1466 int save;
1467 char_u *title;
1468 char_u *initdir;
1469 char_u *defname;
1470 char_u buf[NUMBUFLEN];
1471 char_u buf2[NUMBUFLEN];
1472 int error = FALSE;
1473
1474 save = (int)get_tv_number_chk(&argvars[0], &error);
1475 title = get_tv_string_chk(&argvars[1]);
1476 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1477 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1478
1479 if (error || title == NULL || initdir == NULL || defname == NULL)
1480 rettv->vval.v_string = NULL;
1481 else
1482 rettv->vval.v_string =
1483 do_browse(save ? BROWSE_SAVE : 0,
1484 title, defname, NULL, initdir, NULL, curbuf);
1485#else
1486 rettv->vval.v_string = NULL;
1487#endif
1488 rettv->v_type = VAR_STRING;
1489}
1490
1491/*
1492 * "browsedir(title, initdir)" function
1493 */
1494 static void
1495f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1496{
1497#ifdef FEAT_BROWSE
1498 char_u *title;
1499 char_u *initdir;
1500 char_u buf[NUMBUFLEN];
1501
1502 title = get_tv_string_chk(&argvars[0]);
1503 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1504
1505 if (title == NULL || initdir == NULL)
1506 rettv->vval.v_string = NULL;
1507 else
1508 rettv->vval.v_string = do_browse(BROWSE_DIR,
1509 title, NULL, NULL, initdir, NULL, curbuf);
1510#else
1511 rettv->vval.v_string = NULL;
1512#endif
1513 rettv->v_type = VAR_STRING;
1514}
1515
1516static buf_T *find_buffer(typval_T *avar);
1517
1518/*
1519 * Find a buffer by number or exact name.
1520 */
1521 static buf_T *
1522find_buffer(typval_T *avar)
1523{
1524 buf_T *buf = NULL;
1525
1526 if (avar->v_type == VAR_NUMBER)
1527 buf = buflist_findnr((int)avar->vval.v_number);
1528 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1529 {
1530 buf = buflist_findname_exp(avar->vval.v_string);
1531 if (buf == NULL)
1532 {
1533 /* No full path name match, try a match with a URL or a "nofile"
1534 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001535 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001536 if (buf->b_fname != NULL
1537 && (path_with_url(buf->b_fname)
1538#ifdef FEAT_QUICKFIX
1539 || bt_nofile(buf)
1540#endif
1541 )
1542 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1543 break;
1544 }
1545 }
1546 return buf;
1547}
1548
1549/*
1550 * "bufexists(expr)" function
1551 */
1552 static void
1553f_bufexists(typval_T *argvars, typval_T *rettv)
1554{
1555 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1556}
1557
1558/*
1559 * "buflisted(expr)" function
1560 */
1561 static void
1562f_buflisted(typval_T *argvars, typval_T *rettv)
1563{
1564 buf_T *buf;
1565
1566 buf = find_buffer(&argvars[0]);
1567 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1568}
1569
1570/*
1571 * "bufloaded(expr)" function
1572 */
1573 static void
1574f_bufloaded(typval_T *argvars, typval_T *rettv)
1575{
1576 buf_T *buf;
1577
1578 buf = find_buffer(&argvars[0]);
1579 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1580}
1581
1582 buf_T *
1583buflist_find_by_name(char_u *name, int curtab_only)
1584{
1585 int save_magic;
1586 char_u *save_cpo;
1587 buf_T *buf;
1588
1589 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1590 save_magic = p_magic;
1591 p_magic = TRUE;
1592 save_cpo = p_cpo;
1593 p_cpo = (char_u *)"";
1594
1595 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1596 TRUE, FALSE, curtab_only));
1597
1598 p_magic = save_magic;
1599 p_cpo = save_cpo;
1600 return buf;
1601}
1602
1603/*
1604 * Get buffer by number or pattern.
1605 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001606 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607get_buf_tv(typval_T *tv, int curtab_only)
1608{
1609 char_u *name = tv->vval.v_string;
1610 buf_T *buf;
1611
1612 if (tv->v_type == VAR_NUMBER)
1613 return buflist_findnr((int)tv->vval.v_number);
1614 if (tv->v_type != VAR_STRING)
1615 return NULL;
1616 if (name == NULL || *name == NUL)
1617 return curbuf;
1618 if (name[0] == '$' && name[1] == NUL)
1619 return lastbuf;
1620
1621 buf = buflist_find_by_name(name, curtab_only);
1622
1623 /* If not found, try expanding the name, like done for bufexists(). */
1624 if (buf == NULL)
1625 buf = find_buffer(tv);
1626
1627 return buf;
1628}
1629
1630/*
1631 * "bufname(expr)" function
1632 */
1633 static void
1634f_bufname(typval_T *argvars, typval_T *rettv)
1635{
1636 buf_T *buf;
1637
1638 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1639 ++emsg_off;
1640 buf = get_buf_tv(&argvars[0], FALSE);
1641 rettv->v_type = VAR_STRING;
1642 if (buf != NULL && buf->b_fname != NULL)
1643 rettv->vval.v_string = vim_strsave(buf->b_fname);
1644 else
1645 rettv->vval.v_string = NULL;
1646 --emsg_off;
1647}
1648
1649/*
1650 * "bufnr(expr)" function
1651 */
1652 static void
1653f_bufnr(typval_T *argvars, typval_T *rettv)
1654{
1655 buf_T *buf;
1656 int error = FALSE;
1657 char_u *name;
1658
1659 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1660 ++emsg_off;
1661 buf = get_buf_tv(&argvars[0], FALSE);
1662 --emsg_off;
1663
1664 /* If the buffer isn't found and the second argument is not zero create a
1665 * new buffer. */
1666 if (buf == NULL
1667 && argvars[1].v_type != VAR_UNKNOWN
1668 && get_tv_number_chk(&argvars[1], &error) != 0
1669 && !error
1670 && (name = get_tv_string_chk(&argvars[0])) != NULL
1671 && !error)
1672 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1673
1674 if (buf != NULL)
1675 rettv->vval.v_number = buf->b_fnum;
1676 else
1677 rettv->vval.v_number = -1;
1678}
1679
1680 static void
1681buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1682{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001683 win_T *wp;
1684 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 buf_T *buf;
1686
1687 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1688 ++emsg_off;
1689 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001690 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691 {
1692 ++winnr;
1693 if (wp->w_buffer == buf)
1694 break;
1695 }
1696 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697 --emsg_off;
1698}
1699
1700/*
1701 * "bufwinid(nr)" function
1702 */
1703 static void
1704f_bufwinid(typval_T *argvars, typval_T *rettv)
1705{
1706 buf_win_common(argvars, rettv, FALSE);
1707}
1708
1709/*
1710 * "bufwinnr(nr)" function
1711 */
1712 static void
1713f_bufwinnr(typval_T *argvars, typval_T *rettv)
1714{
1715 buf_win_common(argvars, rettv, TRUE);
1716}
1717
1718/*
1719 * "byte2line(byte)" function
1720 */
1721 static void
1722f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1723{
1724#ifndef FEAT_BYTEOFF
1725 rettv->vval.v_number = -1;
1726#else
1727 long boff = 0;
1728
1729 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1730 if (boff < 0)
1731 rettv->vval.v_number = -1;
1732 else
1733 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1734 (linenr_T)0, &boff);
1735#endif
1736}
1737
1738 static void
1739byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1740{
1741#ifdef FEAT_MBYTE
1742 char_u *t;
1743#endif
1744 char_u *str;
1745 varnumber_T idx;
1746
1747 str = get_tv_string_chk(&argvars[0]);
1748 idx = get_tv_number_chk(&argvars[1], NULL);
1749 rettv->vval.v_number = -1;
1750 if (str == NULL || idx < 0)
1751 return;
1752
1753#ifdef FEAT_MBYTE
1754 t = str;
1755 for ( ; idx > 0; idx--)
1756 {
1757 if (*t == NUL) /* EOL reached */
1758 return;
1759 if (enc_utf8 && comp)
1760 t += utf_ptr2len(t);
1761 else
1762 t += (*mb_ptr2len)(t);
1763 }
1764 rettv->vval.v_number = (varnumber_T)(t - str);
1765#else
1766 if ((size_t)idx <= STRLEN(str))
1767 rettv->vval.v_number = idx;
1768#endif
1769}
1770
1771/*
1772 * "byteidx()" function
1773 */
1774 static void
1775f_byteidx(typval_T *argvars, typval_T *rettv)
1776{
1777 byteidx(argvars, rettv, FALSE);
1778}
1779
1780/*
1781 * "byteidxcomp()" function
1782 */
1783 static void
1784f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1785{
1786 byteidx(argvars, rettv, TRUE);
1787}
1788
1789/*
1790 * "call(func, arglist [, dict])" function
1791 */
1792 static void
1793f_call(typval_T *argvars, typval_T *rettv)
1794{
1795 char_u *func;
1796 partial_T *partial = NULL;
1797 dict_T *selfdict = NULL;
1798
1799 if (argvars[1].v_type != VAR_LIST)
1800 {
1801 EMSG(_(e_listreq));
1802 return;
1803 }
1804 if (argvars[1].vval.v_list == NULL)
1805 return;
1806
1807 if (argvars[0].v_type == VAR_FUNC)
1808 func = argvars[0].vval.v_string;
1809 else if (argvars[0].v_type == VAR_PARTIAL)
1810 {
1811 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001812 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 }
1814 else
1815 func = get_tv_string(&argvars[0]);
1816 if (*func == NUL)
1817 return; /* type error or empty name */
1818
1819 if (argvars[2].v_type != VAR_UNKNOWN)
1820 {
1821 if (argvars[2].v_type != VAR_DICT)
1822 {
1823 EMSG(_(e_dictreq));
1824 return;
1825 }
1826 selfdict = argvars[2].vval.v_dict;
1827 }
1828
1829 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1830}
1831
1832#ifdef FEAT_FLOAT
1833/*
1834 * "ceil({float})" function
1835 */
1836 static void
1837f_ceil(typval_T *argvars, typval_T *rettv)
1838{
1839 float_T f = 0.0;
1840
1841 rettv->v_type = VAR_FLOAT;
1842 if (get_float_arg(argvars, &f) == OK)
1843 rettv->vval.v_float = ceil(f);
1844 else
1845 rettv->vval.v_float = 0.0;
1846}
1847#endif
1848
1849#ifdef FEAT_JOB_CHANNEL
1850/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001851 * "ch_canread()" function
1852 */
1853 static void
1854f_ch_canread(typval_T *argvars, typval_T *rettv)
1855{
Bram Moolenaar958dc692016-12-01 15:34:12 +01001856 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01001857
1858 rettv->vval.v_number = 0;
1859 if (channel != NULL)
1860 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1861 || channel_has_readahead(channel, PART_OUT)
1862 || channel_has_readahead(channel, PART_ERR);
1863}
1864
1865/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001866 * "ch_close()" function
1867 */
1868 static void
1869f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1870{
1871 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1872
1873 if (channel != NULL)
1874 {
1875 channel_close(channel, FALSE);
1876 channel_clear(channel);
1877 }
1878}
1879
1880/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02001881 * "ch_close()" function
1882 */
1883 static void
1884f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1885{
1886 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1887
1888 if (channel != NULL)
1889 channel_close_in(channel);
1890}
1891
1892/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001893 * "ch_getbufnr()" function
1894 */
1895 static void
1896f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1897{
1898 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1899
1900 rettv->vval.v_number = -1;
1901 if (channel != NULL)
1902 {
1903 char_u *what = get_tv_string(&argvars[1]);
1904 int part;
1905
1906 if (STRCMP(what, "err") == 0)
1907 part = PART_ERR;
1908 else if (STRCMP(what, "out") == 0)
1909 part = PART_OUT;
1910 else if (STRCMP(what, "in") == 0)
1911 part = PART_IN;
1912 else
1913 part = PART_SOCK;
1914 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1915 rettv->vval.v_number =
1916 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1917 }
1918}
1919
1920/*
1921 * "ch_getjob()" function
1922 */
1923 static void
1924f_ch_getjob(typval_T *argvars, typval_T *rettv)
1925{
1926 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1927
1928 if (channel != NULL)
1929 {
1930 rettv->v_type = VAR_JOB;
1931 rettv->vval.v_job = channel->ch_job;
1932 if (channel->ch_job != NULL)
1933 ++channel->ch_job->jv_refcount;
1934 }
1935}
1936
1937/*
1938 * "ch_info()" function
1939 */
1940 static void
1941f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1942{
1943 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1944
1945 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1946 channel_info(channel, rettv->vval.v_dict);
1947}
1948
1949/*
1950 * "ch_log()" function
1951 */
1952 static void
1953f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1954{
1955 char_u *msg = get_tv_string(&argvars[0]);
1956 channel_T *channel = NULL;
1957
1958 if (argvars[1].v_type != VAR_UNKNOWN)
1959 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
1960
1961 ch_log(channel, (char *)msg);
1962}
1963
1964/*
1965 * "ch_logfile()" function
1966 */
1967 static void
1968f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
1969{
1970 char_u *fname;
1971 char_u *opt = (char_u *)"";
1972 char_u buf[NUMBUFLEN];
1973
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02001974 /* Don't open a file in restricted mode. */
1975 if (check_restricted() || check_secure())
1976 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001977 fname = get_tv_string(&argvars[0]);
1978 if (argvars[1].v_type == VAR_STRING)
1979 opt = get_tv_string_buf(&argvars[1], buf);
1980 ch_logfile(fname, opt);
1981}
1982
1983/*
1984 * "ch_open()" function
1985 */
1986 static void
1987f_ch_open(typval_T *argvars, typval_T *rettv)
1988{
1989 rettv->v_type = VAR_CHANNEL;
1990 if (check_restricted() || check_secure())
1991 return;
1992 rettv->vval.v_channel = channel_open_func(argvars);
1993}
1994
1995/*
1996 * "ch_read()" function
1997 */
1998 static void
1999f_ch_read(typval_T *argvars, typval_T *rettv)
2000{
2001 common_channel_read(argvars, rettv, FALSE);
2002}
2003
2004/*
2005 * "ch_readraw()" function
2006 */
2007 static void
2008f_ch_readraw(typval_T *argvars, typval_T *rettv)
2009{
2010 common_channel_read(argvars, rettv, TRUE);
2011}
2012
2013/*
2014 * "ch_evalexpr()" function
2015 */
2016 static void
2017f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2018{
2019 ch_expr_common(argvars, rettv, TRUE);
2020}
2021
2022/*
2023 * "ch_sendexpr()" function
2024 */
2025 static void
2026f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2027{
2028 ch_expr_common(argvars, rettv, FALSE);
2029}
2030
2031/*
2032 * "ch_evalraw()" function
2033 */
2034 static void
2035f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2036{
2037 ch_raw_common(argvars, rettv, TRUE);
2038}
2039
2040/*
2041 * "ch_sendraw()" function
2042 */
2043 static void
2044f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2045{
2046 ch_raw_common(argvars, rettv, FALSE);
2047}
2048
2049/*
2050 * "ch_setoptions()" function
2051 */
2052 static void
2053f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2054{
2055 channel_T *channel;
2056 jobopt_T opt;
2057
2058 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2059 if (channel == NULL)
2060 return;
2061 clear_job_options(&opt);
2062 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002063 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002064 channel_set_options(channel, &opt);
2065 free_job_options(&opt);
2066}
2067
2068/*
2069 * "ch_status()" function
2070 */
2071 static void
2072f_ch_status(typval_T *argvars, typval_T *rettv)
2073{
2074 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002075 jobopt_T opt;
2076 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077
2078 /* return an empty string by default */
2079 rettv->v_type = VAR_STRING;
2080 rettv->vval.v_string = NULL;
2081
2082 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002083
2084 if (argvars[1].v_type != VAR_UNKNOWN)
2085 {
2086 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002087 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002088 && (opt.jo_set & JO_PART))
2089 part = opt.jo_part;
2090 }
2091
2092 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093}
2094#endif
2095
2096/*
2097 * "changenr()" function
2098 */
2099 static void
2100f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2101{
2102 rettv->vval.v_number = curbuf->b_u_seq_cur;
2103}
2104
2105/*
2106 * "char2nr(string)" function
2107 */
2108 static void
2109f_char2nr(typval_T *argvars, typval_T *rettv)
2110{
2111#ifdef FEAT_MBYTE
2112 if (has_mbyte)
2113 {
2114 int utf8 = 0;
2115
2116 if (argvars[1].v_type != VAR_UNKNOWN)
2117 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2118
2119 if (utf8)
2120 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2121 else
2122 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2123 }
2124 else
2125#endif
2126 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2127}
2128
2129/*
2130 * "cindent(lnum)" function
2131 */
2132 static void
2133f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2134{
2135#ifdef FEAT_CINDENT
2136 pos_T pos;
2137 linenr_T lnum;
2138
2139 pos = curwin->w_cursor;
2140 lnum = get_tv_lnum(argvars);
2141 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2142 {
2143 curwin->w_cursor.lnum = lnum;
2144 rettv->vval.v_number = get_c_indent();
2145 curwin->w_cursor = pos;
2146 }
2147 else
2148#endif
2149 rettv->vval.v_number = -1;
2150}
2151
2152/*
2153 * "clearmatches()" function
2154 */
2155 static void
2156f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2157{
2158#ifdef FEAT_SEARCH_EXTRA
2159 clear_matches(curwin);
2160#endif
2161}
2162
2163/*
2164 * "col(string)" function
2165 */
2166 static void
2167f_col(typval_T *argvars, typval_T *rettv)
2168{
2169 colnr_T col = 0;
2170 pos_T *fp;
2171 int fnum = curbuf->b_fnum;
2172
2173 fp = var2fpos(&argvars[0], FALSE, &fnum);
2174 if (fp != NULL && fnum == curbuf->b_fnum)
2175 {
2176 if (fp->col == MAXCOL)
2177 {
2178 /* '> can be MAXCOL, get the length of the line then */
2179 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2180 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2181 else
2182 col = MAXCOL;
2183 }
2184 else
2185 {
2186 col = fp->col + 1;
2187#ifdef FEAT_VIRTUALEDIT
2188 /* col(".") when the cursor is on the NUL at the end of the line
2189 * because of "coladd" can be seen as an extra column. */
2190 if (virtual_active() && fp == &curwin->w_cursor)
2191 {
2192 char_u *p = ml_get_cursor();
2193
2194 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2195 curwin->w_virtcol - curwin->w_cursor.coladd))
2196 {
2197# ifdef FEAT_MBYTE
2198 int l;
2199
2200 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2201 col += l;
2202# else
2203 if (*p != NUL && p[1] == NUL)
2204 ++col;
2205# endif
2206 }
2207 }
2208#endif
2209 }
2210 }
2211 rettv->vval.v_number = col;
2212}
2213
2214#if defined(FEAT_INS_EXPAND)
2215/*
2216 * "complete()" function
2217 */
2218 static void
2219f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2220{
2221 int startcol;
2222
2223 if ((State & INSERT) == 0)
2224 {
2225 EMSG(_("E785: complete() can only be used in Insert mode"));
2226 return;
2227 }
2228
2229 /* Check for undo allowed here, because if something was already inserted
2230 * the line was already saved for undo and this check isn't done. */
2231 if (!undo_allowed())
2232 return;
2233
2234 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2235 {
2236 EMSG(_(e_invarg));
2237 return;
2238 }
2239
2240 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2241 if (startcol <= 0)
2242 return;
2243
2244 set_completion(startcol - 1, argvars[1].vval.v_list);
2245}
2246
2247/*
2248 * "complete_add()" function
2249 */
2250 static void
2251f_complete_add(typval_T *argvars, typval_T *rettv)
2252{
2253 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2254}
2255
2256/*
2257 * "complete_check()" function
2258 */
2259 static void
2260f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2261{
2262 int saved = RedrawingDisabled;
2263
2264 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002265 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 rettv->vval.v_number = compl_interrupted;
2267 RedrawingDisabled = saved;
2268}
2269#endif
2270
2271/*
2272 * "confirm(message, buttons[, default [, type]])" function
2273 */
2274 static void
2275f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2276{
2277#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2278 char_u *message;
2279 char_u *buttons = NULL;
2280 char_u buf[NUMBUFLEN];
2281 char_u buf2[NUMBUFLEN];
2282 int def = 1;
2283 int type = VIM_GENERIC;
2284 char_u *typestr;
2285 int error = FALSE;
2286
2287 message = get_tv_string_chk(&argvars[0]);
2288 if (message == NULL)
2289 error = TRUE;
2290 if (argvars[1].v_type != VAR_UNKNOWN)
2291 {
2292 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2293 if (buttons == NULL)
2294 error = TRUE;
2295 if (argvars[2].v_type != VAR_UNKNOWN)
2296 {
2297 def = (int)get_tv_number_chk(&argvars[2], &error);
2298 if (argvars[3].v_type != VAR_UNKNOWN)
2299 {
2300 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2301 if (typestr == NULL)
2302 error = TRUE;
2303 else
2304 {
2305 switch (TOUPPER_ASC(*typestr))
2306 {
2307 case 'E': type = VIM_ERROR; break;
2308 case 'Q': type = VIM_QUESTION; break;
2309 case 'I': type = VIM_INFO; break;
2310 case 'W': type = VIM_WARNING; break;
2311 case 'G': type = VIM_GENERIC; break;
2312 }
2313 }
2314 }
2315 }
2316 }
2317
2318 if (buttons == NULL || *buttons == NUL)
2319 buttons = (char_u *)_("&Ok");
2320
2321 if (!error)
2322 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2323 def, NULL, FALSE);
2324#endif
2325}
2326
2327/*
2328 * "copy()" function
2329 */
2330 static void
2331f_copy(typval_T *argvars, typval_T *rettv)
2332{
2333 item_copy(&argvars[0], rettv, FALSE, 0);
2334}
2335
2336#ifdef FEAT_FLOAT
2337/*
2338 * "cos()" function
2339 */
2340 static void
2341f_cos(typval_T *argvars, typval_T *rettv)
2342{
2343 float_T f = 0.0;
2344
2345 rettv->v_type = VAR_FLOAT;
2346 if (get_float_arg(argvars, &f) == OK)
2347 rettv->vval.v_float = cos(f);
2348 else
2349 rettv->vval.v_float = 0.0;
2350}
2351
2352/*
2353 * "cosh()" function
2354 */
2355 static void
2356f_cosh(typval_T *argvars, typval_T *rettv)
2357{
2358 float_T f = 0.0;
2359
2360 rettv->v_type = VAR_FLOAT;
2361 if (get_float_arg(argvars, &f) == OK)
2362 rettv->vval.v_float = cosh(f);
2363 else
2364 rettv->vval.v_float = 0.0;
2365}
2366#endif
2367
2368/*
2369 * "count()" function
2370 */
2371 static void
2372f_count(typval_T *argvars, typval_T *rettv)
2373{
2374 long n = 0;
2375 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002376 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002377
Bram Moolenaar9966b212017-07-28 16:46:57 +02002378 if (argvars[2].v_type != VAR_UNKNOWN)
2379 ic = (int)get_tv_number_chk(&argvars[2], &error);
2380
2381 if (argvars[0].v_type == VAR_STRING)
2382 {
2383 char_u *expr = get_tv_string_chk(&argvars[1]);
2384 char_u *p = argvars[0].vval.v_string;
2385 char_u *next;
2386
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002387 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002388 {
2389 if (ic)
2390 {
2391 size_t len = STRLEN(expr);
2392
2393 while (*p != NUL)
2394 {
2395 if (MB_STRNICMP(p, expr, len) == 0)
2396 {
2397 ++n;
2398 p += len;
2399 }
2400 else
2401 MB_PTR_ADV(p);
2402 }
2403 }
2404 else
2405 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2406 != NULL)
2407 {
2408 ++n;
2409 p = next + STRLEN(expr);
2410 }
2411 }
2412
2413 }
2414 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002415 {
2416 listitem_T *li;
2417 list_T *l;
2418 long idx;
2419
2420 if ((l = argvars[0].vval.v_list) != NULL)
2421 {
2422 li = l->lv_first;
2423 if (argvars[2].v_type != VAR_UNKNOWN)
2424 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002425 if (argvars[3].v_type != VAR_UNKNOWN)
2426 {
2427 idx = (long)get_tv_number_chk(&argvars[3], &error);
2428 if (!error)
2429 {
2430 li = list_find(l, idx);
2431 if (li == NULL)
2432 EMSGN(_(e_listidx), idx);
2433 }
2434 }
2435 if (error)
2436 li = NULL;
2437 }
2438
2439 for ( ; li != NULL; li = li->li_next)
2440 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2441 ++n;
2442 }
2443 }
2444 else if (argvars[0].v_type == VAR_DICT)
2445 {
2446 int todo;
2447 dict_T *d;
2448 hashitem_T *hi;
2449
2450 if ((d = argvars[0].vval.v_dict) != NULL)
2451 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 if (argvars[2].v_type != VAR_UNKNOWN)
2453 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002454 if (argvars[3].v_type != VAR_UNKNOWN)
2455 EMSG(_(e_invarg));
2456 }
2457
2458 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2459 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2460 {
2461 if (!HASHITEM_EMPTY(hi))
2462 {
2463 --todo;
2464 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2465 ++n;
2466 }
2467 }
2468 }
2469 }
2470 else
2471 EMSG2(_(e_listdictarg), "count()");
2472 rettv->vval.v_number = n;
2473}
2474
2475/*
2476 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2477 *
2478 * Checks the existence of a cscope connection.
2479 */
2480 static void
2481f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2482{
2483#ifdef FEAT_CSCOPE
2484 int num = 0;
2485 char_u *dbpath = NULL;
2486 char_u *prepend = NULL;
2487 char_u buf[NUMBUFLEN];
2488
2489 if (argvars[0].v_type != VAR_UNKNOWN
2490 && argvars[1].v_type != VAR_UNKNOWN)
2491 {
2492 num = (int)get_tv_number(&argvars[0]);
2493 dbpath = get_tv_string(&argvars[1]);
2494 if (argvars[2].v_type != VAR_UNKNOWN)
2495 prepend = get_tv_string_buf(&argvars[2], buf);
2496 }
2497
2498 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2499#endif
2500}
2501
2502/*
2503 * "cursor(lnum, col)" function, or
2504 * "cursor(list)"
2505 *
2506 * Moves the cursor to the specified line and column.
2507 * Returns 0 when the position could be set, -1 otherwise.
2508 */
2509 static void
2510f_cursor(typval_T *argvars, typval_T *rettv)
2511{
2512 long line, col;
2513#ifdef FEAT_VIRTUALEDIT
2514 long coladd = 0;
2515#endif
2516 int set_curswant = TRUE;
2517
2518 rettv->vval.v_number = -1;
2519 if (argvars[1].v_type == VAR_UNKNOWN)
2520 {
2521 pos_T pos;
2522 colnr_T curswant = -1;
2523
2524 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2525 {
2526 EMSG(_(e_invarg));
2527 return;
2528 }
2529 line = pos.lnum;
2530 col = pos.col;
2531#ifdef FEAT_VIRTUALEDIT
2532 coladd = pos.coladd;
2533#endif
2534 if (curswant >= 0)
2535 {
2536 curwin->w_curswant = curswant - 1;
2537 set_curswant = FALSE;
2538 }
2539 }
2540 else
2541 {
2542 line = get_tv_lnum(argvars);
2543 col = (long)get_tv_number_chk(&argvars[1], NULL);
2544#ifdef FEAT_VIRTUALEDIT
2545 if (argvars[2].v_type != VAR_UNKNOWN)
2546 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2547#endif
2548 }
2549 if (line < 0 || col < 0
2550#ifdef FEAT_VIRTUALEDIT
2551 || coladd < 0
2552#endif
2553 )
2554 return; /* type error; errmsg already given */
2555 if (line > 0)
2556 curwin->w_cursor.lnum = line;
2557 if (col > 0)
2558 curwin->w_cursor.col = col - 1;
2559#ifdef FEAT_VIRTUALEDIT
2560 curwin->w_cursor.coladd = coladd;
2561#endif
2562
2563 /* Make sure the cursor is in a valid position. */
2564 check_cursor();
2565#ifdef FEAT_MBYTE
2566 /* Correct cursor for multi-byte character. */
2567 if (has_mbyte)
2568 mb_adjust_cursor();
2569#endif
2570
2571 curwin->w_set_curswant = set_curswant;
2572 rettv->vval.v_number = 0;
2573}
2574
2575/*
2576 * "deepcopy()" function
2577 */
2578 static void
2579f_deepcopy(typval_T *argvars, typval_T *rettv)
2580{
2581 int noref = 0;
2582 int copyID;
2583
2584 if (argvars[1].v_type != VAR_UNKNOWN)
2585 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2586 if (noref < 0 || noref > 1)
2587 EMSG(_(e_invarg));
2588 else
2589 {
2590 copyID = get_copyID();
2591 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2592 }
2593}
2594
2595/*
2596 * "delete()" function
2597 */
2598 static void
2599f_delete(typval_T *argvars, typval_T *rettv)
2600{
2601 char_u nbuf[NUMBUFLEN];
2602 char_u *name;
2603 char_u *flags;
2604
2605 rettv->vval.v_number = -1;
2606 if (check_restricted() || check_secure())
2607 return;
2608
2609 name = get_tv_string(&argvars[0]);
2610 if (name == NULL || *name == NUL)
2611 {
2612 EMSG(_(e_invarg));
2613 return;
2614 }
2615
2616 if (argvars[1].v_type != VAR_UNKNOWN)
2617 flags = get_tv_string_buf(&argvars[1], nbuf);
2618 else
2619 flags = (char_u *)"";
2620
2621 if (*flags == NUL)
2622 /* delete a file */
2623 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2624 else if (STRCMP(flags, "d") == 0)
2625 /* delete an empty directory */
2626 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2627 else if (STRCMP(flags, "rf") == 0)
2628 /* delete a directory recursively */
2629 rettv->vval.v_number = delete_recursive(name);
2630 else
2631 EMSG2(_(e_invexpr2), flags);
2632}
2633
2634/*
2635 * "did_filetype()" function
2636 */
2637 static void
2638f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2639{
2640#ifdef FEAT_AUTOCMD
2641 rettv->vval.v_number = did_filetype;
2642#endif
2643}
2644
2645/*
2646 * "diff_filler()" function
2647 */
2648 static void
2649f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2650{
2651#ifdef FEAT_DIFF
2652 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2653#endif
2654}
2655
2656/*
2657 * "diff_hlID()" function
2658 */
2659 static void
2660f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2661{
2662#ifdef FEAT_DIFF
2663 linenr_T lnum = get_tv_lnum(argvars);
2664 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002665 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666 static int fnum = 0;
2667 static int change_start = 0;
2668 static int change_end = 0;
2669 static hlf_T hlID = (hlf_T)0;
2670 int filler_lines;
2671 int col;
2672
2673 if (lnum < 0) /* ignore type error in {lnum} arg */
2674 lnum = 0;
2675 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002676 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 || fnum != curbuf->b_fnum)
2678 {
2679 /* New line, buffer, change: need to get the values. */
2680 filler_lines = diff_check(curwin, lnum);
2681 if (filler_lines < 0)
2682 {
2683 if (filler_lines == -1)
2684 {
2685 change_start = MAXCOL;
2686 change_end = -1;
2687 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2688 hlID = HLF_ADD; /* added line */
2689 else
2690 hlID = HLF_CHD; /* changed line */
2691 }
2692 else
2693 hlID = HLF_ADD; /* added line */
2694 }
2695 else
2696 hlID = (hlf_T)0;
2697 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002698 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699 fnum = curbuf->b_fnum;
2700 }
2701
2702 if (hlID == HLF_CHD || hlID == HLF_TXD)
2703 {
2704 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2705 if (col >= change_start && col <= change_end)
2706 hlID = HLF_TXD; /* changed text */
2707 else
2708 hlID = HLF_CHD; /* changed line */
2709 }
2710 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2711#endif
2712}
2713
2714/*
2715 * "empty({expr})" function
2716 */
2717 static void
2718f_empty(typval_T *argvars, typval_T *rettv)
2719{
2720 int n = FALSE;
2721
2722 switch (argvars[0].v_type)
2723 {
2724 case VAR_STRING:
2725 case VAR_FUNC:
2726 n = argvars[0].vval.v_string == NULL
2727 || *argvars[0].vval.v_string == NUL;
2728 break;
2729 case VAR_PARTIAL:
2730 n = FALSE;
2731 break;
2732 case VAR_NUMBER:
2733 n = argvars[0].vval.v_number == 0;
2734 break;
2735 case VAR_FLOAT:
2736#ifdef FEAT_FLOAT
2737 n = argvars[0].vval.v_float == 0.0;
2738 break;
2739#endif
2740 case VAR_LIST:
2741 n = argvars[0].vval.v_list == NULL
2742 || argvars[0].vval.v_list->lv_first == NULL;
2743 break;
2744 case VAR_DICT:
2745 n = argvars[0].vval.v_dict == NULL
2746 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2747 break;
2748 case VAR_SPECIAL:
2749 n = argvars[0].vval.v_number != VVAL_TRUE;
2750 break;
2751
2752 case VAR_JOB:
2753#ifdef FEAT_JOB_CHANNEL
2754 n = argvars[0].vval.v_job == NULL
2755 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2756 break;
2757#endif
2758 case VAR_CHANNEL:
2759#ifdef FEAT_JOB_CHANNEL
2760 n = argvars[0].vval.v_channel == NULL
2761 || !channel_is_open(argvars[0].vval.v_channel);
2762 break;
2763#endif
2764 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002765 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002766 n = TRUE;
2767 break;
2768 }
2769
2770 rettv->vval.v_number = n;
2771}
2772
2773/*
2774 * "escape({string}, {chars})" function
2775 */
2776 static void
2777f_escape(typval_T *argvars, typval_T *rettv)
2778{
2779 char_u buf[NUMBUFLEN];
2780
2781 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2782 get_tv_string_buf(&argvars[1], buf));
2783 rettv->v_type = VAR_STRING;
2784}
2785
2786/*
2787 * "eval()" function
2788 */
2789 static void
2790f_eval(typval_T *argvars, typval_T *rettv)
2791{
2792 char_u *s, *p;
2793
2794 s = get_tv_string_chk(&argvars[0]);
2795 if (s != NULL)
2796 s = skipwhite(s);
2797
2798 p = s;
2799 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2800 {
2801 if (p != NULL && !aborting())
2802 EMSG2(_(e_invexpr2), p);
2803 need_clr_eos = FALSE;
2804 rettv->v_type = VAR_NUMBER;
2805 rettv->vval.v_number = 0;
2806 }
2807 else if (*s != NUL)
2808 EMSG(_(e_trailing));
2809}
2810
2811/*
2812 * "eventhandler()" function
2813 */
2814 static void
2815f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2816{
2817 rettv->vval.v_number = vgetc_busy;
2818}
2819
2820/*
2821 * "executable()" function
2822 */
2823 static void
2824f_executable(typval_T *argvars, typval_T *rettv)
2825{
2826 char_u *name = get_tv_string(&argvars[0]);
2827
2828 /* Check in $PATH and also check directly if there is a directory name. */
2829 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2830 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2831}
2832
2833static garray_T redir_execute_ga;
2834
2835/*
2836 * Append "value[value_len]" to the execute() output.
2837 */
2838 void
2839execute_redir_str(char_u *value, int value_len)
2840{
2841 int len;
2842
2843 if (value_len == -1)
2844 len = (int)STRLEN(value); /* Append the entire string */
2845 else
2846 len = value_len; /* Append only "value_len" characters */
2847 if (ga_grow(&redir_execute_ga, len) == OK)
2848 {
2849 mch_memmove((char *)redir_execute_ga.ga_data
2850 + redir_execute_ga.ga_len, value, len);
2851 redir_execute_ga.ga_len += len;
2852 }
2853}
2854
2855/*
2856 * Get next line from a list.
2857 * Called by do_cmdline() to get the next line.
2858 * Returns allocated string, or NULL for end of function.
2859 */
2860
2861 static char_u *
2862get_list_line(
2863 int c UNUSED,
2864 void *cookie,
2865 int indent UNUSED)
2866{
2867 listitem_T **p = (listitem_T **)cookie;
2868 listitem_T *item = *p;
2869 char_u buf[NUMBUFLEN];
2870 char_u *s;
2871
2872 if (item == NULL)
2873 return NULL;
2874 s = get_tv_string_buf_chk(&item->li_tv, buf);
2875 *p = item->li_next;
2876 return s == NULL ? NULL : vim_strsave(s);
2877}
2878
2879/*
2880 * "execute()" function
2881 */
2882 static void
2883f_execute(typval_T *argvars, typval_T *rettv)
2884{
2885 char_u *cmd = NULL;
2886 list_T *list = NULL;
2887 int save_msg_silent = msg_silent;
2888 int save_emsg_silent = emsg_silent;
2889 int save_emsg_noredir = emsg_noredir;
2890 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002891 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002892 garray_T save_ga;
2893
2894 rettv->vval.v_string = NULL;
2895 rettv->v_type = VAR_STRING;
2896
2897 if (argvars[0].v_type == VAR_LIST)
2898 {
2899 list = argvars[0].vval.v_list;
2900 if (list == NULL || list->lv_first == NULL)
2901 /* empty list, no commands, empty output */
2902 return;
2903 ++list->lv_refcount;
2904 }
2905 else
2906 {
2907 cmd = get_tv_string_chk(&argvars[0]);
2908 if (cmd == NULL)
2909 return;
2910 }
2911
2912 if (argvars[1].v_type != VAR_UNKNOWN)
2913 {
2914 char_u buf[NUMBUFLEN];
2915 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2916
2917 if (s == NULL)
2918 return;
2919 if (STRNCMP(s, "silent", 6) == 0)
2920 ++msg_silent;
2921 if (STRCMP(s, "silent!") == 0)
2922 {
2923 emsg_silent = TRUE;
2924 emsg_noredir = TRUE;
2925 }
2926 }
2927 else
2928 ++msg_silent;
2929
2930 if (redir_execute)
2931 save_ga = redir_execute_ga;
2932 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2933 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002934 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002935
2936 if (cmd != NULL)
2937 do_cmdline_cmd(cmd);
2938 else
2939 {
2940 listitem_T *item = list->lv_first;
2941
2942 do_cmdline(NULL, get_list_line, (void *)&item,
2943 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2944 --list->lv_refcount;
2945 }
2946
Bram Moolenaard297f352017-01-29 20:31:21 +01002947 /* Need to append a NUL to the result. */
2948 if (ga_grow(&redir_execute_ga, 1) == OK)
2949 {
2950 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2951 rettv->vval.v_string = redir_execute_ga.ga_data;
2952 }
2953 else
2954 {
2955 ga_clear(&redir_execute_ga);
2956 rettv->vval.v_string = NULL;
2957 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002958 msg_silent = save_msg_silent;
2959 emsg_silent = save_emsg_silent;
2960 emsg_noredir = save_emsg_noredir;
2961
2962 redir_execute = save_redir_execute;
2963 if (redir_execute)
2964 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002965 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002966
2967 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
2968 * line. Put it back in the first column. */
2969 msg_col = 0;
2970}
2971
2972/*
2973 * "exepath()" function
2974 */
2975 static void
2976f_exepath(typval_T *argvars, typval_T *rettv)
2977{
2978 char_u *p = NULL;
2979
2980 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
2981 rettv->v_type = VAR_STRING;
2982 rettv->vval.v_string = p;
2983}
2984
2985/*
2986 * "exists()" function
2987 */
2988 static void
2989f_exists(typval_T *argvars, typval_T *rettv)
2990{
2991 char_u *p;
2992 char_u *name;
2993 int n = FALSE;
2994 int len = 0;
2995
2996 p = get_tv_string(&argvars[0]);
2997 if (*p == '$') /* environment variable */
2998 {
2999 /* first try "normal" environment variables (fast) */
3000 if (mch_getenv(p + 1) != NULL)
3001 n = TRUE;
3002 else
3003 {
3004 /* try expanding things like $VIM and ${HOME} */
3005 p = expand_env_save(p);
3006 if (p != NULL && *p != '$')
3007 n = TRUE;
3008 vim_free(p);
3009 }
3010 }
3011 else if (*p == '&' || *p == '+') /* option */
3012 {
3013 n = (get_option_tv(&p, NULL, TRUE) == OK);
3014 if (*skipwhite(p) != NUL)
3015 n = FALSE; /* trailing garbage */
3016 }
3017 else if (*p == '*') /* internal or user defined function */
3018 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003019 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003020 }
3021 else if (*p == ':')
3022 {
3023 n = cmd_exists(p + 1);
3024 }
3025 else if (*p == '#')
3026 {
3027#ifdef FEAT_AUTOCMD
3028 if (p[1] == '#')
3029 n = autocmd_supported(p + 2);
3030 else
3031 n = au_exists(p + 1);
3032#endif
3033 }
3034 else /* internal variable */
3035 {
3036 char_u *tofree;
3037 typval_T tv;
3038
3039 /* get_name_len() takes care of expanding curly braces */
3040 name = p;
3041 len = get_name_len(&p, &tofree, TRUE, FALSE);
3042 if (len > 0)
3043 {
3044 if (tofree != NULL)
3045 name = tofree;
3046 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
3047 if (n)
3048 {
3049 /* handle d.key, l[idx], f(expr) */
3050 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
3051 if (n)
3052 clear_tv(&tv);
3053 }
3054 }
3055 if (*p != NUL)
3056 n = FALSE;
3057
3058 vim_free(tofree);
3059 }
3060
3061 rettv->vval.v_number = n;
3062}
3063
3064#ifdef FEAT_FLOAT
3065/*
3066 * "exp()" function
3067 */
3068 static void
3069f_exp(typval_T *argvars, typval_T *rettv)
3070{
3071 float_T f = 0.0;
3072
3073 rettv->v_type = VAR_FLOAT;
3074 if (get_float_arg(argvars, &f) == OK)
3075 rettv->vval.v_float = exp(f);
3076 else
3077 rettv->vval.v_float = 0.0;
3078}
3079#endif
3080
3081/*
3082 * "expand()" function
3083 */
3084 static void
3085f_expand(typval_T *argvars, typval_T *rettv)
3086{
3087 char_u *s;
3088 int len;
3089 char_u *errormsg;
3090 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3091 expand_T xpc;
3092 int error = FALSE;
3093 char_u *result;
3094
3095 rettv->v_type = VAR_STRING;
3096 if (argvars[1].v_type != VAR_UNKNOWN
3097 && argvars[2].v_type != VAR_UNKNOWN
3098 && get_tv_number_chk(&argvars[2], &error)
3099 && !error)
3100 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003101 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102 }
3103
3104 s = get_tv_string(&argvars[0]);
3105 if (*s == '%' || *s == '#' || *s == '<')
3106 {
3107 ++emsg_off;
3108 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3109 --emsg_off;
3110 if (rettv->v_type == VAR_LIST)
3111 {
3112 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3113 list_append_string(rettv->vval.v_list, result, -1);
3114 else
3115 vim_free(result);
3116 }
3117 else
3118 rettv->vval.v_string = result;
3119 }
3120 else
3121 {
3122 /* When the optional second argument is non-zero, don't remove matches
3123 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3124 if (argvars[1].v_type != VAR_UNKNOWN
3125 && get_tv_number_chk(&argvars[1], &error))
3126 options |= WILD_KEEP_ALL;
3127 if (!error)
3128 {
3129 ExpandInit(&xpc);
3130 xpc.xp_context = EXPAND_FILES;
3131 if (p_wic)
3132 options += WILD_ICASE;
3133 if (rettv->v_type == VAR_STRING)
3134 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3135 options, WILD_ALL);
3136 else if (rettv_list_alloc(rettv) != FAIL)
3137 {
3138 int i;
3139
3140 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3141 for (i = 0; i < xpc.xp_numfiles; i++)
3142 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3143 ExpandCleanup(&xpc);
3144 }
3145 }
3146 else
3147 rettv->vval.v_string = NULL;
3148 }
3149}
3150
3151/*
3152 * "extend(list, list [, idx])" function
3153 * "extend(dict, dict [, action])" function
3154 */
3155 static void
3156f_extend(typval_T *argvars, typval_T *rettv)
3157{
3158 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3159
3160 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3161 {
3162 list_T *l1, *l2;
3163 listitem_T *item;
3164 long before;
3165 int error = FALSE;
3166
3167 l1 = argvars[0].vval.v_list;
3168 l2 = argvars[1].vval.v_list;
3169 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3170 && l2 != NULL)
3171 {
3172 if (argvars[2].v_type != VAR_UNKNOWN)
3173 {
3174 before = (long)get_tv_number_chk(&argvars[2], &error);
3175 if (error)
3176 return; /* type error; errmsg already given */
3177
3178 if (before == l1->lv_len)
3179 item = NULL;
3180 else
3181 {
3182 item = list_find(l1, before);
3183 if (item == NULL)
3184 {
3185 EMSGN(_(e_listidx), before);
3186 return;
3187 }
3188 }
3189 }
3190 else
3191 item = NULL;
3192 list_extend(l1, l2, item);
3193
3194 copy_tv(&argvars[0], rettv);
3195 }
3196 }
3197 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3198 {
3199 dict_T *d1, *d2;
3200 char_u *action;
3201 int i;
3202
3203 d1 = argvars[0].vval.v_dict;
3204 d2 = argvars[1].vval.v_dict;
3205 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3206 && d2 != NULL)
3207 {
3208 /* Check the third argument. */
3209 if (argvars[2].v_type != VAR_UNKNOWN)
3210 {
3211 static char *(av[]) = {"keep", "force", "error"};
3212
3213 action = get_tv_string_chk(&argvars[2]);
3214 if (action == NULL)
3215 return; /* type error; errmsg already given */
3216 for (i = 0; i < 3; ++i)
3217 if (STRCMP(action, av[i]) == 0)
3218 break;
3219 if (i == 3)
3220 {
3221 EMSG2(_(e_invarg2), action);
3222 return;
3223 }
3224 }
3225 else
3226 action = (char_u *)"force";
3227
3228 dict_extend(d1, d2, action);
3229
3230 copy_tv(&argvars[0], rettv);
3231 }
3232 }
3233 else
3234 EMSG2(_(e_listdictarg), "extend()");
3235}
3236
3237/*
3238 * "feedkeys()" function
3239 */
3240 static void
3241f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3242{
3243 int remap = TRUE;
3244 int insert = FALSE;
3245 char_u *keys, *flags;
3246 char_u nbuf[NUMBUFLEN];
3247 int typed = FALSE;
3248 int execute = FALSE;
3249 int dangerous = FALSE;
3250 char_u *keys_esc;
3251
3252 /* This is not allowed in the sandbox. If the commands would still be
3253 * executed in the sandbox it would be OK, but it probably happens later,
3254 * when "sandbox" is no longer set. */
3255 if (check_secure())
3256 return;
3257
3258 keys = get_tv_string(&argvars[0]);
3259
3260 if (argvars[1].v_type != VAR_UNKNOWN)
3261 {
3262 flags = get_tv_string_buf(&argvars[1], nbuf);
3263 for ( ; *flags != NUL; ++flags)
3264 {
3265 switch (*flags)
3266 {
3267 case 'n': remap = FALSE; break;
3268 case 'm': remap = TRUE; break;
3269 case 't': typed = TRUE; break;
3270 case 'i': insert = TRUE; break;
3271 case 'x': execute = TRUE; break;
3272 case '!': dangerous = TRUE; break;
3273 }
3274 }
3275 }
3276
3277 if (*keys != NUL || execute)
3278 {
3279 /* Need to escape K_SPECIAL and CSI before putting the string in the
3280 * typeahead buffer. */
3281 keys_esc = vim_strsave_escape_csi(keys);
3282 if (keys_esc != NULL)
3283 {
3284 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3285 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3286 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003287 if (vgetc_busy
3288#ifdef FEAT_TIMERS
3289 || timer_busy
3290#endif
3291 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292 typebuf_was_filled = TRUE;
3293 if (execute)
3294 {
3295 int save_msg_scroll = msg_scroll;
3296
3297 /* Avoid a 1 second delay when the keys start Insert mode. */
3298 msg_scroll = FALSE;
3299
Bram Moolenaar69fbc9e2017-09-14 20:37:57 +02003300#ifdef FEAT_TERMINAL
3301 if (term_use_loop())
3302 terminal_loop(FALSE);
3303 else
3304#endif
3305 {
3306 if (!dangerous)
3307 ++ex_normal_busy;
3308 exec_normal(TRUE);
3309 if (!dangerous)
3310 --ex_normal_busy;
3311 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312 msg_scroll |= save_msg_scroll;
3313 }
3314 }
3315 }
3316}
3317
3318/*
3319 * "filereadable()" function
3320 */
3321 static void
3322f_filereadable(typval_T *argvars, typval_T *rettv)
3323{
3324 int fd;
3325 char_u *p;
3326 int n;
3327
3328#ifndef O_NONBLOCK
3329# define O_NONBLOCK 0
3330#endif
3331 p = get_tv_string(&argvars[0]);
3332 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3333 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3334 {
3335 n = TRUE;
3336 close(fd);
3337 }
3338 else
3339 n = FALSE;
3340
3341 rettv->vval.v_number = n;
3342}
3343
3344/*
3345 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3346 * rights to write into.
3347 */
3348 static void
3349f_filewritable(typval_T *argvars, typval_T *rettv)
3350{
3351 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3352}
3353
3354 static void
3355findfilendir(
3356 typval_T *argvars UNUSED,
3357 typval_T *rettv,
3358 int find_what UNUSED)
3359{
3360#ifdef FEAT_SEARCHPATH
3361 char_u *fname;
3362 char_u *fresult = NULL;
3363 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3364 char_u *p;
3365 char_u pathbuf[NUMBUFLEN];
3366 int count = 1;
3367 int first = TRUE;
3368 int error = FALSE;
3369#endif
3370
3371 rettv->vval.v_string = NULL;
3372 rettv->v_type = VAR_STRING;
3373
3374#ifdef FEAT_SEARCHPATH
3375 fname = get_tv_string(&argvars[0]);
3376
3377 if (argvars[1].v_type != VAR_UNKNOWN)
3378 {
3379 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3380 if (p == NULL)
3381 error = TRUE;
3382 else
3383 {
3384 if (*p != NUL)
3385 path = p;
3386
3387 if (argvars[2].v_type != VAR_UNKNOWN)
3388 count = (int)get_tv_number_chk(&argvars[2], &error);
3389 }
3390 }
3391
3392 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3393 error = TRUE;
3394
3395 if (*fname != NUL && !error)
3396 {
3397 do
3398 {
3399 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3400 vim_free(fresult);
3401 fresult = find_file_in_path_option(first ? fname : NULL,
3402 first ? (int)STRLEN(fname) : 0,
3403 0, first, path,
3404 find_what,
3405 curbuf->b_ffname,
3406 find_what == FINDFILE_DIR
3407 ? (char_u *)"" : curbuf->b_p_sua);
3408 first = FALSE;
3409
3410 if (fresult != NULL && rettv->v_type == VAR_LIST)
3411 list_append_string(rettv->vval.v_list, fresult, -1);
3412
3413 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3414 }
3415
3416 if (rettv->v_type == VAR_STRING)
3417 rettv->vval.v_string = fresult;
3418#endif
3419}
3420
3421/*
3422 * "filter()" function
3423 */
3424 static void
3425f_filter(typval_T *argvars, typval_T *rettv)
3426{
3427 filter_map(argvars, rettv, FALSE);
3428}
3429
3430/*
3431 * "finddir({fname}[, {path}[, {count}]])" function
3432 */
3433 static void
3434f_finddir(typval_T *argvars, typval_T *rettv)
3435{
3436 findfilendir(argvars, rettv, FINDFILE_DIR);
3437}
3438
3439/*
3440 * "findfile({fname}[, {path}[, {count}]])" function
3441 */
3442 static void
3443f_findfile(typval_T *argvars, typval_T *rettv)
3444{
3445 findfilendir(argvars, rettv, FINDFILE_FILE);
3446}
3447
3448#ifdef FEAT_FLOAT
3449/*
3450 * "float2nr({float})" function
3451 */
3452 static void
3453f_float2nr(typval_T *argvars, typval_T *rettv)
3454{
3455 float_T f = 0.0;
3456
3457 if (get_float_arg(argvars, &f) == OK)
3458 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003459 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003460 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003461 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003462 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003463 else
3464 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003465 }
3466}
3467
3468/*
3469 * "floor({float})" function
3470 */
3471 static void
3472f_floor(typval_T *argvars, typval_T *rettv)
3473{
3474 float_T f = 0.0;
3475
3476 rettv->v_type = VAR_FLOAT;
3477 if (get_float_arg(argvars, &f) == OK)
3478 rettv->vval.v_float = floor(f);
3479 else
3480 rettv->vval.v_float = 0.0;
3481}
3482
3483/*
3484 * "fmod()" function
3485 */
3486 static void
3487f_fmod(typval_T *argvars, typval_T *rettv)
3488{
3489 float_T fx = 0.0, fy = 0.0;
3490
3491 rettv->v_type = VAR_FLOAT;
3492 if (get_float_arg(argvars, &fx) == OK
3493 && get_float_arg(&argvars[1], &fy) == OK)
3494 rettv->vval.v_float = fmod(fx, fy);
3495 else
3496 rettv->vval.v_float = 0.0;
3497}
3498#endif
3499
3500/*
3501 * "fnameescape({string})" function
3502 */
3503 static void
3504f_fnameescape(typval_T *argvars, typval_T *rettv)
3505{
3506 rettv->vval.v_string = vim_strsave_fnameescape(
3507 get_tv_string(&argvars[0]), FALSE);
3508 rettv->v_type = VAR_STRING;
3509}
3510
3511/*
3512 * "fnamemodify({fname}, {mods})" function
3513 */
3514 static void
3515f_fnamemodify(typval_T *argvars, typval_T *rettv)
3516{
3517 char_u *fname;
3518 char_u *mods;
3519 int usedlen = 0;
3520 int len;
3521 char_u *fbuf = NULL;
3522 char_u buf[NUMBUFLEN];
3523
3524 fname = get_tv_string_chk(&argvars[0]);
3525 mods = get_tv_string_buf_chk(&argvars[1], buf);
3526 if (fname == NULL || mods == NULL)
3527 fname = NULL;
3528 else
3529 {
3530 len = (int)STRLEN(fname);
3531 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3532 }
3533
3534 rettv->v_type = VAR_STRING;
3535 if (fname == NULL)
3536 rettv->vval.v_string = NULL;
3537 else
3538 rettv->vval.v_string = vim_strnsave(fname, len);
3539 vim_free(fbuf);
3540}
3541
3542static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3543
3544/*
3545 * "foldclosed()" function
3546 */
3547 static void
3548foldclosed_both(
3549 typval_T *argvars UNUSED,
3550 typval_T *rettv,
3551 int end UNUSED)
3552{
3553#ifdef FEAT_FOLDING
3554 linenr_T lnum;
3555 linenr_T first, last;
3556
3557 lnum = get_tv_lnum(argvars);
3558 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3559 {
3560 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3561 {
3562 if (end)
3563 rettv->vval.v_number = (varnumber_T)last;
3564 else
3565 rettv->vval.v_number = (varnumber_T)first;
3566 return;
3567 }
3568 }
3569#endif
3570 rettv->vval.v_number = -1;
3571}
3572
3573/*
3574 * "foldclosed()" function
3575 */
3576 static void
3577f_foldclosed(typval_T *argvars, typval_T *rettv)
3578{
3579 foldclosed_both(argvars, rettv, FALSE);
3580}
3581
3582/*
3583 * "foldclosedend()" function
3584 */
3585 static void
3586f_foldclosedend(typval_T *argvars, typval_T *rettv)
3587{
3588 foldclosed_both(argvars, rettv, TRUE);
3589}
3590
3591/*
3592 * "foldlevel()" function
3593 */
3594 static void
3595f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3596{
3597#ifdef FEAT_FOLDING
3598 linenr_T lnum;
3599
3600 lnum = get_tv_lnum(argvars);
3601 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3602 rettv->vval.v_number = foldLevel(lnum);
3603#endif
3604}
3605
3606/*
3607 * "foldtext()" function
3608 */
3609 static void
3610f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3611{
3612#ifdef FEAT_FOLDING
3613 linenr_T foldstart;
3614 linenr_T foldend;
3615 char_u *dashes;
3616 linenr_T lnum;
3617 char_u *s;
3618 char_u *r;
3619 int len;
3620 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003621 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003622#endif
3623
3624 rettv->v_type = VAR_STRING;
3625 rettv->vval.v_string = NULL;
3626#ifdef FEAT_FOLDING
3627 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3628 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3629 dashes = get_vim_var_str(VV_FOLDDASHES);
3630 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3631 && dashes != NULL)
3632 {
3633 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003634 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635 if (!linewhite(lnum))
3636 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637
3638 /* Find interesting text in this line. */
3639 s = skipwhite(ml_get(lnum));
3640 /* skip C comment-start */
3641 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3642 {
3643 s = skipwhite(s + 2);
3644 if (*skipwhite(s) == NUL
3645 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3646 {
3647 s = skipwhite(ml_get(lnum + 1));
3648 if (*s == '*')
3649 s = skipwhite(s + 1);
3650 }
3651 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003652 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003653 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 r = alloc((unsigned)(STRLEN(txt)
3655 + STRLEN(dashes) /* for %s */
3656 + 20 /* for %3ld */
3657 + STRLEN(s))); /* concatenated */
3658 if (r != NULL)
3659 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003660 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661 len = (int)STRLEN(r);
3662 STRCAT(r, s);
3663 /* remove 'foldmarker' and 'commentstring' */
3664 foldtext_cleanup(r + len);
3665 rettv->vval.v_string = r;
3666 }
3667 }
3668#endif
3669}
3670
3671/*
3672 * "foldtextresult(lnum)" function
3673 */
3674 static void
3675f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3676{
3677#ifdef FEAT_FOLDING
3678 linenr_T lnum;
3679 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003680 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681 foldinfo_T foldinfo;
3682 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003683 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003684#endif
3685
3686 rettv->v_type = VAR_STRING;
3687 rettv->vval.v_string = NULL;
3688#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003689 if (entered)
3690 return; /* reject recursive use */
3691 entered = TRUE;
3692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003693 lnum = get_tv_lnum(argvars);
3694 /* treat illegal types and illegal string values for {lnum} the same */
3695 if (lnum < 0)
3696 lnum = 0;
3697 fold_count = foldedCount(curwin, lnum, &foldinfo);
3698 if (fold_count > 0)
3699 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003700 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3701 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003702 if (text == buf)
3703 text = vim_strsave(text);
3704 rettv->vval.v_string = text;
3705 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003706
3707 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003708#endif
3709}
3710
3711/*
3712 * "foreground()" function
3713 */
3714 static void
3715f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3716{
3717#ifdef FEAT_GUI
3718 if (gui.in_use)
3719 gui_mch_set_foreground();
3720#else
3721# ifdef WIN32
3722 win32_set_foreground();
3723# endif
3724#endif
3725}
3726
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003728common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003729{
3730 char_u *s;
3731 char_u *name;
3732 int use_string = FALSE;
3733 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003734 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735
3736 if (argvars[0].v_type == VAR_FUNC)
3737 {
3738 /* function(MyFunc, [arg], dict) */
3739 s = argvars[0].vval.v_string;
3740 }
3741 else if (argvars[0].v_type == VAR_PARTIAL
3742 && argvars[0].vval.v_partial != NULL)
3743 {
3744 /* function(dict.MyFunc, [arg]) */
3745 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003746 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747 }
3748 else
3749 {
3750 /* function('MyFunc', [arg], dict) */
3751 s = get_tv_string(&argvars[0]);
3752 use_string = TRUE;
3753 }
3754
Bram Moolenaar843b8842016-08-21 14:36:15 +02003755 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003756 {
3757 name = s;
3758 trans_name = trans_function_name(&name, FALSE,
3759 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3760 if (*name != NUL)
3761 s = NULL;
3762 }
3763
Bram Moolenaar843b8842016-08-21 14:36:15 +02003764 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3765 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02003766 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003768 else if (trans_name != NULL && (is_funcref
3769 ? find_func(trans_name) == NULL
3770 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003771 EMSG2(_("E700: Unknown function: %s"), s);
3772 else
3773 {
3774 int dict_idx = 0;
3775 int arg_idx = 0;
3776 list_T *list = NULL;
3777
3778 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3779 {
3780 char sid_buf[25];
3781 int off = *s == 's' ? 2 : 5;
3782
3783 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3784 * also be called from another script. Using trans_function_name()
3785 * would also work, but some plugins depend on the name being
3786 * printable text. */
3787 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3788 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3789 if (name != NULL)
3790 {
3791 STRCPY(name, sid_buf);
3792 STRCAT(name, s + off);
3793 }
3794 }
3795 else
3796 name = vim_strsave(s);
3797
3798 if (argvars[1].v_type != VAR_UNKNOWN)
3799 {
3800 if (argvars[2].v_type != VAR_UNKNOWN)
3801 {
3802 /* function(name, [args], dict) */
3803 arg_idx = 1;
3804 dict_idx = 2;
3805 }
3806 else if (argvars[1].v_type == VAR_DICT)
3807 /* function(name, dict) */
3808 dict_idx = 1;
3809 else
3810 /* function(name, [args]) */
3811 arg_idx = 1;
3812 if (dict_idx > 0)
3813 {
3814 if (argvars[dict_idx].v_type != VAR_DICT)
3815 {
3816 EMSG(_("E922: expected a dict"));
3817 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003818 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003819 }
3820 if (argvars[dict_idx].vval.v_dict == NULL)
3821 dict_idx = 0;
3822 }
3823 if (arg_idx > 0)
3824 {
3825 if (argvars[arg_idx].v_type != VAR_LIST)
3826 {
3827 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3828 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003829 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003830 }
3831 list = argvars[arg_idx].vval.v_list;
3832 if (list == NULL || list->lv_len == 0)
3833 arg_idx = 0;
3834 }
3835 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003836 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003837 {
3838 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3839
3840 /* result is a VAR_PARTIAL */
3841 if (pt == NULL)
3842 vim_free(name);
3843 else
3844 {
3845 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3846 {
3847 listitem_T *li;
3848 int i = 0;
3849 int arg_len = 0;
3850 int lv_len = 0;
3851
3852 if (arg_pt != NULL)
3853 arg_len = arg_pt->pt_argc;
3854 if (list != NULL)
3855 lv_len = list->lv_len;
3856 pt->pt_argc = arg_len + lv_len;
3857 pt->pt_argv = (typval_T *)alloc(
3858 sizeof(typval_T) * pt->pt_argc);
3859 if (pt->pt_argv == NULL)
3860 {
3861 vim_free(pt);
3862 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003863 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003865 for (i = 0; i < arg_len; i++)
3866 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3867 if (lv_len > 0)
3868 for (li = list->lv_first; li != NULL;
3869 li = li->li_next)
3870 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871 }
3872
3873 /* For "function(dict.func, [], dict)" and "func" is a partial
3874 * use "dict". That is backwards compatible. */
3875 if (dict_idx > 0)
3876 {
3877 /* The dict is bound explicitly, pt_auto is FALSE. */
3878 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3879 ++pt->pt_dict->dv_refcount;
3880 }
3881 else if (arg_pt != NULL)
3882 {
3883 /* If the dict was bound automatically the result is also
3884 * bound automatically. */
3885 pt->pt_dict = arg_pt->pt_dict;
3886 pt->pt_auto = arg_pt->pt_auto;
3887 if (pt->pt_dict != NULL)
3888 ++pt->pt_dict->dv_refcount;
3889 }
3890
3891 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003892 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3893 {
3894 pt->pt_func = arg_pt->pt_func;
3895 func_ptr_ref(pt->pt_func);
3896 vim_free(name);
3897 }
3898 else if (is_funcref)
3899 {
3900 pt->pt_func = find_func(trans_name);
3901 func_ptr_ref(pt->pt_func);
3902 vim_free(name);
3903 }
3904 else
3905 {
3906 pt->pt_name = name;
3907 func_ref(name);
3908 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 }
3910 rettv->v_type = VAR_PARTIAL;
3911 rettv->vval.v_partial = pt;
3912 }
3913 else
3914 {
3915 /* result is a VAR_FUNC */
3916 rettv->v_type = VAR_FUNC;
3917 rettv->vval.v_string = name;
3918 func_ref(name);
3919 }
3920 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003921theend:
3922 vim_free(trans_name);
3923}
3924
3925/*
3926 * "funcref()" function
3927 */
3928 static void
3929f_funcref(typval_T *argvars, typval_T *rettv)
3930{
3931 common_function(argvars, rettv, TRUE);
3932}
3933
3934/*
3935 * "function()" function
3936 */
3937 static void
3938f_function(typval_T *argvars, typval_T *rettv)
3939{
3940 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941}
3942
3943/*
3944 * "garbagecollect()" function
3945 */
3946 static void
3947f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3948{
3949 /* This is postponed until we are back at the toplevel, because we may be
3950 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3951 want_garbage_collect = TRUE;
3952
3953 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3954 garbage_collect_at_exit = TRUE;
3955}
3956
3957/*
3958 * "get()" function
3959 */
3960 static void
3961f_get(typval_T *argvars, typval_T *rettv)
3962{
3963 listitem_T *li;
3964 list_T *l;
3965 dictitem_T *di;
3966 dict_T *d;
3967 typval_T *tv = NULL;
3968
3969 if (argvars[0].v_type == VAR_LIST)
3970 {
3971 if ((l = argvars[0].vval.v_list) != NULL)
3972 {
3973 int error = FALSE;
3974
3975 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3976 if (!error && li != NULL)
3977 tv = &li->li_tv;
3978 }
3979 }
3980 else if (argvars[0].v_type == VAR_DICT)
3981 {
3982 if ((d = argvars[0].vval.v_dict) != NULL)
3983 {
3984 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3985 if (di != NULL)
3986 tv = &di->di_tv;
3987 }
3988 }
3989 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3990 {
3991 partial_T *pt;
3992 partial_T fref_pt;
3993
3994 if (argvars[0].v_type == VAR_PARTIAL)
3995 pt = argvars[0].vval.v_partial;
3996 else
3997 {
3998 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3999 fref_pt.pt_name = argvars[0].vval.v_string;
4000 pt = &fref_pt;
4001 }
4002
4003 if (pt != NULL)
4004 {
4005 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004006 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007
4008 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4009 {
4010 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004011 n = partial_name(pt);
4012 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 rettv->vval.v_string = NULL;
4014 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004015 {
4016 rettv->vval.v_string = vim_strsave(n);
4017 if (rettv->v_type == VAR_FUNC)
4018 func_ref(rettv->vval.v_string);
4019 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 }
4021 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004022 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023 else if (STRCMP(what, "args") == 0)
4024 {
4025 rettv->v_type = VAR_LIST;
4026 if (rettv_list_alloc(rettv) == OK)
4027 {
4028 int i;
4029
4030 for (i = 0; i < pt->pt_argc; ++i)
4031 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4032 }
4033 }
4034 else
4035 EMSG2(_(e_invarg2), what);
4036 return;
4037 }
4038 }
4039 else
4040 EMSG2(_(e_listdictarg), "get()");
4041
4042 if (tv == NULL)
4043 {
4044 if (argvars[2].v_type != VAR_UNKNOWN)
4045 copy_tv(&argvars[2], rettv);
4046 }
4047 else
4048 copy_tv(tv, rettv);
4049}
4050
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004051#ifdef FEAT_SIGNS
4052/*
4053 * Returns information about signs placed in a buffer as list of dicts.
4054 */
4055 static void
4056get_buffer_signs(buf_T *buf, list_T *l)
4057{
4058 signlist_T *sign;
4059
4060 for (sign = buf->b_signlist; sign; sign = sign->next)
4061 {
4062 dict_T *d = dict_alloc();
4063
4064 if (d != NULL)
4065 {
4066 dict_add_nr_str(d, "id", sign->id, NULL);
4067 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004068 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004069
4070 list_append_dict(l, d);
4071 }
4072 }
4073}
4074#endif
4075
4076/*
4077 * Returns buffer options, variables and other attributes in a dictionary.
4078 */
4079 static dict_T *
4080get_buffer_info(buf_T *buf)
4081{
4082 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004083 tabpage_T *tp;
4084 win_T *wp;
4085 list_T *windows;
4086
4087 dict = dict_alloc();
4088 if (dict == NULL)
4089 return NULL;
4090
Bram Moolenaar33928832016-08-18 21:22:04 +02004091 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004092 dict_add_nr_str(dict, "name", 0L,
4093 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004094 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4095 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004096 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4097 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4098 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004099 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004100 dict_add_nr_str(dict, "hidden",
4101 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4102 NULL);
4103
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004104 /* Get a reference to buffer variables */
4105 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004106
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004107 /* List of windows displaying this buffer */
4108 windows = list_alloc();
4109 if (windows != NULL)
4110 {
4111 FOR_ALL_TAB_WINDOWS(tp, wp)
4112 if (wp->w_buffer == buf)
4113 list_append_number(windows, (varnumber_T)wp->w_id);
4114 dict_add_list(dict, "windows", windows);
4115 }
4116
4117#ifdef FEAT_SIGNS
4118 if (buf->b_signlist != NULL)
4119 {
4120 /* List of signs placed in this buffer */
4121 list_T *signs = list_alloc();
4122 if (signs != NULL)
4123 {
4124 get_buffer_signs(buf, signs);
4125 dict_add_list(dict, "signs", signs);
4126 }
4127 }
4128#endif
4129
4130 return dict;
4131}
4132
4133/*
4134 * "getbufinfo()" function
4135 */
4136 static void
4137f_getbufinfo(typval_T *argvars, typval_T *rettv)
4138{
4139 buf_T *buf = NULL;
4140 buf_T *argbuf = NULL;
4141 dict_T *d;
4142 int filtered = FALSE;
4143 int sel_buflisted = FALSE;
4144 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004145 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004146
4147 if (rettv_list_alloc(rettv) != OK)
4148 return;
4149
4150 /* List of all the buffers or selected buffers */
4151 if (argvars[0].v_type == VAR_DICT)
4152 {
4153 dict_T *sel_d = argvars[0].vval.v_dict;
4154
4155 if (sel_d != NULL)
4156 {
4157 dictitem_T *di;
4158
4159 filtered = TRUE;
4160
4161 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4162 if (di != NULL && get_tv_number(&di->di_tv))
4163 sel_buflisted = TRUE;
4164
4165 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4166 if (di != NULL && get_tv_number(&di->di_tv))
4167 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004168
4169 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4170 if (di != NULL && get_tv_number(&di->di_tv))
4171 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004172 }
4173 }
4174 else if (argvars[0].v_type != VAR_UNKNOWN)
4175 {
4176 /* Information about one buffer. Argument specifies the buffer */
4177 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4178 ++emsg_off;
4179 argbuf = get_buf_tv(&argvars[0], FALSE);
4180 --emsg_off;
4181 if (argbuf == NULL)
4182 return;
4183 }
4184
4185 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004186 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004187 {
4188 if (argbuf != NULL && argbuf != buf)
4189 continue;
4190 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004191 || (sel_buflisted && !buf->b_p_bl)
4192 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004193 continue;
4194
4195 d = get_buffer_info(buf);
4196 if (d != NULL)
4197 list_append_dict(rettv->vval.v_list, d);
4198 if (argbuf != NULL)
4199 return;
4200 }
4201}
4202
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4204
4205/*
4206 * Get line or list of lines from buffer "buf" into "rettv".
4207 * Return a range (from start to end) of lines in rettv from the specified
4208 * buffer.
4209 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4210 */
4211 static void
4212get_buffer_lines(
4213 buf_T *buf,
4214 linenr_T start,
4215 linenr_T end,
4216 int retlist,
4217 typval_T *rettv)
4218{
4219 char_u *p;
4220
4221 rettv->v_type = VAR_STRING;
4222 rettv->vval.v_string = NULL;
4223 if (retlist && rettv_list_alloc(rettv) == FAIL)
4224 return;
4225
4226 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4227 return;
4228
4229 if (!retlist)
4230 {
4231 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4232 p = ml_get_buf(buf, start, FALSE);
4233 else
4234 p = (char_u *)"";
4235 rettv->vval.v_string = vim_strsave(p);
4236 }
4237 else
4238 {
4239 if (end < start)
4240 return;
4241
4242 if (start < 1)
4243 start = 1;
4244 if (end > buf->b_ml.ml_line_count)
4245 end = buf->b_ml.ml_line_count;
4246 while (start <= end)
4247 if (list_append_string(rettv->vval.v_list,
4248 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4249 break;
4250 }
4251}
4252
4253/*
4254 * Get the lnum from the first argument.
4255 * Also accepts "$", then "buf" is used.
4256 * Returns 0 on error.
4257 */
4258 static linenr_T
4259get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4260{
4261 if (argvars[0].v_type == VAR_STRING
4262 && argvars[0].vval.v_string != NULL
4263 && argvars[0].vval.v_string[0] == '$'
4264 && buf != NULL)
4265 return buf->b_ml.ml_line_count;
4266 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4267}
4268
4269/*
4270 * "getbufline()" function
4271 */
4272 static void
4273f_getbufline(typval_T *argvars, typval_T *rettv)
4274{
4275 linenr_T lnum;
4276 linenr_T end;
4277 buf_T *buf;
4278
4279 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4280 ++emsg_off;
4281 buf = get_buf_tv(&argvars[0], FALSE);
4282 --emsg_off;
4283
4284 lnum = get_tv_lnum_buf(&argvars[1], buf);
4285 if (argvars[2].v_type == VAR_UNKNOWN)
4286 end = lnum;
4287 else
4288 end = get_tv_lnum_buf(&argvars[2], buf);
4289
4290 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4291}
4292
4293/*
4294 * "getbufvar()" function
4295 */
4296 static void
4297f_getbufvar(typval_T *argvars, typval_T *rettv)
4298{
4299 buf_T *buf;
4300 buf_T *save_curbuf;
4301 char_u *varname;
4302 dictitem_T *v;
4303 int done = FALSE;
4304
4305 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4306 varname = get_tv_string_chk(&argvars[1]);
4307 ++emsg_off;
4308 buf = get_buf_tv(&argvars[0], FALSE);
4309
4310 rettv->v_type = VAR_STRING;
4311 rettv->vval.v_string = NULL;
4312
4313 if (buf != NULL && varname != NULL)
4314 {
4315 /* set curbuf to be our buf, temporarily */
4316 save_curbuf = curbuf;
4317 curbuf = buf;
4318
Bram Moolenaar30567352016-08-27 21:25:44 +02004319 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004320 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004321 if (varname[1] == NUL)
4322 {
4323 /* get all buffer-local options in a dict */
4324 dict_T *opts = get_winbuf_options(TRUE);
4325
4326 if (opts != NULL)
4327 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004328 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004329 done = TRUE;
4330 }
4331 }
4332 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4333 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004334 done = TRUE;
4335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004336 else
4337 {
4338 /* Look up the variable. */
4339 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4340 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4341 'b', varname, FALSE);
4342 if (v != NULL)
4343 {
4344 copy_tv(&v->di_tv, rettv);
4345 done = TRUE;
4346 }
4347 }
4348
4349 /* restore previous notion of curbuf */
4350 curbuf = save_curbuf;
4351 }
4352
4353 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4354 /* use the default value */
4355 copy_tv(&argvars[2], rettv);
4356
4357 --emsg_off;
4358}
4359
4360/*
4361 * "getchar()" function
4362 */
4363 static void
4364f_getchar(typval_T *argvars, typval_T *rettv)
4365{
4366 varnumber_T n;
4367 int error = FALSE;
4368
4369 /* Position the cursor. Needed after a message that ends in a space. */
4370 windgoto(msg_row, msg_col);
4371
4372 ++no_mapping;
4373 ++allow_keys;
4374 for (;;)
4375 {
4376 if (argvars[0].v_type == VAR_UNKNOWN)
4377 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004378 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004379 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4380 /* getchar(1): only check if char avail */
4381 n = vpeekc_any();
4382 else if (error || vpeekc_any() == NUL)
4383 /* illegal argument or getchar(0) and no char avail: return zero */
4384 n = 0;
4385 else
4386 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004387 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004388
4389 if (n == K_IGNORE)
4390 continue;
4391 break;
4392 }
4393 --no_mapping;
4394 --allow_keys;
4395
4396 set_vim_var_nr(VV_MOUSE_WIN, 0);
4397 set_vim_var_nr(VV_MOUSE_WINID, 0);
4398 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4399 set_vim_var_nr(VV_MOUSE_COL, 0);
4400
4401 rettv->vval.v_number = n;
4402 if (IS_SPECIAL(n) || mod_mask != 0)
4403 {
4404 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4405 int i = 0;
4406
4407 /* Turn a special key into three bytes, plus modifier. */
4408 if (mod_mask != 0)
4409 {
4410 temp[i++] = K_SPECIAL;
4411 temp[i++] = KS_MODIFIER;
4412 temp[i++] = mod_mask;
4413 }
4414 if (IS_SPECIAL(n))
4415 {
4416 temp[i++] = K_SPECIAL;
4417 temp[i++] = K_SECOND(n);
4418 temp[i++] = K_THIRD(n);
4419 }
4420#ifdef FEAT_MBYTE
4421 else if (has_mbyte)
4422 i += (*mb_char2bytes)(n, temp + i);
4423#endif
4424 else
4425 temp[i++] = n;
4426 temp[i++] = NUL;
4427 rettv->v_type = VAR_STRING;
4428 rettv->vval.v_string = vim_strsave(temp);
4429
4430#ifdef FEAT_MOUSE
4431 if (is_mouse_key(n))
4432 {
4433 int row = mouse_row;
4434 int col = mouse_col;
4435 win_T *win;
4436 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004437 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004438 int winnr = 1;
4439
4440 if (row >= 0 && col >= 0)
4441 {
4442 /* Find the window at the mouse coordinates and compute the
4443 * text position. */
4444 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004445 if (win == NULL)
4446 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004447 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448 for (wp = firstwin; wp != win; wp = wp->w_next)
4449 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004450 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4451 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4452 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4453 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4454 }
4455 }
4456#endif
4457 }
4458}
4459
4460/*
4461 * "getcharmod()" function
4462 */
4463 static void
4464f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4465{
4466 rettv->vval.v_number = mod_mask;
4467}
4468
4469/*
4470 * "getcharsearch()" function
4471 */
4472 static void
4473f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4474{
4475 if (rettv_dict_alloc(rettv) != FAIL)
4476 {
4477 dict_T *dict = rettv->vval.v_dict;
4478
4479 dict_add_nr_str(dict, "char", 0L, last_csearch());
4480 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4481 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4482 }
4483}
4484
4485/*
4486 * "getcmdline()" function
4487 */
4488 static void
4489f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4490{
4491 rettv->v_type = VAR_STRING;
4492 rettv->vval.v_string = get_cmdline_str();
4493}
4494
4495/*
4496 * "getcmdpos()" function
4497 */
4498 static void
4499f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4500{
4501 rettv->vval.v_number = get_cmdline_pos() + 1;
4502}
4503
4504/*
4505 * "getcmdtype()" function
4506 */
4507 static void
4508f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4509{
4510 rettv->v_type = VAR_STRING;
4511 rettv->vval.v_string = alloc(2);
4512 if (rettv->vval.v_string != NULL)
4513 {
4514 rettv->vval.v_string[0] = get_cmdline_type();
4515 rettv->vval.v_string[1] = NUL;
4516 }
4517}
4518
4519/*
4520 * "getcmdwintype()" function
4521 */
4522 static void
4523f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4524{
4525 rettv->v_type = VAR_STRING;
4526 rettv->vval.v_string = NULL;
4527#ifdef FEAT_CMDWIN
4528 rettv->vval.v_string = alloc(2);
4529 if (rettv->vval.v_string != NULL)
4530 {
4531 rettv->vval.v_string[0] = cmdwin_type;
4532 rettv->vval.v_string[1] = NUL;
4533 }
4534#endif
4535}
4536
4537#if defined(FEAT_CMDL_COMPL)
4538/*
4539 * "getcompletion()" function
4540 */
4541 static void
4542f_getcompletion(typval_T *argvars, typval_T *rettv)
4543{
4544 char_u *pat;
4545 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004546 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004547 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4548 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004550 if (argvars[2].v_type != VAR_UNKNOWN)
4551 filtered = get_tv_number_chk(&argvars[2], NULL);
4552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004553 if (p_wic)
4554 options |= WILD_ICASE;
4555
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004556 /* For filtered results, 'wildignore' is used */
4557 if (!filtered)
4558 options |= WILD_KEEP_ALL;
4559
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560 ExpandInit(&xpc);
4561 xpc.xp_pattern = get_tv_string(&argvars[0]);
4562 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4563 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4564 if (xpc.xp_context == EXPAND_NOTHING)
4565 {
4566 if (argvars[1].v_type == VAR_STRING)
4567 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4568 else
4569 EMSG(_(e_invarg));
4570 return;
4571 }
4572
4573# if defined(FEAT_MENU)
4574 if (xpc.xp_context == EXPAND_MENUS)
4575 {
4576 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4577 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4578 }
4579# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004580#ifdef FEAT_CSCOPE
4581 if (xpc.xp_context == EXPAND_CSCOPE)
4582 {
4583 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4584 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4585 }
4586#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004587#ifdef FEAT_SIGNS
4588 if (xpc.xp_context == EXPAND_SIGN)
4589 {
4590 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4591 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4592 }
4593#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594
4595 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4596 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4597 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004598 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004599
4600 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4601
4602 for (i = 0; i < xpc.xp_numfiles; i++)
4603 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4604 }
4605 vim_free(pat);
4606 ExpandCleanup(&xpc);
4607}
4608#endif
4609
4610/*
4611 * "getcwd()" function
4612 */
4613 static void
4614f_getcwd(typval_T *argvars, typval_T *rettv)
4615{
4616 win_T *wp = NULL;
4617 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004618 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004619
4620 rettv->v_type = VAR_STRING;
4621 rettv->vval.v_string = NULL;
4622
Bram Moolenaar54591292018-02-09 20:53:59 +01004623 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4624 global = TRUE;
4625 else
4626 wp = find_tabwin(&argvars[0], &argvars[1]);
4627
4628 if (wp != NULL && wp->w_localdir != NULL)
4629 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4630 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004631 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004632 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004633 rettv->vval.v_string = vim_strsave(globaldir);
4634 else
4635 {
4636 cwd = alloc(MAXPATHL);
4637 if (cwd != NULL)
4638 {
4639 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4640 rettv->vval.v_string = vim_strsave(cwd);
4641 vim_free(cwd);
4642 }
4643 }
4644#ifdef BACKSLASH_IN_FILENAME
4645 if (rettv->vval.v_string != NULL)
4646 slash_adjust(rettv->vval.v_string);
4647#endif
4648 }
4649}
4650
4651/*
4652 * "getfontname()" function
4653 */
4654 static void
4655f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4656{
4657 rettv->v_type = VAR_STRING;
4658 rettv->vval.v_string = NULL;
4659#ifdef FEAT_GUI
4660 if (gui.in_use)
4661 {
4662 GuiFont font;
4663 char_u *name = NULL;
4664
4665 if (argvars[0].v_type == VAR_UNKNOWN)
4666 {
4667 /* Get the "Normal" font. Either the name saved by
4668 * hl_set_font_name() or from the font ID. */
4669 font = gui.norm_font;
4670 name = hl_get_font_name();
4671 }
4672 else
4673 {
4674 name = get_tv_string(&argvars[0]);
4675 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4676 return;
4677 font = gui_mch_get_font(name, FALSE);
4678 if (font == NOFONT)
4679 return; /* Invalid font name, return empty string. */
4680 }
4681 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4682 if (argvars[0].v_type != VAR_UNKNOWN)
4683 gui_mch_free_font(font);
4684 }
4685#endif
4686}
4687
4688/*
4689 * "getfperm({fname})" function
4690 */
4691 static void
4692f_getfperm(typval_T *argvars, typval_T *rettv)
4693{
4694 char_u *fname;
4695 stat_T st;
4696 char_u *perm = NULL;
4697 char_u flags[] = "rwx";
4698 int i;
4699
4700 fname = get_tv_string(&argvars[0]);
4701
4702 rettv->v_type = VAR_STRING;
4703 if (mch_stat((char *)fname, &st) >= 0)
4704 {
4705 perm = vim_strsave((char_u *)"---------");
4706 if (perm != NULL)
4707 {
4708 for (i = 0; i < 9; i++)
4709 {
4710 if (st.st_mode & (1 << (8 - i)))
4711 perm[i] = flags[i % 3];
4712 }
4713 }
4714 }
4715 rettv->vval.v_string = perm;
4716}
4717
4718/*
4719 * "getfsize({fname})" function
4720 */
4721 static void
4722f_getfsize(typval_T *argvars, typval_T *rettv)
4723{
4724 char_u *fname;
4725 stat_T st;
4726
4727 fname = get_tv_string(&argvars[0]);
4728
4729 rettv->v_type = VAR_NUMBER;
4730
4731 if (mch_stat((char *)fname, &st) >= 0)
4732 {
4733 if (mch_isdir(fname))
4734 rettv->vval.v_number = 0;
4735 else
4736 {
4737 rettv->vval.v_number = (varnumber_T)st.st_size;
4738
4739 /* non-perfect check for overflow */
4740 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4741 rettv->vval.v_number = -2;
4742 }
4743 }
4744 else
4745 rettv->vval.v_number = -1;
4746}
4747
4748/*
4749 * "getftime({fname})" function
4750 */
4751 static void
4752f_getftime(typval_T *argvars, typval_T *rettv)
4753{
4754 char_u *fname;
4755 stat_T st;
4756
4757 fname = get_tv_string(&argvars[0]);
4758
4759 if (mch_stat((char *)fname, &st) >= 0)
4760 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4761 else
4762 rettv->vval.v_number = -1;
4763}
4764
4765/*
4766 * "getftype({fname})" function
4767 */
4768 static void
4769f_getftype(typval_T *argvars, typval_T *rettv)
4770{
4771 char_u *fname;
4772 stat_T st;
4773 char_u *type = NULL;
4774 char *t;
4775
4776 fname = get_tv_string(&argvars[0]);
4777
4778 rettv->v_type = VAR_STRING;
4779 if (mch_lstat((char *)fname, &st) >= 0)
4780 {
4781#ifdef S_ISREG
4782 if (S_ISREG(st.st_mode))
4783 t = "file";
4784 else if (S_ISDIR(st.st_mode))
4785 t = "dir";
4786# ifdef S_ISLNK
4787 else if (S_ISLNK(st.st_mode))
4788 t = "link";
4789# endif
4790# ifdef S_ISBLK
4791 else if (S_ISBLK(st.st_mode))
4792 t = "bdev";
4793# endif
4794# ifdef S_ISCHR
4795 else if (S_ISCHR(st.st_mode))
4796 t = "cdev";
4797# endif
4798# ifdef S_ISFIFO
4799 else if (S_ISFIFO(st.st_mode))
4800 t = "fifo";
4801# endif
4802# ifdef S_ISSOCK
4803 else if (S_ISSOCK(st.st_mode))
4804 t = "fifo";
4805# endif
4806 else
4807 t = "other";
4808#else
4809# ifdef S_IFMT
4810 switch (st.st_mode & S_IFMT)
4811 {
4812 case S_IFREG: t = "file"; break;
4813 case S_IFDIR: t = "dir"; break;
4814# ifdef S_IFLNK
4815 case S_IFLNK: t = "link"; break;
4816# endif
4817# ifdef S_IFBLK
4818 case S_IFBLK: t = "bdev"; break;
4819# endif
4820# ifdef S_IFCHR
4821 case S_IFCHR: t = "cdev"; break;
4822# endif
4823# ifdef S_IFIFO
4824 case S_IFIFO: t = "fifo"; break;
4825# endif
4826# ifdef S_IFSOCK
4827 case S_IFSOCK: t = "socket"; break;
4828# endif
4829 default: t = "other";
4830 }
4831# else
4832 if (mch_isdir(fname))
4833 t = "dir";
4834 else
4835 t = "file";
4836# endif
4837#endif
4838 type = vim_strsave((char_u *)t);
4839 }
4840 rettv->vval.v_string = type;
4841}
4842
4843/*
4844 * "getline(lnum, [end])" function
4845 */
4846 static void
4847f_getline(typval_T *argvars, typval_T *rettv)
4848{
4849 linenr_T lnum;
4850 linenr_T end;
4851 int retlist;
4852
4853 lnum = get_tv_lnum(argvars);
4854 if (argvars[1].v_type == VAR_UNKNOWN)
4855 {
4856 end = 0;
4857 retlist = FALSE;
4858 }
4859 else
4860 {
4861 end = get_tv_lnum(&argvars[1]);
4862 retlist = TRUE;
4863 }
4864
4865 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4866}
4867
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004868#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02004869 static void
4870get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4871{
Bram Moolenaard823fa92016-08-12 16:29:27 +02004872 if (what_arg->v_type == VAR_UNKNOWN)
4873 {
4874 if (rettv_list_alloc(rettv) == OK)
4875 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02004876 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004877 }
4878 else
4879 {
4880 if (rettv_dict_alloc(rettv) == OK)
4881 if (is_qf || (wp != NULL))
4882 {
4883 if (what_arg->v_type == VAR_DICT)
4884 {
4885 dict_T *d = what_arg->vval.v_dict;
4886
4887 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02004888 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02004889 }
4890 else
4891 EMSG(_(e_dictreq));
4892 }
4893 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02004894}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004895#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02004896
4897/*
4898 * "getloclist()" function
4899 */
4900 static void
4901f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4902{
4903#ifdef FEAT_QUICKFIX
4904 win_T *wp;
4905
4906 wp = find_win_by_nr(&argvars[0], NULL);
4907 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
4908#endif
4909}
4910
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911/*
4912 * "getmatches()" function
4913 */
4914 static void
4915f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4916{
4917#ifdef FEAT_SEARCH_EXTRA
4918 dict_T *dict;
4919 matchitem_T *cur = curwin->w_match_head;
4920 int i;
4921
4922 if (rettv_list_alloc(rettv) == OK)
4923 {
4924 while (cur != NULL)
4925 {
4926 dict = dict_alloc();
4927 if (dict == NULL)
4928 return;
4929 if (cur->match.regprog == NULL)
4930 {
4931 /* match added with matchaddpos() */
4932 for (i = 0; i < MAXPOSMATCH; ++i)
4933 {
4934 llpos_T *llpos;
4935 char buf[6];
4936 list_T *l;
4937
4938 llpos = &cur->pos.pos[i];
4939 if (llpos->lnum == 0)
4940 break;
4941 l = list_alloc();
4942 if (l == NULL)
4943 break;
4944 list_append_number(l, (varnumber_T)llpos->lnum);
4945 if (llpos->col > 0)
4946 {
4947 list_append_number(l, (varnumber_T)llpos->col);
4948 list_append_number(l, (varnumber_T)llpos->len);
4949 }
4950 sprintf(buf, "pos%d", i + 1);
4951 dict_add_list(dict, buf, l);
4952 }
4953 }
4954 else
4955 {
4956 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
4957 }
4958 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
4959 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
4960 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
4961# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
4962 if (cur->conceal_char)
4963 {
4964 char_u buf[MB_MAXBYTES + 1];
4965
4966 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
4967 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
4968 }
4969# endif
4970 list_append_dict(rettv->vval.v_list, dict);
4971 cur = cur->next;
4972 }
4973 }
4974#endif
4975}
4976
4977/*
4978 * "getpid()" function
4979 */
4980 static void
4981f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4982{
4983 rettv->vval.v_number = mch_get_pid();
4984}
4985
4986 static void
4987getpos_both(
4988 typval_T *argvars,
4989 typval_T *rettv,
4990 int getcurpos)
4991{
4992 pos_T *fp;
4993 list_T *l;
4994 int fnum = -1;
4995
4996 if (rettv_list_alloc(rettv) == OK)
4997 {
4998 l = rettv->vval.v_list;
4999 if (getcurpos)
5000 fp = &curwin->w_cursor;
5001 else
5002 fp = var2fpos(&argvars[0], TRUE, &fnum);
5003 if (fnum != -1)
5004 list_append_number(l, (varnumber_T)fnum);
5005 else
5006 list_append_number(l, (varnumber_T)0);
5007 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5008 : (varnumber_T)0);
5009 list_append_number(l, (fp != NULL)
5010 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5011 : (varnumber_T)0);
5012 list_append_number(l,
5013#ifdef FEAT_VIRTUALEDIT
5014 (fp != NULL) ? (varnumber_T)fp->coladd :
5015#endif
5016 (varnumber_T)0);
5017 if (getcurpos)
5018 {
5019 update_curswant();
5020 list_append_number(l, curwin->w_curswant == MAXCOL ?
5021 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5022 }
5023 }
5024 else
5025 rettv->vval.v_number = FALSE;
5026}
5027
5028
5029/*
5030 * "getcurpos()" function
5031 */
5032 static void
5033f_getcurpos(typval_T *argvars, typval_T *rettv)
5034{
5035 getpos_both(argvars, rettv, TRUE);
5036}
5037
5038/*
5039 * "getpos(string)" function
5040 */
5041 static void
5042f_getpos(typval_T *argvars, typval_T *rettv)
5043{
5044 getpos_both(argvars, rettv, FALSE);
5045}
5046
5047/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005048 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005049 */
5050 static void
5051f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5052{
5053#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005054 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005055#endif
5056}
5057
5058/*
5059 * "getreg()" function
5060 */
5061 static void
5062f_getreg(typval_T *argvars, typval_T *rettv)
5063{
5064 char_u *strregname;
5065 int regname;
5066 int arg2 = FALSE;
5067 int return_list = FALSE;
5068 int error = FALSE;
5069
5070 if (argvars[0].v_type != VAR_UNKNOWN)
5071 {
5072 strregname = get_tv_string_chk(&argvars[0]);
5073 error = strregname == NULL;
5074 if (argvars[1].v_type != VAR_UNKNOWN)
5075 {
5076 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5077 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5078 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5079 }
5080 }
5081 else
5082 strregname = get_vim_var_str(VV_REG);
5083
5084 if (error)
5085 return;
5086
5087 regname = (strregname == NULL ? '"' : *strregname);
5088 if (regname == 0)
5089 regname = '"';
5090
5091 if (return_list)
5092 {
5093 rettv->v_type = VAR_LIST;
5094 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5095 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5096 if (rettv->vval.v_list == NULL)
5097 (void)rettv_list_alloc(rettv);
5098 else
5099 ++rettv->vval.v_list->lv_refcount;
5100 }
5101 else
5102 {
5103 rettv->v_type = VAR_STRING;
5104 rettv->vval.v_string = get_reg_contents(regname,
5105 arg2 ? GREG_EXPR_SRC : 0);
5106 }
5107}
5108
5109/*
5110 * "getregtype()" function
5111 */
5112 static void
5113f_getregtype(typval_T *argvars, typval_T *rettv)
5114{
5115 char_u *strregname;
5116 int regname;
5117 char_u buf[NUMBUFLEN + 2];
5118 long reglen = 0;
5119
5120 if (argvars[0].v_type != VAR_UNKNOWN)
5121 {
5122 strregname = get_tv_string_chk(&argvars[0]);
5123 if (strregname == NULL) /* type error; errmsg already given */
5124 {
5125 rettv->v_type = VAR_STRING;
5126 rettv->vval.v_string = NULL;
5127 return;
5128 }
5129 }
5130 else
5131 /* Default to v:register */
5132 strregname = get_vim_var_str(VV_REG);
5133
5134 regname = (strregname == NULL ? '"' : *strregname);
5135 if (regname == 0)
5136 regname = '"';
5137
5138 buf[0] = NUL;
5139 buf[1] = NUL;
5140 switch (get_reg_type(regname, &reglen))
5141 {
5142 case MLINE: buf[0] = 'V'; break;
5143 case MCHAR: buf[0] = 'v'; break;
5144 case MBLOCK:
5145 buf[0] = Ctrl_V;
5146 sprintf((char *)buf + 1, "%ld", reglen + 1);
5147 break;
5148 }
5149 rettv->v_type = VAR_STRING;
5150 rettv->vval.v_string = vim_strsave(buf);
5151}
5152
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005153/*
5154 * Returns information (variables, options, etc.) about a tab page
5155 * as a dictionary.
5156 */
5157 static dict_T *
5158get_tabpage_info(tabpage_T *tp, int tp_idx)
5159{
5160 win_T *wp;
5161 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005162 list_T *l;
5163
5164 dict = dict_alloc();
5165 if (dict == NULL)
5166 return NULL;
5167
Bram Moolenaar33928832016-08-18 21:22:04 +02005168 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005169
5170 l = list_alloc();
5171 if (l != NULL)
5172 {
5173 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5174 wp; wp = wp->w_next)
5175 list_append_number(l, (varnumber_T)wp->w_id);
5176 dict_add_list(dict, "windows", l);
5177 }
5178
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005179 /* Make a reference to tabpage variables */
5180 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005181
5182 return dict;
5183}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005184
5185/*
5186 * "gettabinfo()" function
5187 */
5188 static void
5189f_gettabinfo(typval_T *argvars, typval_T *rettv)
5190{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005191 tabpage_T *tp, *tparg = NULL;
5192 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005193 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005194
5195 if (rettv_list_alloc(rettv) != OK)
5196 return;
5197
5198 if (argvars[0].v_type != VAR_UNKNOWN)
5199 {
5200 /* Information about one tab page */
5201 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5202 if (tparg == NULL)
5203 return;
5204 }
5205
5206 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005207 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005208 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005209 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005210 if (tparg != NULL && tp != tparg)
5211 continue;
5212 d = get_tabpage_info(tp, tpnr);
5213 if (d != NULL)
5214 list_append_dict(rettv->vval.v_list, d);
5215 if (tparg != NULL)
5216 return;
5217 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005218}
5219
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005220/*
5221 * "gettabvar()" function
5222 */
5223 static void
5224f_gettabvar(typval_T *argvars, typval_T *rettv)
5225{
5226 win_T *oldcurwin;
5227 tabpage_T *tp, *oldtabpage;
5228 dictitem_T *v;
5229 char_u *varname;
5230 int done = FALSE;
5231
5232 rettv->v_type = VAR_STRING;
5233 rettv->vval.v_string = NULL;
5234
5235 varname = get_tv_string_chk(&argvars[1]);
5236 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5237 if (tp != NULL && varname != NULL)
5238 {
5239 /* Set tp to be our tabpage, temporarily. Also set the window to the
5240 * first window in the tabpage, otherwise the window is not valid. */
5241 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005242 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5243 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244 {
5245 /* look up the variable */
5246 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5247 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5248 if (v != NULL)
5249 {
5250 copy_tv(&v->di_tv, rettv);
5251 done = TRUE;
5252 }
5253 }
5254
5255 /* restore previous notion of curwin */
5256 restore_win(oldcurwin, oldtabpage, TRUE);
5257 }
5258
5259 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5260 copy_tv(&argvars[2], rettv);
5261}
5262
5263/*
5264 * "gettabwinvar()" function
5265 */
5266 static void
5267f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5268{
5269 getwinvar(argvars, rettv, 1);
5270}
5271
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005272/*
5273 * Returns information about a window as a dictionary.
5274 */
5275 static dict_T *
5276get_win_info(win_T *wp, short tpnr, short winnr)
5277{
5278 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005279
5280 dict = dict_alloc();
5281 if (dict == NULL)
5282 return NULL;
5283
Bram Moolenaar33928832016-08-18 21:22:04 +02005284 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5285 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005286 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5287 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005288#ifdef FEAT_MENU
5289 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5290#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005291 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005292 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005293
Bram Moolenaar69905d12017-08-13 18:14:47 +02005294#ifdef FEAT_TERMINAL
5295 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5296#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005297#ifdef FEAT_QUICKFIX
5298 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5299 dict_add_nr_str(dict, "loclist",
5300 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5301#endif
5302
Bram Moolenaar30567352016-08-27 21:25:44 +02005303 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005304 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005305
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005306 return dict;
5307}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005308
5309/*
5310 * "getwininfo()" function
5311 */
5312 static void
5313f_getwininfo(typval_T *argvars, typval_T *rettv)
5314{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005315 tabpage_T *tp;
5316 win_T *wp = NULL, *wparg = NULL;
5317 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005318 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005319
5320 if (rettv_list_alloc(rettv) != OK)
5321 return;
5322
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005323 if (argvars[0].v_type != VAR_UNKNOWN)
5324 {
5325 wparg = win_id2wp(argvars);
5326 if (wparg == NULL)
5327 return;
5328 }
5329
5330 /* Collect information about either all the windows across all the tab
5331 * pages or one particular window.
5332 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005333 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005334 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005335 tabnr++;
5336 winnr = 0;
5337 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005338 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005339 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005340 if (wparg != NULL && wp != wparg)
5341 continue;
5342 d = get_win_info(wp, tabnr, winnr);
5343 if (d != NULL)
5344 list_append_dict(rettv->vval.v_list, d);
5345 if (wparg != NULL)
5346 /* found information about a specific window */
5347 return;
5348 }
5349 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005350}
5351
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005352/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005353 * "win_findbuf()" function
5354 */
5355 static void
5356f_win_findbuf(typval_T *argvars, typval_T *rettv)
5357{
5358 if (rettv_list_alloc(rettv) != FAIL)
5359 win_findbuf(argvars, rettv->vval.v_list);
5360}
5361
5362/*
5363 * "win_getid()" function
5364 */
5365 static void
5366f_win_getid(typval_T *argvars, typval_T *rettv)
5367{
5368 rettv->vval.v_number = win_getid(argvars);
5369}
5370
5371/*
5372 * "win_gotoid()" function
5373 */
5374 static void
5375f_win_gotoid(typval_T *argvars, typval_T *rettv)
5376{
5377 rettv->vval.v_number = win_gotoid(argvars);
5378}
5379
5380/*
5381 * "win_id2tabwin()" function
5382 */
5383 static void
5384f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5385{
5386 if (rettv_list_alloc(rettv) != FAIL)
5387 win_id2tabwin(argvars, rettv->vval.v_list);
5388}
5389
5390/*
5391 * "win_id2win()" function
5392 */
5393 static void
5394f_win_id2win(typval_T *argvars, typval_T *rettv)
5395{
5396 rettv->vval.v_number = win_id2win(argvars);
5397}
5398
5399/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005400 * "win_screenpos()" function
5401 */
5402 static void
5403f_win_screenpos(typval_T *argvars, typval_T *rettv)
5404{
5405 win_T *wp;
5406
5407 if (rettv_list_alloc(rettv) == FAIL)
5408 return;
5409
5410 wp = find_win_by_nr(&argvars[0], NULL);
5411 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5412 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5413}
5414
5415/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005416 * "getwinposx()" function
5417 */
5418 static void
5419f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5420{
5421 rettv->vval.v_number = -1;
5422#ifdef FEAT_GUI
5423 if (gui.in_use)
5424 {
5425 int x, y;
5426
5427 if (gui_mch_get_winpos(&x, &y) == OK)
5428 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005429 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005430 }
5431#endif
5432#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5433 {
5434 int x, y;
5435
5436 if (term_get_winpos(&x, &y) == OK)
5437 rettv->vval.v_number = x;
5438 }
5439#endif
5440}
5441
5442/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005443 * "getwinposy()" function
5444 */
5445 static void
5446f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5447{
5448 rettv->vval.v_number = -1;
5449#ifdef FEAT_GUI
5450 if (gui.in_use)
5451 {
5452 int x, y;
5453
5454 if (gui_mch_get_winpos(&x, &y) == OK)
5455 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005456 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457 }
5458#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005459#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5460 {
5461 int x, y;
5462
5463 if (term_get_winpos(&x, &y) == OK)
5464 rettv->vval.v_number = y;
5465 }
5466#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005467}
5468
5469/*
5470 * "getwinvar()" function
5471 */
5472 static void
5473f_getwinvar(typval_T *argvars, typval_T *rettv)
5474{
5475 getwinvar(argvars, rettv, 0);
5476}
5477
5478/*
5479 * "glob()" function
5480 */
5481 static void
5482f_glob(typval_T *argvars, typval_T *rettv)
5483{
5484 int options = WILD_SILENT|WILD_USE_NL;
5485 expand_T xpc;
5486 int error = FALSE;
5487
5488 /* When the optional second argument is non-zero, don't remove matches
5489 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5490 rettv->v_type = VAR_STRING;
5491 if (argvars[1].v_type != VAR_UNKNOWN)
5492 {
5493 if (get_tv_number_chk(&argvars[1], &error))
5494 options |= WILD_KEEP_ALL;
5495 if (argvars[2].v_type != VAR_UNKNOWN)
5496 {
5497 if (get_tv_number_chk(&argvars[2], &error))
5498 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005499 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005500 }
5501 if (argvars[3].v_type != VAR_UNKNOWN
5502 && get_tv_number_chk(&argvars[3], &error))
5503 options |= WILD_ALLLINKS;
5504 }
5505 }
5506 if (!error)
5507 {
5508 ExpandInit(&xpc);
5509 xpc.xp_context = EXPAND_FILES;
5510 if (p_wic)
5511 options += WILD_ICASE;
5512 if (rettv->v_type == VAR_STRING)
5513 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5514 NULL, options, WILD_ALL);
5515 else if (rettv_list_alloc(rettv) != FAIL)
5516 {
5517 int i;
5518
5519 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5520 NULL, options, WILD_ALL_KEEP);
5521 for (i = 0; i < xpc.xp_numfiles; i++)
5522 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5523
5524 ExpandCleanup(&xpc);
5525 }
5526 }
5527 else
5528 rettv->vval.v_string = NULL;
5529}
5530
5531/*
5532 * "globpath()" function
5533 */
5534 static void
5535f_globpath(typval_T *argvars, typval_T *rettv)
5536{
5537 int flags = 0;
5538 char_u buf1[NUMBUFLEN];
5539 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5540 int error = FALSE;
5541 garray_T ga;
5542 int i;
5543
5544 /* When the optional second argument is non-zero, don't remove matches
5545 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5546 rettv->v_type = VAR_STRING;
5547 if (argvars[2].v_type != VAR_UNKNOWN)
5548 {
5549 if (get_tv_number_chk(&argvars[2], &error))
5550 flags |= WILD_KEEP_ALL;
5551 if (argvars[3].v_type != VAR_UNKNOWN)
5552 {
5553 if (get_tv_number_chk(&argvars[3], &error))
5554 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005555 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556 }
5557 if (argvars[4].v_type != VAR_UNKNOWN
5558 && get_tv_number_chk(&argvars[4], &error))
5559 flags |= WILD_ALLLINKS;
5560 }
5561 }
5562 if (file != NULL && !error)
5563 {
5564 ga_init2(&ga, (int)sizeof(char_u *), 10);
5565 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5566 if (rettv->v_type == VAR_STRING)
5567 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5568 else if (rettv_list_alloc(rettv) != FAIL)
5569 for (i = 0; i < ga.ga_len; ++i)
5570 list_append_string(rettv->vval.v_list,
5571 ((char_u **)(ga.ga_data))[i], -1);
5572 ga_clear_strings(&ga);
5573 }
5574 else
5575 rettv->vval.v_string = NULL;
5576}
5577
5578/*
5579 * "glob2regpat()" function
5580 */
5581 static void
5582f_glob2regpat(typval_T *argvars, typval_T *rettv)
5583{
5584 char_u *pat = get_tv_string_chk(&argvars[0]);
5585
5586 rettv->v_type = VAR_STRING;
5587 rettv->vval.v_string = (pat == NULL)
5588 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5589}
5590
5591/* for VIM_VERSION_ defines */
5592#include "version.h"
5593
5594/*
5595 * "has()" function
5596 */
5597 static void
5598f_has(typval_T *argvars, typval_T *rettv)
5599{
5600 int i;
5601 char_u *name;
5602 int n = FALSE;
5603 static char *(has_list[]) =
5604 {
5605#ifdef AMIGA
5606 "amiga",
5607# ifdef FEAT_ARP
5608 "arp",
5609# endif
5610#endif
5611#ifdef __BEOS__
5612 "beos",
5613#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005614#ifdef MACOS_X
5615 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5616 "osx", /* Mac OS X */
5617# ifdef MACOS_X_DARWIN
5618 "macunix", /* Mac OS X, with the darwin feature */
5619 "osxdarwin", /* synonym for macunix */
5620# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005621#endif
5622#ifdef __QNX__
5623 "qnx",
5624#endif
5625#ifdef UNIX
5626 "unix",
5627#endif
5628#ifdef VMS
5629 "vms",
5630#endif
5631#ifdef WIN32
5632 "win32",
5633#endif
5634#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5635 "win32unix",
5636#endif
5637#if defined(WIN64) || defined(_WIN64)
5638 "win64",
5639#endif
5640#ifdef EBCDIC
5641 "ebcdic",
5642#endif
5643#ifndef CASE_INSENSITIVE_FILENAME
5644 "fname_case",
5645#endif
5646#ifdef HAVE_ACL
5647 "acl",
5648#endif
5649#ifdef FEAT_ARABIC
5650 "arabic",
5651#endif
5652#ifdef FEAT_AUTOCMD
5653 "autocmd",
5654#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005655#ifdef FEAT_AUTOSERVERNAME
5656 "autoservername",
5657#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005658#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 "balloon_eval",
5660# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5661 "balloon_multiline",
5662# endif
5663#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005664#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005665 "balloon_eval_term",
5666#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005667#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5668 "builtin_terms",
5669# ifdef ALL_BUILTIN_TCAPS
5670 "all_builtin_terms",
5671# endif
5672#endif
5673#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5674 || defined(FEAT_GUI_W32) \
5675 || defined(FEAT_GUI_MOTIF))
5676 "browsefilter",
5677#endif
5678#ifdef FEAT_BYTEOFF
5679 "byte_offset",
5680#endif
5681#ifdef FEAT_JOB_CHANNEL
5682 "channel",
5683#endif
5684#ifdef FEAT_CINDENT
5685 "cindent",
5686#endif
5687#ifdef FEAT_CLIENTSERVER
5688 "clientserver",
5689#endif
5690#ifdef FEAT_CLIPBOARD
5691 "clipboard",
5692#endif
5693#ifdef FEAT_CMDL_COMPL
5694 "cmdline_compl",
5695#endif
5696#ifdef FEAT_CMDHIST
5697 "cmdline_hist",
5698#endif
5699#ifdef FEAT_COMMENTS
5700 "comments",
5701#endif
5702#ifdef FEAT_CONCEAL
5703 "conceal",
5704#endif
5705#ifdef FEAT_CRYPT
5706 "cryptv",
5707 "crypt-blowfish",
5708 "crypt-blowfish2",
5709#endif
5710#ifdef FEAT_CSCOPE
5711 "cscope",
5712#endif
5713#ifdef FEAT_CURSORBIND
5714 "cursorbind",
5715#endif
5716#ifdef CURSOR_SHAPE
5717 "cursorshape",
5718#endif
5719#ifdef DEBUG
5720 "debug",
5721#endif
5722#ifdef FEAT_CON_DIALOG
5723 "dialog_con",
5724#endif
5725#ifdef FEAT_GUI_DIALOG
5726 "dialog_gui",
5727#endif
5728#ifdef FEAT_DIFF
5729 "diff",
5730#endif
5731#ifdef FEAT_DIGRAPHS
5732 "digraphs",
5733#endif
5734#ifdef FEAT_DIRECTX
5735 "directx",
5736#endif
5737#ifdef FEAT_DND
5738 "dnd",
5739#endif
5740#ifdef FEAT_EMACS_TAGS
5741 "emacs_tags",
5742#endif
5743 "eval", /* always present, of course! */
5744 "ex_extra", /* graduated feature */
5745#ifdef FEAT_SEARCH_EXTRA
5746 "extra_search",
5747#endif
5748#ifdef FEAT_FKMAP
5749 "farsi",
5750#endif
5751#ifdef FEAT_SEARCHPATH
5752 "file_in_path",
5753#endif
5754#ifdef FEAT_FILTERPIPE
5755 "filterpipe",
5756#endif
5757#ifdef FEAT_FIND_ID
5758 "find_in_path",
5759#endif
5760#ifdef FEAT_FLOAT
5761 "float",
5762#endif
5763#ifdef FEAT_FOLDING
5764 "folding",
5765#endif
5766#ifdef FEAT_FOOTER
5767 "footer",
5768#endif
5769#if !defined(USE_SYSTEM) && defined(UNIX)
5770 "fork",
5771#endif
5772#ifdef FEAT_GETTEXT
5773 "gettext",
5774#endif
5775#ifdef FEAT_GUI
5776 "gui",
5777#endif
5778#ifdef FEAT_GUI_ATHENA
5779# ifdef FEAT_GUI_NEXTAW
5780 "gui_neXtaw",
5781# else
5782 "gui_athena",
5783# endif
5784#endif
5785#ifdef FEAT_GUI_GTK
5786 "gui_gtk",
5787# ifdef USE_GTK3
5788 "gui_gtk3",
5789# else
5790 "gui_gtk2",
5791# endif
5792#endif
5793#ifdef FEAT_GUI_GNOME
5794 "gui_gnome",
5795#endif
5796#ifdef FEAT_GUI_MAC
5797 "gui_mac",
5798#endif
5799#ifdef FEAT_GUI_MOTIF
5800 "gui_motif",
5801#endif
5802#ifdef FEAT_GUI_PHOTON
5803 "gui_photon",
5804#endif
5805#ifdef FEAT_GUI_W32
5806 "gui_win32",
5807#endif
5808#ifdef FEAT_HANGULIN
5809 "hangul_input",
5810#endif
5811#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5812 "iconv",
5813#endif
5814#ifdef FEAT_INS_EXPAND
5815 "insert_expand",
5816#endif
5817#ifdef FEAT_JOB_CHANNEL
5818 "job",
5819#endif
5820#ifdef FEAT_JUMPLIST
5821 "jumplist",
5822#endif
5823#ifdef FEAT_KEYMAP
5824 "keymap",
5825#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005826 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005827#ifdef FEAT_LANGMAP
5828 "langmap",
5829#endif
5830#ifdef FEAT_LIBCALL
5831 "libcall",
5832#endif
5833#ifdef FEAT_LINEBREAK
5834 "linebreak",
5835#endif
5836#ifdef FEAT_LISP
5837 "lispindent",
5838#endif
5839#ifdef FEAT_LISTCMDS
5840 "listcmds",
5841#endif
5842#ifdef FEAT_LOCALMAP
5843 "localmap",
5844#endif
5845#ifdef FEAT_LUA
5846# ifndef DYNAMIC_LUA
5847 "lua",
5848# endif
5849#endif
5850#ifdef FEAT_MENU
5851 "menu",
5852#endif
5853#ifdef FEAT_SESSION
5854 "mksession",
5855#endif
5856#ifdef FEAT_MODIFY_FNAME
5857 "modify_fname",
5858#endif
5859#ifdef FEAT_MOUSE
5860 "mouse",
5861#endif
5862#ifdef FEAT_MOUSESHAPE
5863 "mouseshape",
5864#endif
5865#if defined(UNIX) || defined(VMS)
5866# ifdef FEAT_MOUSE_DEC
5867 "mouse_dec",
5868# endif
5869# ifdef FEAT_MOUSE_GPM
5870 "mouse_gpm",
5871# endif
5872# ifdef FEAT_MOUSE_JSB
5873 "mouse_jsbterm",
5874# endif
5875# ifdef FEAT_MOUSE_NET
5876 "mouse_netterm",
5877# endif
5878# ifdef FEAT_MOUSE_PTERM
5879 "mouse_pterm",
5880# endif
5881# ifdef FEAT_MOUSE_SGR
5882 "mouse_sgr",
5883# endif
5884# ifdef FEAT_SYSMOUSE
5885 "mouse_sysmouse",
5886# endif
5887# ifdef FEAT_MOUSE_URXVT
5888 "mouse_urxvt",
5889# endif
5890# ifdef FEAT_MOUSE_XTERM
5891 "mouse_xterm",
5892# endif
5893#endif
5894#ifdef FEAT_MBYTE
5895 "multi_byte",
5896#endif
5897#ifdef FEAT_MBYTE_IME
5898 "multi_byte_ime",
5899#endif
5900#ifdef FEAT_MULTI_LANG
5901 "multi_lang",
5902#endif
5903#ifdef FEAT_MZSCHEME
5904#ifndef DYNAMIC_MZSCHEME
5905 "mzscheme",
5906#endif
5907#endif
5908#ifdef FEAT_NUM64
5909 "num64",
5910#endif
5911#ifdef FEAT_OLE
5912 "ole",
5913#endif
5914 "packages",
5915#ifdef FEAT_PATH_EXTRA
5916 "path_extra",
5917#endif
5918#ifdef FEAT_PERL
5919#ifndef DYNAMIC_PERL
5920 "perl",
5921#endif
5922#endif
5923#ifdef FEAT_PERSISTENT_UNDO
5924 "persistent_undo",
5925#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005926#if defined(FEAT_PYTHON)
5927 "python_compiled",
5928# if defined(DYNAMIC_PYTHON)
5929 "python_dynamic",
5930# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005931 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005932 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005933# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005934#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005935#if defined(FEAT_PYTHON3)
5936 "python3_compiled",
5937# if defined(DYNAMIC_PYTHON3)
5938 "python3_dynamic",
5939# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005940 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005941 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005942# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005943#endif
5944#ifdef FEAT_POSTSCRIPT
5945 "postscript",
5946#endif
5947#ifdef FEAT_PRINTER
5948 "printer",
5949#endif
5950#ifdef FEAT_PROFILE
5951 "profile",
5952#endif
5953#ifdef FEAT_RELTIME
5954 "reltime",
5955#endif
5956#ifdef FEAT_QUICKFIX
5957 "quickfix",
5958#endif
5959#ifdef FEAT_RIGHTLEFT
5960 "rightleft",
5961#endif
5962#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5963 "ruby",
5964#endif
5965#ifdef FEAT_SCROLLBIND
5966 "scrollbind",
5967#endif
5968#ifdef FEAT_CMDL_INFO
5969 "showcmd",
5970 "cmdline_info",
5971#endif
5972#ifdef FEAT_SIGNS
5973 "signs",
5974#endif
5975#ifdef FEAT_SMARTINDENT
5976 "smartindent",
5977#endif
5978#ifdef STARTUPTIME
5979 "startuptime",
5980#endif
5981#ifdef FEAT_STL_OPT
5982 "statusline",
5983#endif
5984#ifdef FEAT_SUN_WORKSHOP
5985 "sun_workshop",
5986#endif
5987#ifdef FEAT_NETBEANS_INTG
5988 "netbeans_intg",
5989#endif
5990#ifdef FEAT_SPELL
5991 "spell",
5992#endif
5993#ifdef FEAT_SYN_HL
5994 "syntax",
5995#endif
5996#if defined(USE_SYSTEM) || !defined(UNIX)
5997 "system",
5998#endif
5999#ifdef FEAT_TAG_BINS
6000 "tag_binary",
6001#endif
6002#ifdef FEAT_TAG_OLDSTATIC
6003 "tag_old_static",
6004#endif
6005#ifdef FEAT_TAG_ANYWHITE
6006 "tag_any_white",
6007#endif
6008#ifdef FEAT_TCL
6009# ifndef DYNAMIC_TCL
6010 "tcl",
6011# endif
6012#endif
6013#ifdef FEAT_TERMGUICOLORS
6014 "termguicolors",
6015#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006016#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006017 "terminal",
6018#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006019#ifdef TERMINFO
6020 "terminfo",
6021#endif
6022#ifdef FEAT_TERMRESPONSE
6023 "termresponse",
6024#endif
6025#ifdef FEAT_TEXTOBJ
6026 "textobjects",
6027#endif
6028#ifdef HAVE_TGETENT
6029 "tgetent",
6030#endif
6031#ifdef FEAT_TIMERS
6032 "timers",
6033#endif
6034#ifdef FEAT_TITLE
6035 "title",
6036#endif
6037#ifdef FEAT_TOOLBAR
6038 "toolbar",
6039#endif
6040#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6041 "unnamedplus",
6042#endif
6043#ifdef FEAT_USR_CMDS
6044 "user-commands", /* was accidentally included in 5.4 */
6045 "user_commands",
6046#endif
6047#ifdef FEAT_VIMINFO
6048 "viminfo",
6049#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006051#ifdef FEAT_VIRTUALEDIT
6052 "virtualedit",
6053#endif
6054 "visual",
6055#ifdef FEAT_VISUALEXTRA
6056 "visualextra",
6057#endif
6058#ifdef FEAT_VREPLACE
6059 "vreplace",
6060#endif
6061#ifdef FEAT_WILDIGN
6062 "wildignore",
6063#endif
6064#ifdef FEAT_WILDMENU
6065 "wildmenu",
6066#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006067 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006068#ifdef FEAT_WAK
6069 "winaltkeys",
6070#endif
6071#ifdef FEAT_WRITEBACKUP
6072 "writebackup",
6073#endif
6074#ifdef FEAT_XIM
6075 "xim",
6076#endif
6077#ifdef FEAT_XFONTSET
6078 "xfontset",
6079#endif
6080#ifdef FEAT_XPM_W32
6081 "xpm",
6082 "xpm_w32", /* for backward compatibility */
6083#else
6084# if defined(HAVE_XPM)
6085 "xpm",
6086# endif
6087#endif
6088#ifdef USE_XSMP
6089 "xsmp",
6090#endif
6091#ifdef USE_XSMP_INTERACT
6092 "xsmp_interact",
6093#endif
6094#ifdef FEAT_XCLIPBOARD
6095 "xterm_clipboard",
6096#endif
6097#ifdef FEAT_XTERM_SAVE
6098 "xterm_save",
6099#endif
6100#if defined(UNIX) && defined(FEAT_X11)
6101 "X11",
6102#endif
6103 NULL
6104 };
6105
6106 name = get_tv_string(&argvars[0]);
6107 for (i = 0; has_list[i] != NULL; ++i)
6108 if (STRICMP(name, has_list[i]) == 0)
6109 {
6110 n = TRUE;
6111 break;
6112 }
6113
6114 if (n == FALSE)
6115 {
6116 if (STRNICMP(name, "patch", 5) == 0)
6117 {
6118 if (name[5] == '-'
6119 && STRLEN(name) >= 11
6120 && vim_isdigit(name[6])
6121 && vim_isdigit(name[8])
6122 && vim_isdigit(name[10]))
6123 {
6124 int major = atoi((char *)name + 6);
6125 int minor = atoi((char *)name + 8);
6126
6127 /* Expect "patch-9.9.01234". */
6128 n = (major < VIM_VERSION_MAJOR
6129 || (major == VIM_VERSION_MAJOR
6130 && (minor < VIM_VERSION_MINOR
6131 || (minor == VIM_VERSION_MINOR
6132 && has_patch(atoi((char *)name + 10))))));
6133 }
6134 else
6135 n = has_patch(atoi((char *)name + 5));
6136 }
6137 else if (STRICMP(name, "vim_starting") == 0)
6138 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006139 else if (STRICMP(name, "ttyin") == 0)
6140 n = mch_input_isatty();
6141 else if (STRICMP(name, "ttyout") == 0)
6142 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143#ifdef FEAT_MBYTE
6144 else if (STRICMP(name, "multi_byte_encoding") == 0)
6145 n = has_mbyte;
6146#endif
6147#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6148 else if (STRICMP(name, "balloon_multiline") == 0)
6149 n = multiline_balloon_available();
6150#endif
6151#ifdef DYNAMIC_TCL
6152 else if (STRICMP(name, "tcl") == 0)
6153 n = tcl_enabled(FALSE);
6154#endif
6155#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6156 else if (STRICMP(name, "iconv") == 0)
6157 n = iconv_enabled(FALSE);
6158#endif
6159#ifdef DYNAMIC_LUA
6160 else if (STRICMP(name, "lua") == 0)
6161 n = lua_enabled(FALSE);
6162#endif
6163#ifdef DYNAMIC_MZSCHEME
6164 else if (STRICMP(name, "mzscheme") == 0)
6165 n = mzscheme_enabled(FALSE);
6166#endif
6167#ifdef DYNAMIC_RUBY
6168 else if (STRICMP(name, "ruby") == 0)
6169 n = ruby_enabled(FALSE);
6170#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006171#ifdef DYNAMIC_PYTHON
6172 else if (STRICMP(name, "python") == 0)
6173 n = python_enabled(FALSE);
6174#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175#ifdef DYNAMIC_PYTHON3
6176 else if (STRICMP(name, "python3") == 0)
6177 n = python3_enabled(FALSE);
6178#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006179#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6180 else if (STRICMP(name, "pythonx") == 0)
6181 {
6182# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6183 if (p_pyx == 0)
6184 n = python3_enabled(FALSE) || python_enabled(FALSE);
6185 else if (p_pyx == 3)
6186 n = python3_enabled(FALSE);
6187 else if (p_pyx == 2)
6188 n = python_enabled(FALSE);
6189# elif defined(DYNAMIC_PYTHON)
6190 n = python_enabled(FALSE);
6191# elif defined(DYNAMIC_PYTHON3)
6192 n = python3_enabled(FALSE);
6193# endif
6194 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195#endif
6196#ifdef DYNAMIC_PERL
6197 else if (STRICMP(name, "perl") == 0)
6198 n = perl_enabled(FALSE);
6199#endif
6200#ifdef FEAT_GUI
6201 else if (STRICMP(name, "gui_running") == 0)
6202 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006203# ifdef FEAT_BROWSE
6204 else if (STRICMP(name, "browse") == 0)
6205 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6206# endif
6207#endif
6208#ifdef FEAT_SYN_HL
6209 else if (STRICMP(name, "syntax_items") == 0)
6210 n = syntax_present(curwin);
6211#endif
6212#if defined(WIN3264)
6213 else if (STRICMP(name, "win95") == 0)
Bram Moolenaarcea912a2016-10-12 14:20:24 +02006214 n = FALSE; /* Win9x is no more supported. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215#endif
6216#ifdef FEAT_NETBEANS_INTG
6217 else if (STRICMP(name, "netbeans_enabled") == 0)
6218 n = netbeans_active();
6219#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006220#if defined(FEAT_TERMINAL) && defined(WIN3264)
6221 else if (STRICMP(name, "terminal") == 0)
6222 n = terminal_enabled();
6223#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006224 }
6225
6226 rettv->vval.v_number = n;
6227}
6228
6229/*
6230 * "has_key()" function
6231 */
6232 static void
6233f_has_key(typval_T *argvars, typval_T *rettv)
6234{
6235 if (argvars[0].v_type != VAR_DICT)
6236 {
6237 EMSG(_(e_dictreq));
6238 return;
6239 }
6240 if (argvars[0].vval.v_dict == NULL)
6241 return;
6242
6243 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6244 get_tv_string(&argvars[1]), -1) != NULL;
6245}
6246
6247/*
6248 * "haslocaldir()" function
6249 */
6250 static void
6251f_haslocaldir(typval_T *argvars, typval_T *rettv)
6252{
6253 win_T *wp = NULL;
6254
6255 wp = find_tabwin(&argvars[0], &argvars[1]);
6256 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6257}
6258
6259/*
6260 * "hasmapto()" function
6261 */
6262 static void
6263f_hasmapto(typval_T *argvars, typval_T *rettv)
6264{
6265 char_u *name;
6266 char_u *mode;
6267 char_u buf[NUMBUFLEN];
6268 int abbr = FALSE;
6269
6270 name = get_tv_string(&argvars[0]);
6271 if (argvars[1].v_type == VAR_UNKNOWN)
6272 mode = (char_u *)"nvo";
6273 else
6274 {
6275 mode = get_tv_string_buf(&argvars[1], buf);
6276 if (argvars[2].v_type != VAR_UNKNOWN)
6277 abbr = (int)get_tv_number(&argvars[2]);
6278 }
6279
6280 if (map_to_exists(name, mode, abbr))
6281 rettv->vval.v_number = TRUE;
6282 else
6283 rettv->vval.v_number = FALSE;
6284}
6285
6286/*
6287 * "histadd()" function
6288 */
6289 static void
6290f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6291{
6292#ifdef FEAT_CMDHIST
6293 int histype;
6294 char_u *str;
6295 char_u buf[NUMBUFLEN];
6296#endif
6297
6298 rettv->vval.v_number = FALSE;
6299 if (check_restricted() || check_secure())
6300 return;
6301#ifdef FEAT_CMDHIST
6302 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6303 histype = str != NULL ? get_histtype(str) : -1;
6304 if (histype >= 0)
6305 {
6306 str = get_tv_string_buf(&argvars[1], buf);
6307 if (*str != NUL)
6308 {
6309 init_history();
6310 add_to_history(histype, str, FALSE, NUL);
6311 rettv->vval.v_number = TRUE;
6312 return;
6313 }
6314 }
6315#endif
6316}
6317
6318/*
6319 * "histdel()" function
6320 */
6321 static void
6322f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6323{
6324#ifdef FEAT_CMDHIST
6325 int n;
6326 char_u buf[NUMBUFLEN];
6327 char_u *str;
6328
6329 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6330 if (str == NULL)
6331 n = 0;
6332 else if (argvars[1].v_type == VAR_UNKNOWN)
6333 /* only one argument: clear entire history */
6334 n = clr_history(get_histtype(str));
6335 else if (argvars[1].v_type == VAR_NUMBER)
6336 /* index given: remove that entry */
6337 n = del_history_idx(get_histtype(str),
6338 (int)get_tv_number(&argvars[1]));
6339 else
6340 /* string given: remove all matching entries */
6341 n = del_history_entry(get_histtype(str),
6342 get_tv_string_buf(&argvars[1], buf));
6343 rettv->vval.v_number = n;
6344#endif
6345}
6346
6347/*
6348 * "histget()" function
6349 */
6350 static void
6351f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6352{
6353#ifdef FEAT_CMDHIST
6354 int type;
6355 int idx;
6356 char_u *str;
6357
6358 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6359 if (str == NULL)
6360 rettv->vval.v_string = NULL;
6361 else
6362 {
6363 type = get_histtype(str);
6364 if (argvars[1].v_type == VAR_UNKNOWN)
6365 idx = get_history_idx(type);
6366 else
6367 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6368 /* -1 on type error */
6369 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6370 }
6371#else
6372 rettv->vval.v_string = NULL;
6373#endif
6374 rettv->v_type = VAR_STRING;
6375}
6376
6377/*
6378 * "histnr()" function
6379 */
6380 static void
6381f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6382{
6383 int i;
6384
6385#ifdef FEAT_CMDHIST
6386 char_u *history = get_tv_string_chk(&argvars[0]);
6387
6388 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6389 if (i >= HIST_CMD && i < HIST_COUNT)
6390 i = get_history_idx(i);
6391 else
6392#endif
6393 i = -1;
6394 rettv->vval.v_number = i;
6395}
6396
6397/*
6398 * "highlightID(name)" function
6399 */
6400 static void
6401f_hlID(typval_T *argvars, typval_T *rettv)
6402{
6403 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6404}
6405
6406/*
6407 * "highlight_exists()" function
6408 */
6409 static void
6410f_hlexists(typval_T *argvars, typval_T *rettv)
6411{
6412 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6413}
6414
6415/*
6416 * "hostname()" function
6417 */
6418 static void
6419f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6420{
6421 char_u hostname[256];
6422
6423 mch_get_host_name(hostname, 256);
6424 rettv->v_type = VAR_STRING;
6425 rettv->vval.v_string = vim_strsave(hostname);
6426}
6427
6428/*
6429 * iconv() function
6430 */
6431 static void
6432f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6433{
6434#ifdef FEAT_MBYTE
6435 char_u buf1[NUMBUFLEN];
6436 char_u buf2[NUMBUFLEN];
6437 char_u *from, *to, *str;
6438 vimconv_T vimconv;
6439#endif
6440
6441 rettv->v_type = VAR_STRING;
6442 rettv->vval.v_string = NULL;
6443
6444#ifdef FEAT_MBYTE
6445 str = get_tv_string(&argvars[0]);
6446 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6447 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6448 vimconv.vc_type = CONV_NONE;
6449 convert_setup(&vimconv, from, to);
6450
6451 /* If the encodings are equal, no conversion needed. */
6452 if (vimconv.vc_type == CONV_NONE)
6453 rettv->vval.v_string = vim_strsave(str);
6454 else
6455 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6456
6457 convert_setup(&vimconv, NULL, NULL);
6458 vim_free(from);
6459 vim_free(to);
6460#endif
6461}
6462
6463/*
6464 * "indent()" function
6465 */
6466 static void
6467f_indent(typval_T *argvars, typval_T *rettv)
6468{
6469 linenr_T lnum;
6470
6471 lnum = get_tv_lnum(argvars);
6472 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6473 rettv->vval.v_number = get_indent_lnum(lnum);
6474 else
6475 rettv->vval.v_number = -1;
6476}
6477
6478/*
6479 * "index()" function
6480 */
6481 static void
6482f_index(typval_T *argvars, typval_T *rettv)
6483{
6484 list_T *l;
6485 listitem_T *item;
6486 long idx = 0;
6487 int ic = FALSE;
6488
6489 rettv->vval.v_number = -1;
6490 if (argvars[0].v_type != VAR_LIST)
6491 {
6492 EMSG(_(e_listreq));
6493 return;
6494 }
6495 l = argvars[0].vval.v_list;
6496 if (l != NULL)
6497 {
6498 item = l->lv_first;
6499 if (argvars[2].v_type != VAR_UNKNOWN)
6500 {
6501 int error = FALSE;
6502
6503 /* Start at specified item. Use the cached index that list_find()
6504 * sets, so that a negative number also works. */
6505 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6506 idx = l->lv_idx;
6507 if (argvars[3].v_type != VAR_UNKNOWN)
6508 ic = (int)get_tv_number_chk(&argvars[3], &error);
6509 if (error)
6510 item = NULL;
6511 }
6512
6513 for ( ; item != NULL; item = item->li_next, ++idx)
6514 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6515 {
6516 rettv->vval.v_number = idx;
6517 break;
6518 }
6519 }
6520}
6521
6522static int inputsecret_flag = 0;
6523
6524/*
6525 * "input()" function
6526 * Also handles inputsecret() when inputsecret is set.
6527 */
6528 static void
6529f_input(typval_T *argvars, typval_T *rettv)
6530{
6531 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6532}
6533
6534/*
6535 * "inputdialog()" function
6536 */
6537 static void
6538f_inputdialog(typval_T *argvars, typval_T *rettv)
6539{
6540#if defined(FEAT_GUI_TEXTDIALOG)
6541 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6542 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6543 {
6544 char_u *message;
6545 char_u buf[NUMBUFLEN];
6546 char_u *defstr = (char_u *)"";
6547
6548 message = get_tv_string_chk(&argvars[0]);
6549 if (argvars[1].v_type != VAR_UNKNOWN
6550 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6551 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6552 else
6553 IObuff[0] = NUL;
6554 if (message != NULL && defstr != NULL
6555 && do_dialog(VIM_QUESTION, NULL, message,
6556 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6557 rettv->vval.v_string = vim_strsave(IObuff);
6558 else
6559 {
6560 if (message != NULL && defstr != NULL
6561 && argvars[1].v_type != VAR_UNKNOWN
6562 && argvars[2].v_type != VAR_UNKNOWN)
6563 rettv->vval.v_string = vim_strsave(
6564 get_tv_string_buf(&argvars[2], buf));
6565 else
6566 rettv->vval.v_string = NULL;
6567 }
6568 rettv->v_type = VAR_STRING;
6569 }
6570 else
6571#endif
6572 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6573}
6574
6575/*
6576 * "inputlist()" function
6577 */
6578 static void
6579f_inputlist(typval_T *argvars, typval_T *rettv)
6580{
6581 listitem_T *li;
6582 int selected;
6583 int mouse_used;
6584
6585#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006586 /* While starting up, there is no place to enter text. When running tests
6587 * with --not-a-term we assume feedkeys() will be used. */
6588 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589 return;
6590#endif
6591 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6592 {
6593 EMSG2(_(e_listarg), "inputlist()");
6594 return;
6595 }
6596
6597 msg_start();
6598 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6599 lines_left = Rows; /* avoid more prompt */
6600 msg_scroll = TRUE;
6601 msg_clr_eos();
6602
6603 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6604 {
6605 msg_puts(get_tv_string(&li->li_tv));
6606 msg_putchar('\n');
6607 }
6608
6609 /* Ask for choice. */
6610 selected = prompt_for_number(&mouse_used);
6611 if (mouse_used)
6612 selected -= lines_left;
6613
6614 rettv->vval.v_number = selected;
6615}
6616
6617
6618static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6619
6620/*
6621 * "inputrestore()" function
6622 */
6623 static void
6624f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6625{
6626 if (ga_userinput.ga_len > 0)
6627 {
6628 --ga_userinput.ga_len;
6629 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6630 + ga_userinput.ga_len);
6631 /* default return is zero == OK */
6632 }
6633 else if (p_verbose > 1)
6634 {
6635 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6636 rettv->vval.v_number = 1; /* Failed */
6637 }
6638}
6639
6640/*
6641 * "inputsave()" function
6642 */
6643 static void
6644f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6645{
6646 /* Add an entry to the stack of typeahead storage. */
6647 if (ga_grow(&ga_userinput, 1) == OK)
6648 {
6649 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6650 + ga_userinput.ga_len);
6651 ++ga_userinput.ga_len;
6652 /* default return is zero == OK */
6653 }
6654 else
6655 rettv->vval.v_number = 1; /* Failed */
6656}
6657
6658/*
6659 * "inputsecret()" function
6660 */
6661 static void
6662f_inputsecret(typval_T *argvars, typval_T *rettv)
6663{
6664 ++cmdline_star;
6665 ++inputsecret_flag;
6666 f_input(argvars, rettv);
6667 --cmdline_star;
6668 --inputsecret_flag;
6669}
6670
6671/*
6672 * "insert()" function
6673 */
6674 static void
6675f_insert(typval_T *argvars, typval_T *rettv)
6676{
6677 long before = 0;
6678 listitem_T *item;
6679 list_T *l;
6680 int error = FALSE;
6681
6682 if (argvars[0].v_type != VAR_LIST)
6683 EMSG2(_(e_listarg), "insert()");
6684 else if ((l = argvars[0].vval.v_list) != NULL
6685 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6686 {
6687 if (argvars[2].v_type != VAR_UNKNOWN)
6688 before = (long)get_tv_number_chk(&argvars[2], &error);
6689 if (error)
6690 return; /* type error; errmsg already given */
6691
6692 if (before == l->lv_len)
6693 item = NULL;
6694 else
6695 {
6696 item = list_find(l, before);
6697 if (item == NULL)
6698 {
6699 EMSGN(_(e_listidx), before);
6700 l = NULL;
6701 }
6702 }
6703 if (l != NULL)
6704 {
6705 list_insert_tv(l, &argvars[1], item);
6706 copy_tv(&argvars[0], rettv);
6707 }
6708 }
6709}
6710
6711/*
6712 * "invert(expr)" function
6713 */
6714 static void
6715f_invert(typval_T *argvars, typval_T *rettv)
6716{
6717 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6718}
6719
6720/*
6721 * "isdirectory()" function
6722 */
6723 static void
6724f_isdirectory(typval_T *argvars, typval_T *rettv)
6725{
6726 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6727}
6728
6729/*
6730 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6731 * or it refers to a List or Dictionary that is locked.
6732 */
6733 static int
6734tv_islocked(typval_T *tv)
6735{
6736 return (tv->v_lock & VAR_LOCKED)
6737 || (tv->v_type == VAR_LIST
6738 && tv->vval.v_list != NULL
6739 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6740 || (tv->v_type == VAR_DICT
6741 && tv->vval.v_dict != NULL
6742 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6743}
6744
6745/*
6746 * "islocked()" function
6747 */
6748 static void
6749f_islocked(typval_T *argvars, typval_T *rettv)
6750{
6751 lval_T lv;
6752 char_u *end;
6753 dictitem_T *di;
6754
6755 rettv->vval.v_number = -1;
6756 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006757 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 if (end != NULL && lv.ll_name != NULL)
6759 {
6760 if (*end != NUL)
6761 EMSG(_(e_trailing));
6762 else
6763 {
6764 if (lv.ll_tv == NULL)
6765 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006766 di = find_var(lv.ll_name, NULL, TRUE);
6767 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006769 /* Consider a variable locked when:
6770 * 1. the variable itself is locked
6771 * 2. the value of the variable is locked.
6772 * 3. the List or Dict value is locked.
6773 */
6774 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6775 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776 }
6777 }
6778 else if (lv.ll_range)
6779 EMSG(_("E786: Range not allowed"));
6780 else if (lv.ll_newkey != NULL)
6781 EMSG2(_(e_dictkey), lv.ll_newkey);
6782 else if (lv.ll_list != NULL)
6783 /* List item. */
6784 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6785 else
6786 /* Dictionary item. */
6787 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6788 }
6789 }
6790
6791 clear_lval(&lv);
6792}
6793
6794#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6795/*
6796 * "isnan()" function
6797 */
6798 static void
6799f_isnan(typval_T *argvars, typval_T *rettv)
6800{
6801 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6802 && isnan(argvars[0].vval.v_float);
6803}
6804#endif
6805
6806/*
6807 * "items(dict)" function
6808 */
6809 static void
6810f_items(typval_T *argvars, typval_T *rettv)
6811{
6812 dict_list(argvars, rettv, 2);
6813}
6814
6815#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6816/*
6817 * Get the job from the argument.
6818 * Returns NULL if the job is invalid.
6819 */
6820 static job_T *
6821get_job_arg(typval_T *tv)
6822{
6823 job_T *job;
6824
6825 if (tv->v_type != VAR_JOB)
6826 {
6827 EMSG2(_(e_invarg2), get_tv_string(tv));
6828 return NULL;
6829 }
6830 job = tv->vval.v_job;
6831
6832 if (job == NULL)
6833 EMSG(_("E916: not a valid job"));
6834 return job;
6835}
6836
6837/*
6838 * "job_getchannel()" function
6839 */
6840 static void
6841f_job_getchannel(typval_T *argvars, typval_T *rettv)
6842{
6843 job_T *job = get_job_arg(&argvars[0]);
6844
6845 if (job != NULL)
6846 {
6847 rettv->v_type = VAR_CHANNEL;
6848 rettv->vval.v_channel = job->jv_channel;
6849 if (job->jv_channel != NULL)
6850 ++job->jv_channel->ch_refcount;
6851 }
6852}
6853
6854/*
6855 * "job_info()" function
6856 */
6857 static void
6858f_job_info(typval_T *argvars, typval_T *rettv)
6859{
6860 job_T *job = get_job_arg(&argvars[0]);
6861
6862 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6863 job_info(job, rettv->vval.v_dict);
6864}
6865
6866/*
6867 * "job_setoptions()" function
6868 */
6869 static void
6870f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6871{
6872 job_T *job = get_job_arg(&argvars[0]);
6873 jobopt_T opt;
6874
6875 if (job == NULL)
6876 return;
6877 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02006878 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879 job_set_options(job, &opt);
6880 free_job_options(&opt);
6881}
6882
6883/*
6884 * "job_start()" function
6885 */
6886 static void
6887f_job_start(typval_T *argvars, typval_T *rettv)
6888{
6889 rettv->v_type = VAR_JOB;
6890 if (check_restricted() || check_secure())
6891 return;
Bram Moolenaarcb8bbe92017-07-16 13:48:22 +02006892 rettv->vval.v_job = job_start(argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893}
6894
6895/*
6896 * "job_status()" function
6897 */
6898 static void
6899f_job_status(typval_T *argvars, typval_T *rettv)
6900{
6901 job_T *job = get_job_arg(&argvars[0]);
6902
6903 if (job != NULL)
6904 {
6905 rettv->v_type = VAR_STRING;
6906 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6907 }
6908}
6909
6910/*
6911 * "job_stop()" function
6912 */
6913 static void
6914f_job_stop(typval_T *argvars, typval_T *rettv)
6915{
6916 job_T *job = get_job_arg(&argvars[0]);
6917
6918 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02006919 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920}
6921#endif
6922
6923/*
6924 * "join()" function
6925 */
6926 static void
6927f_join(typval_T *argvars, typval_T *rettv)
6928{
6929 garray_T ga;
6930 char_u *sep;
6931
6932 if (argvars[0].v_type != VAR_LIST)
6933 {
6934 EMSG(_(e_listreq));
6935 return;
6936 }
6937 if (argvars[0].vval.v_list == NULL)
6938 return;
6939 if (argvars[1].v_type == VAR_UNKNOWN)
6940 sep = (char_u *)" ";
6941 else
6942 sep = get_tv_string_chk(&argvars[1]);
6943
6944 rettv->v_type = VAR_STRING;
6945
6946 if (sep != NULL)
6947 {
6948 ga_init2(&ga, (int)sizeof(char), 80);
6949 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6950 ga_append(&ga, NUL);
6951 rettv->vval.v_string = (char_u *)ga.ga_data;
6952 }
6953 else
6954 rettv->vval.v_string = NULL;
6955}
6956
6957/*
6958 * "js_decode()" function
6959 */
6960 static void
6961f_js_decode(typval_T *argvars, typval_T *rettv)
6962{
6963 js_read_T reader;
6964
6965 reader.js_buf = get_tv_string(&argvars[0]);
6966 reader.js_fill = NULL;
6967 reader.js_used = 0;
6968 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6969 EMSG(_(e_invarg));
6970}
6971
6972/*
6973 * "js_encode()" function
6974 */
6975 static void
6976f_js_encode(typval_T *argvars, typval_T *rettv)
6977{
6978 rettv->v_type = VAR_STRING;
6979 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6980}
6981
6982/*
6983 * "json_decode()" function
6984 */
6985 static void
6986f_json_decode(typval_T *argvars, typval_T *rettv)
6987{
6988 js_read_T reader;
6989
6990 reader.js_buf = get_tv_string(&argvars[0]);
6991 reader.js_fill = NULL;
6992 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01006993 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006994}
6995
6996/*
6997 * "json_encode()" function
6998 */
6999 static void
7000f_json_encode(typval_T *argvars, typval_T *rettv)
7001{
7002 rettv->v_type = VAR_STRING;
7003 rettv->vval.v_string = json_encode(&argvars[0], 0);
7004}
7005
7006/*
7007 * "keys()" function
7008 */
7009 static void
7010f_keys(typval_T *argvars, typval_T *rettv)
7011{
7012 dict_list(argvars, rettv, 0);
7013}
7014
7015/*
7016 * "last_buffer_nr()" function.
7017 */
7018 static void
7019f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7020{
7021 int n = 0;
7022 buf_T *buf;
7023
Bram Moolenaar29323592016-07-24 22:04:11 +02007024 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025 if (n < buf->b_fnum)
7026 n = buf->b_fnum;
7027
7028 rettv->vval.v_number = n;
7029}
7030
7031/*
7032 * "len()" function
7033 */
7034 static void
7035f_len(typval_T *argvars, typval_T *rettv)
7036{
7037 switch (argvars[0].v_type)
7038 {
7039 case VAR_STRING:
7040 case VAR_NUMBER:
7041 rettv->vval.v_number = (varnumber_T)STRLEN(
7042 get_tv_string(&argvars[0]));
7043 break;
7044 case VAR_LIST:
7045 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7046 break;
7047 case VAR_DICT:
7048 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7049 break;
7050 case VAR_UNKNOWN:
7051 case VAR_SPECIAL:
7052 case VAR_FLOAT:
7053 case VAR_FUNC:
7054 case VAR_PARTIAL:
7055 case VAR_JOB:
7056 case VAR_CHANNEL:
7057 EMSG(_("E701: Invalid type for len()"));
7058 break;
7059 }
7060}
7061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007063libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007064{
7065#ifdef FEAT_LIBCALL
7066 char_u *string_in;
7067 char_u **string_result;
7068 int nr_result;
7069#endif
7070
7071 rettv->v_type = type;
7072 if (type != VAR_NUMBER)
7073 rettv->vval.v_string = NULL;
7074
7075 if (check_restricted() || check_secure())
7076 return;
7077
7078#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007079 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7081 {
7082 string_in = NULL;
7083 if (argvars[2].v_type == VAR_STRING)
7084 string_in = argvars[2].vval.v_string;
7085 if (type == VAR_NUMBER)
7086 string_result = NULL;
7087 else
7088 string_result = &rettv->vval.v_string;
7089 if (mch_libcall(argvars[0].vval.v_string,
7090 argvars[1].vval.v_string,
7091 string_in,
7092 argvars[2].vval.v_number,
7093 string_result,
7094 &nr_result) == OK
7095 && type == VAR_NUMBER)
7096 rettv->vval.v_number = nr_result;
7097 }
7098#endif
7099}
7100
7101/*
7102 * "libcall()" function
7103 */
7104 static void
7105f_libcall(typval_T *argvars, typval_T *rettv)
7106{
7107 libcall_common(argvars, rettv, VAR_STRING);
7108}
7109
7110/*
7111 * "libcallnr()" function
7112 */
7113 static void
7114f_libcallnr(typval_T *argvars, typval_T *rettv)
7115{
7116 libcall_common(argvars, rettv, VAR_NUMBER);
7117}
7118
7119/*
7120 * "line(string)" function
7121 */
7122 static void
7123f_line(typval_T *argvars, typval_T *rettv)
7124{
7125 linenr_T lnum = 0;
7126 pos_T *fp;
7127 int fnum;
7128
7129 fp = var2fpos(&argvars[0], TRUE, &fnum);
7130 if (fp != NULL)
7131 lnum = fp->lnum;
7132 rettv->vval.v_number = lnum;
7133}
7134
7135/*
7136 * "line2byte(lnum)" function
7137 */
7138 static void
7139f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7140{
7141#ifndef FEAT_BYTEOFF
7142 rettv->vval.v_number = -1;
7143#else
7144 linenr_T lnum;
7145
7146 lnum = get_tv_lnum(argvars);
7147 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7148 rettv->vval.v_number = -1;
7149 else
7150 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7151 if (rettv->vval.v_number >= 0)
7152 ++rettv->vval.v_number;
7153#endif
7154}
7155
7156/*
7157 * "lispindent(lnum)" function
7158 */
7159 static void
7160f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7161{
7162#ifdef FEAT_LISP
7163 pos_T pos;
7164 linenr_T lnum;
7165
7166 pos = curwin->w_cursor;
7167 lnum = get_tv_lnum(argvars);
7168 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7169 {
7170 curwin->w_cursor.lnum = lnum;
7171 rettv->vval.v_number = get_lisp_indent();
7172 curwin->w_cursor = pos;
7173 }
7174 else
7175#endif
7176 rettv->vval.v_number = -1;
7177}
7178
7179/*
7180 * "localtime()" function
7181 */
7182 static void
7183f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7184{
7185 rettv->vval.v_number = (varnumber_T)time(NULL);
7186}
7187
7188static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7189
7190 static void
7191get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7192{
7193 char_u *keys;
7194 char_u *which;
7195 char_u buf[NUMBUFLEN];
7196 char_u *keys_buf = NULL;
7197 char_u *rhs;
7198 int mode;
7199 int abbr = FALSE;
7200 int get_dict = FALSE;
7201 mapblock_T *mp;
7202 int buffer_local;
7203
7204 /* return empty string for failure */
7205 rettv->v_type = VAR_STRING;
7206 rettv->vval.v_string = NULL;
7207
7208 keys = get_tv_string(&argvars[0]);
7209 if (*keys == NUL)
7210 return;
7211
7212 if (argvars[1].v_type != VAR_UNKNOWN)
7213 {
7214 which = get_tv_string_buf_chk(&argvars[1], buf);
7215 if (argvars[2].v_type != VAR_UNKNOWN)
7216 {
7217 abbr = (int)get_tv_number(&argvars[2]);
7218 if (argvars[3].v_type != VAR_UNKNOWN)
7219 get_dict = (int)get_tv_number(&argvars[3]);
7220 }
7221 }
7222 else
7223 which = (char_u *)"";
7224 if (which == NULL)
7225 return;
7226
7227 mode = get_map_mode(&which, 0);
7228
7229 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7230 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7231 vim_free(keys_buf);
7232
7233 if (!get_dict)
7234 {
7235 /* Return a string. */
7236 if (rhs != NULL)
7237 rettv->vval.v_string = str2special_save(rhs, FALSE);
7238
7239 }
7240 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7241 {
7242 /* Return a dictionary. */
7243 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7244 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7245 dict_T *dict = rettv->vval.v_dict;
7246
7247 dict_add_nr_str(dict, "lhs", 0L, lhs);
7248 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7249 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7250 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7251 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7252 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7253 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7254 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7255 dict_add_nr_str(dict, "mode", 0L, mapmode);
7256
7257 vim_free(lhs);
7258 vim_free(mapmode);
7259 }
7260}
7261
7262#ifdef FEAT_FLOAT
7263/*
7264 * "log()" function
7265 */
7266 static void
7267f_log(typval_T *argvars, typval_T *rettv)
7268{
7269 float_T f = 0.0;
7270
7271 rettv->v_type = VAR_FLOAT;
7272 if (get_float_arg(argvars, &f) == OK)
7273 rettv->vval.v_float = log(f);
7274 else
7275 rettv->vval.v_float = 0.0;
7276}
7277
7278/*
7279 * "log10()" function
7280 */
7281 static void
7282f_log10(typval_T *argvars, typval_T *rettv)
7283{
7284 float_T f = 0.0;
7285
7286 rettv->v_type = VAR_FLOAT;
7287 if (get_float_arg(argvars, &f) == OK)
7288 rettv->vval.v_float = log10(f);
7289 else
7290 rettv->vval.v_float = 0.0;
7291}
7292#endif
7293
7294#ifdef FEAT_LUA
7295/*
7296 * "luaeval()" function
7297 */
7298 static void
7299f_luaeval(typval_T *argvars, typval_T *rettv)
7300{
7301 char_u *str;
7302 char_u buf[NUMBUFLEN];
7303
7304 str = get_tv_string_buf(&argvars[0], buf);
7305 do_luaeval(str, argvars + 1, rettv);
7306}
7307#endif
7308
7309/*
7310 * "map()" function
7311 */
7312 static void
7313f_map(typval_T *argvars, typval_T *rettv)
7314{
7315 filter_map(argvars, rettv, TRUE);
7316}
7317
7318/*
7319 * "maparg()" function
7320 */
7321 static void
7322f_maparg(typval_T *argvars, typval_T *rettv)
7323{
7324 get_maparg(argvars, rettv, TRUE);
7325}
7326
7327/*
7328 * "mapcheck()" function
7329 */
7330 static void
7331f_mapcheck(typval_T *argvars, typval_T *rettv)
7332{
7333 get_maparg(argvars, rettv, FALSE);
7334}
7335
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007336typedef enum
7337{
7338 MATCH_END, /* matchend() */
7339 MATCH_MATCH, /* match() */
7340 MATCH_STR, /* matchstr() */
7341 MATCH_LIST, /* matchlist() */
7342 MATCH_POS /* matchstrpos() */
7343} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344
7345 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007346find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347{
7348 char_u *str = NULL;
7349 long len = 0;
7350 char_u *expr = NULL;
7351 char_u *pat;
7352 regmatch_T regmatch;
7353 char_u patbuf[NUMBUFLEN];
7354 char_u strbuf[NUMBUFLEN];
7355 char_u *save_cpo;
7356 long start = 0;
7357 long nth = 1;
7358 colnr_T startcol = 0;
7359 int match = 0;
7360 list_T *l = NULL;
7361 listitem_T *li = NULL;
7362 long idx = 0;
7363 char_u *tofree = NULL;
7364
7365 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7366 save_cpo = p_cpo;
7367 p_cpo = (char_u *)"";
7368
7369 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007370 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007371 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007372 /* type MATCH_LIST: return empty list when there are no matches.
7373 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 if (rettv_list_alloc(rettv) == FAIL)
7375 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007376 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 && (list_append_string(rettv->vval.v_list,
7378 (char_u *)"", 0) == FAIL
7379 || list_append_number(rettv->vval.v_list,
7380 (varnumber_T)-1) == FAIL
7381 || list_append_number(rettv->vval.v_list,
7382 (varnumber_T)-1) == FAIL
7383 || list_append_number(rettv->vval.v_list,
7384 (varnumber_T)-1) == FAIL))
7385 {
7386 list_free(rettv->vval.v_list);
7387 rettv->vval.v_list = NULL;
7388 goto theend;
7389 }
7390 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007391 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 {
7393 rettv->v_type = VAR_STRING;
7394 rettv->vval.v_string = NULL;
7395 }
7396
7397 if (argvars[0].v_type == VAR_LIST)
7398 {
7399 if ((l = argvars[0].vval.v_list) == NULL)
7400 goto theend;
7401 li = l->lv_first;
7402 }
7403 else
7404 {
7405 expr = str = get_tv_string(&argvars[0]);
7406 len = (long)STRLEN(str);
7407 }
7408
7409 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7410 if (pat == NULL)
7411 goto theend;
7412
7413 if (argvars[2].v_type != VAR_UNKNOWN)
7414 {
7415 int error = FALSE;
7416
7417 start = (long)get_tv_number_chk(&argvars[2], &error);
7418 if (error)
7419 goto theend;
7420 if (l != NULL)
7421 {
7422 li = list_find(l, start);
7423 if (li == NULL)
7424 goto theend;
7425 idx = l->lv_idx; /* use the cached index */
7426 }
7427 else
7428 {
7429 if (start < 0)
7430 start = 0;
7431 if (start > len)
7432 goto theend;
7433 /* When "count" argument is there ignore matches before "start",
7434 * otherwise skip part of the string. Differs when pattern is "^"
7435 * or "\<". */
7436 if (argvars[3].v_type != VAR_UNKNOWN)
7437 startcol = start;
7438 else
7439 {
7440 str += start;
7441 len -= start;
7442 }
7443 }
7444
7445 if (argvars[3].v_type != VAR_UNKNOWN)
7446 nth = (long)get_tv_number_chk(&argvars[3], &error);
7447 if (error)
7448 goto theend;
7449 }
7450
7451 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7452 if (regmatch.regprog != NULL)
7453 {
7454 regmatch.rm_ic = p_ic;
7455
7456 for (;;)
7457 {
7458 if (l != NULL)
7459 {
7460 if (li == NULL)
7461 {
7462 match = FALSE;
7463 break;
7464 }
7465 vim_free(tofree);
7466 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7467 if (str == NULL)
7468 break;
7469 }
7470
7471 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7472
7473 if (match && --nth <= 0)
7474 break;
7475 if (l == NULL && !match)
7476 break;
7477
7478 /* Advance to just after the match. */
7479 if (l != NULL)
7480 {
7481 li = li->li_next;
7482 ++idx;
7483 }
7484 else
7485 {
7486#ifdef FEAT_MBYTE
7487 startcol = (colnr_T)(regmatch.startp[0]
7488 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7489#else
7490 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7491#endif
7492 if (startcol > (colnr_T)len
7493 || str + startcol <= regmatch.startp[0])
7494 {
7495 match = FALSE;
7496 break;
7497 }
7498 }
7499 }
7500
7501 if (match)
7502 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007503 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 {
7505 listitem_T *li1 = rettv->vval.v_list->lv_first;
7506 listitem_T *li2 = li1->li_next;
7507 listitem_T *li3 = li2->li_next;
7508 listitem_T *li4 = li3->li_next;
7509
7510 vim_free(li1->li_tv.vval.v_string);
7511 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7512 (int)(regmatch.endp[0] - regmatch.startp[0]));
7513 li3->li_tv.vval.v_number =
7514 (varnumber_T)(regmatch.startp[0] - expr);
7515 li4->li_tv.vval.v_number =
7516 (varnumber_T)(regmatch.endp[0] - expr);
7517 if (l != NULL)
7518 li2->li_tv.vval.v_number = (varnumber_T)idx;
7519 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007520 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 {
7522 int i;
7523
7524 /* return list with matched string and submatches */
7525 for (i = 0; i < NSUBEXP; ++i)
7526 {
7527 if (regmatch.endp[i] == NULL)
7528 {
7529 if (list_append_string(rettv->vval.v_list,
7530 (char_u *)"", 0) == FAIL)
7531 break;
7532 }
7533 else if (list_append_string(rettv->vval.v_list,
7534 regmatch.startp[i],
7535 (int)(regmatch.endp[i] - regmatch.startp[i]))
7536 == FAIL)
7537 break;
7538 }
7539 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007540 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007541 {
7542 /* return matched string */
7543 if (l != NULL)
7544 copy_tv(&li->li_tv, rettv);
7545 else
7546 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7547 (int)(regmatch.endp[0] - regmatch.startp[0]));
7548 }
7549 else if (l != NULL)
7550 rettv->vval.v_number = idx;
7551 else
7552 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007553 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554 rettv->vval.v_number =
7555 (varnumber_T)(regmatch.startp[0] - str);
7556 else
7557 rettv->vval.v_number =
7558 (varnumber_T)(regmatch.endp[0] - str);
7559 rettv->vval.v_number += (varnumber_T)(str - expr);
7560 }
7561 }
7562 vim_regfree(regmatch.regprog);
7563 }
7564
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007565theend:
7566 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567 /* matchstrpos() without a list: drop the second item. */
7568 listitem_remove(rettv->vval.v_list,
7569 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570 vim_free(tofree);
7571 p_cpo = save_cpo;
7572}
7573
7574/*
7575 * "match()" function
7576 */
7577 static void
7578f_match(typval_T *argvars, typval_T *rettv)
7579{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007580 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581}
7582
7583/*
7584 * "matchadd()" function
7585 */
7586 static void
7587f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7588{
7589#ifdef FEAT_SEARCH_EXTRA
7590 char_u buf[NUMBUFLEN];
7591 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7592 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7593 int prio = 10; /* default priority */
7594 int id = -1;
7595 int error = FALSE;
7596 char_u *conceal_char = NULL;
7597
7598 rettv->vval.v_number = -1;
7599
7600 if (grp == NULL || pat == NULL)
7601 return;
7602 if (argvars[2].v_type != VAR_UNKNOWN)
7603 {
7604 prio = (int)get_tv_number_chk(&argvars[2], &error);
7605 if (argvars[3].v_type != VAR_UNKNOWN)
7606 {
7607 id = (int)get_tv_number_chk(&argvars[3], &error);
7608 if (argvars[4].v_type != VAR_UNKNOWN)
7609 {
7610 if (argvars[4].v_type != VAR_DICT)
7611 {
7612 EMSG(_(e_dictreq));
7613 return;
7614 }
7615 if (dict_find(argvars[4].vval.v_dict,
7616 (char_u *)"conceal", -1) != NULL)
7617 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7618 (char_u *)"conceal", FALSE);
7619 }
7620 }
7621 }
7622 if (error == TRUE)
7623 return;
7624 if (id >= 1 && id <= 3)
7625 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007626 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 return;
7628 }
7629
7630 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7631 conceal_char);
7632#endif
7633}
7634
7635/*
7636 * "matchaddpos()" function
7637 */
7638 static void
7639f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7640{
7641#ifdef FEAT_SEARCH_EXTRA
7642 char_u buf[NUMBUFLEN];
7643 char_u *group;
7644 int prio = 10;
7645 int id = -1;
7646 int error = FALSE;
7647 list_T *l;
7648 char_u *conceal_char = NULL;
7649
7650 rettv->vval.v_number = -1;
7651
7652 group = get_tv_string_buf_chk(&argvars[0], buf);
7653 if (group == NULL)
7654 return;
7655
7656 if (argvars[1].v_type != VAR_LIST)
7657 {
7658 EMSG2(_(e_listarg), "matchaddpos()");
7659 return;
7660 }
7661 l = argvars[1].vval.v_list;
7662 if (l == NULL)
7663 return;
7664
7665 if (argvars[2].v_type != VAR_UNKNOWN)
7666 {
7667 prio = (int)get_tv_number_chk(&argvars[2], &error);
7668 if (argvars[3].v_type != VAR_UNKNOWN)
7669 {
7670 id = (int)get_tv_number_chk(&argvars[3], &error);
7671 if (argvars[4].v_type != VAR_UNKNOWN)
7672 {
7673 if (argvars[4].v_type != VAR_DICT)
7674 {
7675 EMSG(_(e_dictreq));
7676 return;
7677 }
7678 if (dict_find(argvars[4].vval.v_dict,
7679 (char_u *)"conceal", -1) != NULL)
7680 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7681 (char_u *)"conceal", FALSE);
7682 }
7683 }
7684 }
7685 if (error == TRUE)
7686 return;
7687
7688 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7689 if (id == 1 || id == 2)
7690 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007691 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007692 return;
7693 }
7694
7695 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7696 conceal_char);
7697#endif
7698}
7699
7700/*
7701 * "matcharg()" function
7702 */
7703 static void
7704f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7705{
7706 if (rettv_list_alloc(rettv) == OK)
7707 {
7708#ifdef FEAT_SEARCH_EXTRA
7709 int id = (int)get_tv_number(&argvars[0]);
7710 matchitem_T *m;
7711
7712 if (id >= 1 && id <= 3)
7713 {
7714 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7715 {
7716 list_append_string(rettv->vval.v_list,
7717 syn_id2name(m->hlg_id), -1);
7718 list_append_string(rettv->vval.v_list, m->pattern, -1);
7719 }
7720 else
7721 {
7722 list_append_string(rettv->vval.v_list, NULL, -1);
7723 list_append_string(rettv->vval.v_list, NULL, -1);
7724 }
7725 }
7726#endif
7727 }
7728}
7729
7730/*
7731 * "matchdelete()" function
7732 */
7733 static void
7734f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7735{
7736#ifdef FEAT_SEARCH_EXTRA
7737 rettv->vval.v_number = match_delete(curwin,
7738 (int)get_tv_number(&argvars[0]), TRUE);
7739#endif
7740}
7741
7742/*
7743 * "matchend()" function
7744 */
7745 static void
7746f_matchend(typval_T *argvars, typval_T *rettv)
7747{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007748 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749}
7750
7751/*
7752 * "matchlist()" function
7753 */
7754 static void
7755f_matchlist(typval_T *argvars, typval_T *rettv)
7756{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007757 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007758}
7759
7760/*
7761 * "matchstr()" function
7762 */
7763 static void
7764f_matchstr(typval_T *argvars, typval_T *rettv)
7765{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007766 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767}
7768
7769/*
7770 * "matchstrpos()" function
7771 */
7772 static void
7773f_matchstrpos(typval_T *argvars, typval_T *rettv)
7774{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007775 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776}
7777
7778static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7779
7780 static void
7781max_min(typval_T *argvars, typval_T *rettv, int domax)
7782{
7783 varnumber_T n = 0;
7784 varnumber_T i;
7785 int error = FALSE;
7786
7787 if (argvars[0].v_type == VAR_LIST)
7788 {
7789 list_T *l;
7790 listitem_T *li;
7791
7792 l = argvars[0].vval.v_list;
7793 if (l != NULL)
7794 {
7795 li = l->lv_first;
7796 if (li != NULL)
7797 {
7798 n = get_tv_number_chk(&li->li_tv, &error);
7799 for (;;)
7800 {
7801 li = li->li_next;
7802 if (li == NULL)
7803 break;
7804 i = get_tv_number_chk(&li->li_tv, &error);
7805 if (domax ? i > n : i < n)
7806 n = i;
7807 }
7808 }
7809 }
7810 }
7811 else if (argvars[0].v_type == VAR_DICT)
7812 {
7813 dict_T *d;
7814 int first = TRUE;
7815 hashitem_T *hi;
7816 int todo;
7817
7818 d = argvars[0].vval.v_dict;
7819 if (d != NULL)
7820 {
7821 todo = (int)d->dv_hashtab.ht_used;
7822 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7823 {
7824 if (!HASHITEM_EMPTY(hi))
7825 {
7826 --todo;
7827 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7828 if (first)
7829 {
7830 n = i;
7831 first = FALSE;
7832 }
7833 else if (domax ? i > n : i < n)
7834 n = i;
7835 }
7836 }
7837 }
7838 }
7839 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007840 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841 rettv->vval.v_number = error ? 0 : n;
7842}
7843
7844/*
7845 * "max()" function
7846 */
7847 static void
7848f_max(typval_T *argvars, typval_T *rettv)
7849{
7850 max_min(argvars, rettv, TRUE);
7851}
7852
7853/*
7854 * "min()" function
7855 */
7856 static void
7857f_min(typval_T *argvars, typval_T *rettv)
7858{
7859 max_min(argvars, rettv, FALSE);
7860}
7861
7862static int mkdir_recurse(char_u *dir, int prot);
7863
7864/*
7865 * Create the directory in which "dir" is located, and higher levels when
7866 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007867 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 */
7869 static int
7870mkdir_recurse(char_u *dir, int prot)
7871{
7872 char_u *p;
7873 char_u *updir;
7874 int r = FAIL;
7875
7876 /* Get end of directory name in "dir".
7877 * We're done when it's "/" or "c:/". */
7878 p = gettail_sep(dir);
7879 if (p <= get_past_head(dir))
7880 return OK;
7881
7882 /* If the directory exists we're done. Otherwise: create it.*/
7883 updir = vim_strnsave(dir, (int)(p - dir));
7884 if (updir == NULL)
7885 return FAIL;
7886 if (mch_isdir(updir))
7887 r = OK;
7888 else if (mkdir_recurse(updir, prot) == OK)
7889 r = vim_mkdir_emsg(updir, prot);
7890 vim_free(updir);
7891 return r;
7892}
7893
7894#ifdef vim_mkdir
7895/*
7896 * "mkdir()" function
7897 */
7898 static void
7899f_mkdir(typval_T *argvars, typval_T *rettv)
7900{
7901 char_u *dir;
7902 char_u buf[NUMBUFLEN];
7903 int prot = 0755;
7904
7905 rettv->vval.v_number = FAIL;
7906 if (check_restricted() || check_secure())
7907 return;
7908
7909 dir = get_tv_string_buf(&argvars[0], buf);
7910 if (*dir == NUL)
7911 rettv->vval.v_number = FAIL;
7912 else
7913 {
7914 if (*gettail(dir) == NUL)
7915 /* remove trailing slashes */
7916 *gettail_sep(dir) = NUL;
7917
7918 if (argvars[1].v_type != VAR_UNKNOWN)
7919 {
7920 if (argvars[2].v_type != VAR_UNKNOWN)
7921 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7922 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7923 mkdir_recurse(dir, prot);
7924 }
7925 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7926 }
7927}
7928#endif
7929
7930/*
7931 * "mode()" function
7932 */
7933 static void
7934f_mode(typval_T *argvars, typval_T *rettv)
7935{
7936 char_u buf[3];
7937
7938 buf[1] = NUL;
7939 buf[2] = NUL;
7940
7941 if (time_for_testing == 93784)
7942 {
7943 /* Testing the two-character code. */
7944 buf[0] = 'x';
7945 buf[1] = '!';
7946 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007947#ifdef FEAT_TERMINAL
7948 else if (term_use_loop())
7949 buf[0] = 't';
7950#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951 else if (VIsual_active)
7952 {
7953 if (VIsual_select)
7954 buf[0] = VIsual_mode + 's' - 'v';
7955 else
7956 buf[0] = VIsual_mode;
7957 }
7958 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7959 || State == CONFIRM)
7960 {
7961 buf[0] = 'r';
7962 if (State == ASKMORE)
7963 buf[1] = 'm';
7964 else if (State == CONFIRM)
7965 buf[1] = '?';
7966 }
7967 else if (State == EXTERNCMD)
7968 buf[0] = '!';
7969 else if (State & INSERT)
7970 {
7971#ifdef FEAT_VREPLACE
7972 if (State & VREPLACE_FLAG)
7973 {
7974 buf[0] = 'R';
7975 buf[1] = 'v';
7976 }
7977 else
7978#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01007979 {
7980 if (State & REPLACE_FLAG)
7981 buf[0] = 'R';
7982 else
7983 buf[0] = 'i';
7984#ifdef FEAT_INS_EXPAND
7985 if (ins_compl_active())
7986 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007987 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007988 buf[1] = 'x';
7989#endif
7990 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007992 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 {
7994 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007995 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007996 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007997 else if (exmode_active == EXMODE_NORMAL)
7998 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007999 }
8000 else
8001 {
8002 buf[0] = 'n';
8003 if (finish_op)
8004 buf[1] = 'o';
8005 }
8006
8007 /* Clear out the minor mode when the argument is not a non-zero number or
8008 * non-empty string. */
8009 if (!non_zero_arg(&argvars[0]))
8010 buf[1] = NUL;
8011
8012 rettv->vval.v_string = vim_strsave(buf);
8013 rettv->v_type = VAR_STRING;
8014}
8015
8016#if defined(FEAT_MZSCHEME) || defined(PROTO)
8017/*
8018 * "mzeval()" function
8019 */
8020 static void
8021f_mzeval(typval_T *argvars, typval_T *rettv)
8022{
8023 char_u *str;
8024 char_u buf[NUMBUFLEN];
8025
8026 str = get_tv_string_buf(&argvars[0], buf);
8027 do_mzeval(str, rettv);
8028}
8029
8030 void
8031mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8032{
8033 typval_T argvars[3];
8034
8035 argvars[0].v_type = VAR_STRING;
8036 argvars[0].vval.v_string = name;
8037 copy_tv(args, &argvars[1]);
8038 argvars[2].v_type = VAR_UNKNOWN;
8039 f_call(argvars, rettv);
8040 clear_tv(&argvars[1]);
8041}
8042#endif
8043
8044/*
8045 * "nextnonblank()" function
8046 */
8047 static void
8048f_nextnonblank(typval_T *argvars, typval_T *rettv)
8049{
8050 linenr_T lnum;
8051
8052 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8053 {
8054 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8055 {
8056 lnum = 0;
8057 break;
8058 }
8059 if (*skipwhite(ml_get(lnum)) != NUL)
8060 break;
8061 }
8062 rettv->vval.v_number = lnum;
8063}
8064
8065/*
8066 * "nr2char()" function
8067 */
8068 static void
8069f_nr2char(typval_T *argvars, typval_T *rettv)
8070{
8071 char_u buf[NUMBUFLEN];
8072
8073#ifdef FEAT_MBYTE
8074 if (has_mbyte)
8075 {
8076 int utf8 = 0;
8077
8078 if (argvars[1].v_type != VAR_UNKNOWN)
8079 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8080 if (utf8)
8081 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8082 else
8083 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8084 }
8085 else
8086#endif
8087 {
8088 buf[0] = (char_u)get_tv_number(&argvars[0]);
8089 buf[1] = NUL;
8090 }
8091 rettv->v_type = VAR_STRING;
8092 rettv->vval.v_string = vim_strsave(buf);
8093}
8094
8095/*
8096 * "or(expr, expr)" function
8097 */
8098 static void
8099f_or(typval_T *argvars, typval_T *rettv)
8100{
8101 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8102 | get_tv_number_chk(&argvars[1], NULL);
8103}
8104
8105/*
8106 * "pathshorten()" function
8107 */
8108 static void
8109f_pathshorten(typval_T *argvars, typval_T *rettv)
8110{
8111 char_u *p;
8112
8113 rettv->v_type = VAR_STRING;
8114 p = get_tv_string_chk(&argvars[0]);
8115 if (p == NULL)
8116 rettv->vval.v_string = NULL;
8117 else
8118 {
8119 p = vim_strsave(p);
8120 rettv->vval.v_string = p;
8121 if (p != NULL)
8122 shorten_dir(p);
8123 }
8124}
8125
8126#ifdef FEAT_PERL
8127/*
8128 * "perleval()" function
8129 */
8130 static void
8131f_perleval(typval_T *argvars, typval_T *rettv)
8132{
8133 char_u *str;
8134 char_u buf[NUMBUFLEN];
8135
8136 str = get_tv_string_buf(&argvars[0], buf);
8137 do_perleval(str, rettv);
8138}
8139#endif
8140
8141#ifdef FEAT_FLOAT
8142/*
8143 * "pow()" function
8144 */
8145 static void
8146f_pow(typval_T *argvars, typval_T *rettv)
8147{
8148 float_T fx = 0.0, fy = 0.0;
8149
8150 rettv->v_type = VAR_FLOAT;
8151 if (get_float_arg(argvars, &fx) == OK
8152 && get_float_arg(&argvars[1], &fy) == OK)
8153 rettv->vval.v_float = pow(fx, fy);
8154 else
8155 rettv->vval.v_float = 0.0;
8156}
8157#endif
8158
8159/*
8160 * "prevnonblank()" function
8161 */
8162 static void
8163f_prevnonblank(typval_T *argvars, typval_T *rettv)
8164{
8165 linenr_T lnum;
8166
8167 lnum = get_tv_lnum(argvars);
8168 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8169 lnum = 0;
8170 else
8171 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8172 --lnum;
8173 rettv->vval.v_number = lnum;
8174}
8175
8176/* This dummy va_list is here because:
8177 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8178 * - locally in the function results in a "used before set" warning
8179 * - using va_start() to initialize it gives "function with fixed args" error */
8180static va_list ap;
8181
8182/*
8183 * "printf()" function
8184 */
8185 static void
8186f_printf(typval_T *argvars, typval_T *rettv)
8187{
8188 char_u buf[NUMBUFLEN];
8189 int len;
8190 char_u *s;
8191 int saved_did_emsg = did_emsg;
8192 char *fmt;
8193
8194 rettv->v_type = VAR_STRING;
8195 rettv->vval.v_string = NULL;
8196
8197 /* Get the required length, allocate the buffer and do it for real. */
8198 did_emsg = FALSE;
8199 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008200 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201 if (!did_emsg)
8202 {
8203 s = alloc(len + 1);
8204 if (s != NULL)
8205 {
8206 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008207 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8208 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209 }
8210 }
8211 did_emsg |= saved_did_emsg;
8212}
8213
8214/*
8215 * "pumvisible()" function
8216 */
8217 static void
8218f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8219{
8220#ifdef FEAT_INS_EXPAND
8221 if (pum_visible())
8222 rettv->vval.v_number = 1;
8223#endif
8224}
8225
8226#ifdef FEAT_PYTHON3
8227/*
8228 * "py3eval()" function
8229 */
8230 static void
8231f_py3eval(typval_T *argvars, typval_T *rettv)
8232{
8233 char_u *str;
8234 char_u buf[NUMBUFLEN];
8235
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008236 if (p_pyx == 0)
8237 p_pyx = 3;
8238
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239 str = get_tv_string_buf(&argvars[0], buf);
8240 do_py3eval(str, rettv);
8241}
8242#endif
8243
8244#ifdef FEAT_PYTHON
8245/*
8246 * "pyeval()" function
8247 */
8248 static void
8249f_pyeval(typval_T *argvars, typval_T *rettv)
8250{
8251 char_u *str;
8252 char_u buf[NUMBUFLEN];
8253
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008254 if (p_pyx == 0)
8255 p_pyx = 2;
8256
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 str = get_tv_string_buf(&argvars[0], buf);
8258 do_pyeval(str, rettv);
8259}
8260#endif
8261
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008262#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8263/*
8264 * "pyxeval()" function
8265 */
8266 static void
8267f_pyxeval(typval_T *argvars, typval_T *rettv)
8268{
8269# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8270 init_pyxversion();
8271 if (p_pyx == 2)
8272 f_pyeval(argvars, rettv);
8273 else
8274 f_py3eval(argvars, rettv);
8275# elif defined(FEAT_PYTHON)
8276 f_pyeval(argvars, rettv);
8277# elif defined(FEAT_PYTHON3)
8278 f_py3eval(argvars, rettv);
8279# endif
8280}
8281#endif
8282
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283/*
8284 * "range()" function
8285 */
8286 static void
8287f_range(typval_T *argvars, typval_T *rettv)
8288{
8289 varnumber_T start;
8290 varnumber_T end;
8291 varnumber_T stride = 1;
8292 varnumber_T i;
8293 int error = FALSE;
8294
8295 start = get_tv_number_chk(&argvars[0], &error);
8296 if (argvars[1].v_type == VAR_UNKNOWN)
8297 {
8298 end = start - 1;
8299 start = 0;
8300 }
8301 else
8302 {
8303 end = get_tv_number_chk(&argvars[1], &error);
8304 if (argvars[2].v_type != VAR_UNKNOWN)
8305 stride = get_tv_number_chk(&argvars[2], &error);
8306 }
8307
8308 if (error)
8309 return; /* type error; errmsg already given */
8310 if (stride == 0)
8311 EMSG(_("E726: Stride is zero"));
8312 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8313 EMSG(_("E727: Start past end"));
8314 else
8315 {
8316 if (rettv_list_alloc(rettv) == OK)
8317 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8318 if (list_append_number(rettv->vval.v_list,
8319 (varnumber_T)i) == FAIL)
8320 break;
8321 }
8322}
8323
8324/*
8325 * "readfile()" function
8326 */
8327 static void
8328f_readfile(typval_T *argvars, typval_T *rettv)
8329{
8330 int binary = FALSE;
8331 int failed = FALSE;
8332 char_u *fname;
8333 FILE *fd;
8334 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8335 int io_size = sizeof(buf);
8336 int readlen; /* size of last fread() */
8337 char_u *prev = NULL; /* previously read bytes, if any */
8338 long prevlen = 0; /* length of data in prev */
8339 long prevsize = 0; /* size of prev buffer */
8340 long maxline = MAXLNUM;
8341 long cnt = 0;
8342 char_u *p; /* position in buf */
8343 char_u *start; /* start of current line */
8344
8345 if (argvars[1].v_type != VAR_UNKNOWN)
8346 {
8347 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8348 binary = TRUE;
8349 if (argvars[2].v_type != VAR_UNKNOWN)
8350 maxline = (long)get_tv_number(&argvars[2]);
8351 }
8352
8353 if (rettv_list_alloc(rettv) == FAIL)
8354 return;
8355
8356 /* Always open the file in binary mode, library functions have a mind of
8357 * their own about CR-LF conversion. */
8358 fname = get_tv_string(&argvars[0]);
8359 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8360 {
8361 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8362 return;
8363 }
8364
8365 while (cnt < maxline || maxline < 0)
8366 {
8367 readlen = (int)fread(buf, 1, io_size, fd);
8368
8369 /* This for loop processes what was read, but is also entered at end
8370 * of file so that either:
8371 * - an incomplete line gets written
8372 * - a "binary" file gets an empty line at the end if it ends in a
8373 * newline. */
8374 for (p = buf, start = buf;
8375 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8376 ++p)
8377 {
8378 if (*p == '\n' || readlen <= 0)
8379 {
8380 listitem_T *li;
8381 char_u *s = NULL;
8382 long_u len = p - start;
8383
8384 /* Finished a line. Remove CRs before NL. */
8385 if (readlen > 0 && !binary)
8386 {
8387 while (len > 0 && start[len - 1] == '\r')
8388 --len;
8389 /* removal may cross back to the "prev" string */
8390 if (len == 0)
8391 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8392 --prevlen;
8393 }
8394 if (prevlen == 0)
8395 s = vim_strnsave(start, (int)len);
8396 else
8397 {
8398 /* Change "prev" buffer to be the right size. This way
8399 * the bytes are only copied once, and very long lines are
8400 * allocated only once. */
8401 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8402 {
8403 mch_memmove(s + prevlen, start, len);
8404 s[prevlen + len] = NUL;
8405 prev = NULL; /* the list will own the string */
8406 prevlen = prevsize = 0;
8407 }
8408 }
8409 if (s == NULL)
8410 {
8411 do_outofmem_msg((long_u) prevlen + len + 1);
8412 failed = TRUE;
8413 break;
8414 }
8415
8416 if ((li = listitem_alloc()) == NULL)
8417 {
8418 vim_free(s);
8419 failed = TRUE;
8420 break;
8421 }
8422 li->li_tv.v_type = VAR_STRING;
8423 li->li_tv.v_lock = 0;
8424 li->li_tv.vval.v_string = s;
8425 list_append(rettv->vval.v_list, li);
8426
8427 start = p + 1; /* step over newline */
8428 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8429 break;
8430 }
8431 else if (*p == NUL)
8432 *p = '\n';
8433#ifdef FEAT_MBYTE
8434 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8435 * when finding the BF and check the previous two bytes. */
8436 else if (*p == 0xbf && enc_utf8 && !binary)
8437 {
8438 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8439 * + 1, these may be in the "prev" string. */
8440 char_u back1 = p >= buf + 1 ? p[-1]
8441 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8442 char_u back2 = p >= buf + 2 ? p[-2]
8443 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8444 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8445
8446 if (back2 == 0xef && back1 == 0xbb)
8447 {
8448 char_u *dest = p - 2;
8449
8450 /* Usually a BOM is at the beginning of a file, and so at
8451 * the beginning of a line; then we can just step over it.
8452 */
8453 if (start == dest)
8454 start = p + 1;
8455 else
8456 {
8457 /* have to shuffle buf to close gap */
8458 int adjust_prevlen = 0;
8459
8460 if (dest < buf)
8461 {
8462 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8463 dest = buf;
8464 }
8465 if (readlen > p - buf + 1)
8466 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8467 readlen -= 3 - adjust_prevlen;
8468 prevlen -= adjust_prevlen;
8469 p = dest - 1;
8470 }
8471 }
8472 }
8473#endif
8474 } /* for */
8475
8476 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8477 break;
8478 if (start < p)
8479 {
8480 /* There's part of a line in buf, store it in "prev". */
8481 if (p - start + prevlen >= prevsize)
8482 {
8483 /* need bigger "prev" buffer */
8484 char_u *newprev;
8485
8486 /* A common use case is ordinary text files and "prev" gets a
8487 * fragment of a line, so the first allocation is made
8488 * small, to avoid repeatedly 'allocing' large and
8489 * 'reallocing' small. */
8490 if (prevsize == 0)
8491 prevsize = (long)(p - start);
8492 else
8493 {
8494 long grow50pc = (prevsize * 3) / 2;
8495 long growmin = (long)((p - start) * 2 + prevlen);
8496 prevsize = grow50pc > growmin ? grow50pc : growmin;
8497 }
8498 newprev = prev == NULL ? alloc(prevsize)
8499 : vim_realloc(prev, prevsize);
8500 if (newprev == NULL)
8501 {
8502 do_outofmem_msg((long_u)prevsize);
8503 failed = TRUE;
8504 break;
8505 }
8506 prev = newprev;
8507 }
8508 /* Add the line part to end of "prev". */
8509 mch_memmove(prev + prevlen, start, p - start);
8510 prevlen += (long)(p - start);
8511 }
8512 } /* while */
8513
8514 /*
8515 * For a negative line count use only the lines at the end of the file,
8516 * free the rest.
8517 */
8518 if (!failed && maxline < 0)
8519 while (cnt > -maxline)
8520 {
8521 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8522 --cnt;
8523 }
8524
8525 if (failed)
8526 {
8527 list_free(rettv->vval.v_list);
8528 /* readfile doc says an empty list is returned on error */
8529 rettv->vval.v_list = list_alloc();
8530 }
8531
8532 vim_free(prev);
8533 fclose(fd);
8534}
8535
8536#if defined(FEAT_RELTIME)
8537static int list2proftime(typval_T *arg, proftime_T *tm);
8538
8539/*
8540 * Convert a List to proftime_T.
8541 * Return FAIL when there is something wrong.
8542 */
8543 static int
8544list2proftime(typval_T *arg, proftime_T *tm)
8545{
8546 long n1, n2;
8547 int error = FALSE;
8548
8549 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8550 || arg->vval.v_list->lv_len != 2)
8551 return FAIL;
8552 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8553 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8554# ifdef WIN3264
8555 tm->HighPart = n1;
8556 tm->LowPart = n2;
8557# else
8558 tm->tv_sec = n1;
8559 tm->tv_usec = n2;
8560# endif
8561 return error ? FAIL : OK;
8562}
8563#endif /* FEAT_RELTIME */
8564
8565/*
8566 * "reltime()" function
8567 */
8568 static void
8569f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8570{
8571#ifdef FEAT_RELTIME
8572 proftime_T res;
8573 proftime_T start;
8574
8575 if (argvars[0].v_type == VAR_UNKNOWN)
8576 {
8577 /* No arguments: get current time. */
8578 profile_start(&res);
8579 }
8580 else if (argvars[1].v_type == VAR_UNKNOWN)
8581 {
8582 if (list2proftime(&argvars[0], &res) == FAIL)
8583 return;
8584 profile_end(&res);
8585 }
8586 else
8587 {
8588 /* Two arguments: compute the difference. */
8589 if (list2proftime(&argvars[0], &start) == FAIL
8590 || list2proftime(&argvars[1], &res) == FAIL)
8591 return;
8592 profile_sub(&res, &start);
8593 }
8594
8595 if (rettv_list_alloc(rettv) == OK)
8596 {
8597 long n1, n2;
8598
8599# ifdef WIN3264
8600 n1 = res.HighPart;
8601 n2 = res.LowPart;
8602# else
8603 n1 = res.tv_sec;
8604 n2 = res.tv_usec;
8605# endif
8606 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8607 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8608 }
8609#endif
8610}
8611
8612#ifdef FEAT_FLOAT
8613/*
8614 * "reltimefloat()" function
8615 */
8616 static void
8617f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8618{
8619# ifdef FEAT_RELTIME
8620 proftime_T tm;
8621# endif
8622
8623 rettv->v_type = VAR_FLOAT;
8624 rettv->vval.v_float = 0;
8625# ifdef FEAT_RELTIME
8626 if (list2proftime(&argvars[0], &tm) == OK)
8627 rettv->vval.v_float = profile_float(&tm);
8628# endif
8629}
8630#endif
8631
8632/*
8633 * "reltimestr()" function
8634 */
8635 static void
8636f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8637{
8638#ifdef FEAT_RELTIME
8639 proftime_T tm;
8640#endif
8641
8642 rettv->v_type = VAR_STRING;
8643 rettv->vval.v_string = NULL;
8644#ifdef FEAT_RELTIME
8645 if (list2proftime(&argvars[0], &tm) == OK)
8646 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8647#endif
8648}
8649
8650#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8651static void make_connection(void);
8652static int check_connection(void);
8653
8654 static void
8655make_connection(void)
8656{
8657 if (X_DISPLAY == NULL
8658# ifdef FEAT_GUI
8659 && !gui.in_use
8660# endif
8661 )
8662 {
8663 x_force_connect = TRUE;
8664 setup_term_clip();
8665 x_force_connect = FALSE;
8666 }
8667}
8668
8669 static int
8670check_connection(void)
8671{
8672 make_connection();
8673 if (X_DISPLAY == NULL)
8674 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008675 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008676 return FAIL;
8677 }
8678 return OK;
8679}
8680#endif
8681
8682#ifdef FEAT_CLIENTSERVER
8683 static void
8684remote_common(typval_T *argvars, typval_T *rettv, int expr)
8685{
8686 char_u *server_name;
8687 char_u *keys;
8688 char_u *r = NULL;
8689 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008690 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008691# ifdef WIN32
8692 HWND w;
8693# else
8694 Window w;
8695# endif
8696
8697 if (check_restricted() || check_secure())
8698 return;
8699
8700# ifdef FEAT_X11
8701 if (check_connection() == FAIL)
8702 return;
8703# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008704 if (argvars[2].v_type != VAR_UNKNOWN
8705 && argvars[3].v_type != VAR_UNKNOWN)
8706 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008707
8708 server_name = get_tv_string_chk(&argvars[0]);
8709 if (server_name == NULL)
8710 return; /* type error; errmsg already given */
8711 keys = get_tv_string_buf(&argvars[1], buf);
8712# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008713 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008714# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008715 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8716 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008717# endif
8718 {
8719 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008720 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008722 vim_free(r);
8723 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724 else
8725 EMSG2(_("E241: Unable to send to %s"), server_name);
8726 return;
8727 }
8728
8729 rettv->vval.v_string = r;
8730
8731 if (argvars[2].v_type != VAR_UNKNOWN)
8732 {
8733 dictitem_T v;
8734 char_u str[30];
8735 char_u *idvar;
8736
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008737 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008738 if (idvar != NULL && *idvar != NUL)
8739 {
8740 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8741 v.di_tv.v_type = VAR_STRING;
8742 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008743 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008744 vim_free(v.di_tv.vval.v_string);
8745 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008746 }
8747}
8748#endif
8749
8750/*
8751 * "remote_expr()" function
8752 */
8753 static void
8754f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8755{
8756 rettv->v_type = VAR_STRING;
8757 rettv->vval.v_string = NULL;
8758#ifdef FEAT_CLIENTSERVER
8759 remote_common(argvars, rettv, TRUE);
8760#endif
8761}
8762
8763/*
8764 * "remote_foreground()" function
8765 */
8766 static void
8767f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8768{
8769#ifdef FEAT_CLIENTSERVER
8770# ifdef WIN32
8771 /* On Win32 it's done in this application. */
8772 {
8773 char_u *server_name = get_tv_string_chk(&argvars[0]);
8774
8775 if (server_name != NULL)
8776 serverForeground(server_name);
8777 }
8778# else
8779 /* Send a foreground() expression to the server. */
8780 argvars[1].v_type = VAR_STRING;
8781 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8782 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008783 rettv->v_type = VAR_STRING;
8784 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008785 remote_common(argvars, rettv, TRUE);
8786 vim_free(argvars[1].vval.v_string);
8787# endif
8788#endif
8789}
8790
8791 static void
8792f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8793{
8794#ifdef FEAT_CLIENTSERVER
8795 dictitem_T v;
8796 char_u *s = NULL;
8797# ifdef WIN32
8798 long_u n = 0;
8799# endif
8800 char_u *serverid;
8801
8802 if (check_restricted() || check_secure())
8803 {
8804 rettv->vval.v_number = -1;
8805 return;
8806 }
8807 serverid = get_tv_string_chk(&argvars[0]);
8808 if (serverid == NULL)
8809 {
8810 rettv->vval.v_number = -1;
8811 return; /* type error; errmsg already given */
8812 }
8813# ifdef WIN32
8814 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8815 if (n == 0)
8816 rettv->vval.v_number = -1;
8817 else
8818 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008819 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008820 rettv->vval.v_number = (s != NULL);
8821 }
8822# else
8823 if (check_connection() == FAIL)
8824 return;
8825
8826 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8827 serverStrToWin(serverid), &s);
8828# endif
8829
8830 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8831 {
8832 char_u *retvar;
8833
8834 v.di_tv.v_type = VAR_STRING;
8835 v.di_tv.vval.v_string = vim_strsave(s);
8836 retvar = get_tv_string_chk(&argvars[1]);
8837 if (retvar != NULL)
8838 set_var(retvar, &v.di_tv, FALSE);
8839 vim_free(v.di_tv.vval.v_string);
8840 }
8841#else
8842 rettv->vval.v_number = -1;
8843#endif
8844}
8845
8846 static void
8847f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8848{
8849 char_u *r = NULL;
8850
8851#ifdef FEAT_CLIENTSERVER
8852 char_u *serverid = get_tv_string_chk(&argvars[0]);
8853
8854 if (serverid != NULL && !check_restricted() && !check_secure())
8855 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008856 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008857# ifdef WIN32
8858 /* The server's HWND is encoded in the 'id' parameter */
8859 long_u n = 0;
8860# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008861
8862 if (argvars[1].v_type != VAR_UNKNOWN)
8863 timeout = get_tv_number(&argvars[1]);
8864
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008865# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008866 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8867 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008868 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008869 if (r == NULL)
8870# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008871 if (check_connection() == FAIL
8872 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8873 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008874# endif
8875 EMSG(_("E277: Unable to read a server reply"));
8876 }
8877#endif
8878 rettv->v_type = VAR_STRING;
8879 rettv->vval.v_string = r;
8880}
8881
8882/*
8883 * "remote_send()" function
8884 */
8885 static void
8886f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8887{
8888 rettv->v_type = VAR_STRING;
8889 rettv->vval.v_string = NULL;
8890#ifdef FEAT_CLIENTSERVER
8891 remote_common(argvars, rettv, FALSE);
8892#endif
8893}
8894
8895/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008896 * "remote_startserver()" function
8897 */
8898 static void
8899f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8900{
8901#ifdef FEAT_CLIENTSERVER
8902 char_u *server = get_tv_string_chk(&argvars[0]);
8903
8904 if (server == NULL)
8905 return; /* type error; errmsg already given */
8906 if (serverName != NULL)
8907 EMSG(_("E941: already started a server"));
8908 else
8909 {
8910# ifdef FEAT_X11
8911 if (check_connection() == OK)
8912 serverRegisterName(X_DISPLAY, server);
8913# else
8914 serverSetName(server);
8915# endif
8916 }
8917#else
8918 EMSG(_("E942: +clientserver feature not available"));
8919#endif
8920}
8921
8922/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008923 * "remove()" function
8924 */
8925 static void
8926f_remove(typval_T *argvars, typval_T *rettv)
8927{
8928 list_T *l;
8929 listitem_T *item, *item2;
8930 listitem_T *li;
8931 long idx;
8932 long end;
8933 char_u *key;
8934 dict_T *d;
8935 dictitem_T *di;
8936 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8937
8938 if (argvars[0].v_type == VAR_DICT)
8939 {
8940 if (argvars[2].v_type != VAR_UNKNOWN)
8941 EMSG2(_(e_toomanyarg), "remove()");
8942 else if ((d = argvars[0].vval.v_dict) != NULL
8943 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8944 {
8945 key = get_tv_string_chk(&argvars[1]);
8946 if (key != NULL)
8947 {
8948 di = dict_find(d, key, -1);
8949 if (di == NULL)
8950 EMSG2(_(e_dictkey), key);
8951 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8952 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8953 {
8954 *rettv = di->di_tv;
8955 init_tv(&di->di_tv);
8956 dictitem_remove(d, di);
8957 }
8958 }
8959 }
8960 }
8961 else if (argvars[0].v_type != VAR_LIST)
8962 EMSG2(_(e_listdictarg), "remove()");
8963 else if ((l = argvars[0].vval.v_list) != NULL
8964 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8965 {
8966 int error = FALSE;
8967
8968 idx = (long)get_tv_number_chk(&argvars[1], &error);
8969 if (error)
8970 ; /* type error: do nothing, errmsg already given */
8971 else if ((item = list_find(l, idx)) == NULL)
8972 EMSGN(_(e_listidx), idx);
8973 else
8974 {
8975 if (argvars[2].v_type == VAR_UNKNOWN)
8976 {
8977 /* Remove one item, return its value. */
8978 vimlist_remove(l, item, item);
8979 *rettv = item->li_tv;
8980 vim_free(item);
8981 }
8982 else
8983 {
8984 /* Remove range of items, return list with values. */
8985 end = (long)get_tv_number_chk(&argvars[2], &error);
8986 if (error)
8987 ; /* type error: do nothing */
8988 else if ((item2 = list_find(l, end)) == NULL)
8989 EMSGN(_(e_listidx), end);
8990 else
8991 {
8992 int cnt = 0;
8993
8994 for (li = item; li != NULL; li = li->li_next)
8995 {
8996 ++cnt;
8997 if (li == item2)
8998 break;
8999 }
9000 if (li == NULL) /* didn't find "item2" after "item" */
9001 EMSG(_(e_invrange));
9002 else
9003 {
9004 vimlist_remove(l, item, item2);
9005 if (rettv_list_alloc(rettv) == OK)
9006 {
9007 l = rettv->vval.v_list;
9008 l->lv_first = item;
9009 l->lv_last = item2;
9010 item->li_prev = NULL;
9011 item2->li_next = NULL;
9012 l->lv_len = cnt;
9013 }
9014 }
9015 }
9016 }
9017 }
9018 }
9019}
9020
9021/*
9022 * "rename({from}, {to})" function
9023 */
9024 static void
9025f_rename(typval_T *argvars, typval_T *rettv)
9026{
9027 char_u buf[NUMBUFLEN];
9028
9029 if (check_restricted() || check_secure())
9030 rettv->vval.v_number = -1;
9031 else
9032 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9033 get_tv_string_buf(&argvars[1], buf));
9034}
9035
9036/*
9037 * "repeat()" function
9038 */
9039 static void
9040f_repeat(typval_T *argvars, typval_T *rettv)
9041{
9042 char_u *p;
9043 int n;
9044 int slen;
9045 int len;
9046 char_u *r;
9047 int i;
9048
9049 n = (int)get_tv_number(&argvars[1]);
9050 if (argvars[0].v_type == VAR_LIST)
9051 {
9052 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9053 while (n-- > 0)
9054 if (list_extend(rettv->vval.v_list,
9055 argvars[0].vval.v_list, NULL) == FAIL)
9056 break;
9057 }
9058 else
9059 {
9060 p = get_tv_string(&argvars[0]);
9061 rettv->v_type = VAR_STRING;
9062 rettv->vval.v_string = NULL;
9063
9064 slen = (int)STRLEN(p);
9065 len = slen * n;
9066 if (len <= 0)
9067 return;
9068
9069 r = alloc(len + 1);
9070 if (r != NULL)
9071 {
9072 for (i = 0; i < n; i++)
9073 mch_memmove(r + i * slen, p, (size_t)slen);
9074 r[len] = NUL;
9075 }
9076
9077 rettv->vval.v_string = r;
9078 }
9079}
9080
9081/*
9082 * "resolve()" function
9083 */
9084 static void
9085f_resolve(typval_T *argvars, typval_T *rettv)
9086{
9087 char_u *p;
9088#ifdef HAVE_READLINK
9089 char_u *buf = NULL;
9090#endif
9091
9092 p = get_tv_string(&argvars[0]);
9093#ifdef FEAT_SHORTCUT
9094 {
9095 char_u *v = NULL;
9096
9097 v = mch_resolve_shortcut(p);
9098 if (v != NULL)
9099 rettv->vval.v_string = v;
9100 else
9101 rettv->vval.v_string = vim_strsave(p);
9102 }
9103#else
9104# ifdef HAVE_READLINK
9105 {
9106 char_u *cpy;
9107 int len;
9108 char_u *remain = NULL;
9109 char_u *q;
9110 int is_relative_to_current = FALSE;
9111 int has_trailing_pathsep = FALSE;
9112 int limit = 100;
9113
9114 p = vim_strsave(p);
9115
9116 if (p[0] == '.' && (vim_ispathsep(p[1])
9117 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9118 is_relative_to_current = TRUE;
9119
9120 len = STRLEN(p);
9121 if (len > 0 && after_pathsep(p, p + len))
9122 {
9123 has_trailing_pathsep = TRUE;
9124 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9125 }
9126
9127 q = getnextcomp(p);
9128 if (*q != NUL)
9129 {
9130 /* Separate the first path component in "p", and keep the
9131 * remainder (beginning with the path separator). */
9132 remain = vim_strsave(q - 1);
9133 q[-1] = NUL;
9134 }
9135
9136 buf = alloc(MAXPATHL + 1);
9137 if (buf == NULL)
9138 goto fail;
9139
9140 for (;;)
9141 {
9142 for (;;)
9143 {
9144 len = readlink((char *)p, (char *)buf, MAXPATHL);
9145 if (len <= 0)
9146 break;
9147 buf[len] = NUL;
9148
9149 if (limit-- == 0)
9150 {
9151 vim_free(p);
9152 vim_free(remain);
9153 EMSG(_("E655: Too many symbolic links (cycle?)"));
9154 rettv->vval.v_string = NULL;
9155 goto fail;
9156 }
9157
9158 /* Ensure that the result will have a trailing path separator
9159 * if the argument has one. */
9160 if (remain == NULL && has_trailing_pathsep)
9161 add_pathsep(buf);
9162
9163 /* Separate the first path component in the link value and
9164 * concatenate the remainders. */
9165 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9166 if (*q != NUL)
9167 {
9168 if (remain == NULL)
9169 remain = vim_strsave(q - 1);
9170 else
9171 {
9172 cpy = concat_str(q - 1, remain);
9173 if (cpy != NULL)
9174 {
9175 vim_free(remain);
9176 remain = cpy;
9177 }
9178 }
9179 q[-1] = NUL;
9180 }
9181
9182 q = gettail(p);
9183 if (q > p && *q == NUL)
9184 {
9185 /* Ignore trailing path separator. */
9186 q[-1] = NUL;
9187 q = gettail(p);
9188 }
9189 if (q > p && !mch_isFullName(buf))
9190 {
9191 /* symlink is relative to directory of argument */
9192 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9193 if (cpy != NULL)
9194 {
9195 STRCPY(cpy, p);
9196 STRCPY(gettail(cpy), buf);
9197 vim_free(p);
9198 p = cpy;
9199 }
9200 }
9201 else
9202 {
9203 vim_free(p);
9204 p = vim_strsave(buf);
9205 }
9206 }
9207
9208 if (remain == NULL)
9209 break;
9210
9211 /* Append the first path component of "remain" to "p". */
9212 q = getnextcomp(remain + 1);
9213 len = q - remain - (*q != NUL);
9214 cpy = vim_strnsave(p, STRLEN(p) + len);
9215 if (cpy != NULL)
9216 {
9217 STRNCAT(cpy, remain, len);
9218 vim_free(p);
9219 p = cpy;
9220 }
9221 /* Shorten "remain". */
9222 if (*q != NUL)
9223 STRMOVE(remain, q - 1);
9224 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009225 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009226 }
9227
9228 /* If the result is a relative path name, make it explicitly relative to
9229 * the current directory if and only if the argument had this form. */
9230 if (!vim_ispathsep(*p))
9231 {
9232 if (is_relative_to_current
9233 && *p != NUL
9234 && !(p[0] == '.'
9235 && (p[1] == NUL
9236 || vim_ispathsep(p[1])
9237 || (p[1] == '.'
9238 && (p[2] == NUL
9239 || vim_ispathsep(p[2]))))))
9240 {
9241 /* Prepend "./". */
9242 cpy = concat_str((char_u *)"./", p);
9243 if (cpy != NULL)
9244 {
9245 vim_free(p);
9246 p = cpy;
9247 }
9248 }
9249 else if (!is_relative_to_current)
9250 {
9251 /* Strip leading "./". */
9252 q = p;
9253 while (q[0] == '.' && vim_ispathsep(q[1]))
9254 q += 2;
9255 if (q > p)
9256 STRMOVE(p, p + 2);
9257 }
9258 }
9259
9260 /* Ensure that the result will have no trailing path separator
9261 * if the argument had none. But keep "/" or "//". */
9262 if (!has_trailing_pathsep)
9263 {
9264 q = p + STRLEN(p);
9265 if (after_pathsep(p, q))
9266 *gettail_sep(p) = NUL;
9267 }
9268
9269 rettv->vval.v_string = p;
9270 }
9271# else
9272 rettv->vval.v_string = vim_strsave(p);
9273# endif
9274#endif
9275
9276 simplify_filename(rettv->vval.v_string);
9277
9278#ifdef HAVE_READLINK
9279fail:
9280 vim_free(buf);
9281#endif
9282 rettv->v_type = VAR_STRING;
9283}
9284
9285/*
9286 * "reverse({list})" function
9287 */
9288 static void
9289f_reverse(typval_T *argvars, typval_T *rettv)
9290{
9291 list_T *l;
9292 listitem_T *li, *ni;
9293
9294 if (argvars[0].v_type != VAR_LIST)
9295 EMSG2(_(e_listarg), "reverse()");
9296 else if ((l = argvars[0].vval.v_list) != NULL
9297 && !tv_check_lock(l->lv_lock,
9298 (char_u *)N_("reverse() argument"), TRUE))
9299 {
9300 li = l->lv_last;
9301 l->lv_first = l->lv_last = NULL;
9302 l->lv_len = 0;
9303 while (li != NULL)
9304 {
9305 ni = li->li_prev;
9306 list_append(l, li);
9307 li = ni;
9308 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009309 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009310 l->lv_idx = l->lv_len - l->lv_idx - 1;
9311 }
9312}
9313
9314#define SP_NOMOVE 0x01 /* don't move cursor */
9315#define SP_REPEAT 0x02 /* repeat to find outer pair */
9316#define SP_RETCOUNT 0x04 /* return matchcount */
9317#define SP_SETPCMARK 0x08 /* set previous context mark */
9318#define SP_START 0x10 /* accept match at start position */
9319#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9320#define SP_END 0x40 /* leave cursor at end of match */
9321#define SP_COLUMN 0x80 /* start at cursor column */
9322
9323static int get_search_arg(typval_T *varp, int *flagsp);
9324
9325/*
9326 * Get flags for a search function.
9327 * Possibly sets "p_ws".
9328 * Returns BACKWARD, FORWARD or zero (for an error).
9329 */
9330 static int
9331get_search_arg(typval_T *varp, int *flagsp)
9332{
9333 int dir = FORWARD;
9334 char_u *flags;
9335 char_u nbuf[NUMBUFLEN];
9336 int mask;
9337
9338 if (varp->v_type != VAR_UNKNOWN)
9339 {
9340 flags = get_tv_string_buf_chk(varp, nbuf);
9341 if (flags == NULL)
9342 return 0; /* type error; errmsg already given */
9343 while (*flags != NUL)
9344 {
9345 switch (*flags)
9346 {
9347 case 'b': dir = BACKWARD; break;
9348 case 'w': p_ws = TRUE; break;
9349 case 'W': p_ws = FALSE; break;
9350 default: mask = 0;
9351 if (flagsp != NULL)
9352 switch (*flags)
9353 {
9354 case 'c': mask = SP_START; break;
9355 case 'e': mask = SP_END; break;
9356 case 'm': mask = SP_RETCOUNT; break;
9357 case 'n': mask = SP_NOMOVE; break;
9358 case 'p': mask = SP_SUBPAT; break;
9359 case 'r': mask = SP_REPEAT; break;
9360 case 's': mask = SP_SETPCMARK; break;
9361 case 'z': mask = SP_COLUMN; break;
9362 }
9363 if (mask == 0)
9364 {
9365 EMSG2(_(e_invarg2), flags);
9366 dir = 0;
9367 }
9368 else
9369 *flagsp |= mask;
9370 }
9371 if (dir == 0)
9372 break;
9373 ++flags;
9374 }
9375 }
9376 return dir;
9377}
9378
9379/*
9380 * Shared by search() and searchpos() functions.
9381 */
9382 static int
9383search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9384{
9385 int flags;
9386 char_u *pat;
9387 pos_T pos;
9388 pos_T save_cursor;
9389 int save_p_ws = p_ws;
9390 int dir;
9391 int retval = 0; /* default: FAIL */
9392 long lnum_stop = 0;
9393 proftime_T tm;
9394#ifdef FEAT_RELTIME
9395 long time_limit = 0;
9396#endif
9397 int options = SEARCH_KEEP;
9398 int subpatnum;
9399
9400 pat = get_tv_string(&argvars[0]);
9401 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9402 if (dir == 0)
9403 goto theend;
9404 flags = *flagsp;
9405 if (flags & SP_START)
9406 options |= SEARCH_START;
9407 if (flags & SP_END)
9408 options |= SEARCH_END;
9409 if (flags & SP_COLUMN)
9410 options |= SEARCH_COL;
9411
9412 /* Optional arguments: line number to stop searching and timeout. */
9413 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9414 {
9415 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9416 if (lnum_stop < 0)
9417 goto theend;
9418#ifdef FEAT_RELTIME
9419 if (argvars[3].v_type != VAR_UNKNOWN)
9420 {
9421 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9422 if (time_limit < 0)
9423 goto theend;
9424 }
9425#endif
9426 }
9427
9428#ifdef FEAT_RELTIME
9429 /* Set the time limit, if there is one. */
9430 profile_setlimit(time_limit, &tm);
9431#endif
9432
9433 /*
9434 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9435 * Check to make sure only those flags are set.
9436 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9437 * flags cannot be set. Check for that condition also.
9438 */
9439 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9440 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9441 {
9442 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9443 goto theend;
9444 }
9445
9446 pos = save_cursor = curwin->w_cursor;
9447 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009448 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009449 if (subpatnum != FAIL)
9450 {
9451 if (flags & SP_SUBPAT)
9452 retval = subpatnum;
9453 else
9454 retval = pos.lnum;
9455 if (flags & SP_SETPCMARK)
9456 setpcmark();
9457 curwin->w_cursor = pos;
9458 if (match_pos != NULL)
9459 {
9460 /* Store the match cursor position */
9461 match_pos->lnum = pos.lnum;
9462 match_pos->col = pos.col + 1;
9463 }
9464 /* "/$" will put the cursor after the end of the line, may need to
9465 * correct that here */
9466 check_cursor();
9467 }
9468
9469 /* If 'n' flag is used: restore cursor position. */
9470 if (flags & SP_NOMOVE)
9471 curwin->w_cursor = save_cursor;
9472 else
9473 curwin->w_set_curswant = TRUE;
9474theend:
9475 p_ws = save_p_ws;
9476
9477 return retval;
9478}
9479
9480#ifdef FEAT_FLOAT
9481
9482/*
9483 * round() is not in C90, use ceil() or floor() instead.
9484 */
9485 float_T
9486vim_round(float_T f)
9487{
9488 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9489}
9490
9491/*
9492 * "round({float})" function
9493 */
9494 static void
9495f_round(typval_T *argvars, typval_T *rettv)
9496{
9497 float_T f = 0.0;
9498
9499 rettv->v_type = VAR_FLOAT;
9500 if (get_float_arg(argvars, &f) == OK)
9501 rettv->vval.v_float = vim_round(f);
9502 else
9503 rettv->vval.v_float = 0.0;
9504}
9505#endif
9506
9507/*
9508 * "screenattr()" function
9509 */
9510 static void
9511f_screenattr(typval_T *argvars, typval_T *rettv)
9512{
9513 int row;
9514 int col;
9515 int c;
9516
9517 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9518 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9519 if (row < 0 || row >= screen_Rows
9520 || col < 0 || col >= screen_Columns)
9521 c = -1;
9522 else
9523 c = ScreenAttrs[LineOffset[row] + col];
9524 rettv->vval.v_number = c;
9525}
9526
9527/*
9528 * "screenchar()" function
9529 */
9530 static void
9531f_screenchar(typval_T *argvars, typval_T *rettv)
9532{
9533 int row;
9534 int col;
9535 int off;
9536 int c;
9537
9538 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9539 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9540 if (row < 0 || row >= screen_Rows
9541 || col < 0 || col >= screen_Columns)
9542 c = -1;
9543 else
9544 {
9545 off = LineOffset[row] + col;
9546#ifdef FEAT_MBYTE
9547 if (enc_utf8 && ScreenLinesUC[off] != 0)
9548 c = ScreenLinesUC[off];
9549 else
9550#endif
9551 c = ScreenLines[off];
9552 }
9553 rettv->vval.v_number = c;
9554}
9555
9556/*
9557 * "screencol()" function
9558 *
9559 * First column is 1 to be consistent with virtcol().
9560 */
9561 static void
9562f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9563{
9564 rettv->vval.v_number = screen_screencol() + 1;
9565}
9566
9567/*
9568 * "screenrow()" function
9569 */
9570 static void
9571f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9572{
9573 rettv->vval.v_number = screen_screenrow() + 1;
9574}
9575
9576/*
9577 * "search()" function
9578 */
9579 static void
9580f_search(typval_T *argvars, typval_T *rettv)
9581{
9582 int flags = 0;
9583
9584 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9585}
9586
9587/*
9588 * "searchdecl()" function
9589 */
9590 static void
9591f_searchdecl(typval_T *argvars, typval_T *rettv)
9592{
9593 int locally = 1;
9594 int thisblock = 0;
9595 int error = FALSE;
9596 char_u *name;
9597
9598 rettv->vval.v_number = 1; /* default: FAIL */
9599
9600 name = get_tv_string_chk(&argvars[0]);
9601 if (argvars[1].v_type != VAR_UNKNOWN)
9602 {
9603 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9604 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9605 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9606 }
9607 if (!error && name != NULL)
9608 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9609 locally, thisblock, SEARCH_KEEP) == FAIL;
9610}
9611
9612/*
9613 * Used by searchpair() and searchpairpos()
9614 */
9615 static int
9616searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9617{
9618 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009619 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009620 int save_p_ws = p_ws;
9621 int dir;
9622 int flags = 0;
9623 char_u nbuf1[NUMBUFLEN];
9624 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009625 int retval = 0; /* default: FAIL */
9626 long lnum_stop = 0;
9627 long time_limit = 0;
9628
9629 /* Get the three pattern arguments: start, middle, end. */
9630 spat = get_tv_string_chk(&argvars[0]);
9631 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9632 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9633 if (spat == NULL || mpat == NULL || epat == NULL)
9634 goto theend; /* type error */
9635
9636 /* Handle the optional fourth argument: flags */
9637 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9638 if (dir == 0)
9639 goto theend;
9640
9641 /* Don't accept SP_END or SP_SUBPAT.
9642 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9643 */
9644 if ((flags & (SP_END | SP_SUBPAT)) != 0
9645 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9646 {
9647 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9648 goto theend;
9649 }
9650
9651 /* Using 'r' implies 'W', otherwise it doesn't work. */
9652 if (flags & SP_REPEAT)
9653 p_ws = FALSE;
9654
9655 /* Optional fifth argument: skip expression */
9656 if (argvars[3].v_type == VAR_UNKNOWN
9657 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009658 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009659 else
9660 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009661 skip = &argvars[4];
9662 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9663 && skip->v_type != VAR_STRING)
9664 {
9665 /* Type error */
9666 goto theend;
9667 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009668 if (argvars[5].v_type != VAR_UNKNOWN)
9669 {
9670 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9671 if (lnum_stop < 0)
9672 goto theend;
9673#ifdef FEAT_RELTIME
9674 if (argvars[6].v_type != VAR_UNKNOWN)
9675 {
9676 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9677 if (time_limit < 0)
9678 goto theend;
9679 }
9680#endif
9681 }
9682 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009683
9684 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9685 match_pos, lnum_stop, time_limit);
9686
9687theend:
9688 p_ws = save_p_ws;
9689
9690 return retval;
9691}
9692
9693/*
9694 * "searchpair()" function
9695 */
9696 static void
9697f_searchpair(typval_T *argvars, typval_T *rettv)
9698{
9699 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9700}
9701
9702/*
9703 * "searchpairpos()" function
9704 */
9705 static void
9706f_searchpairpos(typval_T *argvars, typval_T *rettv)
9707{
9708 pos_T match_pos;
9709 int lnum = 0;
9710 int col = 0;
9711
9712 if (rettv_list_alloc(rettv) == FAIL)
9713 return;
9714
9715 if (searchpair_cmn(argvars, &match_pos) > 0)
9716 {
9717 lnum = match_pos.lnum;
9718 col = match_pos.col;
9719 }
9720
9721 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9722 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9723}
9724
9725/*
9726 * Search for a start/middle/end thing.
9727 * Used by searchpair(), see its documentation for the details.
9728 * Returns 0 or -1 for no match,
9729 */
9730 long
9731do_searchpair(
9732 char_u *spat, /* start pattern */
9733 char_u *mpat, /* middle pattern */
9734 char_u *epat, /* end pattern */
9735 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009736 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009737 int flags, /* SP_SETPCMARK and other SP_ values */
9738 pos_T *match_pos,
9739 linenr_T lnum_stop, /* stop at this line if not zero */
9740 long time_limit UNUSED) /* stop after this many msec */
9741{
9742 char_u *save_cpo;
9743 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9744 long retval = 0;
9745 pos_T pos;
9746 pos_T firstpos;
9747 pos_T foundpos;
9748 pos_T save_cursor;
9749 pos_T save_pos;
9750 int n;
9751 int r;
9752 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009753 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009754 int err;
9755 int options = SEARCH_KEEP;
9756 proftime_T tm;
9757
9758 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9759 save_cpo = p_cpo;
9760 p_cpo = empty_option;
9761
9762#ifdef FEAT_RELTIME
9763 /* Set the time limit, if there is one. */
9764 profile_setlimit(time_limit, &tm);
9765#endif
9766
9767 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9768 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009769 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9770 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009771 if (pat2 == NULL || pat3 == NULL)
9772 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009773 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009774 if (*mpat == NUL)
9775 STRCPY(pat3, pat2);
9776 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009777 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009778 spat, epat, mpat);
9779 if (flags & SP_START)
9780 options |= SEARCH_START;
9781
Bram Moolenaar48570482017-10-30 21:48:41 +01009782 if (skip != NULL)
9783 {
9784 /* Empty string means to not use the skip expression. */
9785 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9786 use_skip = skip->vval.v_string != NULL
9787 && *skip->vval.v_string != NUL;
9788 }
9789
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009790 save_cursor = curwin->w_cursor;
9791 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009792 CLEAR_POS(&firstpos);
9793 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009794 pat = pat3;
9795 for (;;)
9796 {
9797 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009798 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009799 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009800 /* didn't find it or found the first match again: FAIL */
9801 break;
9802
9803 if (firstpos.lnum == 0)
9804 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009805 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009806 {
9807 /* Found the same position again. Can happen with a pattern that
9808 * has "\zs" at the end and searching backwards. Advance one
9809 * character and try again. */
9810 if (dir == BACKWARD)
9811 decl(&pos);
9812 else
9813 incl(&pos);
9814 }
9815 foundpos = pos;
9816
9817 /* clear the start flag to avoid getting stuck here */
9818 options &= ~SEARCH_START;
9819
9820 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009821 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009822 {
9823 save_pos = curwin->w_cursor;
9824 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009825 err = FALSE;
9826 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009827 curwin->w_cursor = save_pos;
9828 if (err)
9829 {
9830 /* Evaluating {skip} caused an error, break here. */
9831 curwin->w_cursor = save_cursor;
9832 retval = -1;
9833 break;
9834 }
9835 if (r)
9836 continue;
9837 }
9838
9839 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9840 {
9841 /* Found end when searching backwards or start when searching
9842 * forward: nested pair. */
9843 ++nest;
9844 pat = pat2; /* nested, don't search for middle */
9845 }
9846 else
9847 {
9848 /* Found end when searching forward or start when searching
9849 * backward: end of (nested) pair; or found middle in outer pair. */
9850 if (--nest == 1)
9851 pat = pat3; /* outer level, search for middle */
9852 }
9853
9854 if (nest == 0)
9855 {
9856 /* Found the match: return matchcount or line number. */
9857 if (flags & SP_RETCOUNT)
9858 ++retval;
9859 else
9860 retval = pos.lnum;
9861 if (flags & SP_SETPCMARK)
9862 setpcmark();
9863 curwin->w_cursor = pos;
9864 if (!(flags & SP_REPEAT))
9865 break;
9866 nest = 1; /* search for next unmatched */
9867 }
9868 }
9869
9870 if (match_pos != NULL)
9871 {
9872 /* Store the match cursor position */
9873 match_pos->lnum = curwin->w_cursor.lnum;
9874 match_pos->col = curwin->w_cursor.col + 1;
9875 }
9876
9877 /* If 'n' flag is used or search failed: restore cursor position. */
9878 if ((flags & SP_NOMOVE) || retval == 0)
9879 curwin->w_cursor = save_cursor;
9880
9881theend:
9882 vim_free(pat2);
9883 vim_free(pat3);
9884 if (p_cpo == empty_option)
9885 p_cpo = save_cpo;
9886 else
9887 /* Darn, evaluating the {skip} expression changed the value. */
9888 free_string_option(save_cpo);
9889
9890 return retval;
9891}
9892
9893/*
9894 * "searchpos()" function
9895 */
9896 static void
9897f_searchpos(typval_T *argvars, typval_T *rettv)
9898{
9899 pos_T match_pos;
9900 int lnum = 0;
9901 int col = 0;
9902 int n;
9903 int flags = 0;
9904
9905 if (rettv_list_alloc(rettv) == FAIL)
9906 return;
9907
9908 n = search_cmn(argvars, &match_pos, &flags);
9909 if (n > 0)
9910 {
9911 lnum = match_pos.lnum;
9912 col = match_pos.col;
9913 }
9914
9915 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9916 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9917 if (flags & SP_SUBPAT)
9918 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9919}
9920
9921 static void
9922f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9923{
9924#ifdef FEAT_CLIENTSERVER
9925 char_u buf[NUMBUFLEN];
9926 char_u *server = get_tv_string_chk(&argvars[0]);
9927 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9928
9929 rettv->vval.v_number = -1;
9930 if (server == NULL || reply == NULL)
9931 return;
9932 if (check_restricted() || check_secure())
9933 return;
9934# ifdef FEAT_X11
9935 if (check_connection() == FAIL)
9936 return;
9937# endif
9938
9939 if (serverSendReply(server, reply) < 0)
9940 {
9941 EMSG(_("E258: Unable to send to client"));
9942 return;
9943 }
9944 rettv->vval.v_number = 0;
9945#else
9946 rettv->vval.v_number = -1;
9947#endif
9948}
9949
9950 static void
9951f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9952{
9953 char_u *r = NULL;
9954
9955#ifdef FEAT_CLIENTSERVER
9956# ifdef WIN32
9957 r = serverGetVimNames();
9958# else
9959 make_connection();
9960 if (X_DISPLAY != NULL)
9961 r = serverGetVimNames(X_DISPLAY);
9962# endif
9963#endif
9964 rettv->v_type = VAR_STRING;
9965 rettv->vval.v_string = r;
9966}
9967
9968/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009969 * Set line or list of lines in buffer "buf".
9970 */
9971 static void
9972set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
9973{
9974 char_u *line = NULL;
9975 list_T *l = NULL;
9976 listitem_T *li = NULL;
9977 long added = 0;
9978 linenr_T lcount;
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009979 buf_T *curbuf_save = NULL;
9980 win_T *curwin_save = NULL;
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009981 int is_curbuf = buf == curbuf;
9982
Bram Moolenaar9d954202017-09-04 20:34:19 +02009983 /* When using the current buffer ml_mfp will be set if needed. Useful when
9984 * setline() is used on startup. For other buffers the buffer must be
9985 * loaded. */
9986 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009987 {
9988 rettv->vval.v_number = 1; /* FAIL */
9989 return;
9990 }
9991
Bram Moolenaar0c4dc882017-11-06 21:32:54 +01009992 if (!is_curbuf)
9993 {
9994 wininfo_T *wip;
9995
9996 curbuf_save = curbuf;
9997 curwin_save = curwin;
9998 curbuf = buf;
9999 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
10000 {
10001 if (wip->wi_win != NULL)
10002 {
10003 curwin = wip->wi_win;
10004 break;
10005 }
10006 }
10007 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010008
10009 lcount = curbuf->b_ml.ml_line_count;
10010
10011 if (lines->v_type == VAR_LIST)
10012 {
10013 l = lines->vval.v_list;
10014 li = l->lv_first;
10015 }
10016 else
10017 line = get_tv_string_chk(lines);
10018
10019 /* default result is zero == OK */
10020 for (;;)
10021 {
10022 if (l != NULL)
10023 {
10024 /* list argument, get next string */
10025 if (li == NULL)
10026 break;
10027 line = get_tv_string_chk(&li->li_tv);
10028 li = li->li_next;
10029 }
10030
10031 rettv->vval.v_number = 1; /* FAIL */
10032 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10033 break;
10034
10035 /* When coming here from Insert mode, sync undo, so that this can be
10036 * undone separately from what was previously inserted. */
10037 if (u_sync_once == 2)
10038 {
10039 u_sync_once = 1; /* notify that u_sync() was called */
10040 u_sync(TRUE);
10041 }
10042
10043 if (lnum <= curbuf->b_ml.ml_line_count)
10044 {
10045 /* existing line, replace it */
10046 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10047 {
10048 changed_bytes(lnum, 0);
10049 if (is_curbuf && lnum == curwin->w_cursor.lnum)
10050 check_cursor_col();
10051 rettv->vval.v_number = 0; /* OK */
10052 }
10053 }
10054 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10055 {
10056 /* lnum is one past the last line, append the line */
10057 ++added;
10058 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10059 rettv->vval.v_number = 0; /* OK */
10060 }
10061
10062 if (l == NULL) /* only one string argument */
10063 break;
10064 ++lnum;
10065 }
10066
10067 if (added > 0)
10068 appended_lines_mark(lcount, added);
10069
Bram Moolenaar0c4dc882017-11-06 21:32:54 +010010070 if (!is_curbuf)
10071 {
10072 curbuf = curbuf_save;
10073 curwin = curwin_save;
10074 }
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010075}
10076
10077/*
10078 * "setbufline()" function
10079 */
10080 static void
10081f_setbufline(argvars, rettv)
10082 typval_T *argvars;
10083 typval_T *rettv;
10084{
10085 linenr_T lnum;
10086 buf_T *buf;
10087
10088 buf = get_buf_tv(&argvars[0], FALSE);
10089 if (buf == NULL)
10090 rettv->vval.v_number = 1; /* FAIL */
10091 else
10092 {
10093 lnum = get_tv_lnum_buf(&argvars[1], buf);
10094
10095 set_buffer_lines(buf, lnum, &argvars[2], rettv);
10096 }
10097}
10098
10099/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010100 * "setbufvar()" function
10101 */
10102 static void
10103f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10104{
10105 buf_T *buf;
10106 char_u *varname, *bufvarname;
10107 typval_T *varp;
10108 char_u nbuf[NUMBUFLEN];
10109
10110 if (check_restricted() || check_secure())
10111 return;
10112 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10113 varname = get_tv_string_chk(&argvars[1]);
10114 buf = get_buf_tv(&argvars[0], FALSE);
10115 varp = &argvars[2];
10116
10117 if (buf != NULL && varname != NULL && varp != NULL)
10118 {
10119 if (*varname == '&')
10120 {
10121 long numval;
10122 char_u *strval;
10123 int error = FALSE;
10124 aco_save_T aco;
10125
10126 /* set curbuf to be our buf, temporarily */
10127 aucmd_prepbuf(&aco, buf);
10128
10129 ++varname;
10130 numval = (long)get_tv_number_chk(varp, &error);
10131 strval = get_tv_string_buf_chk(varp, nbuf);
10132 if (!error && strval != NULL)
10133 set_option_value(varname, numval, strval, OPT_LOCAL);
10134
10135 /* reset notion of buffer */
10136 aucmd_restbuf(&aco);
10137 }
10138 else
10139 {
10140 buf_T *save_curbuf = curbuf;
10141
10142 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10143 if (bufvarname != NULL)
10144 {
10145 curbuf = buf;
10146 STRCPY(bufvarname, "b:");
10147 STRCPY(bufvarname + 2, varname);
10148 set_var(bufvarname, varp, TRUE);
10149 vim_free(bufvarname);
10150 curbuf = save_curbuf;
10151 }
10152 }
10153 }
10154}
10155
10156 static void
10157f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10158{
10159 dict_T *d;
10160 dictitem_T *di;
10161 char_u *csearch;
10162
10163 if (argvars[0].v_type != VAR_DICT)
10164 {
10165 EMSG(_(e_dictreq));
10166 return;
10167 }
10168
10169 if ((d = argvars[0].vval.v_dict) != NULL)
10170 {
10171 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10172 if (csearch != NULL)
10173 {
10174#ifdef FEAT_MBYTE
10175 if (enc_utf8)
10176 {
10177 int pcc[MAX_MCO];
10178 int c = utfc_ptr2char(csearch, pcc);
10179
10180 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10181 }
10182 else
10183#endif
10184 set_last_csearch(PTR2CHAR(csearch),
10185 csearch, MB_PTR2LEN(csearch));
10186 }
10187
10188 di = dict_find(d, (char_u *)"forward", -1);
10189 if (di != NULL)
10190 set_csearch_direction((int)get_tv_number(&di->di_tv)
10191 ? FORWARD : BACKWARD);
10192
10193 di = dict_find(d, (char_u *)"until", -1);
10194 if (di != NULL)
10195 set_csearch_until(!!get_tv_number(&di->di_tv));
10196 }
10197}
10198
10199/*
10200 * "setcmdpos()" function
10201 */
10202 static void
10203f_setcmdpos(typval_T *argvars, typval_T *rettv)
10204{
10205 int pos = (int)get_tv_number(&argvars[0]) - 1;
10206
10207 if (pos >= 0)
10208 rettv->vval.v_number = set_cmdline_pos(pos);
10209}
10210
10211/*
10212 * "setfperm({fname}, {mode})" function
10213 */
10214 static void
10215f_setfperm(typval_T *argvars, typval_T *rettv)
10216{
10217 char_u *fname;
10218 char_u modebuf[NUMBUFLEN];
10219 char_u *mode_str;
10220 int i;
10221 int mask;
10222 int mode = 0;
10223
10224 rettv->vval.v_number = 0;
10225 fname = get_tv_string_chk(&argvars[0]);
10226 if (fname == NULL)
10227 return;
10228 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10229 if (mode_str == NULL)
10230 return;
10231 if (STRLEN(mode_str) != 9)
10232 {
10233 EMSG2(_(e_invarg2), mode_str);
10234 return;
10235 }
10236
10237 mask = 1;
10238 for (i = 8; i >= 0; --i)
10239 {
10240 if (mode_str[i] != '-')
10241 mode |= mask;
10242 mask = mask << 1;
10243 }
10244 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10245}
10246
10247/*
10248 * "setline()" function
10249 */
10250 static void
10251f_setline(typval_T *argvars, typval_T *rettv)
10252{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010253 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010254
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010255 set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010256}
10257
Bram Moolenaard823fa92016-08-12 16:29:27 +020010258static 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 +020010259
10260/*
10261 * Used by "setqflist()" and "setloclist()" functions
10262 */
10263 static void
10264set_qf_ll_list(
10265 win_T *wp UNUSED,
10266 typval_T *list_arg UNUSED,
10267 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010268 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010269 typval_T *rettv)
10270{
10271#ifdef FEAT_QUICKFIX
10272 static char *e_invact = N_("E927: Invalid action: '%s'");
10273 char_u *act;
10274 int action = 0;
10275#endif
10276
10277 rettv->vval.v_number = -1;
10278
10279#ifdef FEAT_QUICKFIX
10280 if (list_arg->v_type != VAR_LIST)
10281 EMSG(_(e_listreq));
10282 else
10283 {
10284 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010285 dict_T *d = NULL;
10286 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010287
10288 if (action_arg->v_type == VAR_STRING)
10289 {
10290 act = get_tv_string_chk(action_arg);
10291 if (act == NULL)
10292 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010293 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10294 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010295 action = *act;
10296 else
10297 EMSG2(_(e_invact), act);
10298 }
10299 else if (action_arg->v_type == VAR_UNKNOWN)
10300 action = ' ';
10301 else
10302 EMSG(_(e_stringreq));
10303
Bram Moolenaard823fa92016-08-12 16:29:27 +020010304 if (action_arg->v_type != VAR_UNKNOWN
10305 && what_arg->v_type != VAR_UNKNOWN)
10306 {
10307 if (what_arg->v_type == VAR_DICT)
10308 d = what_arg->vval.v_dict;
10309 else
10310 {
10311 EMSG(_(e_dictreq));
10312 valid_dict = FALSE;
10313 }
10314 }
10315
10316 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10317 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010318 rettv->vval.v_number = 0;
10319 }
10320#endif
10321}
10322
10323/*
10324 * "setloclist()" function
10325 */
10326 static void
10327f_setloclist(typval_T *argvars, typval_T *rettv)
10328{
10329 win_T *win;
10330
10331 rettv->vval.v_number = -1;
10332
10333 win = find_win_by_nr(&argvars[0], NULL);
10334 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010335 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010336}
10337
10338/*
10339 * "setmatches()" function
10340 */
10341 static void
10342f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10343{
10344#ifdef FEAT_SEARCH_EXTRA
10345 list_T *l;
10346 listitem_T *li;
10347 dict_T *d;
10348 list_T *s = NULL;
10349
10350 rettv->vval.v_number = -1;
10351 if (argvars[0].v_type != VAR_LIST)
10352 {
10353 EMSG(_(e_listreq));
10354 return;
10355 }
10356 if ((l = argvars[0].vval.v_list) != NULL)
10357 {
10358
10359 /* To some extent make sure that we are dealing with a list from
10360 * "getmatches()". */
10361 li = l->lv_first;
10362 while (li != NULL)
10363 {
10364 if (li->li_tv.v_type != VAR_DICT
10365 || (d = li->li_tv.vval.v_dict) == NULL)
10366 {
10367 EMSG(_(e_invarg));
10368 return;
10369 }
10370 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10371 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10372 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10373 && dict_find(d, (char_u *)"priority", -1) != NULL
10374 && dict_find(d, (char_u *)"id", -1) != NULL))
10375 {
10376 EMSG(_(e_invarg));
10377 return;
10378 }
10379 li = li->li_next;
10380 }
10381
10382 clear_matches(curwin);
10383 li = l->lv_first;
10384 while (li != NULL)
10385 {
10386 int i = 0;
10387 char_u buf[5];
10388 dictitem_T *di;
10389 char_u *group;
10390 int priority;
10391 int id;
10392 char_u *conceal;
10393
10394 d = li->li_tv.vval.v_dict;
10395 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10396 {
10397 if (s == NULL)
10398 {
10399 s = list_alloc();
10400 if (s == NULL)
10401 return;
10402 }
10403
10404 /* match from matchaddpos() */
10405 for (i = 1; i < 9; i++)
10406 {
10407 sprintf((char *)buf, (char *)"pos%d", i);
10408 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10409 {
10410 if (di->di_tv.v_type != VAR_LIST)
10411 return;
10412
10413 list_append_tv(s, &di->di_tv);
10414 s->lv_refcount++;
10415 }
10416 else
10417 break;
10418 }
10419 }
10420
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010421 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010422 priority = (int)get_dict_number(d, (char_u *)"priority");
10423 id = (int)get_dict_number(d, (char_u *)"id");
10424 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010425 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010426 : NULL;
10427 if (i == 0)
10428 {
10429 match_add(curwin, group,
10430 get_dict_string(d, (char_u *)"pattern", FALSE),
10431 priority, id, NULL, conceal);
10432 }
10433 else
10434 {
10435 match_add(curwin, group, NULL, priority, id, s, conceal);
10436 list_unref(s);
10437 s = NULL;
10438 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010439 vim_free(group);
10440 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010441
10442 li = li->li_next;
10443 }
10444 rettv->vval.v_number = 0;
10445 }
10446#endif
10447}
10448
10449/*
10450 * "setpos()" function
10451 */
10452 static void
10453f_setpos(typval_T *argvars, typval_T *rettv)
10454{
10455 pos_T pos;
10456 int fnum;
10457 char_u *name;
10458 colnr_T curswant = -1;
10459
10460 rettv->vval.v_number = -1;
10461 name = get_tv_string_chk(argvars);
10462 if (name != NULL)
10463 {
10464 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10465 {
10466 if (--pos.col < 0)
10467 pos.col = 0;
10468 if (name[0] == '.' && name[1] == NUL)
10469 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010470 /* set cursor; "fnum" is ignored */
10471 curwin->w_cursor = pos;
10472 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010473 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010474 curwin->w_curswant = curswant - 1;
10475 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010476 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010477 check_cursor();
10478 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010479 }
10480 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10481 {
10482 /* set mark */
10483 if (setmark_pos(name[1], &pos, fnum) == OK)
10484 rettv->vval.v_number = 0;
10485 }
10486 else
10487 EMSG(_(e_invarg));
10488 }
10489 }
10490}
10491
10492/*
10493 * "setqflist()" function
10494 */
10495 static void
10496f_setqflist(typval_T *argvars, typval_T *rettv)
10497{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010498 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010499}
10500
10501/*
10502 * "setreg()" function
10503 */
10504 static void
10505f_setreg(typval_T *argvars, typval_T *rettv)
10506{
10507 int regname;
10508 char_u *strregname;
10509 char_u *stropt;
10510 char_u *strval;
10511 int append;
10512 char_u yank_type;
10513 long block_len;
10514
10515 block_len = -1;
10516 yank_type = MAUTO;
10517 append = FALSE;
10518
10519 strregname = get_tv_string_chk(argvars);
10520 rettv->vval.v_number = 1; /* FAIL is default */
10521
10522 if (strregname == NULL)
10523 return; /* type error; errmsg already given */
10524 regname = *strregname;
10525 if (regname == 0 || regname == '@')
10526 regname = '"';
10527
10528 if (argvars[2].v_type != VAR_UNKNOWN)
10529 {
10530 stropt = get_tv_string_chk(&argvars[2]);
10531 if (stropt == NULL)
10532 return; /* type error */
10533 for (; *stropt != NUL; ++stropt)
10534 switch (*stropt)
10535 {
10536 case 'a': case 'A': /* append */
10537 append = TRUE;
10538 break;
10539 case 'v': case 'c': /* character-wise selection */
10540 yank_type = MCHAR;
10541 break;
10542 case 'V': case 'l': /* line-wise selection */
10543 yank_type = MLINE;
10544 break;
10545 case 'b': case Ctrl_V: /* block-wise selection */
10546 yank_type = MBLOCK;
10547 if (VIM_ISDIGIT(stropt[1]))
10548 {
10549 ++stropt;
10550 block_len = getdigits(&stropt) - 1;
10551 --stropt;
10552 }
10553 break;
10554 }
10555 }
10556
10557 if (argvars[1].v_type == VAR_LIST)
10558 {
10559 char_u **lstval;
10560 char_u **allocval;
10561 char_u buf[NUMBUFLEN];
10562 char_u **curval;
10563 char_u **curallocval;
10564 list_T *ll = argvars[1].vval.v_list;
10565 listitem_T *li;
10566 int len;
10567
10568 /* If the list is NULL handle like an empty list. */
10569 len = ll == NULL ? 0 : ll->lv_len;
10570
10571 /* First half: use for pointers to result lines; second half: use for
10572 * pointers to allocated copies. */
10573 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10574 if (lstval == NULL)
10575 return;
10576 curval = lstval;
10577 allocval = lstval + len + 2;
10578 curallocval = allocval;
10579
10580 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10581 li = li->li_next)
10582 {
10583 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10584 if (strval == NULL)
10585 goto free_lstval;
10586 if (strval == buf)
10587 {
10588 /* Need to make a copy, next get_tv_string_buf_chk() will
10589 * overwrite the string. */
10590 strval = vim_strsave(buf);
10591 if (strval == NULL)
10592 goto free_lstval;
10593 *curallocval++ = strval;
10594 }
10595 *curval++ = strval;
10596 }
10597 *curval++ = NULL;
10598
10599 write_reg_contents_lst(regname, lstval, -1,
10600 append, yank_type, block_len);
10601free_lstval:
10602 while (curallocval > allocval)
10603 vim_free(*--curallocval);
10604 vim_free(lstval);
10605 }
10606 else
10607 {
10608 strval = get_tv_string_chk(&argvars[1]);
10609 if (strval == NULL)
10610 return;
10611 write_reg_contents_ex(regname, strval, -1,
10612 append, yank_type, block_len);
10613 }
10614 rettv->vval.v_number = 0;
10615}
10616
10617/*
10618 * "settabvar()" function
10619 */
10620 static void
10621f_settabvar(typval_T *argvars, typval_T *rettv)
10622{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010623 tabpage_T *save_curtab;
10624 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010625 char_u *varname, *tabvarname;
10626 typval_T *varp;
10627
10628 rettv->vval.v_number = 0;
10629
10630 if (check_restricted() || check_secure())
10631 return;
10632
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010633 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010634 varname = get_tv_string_chk(&argvars[1]);
10635 varp = &argvars[2];
10636
Bram Moolenaar4033c552017-09-16 20:54:51 +020010637 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010638 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010639 save_curtab = curtab;
10640 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010641
10642 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10643 if (tabvarname != NULL)
10644 {
10645 STRCPY(tabvarname, "t:");
10646 STRCPY(tabvarname + 2, varname);
10647 set_var(tabvarname, varp, TRUE);
10648 vim_free(tabvarname);
10649 }
10650
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010651 /* Restore current tabpage */
10652 if (valid_tabpage(save_curtab))
10653 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010654 }
10655}
10656
10657/*
10658 * "settabwinvar()" function
10659 */
10660 static void
10661f_settabwinvar(typval_T *argvars, typval_T *rettv)
10662{
10663 setwinvar(argvars, rettv, 1);
10664}
10665
10666/*
10667 * "setwinvar()" function
10668 */
10669 static void
10670f_setwinvar(typval_T *argvars, typval_T *rettv)
10671{
10672 setwinvar(argvars, rettv, 0);
10673}
10674
10675#ifdef FEAT_CRYPT
10676/*
10677 * "sha256({string})" function
10678 */
10679 static void
10680f_sha256(typval_T *argvars, typval_T *rettv)
10681{
10682 char_u *p;
10683
10684 p = get_tv_string(&argvars[0]);
10685 rettv->vval.v_string = vim_strsave(
10686 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10687 rettv->v_type = VAR_STRING;
10688}
10689#endif /* FEAT_CRYPT */
10690
10691/*
10692 * "shellescape({string})" function
10693 */
10694 static void
10695f_shellescape(typval_T *argvars, typval_T *rettv)
10696{
Bram Moolenaar20615522017-06-05 18:46:26 +020010697 int do_special = non_zero_arg(&argvars[1]);
10698
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010699 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020010700 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010701 rettv->v_type = VAR_STRING;
10702}
10703
10704/*
10705 * shiftwidth() function
10706 */
10707 static void
10708f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10709{
10710 rettv->vval.v_number = get_sw_value(curbuf);
10711}
10712
10713/*
10714 * "simplify()" function
10715 */
10716 static void
10717f_simplify(typval_T *argvars, typval_T *rettv)
10718{
10719 char_u *p;
10720
10721 p = get_tv_string(&argvars[0]);
10722 rettv->vval.v_string = vim_strsave(p);
10723 simplify_filename(rettv->vval.v_string); /* simplify in place */
10724 rettv->v_type = VAR_STRING;
10725}
10726
10727#ifdef FEAT_FLOAT
10728/*
10729 * "sin()" function
10730 */
10731 static void
10732f_sin(typval_T *argvars, typval_T *rettv)
10733{
10734 float_T f = 0.0;
10735
10736 rettv->v_type = VAR_FLOAT;
10737 if (get_float_arg(argvars, &f) == OK)
10738 rettv->vval.v_float = sin(f);
10739 else
10740 rettv->vval.v_float = 0.0;
10741}
10742
10743/*
10744 * "sinh()" function
10745 */
10746 static void
10747f_sinh(typval_T *argvars, typval_T *rettv)
10748{
10749 float_T f = 0.0;
10750
10751 rettv->v_type = VAR_FLOAT;
10752 if (get_float_arg(argvars, &f) == OK)
10753 rettv->vval.v_float = sinh(f);
10754 else
10755 rettv->vval.v_float = 0.0;
10756}
10757#endif
10758
10759static int
10760#ifdef __BORLANDC__
10761 _RTLENTRYF
10762#endif
10763 item_compare(const void *s1, const void *s2);
10764static int
10765#ifdef __BORLANDC__
10766 _RTLENTRYF
10767#endif
10768 item_compare2(const void *s1, const void *s2);
10769
10770/* struct used in the array that's given to qsort() */
10771typedef struct
10772{
10773 listitem_T *item;
10774 int idx;
10775} sortItem_T;
10776
10777/* struct storing information about current sort */
10778typedef struct
10779{
10780 int item_compare_ic;
10781 int item_compare_numeric;
10782 int item_compare_numbers;
10783#ifdef FEAT_FLOAT
10784 int item_compare_float;
10785#endif
10786 char_u *item_compare_func;
10787 partial_T *item_compare_partial;
10788 dict_T *item_compare_selfdict;
10789 int item_compare_func_err;
10790 int item_compare_keep_zero;
10791} sortinfo_T;
10792static sortinfo_T *sortinfo = NULL;
10793static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10794#define ITEM_COMPARE_FAIL 999
10795
10796/*
10797 * Compare functions for f_sort() and f_uniq() below.
10798 */
10799 static int
10800#ifdef __BORLANDC__
10801_RTLENTRYF
10802#endif
10803item_compare(const void *s1, const void *s2)
10804{
10805 sortItem_T *si1, *si2;
10806 typval_T *tv1, *tv2;
10807 char_u *p1, *p2;
10808 char_u *tofree1 = NULL, *tofree2 = NULL;
10809 int res;
10810 char_u numbuf1[NUMBUFLEN];
10811 char_u numbuf2[NUMBUFLEN];
10812
10813 si1 = (sortItem_T *)s1;
10814 si2 = (sortItem_T *)s2;
10815 tv1 = &si1->item->li_tv;
10816 tv2 = &si2->item->li_tv;
10817
10818 if (sortinfo->item_compare_numbers)
10819 {
10820 varnumber_T v1 = get_tv_number(tv1);
10821 varnumber_T v2 = get_tv_number(tv2);
10822
10823 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10824 }
10825
10826#ifdef FEAT_FLOAT
10827 if (sortinfo->item_compare_float)
10828 {
10829 float_T v1 = get_tv_float(tv1);
10830 float_T v2 = get_tv_float(tv2);
10831
10832 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10833 }
10834#endif
10835
10836 /* tv2string() puts quotes around a string and allocates memory. Don't do
10837 * that for string variables. Use a single quote when comparing with a
10838 * non-string to do what the docs promise. */
10839 if (tv1->v_type == VAR_STRING)
10840 {
10841 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10842 p1 = (char_u *)"'";
10843 else
10844 p1 = tv1->vval.v_string;
10845 }
10846 else
10847 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10848 if (tv2->v_type == VAR_STRING)
10849 {
10850 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10851 p2 = (char_u *)"'";
10852 else
10853 p2 = tv2->vval.v_string;
10854 }
10855 else
10856 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10857 if (p1 == NULL)
10858 p1 = (char_u *)"";
10859 if (p2 == NULL)
10860 p2 = (char_u *)"";
10861 if (!sortinfo->item_compare_numeric)
10862 {
10863 if (sortinfo->item_compare_ic)
10864 res = STRICMP(p1, p2);
10865 else
10866 res = STRCMP(p1, p2);
10867 }
10868 else
10869 {
10870 double n1, n2;
10871 n1 = strtod((char *)p1, (char **)&p1);
10872 n2 = strtod((char *)p2, (char **)&p2);
10873 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10874 }
10875
10876 /* When the result would be zero, compare the item indexes. Makes the
10877 * sort stable. */
10878 if (res == 0 && !sortinfo->item_compare_keep_zero)
10879 res = si1->idx > si2->idx ? 1 : -1;
10880
10881 vim_free(tofree1);
10882 vim_free(tofree2);
10883 return res;
10884}
10885
10886 static int
10887#ifdef __BORLANDC__
10888_RTLENTRYF
10889#endif
10890item_compare2(const void *s1, const void *s2)
10891{
10892 sortItem_T *si1, *si2;
10893 int res;
10894 typval_T rettv;
10895 typval_T argv[3];
10896 int dummy;
10897 char_u *func_name;
10898 partial_T *partial = sortinfo->item_compare_partial;
10899
10900 /* shortcut after failure in previous call; compare all items equal */
10901 if (sortinfo->item_compare_func_err)
10902 return 0;
10903
10904 si1 = (sortItem_T *)s1;
10905 si2 = (sortItem_T *)s2;
10906
10907 if (partial == NULL)
10908 func_name = sortinfo->item_compare_func;
10909 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010910 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010911
10912 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10913 * in the copy without changing the original list items. */
10914 copy_tv(&si1->item->li_tv, &argv[0]);
10915 copy_tv(&si2->item->li_tv, &argv[1]);
10916
10917 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10918 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010919 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010920 partial, sortinfo->item_compare_selfdict);
10921 clear_tv(&argv[0]);
10922 clear_tv(&argv[1]);
10923
10924 if (res == FAIL)
10925 res = ITEM_COMPARE_FAIL;
10926 else
10927 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10928 if (sortinfo->item_compare_func_err)
10929 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10930 clear_tv(&rettv);
10931
10932 /* When the result would be zero, compare the pointers themselves. Makes
10933 * the sort stable. */
10934 if (res == 0 && !sortinfo->item_compare_keep_zero)
10935 res = si1->idx > si2->idx ? 1 : -1;
10936
10937 return res;
10938}
10939
10940/*
10941 * "sort({list})" function
10942 */
10943 static void
10944do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10945{
10946 list_T *l;
10947 listitem_T *li;
10948 sortItem_T *ptrs;
10949 sortinfo_T *old_sortinfo;
10950 sortinfo_T info;
10951 long len;
10952 long i;
10953
10954 /* Pointer to current info struct used in compare function. Save and
10955 * restore the current one for nested calls. */
10956 old_sortinfo = sortinfo;
10957 sortinfo = &info;
10958
10959 if (argvars[0].v_type != VAR_LIST)
10960 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10961 else
10962 {
10963 l = argvars[0].vval.v_list;
10964 if (l == NULL || tv_check_lock(l->lv_lock,
10965 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10966 TRUE))
10967 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010968 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010969
10970 len = list_len(l);
10971 if (len <= 1)
10972 goto theend; /* short list sorts pretty quickly */
10973
10974 info.item_compare_ic = FALSE;
10975 info.item_compare_numeric = FALSE;
10976 info.item_compare_numbers = FALSE;
10977#ifdef FEAT_FLOAT
10978 info.item_compare_float = FALSE;
10979#endif
10980 info.item_compare_func = NULL;
10981 info.item_compare_partial = NULL;
10982 info.item_compare_selfdict = NULL;
10983 if (argvars[1].v_type != VAR_UNKNOWN)
10984 {
10985 /* optional second argument: {func} */
10986 if (argvars[1].v_type == VAR_FUNC)
10987 info.item_compare_func = argvars[1].vval.v_string;
10988 else if (argvars[1].v_type == VAR_PARTIAL)
10989 info.item_compare_partial = argvars[1].vval.v_partial;
10990 else
10991 {
10992 int error = FALSE;
10993
10994 i = (long)get_tv_number_chk(&argvars[1], &error);
10995 if (error)
10996 goto theend; /* type error; errmsg already given */
10997 if (i == 1)
10998 info.item_compare_ic = TRUE;
10999 else if (argvars[1].v_type != VAR_NUMBER)
11000 info.item_compare_func = get_tv_string(&argvars[1]);
11001 else if (i != 0)
11002 {
11003 EMSG(_(e_invarg));
11004 goto theend;
11005 }
11006 if (info.item_compare_func != NULL)
11007 {
11008 if (*info.item_compare_func == NUL)
11009 {
11010 /* empty string means default sort */
11011 info.item_compare_func = NULL;
11012 }
11013 else if (STRCMP(info.item_compare_func, "n") == 0)
11014 {
11015 info.item_compare_func = NULL;
11016 info.item_compare_numeric = TRUE;
11017 }
11018 else if (STRCMP(info.item_compare_func, "N") == 0)
11019 {
11020 info.item_compare_func = NULL;
11021 info.item_compare_numbers = TRUE;
11022 }
11023#ifdef FEAT_FLOAT
11024 else if (STRCMP(info.item_compare_func, "f") == 0)
11025 {
11026 info.item_compare_func = NULL;
11027 info.item_compare_float = TRUE;
11028 }
11029#endif
11030 else if (STRCMP(info.item_compare_func, "i") == 0)
11031 {
11032 info.item_compare_func = NULL;
11033 info.item_compare_ic = TRUE;
11034 }
11035 }
11036 }
11037
11038 if (argvars[2].v_type != VAR_UNKNOWN)
11039 {
11040 /* optional third argument: {dict} */
11041 if (argvars[2].v_type != VAR_DICT)
11042 {
11043 EMSG(_(e_dictreq));
11044 goto theend;
11045 }
11046 info.item_compare_selfdict = argvars[2].vval.v_dict;
11047 }
11048 }
11049
11050 /* Make an array with each entry pointing to an item in the List. */
11051 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11052 if (ptrs == NULL)
11053 goto theend;
11054
11055 i = 0;
11056 if (sort)
11057 {
11058 /* sort(): ptrs will be the list to sort */
11059 for (li = l->lv_first; li != NULL; li = li->li_next)
11060 {
11061 ptrs[i].item = li;
11062 ptrs[i].idx = i;
11063 ++i;
11064 }
11065
11066 info.item_compare_func_err = FALSE;
11067 info.item_compare_keep_zero = FALSE;
11068 /* test the compare function */
11069 if ((info.item_compare_func != NULL
11070 || info.item_compare_partial != NULL)
11071 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11072 == ITEM_COMPARE_FAIL)
11073 EMSG(_("E702: Sort compare function failed"));
11074 else
11075 {
11076 /* Sort the array with item pointers. */
11077 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11078 info.item_compare_func == NULL
11079 && info.item_compare_partial == NULL
11080 ? item_compare : item_compare2);
11081
11082 if (!info.item_compare_func_err)
11083 {
11084 /* Clear the List and append the items in sorted order. */
11085 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11086 l->lv_len = 0;
11087 for (i = 0; i < len; ++i)
11088 list_append(l, ptrs[i].item);
11089 }
11090 }
11091 }
11092 else
11093 {
11094 int (*item_compare_func_ptr)(const void *, const void *);
11095
11096 /* f_uniq(): ptrs will be a stack of items to remove */
11097 info.item_compare_func_err = FALSE;
11098 info.item_compare_keep_zero = TRUE;
11099 item_compare_func_ptr = info.item_compare_func != NULL
11100 || info.item_compare_partial != NULL
11101 ? item_compare2 : item_compare;
11102
11103 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11104 li = li->li_next)
11105 {
11106 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11107 == 0)
11108 ptrs[i++].item = li;
11109 if (info.item_compare_func_err)
11110 {
11111 EMSG(_("E882: Uniq compare function failed"));
11112 break;
11113 }
11114 }
11115
11116 if (!info.item_compare_func_err)
11117 {
11118 while (--i >= 0)
11119 {
11120 li = ptrs[i].item->li_next;
11121 ptrs[i].item->li_next = li->li_next;
11122 if (li->li_next != NULL)
11123 li->li_next->li_prev = ptrs[i].item;
11124 else
11125 l->lv_last = ptrs[i].item;
11126 list_fix_watch(l, li);
11127 listitem_free(li);
11128 l->lv_len--;
11129 }
11130 }
11131 }
11132
11133 vim_free(ptrs);
11134 }
11135theend:
11136 sortinfo = old_sortinfo;
11137}
11138
11139/*
11140 * "sort({list})" function
11141 */
11142 static void
11143f_sort(typval_T *argvars, typval_T *rettv)
11144{
11145 do_sort_uniq(argvars, rettv, TRUE);
11146}
11147
11148/*
11149 * "uniq({list})" function
11150 */
11151 static void
11152f_uniq(typval_T *argvars, typval_T *rettv)
11153{
11154 do_sort_uniq(argvars, rettv, FALSE);
11155}
11156
11157/*
11158 * "soundfold({word})" function
11159 */
11160 static void
11161f_soundfold(typval_T *argvars, typval_T *rettv)
11162{
11163 char_u *s;
11164
11165 rettv->v_type = VAR_STRING;
11166 s = get_tv_string(&argvars[0]);
11167#ifdef FEAT_SPELL
11168 rettv->vval.v_string = eval_soundfold(s);
11169#else
11170 rettv->vval.v_string = vim_strsave(s);
11171#endif
11172}
11173
11174/*
11175 * "spellbadword()" function
11176 */
11177 static void
11178f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11179{
11180 char_u *word = (char_u *)"";
11181 hlf_T attr = HLF_COUNT;
11182 int len = 0;
11183
11184 if (rettv_list_alloc(rettv) == FAIL)
11185 return;
11186
11187#ifdef FEAT_SPELL
11188 if (argvars[0].v_type == VAR_UNKNOWN)
11189 {
11190 /* Find the start and length of the badly spelled word. */
11191 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11192 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011193 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011194 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011195 curwin->w_set_curswant = TRUE;
11196 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011197 }
11198 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11199 {
11200 char_u *str = get_tv_string_chk(&argvars[0]);
11201 int capcol = -1;
11202
11203 if (str != NULL)
11204 {
11205 /* Check the argument for spelling. */
11206 while (*str != NUL)
11207 {
11208 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11209 if (attr != HLF_COUNT)
11210 {
11211 word = str;
11212 break;
11213 }
11214 str += len;
11215 }
11216 }
11217 }
11218#endif
11219
11220 list_append_string(rettv->vval.v_list, word, len);
11221 list_append_string(rettv->vval.v_list, (char_u *)(
11222 attr == HLF_SPB ? "bad" :
11223 attr == HLF_SPR ? "rare" :
11224 attr == HLF_SPL ? "local" :
11225 attr == HLF_SPC ? "caps" :
11226 ""), -1);
11227}
11228
11229/*
11230 * "spellsuggest()" function
11231 */
11232 static void
11233f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11234{
11235#ifdef FEAT_SPELL
11236 char_u *str;
11237 int typeerr = FALSE;
11238 int maxcount;
11239 garray_T ga;
11240 int i;
11241 listitem_T *li;
11242 int need_capital = FALSE;
11243#endif
11244
11245 if (rettv_list_alloc(rettv) == FAIL)
11246 return;
11247
11248#ifdef FEAT_SPELL
11249 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11250 {
11251 str = get_tv_string(&argvars[0]);
11252 if (argvars[1].v_type != VAR_UNKNOWN)
11253 {
11254 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11255 if (maxcount <= 0)
11256 return;
11257 if (argvars[2].v_type != VAR_UNKNOWN)
11258 {
11259 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11260 if (typeerr)
11261 return;
11262 }
11263 }
11264 else
11265 maxcount = 25;
11266
11267 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11268
11269 for (i = 0; i < ga.ga_len; ++i)
11270 {
11271 str = ((char_u **)ga.ga_data)[i];
11272
11273 li = listitem_alloc();
11274 if (li == NULL)
11275 vim_free(str);
11276 else
11277 {
11278 li->li_tv.v_type = VAR_STRING;
11279 li->li_tv.v_lock = 0;
11280 li->li_tv.vval.v_string = str;
11281 list_append(rettv->vval.v_list, li);
11282 }
11283 }
11284 ga_clear(&ga);
11285 }
11286#endif
11287}
11288
11289 static void
11290f_split(typval_T *argvars, typval_T *rettv)
11291{
11292 char_u *str;
11293 char_u *end;
11294 char_u *pat = NULL;
11295 regmatch_T regmatch;
11296 char_u patbuf[NUMBUFLEN];
11297 char_u *save_cpo;
11298 int match;
11299 colnr_T col = 0;
11300 int keepempty = FALSE;
11301 int typeerr = FALSE;
11302
11303 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11304 save_cpo = p_cpo;
11305 p_cpo = (char_u *)"";
11306
11307 str = get_tv_string(&argvars[0]);
11308 if (argvars[1].v_type != VAR_UNKNOWN)
11309 {
11310 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11311 if (pat == NULL)
11312 typeerr = TRUE;
11313 if (argvars[2].v_type != VAR_UNKNOWN)
11314 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11315 }
11316 if (pat == NULL || *pat == NUL)
11317 pat = (char_u *)"[\\x01- ]\\+";
11318
11319 if (rettv_list_alloc(rettv) == FAIL)
11320 return;
11321 if (typeerr)
11322 return;
11323
11324 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11325 if (regmatch.regprog != NULL)
11326 {
11327 regmatch.rm_ic = FALSE;
11328 while (*str != NUL || keepempty)
11329 {
11330 if (*str == NUL)
11331 match = FALSE; /* empty item at the end */
11332 else
11333 match = vim_regexec_nl(&regmatch, str, col);
11334 if (match)
11335 end = regmatch.startp[0];
11336 else
11337 end = str + STRLEN(str);
11338 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11339 && *str != NUL && match && end < regmatch.endp[0]))
11340 {
11341 if (list_append_string(rettv->vval.v_list, str,
11342 (int)(end - str)) == FAIL)
11343 break;
11344 }
11345 if (!match)
11346 break;
11347 /* Advance to just after the match. */
11348 if (regmatch.endp[0] > str)
11349 col = 0;
11350 else
11351 {
11352 /* Don't get stuck at the same match. */
11353#ifdef FEAT_MBYTE
11354 col = (*mb_ptr2len)(regmatch.endp[0]);
11355#else
11356 col = 1;
11357#endif
11358 }
11359 str = regmatch.endp[0];
11360 }
11361
11362 vim_regfree(regmatch.regprog);
11363 }
11364
11365 p_cpo = save_cpo;
11366}
11367
11368#ifdef FEAT_FLOAT
11369/*
11370 * "sqrt()" function
11371 */
11372 static void
11373f_sqrt(typval_T *argvars, typval_T *rettv)
11374{
11375 float_T f = 0.0;
11376
11377 rettv->v_type = VAR_FLOAT;
11378 if (get_float_arg(argvars, &f) == OK)
11379 rettv->vval.v_float = sqrt(f);
11380 else
11381 rettv->vval.v_float = 0.0;
11382}
11383
11384/*
11385 * "str2float()" function
11386 */
11387 static void
11388f_str2float(typval_T *argvars, typval_T *rettv)
11389{
11390 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011391 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011392
Bram Moolenaar08243d22017-01-10 16:12:29 +010011393 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011394 p = skipwhite(p + 1);
11395 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011396 if (isneg)
11397 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011398 rettv->v_type = VAR_FLOAT;
11399}
11400#endif
11401
11402/*
11403 * "str2nr()" function
11404 */
11405 static void
11406f_str2nr(typval_T *argvars, typval_T *rettv)
11407{
11408 int base = 10;
11409 char_u *p;
11410 varnumber_T n;
11411 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011412 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011413
11414 if (argvars[1].v_type != VAR_UNKNOWN)
11415 {
11416 base = (int)get_tv_number(&argvars[1]);
11417 if (base != 2 && base != 8 && base != 10 && base != 16)
11418 {
11419 EMSG(_(e_invarg));
11420 return;
11421 }
11422 }
11423
11424 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011425 isneg = (*p == '-');
11426 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011427 p = skipwhite(p + 1);
11428 switch (base)
11429 {
11430 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11431 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11432 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11433 default: what = 0;
11434 }
11435 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011436 if (isneg)
11437 rettv->vval.v_number = -n;
11438 else
11439 rettv->vval.v_number = n;
11440
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011441}
11442
11443#ifdef HAVE_STRFTIME
11444/*
11445 * "strftime({format}[, {time}])" function
11446 */
11447 static void
11448f_strftime(typval_T *argvars, typval_T *rettv)
11449{
11450 char_u result_buf[256];
11451 struct tm *curtime;
11452 time_t seconds;
11453 char_u *p;
11454
11455 rettv->v_type = VAR_STRING;
11456
11457 p = get_tv_string(&argvars[0]);
11458 if (argvars[1].v_type == VAR_UNKNOWN)
11459 seconds = time(NULL);
11460 else
11461 seconds = (time_t)get_tv_number(&argvars[1]);
11462 curtime = localtime(&seconds);
11463 /* MSVC returns NULL for an invalid value of seconds. */
11464 if (curtime == NULL)
11465 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11466 else
11467 {
11468# ifdef FEAT_MBYTE
11469 vimconv_T conv;
11470 char_u *enc;
11471
11472 conv.vc_type = CONV_NONE;
11473 enc = enc_locale();
11474 convert_setup(&conv, p_enc, enc);
11475 if (conv.vc_type != CONV_NONE)
11476 p = string_convert(&conv, p, NULL);
11477# endif
11478 if (p != NULL)
11479 (void)strftime((char *)result_buf, sizeof(result_buf),
11480 (char *)p, curtime);
11481 else
11482 result_buf[0] = NUL;
11483
11484# ifdef FEAT_MBYTE
11485 if (conv.vc_type != CONV_NONE)
11486 vim_free(p);
11487 convert_setup(&conv, enc, p_enc);
11488 if (conv.vc_type != CONV_NONE)
11489 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11490 else
11491# endif
11492 rettv->vval.v_string = vim_strsave(result_buf);
11493
11494# ifdef FEAT_MBYTE
11495 /* Release conversion descriptors */
11496 convert_setup(&conv, NULL, NULL);
11497 vim_free(enc);
11498# endif
11499 }
11500}
11501#endif
11502
11503/*
11504 * "strgetchar()" function
11505 */
11506 static void
11507f_strgetchar(typval_T *argvars, typval_T *rettv)
11508{
11509 char_u *str;
11510 int len;
11511 int error = FALSE;
11512 int charidx;
11513
11514 rettv->vval.v_number = -1;
11515 str = get_tv_string_chk(&argvars[0]);
11516 if (str == NULL)
11517 return;
11518 len = (int)STRLEN(str);
11519 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11520 if (error)
11521 return;
11522#ifdef FEAT_MBYTE
11523 {
11524 int byteidx = 0;
11525
11526 while (charidx >= 0 && byteidx < len)
11527 {
11528 if (charidx == 0)
11529 {
11530 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11531 break;
11532 }
11533 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011534 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011535 }
11536 }
11537#else
11538 if (charidx < len)
11539 rettv->vval.v_number = str[charidx];
11540#endif
11541}
11542
11543/*
11544 * "stridx()" function
11545 */
11546 static void
11547f_stridx(typval_T *argvars, typval_T *rettv)
11548{
11549 char_u buf[NUMBUFLEN];
11550 char_u *needle;
11551 char_u *haystack;
11552 char_u *save_haystack;
11553 char_u *pos;
11554 int start_idx;
11555
11556 needle = get_tv_string_chk(&argvars[1]);
11557 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11558 rettv->vval.v_number = -1;
11559 if (needle == NULL || haystack == NULL)
11560 return; /* type error; errmsg already given */
11561
11562 if (argvars[2].v_type != VAR_UNKNOWN)
11563 {
11564 int error = FALSE;
11565
11566 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11567 if (error || start_idx >= (int)STRLEN(haystack))
11568 return;
11569 if (start_idx >= 0)
11570 haystack += start_idx;
11571 }
11572
11573 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11574 if (pos != NULL)
11575 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11576}
11577
11578/*
11579 * "string()" function
11580 */
11581 static void
11582f_string(typval_T *argvars, typval_T *rettv)
11583{
11584 char_u *tofree;
11585 char_u numbuf[NUMBUFLEN];
11586
11587 rettv->v_type = VAR_STRING;
11588 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11589 get_copyID());
11590 /* Make a copy if we have a value but it's not in allocated memory. */
11591 if (rettv->vval.v_string != NULL && tofree == NULL)
11592 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11593}
11594
11595/*
11596 * "strlen()" function
11597 */
11598 static void
11599f_strlen(typval_T *argvars, typval_T *rettv)
11600{
11601 rettv->vval.v_number = (varnumber_T)(STRLEN(
11602 get_tv_string(&argvars[0])));
11603}
11604
11605/*
11606 * "strchars()" function
11607 */
11608 static void
11609f_strchars(typval_T *argvars, typval_T *rettv)
11610{
11611 char_u *s = get_tv_string(&argvars[0]);
11612 int skipcc = 0;
11613#ifdef FEAT_MBYTE
11614 varnumber_T len = 0;
11615 int (*func_mb_ptr2char_adv)(char_u **pp);
11616#endif
11617
11618 if (argvars[1].v_type != VAR_UNKNOWN)
11619 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11620 if (skipcc < 0 || skipcc > 1)
11621 EMSG(_(e_invarg));
11622 else
11623 {
11624#ifdef FEAT_MBYTE
11625 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11626 while (*s != NUL)
11627 {
11628 func_mb_ptr2char_adv(&s);
11629 ++len;
11630 }
11631 rettv->vval.v_number = len;
11632#else
11633 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11634#endif
11635 }
11636}
11637
11638/*
11639 * "strdisplaywidth()" function
11640 */
11641 static void
11642f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11643{
11644 char_u *s = get_tv_string(&argvars[0]);
11645 int col = 0;
11646
11647 if (argvars[1].v_type != VAR_UNKNOWN)
11648 col = (int)get_tv_number(&argvars[1]);
11649
11650 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11651}
11652
11653/*
11654 * "strwidth()" function
11655 */
11656 static void
11657f_strwidth(typval_T *argvars, typval_T *rettv)
11658{
11659 char_u *s = get_tv_string(&argvars[0]);
11660
11661 rettv->vval.v_number = (varnumber_T)(
11662#ifdef FEAT_MBYTE
11663 mb_string2cells(s, -1)
11664#else
11665 STRLEN(s)
11666#endif
11667 );
11668}
11669
11670/*
11671 * "strcharpart()" function
11672 */
11673 static void
11674f_strcharpart(typval_T *argvars, typval_T *rettv)
11675{
11676#ifdef FEAT_MBYTE
11677 char_u *p;
11678 int nchar;
11679 int nbyte = 0;
11680 int charlen;
11681 int len = 0;
11682 int slen;
11683 int error = FALSE;
11684
11685 p = get_tv_string(&argvars[0]);
11686 slen = (int)STRLEN(p);
11687
11688 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11689 if (!error)
11690 {
11691 if (nchar > 0)
11692 while (nchar > 0 && nbyte < slen)
11693 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011694 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011695 --nchar;
11696 }
11697 else
11698 nbyte = nchar;
11699 if (argvars[2].v_type != VAR_UNKNOWN)
11700 {
11701 charlen = (int)get_tv_number(&argvars[2]);
11702 while (charlen > 0 && nbyte + len < slen)
11703 {
11704 int off = nbyte + len;
11705
11706 if (off < 0)
11707 len += 1;
11708 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011709 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011710 --charlen;
11711 }
11712 }
11713 else
11714 len = slen - nbyte; /* default: all bytes that are available. */
11715 }
11716
11717 /*
11718 * Only return the overlap between the specified part and the actual
11719 * string.
11720 */
11721 if (nbyte < 0)
11722 {
11723 len += nbyte;
11724 nbyte = 0;
11725 }
11726 else if (nbyte > slen)
11727 nbyte = slen;
11728 if (len < 0)
11729 len = 0;
11730 else if (nbyte + len > slen)
11731 len = slen - nbyte;
11732
11733 rettv->v_type = VAR_STRING;
11734 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11735#else
11736 f_strpart(argvars, rettv);
11737#endif
11738}
11739
11740/*
11741 * "strpart()" function
11742 */
11743 static void
11744f_strpart(typval_T *argvars, typval_T *rettv)
11745{
11746 char_u *p;
11747 int n;
11748 int len;
11749 int slen;
11750 int error = FALSE;
11751
11752 p = get_tv_string(&argvars[0]);
11753 slen = (int)STRLEN(p);
11754
11755 n = (int)get_tv_number_chk(&argvars[1], &error);
11756 if (error)
11757 len = 0;
11758 else if (argvars[2].v_type != VAR_UNKNOWN)
11759 len = (int)get_tv_number(&argvars[2]);
11760 else
11761 len = slen - n; /* default len: all bytes that are available. */
11762
11763 /*
11764 * Only return the overlap between the specified part and the actual
11765 * string.
11766 */
11767 if (n < 0)
11768 {
11769 len += n;
11770 n = 0;
11771 }
11772 else if (n > slen)
11773 n = slen;
11774 if (len < 0)
11775 len = 0;
11776 else if (n + len > slen)
11777 len = slen - n;
11778
11779 rettv->v_type = VAR_STRING;
11780 rettv->vval.v_string = vim_strnsave(p + n, len);
11781}
11782
11783/*
11784 * "strridx()" function
11785 */
11786 static void
11787f_strridx(typval_T *argvars, typval_T *rettv)
11788{
11789 char_u buf[NUMBUFLEN];
11790 char_u *needle;
11791 char_u *haystack;
11792 char_u *rest;
11793 char_u *lastmatch = NULL;
11794 int haystack_len, end_idx;
11795
11796 needle = get_tv_string_chk(&argvars[1]);
11797 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11798
11799 rettv->vval.v_number = -1;
11800 if (needle == NULL || haystack == NULL)
11801 return; /* type error; errmsg already given */
11802
11803 haystack_len = (int)STRLEN(haystack);
11804 if (argvars[2].v_type != VAR_UNKNOWN)
11805 {
11806 /* Third argument: upper limit for index */
11807 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11808 if (end_idx < 0)
11809 return; /* can never find a match */
11810 }
11811 else
11812 end_idx = haystack_len;
11813
11814 if (*needle == NUL)
11815 {
11816 /* Empty string matches past the end. */
11817 lastmatch = haystack + end_idx;
11818 }
11819 else
11820 {
11821 for (rest = haystack; *rest != '\0'; ++rest)
11822 {
11823 rest = (char_u *)strstr((char *)rest, (char *)needle);
11824 if (rest == NULL || rest > haystack + end_idx)
11825 break;
11826 lastmatch = rest;
11827 }
11828 }
11829
11830 if (lastmatch == NULL)
11831 rettv->vval.v_number = -1;
11832 else
11833 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11834}
11835
11836/*
11837 * "strtrans()" function
11838 */
11839 static void
11840f_strtrans(typval_T *argvars, typval_T *rettv)
11841{
11842 rettv->v_type = VAR_STRING;
11843 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11844}
11845
11846/*
11847 * "submatch()" function
11848 */
11849 static void
11850f_submatch(typval_T *argvars, typval_T *rettv)
11851{
11852 int error = FALSE;
11853 int no;
11854 int retList = 0;
11855
11856 no = (int)get_tv_number_chk(&argvars[0], &error);
11857 if (error)
11858 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011859 if (no < 0 || no >= NSUBEXP)
11860 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010011861 EMSGN(_("E935: invalid submatch number: %d"), no);
11862 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011863 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011864 if (argvars[1].v_type != VAR_UNKNOWN)
11865 retList = (int)get_tv_number_chk(&argvars[1], &error);
11866 if (error)
11867 return;
11868
11869 if (retList == 0)
11870 {
11871 rettv->v_type = VAR_STRING;
11872 rettv->vval.v_string = reg_submatch(no);
11873 }
11874 else
11875 {
11876 rettv->v_type = VAR_LIST;
11877 rettv->vval.v_list = reg_submatch_list(no);
11878 }
11879}
11880
11881/*
11882 * "substitute()" function
11883 */
11884 static void
11885f_substitute(typval_T *argvars, typval_T *rettv)
11886{
11887 char_u patbuf[NUMBUFLEN];
11888 char_u subbuf[NUMBUFLEN];
11889 char_u flagsbuf[NUMBUFLEN];
11890
11891 char_u *str = get_tv_string_chk(&argvars[0]);
11892 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011893 char_u *sub = NULL;
11894 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011895 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11896
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011897 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11898 expr = &argvars[2];
11899 else
11900 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11901
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011902 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011903 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11904 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011905 rettv->vval.v_string = NULL;
11906 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011907 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011908}
11909
11910/*
11911 * "synID(lnum, col, trans)" function
11912 */
11913 static void
11914f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11915{
11916 int id = 0;
11917#ifdef FEAT_SYN_HL
11918 linenr_T lnum;
11919 colnr_T col;
11920 int trans;
11921 int transerr = FALSE;
11922
11923 lnum = get_tv_lnum(argvars); /* -1 on type error */
11924 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11925 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11926
11927 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11928 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11929 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11930#endif
11931
11932 rettv->vval.v_number = id;
11933}
11934
11935/*
11936 * "synIDattr(id, what [, mode])" function
11937 */
11938 static void
11939f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11940{
11941 char_u *p = NULL;
11942#ifdef FEAT_SYN_HL
11943 int id;
11944 char_u *what;
11945 char_u *mode;
11946 char_u modebuf[NUMBUFLEN];
11947 int modec;
11948
11949 id = (int)get_tv_number(&argvars[0]);
11950 what = get_tv_string(&argvars[1]);
11951 if (argvars[2].v_type != VAR_UNKNOWN)
11952 {
11953 mode = get_tv_string_buf(&argvars[2], modebuf);
11954 modec = TOLOWER_ASC(mode[0]);
11955 if (modec != 't' && modec != 'c' && modec != 'g')
11956 modec = 0; /* replace invalid with current */
11957 }
11958 else
11959 {
11960#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11961 if (USE_24BIT)
11962 modec = 'g';
11963 else
11964#endif
11965 if (t_colors > 1)
11966 modec = 'c';
11967 else
11968 modec = 't';
11969 }
11970
11971
11972 switch (TOLOWER_ASC(what[0]))
11973 {
11974 case 'b':
11975 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11976 p = highlight_color(id, what, modec);
11977 else /* bold */
11978 p = highlight_has_attr(id, HL_BOLD, modec);
11979 break;
11980
11981 case 'f': /* fg[#] or font */
11982 p = highlight_color(id, what, modec);
11983 break;
11984
11985 case 'i':
11986 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11987 p = highlight_has_attr(id, HL_INVERSE, modec);
11988 else /* italic */
11989 p = highlight_has_attr(id, HL_ITALIC, modec);
11990 break;
11991
11992 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011993 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011994 break;
11995
11996 case 'r': /* reverse */
11997 p = highlight_has_attr(id, HL_INVERSE, modec);
11998 break;
11999
12000 case 's':
12001 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12002 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012003 /* strikeout */
12004 else if (TOLOWER_ASC(what[1]) == 't' &&
12005 TOLOWER_ASC(what[2]) == 'r')
12006 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012007 else /* standout */
12008 p = highlight_has_attr(id, HL_STANDOUT, modec);
12009 break;
12010
12011 case 'u':
12012 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12013 /* underline */
12014 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12015 else
12016 /* undercurl */
12017 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12018 break;
12019 }
12020
12021 if (p != NULL)
12022 p = vim_strsave(p);
12023#endif
12024 rettv->v_type = VAR_STRING;
12025 rettv->vval.v_string = p;
12026}
12027
12028/*
12029 * "synIDtrans(id)" function
12030 */
12031 static void
12032f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12033{
12034 int id;
12035
12036#ifdef FEAT_SYN_HL
12037 id = (int)get_tv_number(&argvars[0]);
12038
12039 if (id > 0)
12040 id = syn_get_final_id(id);
12041 else
12042#endif
12043 id = 0;
12044
12045 rettv->vval.v_number = id;
12046}
12047
12048/*
12049 * "synconcealed(lnum, col)" function
12050 */
12051 static void
12052f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12053{
12054#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12055 linenr_T lnum;
12056 colnr_T col;
12057 int syntax_flags = 0;
12058 int cchar;
12059 int matchid = 0;
12060 char_u str[NUMBUFLEN];
12061#endif
12062
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012063 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012064
12065#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12066 lnum = get_tv_lnum(argvars); /* -1 on type error */
12067 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12068
12069 vim_memset(str, NUL, sizeof(str));
12070
12071 if (rettv_list_alloc(rettv) != FAIL)
12072 {
12073 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12074 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12075 && curwin->w_p_cole > 0)
12076 {
12077 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12078 syntax_flags = get_syntax_info(&matchid);
12079
12080 /* get the conceal character */
12081 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12082 {
12083 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012084 if (cchar == NUL && curwin->w_p_cole == 1)
12085 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012086 if (cchar != NUL)
12087 {
12088# ifdef FEAT_MBYTE
12089 if (has_mbyte)
12090 (*mb_char2bytes)(cchar, str);
12091 else
12092# endif
12093 str[0] = cchar;
12094 }
12095 }
12096 }
12097
12098 list_append_number(rettv->vval.v_list,
12099 (syntax_flags & HL_CONCEAL) != 0);
12100 /* -1 to auto-determine strlen */
12101 list_append_string(rettv->vval.v_list, str, -1);
12102 list_append_number(rettv->vval.v_list, matchid);
12103 }
12104#endif
12105}
12106
12107/*
12108 * "synstack(lnum, col)" function
12109 */
12110 static void
12111f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12112{
12113#ifdef FEAT_SYN_HL
12114 linenr_T lnum;
12115 colnr_T col;
12116 int i;
12117 int id;
12118#endif
12119
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012120 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012121
12122#ifdef FEAT_SYN_HL
12123 lnum = get_tv_lnum(argvars); /* -1 on type error */
12124 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12125
12126 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12127 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12128 && rettv_list_alloc(rettv) != FAIL)
12129 {
12130 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12131 for (i = 0; ; ++i)
12132 {
12133 id = syn_get_stack_item(i);
12134 if (id < 0)
12135 break;
12136 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12137 break;
12138 }
12139 }
12140#endif
12141}
12142
12143 static void
12144get_cmd_output_as_rettv(
12145 typval_T *argvars,
12146 typval_T *rettv,
12147 int retlist)
12148{
12149 char_u *res = NULL;
12150 char_u *p;
12151 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012152 int err = FALSE;
12153 FILE *fd;
12154 list_T *list = NULL;
12155 int flags = SHELL_SILENT;
12156
12157 rettv->v_type = VAR_STRING;
12158 rettv->vval.v_string = NULL;
12159 if (check_restricted() || check_secure())
12160 goto errret;
12161
12162 if (argvars[1].v_type != VAR_UNKNOWN)
12163 {
12164 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012165 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012166 * command.
12167 */
12168 if ((infile = vim_tempname('i', TRUE)) == NULL)
12169 {
12170 EMSG(_(e_notmp));
12171 goto errret;
12172 }
12173
12174 fd = mch_fopen((char *)infile, WRITEBIN);
12175 if (fd == NULL)
12176 {
12177 EMSG2(_(e_notopen), infile);
12178 goto errret;
12179 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012180 if (argvars[1].v_type == VAR_NUMBER)
12181 {
12182 linenr_T lnum;
12183 buf_T *buf;
12184
12185 buf = buflist_findnr(argvars[1].vval.v_number);
12186 if (buf == NULL)
12187 {
12188 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012189 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012190 goto errret;
12191 }
12192
12193 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12194 {
12195 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12196 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12197 {
12198 err = TRUE;
12199 break;
12200 }
12201 if (putc(NL, fd) == EOF)
12202 {
12203 err = TRUE;
12204 break;
12205 }
12206 }
12207 }
12208 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012209 {
12210 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12211 err = TRUE;
12212 }
12213 else
12214 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012215 size_t len;
12216 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012217
12218 p = get_tv_string_buf_chk(&argvars[1], buf);
12219 if (p == NULL)
12220 {
12221 fclose(fd);
12222 goto errret; /* type error; errmsg already given */
12223 }
12224 len = STRLEN(p);
12225 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12226 err = TRUE;
12227 }
12228 if (fclose(fd) != 0)
12229 err = TRUE;
12230 if (err)
12231 {
12232 EMSG(_("E677: Error writing temp file"));
12233 goto errret;
12234 }
12235 }
12236
12237 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12238 * echoes typeahead, that messes up the display. */
12239 if (!msg_silent)
12240 flags += SHELL_COOKED;
12241
12242 if (retlist)
12243 {
12244 int len;
12245 listitem_T *li;
12246 char_u *s = NULL;
12247 char_u *start;
12248 char_u *end;
12249 int i;
12250
12251 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12252 if (res == NULL)
12253 goto errret;
12254
12255 list = list_alloc();
12256 if (list == NULL)
12257 goto errret;
12258
12259 for (i = 0; i < len; ++i)
12260 {
12261 start = res + i;
12262 while (i < len && res[i] != NL)
12263 ++i;
12264 end = res + i;
12265
12266 s = alloc((unsigned)(end - start + 1));
12267 if (s == NULL)
12268 goto errret;
12269
12270 for (p = s; start < end; ++p, ++start)
12271 *p = *start == NUL ? NL : *start;
12272 *p = NUL;
12273
12274 li = listitem_alloc();
12275 if (li == NULL)
12276 {
12277 vim_free(s);
12278 goto errret;
12279 }
12280 li->li_tv.v_type = VAR_STRING;
12281 li->li_tv.v_lock = 0;
12282 li->li_tv.vval.v_string = s;
12283 list_append(list, li);
12284 }
12285
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012286 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012287 list = NULL;
12288 }
12289 else
12290 {
12291 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12292#ifdef USE_CR
12293 /* translate <CR> into <NL> */
12294 if (res != NULL)
12295 {
12296 char_u *s;
12297
12298 for (s = res; *s; ++s)
12299 {
12300 if (*s == CAR)
12301 *s = NL;
12302 }
12303 }
12304#else
12305# ifdef USE_CRNL
12306 /* translate <CR><NL> into <NL> */
12307 if (res != NULL)
12308 {
12309 char_u *s, *d;
12310
12311 d = res;
12312 for (s = res; *s; ++s)
12313 {
12314 if (s[0] == CAR && s[1] == NL)
12315 ++s;
12316 *d++ = *s;
12317 }
12318 *d = NUL;
12319 }
12320# endif
12321#endif
12322 rettv->vval.v_string = res;
12323 res = NULL;
12324 }
12325
12326errret:
12327 if (infile != NULL)
12328 {
12329 mch_remove(infile);
12330 vim_free(infile);
12331 }
12332 if (res != NULL)
12333 vim_free(res);
12334 if (list != NULL)
12335 list_free(list);
12336}
12337
12338/*
12339 * "system()" function
12340 */
12341 static void
12342f_system(typval_T *argvars, typval_T *rettv)
12343{
12344 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12345}
12346
12347/*
12348 * "systemlist()" function
12349 */
12350 static void
12351f_systemlist(typval_T *argvars, typval_T *rettv)
12352{
12353 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12354}
12355
12356/*
12357 * "tabpagebuflist()" function
12358 */
12359 static void
12360f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12361{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012362 tabpage_T *tp;
12363 win_T *wp = NULL;
12364
12365 if (argvars[0].v_type == VAR_UNKNOWN)
12366 wp = firstwin;
12367 else
12368 {
12369 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12370 if (tp != NULL)
12371 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12372 }
12373 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12374 {
12375 for (; wp != NULL; wp = wp->w_next)
12376 if (list_append_number(rettv->vval.v_list,
12377 wp->w_buffer->b_fnum) == FAIL)
12378 break;
12379 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012380}
12381
12382
12383/*
12384 * "tabpagenr()" function
12385 */
12386 static void
12387f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12388{
12389 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012390 char_u *arg;
12391
12392 if (argvars[0].v_type != VAR_UNKNOWN)
12393 {
12394 arg = get_tv_string_chk(&argvars[0]);
12395 nr = 0;
12396 if (arg != NULL)
12397 {
12398 if (STRCMP(arg, "$") == 0)
12399 nr = tabpage_index(NULL) - 1;
12400 else
12401 EMSG2(_(e_invexpr2), arg);
12402 }
12403 }
12404 else
12405 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012406 rettv->vval.v_number = nr;
12407}
12408
12409
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012410static int get_winnr(tabpage_T *tp, typval_T *argvar);
12411
12412/*
12413 * Common code for tabpagewinnr() and winnr().
12414 */
12415 static int
12416get_winnr(tabpage_T *tp, typval_T *argvar)
12417{
12418 win_T *twin;
12419 int nr = 1;
12420 win_T *wp;
12421 char_u *arg;
12422
12423 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12424 if (argvar->v_type != VAR_UNKNOWN)
12425 {
12426 arg = get_tv_string_chk(argvar);
12427 if (arg == NULL)
12428 nr = 0; /* type error; errmsg already given */
12429 else if (STRCMP(arg, "$") == 0)
12430 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12431 else if (STRCMP(arg, "#") == 0)
12432 {
12433 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12434 if (twin == NULL)
12435 nr = 0;
12436 }
12437 else
12438 {
12439 EMSG2(_(e_invexpr2), arg);
12440 nr = 0;
12441 }
12442 }
12443
12444 if (nr > 0)
12445 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12446 wp != twin; wp = wp->w_next)
12447 {
12448 if (wp == NULL)
12449 {
12450 /* didn't find it in this tabpage */
12451 nr = 0;
12452 break;
12453 }
12454 ++nr;
12455 }
12456 return nr;
12457}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012458
12459/*
12460 * "tabpagewinnr()" function
12461 */
12462 static void
12463f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12464{
12465 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012466 tabpage_T *tp;
12467
12468 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12469 if (tp == NULL)
12470 nr = 0;
12471 else
12472 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012473 rettv->vval.v_number = nr;
12474}
12475
12476
12477/*
12478 * "tagfiles()" function
12479 */
12480 static void
12481f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12482{
12483 char_u *fname;
12484 tagname_T tn;
12485 int first;
12486
12487 if (rettv_list_alloc(rettv) == FAIL)
12488 return;
12489 fname = alloc(MAXPATHL);
12490 if (fname == NULL)
12491 return;
12492
12493 for (first = TRUE; ; first = FALSE)
12494 if (get_tagfname(&tn, first, fname) == FAIL
12495 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12496 break;
12497 tagname_free(&tn);
12498 vim_free(fname);
12499}
12500
12501/*
12502 * "taglist()" function
12503 */
12504 static void
12505f_taglist(typval_T *argvars, typval_T *rettv)
12506{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012507 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012508 char_u *tag_pattern;
12509
12510 tag_pattern = get_tv_string(&argvars[0]);
12511
12512 rettv->vval.v_number = FALSE;
12513 if (*tag_pattern == NUL)
12514 return;
12515
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012516 if (argvars[1].v_type != VAR_UNKNOWN)
12517 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012518 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012519 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012520}
12521
12522/*
12523 * "tempname()" function
12524 */
12525 static void
12526f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12527{
12528 static int x = 'A';
12529
12530 rettv->v_type = VAR_STRING;
12531 rettv->vval.v_string = vim_tempname(x, FALSE);
12532
12533 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12534 * names. Skip 'I' and 'O', they are used for shell redirection. */
12535 do
12536 {
12537 if (x == 'Z')
12538 x = '0';
12539 else if (x == '9')
12540 x = 'A';
12541 else
12542 {
12543#ifdef EBCDIC
12544 if (x == 'I')
12545 x = 'J';
12546 else if (x == 'R')
12547 x = 'S';
12548 else
12549#endif
12550 ++x;
12551 }
12552 } while (x == 'I' || x == 'O');
12553}
12554
12555#ifdef FEAT_FLOAT
12556/*
12557 * "tan()" function
12558 */
12559 static void
12560f_tan(typval_T *argvars, typval_T *rettv)
12561{
12562 float_T f = 0.0;
12563
12564 rettv->v_type = VAR_FLOAT;
12565 if (get_float_arg(argvars, &f) == OK)
12566 rettv->vval.v_float = tan(f);
12567 else
12568 rettv->vval.v_float = 0.0;
12569}
12570
12571/*
12572 * "tanh()" function
12573 */
12574 static void
12575f_tanh(typval_T *argvars, typval_T *rettv)
12576{
12577 float_T f = 0.0;
12578
12579 rettv->v_type = VAR_FLOAT;
12580 if (get_float_arg(argvars, &f) == OK)
12581 rettv->vval.v_float = tanh(f);
12582 else
12583 rettv->vval.v_float = 0.0;
12584}
12585#endif
12586
12587/*
12588 * "test_alloc_fail(id, countdown, repeat)" function
12589 */
12590 static void
12591f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12592{
12593 if (argvars[0].v_type != VAR_NUMBER
12594 || argvars[0].vval.v_number <= 0
12595 || argvars[1].v_type != VAR_NUMBER
12596 || argvars[1].vval.v_number < 0
12597 || argvars[2].v_type != VAR_NUMBER)
12598 EMSG(_(e_invarg));
12599 else
12600 {
12601 alloc_fail_id = argvars[0].vval.v_number;
12602 if (alloc_fail_id >= aid_last)
12603 EMSG(_(e_invarg));
12604 alloc_fail_countdown = argvars[1].vval.v_number;
12605 alloc_fail_repeat = argvars[2].vval.v_number;
12606 did_outofmem_msg = FALSE;
12607 }
12608}
12609
12610/*
12611 * "test_autochdir()"
12612 */
12613 static void
12614f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12615{
12616#if defined(FEAT_AUTOCHDIR)
12617 test_autochdir = TRUE;
12618#endif
12619}
12620
12621/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012622 * "test_feedinput()"
12623 */
12624 static void
12625f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12626{
12627#ifdef USE_INPUT_BUF
12628 char_u *val = get_tv_string_chk(&argvars[0]);
12629
12630 if (val != NULL)
12631 {
12632 trash_input_buf();
12633 add_to_input_buf_csi(val, (int)STRLEN(val));
12634 }
12635#endif
12636}
12637
12638/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012639 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012640 */
12641 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012642f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012643{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012644 char_u *name = (char_u *)"";
12645 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012646 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012647
12648 if (argvars[0].v_type != VAR_STRING
12649 || (argvars[1].v_type) != VAR_NUMBER)
12650 EMSG(_(e_invarg));
12651 else
12652 {
12653 name = get_tv_string_chk(&argvars[0]);
12654 val = (int)get_tv_number(&argvars[1]);
12655
12656 if (STRCMP(name, (char_u *)"redraw") == 0)
12657 disable_redraw_for_testing = val;
12658 else if (STRCMP(name, (char_u *)"char_avail") == 0)
12659 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012660 else if (STRCMP(name, (char_u *)"starting") == 0)
12661 {
12662 if (val)
12663 {
12664 if (save_starting < 0)
12665 save_starting = starting;
12666 starting = 0;
12667 }
12668 else
12669 {
12670 starting = save_starting;
12671 save_starting = -1;
12672 }
12673 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012674 else if (STRCMP(name, (char_u *)"ALL") == 0)
12675 {
12676 disable_char_avail_for_testing = FALSE;
12677 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012678 if (save_starting >= 0)
12679 {
12680 starting = save_starting;
12681 save_starting = -1;
12682 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012683 }
12684 else
12685 EMSG2(_(e_invarg2), name);
12686 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012687}
12688
12689/*
12690 * "test_garbagecollect_now()" function
12691 */
12692 static void
12693f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12694{
12695 /* This is dangerous, any Lists and Dicts used internally may be freed
12696 * while still in use. */
12697 garbage_collect(TRUE);
12698}
12699
Bram Moolenaare0c31f62017-03-01 15:07:05 +010012700/*
12701 * "test_ignore_error()" function
12702 */
12703 static void
12704f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12705{
12706 ignore_error_for_testing(get_tv_string(&argvars[0]));
12707}
12708
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012709#ifdef FEAT_JOB_CHANNEL
12710 static void
12711f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12712{
12713 rettv->v_type = VAR_CHANNEL;
12714 rettv->vval.v_channel = NULL;
12715}
12716#endif
12717
12718 static void
12719f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12720{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012721 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012722}
12723
12724#ifdef FEAT_JOB_CHANNEL
12725 static void
12726f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12727{
12728 rettv->v_type = VAR_JOB;
12729 rettv->vval.v_job = NULL;
12730}
12731#endif
12732
12733 static void
12734f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12735{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012736 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012737}
12738
12739 static void
12740f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12741{
12742 rettv->v_type = VAR_PARTIAL;
12743 rettv->vval.v_partial = NULL;
12744}
12745
12746 static void
12747f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12748{
12749 rettv->v_type = VAR_STRING;
12750 rettv->vval.v_string = NULL;
12751}
12752
12753 static void
12754f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12755{
12756 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12757}
12758
12759#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12760/*
12761 * Get a callback from "arg". It can be a Funcref or a function name.
12762 * When "arg" is zero return an empty string.
12763 * Return NULL for an invalid argument.
12764 */
12765 char_u *
12766get_callback(typval_T *arg, partial_T **pp)
12767{
12768 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12769 {
12770 *pp = arg->vval.v_partial;
12771 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012772 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012773 }
12774 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012775 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012776 {
12777 func_ref(arg->vval.v_string);
12778 return arg->vval.v_string;
12779 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012780 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12781 return (char_u *)"";
12782 EMSG(_("E921: Invalid callback argument"));
12783 return NULL;
12784}
12785
12786/*
12787 * Unref/free "callback" and "partial" retured by get_callback().
12788 */
12789 void
12790free_callback(char_u *callback, partial_T *partial)
12791{
12792 if (partial != NULL)
12793 partial_unref(partial);
12794 else if (callback != NULL)
12795 {
12796 func_unref(callback);
12797 vim_free(callback);
12798 }
12799}
12800#endif
12801
12802#ifdef FEAT_TIMERS
12803/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012804 * "timer_info([timer])" function
12805 */
12806 static void
12807f_timer_info(typval_T *argvars, typval_T *rettv)
12808{
12809 timer_T *timer = NULL;
12810
12811 if (rettv_list_alloc(rettv) != OK)
12812 return;
12813 if (argvars[0].v_type != VAR_UNKNOWN)
12814 {
12815 if (argvars[0].v_type != VAR_NUMBER)
12816 EMSG(_(e_number_exp));
12817 else
12818 {
12819 timer = find_timer((int)get_tv_number(&argvars[0]));
12820 if (timer != NULL)
12821 add_timer_info(rettv, timer);
12822 }
12823 }
12824 else
12825 add_timer_info_all(rettv);
12826}
12827
12828/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012829 * "timer_pause(timer, paused)" function
12830 */
12831 static void
12832f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12833{
12834 timer_T *timer = NULL;
12835 int paused = (int)get_tv_number(&argvars[1]);
12836
12837 if (argvars[0].v_type != VAR_NUMBER)
12838 EMSG(_(e_number_exp));
12839 else
12840 {
12841 timer = find_timer((int)get_tv_number(&argvars[0]));
12842 if (timer != NULL)
12843 timer->tr_paused = paused;
12844 }
12845}
12846
12847/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012848 * "timer_start(time, callback [, options])" function
12849 */
12850 static void
12851f_timer_start(typval_T *argvars, typval_T *rettv)
12852{
Bram Moolenaar75537a92016-09-05 22:45:28 +020012853 long msec = (long)get_tv_number(&argvars[0]);
12854 timer_T *timer;
12855 int repeat = 0;
12856 char_u *callback;
12857 dict_T *dict;
12858 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012859
Bram Moolenaar75537a92016-09-05 22:45:28 +020012860 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012861 if (check_secure())
12862 return;
12863 if (argvars[2].v_type != VAR_UNKNOWN)
12864 {
12865 if (argvars[2].v_type != VAR_DICT
12866 || (dict = argvars[2].vval.v_dict) == NULL)
12867 {
12868 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12869 return;
12870 }
12871 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12872 repeat = get_dict_number(dict, (char_u *)"repeat");
12873 }
12874
Bram Moolenaar75537a92016-09-05 22:45:28 +020012875 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012876 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012877 return;
12878
12879 timer = create_timer(msec, repeat);
12880 if (timer == NULL)
12881 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012882 else
12883 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020012884 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020012885 timer->tr_callback = vim_strsave(callback);
12886 else
12887 /* pointer into the partial */
12888 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012889 timer->tr_partial = partial;
12890 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012891 }
12892}
12893
12894/*
12895 * "timer_stop(timer)" function
12896 */
12897 static void
12898f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12899{
12900 timer_T *timer;
12901
12902 if (argvars[0].v_type != VAR_NUMBER)
12903 {
12904 EMSG(_(e_number_exp));
12905 return;
12906 }
12907 timer = find_timer((int)get_tv_number(&argvars[0]));
12908 if (timer != NULL)
12909 stop_timer(timer);
12910}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012911
12912/*
12913 * "timer_stopall()" function
12914 */
12915 static void
12916f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12917{
12918 stop_all_timers();
12919}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012920#endif
12921
12922/*
12923 * "tolower(string)" function
12924 */
12925 static void
12926f_tolower(typval_T *argvars, typval_T *rettv)
12927{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012928 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010012929 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012930}
12931
12932/*
12933 * "toupper(string)" function
12934 */
12935 static void
12936f_toupper(typval_T *argvars, typval_T *rettv)
12937{
12938 rettv->v_type = VAR_STRING;
12939 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12940}
12941
12942/*
12943 * "tr(string, fromstr, tostr)" function
12944 */
12945 static void
12946f_tr(typval_T *argvars, typval_T *rettv)
12947{
12948 char_u *in_str;
12949 char_u *fromstr;
12950 char_u *tostr;
12951 char_u *p;
12952#ifdef FEAT_MBYTE
12953 int inlen;
12954 int fromlen;
12955 int tolen;
12956 int idx;
12957 char_u *cpstr;
12958 int cplen;
12959 int first = TRUE;
12960#endif
12961 char_u buf[NUMBUFLEN];
12962 char_u buf2[NUMBUFLEN];
12963 garray_T ga;
12964
12965 in_str = get_tv_string(&argvars[0]);
12966 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12967 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12968
12969 /* Default return value: empty string. */
12970 rettv->v_type = VAR_STRING;
12971 rettv->vval.v_string = NULL;
12972 if (fromstr == NULL || tostr == NULL)
12973 return; /* type error; errmsg already given */
12974 ga_init2(&ga, (int)sizeof(char), 80);
12975
12976#ifdef FEAT_MBYTE
12977 if (!has_mbyte)
12978#endif
12979 /* not multi-byte: fromstr and tostr must be the same length */
12980 if (STRLEN(fromstr) != STRLEN(tostr))
12981 {
12982#ifdef FEAT_MBYTE
12983error:
12984#endif
12985 EMSG2(_(e_invarg2), fromstr);
12986 ga_clear(&ga);
12987 return;
12988 }
12989
12990 /* fromstr and tostr have to contain the same number of chars */
12991 while (*in_str != NUL)
12992 {
12993#ifdef FEAT_MBYTE
12994 if (has_mbyte)
12995 {
12996 inlen = (*mb_ptr2len)(in_str);
12997 cpstr = in_str;
12998 cplen = inlen;
12999 idx = 0;
13000 for (p = fromstr; *p != NUL; p += fromlen)
13001 {
13002 fromlen = (*mb_ptr2len)(p);
13003 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13004 {
13005 for (p = tostr; *p != NUL; p += tolen)
13006 {
13007 tolen = (*mb_ptr2len)(p);
13008 if (idx-- == 0)
13009 {
13010 cplen = tolen;
13011 cpstr = p;
13012 break;
13013 }
13014 }
13015 if (*p == NUL) /* tostr is shorter than fromstr */
13016 goto error;
13017 break;
13018 }
13019 ++idx;
13020 }
13021
13022 if (first && cpstr == in_str)
13023 {
13024 /* Check that fromstr and tostr have the same number of
13025 * (multi-byte) characters. Done only once when a character
13026 * of in_str doesn't appear in fromstr. */
13027 first = FALSE;
13028 for (p = tostr; *p != NUL; p += tolen)
13029 {
13030 tolen = (*mb_ptr2len)(p);
13031 --idx;
13032 }
13033 if (idx != 0)
13034 goto error;
13035 }
13036
13037 (void)ga_grow(&ga, cplen);
13038 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13039 ga.ga_len += cplen;
13040
13041 in_str += inlen;
13042 }
13043 else
13044#endif
13045 {
13046 /* When not using multi-byte chars we can do it faster. */
13047 p = vim_strchr(fromstr, *in_str);
13048 if (p != NULL)
13049 ga_append(&ga, tostr[p - fromstr]);
13050 else
13051 ga_append(&ga, *in_str);
13052 ++in_str;
13053 }
13054 }
13055
13056 /* add a terminating NUL */
13057 (void)ga_grow(&ga, 1);
13058 ga_append(&ga, NUL);
13059
13060 rettv->vval.v_string = ga.ga_data;
13061}
13062
13063#ifdef FEAT_FLOAT
13064/*
13065 * "trunc({float})" function
13066 */
13067 static void
13068f_trunc(typval_T *argvars, typval_T *rettv)
13069{
13070 float_T f = 0.0;
13071
13072 rettv->v_type = VAR_FLOAT;
13073 if (get_float_arg(argvars, &f) == OK)
13074 /* trunc() is not in C90, use floor() or ceil() instead. */
13075 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13076 else
13077 rettv->vval.v_float = 0.0;
13078}
13079#endif
13080
13081/*
13082 * "type(expr)" function
13083 */
13084 static void
13085f_type(typval_T *argvars, typval_T *rettv)
13086{
13087 int n = -1;
13088
13089 switch (argvars[0].v_type)
13090 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013091 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13092 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013093 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013094 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13095 case VAR_LIST: n = VAR_TYPE_LIST; break;
13096 case VAR_DICT: n = VAR_TYPE_DICT; break;
13097 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013098 case VAR_SPECIAL:
13099 if (argvars[0].vval.v_number == VVAL_FALSE
13100 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013101 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013102 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013103 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013104 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013105 case VAR_JOB: n = VAR_TYPE_JOB; break;
13106 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013107 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013108 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013109 n = -1;
13110 break;
13111 }
13112 rettv->vval.v_number = n;
13113}
13114
13115/*
13116 * "undofile(name)" function
13117 */
13118 static void
13119f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13120{
13121 rettv->v_type = VAR_STRING;
13122#ifdef FEAT_PERSISTENT_UNDO
13123 {
13124 char_u *fname = get_tv_string(&argvars[0]);
13125
13126 if (*fname == NUL)
13127 {
13128 /* If there is no file name there will be no undo file. */
13129 rettv->vval.v_string = NULL;
13130 }
13131 else
13132 {
13133 char_u *ffname = FullName_save(fname, FALSE);
13134
13135 if (ffname != NULL)
13136 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13137 vim_free(ffname);
13138 }
13139 }
13140#else
13141 rettv->vval.v_string = NULL;
13142#endif
13143}
13144
13145/*
13146 * "undotree()" function
13147 */
13148 static void
13149f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13150{
13151 if (rettv_dict_alloc(rettv) == OK)
13152 {
13153 dict_T *dict = rettv->vval.v_dict;
13154 list_T *list;
13155
13156 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13157 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13158 dict_add_nr_str(dict, "save_last",
13159 (long)curbuf->b_u_save_nr_last, NULL);
13160 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13161 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13162 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13163
13164 list = list_alloc();
13165 if (list != NULL)
13166 {
13167 u_eval_tree(curbuf->b_u_oldhead, list);
13168 dict_add_list(dict, "entries", list);
13169 }
13170 }
13171}
13172
13173/*
13174 * "values(dict)" function
13175 */
13176 static void
13177f_values(typval_T *argvars, typval_T *rettv)
13178{
13179 dict_list(argvars, rettv, 1);
13180}
13181
13182/*
13183 * "virtcol(string)" function
13184 */
13185 static void
13186f_virtcol(typval_T *argvars, typval_T *rettv)
13187{
13188 colnr_T vcol = 0;
13189 pos_T *fp;
13190 int fnum = curbuf->b_fnum;
13191
13192 fp = var2fpos(&argvars[0], FALSE, &fnum);
13193 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13194 && fnum == curbuf->b_fnum)
13195 {
13196 getvvcol(curwin, fp, NULL, NULL, &vcol);
13197 ++vcol;
13198 }
13199
13200 rettv->vval.v_number = vcol;
13201}
13202
13203/*
13204 * "visualmode()" function
13205 */
13206 static void
13207f_visualmode(typval_T *argvars, typval_T *rettv)
13208{
13209 char_u str[2];
13210
13211 rettv->v_type = VAR_STRING;
13212 str[0] = curbuf->b_visual_mode_eval;
13213 str[1] = NUL;
13214 rettv->vval.v_string = vim_strsave(str);
13215
13216 /* A non-zero number or non-empty string argument: reset mode. */
13217 if (non_zero_arg(&argvars[0]))
13218 curbuf->b_visual_mode_eval = NUL;
13219}
13220
13221/*
13222 * "wildmenumode()" function
13223 */
13224 static void
13225f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13226{
13227#ifdef FEAT_WILDMENU
13228 if (wild_menu_showing)
13229 rettv->vval.v_number = 1;
13230#endif
13231}
13232
13233/*
13234 * "winbufnr(nr)" function
13235 */
13236 static void
13237f_winbufnr(typval_T *argvars, typval_T *rettv)
13238{
13239 win_T *wp;
13240
13241 wp = find_win_by_nr(&argvars[0], NULL);
13242 if (wp == NULL)
13243 rettv->vval.v_number = -1;
13244 else
13245 rettv->vval.v_number = wp->w_buffer->b_fnum;
13246}
13247
13248/*
13249 * "wincol()" function
13250 */
13251 static void
13252f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13253{
13254 validate_cursor();
13255 rettv->vval.v_number = curwin->w_wcol + 1;
13256}
13257
13258/*
13259 * "winheight(nr)" function
13260 */
13261 static void
13262f_winheight(typval_T *argvars, typval_T *rettv)
13263{
13264 win_T *wp;
13265
13266 wp = find_win_by_nr(&argvars[0], NULL);
13267 if (wp == NULL)
13268 rettv->vval.v_number = -1;
13269 else
13270 rettv->vval.v_number = wp->w_height;
13271}
13272
13273/*
13274 * "winline()" function
13275 */
13276 static void
13277f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13278{
13279 validate_cursor();
13280 rettv->vval.v_number = curwin->w_wrow + 1;
13281}
13282
13283/*
13284 * "winnr()" function
13285 */
13286 static void
13287f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13288{
13289 int nr = 1;
13290
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013291 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013292 rettv->vval.v_number = nr;
13293}
13294
13295/*
13296 * "winrestcmd()" function
13297 */
13298 static void
13299f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13300{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013301 win_T *wp;
13302 int winnr = 1;
13303 garray_T ga;
13304 char_u buf[50];
13305
13306 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013307 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013308 {
13309 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13310 ga_concat(&ga, buf);
13311 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13312 ga_concat(&ga, buf);
13313 ++winnr;
13314 }
13315 ga_append(&ga, NUL);
13316
13317 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013318 rettv->v_type = VAR_STRING;
13319}
13320
13321/*
13322 * "winrestview()" function
13323 */
13324 static void
13325f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13326{
13327 dict_T *dict;
13328
13329 if (argvars[0].v_type != VAR_DICT
13330 || (dict = argvars[0].vval.v_dict) == NULL)
13331 EMSG(_(e_invarg));
13332 else
13333 {
13334 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13335 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13336 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13337 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13338#ifdef FEAT_VIRTUALEDIT
13339 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13340 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13341#endif
13342 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13343 {
13344 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13345 curwin->w_set_curswant = FALSE;
13346 }
13347
13348 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13349 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13350#ifdef FEAT_DIFF
13351 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13352 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13353#endif
13354 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13355 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13356 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13357 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13358
13359 check_cursor();
13360 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013361 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013362 changed_window_setting();
13363
13364 if (curwin->w_topline <= 0)
13365 curwin->w_topline = 1;
13366 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13367 curwin->w_topline = curbuf->b_ml.ml_line_count;
13368#ifdef FEAT_DIFF
13369 check_topfill(curwin, TRUE);
13370#endif
13371 }
13372}
13373
13374/*
13375 * "winsaveview()" function
13376 */
13377 static void
13378f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13379{
13380 dict_T *dict;
13381
13382 if (rettv_dict_alloc(rettv) == FAIL)
13383 return;
13384 dict = rettv->vval.v_dict;
13385
13386 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13387 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13388#ifdef FEAT_VIRTUALEDIT
13389 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13390#endif
13391 update_curswant();
13392 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13393
13394 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13395#ifdef FEAT_DIFF
13396 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13397#endif
13398 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13399 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13400}
13401
13402/*
13403 * "winwidth(nr)" function
13404 */
13405 static void
13406f_winwidth(typval_T *argvars, typval_T *rettv)
13407{
13408 win_T *wp;
13409
13410 wp = find_win_by_nr(&argvars[0], NULL);
13411 if (wp == NULL)
13412 rettv->vval.v_number = -1;
13413 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013414 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013415}
13416
13417/*
13418 * "wordcount()" function
13419 */
13420 static void
13421f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13422{
13423 if (rettv_dict_alloc(rettv) == FAIL)
13424 return;
13425 cursor_pos_info(rettv->vval.v_dict);
13426}
13427
13428/*
13429 * "writefile()" function
13430 */
13431 static void
13432f_writefile(typval_T *argvars, typval_T *rettv)
13433{
13434 int binary = FALSE;
13435 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013436#ifdef HAVE_FSYNC
13437 int do_fsync = p_fs;
13438#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013439 char_u *fname;
13440 FILE *fd;
13441 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013442 listitem_T *li;
13443 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013444
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013445 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013446 if (check_restricted() || check_secure())
13447 return;
13448
13449 if (argvars[0].v_type != VAR_LIST)
13450 {
13451 EMSG2(_(e_listarg), "writefile()");
13452 return;
13453 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013454 list = argvars[0].vval.v_list;
13455 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013456 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013457 for (li = list->lv_first; li != NULL; li = li->li_next)
13458 if (get_tv_string_chk(&li->li_tv) == NULL)
13459 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013460
13461 if (argvars[2].v_type != VAR_UNKNOWN)
13462 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013463 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13464
13465 if (arg2 == NULL)
13466 return;
13467 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013468 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013469 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013470 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013471#ifdef HAVE_FSYNC
13472 if (vim_strchr(arg2, 's') != NULL)
13473 do_fsync = TRUE;
13474 else if (vim_strchr(arg2, 'S') != NULL)
13475 do_fsync = FALSE;
13476#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013477 }
13478
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013479 fname = get_tv_string_chk(&argvars[1]);
13480 if (fname == NULL)
13481 return;
13482
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013483 /* Always open the file in binary mode, library functions have a mind of
13484 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013485 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13486 append ? APPENDBIN : WRITEBIN)) == NULL)
13487 {
13488 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13489 ret = -1;
13490 }
13491 else
13492 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013493 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013494 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013495#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013496 else if (do_fsync)
13497 /* Ignore the error, the user wouldn't know what to do about it.
13498 * May happen for a device. */
13499 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013500#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013501 fclose(fd);
13502 }
13503
13504 rettv->vval.v_number = ret;
13505}
13506
13507/*
13508 * "xor(expr, expr)" function
13509 */
13510 static void
13511f_xor(typval_T *argvars, typval_T *rettv)
13512{
13513 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13514 ^ get_tv_number_chk(&argvars[1], NULL);
13515}
13516
13517
13518#endif /* FEAT_EVAL */