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