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