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