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