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