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