blob: 768a0f1574405ab8b987eba4cbf727460c8175a5 [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
6862static void libcall_common(typval_T *argvars, typval_T *rettv, int type);
6863
6864 static void
6865libcall_common(typval_T *argvars, typval_T *rettv, int type)
6866{
6867#ifdef FEAT_LIBCALL
6868 char_u *string_in;
6869 char_u **string_result;
6870 int nr_result;
6871#endif
6872
6873 rettv->v_type = type;
6874 if (type != VAR_NUMBER)
6875 rettv->vval.v_string = NULL;
6876
6877 if (check_restricted() || check_secure())
6878 return;
6879
6880#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006881 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6883 {
6884 string_in = NULL;
6885 if (argvars[2].v_type == VAR_STRING)
6886 string_in = argvars[2].vval.v_string;
6887 if (type == VAR_NUMBER)
6888 string_result = NULL;
6889 else
6890 string_result = &rettv->vval.v_string;
6891 if (mch_libcall(argvars[0].vval.v_string,
6892 argvars[1].vval.v_string,
6893 string_in,
6894 argvars[2].vval.v_number,
6895 string_result,
6896 &nr_result) == OK
6897 && type == VAR_NUMBER)
6898 rettv->vval.v_number = nr_result;
6899 }
6900#endif
6901}
6902
6903/*
6904 * "libcall()" function
6905 */
6906 static void
6907f_libcall(typval_T *argvars, typval_T *rettv)
6908{
6909 libcall_common(argvars, rettv, VAR_STRING);
6910}
6911
6912/*
6913 * "libcallnr()" function
6914 */
6915 static void
6916f_libcallnr(typval_T *argvars, typval_T *rettv)
6917{
6918 libcall_common(argvars, rettv, VAR_NUMBER);
6919}
6920
6921/*
6922 * "line(string)" function
6923 */
6924 static void
6925f_line(typval_T *argvars, typval_T *rettv)
6926{
6927 linenr_T lnum = 0;
6928 pos_T *fp;
6929 int fnum;
6930
6931 fp = var2fpos(&argvars[0], TRUE, &fnum);
6932 if (fp != NULL)
6933 lnum = fp->lnum;
6934 rettv->vval.v_number = lnum;
6935}
6936
6937/*
6938 * "line2byte(lnum)" function
6939 */
6940 static void
6941f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6942{
6943#ifndef FEAT_BYTEOFF
6944 rettv->vval.v_number = -1;
6945#else
6946 linenr_T lnum;
6947
6948 lnum = get_tv_lnum(argvars);
6949 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6950 rettv->vval.v_number = -1;
6951 else
6952 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6953 if (rettv->vval.v_number >= 0)
6954 ++rettv->vval.v_number;
6955#endif
6956}
6957
6958/*
6959 * "lispindent(lnum)" function
6960 */
6961 static void
6962f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
6963{
6964#ifdef FEAT_LISP
6965 pos_T pos;
6966 linenr_T lnum;
6967
6968 pos = curwin->w_cursor;
6969 lnum = get_tv_lnum(argvars);
6970 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6971 {
6972 curwin->w_cursor.lnum = lnum;
6973 rettv->vval.v_number = get_lisp_indent();
6974 curwin->w_cursor = pos;
6975 }
6976 else
6977#endif
6978 rettv->vval.v_number = -1;
6979}
6980
6981/*
6982 * "localtime()" function
6983 */
6984 static void
6985f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
6986{
6987 rettv->vval.v_number = (varnumber_T)time(NULL);
6988}
6989
6990static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
6991
6992 static void
6993get_maparg(typval_T *argvars, typval_T *rettv, int exact)
6994{
6995 char_u *keys;
6996 char_u *which;
6997 char_u buf[NUMBUFLEN];
6998 char_u *keys_buf = NULL;
6999 char_u *rhs;
7000 int mode;
7001 int abbr = FALSE;
7002 int get_dict = FALSE;
7003 mapblock_T *mp;
7004 int buffer_local;
7005
7006 /* return empty string for failure */
7007 rettv->v_type = VAR_STRING;
7008 rettv->vval.v_string = NULL;
7009
7010 keys = get_tv_string(&argvars[0]);
7011 if (*keys == NUL)
7012 return;
7013
7014 if (argvars[1].v_type != VAR_UNKNOWN)
7015 {
7016 which = get_tv_string_buf_chk(&argvars[1], buf);
7017 if (argvars[2].v_type != VAR_UNKNOWN)
7018 {
7019 abbr = (int)get_tv_number(&argvars[2]);
7020 if (argvars[3].v_type != VAR_UNKNOWN)
7021 get_dict = (int)get_tv_number(&argvars[3]);
7022 }
7023 }
7024 else
7025 which = (char_u *)"";
7026 if (which == NULL)
7027 return;
7028
7029 mode = get_map_mode(&which, 0);
7030
7031 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7032 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7033 vim_free(keys_buf);
7034
7035 if (!get_dict)
7036 {
7037 /* Return a string. */
7038 if (rhs != NULL)
7039 rettv->vval.v_string = str2special_save(rhs, FALSE);
7040
7041 }
7042 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7043 {
7044 /* Return a dictionary. */
7045 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7046 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7047 dict_T *dict = rettv->vval.v_dict;
7048
7049 dict_add_nr_str(dict, "lhs", 0L, lhs);
7050 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7051 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7052 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7053 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7054 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7055 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7056 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7057 dict_add_nr_str(dict, "mode", 0L, mapmode);
7058
7059 vim_free(lhs);
7060 vim_free(mapmode);
7061 }
7062}
7063
7064#ifdef FEAT_FLOAT
7065/*
7066 * "log()" function
7067 */
7068 static void
7069f_log(typval_T *argvars, typval_T *rettv)
7070{
7071 float_T f = 0.0;
7072
7073 rettv->v_type = VAR_FLOAT;
7074 if (get_float_arg(argvars, &f) == OK)
7075 rettv->vval.v_float = log(f);
7076 else
7077 rettv->vval.v_float = 0.0;
7078}
7079
7080/*
7081 * "log10()" function
7082 */
7083 static void
7084f_log10(typval_T *argvars, typval_T *rettv)
7085{
7086 float_T f = 0.0;
7087
7088 rettv->v_type = VAR_FLOAT;
7089 if (get_float_arg(argvars, &f) == OK)
7090 rettv->vval.v_float = log10(f);
7091 else
7092 rettv->vval.v_float = 0.0;
7093}
7094#endif
7095
7096#ifdef FEAT_LUA
7097/*
7098 * "luaeval()" function
7099 */
7100 static void
7101f_luaeval(typval_T *argvars, typval_T *rettv)
7102{
7103 char_u *str;
7104 char_u buf[NUMBUFLEN];
7105
7106 str = get_tv_string_buf(&argvars[0], buf);
7107 do_luaeval(str, argvars + 1, rettv);
7108}
7109#endif
7110
7111/*
7112 * "map()" function
7113 */
7114 static void
7115f_map(typval_T *argvars, typval_T *rettv)
7116{
7117 filter_map(argvars, rettv, TRUE);
7118}
7119
7120/*
7121 * "maparg()" function
7122 */
7123 static void
7124f_maparg(typval_T *argvars, typval_T *rettv)
7125{
7126 get_maparg(argvars, rettv, TRUE);
7127}
7128
7129/*
7130 * "mapcheck()" function
7131 */
7132 static void
7133f_mapcheck(typval_T *argvars, typval_T *rettv)
7134{
7135 get_maparg(argvars, rettv, FALSE);
7136}
7137
7138static void find_some_match(typval_T *argvars, typval_T *rettv, int start);
7139
7140 static void
7141find_some_match(typval_T *argvars, typval_T *rettv, int type)
7142{
7143 char_u *str = NULL;
7144 long len = 0;
7145 char_u *expr = NULL;
7146 char_u *pat;
7147 regmatch_T regmatch;
7148 char_u patbuf[NUMBUFLEN];
7149 char_u strbuf[NUMBUFLEN];
7150 char_u *save_cpo;
7151 long start = 0;
7152 long nth = 1;
7153 colnr_T startcol = 0;
7154 int match = 0;
7155 list_T *l = NULL;
7156 listitem_T *li = NULL;
7157 long idx = 0;
7158 char_u *tofree = NULL;
7159
7160 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7161 save_cpo = p_cpo;
7162 p_cpo = (char_u *)"";
7163
7164 rettv->vval.v_number = -1;
7165 if (type == 3 || type == 4)
7166 {
7167 /* type 3: return empty list when there are no matches.
7168 * type 4: return ["", -1, -1, -1] */
7169 if (rettv_list_alloc(rettv) == FAIL)
7170 goto theend;
7171 if (type == 4
7172 && (list_append_string(rettv->vval.v_list,
7173 (char_u *)"", 0) == 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 || list_append_number(rettv->vval.v_list,
7179 (varnumber_T)-1) == FAIL))
7180 {
7181 list_free(rettv->vval.v_list);
7182 rettv->vval.v_list = NULL;
7183 goto theend;
7184 }
7185 }
7186 else if (type == 2)
7187 {
7188 rettv->v_type = VAR_STRING;
7189 rettv->vval.v_string = NULL;
7190 }
7191
7192 if (argvars[0].v_type == VAR_LIST)
7193 {
7194 if ((l = argvars[0].vval.v_list) == NULL)
7195 goto theend;
7196 li = l->lv_first;
7197 }
7198 else
7199 {
7200 expr = str = get_tv_string(&argvars[0]);
7201 len = (long)STRLEN(str);
7202 }
7203
7204 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7205 if (pat == NULL)
7206 goto theend;
7207
7208 if (argvars[2].v_type != VAR_UNKNOWN)
7209 {
7210 int error = FALSE;
7211
7212 start = (long)get_tv_number_chk(&argvars[2], &error);
7213 if (error)
7214 goto theend;
7215 if (l != NULL)
7216 {
7217 li = list_find(l, start);
7218 if (li == NULL)
7219 goto theend;
7220 idx = l->lv_idx; /* use the cached index */
7221 }
7222 else
7223 {
7224 if (start < 0)
7225 start = 0;
7226 if (start > len)
7227 goto theend;
7228 /* When "count" argument is there ignore matches before "start",
7229 * otherwise skip part of the string. Differs when pattern is "^"
7230 * or "\<". */
7231 if (argvars[3].v_type != VAR_UNKNOWN)
7232 startcol = start;
7233 else
7234 {
7235 str += start;
7236 len -= start;
7237 }
7238 }
7239
7240 if (argvars[3].v_type != VAR_UNKNOWN)
7241 nth = (long)get_tv_number_chk(&argvars[3], &error);
7242 if (error)
7243 goto theend;
7244 }
7245
7246 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7247 if (regmatch.regprog != NULL)
7248 {
7249 regmatch.rm_ic = p_ic;
7250
7251 for (;;)
7252 {
7253 if (l != NULL)
7254 {
7255 if (li == NULL)
7256 {
7257 match = FALSE;
7258 break;
7259 }
7260 vim_free(tofree);
7261 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7262 if (str == NULL)
7263 break;
7264 }
7265
7266 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7267
7268 if (match && --nth <= 0)
7269 break;
7270 if (l == NULL && !match)
7271 break;
7272
7273 /* Advance to just after the match. */
7274 if (l != NULL)
7275 {
7276 li = li->li_next;
7277 ++idx;
7278 }
7279 else
7280 {
7281#ifdef FEAT_MBYTE
7282 startcol = (colnr_T)(regmatch.startp[0]
7283 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7284#else
7285 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7286#endif
7287 if (startcol > (colnr_T)len
7288 || str + startcol <= regmatch.startp[0])
7289 {
7290 match = FALSE;
7291 break;
7292 }
7293 }
7294 }
7295
7296 if (match)
7297 {
7298 if (type == 4)
7299 {
7300 listitem_T *li1 = rettv->vval.v_list->lv_first;
7301 listitem_T *li2 = li1->li_next;
7302 listitem_T *li3 = li2->li_next;
7303 listitem_T *li4 = li3->li_next;
7304
7305 vim_free(li1->li_tv.vval.v_string);
7306 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7307 (int)(regmatch.endp[0] - regmatch.startp[0]));
7308 li3->li_tv.vval.v_number =
7309 (varnumber_T)(regmatch.startp[0] - expr);
7310 li4->li_tv.vval.v_number =
7311 (varnumber_T)(regmatch.endp[0] - expr);
7312 if (l != NULL)
7313 li2->li_tv.vval.v_number = (varnumber_T)idx;
7314 }
7315 else if (type == 3)
7316 {
7317 int i;
7318
7319 /* return list with matched string and submatches */
7320 for (i = 0; i < NSUBEXP; ++i)
7321 {
7322 if (regmatch.endp[i] == NULL)
7323 {
7324 if (list_append_string(rettv->vval.v_list,
7325 (char_u *)"", 0) == FAIL)
7326 break;
7327 }
7328 else if (list_append_string(rettv->vval.v_list,
7329 regmatch.startp[i],
7330 (int)(regmatch.endp[i] - regmatch.startp[i]))
7331 == FAIL)
7332 break;
7333 }
7334 }
7335 else if (type == 2)
7336 {
7337 /* return matched string */
7338 if (l != NULL)
7339 copy_tv(&li->li_tv, rettv);
7340 else
7341 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7342 (int)(regmatch.endp[0] - regmatch.startp[0]));
7343 }
7344 else if (l != NULL)
7345 rettv->vval.v_number = idx;
7346 else
7347 {
7348 if (type != 0)
7349 rettv->vval.v_number =
7350 (varnumber_T)(regmatch.startp[0] - str);
7351 else
7352 rettv->vval.v_number =
7353 (varnumber_T)(regmatch.endp[0] - str);
7354 rettv->vval.v_number += (varnumber_T)(str - expr);
7355 }
7356 }
7357 vim_regfree(regmatch.regprog);
7358 }
7359
7360 if (type == 4 && l == NULL)
7361 /* matchstrpos() without a list: drop the second item. */
7362 listitem_remove(rettv->vval.v_list,
7363 rettv->vval.v_list->lv_first->li_next);
7364
7365theend:
7366 vim_free(tofree);
7367 p_cpo = save_cpo;
7368}
7369
7370/*
7371 * "match()" function
7372 */
7373 static void
7374f_match(typval_T *argvars, typval_T *rettv)
7375{
7376 find_some_match(argvars, rettv, 1);
7377}
7378
7379/*
7380 * "matchadd()" function
7381 */
7382 static void
7383f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7384{
7385#ifdef FEAT_SEARCH_EXTRA
7386 char_u buf[NUMBUFLEN];
7387 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7388 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7389 int prio = 10; /* default priority */
7390 int id = -1;
7391 int error = FALSE;
7392 char_u *conceal_char = NULL;
7393
7394 rettv->vval.v_number = -1;
7395
7396 if (grp == NULL || pat == NULL)
7397 return;
7398 if (argvars[2].v_type != VAR_UNKNOWN)
7399 {
7400 prio = (int)get_tv_number_chk(&argvars[2], &error);
7401 if (argvars[3].v_type != VAR_UNKNOWN)
7402 {
7403 id = (int)get_tv_number_chk(&argvars[3], &error);
7404 if (argvars[4].v_type != VAR_UNKNOWN)
7405 {
7406 if (argvars[4].v_type != VAR_DICT)
7407 {
7408 EMSG(_(e_dictreq));
7409 return;
7410 }
7411 if (dict_find(argvars[4].vval.v_dict,
7412 (char_u *)"conceal", -1) != NULL)
7413 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7414 (char_u *)"conceal", FALSE);
7415 }
7416 }
7417 }
7418 if (error == TRUE)
7419 return;
7420 if (id >= 1 && id <= 3)
7421 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007422 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 return;
7424 }
7425
7426 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7427 conceal_char);
7428#endif
7429}
7430
7431/*
7432 * "matchaddpos()" function
7433 */
7434 static void
7435f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7436{
7437#ifdef FEAT_SEARCH_EXTRA
7438 char_u buf[NUMBUFLEN];
7439 char_u *group;
7440 int prio = 10;
7441 int id = -1;
7442 int error = FALSE;
7443 list_T *l;
7444 char_u *conceal_char = NULL;
7445
7446 rettv->vval.v_number = -1;
7447
7448 group = get_tv_string_buf_chk(&argvars[0], buf);
7449 if (group == NULL)
7450 return;
7451
7452 if (argvars[1].v_type != VAR_LIST)
7453 {
7454 EMSG2(_(e_listarg), "matchaddpos()");
7455 return;
7456 }
7457 l = argvars[1].vval.v_list;
7458 if (l == NULL)
7459 return;
7460
7461 if (argvars[2].v_type != VAR_UNKNOWN)
7462 {
7463 prio = (int)get_tv_number_chk(&argvars[2], &error);
7464 if (argvars[3].v_type != VAR_UNKNOWN)
7465 {
7466 id = (int)get_tv_number_chk(&argvars[3], &error);
7467 if (argvars[4].v_type != VAR_UNKNOWN)
7468 {
7469 if (argvars[4].v_type != VAR_DICT)
7470 {
7471 EMSG(_(e_dictreq));
7472 return;
7473 }
7474 if (dict_find(argvars[4].vval.v_dict,
7475 (char_u *)"conceal", -1) != NULL)
7476 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7477 (char_u *)"conceal", FALSE);
7478 }
7479 }
7480 }
7481 if (error == TRUE)
7482 return;
7483
7484 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7485 if (id == 1 || id == 2)
7486 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007487 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488 return;
7489 }
7490
7491 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7492 conceal_char);
7493#endif
7494}
7495
7496/*
7497 * "matcharg()" function
7498 */
7499 static void
7500f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7501{
7502 if (rettv_list_alloc(rettv) == OK)
7503 {
7504#ifdef FEAT_SEARCH_EXTRA
7505 int id = (int)get_tv_number(&argvars[0]);
7506 matchitem_T *m;
7507
7508 if (id >= 1 && id <= 3)
7509 {
7510 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7511 {
7512 list_append_string(rettv->vval.v_list,
7513 syn_id2name(m->hlg_id), -1);
7514 list_append_string(rettv->vval.v_list, m->pattern, -1);
7515 }
7516 else
7517 {
7518 list_append_string(rettv->vval.v_list, NULL, -1);
7519 list_append_string(rettv->vval.v_list, NULL, -1);
7520 }
7521 }
7522#endif
7523 }
7524}
7525
7526/*
7527 * "matchdelete()" function
7528 */
7529 static void
7530f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7531{
7532#ifdef FEAT_SEARCH_EXTRA
7533 rettv->vval.v_number = match_delete(curwin,
7534 (int)get_tv_number(&argvars[0]), TRUE);
7535#endif
7536}
7537
7538/*
7539 * "matchend()" function
7540 */
7541 static void
7542f_matchend(typval_T *argvars, typval_T *rettv)
7543{
7544 find_some_match(argvars, rettv, 0);
7545}
7546
7547/*
7548 * "matchlist()" function
7549 */
7550 static void
7551f_matchlist(typval_T *argvars, typval_T *rettv)
7552{
7553 find_some_match(argvars, rettv, 3);
7554}
7555
7556/*
7557 * "matchstr()" function
7558 */
7559 static void
7560f_matchstr(typval_T *argvars, typval_T *rettv)
7561{
7562 find_some_match(argvars, rettv, 2);
7563}
7564
7565/*
7566 * "matchstrpos()" function
7567 */
7568 static void
7569f_matchstrpos(typval_T *argvars, typval_T *rettv)
7570{
7571 find_some_match(argvars, rettv, 4);
7572}
7573
7574static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7575
7576 static void
7577max_min(typval_T *argvars, typval_T *rettv, int domax)
7578{
7579 varnumber_T n = 0;
7580 varnumber_T i;
7581 int error = FALSE;
7582
7583 if (argvars[0].v_type == VAR_LIST)
7584 {
7585 list_T *l;
7586 listitem_T *li;
7587
7588 l = argvars[0].vval.v_list;
7589 if (l != NULL)
7590 {
7591 li = l->lv_first;
7592 if (li != NULL)
7593 {
7594 n = get_tv_number_chk(&li->li_tv, &error);
7595 for (;;)
7596 {
7597 li = li->li_next;
7598 if (li == NULL)
7599 break;
7600 i = get_tv_number_chk(&li->li_tv, &error);
7601 if (domax ? i > n : i < n)
7602 n = i;
7603 }
7604 }
7605 }
7606 }
7607 else if (argvars[0].v_type == VAR_DICT)
7608 {
7609 dict_T *d;
7610 int first = TRUE;
7611 hashitem_T *hi;
7612 int todo;
7613
7614 d = argvars[0].vval.v_dict;
7615 if (d != NULL)
7616 {
7617 todo = (int)d->dv_hashtab.ht_used;
7618 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7619 {
7620 if (!HASHITEM_EMPTY(hi))
7621 {
7622 --todo;
7623 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7624 if (first)
7625 {
7626 n = i;
7627 first = FALSE;
7628 }
7629 else if (domax ? i > n : i < n)
7630 n = i;
7631 }
7632 }
7633 }
7634 }
7635 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02007636 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007637 rettv->vval.v_number = error ? 0 : n;
7638}
7639
7640/*
7641 * "max()" function
7642 */
7643 static void
7644f_max(typval_T *argvars, typval_T *rettv)
7645{
7646 max_min(argvars, rettv, TRUE);
7647}
7648
7649/*
7650 * "min()" function
7651 */
7652 static void
7653f_min(typval_T *argvars, typval_T *rettv)
7654{
7655 max_min(argvars, rettv, FALSE);
7656}
7657
7658static int mkdir_recurse(char_u *dir, int prot);
7659
7660/*
7661 * Create the directory in which "dir" is located, and higher levels when
7662 * needed.
7663 */
7664 static int
7665mkdir_recurse(char_u *dir, int prot)
7666{
7667 char_u *p;
7668 char_u *updir;
7669 int r = FAIL;
7670
7671 /* Get end of directory name in "dir".
7672 * We're done when it's "/" or "c:/". */
7673 p = gettail_sep(dir);
7674 if (p <= get_past_head(dir))
7675 return OK;
7676
7677 /* If the directory exists we're done. Otherwise: create it.*/
7678 updir = vim_strnsave(dir, (int)(p - dir));
7679 if (updir == NULL)
7680 return FAIL;
7681 if (mch_isdir(updir))
7682 r = OK;
7683 else if (mkdir_recurse(updir, prot) == OK)
7684 r = vim_mkdir_emsg(updir, prot);
7685 vim_free(updir);
7686 return r;
7687}
7688
7689#ifdef vim_mkdir
7690/*
7691 * "mkdir()" function
7692 */
7693 static void
7694f_mkdir(typval_T *argvars, typval_T *rettv)
7695{
7696 char_u *dir;
7697 char_u buf[NUMBUFLEN];
7698 int prot = 0755;
7699
7700 rettv->vval.v_number = FAIL;
7701 if (check_restricted() || check_secure())
7702 return;
7703
7704 dir = get_tv_string_buf(&argvars[0], buf);
7705 if (*dir == NUL)
7706 rettv->vval.v_number = FAIL;
7707 else
7708 {
7709 if (*gettail(dir) == NUL)
7710 /* remove trailing slashes */
7711 *gettail_sep(dir) = NUL;
7712
7713 if (argvars[1].v_type != VAR_UNKNOWN)
7714 {
7715 if (argvars[2].v_type != VAR_UNKNOWN)
7716 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7717 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7718 mkdir_recurse(dir, prot);
7719 }
7720 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7721 }
7722}
7723#endif
7724
7725/*
7726 * "mode()" function
7727 */
7728 static void
7729f_mode(typval_T *argvars, typval_T *rettv)
7730{
7731 char_u buf[3];
7732
7733 buf[1] = NUL;
7734 buf[2] = NUL;
7735
7736 if (time_for_testing == 93784)
7737 {
7738 /* Testing the two-character code. */
7739 buf[0] = 'x';
7740 buf[1] = '!';
7741 }
7742 else if (VIsual_active)
7743 {
7744 if (VIsual_select)
7745 buf[0] = VIsual_mode + 's' - 'v';
7746 else
7747 buf[0] = VIsual_mode;
7748 }
7749 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7750 || State == CONFIRM)
7751 {
7752 buf[0] = 'r';
7753 if (State == ASKMORE)
7754 buf[1] = 'm';
7755 else if (State == CONFIRM)
7756 buf[1] = '?';
7757 }
7758 else if (State == EXTERNCMD)
7759 buf[0] = '!';
7760 else if (State & INSERT)
7761 {
7762#ifdef FEAT_VREPLACE
7763 if (State & VREPLACE_FLAG)
7764 {
7765 buf[0] = 'R';
7766 buf[1] = 'v';
7767 }
7768 else
7769#endif
7770 if (State & REPLACE_FLAG)
7771 buf[0] = 'R';
7772 else
7773 buf[0] = 'i';
7774 }
7775 else if (State & CMDLINE)
7776 {
7777 buf[0] = 'c';
7778 if (exmode_active)
7779 buf[1] = 'v';
7780 }
7781 else if (exmode_active)
7782 {
7783 buf[0] = 'c';
7784 buf[1] = 'e';
7785 }
7786 else
7787 {
7788 buf[0] = 'n';
7789 if (finish_op)
7790 buf[1] = 'o';
7791 }
7792
7793 /* Clear out the minor mode when the argument is not a non-zero number or
7794 * non-empty string. */
7795 if (!non_zero_arg(&argvars[0]))
7796 buf[1] = NUL;
7797
7798 rettv->vval.v_string = vim_strsave(buf);
7799 rettv->v_type = VAR_STRING;
7800}
7801
7802#if defined(FEAT_MZSCHEME) || defined(PROTO)
7803/*
7804 * "mzeval()" function
7805 */
7806 static void
7807f_mzeval(typval_T *argvars, typval_T *rettv)
7808{
7809 char_u *str;
7810 char_u buf[NUMBUFLEN];
7811
7812 str = get_tv_string_buf(&argvars[0], buf);
7813 do_mzeval(str, rettv);
7814}
7815
7816 void
7817mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7818{
7819 typval_T argvars[3];
7820
7821 argvars[0].v_type = VAR_STRING;
7822 argvars[0].vval.v_string = name;
7823 copy_tv(args, &argvars[1]);
7824 argvars[2].v_type = VAR_UNKNOWN;
7825 f_call(argvars, rettv);
7826 clear_tv(&argvars[1]);
7827}
7828#endif
7829
7830/*
7831 * "nextnonblank()" function
7832 */
7833 static void
7834f_nextnonblank(typval_T *argvars, typval_T *rettv)
7835{
7836 linenr_T lnum;
7837
7838 for (lnum = get_tv_lnum(argvars); ; ++lnum)
7839 {
7840 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7841 {
7842 lnum = 0;
7843 break;
7844 }
7845 if (*skipwhite(ml_get(lnum)) != NUL)
7846 break;
7847 }
7848 rettv->vval.v_number = lnum;
7849}
7850
7851/*
7852 * "nr2char()" function
7853 */
7854 static void
7855f_nr2char(typval_T *argvars, typval_T *rettv)
7856{
7857 char_u buf[NUMBUFLEN];
7858
7859#ifdef FEAT_MBYTE
7860 if (has_mbyte)
7861 {
7862 int utf8 = 0;
7863
7864 if (argvars[1].v_type != VAR_UNKNOWN)
7865 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
7866 if (utf8)
7867 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7868 else
7869 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7870 }
7871 else
7872#endif
7873 {
7874 buf[0] = (char_u)get_tv_number(&argvars[0]);
7875 buf[1] = NUL;
7876 }
7877 rettv->v_type = VAR_STRING;
7878 rettv->vval.v_string = vim_strsave(buf);
7879}
7880
7881/*
7882 * "or(expr, expr)" function
7883 */
7884 static void
7885f_or(typval_T *argvars, typval_T *rettv)
7886{
7887 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
7888 | get_tv_number_chk(&argvars[1], NULL);
7889}
7890
7891/*
7892 * "pathshorten()" function
7893 */
7894 static void
7895f_pathshorten(typval_T *argvars, typval_T *rettv)
7896{
7897 char_u *p;
7898
7899 rettv->v_type = VAR_STRING;
7900 p = get_tv_string_chk(&argvars[0]);
7901 if (p == NULL)
7902 rettv->vval.v_string = NULL;
7903 else
7904 {
7905 p = vim_strsave(p);
7906 rettv->vval.v_string = p;
7907 if (p != NULL)
7908 shorten_dir(p);
7909 }
7910}
7911
7912#ifdef FEAT_PERL
7913/*
7914 * "perleval()" function
7915 */
7916 static void
7917f_perleval(typval_T *argvars, typval_T *rettv)
7918{
7919 char_u *str;
7920 char_u buf[NUMBUFLEN];
7921
7922 str = get_tv_string_buf(&argvars[0], buf);
7923 do_perleval(str, rettv);
7924}
7925#endif
7926
7927#ifdef FEAT_FLOAT
7928/*
7929 * "pow()" function
7930 */
7931 static void
7932f_pow(typval_T *argvars, typval_T *rettv)
7933{
7934 float_T fx = 0.0, fy = 0.0;
7935
7936 rettv->v_type = VAR_FLOAT;
7937 if (get_float_arg(argvars, &fx) == OK
7938 && get_float_arg(&argvars[1], &fy) == OK)
7939 rettv->vval.v_float = pow(fx, fy);
7940 else
7941 rettv->vval.v_float = 0.0;
7942}
7943#endif
7944
7945/*
7946 * "prevnonblank()" function
7947 */
7948 static void
7949f_prevnonblank(typval_T *argvars, typval_T *rettv)
7950{
7951 linenr_T lnum;
7952
7953 lnum = get_tv_lnum(argvars);
7954 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7955 lnum = 0;
7956 else
7957 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7958 --lnum;
7959 rettv->vval.v_number = lnum;
7960}
7961
7962/* This dummy va_list is here because:
7963 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7964 * - locally in the function results in a "used before set" warning
7965 * - using va_start() to initialize it gives "function with fixed args" error */
7966static va_list ap;
7967
7968/*
7969 * "printf()" function
7970 */
7971 static void
7972f_printf(typval_T *argvars, typval_T *rettv)
7973{
7974 char_u buf[NUMBUFLEN];
7975 int len;
7976 char_u *s;
7977 int saved_did_emsg = did_emsg;
7978 char *fmt;
7979
7980 rettv->v_type = VAR_STRING;
7981 rettv->vval.v_string = NULL;
7982
7983 /* Get the required length, allocate the buffer and do it for real. */
7984 did_emsg = FALSE;
7985 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
7986 len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
7987 if (!did_emsg)
7988 {
7989 s = alloc(len + 1);
7990 if (s != NULL)
7991 {
7992 rettv->vval.v_string = s;
7993 (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1);
7994 }
7995 }
7996 did_emsg |= saved_did_emsg;
7997}
7998
7999/*
8000 * "pumvisible()" function
8001 */
8002 static void
8003f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8004{
8005#ifdef FEAT_INS_EXPAND
8006 if (pum_visible())
8007 rettv->vval.v_number = 1;
8008#endif
8009}
8010
8011#ifdef FEAT_PYTHON3
8012/*
8013 * "py3eval()" function
8014 */
8015 static void
8016f_py3eval(typval_T *argvars, typval_T *rettv)
8017{
8018 char_u *str;
8019 char_u buf[NUMBUFLEN];
8020
8021 str = get_tv_string_buf(&argvars[0], buf);
8022 do_py3eval(str, rettv);
8023}
8024#endif
8025
8026#ifdef FEAT_PYTHON
8027/*
8028 * "pyeval()" function
8029 */
8030 static void
8031f_pyeval(typval_T *argvars, typval_T *rettv)
8032{
8033 char_u *str;
8034 char_u buf[NUMBUFLEN];
8035
8036 str = get_tv_string_buf(&argvars[0], buf);
8037 do_pyeval(str, rettv);
8038}
8039#endif
8040
8041/*
8042 * "range()" function
8043 */
8044 static void
8045f_range(typval_T *argvars, typval_T *rettv)
8046{
8047 varnumber_T start;
8048 varnumber_T end;
8049 varnumber_T stride = 1;
8050 varnumber_T i;
8051 int error = FALSE;
8052
8053 start = get_tv_number_chk(&argvars[0], &error);
8054 if (argvars[1].v_type == VAR_UNKNOWN)
8055 {
8056 end = start - 1;
8057 start = 0;
8058 }
8059 else
8060 {
8061 end = get_tv_number_chk(&argvars[1], &error);
8062 if (argvars[2].v_type != VAR_UNKNOWN)
8063 stride = get_tv_number_chk(&argvars[2], &error);
8064 }
8065
8066 if (error)
8067 return; /* type error; errmsg already given */
8068 if (stride == 0)
8069 EMSG(_("E726: Stride is zero"));
8070 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8071 EMSG(_("E727: Start past end"));
8072 else
8073 {
8074 if (rettv_list_alloc(rettv) == OK)
8075 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8076 if (list_append_number(rettv->vval.v_list,
8077 (varnumber_T)i) == FAIL)
8078 break;
8079 }
8080}
8081
8082/*
8083 * "readfile()" function
8084 */
8085 static void
8086f_readfile(typval_T *argvars, typval_T *rettv)
8087{
8088 int binary = FALSE;
8089 int failed = FALSE;
8090 char_u *fname;
8091 FILE *fd;
8092 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8093 int io_size = sizeof(buf);
8094 int readlen; /* size of last fread() */
8095 char_u *prev = NULL; /* previously read bytes, if any */
8096 long prevlen = 0; /* length of data in prev */
8097 long prevsize = 0; /* size of prev buffer */
8098 long maxline = MAXLNUM;
8099 long cnt = 0;
8100 char_u *p; /* position in buf */
8101 char_u *start; /* start of current line */
8102
8103 if (argvars[1].v_type != VAR_UNKNOWN)
8104 {
8105 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8106 binary = TRUE;
8107 if (argvars[2].v_type != VAR_UNKNOWN)
8108 maxline = (long)get_tv_number(&argvars[2]);
8109 }
8110
8111 if (rettv_list_alloc(rettv) == FAIL)
8112 return;
8113
8114 /* Always open the file in binary mode, library functions have a mind of
8115 * their own about CR-LF conversion. */
8116 fname = get_tv_string(&argvars[0]);
8117 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8118 {
8119 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8120 return;
8121 }
8122
8123 while (cnt < maxline || maxline < 0)
8124 {
8125 readlen = (int)fread(buf, 1, io_size, fd);
8126
8127 /* This for loop processes what was read, but is also entered at end
8128 * of file so that either:
8129 * - an incomplete line gets written
8130 * - a "binary" file gets an empty line at the end if it ends in a
8131 * newline. */
8132 for (p = buf, start = buf;
8133 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8134 ++p)
8135 {
8136 if (*p == '\n' || readlen <= 0)
8137 {
8138 listitem_T *li;
8139 char_u *s = NULL;
8140 long_u len = p - start;
8141
8142 /* Finished a line. Remove CRs before NL. */
8143 if (readlen > 0 && !binary)
8144 {
8145 while (len > 0 && start[len - 1] == '\r')
8146 --len;
8147 /* removal may cross back to the "prev" string */
8148 if (len == 0)
8149 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8150 --prevlen;
8151 }
8152 if (prevlen == 0)
8153 s = vim_strnsave(start, (int)len);
8154 else
8155 {
8156 /* Change "prev" buffer to be the right size. This way
8157 * the bytes are only copied once, and very long lines are
8158 * allocated only once. */
8159 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8160 {
8161 mch_memmove(s + prevlen, start, len);
8162 s[prevlen + len] = NUL;
8163 prev = NULL; /* the list will own the string */
8164 prevlen = prevsize = 0;
8165 }
8166 }
8167 if (s == NULL)
8168 {
8169 do_outofmem_msg((long_u) prevlen + len + 1);
8170 failed = TRUE;
8171 break;
8172 }
8173
8174 if ((li = listitem_alloc()) == NULL)
8175 {
8176 vim_free(s);
8177 failed = TRUE;
8178 break;
8179 }
8180 li->li_tv.v_type = VAR_STRING;
8181 li->li_tv.v_lock = 0;
8182 li->li_tv.vval.v_string = s;
8183 list_append(rettv->vval.v_list, li);
8184
8185 start = p + 1; /* step over newline */
8186 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8187 break;
8188 }
8189 else if (*p == NUL)
8190 *p = '\n';
8191#ifdef FEAT_MBYTE
8192 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8193 * when finding the BF and check the previous two bytes. */
8194 else if (*p == 0xbf && enc_utf8 && !binary)
8195 {
8196 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8197 * + 1, these may be in the "prev" string. */
8198 char_u back1 = p >= buf + 1 ? p[-1]
8199 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8200 char_u back2 = p >= buf + 2 ? p[-2]
8201 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8202 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8203
8204 if (back2 == 0xef && back1 == 0xbb)
8205 {
8206 char_u *dest = p - 2;
8207
8208 /* Usually a BOM is at the beginning of a file, and so at
8209 * the beginning of a line; then we can just step over it.
8210 */
8211 if (start == dest)
8212 start = p + 1;
8213 else
8214 {
8215 /* have to shuffle buf to close gap */
8216 int adjust_prevlen = 0;
8217
8218 if (dest < buf)
8219 {
8220 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8221 dest = buf;
8222 }
8223 if (readlen > p - buf + 1)
8224 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8225 readlen -= 3 - adjust_prevlen;
8226 prevlen -= adjust_prevlen;
8227 p = dest - 1;
8228 }
8229 }
8230 }
8231#endif
8232 } /* for */
8233
8234 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8235 break;
8236 if (start < p)
8237 {
8238 /* There's part of a line in buf, store it in "prev". */
8239 if (p - start + prevlen >= prevsize)
8240 {
8241 /* need bigger "prev" buffer */
8242 char_u *newprev;
8243
8244 /* A common use case is ordinary text files and "prev" gets a
8245 * fragment of a line, so the first allocation is made
8246 * small, to avoid repeatedly 'allocing' large and
8247 * 'reallocing' small. */
8248 if (prevsize == 0)
8249 prevsize = (long)(p - start);
8250 else
8251 {
8252 long grow50pc = (prevsize * 3) / 2;
8253 long growmin = (long)((p - start) * 2 + prevlen);
8254 prevsize = grow50pc > growmin ? grow50pc : growmin;
8255 }
8256 newprev = prev == NULL ? alloc(prevsize)
8257 : vim_realloc(prev, prevsize);
8258 if (newprev == NULL)
8259 {
8260 do_outofmem_msg((long_u)prevsize);
8261 failed = TRUE;
8262 break;
8263 }
8264 prev = newprev;
8265 }
8266 /* Add the line part to end of "prev". */
8267 mch_memmove(prev + prevlen, start, p - start);
8268 prevlen += (long)(p - start);
8269 }
8270 } /* while */
8271
8272 /*
8273 * For a negative line count use only the lines at the end of the file,
8274 * free the rest.
8275 */
8276 if (!failed && maxline < 0)
8277 while (cnt > -maxline)
8278 {
8279 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8280 --cnt;
8281 }
8282
8283 if (failed)
8284 {
8285 list_free(rettv->vval.v_list);
8286 /* readfile doc says an empty list is returned on error */
8287 rettv->vval.v_list = list_alloc();
8288 }
8289
8290 vim_free(prev);
8291 fclose(fd);
8292}
8293
8294#if defined(FEAT_RELTIME)
8295static int list2proftime(typval_T *arg, proftime_T *tm);
8296
8297/*
8298 * Convert a List to proftime_T.
8299 * Return FAIL when there is something wrong.
8300 */
8301 static int
8302list2proftime(typval_T *arg, proftime_T *tm)
8303{
8304 long n1, n2;
8305 int error = FALSE;
8306
8307 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8308 || arg->vval.v_list->lv_len != 2)
8309 return FAIL;
8310 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8311 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8312# ifdef WIN3264
8313 tm->HighPart = n1;
8314 tm->LowPart = n2;
8315# else
8316 tm->tv_sec = n1;
8317 tm->tv_usec = n2;
8318# endif
8319 return error ? FAIL : OK;
8320}
8321#endif /* FEAT_RELTIME */
8322
8323/*
8324 * "reltime()" function
8325 */
8326 static void
8327f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8328{
8329#ifdef FEAT_RELTIME
8330 proftime_T res;
8331 proftime_T start;
8332
8333 if (argvars[0].v_type == VAR_UNKNOWN)
8334 {
8335 /* No arguments: get current time. */
8336 profile_start(&res);
8337 }
8338 else if (argvars[1].v_type == VAR_UNKNOWN)
8339 {
8340 if (list2proftime(&argvars[0], &res) == FAIL)
8341 return;
8342 profile_end(&res);
8343 }
8344 else
8345 {
8346 /* Two arguments: compute the difference. */
8347 if (list2proftime(&argvars[0], &start) == FAIL
8348 || list2proftime(&argvars[1], &res) == FAIL)
8349 return;
8350 profile_sub(&res, &start);
8351 }
8352
8353 if (rettv_list_alloc(rettv) == OK)
8354 {
8355 long n1, n2;
8356
8357# ifdef WIN3264
8358 n1 = res.HighPart;
8359 n2 = res.LowPart;
8360# else
8361 n1 = res.tv_sec;
8362 n2 = res.tv_usec;
8363# endif
8364 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8365 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8366 }
8367#endif
8368}
8369
8370#ifdef FEAT_FLOAT
8371/*
8372 * "reltimefloat()" function
8373 */
8374 static void
8375f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8376{
8377# ifdef FEAT_RELTIME
8378 proftime_T tm;
8379# endif
8380
8381 rettv->v_type = VAR_FLOAT;
8382 rettv->vval.v_float = 0;
8383# ifdef FEAT_RELTIME
8384 if (list2proftime(&argvars[0], &tm) == OK)
8385 rettv->vval.v_float = profile_float(&tm);
8386# endif
8387}
8388#endif
8389
8390/*
8391 * "reltimestr()" function
8392 */
8393 static void
8394f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8395{
8396#ifdef FEAT_RELTIME
8397 proftime_T tm;
8398#endif
8399
8400 rettv->v_type = VAR_STRING;
8401 rettv->vval.v_string = NULL;
8402#ifdef FEAT_RELTIME
8403 if (list2proftime(&argvars[0], &tm) == OK)
8404 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8405#endif
8406}
8407
8408#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8409static void make_connection(void);
8410static int check_connection(void);
8411
8412 static void
8413make_connection(void)
8414{
8415 if (X_DISPLAY == NULL
8416# ifdef FEAT_GUI
8417 && !gui.in_use
8418# endif
8419 )
8420 {
8421 x_force_connect = TRUE;
8422 setup_term_clip();
8423 x_force_connect = FALSE;
8424 }
8425}
8426
8427 static int
8428check_connection(void)
8429{
8430 make_connection();
8431 if (X_DISPLAY == NULL)
8432 {
8433 EMSG(_("E240: No connection to Vim server"));
8434 return FAIL;
8435 }
8436 return OK;
8437}
8438#endif
8439
8440#ifdef FEAT_CLIENTSERVER
8441 static void
8442remote_common(typval_T *argvars, typval_T *rettv, int expr)
8443{
8444 char_u *server_name;
8445 char_u *keys;
8446 char_u *r = NULL;
8447 char_u buf[NUMBUFLEN];
8448# ifdef WIN32
8449 HWND w;
8450# else
8451 Window w;
8452# endif
8453
8454 if (check_restricted() || check_secure())
8455 return;
8456
8457# ifdef FEAT_X11
8458 if (check_connection() == FAIL)
8459 return;
8460# endif
8461
8462 server_name = get_tv_string_chk(&argvars[0]);
8463 if (server_name == NULL)
8464 return; /* type error; errmsg already given */
8465 keys = get_tv_string_buf(&argvars[1], buf);
8466# ifdef WIN32
8467 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
8468# else
8469 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
8470 < 0)
8471# endif
8472 {
8473 if (r != NULL)
8474 EMSG(r); /* sending worked but evaluation failed */
8475 else
8476 EMSG2(_("E241: Unable to send to %s"), server_name);
8477 return;
8478 }
8479
8480 rettv->vval.v_string = r;
8481
8482 if (argvars[2].v_type != VAR_UNKNOWN)
8483 {
8484 dictitem_T v;
8485 char_u str[30];
8486 char_u *idvar;
8487
8488 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8489 v.di_tv.v_type = VAR_STRING;
8490 v.di_tv.vval.v_string = vim_strsave(str);
8491 idvar = get_tv_string_chk(&argvars[2]);
8492 if (idvar != NULL)
8493 set_var(idvar, &v.di_tv, FALSE);
8494 vim_free(v.di_tv.vval.v_string);
8495 }
8496}
8497#endif
8498
8499/*
8500 * "remote_expr()" function
8501 */
8502 static void
8503f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8504{
8505 rettv->v_type = VAR_STRING;
8506 rettv->vval.v_string = NULL;
8507#ifdef FEAT_CLIENTSERVER
8508 remote_common(argvars, rettv, TRUE);
8509#endif
8510}
8511
8512/*
8513 * "remote_foreground()" function
8514 */
8515 static void
8516f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8517{
8518#ifdef FEAT_CLIENTSERVER
8519# ifdef WIN32
8520 /* On Win32 it's done in this application. */
8521 {
8522 char_u *server_name = get_tv_string_chk(&argvars[0]);
8523
8524 if (server_name != NULL)
8525 serverForeground(server_name);
8526 }
8527# else
8528 /* Send a foreground() expression to the server. */
8529 argvars[1].v_type = VAR_STRING;
8530 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8531 argvars[2].v_type = VAR_UNKNOWN;
8532 remote_common(argvars, rettv, TRUE);
8533 vim_free(argvars[1].vval.v_string);
8534# endif
8535#endif
8536}
8537
8538 static void
8539f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8540{
8541#ifdef FEAT_CLIENTSERVER
8542 dictitem_T v;
8543 char_u *s = NULL;
8544# ifdef WIN32
8545 long_u n = 0;
8546# endif
8547 char_u *serverid;
8548
8549 if (check_restricted() || check_secure())
8550 {
8551 rettv->vval.v_number = -1;
8552 return;
8553 }
8554 serverid = get_tv_string_chk(&argvars[0]);
8555 if (serverid == NULL)
8556 {
8557 rettv->vval.v_number = -1;
8558 return; /* type error; errmsg already given */
8559 }
8560# ifdef WIN32
8561 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8562 if (n == 0)
8563 rettv->vval.v_number = -1;
8564 else
8565 {
8566 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
8567 rettv->vval.v_number = (s != NULL);
8568 }
8569# else
8570 if (check_connection() == FAIL)
8571 return;
8572
8573 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8574 serverStrToWin(serverid), &s);
8575# endif
8576
8577 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8578 {
8579 char_u *retvar;
8580
8581 v.di_tv.v_type = VAR_STRING;
8582 v.di_tv.vval.v_string = vim_strsave(s);
8583 retvar = get_tv_string_chk(&argvars[1]);
8584 if (retvar != NULL)
8585 set_var(retvar, &v.di_tv, FALSE);
8586 vim_free(v.di_tv.vval.v_string);
8587 }
8588#else
8589 rettv->vval.v_number = -1;
8590#endif
8591}
8592
8593 static void
8594f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8595{
8596 char_u *r = NULL;
8597
8598#ifdef FEAT_CLIENTSERVER
8599 char_u *serverid = get_tv_string_chk(&argvars[0]);
8600
8601 if (serverid != NULL && !check_restricted() && !check_secure())
8602 {
8603# ifdef WIN32
8604 /* The server's HWND is encoded in the 'id' parameter */
8605 long_u n = 0;
8606
8607 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8608 if (n != 0)
8609 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
8610 if (r == NULL)
8611# else
8612 if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
8613 serverStrToWin(serverid), &r, FALSE) < 0)
8614# endif
8615 EMSG(_("E277: Unable to read a server reply"));
8616 }
8617#endif
8618 rettv->v_type = VAR_STRING;
8619 rettv->vval.v_string = r;
8620}
8621
8622/*
8623 * "remote_send()" function
8624 */
8625 static void
8626f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8627{
8628 rettv->v_type = VAR_STRING;
8629 rettv->vval.v_string = NULL;
8630#ifdef FEAT_CLIENTSERVER
8631 remote_common(argvars, rettv, FALSE);
8632#endif
8633}
8634
8635/*
8636 * "remove()" function
8637 */
8638 static void
8639f_remove(typval_T *argvars, typval_T *rettv)
8640{
8641 list_T *l;
8642 listitem_T *item, *item2;
8643 listitem_T *li;
8644 long idx;
8645 long end;
8646 char_u *key;
8647 dict_T *d;
8648 dictitem_T *di;
8649 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8650
8651 if (argvars[0].v_type == VAR_DICT)
8652 {
8653 if (argvars[2].v_type != VAR_UNKNOWN)
8654 EMSG2(_(e_toomanyarg), "remove()");
8655 else if ((d = argvars[0].vval.v_dict) != NULL
8656 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8657 {
8658 key = get_tv_string_chk(&argvars[1]);
8659 if (key != NULL)
8660 {
8661 di = dict_find(d, key, -1);
8662 if (di == NULL)
8663 EMSG2(_(e_dictkey), key);
8664 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8665 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8666 {
8667 *rettv = di->di_tv;
8668 init_tv(&di->di_tv);
8669 dictitem_remove(d, di);
8670 }
8671 }
8672 }
8673 }
8674 else if (argvars[0].v_type != VAR_LIST)
8675 EMSG2(_(e_listdictarg), "remove()");
8676 else if ((l = argvars[0].vval.v_list) != NULL
8677 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8678 {
8679 int error = FALSE;
8680
8681 idx = (long)get_tv_number_chk(&argvars[1], &error);
8682 if (error)
8683 ; /* type error: do nothing, errmsg already given */
8684 else if ((item = list_find(l, idx)) == NULL)
8685 EMSGN(_(e_listidx), idx);
8686 else
8687 {
8688 if (argvars[2].v_type == VAR_UNKNOWN)
8689 {
8690 /* Remove one item, return its value. */
8691 vimlist_remove(l, item, item);
8692 *rettv = item->li_tv;
8693 vim_free(item);
8694 }
8695 else
8696 {
8697 /* Remove range of items, return list with values. */
8698 end = (long)get_tv_number_chk(&argvars[2], &error);
8699 if (error)
8700 ; /* type error: do nothing */
8701 else if ((item2 = list_find(l, end)) == NULL)
8702 EMSGN(_(e_listidx), end);
8703 else
8704 {
8705 int cnt = 0;
8706
8707 for (li = item; li != NULL; li = li->li_next)
8708 {
8709 ++cnt;
8710 if (li == item2)
8711 break;
8712 }
8713 if (li == NULL) /* didn't find "item2" after "item" */
8714 EMSG(_(e_invrange));
8715 else
8716 {
8717 vimlist_remove(l, item, item2);
8718 if (rettv_list_alloc(rettv) == OK)
8719 {
8720 l = rettv->vval.v_list;
8721 l->lv_first = item;
8722 l->lv_last = item2;
8723 item->li_prev = NULL;
8724 item2->li_next = NULL;
8725 l->lv_len = cnt;
8726 }
8727 }
8728 }
8729 }
8730 }
8731 }
8732}
8733
8734/*
8735 * "rename({from}, {to})" function
8736 */
8737 static void
8738f_rename(typval_T *argvars, typval_T *rettv)
8739{
8740 char_u buf[NUMBUFLEN];
8741
8742 if (check_restricted() || check_secure())
8743 rettv->vval.v_number = -1;
8744 else
8745 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8746 get_tv_string_buf(&argvars[1], buf));
8747}
8748
8749/*
8750 * "repeat()" function
8751 */
8752 static void
8753f_repeat(typval_T *argvars, typval_T *rettv)
8754{
8755 char_u *p;
8756 int n;
8757 int slen;
8758 int len;
8759 char_u *r;
8760 int i;
8761
8762 n = (int)get_tv_number(&argvars[1]);
8763 if (argvars[0].v_type == VAR_LIST)
8764 {
8765 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8766 while (n-- > 0)
8767 if (list_extend(rettv->vval.v_list,
8768 argvars[0].vval.v_list, NULL) == FAIL)
8769 break;
8770 }
8771 else
8772 {
8773 p = get_tv_string(&argvars[0]);
8774 rettv->v_type = VAR_STRING;
8775 rettv->vval.v_string = NULL;
8776
8777 slen = (int)STRLEN(p);
8778 len = slen * n;
8779 if (len <= 0)
8780 return;
8781
8782 r = alloc(len + 1);
8783 if (r != NULL)
8784 {
8785 for (i = 0; i < n; i++)
8786 mch_memmove(r + i * slen, p, (size_t)slen);
8787 r[len] = NUL;
8788 }
8789
8790 rettv->vval.v_string = r;
8791 }
8792}
8793
8794/*
8795 * "resolve()" function
8796 */
8797 static void
8798f_resolve(typval_T *argvars, typval_T *rettv)
8799{
8800 char_u *p;
8801#ifdef HAVE_READLINK
8802 char_u *buf = NULL;
8803#endif
8804
8805 p = get_tv_string(&argvars[0]);
8806#ifdef FEAT_SHORTCUT
8807 {
8808 char_u *v = NULL;
8809
8810 v = mch_resolve_shortcut(p);
8811 if (v != NULL)
8812 rettv->vval.v_string = v;
8813 else
8814 rettv->vval.v_string = vim_strsave(p);
8815 }
8816#else
8817# ifdef HAVE_READLINK
8818 {
8819 char_u *cpy;
8820 int len;
8821 char_u *remain = NULL;
8822 char_u *q;
8823 int is_relative_to_current = FALSE;
8824 int has_trailing_pathsep = FALSE;
8825 int limit = 100;
8826
8827 p = vim_strsave(p);
8828
8829 if (p[0] == '.' && (vim_ispathsep(p[1])
8830 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8831 is_relative_to_current = TRUE;
8832
8833 len = STRLEN(p);
8834 if (len > 0 && after_pathsep(p, p + len))
8835 {
8836 has_trailing_pathsep = TRUE;
8837 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8838 }
8839
8840 q = getnextcomp(p);
8841 if (*q != NUL)
8842 {
8843 /* Separate the first path component in "p", and keep the
8844 * remainder (beginning with the path separator). */
8845 remain = vim_strsave(q - 1);
8846 q[-1] = NUL;
8847 }
8848
8849 buf = alloc(MAXPATHL + 1);
8850 if (buf == NULL)
8851 goto fail;
8852
8853 for (;;)
8854 {
8855 for (;;)
8856 {
8857 len = readlink((char *)p, (char *)buf, MAXPATHL);
8858 if (len <= 0)
8859 break;
8860 buf[len] = NUL;
8861
8862 if (limit-- == 0)
8863 {
8864 vim_free(p);
8865 vim_free(remain);
8866 EMSG(_("E655: Too many symbolic links (cycle?)"));
8867 rettv->vval.v_string = NULL;
8868 goto fail;
8869 }
8870
8871 /* Ensure that the result will have a trailing path separator
8872 * if the argument has one. */
8873 if (remain == NULL && has_trailing_pathsep)
8874 add_pathsep(buf);
8875
8876 /* Separate the first path component in the link value and
8877 * concatenate the remainders. */
8878 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8879 if (*q != NUL)
8880 {
8881 if (remain == NULL)
8882 remain = vim_strsave(q - 1);
8883 else
8884 {
8885 cpy = concat_str(q - 1, remain);
8886 if (cpy != NULL)
8887 {
8888 vim_free(remain);
8889 remain = cpy;
8890 }
8891 }
8892 q[-1] = NUL;
8893 }
8894
8895 q = gettail(p);
8896 if (q > p && *q == NUL)
8897 {
8898 /* Ignore trailing path separator. */
8899 q[-1] = NUL;
8900 q = gettail(p);
8901 }
8902 if (q > p && !mch_isFullName(buf))
8903 {
8904 /* symlink is relative to directory of argument */
8905 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
8906 if (cpy != NULL)
8907 {
8908 STRCPY(cpy, p);
8909 STRCPY(gettail(cpy), buf);
8910 vim_free(p);
8911 p = cpy;
8912 }
8913 }
8914 else
8915 {
8916 vim_free(p);
8917 p = vim_strsave(buf);
8918 }
8919 }
8920
8921 if (remain == NULL)
8922 break;
8923
8924 /* Append the first path component of "remain" to "p". */
8925 q = getnextcomp(remain + 1);
8926 len = q - remain - (*q != NUL);
8927 cpy = vim_strnsave(p, STRLEN(p) + len);
8928 if (cpy != NULL)
8929 {
8930 STRNCAT(cpy, remain, len);
8931 vim_free(p);
8932 p = cpy;
8933 }
8934 /* Shorten "remain". */
8935 if (*q != NUL)
8936 STRMOVE(remain, q - 1);
8937 else
8938 {
8939 vim_free(remain);
8940 remain = NULL;
8941 }
8942 }
8943
8944 /* If the result is a relative path name, make it explicitly relative to
8945 * the current directory if and only if the argument had this form. */
8946 if (!vim_ispathsep(*p))
8947 {
8948 if (is_relative_to_current
8949 && *p != NUL
8950 && !(p[0] == '.'
8951 && (p[1] == NUL
8952 || vim_ispathsep(p[1])
8953 || (p[1] == '.'
8954 && (p[2] == NUL
8955 || vim_ispathsep(p[2]))))))
8956 {
8957 /* Prepend "./". */
8958 cpy = concat_str((char_u *)"./", p);
8959 if (cpy != NULL)
8960 {
8961 vim_free(p);
8962 p = cpy;
8963 }
8964 }
8965 else if (!is_relative_to_current)
8966 {
8967 /* Strip leading "./". */
8968 q = p;
8969 while (q[0] == '.' && vim_ispathsep(q[1]))
8970 q += 2;
8971 if (q > p)
8972 STRMOVE(p, p + 2);
8973 }
8974 }
8975
8976 /* Ensure that the result will have no trailing path separator
8977 * if the argument had none. But keep "/" or "//". */
8978 if (!has_trailing_pathsep)
8979 {
8980 q = p + STRLEN(p);
8981 if (after_pathsep(p, q))
8982 *gettail_sep(p) = NUL;
8983 }
8984
8985 rettv->vval.v_string = p;
8986 }
8987# else
8988 rettv->vval.v_string = vim_strsave(p);
8989# endif
8990#endif
8991
8992 simplify_filename(rettv->vval.v_string);
8993
8994#ifdef HAVE_READLINK
8995fail:
8996 vim_free(buf);
8997#endif
8998 rettv->v_type = VAR_STRING;
8999}
9000
9001/*
9002 * "reverse({list})" function
9003 */
9004 static void
9005f_reverse(typval_T *argvars, typval_T *rettv)
9006{
9007 list_T *l;
9008 listitem_T *li, *ni;
9009
9010 if (argvars[0].v_type != VAR_LIST)
9011 EMSG2(_(e_listarg), "reverse()");
9012 else if ((l = argvars[0].vval.v_list) != NULL
9013 && !tv_check_lock(l->lv_lock,
9014 (char_u *)N_("reverse() argument"), TRUE))
9015 {
9016 li = l->lv_last;
9017 l->lv_first = l->lv_last = NULL;
9018 l->lv_len = 0;
9019 while (li != NULL)
9020 {
9021 ni = li->li_prev;
9022 list_append(l, li);
9023 li = ni;
9024 }
9025 rettv->vval.v_list = l;
9026 rettv->v_type = VAR_LIST;
9027 ++l->lv_refcount;
9028 l->lv_idx = l->lv_len - l->lv_idx - 1;
9029 }
9030}
9031
9032#define SP_NOMOVE 0x01 /* don't move cursor */
9033#define SP_REPEAT 0x02 /* repeat to find outer pair */
9034#define SP_RETCOUNT 0x04 /* return matchcount */
9035#define SP_SETPCMARK 0x08 /* set previous context mark */
9036#define SP_START 0x10 /* accept match at start position */
9037#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9038#define SP_END 0x40 /* leave cursor at end of match */
9039#define SP_COLUMN 0x80 /* start at cursor column */
9040
9041static int get_search_arg(typval_T *varp, int *flagsp);
9042
9043/*
9044 * Get flags for a search function.
9045 * Possibly sets "p_ws".
9046 * Returns BACKWARD, FORWARD or zero (for an error).
9047 */
9048 static int
9049get_search_arg(typval_T *varp, int *flagsp)
9050{
9051 int dir = FORWARD;
9052 char_u *flags;
9053 char_u nbuf[NUMBUFLEN];
9054 int mask;
9055
9056 if (varp->v_type != VAR_UNKNOWN)
9057 {
9058 flags = get_tv_string_buf_chk(varp, nbuf);
9059 if (flags == NULL)
9060 return 0; /* type error; errmsg already given */
9061 while (*flags != NUL)
9062 {
9063 switch (*flags)
9064 {
9065 case 'b': dir = BACKWARD; break;
9066 case 'w': p_ws = TRUE; break;
9067 case 'W': p_ws = FALSE; break;
9068 default: mask = 0;
9069 if (flagsp != NULL)
9070 switch (*flags)
9071 {
9072 case 'c': mask = SP_START; break;
9073 case 'e': mask = SP_END; break;
9074 case 'm': mask = SP_RETCOUNT; break;
9075 case 'n': mask = SP_NOMOVE; break;
9076 case 'p': mask = SP_SUBPAT; break;
9077 case 'r': mask = SP_REPEAT; break;
9078 case 's': mask = SP_SETPCMARK; break;
9079 case 'z': mask = SP_COLUMN; break;
9080 }
9081 if (mask == 0)
9082 {
9083 EMSG2(_(e_invarg2), flags);
9084 dir = 0;
9085 }
9086 else
9087 *flagsp |= mask;
9088 }
9089 if (dir == 0)
9090 break;
9091 ++flags;
9092 }
9093 }
9094 return dir;
9095}
9096
9097/*
9098 * Shared by search() and searchpos() functions.
9099 */
9100 static int
9101search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9102{
9103 int flags;
9104 char_u *pat;
9105 pos_T pos;
9106 pos_T save_cursor;
9107 int save_p_ws = p_ws;
9108 int dir;
9109 int retval = 0; /* default: FAIL */
9110 long lnum_stop = 0;
9111 proftime_T tm;
9112#ifdef FEAT_RELTIME
9113 long time_limit = 0;
9114#endif
9115 int options = SEARCH_KEEP;
9116 int subpatnum;
9117
9118 pat = get_tv_string(&argvars[0]);
9119 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9120 if (dir == 0)
9121 goto theend;
9122 flags = *flagsp;
9123 if (flags & SP_START)
9124 options |= SEARCH_START;
9125 if (flags & SP_END)
9126 options |= SEARCH_END;
9127 if (flags & SP_COLUMN)
9128 options |= SEARCH_COL;
9129
9130 /* Optional arguments: line number to stop searching and timeout. */
9131 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9132 {
9133 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9134 if (lnum_stop < 0)
9135 goto theend;
9136#ifdef FEAT_RELTIME
9137 if (argvars[3].v_type != VAR_UNKNOWN)
9138 {
9139 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9140 if (time_limit < 0)
9141 goto theend;
9142 }
9143#endif
9144 }
9145
9146#ifdef FEAT_RELTIME
9147 /* Set the time limit, if there is one. */
9148 profile_setlimit(time_limit, &tm);
9149#endif
9150
9151 /*
9152 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9153 * Check to make sure only those flags are set.
9154 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9155 * flags cannot be set. Check for that condition also.
9156 */
9157 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9158 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9159 {
9160 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9161 goto theend;
9162 }
9163
9164 pos = save_cursor = curwin->w_cursor;
9165 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
9166 options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
9167 if (subpatnum != FAIL)
9168 {
9169 if (flags & SP_SUBPAT)
9170 retval = subpatnum;
9171 else
9172 retval = pos.lnum;
9173 if (flags & SP_SETPCMARK)
9174 setpcmark();
9175 curwin->w_cursor = pos;
9176 if (match_pos != NULL)
9177 {
9178 /* Store the match cursor position */
9179 match_pos->lnum = pos.lnum;
9180 match_pos->col = pos.col + 1;
9181 }
9182 /* "/$" will put the cursor after the end of the line, may need to
9183 * correct that here */
9184 check_cursor();
9185 }
9186
9187 /* If 'n' flag is used: restore cursor position. */
9188 if (flags & SP_NOMOVE)
9189 curwin->w_cursor = save_cursor;
9190 else
9191 curwin->w_set_curswant = TRUE;
9192theend:
9193 p_ws = save_p_ws;
9194
9195 return retval;
9196}
9197
9198#ifdef FEAT_FLOAT
9199
9200/*
9201 * round() is not in C90, use ceil() or floor() instead.
9202 */
9203 float_T
9204vim_round(float_T f)
9205{
9206 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9207}
9208
9209/*
9210 * "round({float})" function
9211 */
9212 static void
9213f_round(typval_T *argvars, typval_T *rettv)
9214{
9215 float_T f = 0.0;
9216
9217 rettv->v_type = VAR_FLOAT;
9218 if (get_float_arg(argvars, &f) == OK)
9219 rettv->vval.v_float = vim_round(f);
9220 else
9221 rettv->vval.v_float = 0.0;
9222}
9223#endif
9224
9225/*
9226 * "screenattr()" function
9227 */
9228 static void
9229f_screenattr(typval_T *argvars, typval_T *rettv)
9230{
9231 int row;
9232 int col;
9233 int c;
9234
9235 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9236 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9237 if (row < 0 || row >= screen_Rows
9238 || col < 0 || col >= screen_Columns)
9239 c = -1;
9240 else
9241 c = ScreenAttrs[LineOffset[row] + col];
9242 rettv->vval.v_number = c;
9243}
9244
9245/*
9246 * "screenchar()" function
9247 */
9248 static void
9249f_screenchar(typval_T *argvars, typval_T *rettv)
9250{
9251 int row;
9252 int col;
9253 int off;
9254 int c;
9255
9256 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9257 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9258 if (row < 0 || row >= screen_Rows
9259 || col < 0 || col >= screen_Columns)
9260 c = -1;
9261 else
9262 {
9263 off = LineOffset[row] + col;
9264#ifdef FEAT_MBYTE
9265 if (enc_utf8 && ScreenLinesUC[off] != 0)
9266 c = ScreenLinesUC[off];
9267 else
9268#endif
9269 c = ScreenLines[off];
9270 }
9271 rettv->vval.v_number = c;
9272}
9273
9274/*
9275 * "screencol()" function
9276 *
9277 * First column is 1 to be consistent with virtcol().
9278 */
9279 static void
9280f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9281{
9282 rettv->vval.v_number = screen_screencol() + 1;
9283}
9284
9285/*
9286 * "screenrow()" function
9287 */
9288 static void
9289f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9290{
9291 rettv->vval.v_number = screen_screenrow() + 1;
9292}
9293
9294/*
9295 * "search()" function
9296 */
9297 static void
9298f_search(typval_T *argvars, typval_T *rettv)
9299{
9300 int flags = 0;
9301
9302 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9303}
9304
9305/*
9306 * "searchdecl()" function
9307 */
9308 static void
9309f_searchdecl(typval_T *argvars, typval_T *rettv)
9310{
9311 int locally = 1;
9312 int thisblock = 0;
9313 int error = FALSE;
9314 char_u *name;
9315
9316 rettv->vval.v_number = 1; /* default: FAIL */
9317
9318 name = get_tv_string_chk(&argvars[0]);
9319 if (argvars[1].v_type != VAR_UNKNOWN)
9320 {
9321 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9322 if (!error && argvars[2].v_type != VAR_UNKNOWN)
9323 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9324 }
9325 if (!error && name != NULL)
9326 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9327 locally, thisblock, SEARCH_KEEP) == FAIL;
9328}
9329
9330/*
9331 * Used by searchpair() and searchpairpos()
9332 */
9333 static int
9334searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9335{
9336 char_u *spat, *mpat, *epat;
9337 char_u *skip;
9338 int save_p_ws = p_ws;
9339 int dir;
9340 int flags = 0;
9341 char_u nbuf1[NUMBUFLEN];
9342 char_u nbuf2[NUMBUFLEN];
9343 char_u nbuf3[NUMBUFLEN];
9344 int retval = 0; /* default: FAIL */
9345 long lnum_stop = 0;
9346 long time_limit = 0;
9347
9348 /* Get the three pattern arguments: start, middle, end. */
9349 spat = get_tv_string_chk(&argvars[0]);
9350 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9351 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9352 if (spat == NULL || mpat == NULL || epat == NULL)
9353 goto theend; /* type error */
9354
9355 /* Handle the optional fourth argument: flags */
9356 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9357 if (dir == 0)
9358 goto theend;
9359
9360 /* Don't accept SP_END or SP_SUBPAT.
9361 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9362 */
9363 if ((flags & (SP_END | SP_SUBPAT)) != 0
9364 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9365 {
9366 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9367 goto theend;
9368 }
9369
9370 /* Using 'r' implies 'W', otherwise it doesn't work. */
9371 if (flags & SP_REPEAT)
9372 p_ws = FALSE;
9373
9374 /* Optional fifth argument: skip expression */
9375 if (argvars[3].v_type == VAR_UNKNOWN
9376 || argvars[4].v_type == VAR_UNKNOWN)
9377 skip = (char_u *)"";
9378 else
9379 {
9380 skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
9381 if (argvars[5].v_type != VAR_UNKNOWN)
9382 {
9383 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9384 if (lnum_stop < 0)
9385 goto theend;
9386#ifdef FEAT_RELTIME
9387 if (argvars[6].v_type != VAR_UNKNOWN)
9388 {
9389 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9390 if (time_limit < 0)
9391 goto theend;
9392 }
9393#endif
9394 }
9395 }
9396 if (skip == NULL)
9397 goto theend; /* type error */
9398
9399 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9400 match_pos, lnum_stop, time_limit);
9401
9402theend:
9403 p_ws = save_p_ws;
9404
9405 return retval;
9406}
9407
9408/*
9409 * "searchpair()" function
9410 */
9411 static void
9412f_searchpair(typval_T *argvars, typval_T *rettv)
9413{
9414 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9415}
9416
9417/*
9418 * "searchpairpos()" function
9419 */
9420 static void
9421f_searchpairpos(typval_T *argvars, typval_T *rettv)
9422{
9423 pos_T match_pos;
9424 int lnum = 0;
9425 int col = 0;
9426
9427 if (rettv_list_alloc(rettv) == FAIL)
9428 return;
9429
9430 if (searchpair_cmn(argvars, &match_pos) > 0)
9431 {
9432 lnum = match_pos.lnum;
9433 col = match_pos.col;
9434 }
9435
9436 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9437 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9438}
9439
9440/*
9441 * Search for a start/middle/end thing.
9442 * Used by searchpair(), see its documentation for the details.
9443 * Returns 0 or -1 for no match,
9444 */
9445 long
9446do_searchpair(
9447 char_u *spat, /* start pattern */
9448 char_u *mpat, /* middle pattern */
9449 char_u *epat, /* end pattern */
9450 int dir, /* BACKWARD or FORWARD */
9451 char_u *skip, /* skip expression */
9452 int flags, /* SP_SETPCMARK and other SP_ values */
9453 pos_T *match_pos,
9454 linenr_T lnum_stop, /* stop at this line if not zero */
9455 long time_limit UNUSED) /* stop after this many msec */
9456{
9457 char_u *save_cpo;
9458 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9459 long retval = 0;
9460 pos_T pos;
9461 pos_T firstpos;
9462 pos_T foundpos;
9463 pos_T save_cursor;
9464 pos_T save_pos;
9465 int n;
9466 int r;
9467 int nest = 1;
9468 int err;
9469 int options = SEARCH_KEEP;
9470 proftime_T tm;
9471
9472 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9473 save_cpo = p_cpo;
9474 p_cpo = empty_option;
9475
9476#ifdef FEAT_RELTIME
9477 /* Set the time limit, if there is one. */
9478 profile_setlimit(time_limit, &tm);
9479#endif
9480
9481 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9482 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009483 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9484 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009485 if (pat2 == NULL || pat3 == NULL)
9486 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009487 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009488 if (*mpat == NUL)
9489 STRCPY(pat3, pat2);
9490 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009491 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492 spat, epat, mpat);
9493 if (flags & SP_START)
9494 options |= SEARCH_START;
9495
9496 save_cursor = curwin->w_cursor;
9497 pos = curwin->w_cursor;
9498 clearpos(&firstpos);
9499 clearpos(&foundpos);
9500 pat = pat3;
9501 for (;;)
9502 {
9503 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
9504 options, RE_SEARCH, lnum_stop, &tm);
9505 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
9506 /* didn't find it or found the first match again: FAIL */
9507 break;
9508
9509 if (firstpos.lnum == 0)
9510 firstpos = pos;
9511 if (equalpos(pos, foundpos))
9512 {
9513 /* Found the same position again. Can happen with a pattern that
9514 * has "\zs" at the end and searching backwards. Advance one
9515 * character and try again. */
9516 if (dir == BACKWARD)
9517 decl(&pos);
9518 else
9519 incl(&pos);
9520 }
9521 foundpos = pos;
9522
9523 /* clear the start flag to avoid getting stuck here */
9524 options &= ~SEARCH_START;
9525
9526 /* If the skip pattern matches, ignore this match. */
9527 if (*skip != NUL)
9528 {
9529 save_pos = curwin->w_cursor;
9530 curwin->w_cursor = pos;
9531 r = eval_to_bool(skip, &err, NULL, FALSE);
9532 curwin->w_cursor = save_pos;
9533 if (err)
9534 {
9535 /* Evaluating {skip} caused an error, break here. */
9536 curwin->w_cursor = save_cursor;
9537 retval = -1;
9538 break;
9539 }
9540 if (r)
9541 continue;
9542 }
9543
9544 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9545 {
9546 /* Found end when searching backwards or start when searching
9547 * forward: nested pair. */
9548 ++nest;
9549 pat = pat2; /* nested, don't search for middle */
9550 }
9551 else
9552 {
9553 /* Found end when searching forward or start when searching
9554 * backward: end of (nested) pair; or found middle in outer pair. */
9555 if (--nest == 1)
9556 pat = pat3; /* outer level, search for middle */
9557 }
9558
9559 if (nest == 0)
9560 {
9561 /* Found the match: return matchcount or line number. */
9562 if (flags & SP_RETCOUNT)
9563 ++retval;
9564 else
9565 retval = pos.lnum;
9566 if (flags & SP_SETPCMARK)
9567 setpcmark();
9568 curwin->w_cursor = pos;
9569 if (!(flags & SP_REPEAT))
9570 break;
9571 nest = 1; /* search for next unmatched */
9572 }
9573 }
9574
9575 if (match_pos != NULL)
9576 {
9577 /* Store the match cursor position */
9578 match_pos->lnum = curwin->w_cursor.lnum;
9579 match_pos->col = curwin->w_cursor.col + 1;
9580 }
9581
9582 /* If 'n' flag is used or search failed: restore cursor position. */
9583 if ((flags & SP_NOMOVE) || retval == 0)
9584 curwin->w_cursor = save_cursor;
9585
9586theend:
9587 vim_free(pat2);
9588 vim_free(pat3);
9589 if (p_cpo == empty_option)
9590 p_cpo = save_cpo;
9591 else
9592 /* Darn, evaluating the {skip} expression changed the value. */
9593 free_string_option(save_cpo);
9594
9595 return retval;
9596}
9597
9598/*
9599 * "searchpos()" function
9600 */
9601 static void
9602f_searchpos(typval_T *argvars, typval_T *rettv)
9603{
9604 pos_T match_pos;
9605 int lnum = 0;
9606 int col = 0;
9607 int n;
9608 int flags = 0;
9609
9610 if (rettv_list_alloc(rettv) == FAIL)
9611 return;
9612
9613 n = search_cmn(argvars, &match_pos, &flags);
9614 if (n > 0)
9615 {
9616 lnum = match_pos.lnum;
9617 col = match_pos.col;
9618 }
9619
9620 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9621 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9622 if (flags & SP_SUBPAT)
9623 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9624}
9625
9626 static void
9627f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9628{
9629#ifdef FEAT_CLIENTSERVER
9630 char_u buf[NUMBUFLEN];
9631 char_u *server = get_tv_string_chk(&argvars[0]);
9632 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9633
9634 rettv->vval.v_number = -1;
9635 if (server == NULL || reply == NULL)
9636 return;
9637 if (check_restricted() || check_secure())
9638 return;
9639# ifdef FEAT_X11
9640 if (check_connection() == FAIL)
9641 return;
9642# endif
9643
9644 if (serverSendReply(server, reply) < 0)
9645 {
9646 EMSG(_("E258: Unable to send to client"));
9647 return;
9648 }
9649 rettv->vval.v_number = 0;
9650#else
9651 rettv->vval.v_number = -1;
9652#endif
9653}
9654
9655 static void
9656f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9657{
9658 char_u *r = NULL;
9659
9660#ifdef FEAT_CLIENTSERVER
9661# ifdef WIN32
9662 r = serverGetVimNames();
9663# else
9664 make_connection();
9665 if (X_DISPLAY != NULL)
9666 r = serverGetVimNames(X_DISPLAY);
9667# endif
9668#endif
9669 rettv->v_type = VAR_STRING;
9670 rettv->vval.v_string = r;
9671}
9672
9673/*
9674 * "setbufvar()" function
9675 */
9676 static void
9677f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9678{
9679 buf_T *buf;
9680 char_u *varname, *bufvarname;
9681 typval_T *varp;
9682 char_u nbuf[NUMBUFLEN];
9683
9684 if (check_restricted() || check_secure())
9685 return;
9686 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
9687 varname = get_tv_string_chk(&argvars[1]);
9688 buf = get_buf_tv(&argvars[0], FALSE);
9689 varp = &argvars[2];
9690
9691 if (buf != NULL && varname != NULL && varp != NULL)
9692 {
9693 if (*varname == '&')
9694 {
9695 long numval;
9696 char_u *strval;
9697 int error = FALSE;
9698 aco_save_T aco;
9699
9700 /* set curbuf to be our buf, temporarily */
9701 aucmd_prepbuf(&aco, buf);
9702
9703 ++varname;
9704 numval = (long)get_tv_number_chk(varp, &error);
9705 strval = get_tv_string_buf_chk(varp, nbuf);
9706 if (!error && strval != NULL)
9707 set_option_value(varname, numval, strval, OPT_LOCAL);
9708
9709 /* reset notion of buffer */
9710 aucmd_restbuf(&aco);
9711 }
9712 else
9713 {
9714 buf_T *save_curbuf = curbuf;
9715
9716 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
9717 if (bufvarname != NULL)
9718 {
9719 curbuf = buf;
9720 STRCPY(bufvarname, "b:");
9721 STRCPY(bufvarname + 2, varname);
9722 set_var(bufvarname, varp, TRUE);
9723 vim_free(bufvarname);
9724 curbuf = save_curbuf;
9725 }
9726 }
9727 }
9728}
9729
9730 static void
9731f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9732{
9733 dict_T *d;
9734 dictitem_T *di;
9735 char_u *csearch;
9736
9737 if (argvars[0].v_type != VAR_DICT)
9738 {
9739 EMSG(_(e_dictreq));
9740 return;
9741 }
9742
9743 if ((d = argvars[0].vval.v_dict) != NULL)
9744 {
9745 csearch = get_dict_string(d, (char_u *)"char", FALSE);
9746 if (csearch != NULL)
9747 {
9748#ifdef FEAT_MBYTE
9749 if (enc_utf8)
9750 {
9751 int pcc[MAX_MCO];
9752 int c = utfc_ptr2char(csearch, pcc);
9753
9754 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9755 }
9756 else
9757#endif
9758 set_last_csearch(PTR2CHAR(csearch),
9759 csearch, MB_PTR2LEN(csearch));
9760 }
9761
9762 di = dict_find(d, (char_u *)"forward", -1);
9763 if (di != NULL)
9764 set_csearch_direction((int)get_tv_number(&di->di_tv)
9765 ? FORWARD : BACKWARD);
9766
9767 di = dict_find(d, (char_u *)"until", -1);
9768 if (di != NULL)
9769 set_csearch_until(!!get_tv_number(&di->di_tv));
9770 }
9771}
9772
9773/*
9774 * "setcmdpos()" function
9775 */
9776 static void
9777f_setcmdpos(typval_T *argvars, typval_T *rettv)
9778{
9779 int pos = (int)get_tv_number(&argvars[0]) - 1;
9780
9781 if (pos >= 0)
9782 rettv->vval.v_number = set_cmdline_pos(pos);
9783}
9784
9785/*
9786 * "setfperm({fname}, {mode})" function
9787 */
9788 static void
9789f_setfperm(typval_T *argvars, typval_T *rettv)
9790{
9791 char_u *fname;
9792 char_u modebuf[NUMBUFLEN];
9793 char_u *mode_str;
9794 int i;
9795 int mask;
9796 int mode = 0;
9797
9798 rettv->vval.v_number = 0;
9799 fname = get_tv_string_chk(&argvars[0]);
9800 if (fname == NULL)
9801 return;
9802 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
9803 if (mode_str == NULL)
9804 return;
9805 if (STRLEN(mode_str) != 9)
9806 {
9807 EMSG2(_(e_invarg2), mode_str);
9808 return;
9809 }
9810
9811 mask = 1;
9812 for (i = 8; i >= 0; --i)
9813 {
9814 if (mode_str[i] != '-')
9815 mode |= mask;
9816 mask = mask << 1;
9817 }
9818 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9819}
9820
9821/*
9822 * "setline()" function
9823 */
9824 static void
9825f_setline(typval_T *argvars, typval_T *rettv)
9826{
9827 linenr_T lnum;
9828 char_u *line = NULL;
9829 list_T *l = NULL;
9830 listitem_T *li = NULL;
9831 long added = 0;
9832 linenr_T lcount = curbuf->b_ml.ml_line_count;
9833
9834 lnum = get_tv_lnum(&argvars[0]);
9835 if (argvars[1].v_type == VAR_LIST)
9836 {
9837 l = argvars[1].vval.v_list;
9838 li = l->lv_first;
9839 }
9840 else
9841 line = get_tv_string_chk(&argvars[1]);
9842
9843 /* default result is zero == OK */
9844 for (;;)
9845 {
9846 if (l != NULL)
9847 {
9848 /* list argument, get next string */
9849 if (li == NULL)
9850 break;
9851 line = get_tv_string_chk(&li->li_tv);
9852 li = li->li_next;
9853 }
9854
9855 rettv->vval.v_number = 1; /* FAIL */
9856 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
9857 break;
9858
9859 /* When coming here from Insert mode, sync undo, so that this can be
9860 * undone separately from what was previously inserted. */
9861 if (u_sync_once == 2)
9862 {
9863 u_sync_once = 1; /* notify that u_sync() was called */
9864 u_sync(TRUE);
9865 }
9866
9867 if (lnum <= curbuf->b_ml.ml_line_count)
9868 {
9869 /* existing line, replace it */
9870 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
9871 {
9872 changed_bytes(lnum, 0);
9873 if (lnum == curwin->w_cursor.lnum)
9874 check_cursor_col();
9875 rettv->vval.v_number = 0; /* OK */
9876 }
9877 }
9878 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
9879 {
9880 /* lnum is one past the last line, append the line */
9881 ++added;
9882 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
9883 rettv->vval.v_number = 0; /* OK */
9884 }
9885
9886 if (l == NULL) /* only one string argument */
9887 break;
9888 ++lnum;
9889 }
9890
9891 if (added > 0)
9892 appended_lines_mark(lcount, added);
9893}
9894
Bram Moolenaard823fa92016-08-12 16:29:27 +02009895static 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 +02009896
9897/*
9898 * Used by "setqflist()" and "setloclist()" functions
9899 */
9900 static void
9901set_qf_ll_list(
9902 win_T *wp UNUSED,
9903 typval_T *list_arg UNUSED,
9904 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +02009905 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009906 typval_T *rettv)
9907{
9908#ifdef FEAT_QUICKFIX
9909 static char *e_invact = N_("E927: Invalid action: '%s'");
9910 char_u *act;
9911 int action = 0;
9912#endif
9913
9914 rettv->vval.v_number = -1;
9915
9916#ifdef FEAT_QUICKFIX
9917 if (list_arg->v_type != VAR_LIST)
9918 EMSG(_(e_listreq));
9919 else
9920 {
9921 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +02009922 dict_T *d = NULL;
9923 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009924
9925 if (action_arg->v_type == VAR_STRING)
9926 {
9927 act = get_tv_string_chk(action_arg);
9928 if (act == NULL)
9929 return; /* type error; errmsg already given */
9930 if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL)
9931 action = *act;
9932 else
9933 EMSG2(_(e_invact), act);
9934 }
9935 else if (action_arg->v_type == VAR_UNKNOWN)
9936 action = ' ';
9937 else
9938 EMSG(_(e_stringreq));
9939
Bram Moolenaard823fa92016-08-12 16:29:27 +02009940 if (action_arg->v_type != VAR_UNKNOWN
9941 && what_arg->v_type != VAR_UNKNOWN)
9942 {
9943 if (what_arg->v_type == VAR_DICT)
9944 d = what_arg->vval.v_dict;
9945 else
9946 {
9947 EMSG(_(e_dictreq));
9948 valid_dict = FALSE;
9949 }
9950 }
9951
9952 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
9953 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009954 rettv->vval.v_number = 0;
9955 }
9956#endif
9957}
9958
9959/*
9960 * "setloclist()" function
9961 */
9962 static void
9963f_setloclist(typval_T *argvars, typval_T *rettv)
9964{
9965 win_T *win;
9966
9967 rettv->vval.v_number = -1;
9968
9969 win = find_win_by_nr(&argvars[0], NULL);
9970 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +02009971 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009972}
9973
9974/*
9975 * "setmatches()" function
9976 */
9977 static void
9978f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9979{
9980#ifdef FEAT_SEARCH_EXTRA
9981 list_T *l;
9982 listitem_T *li;
9983 dict_T *d;
9984 list_T *s = NULL;
9985
9986 rettv->vval.v_number = -1;
9987 if (argvars[0].v_type != VAR_LIST)
9988 {
9989 EMSG(_(e_listreq));
9990 return;
9991 }
9992 if ((l = argvars[0].vval.v_list) != NULL)
9993 {
9994
9995 /* To some extent make sure that we are dealing with a list from
9996 * "getmatches()". */
9997 li = l->lv_first;
9998 while (li != NULL)
9999 {
10000 if (li->li_tv.v_type != VAR_DICT
10001 || (d = li->li_tv.vval.v_dict) == NULL)
10002 {
10003 EMSG(_(e_invarg));
10004 return;
10005 }
10006 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10007 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10008 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10009 && dict_find(d, (char_u *)"priority", -1) != NULL
10010 && dict_find(d, (char_u *)"id", -1) != NULL))
10011 {
10012 EMSG(_(e_invarg));
10013 return;
10014 }
10015 li = li->li_next;
10016 }
10017
10018 clear_matches(curwin);
10019 li = l->lv_first;
10020 while (li != NULL)
10021 {
10022 int i = 0;
10023 char_u buf[5];
10024 dictitem_T *di;
10025 char_u *group;
10026 int priority;
10027 int id;
10028 char_u *conceal;
10029
10030 d = li->li_tv.vval.v_dict;
10031 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10032 {
10033 if (s == NULL)
10034 {
10035 s = list_alloc();
10036 if (s == NULL)
10037 return;
10038 }
10039
10040 /* match from matchaddpos() */
10041 for (i = 1; i < 9; i++)
10042 {
10043 sprintf((char *)buf, (char *)"pos%d", i);
10044 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10045 {
10046 if (di->di_tv.v_type != VAR_LIST)
10047 return;
10048
10049 list_append_tv(s, &di->di_tv);
10050 s->lv_refcount++;
10051 }
10052 else
10053 break;
10054 }
10055 }
10056
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010057 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010058 priority = (int)get_dict_number(d, (char_u *)"priority");
10059 id = (int)get_dict_number(d, (char_u *)"id");
10060 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010061 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010062 : NULL;
10063 if (i == 0)
10064 {
10065 match_add(curwin, group,
10066 get_dict_string(d, (char_u *)"pattern", FALSE),
10067 priority, id, NULL, conceal);
10068 }
10069 else
10070 {
10071 match_add(curwin, group, NULL, priority, id, s, conceal);
10072 list_unref(s);
10073 s = NULL;
10074 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010075 vim_free(group);
10076 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010077
10078 li = li->li_next;
10079 }
10080 rettv->vval.v_number = 0;
10081 }
10082#endif
10083}
10084
10085/*
10086 * "setpos()" function
10087 */
10088 static void
10089f_setpos(typval_T *argvars, typval_T *rettv)
10090{
10091 pos_T pos;
10092 int fnum;
10093 char_u *name;
10094 colnr_T curswant = -1;
10095
10096 rettv->vval.v_number = -1;
10097 name = get_tv_string_chk(argvars);
10098 if (name != NULL)
10099 {
10100 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10101 {
10102 if (--pos.col < 0)
10103 pos.col = 0;
10104 if (name[0] == '.' && name[1] == NUL)
10105 {
10106 /* set cursor */
10107 if (fnum == curbuf->b_fnum)
10108 {
10109 curwin->w_cursor = pos;
10110 if (curswant >= 0)
10111 {
10112 curwin->w_curswant = curswant - 1;
10113 curwin->w_set_curswant = FALSE;
10114 }
10115 check_cursor();
10116 rettv->vval.v_number = 0;
10117 }
10118 else
10119 EMSG(_(e_invarg));
10120 }
10121 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10122 {
10123 /* set mark */
10124 if (setmark_pos(name[1], &pos, fnum) == OK)
10125 rettv->vval.v_number = 0;
10126 }
10127 else
10128 EMSG(_(e_invarg));
10129 }
10130 }
10131}
10132
10133/*
10134 * "setqflist()" function
10135 */
10136 static void
10137f_setqflist(typval_T *argvars, typval_T *rettv)
10138{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010139 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010140}
10141
10142/*
10143 * "setreg()" function
10144 */
10145 static void
10146f_setreg(typval_T *argvars, typval_T *rettv)
10147{
10148 int regname;
10149 char_u *strregname;
10150 char_u *stropt;
10151 char_u *strval;
10152 int append;
10153 char_u yank_type;
10154 long block_len;
10155
10156 block_len = -1;
10157 yank_type = MAUTO;
10158 append = FALSE;
10159
10160 strregname = get_tv_string_chk(argvars);
10161 rettv->vval.v_number = 1; /* FAIL is default */
10162
10163 if (strregname == NULL)
10164 return; /* type error; errmsg already given */
10165 regname = *strregname;
10166 if (regname == 0 || regname == '@')
10167 regname = '"';
10168
10169 if (argvars[2].v_type != VAR_UNKNOWN)
10170 {
10171 stropt = get_tv_string_chk(&argvars[2]);
10172 if (stropt == NULL)
10173 return; /* type error */
10174 for (; *stropt != NUL; ++stropt)
10175 switch (*stropt)
10176 {
10177 case 'a': case 'A': /* append */
10178 append = TRUE;
10179 break;
10180 case 'v': case 'c': /* character-wise selection */
10181 yank_type = MCHAR;
10182 break;
10183 case 'V': case 'l': /* line-wise selection */
10184 yank_type = MLINE;
10185 break;
10186 case 'b': case Ctrl_V: /* block-wise selection */
10187 yank_type = MBLOCK;
10188 if (VIM_ISDIGIT(stropt[1]))
10189 {
10190 ++stropt;
10191 block_len = getdigits(&stropt) - 1;
10192 --stropt;
10193 }
10194 break;
10195 }
10196 }
10197
10198 if (argvars[1].v_type == VAR_LIST)
10199 {
10200 char_u **lstval;
10201 char_u **allocval;
10202 char_u buf[NUMBUFLEN];
10203 char_u **curval;
10204 char_u **curallocval;
10205 list_T *ll = argvars[1].vval.v_list;
10206 listitem_T *li;
10207 int len;
10208
10209 /* If the list is NULL handle like an empty list. */
10210 len = ll == NULL ? 0 : ll->lv_len;
10211
10212 /* First half: use for pointers to result lines; second half: use for
10213 * pointers to allocated copies. */
10214 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10215 if (lstval == NULL)
10216 return;
10217 curval = lstval;
10218 allocval = lstval + len + 2;
10219 curallocval = allocval;
10220
10221 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10222 li = li->li_next)
10223 {
10224 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10225 if (strval == NULL)
10226 goto free_lstval;
10227 if (strval == buf)
10228 {
10229 /* Need to make a copy, next get_tv_string_buf_chk() will
10230 * overwrite the string. */
10231 strval = vim_strsave(buf);
10232 if (strval == NULL)
10233 goto free_lstval;
10234 *curallocval++ = strval;
10235 }
10236 *curval++ = strval;
10237 }
10238 *curval++ = NULL;
10239
10240 write_reg_contents_lst(regname, lstval, -1,
10241 append, yank_type, block_len);
10242free_lstval:
10243 while (curallocval > allocval)
10244 vim_free(*--curallocval);
10245 vim_free(lstval);
10246 }
10247 else
10248 {
10249 strval = get_tv_string_chk(&argvars[1]);
10250 if (strval == NULL)
10251 return;
10252 write_reg_contents_ex(regname, strval, -1,
10253 append, yank_type, block_len);
10254 }
10255 rettv->vval.v_number = 0;
10256}
10257
10258/*
10259 * "settabvar()" function
10260 */
10261 static void
10262f_settabvar(typval_T *argvars, typval_T *rettv)
10263{
10264#ifdef FEAT_WINDOWS
10265 tabpage_T *save_curtab;
10266 tabpage_T *tp;
10267#endif
10268 char_u *varname, *tabvarname;
10269 typval_T *varp;
10270
10271 rettv->vval.v_number = 0;
10272
10273 if (check_restricted() || check_secure())
10274 return;
10275
10276#ifdef FEAT_WINDOWS
10277 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
10278#endif
10279 varname = get_tv_string_chk(&argvars[1]);
10280 varp = &argvars[2];
10281
10282 if (varname != NULL && varp != NULL
10283#ifdef FEAT_WINDOWS
10284 && tp != NULL
10285#endif
10286 )
10287 {
10288#ifdef FEAT_WINDOWS
10289 save_curtab = curtab;
10290 goto_tabpage_tp(tp, FALSE, FALSE);
10291#endif
10292
10293 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10294 if (tabvarname != NULL)
10295 {
10296 STRCPY(tabvarname, "t:");
10297 STRCPY(tabvarname + 2, varname);
10298 set_var(tabvarname, varp, TRUE);
10299 vim_free(tabvarname);
10300 }
10301
10302#ifdef FEAT_WINDOWS
10303 /* Restore current tabpage */
10304 if (valid_tabpage(save_curtab))
10305 goto_tabpage_tp(save_curtab, FALSE, FALSE);
10306#endif
10307 }
10308}
10309
10310/*
10311 * "settabwinvar()" function
10312 */
10313 static void
10314f_settabwinvar(typval_T *argvars, typval_T *rettv)
10315{
10316 setwinvar(argvars, rettv, 1);
10317}
10318
10319/*
10320 * "setwinvar()" function
10321 */
10322 static void
10323f_setwinvar(typval_T *argvars, typval_T *rettv)
10324{
10325 setwinvar(argvars, rettv, 0);
10326}
10327
10328#ifdef FEAT_CRYPT
10329/*
10330 * "sha256({string})" function
10331 */
10332 static void
10333f_sha256(typval_T *argvars, typval_T *rettv)
10334{
10335 char_u *p;
10336
10337 p = get_tv_string(&argvars[0]);
10338 rettv->vval.v_string = vim_strsave(
10339 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10340 rettv->v_type = VAR_STRING;
10341}
10342#endif /* FEAT_CRYPT */
10343
10344/*
10345 * "shellescape({string})" function
10346 */
10347 static void
10348f_shellescape(typval_T *argvars, typval_T *rettv)
10349{
10350 rettv->vval.v_string = vim_strsave_shellescape(
10351 get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE);
10352 rettv->v_type = VAR_STRING;
10353}
10354
10355/*
10356 * shiftwidth() function
10357 */
10358 static void
10359f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10360{
10361 rettv->vval.v_number = get_sw_value(curbuf);
10362}
10363
10364/*
10365 * "simplify()" function
10366 */
10367 static void
10368f_simplify(typval_T *argvars, typval_T *rettv)
10369{
10370 char_u *p;
10371
10372 p = get_tv_string(&argvars[0]);
10373 rettv->vval.v_string = vim_strsave(p);
10374 simplify_filename(rettv->vval.v_string); /* simplify in place */
10375 rettv->v_type = VAR_STRING;
10376}
10377
10378#ifdef FEAT_FLOAT
10379/*
10380 * "sin()" function
10381 */
10382 static void
10383f_sin(typval_T *argvars, typval_T *rettv)
10384{
10385 float_T f = 0.0;
10386
10387 rettv->v_type = VAR_FLOAT;
10388 if (get_float_arg(argvars, &f) == OK)
10389 rettv->vval.v_float = sin(f);
10390 else
10391 rettv->vval.v_float = 0.0;
10392}
10393
10394/*
10395 * "sinh()" function
10396 */
10397 static void
10398f_sinh(typval_T *argvars, typval_T *rettv)
10399{
10400 float_T f = 0.0;
10401
10402 rettv->v_type = VAR_FLOAT;
10403 if (get_float_arg(argvars, &f) == OK)
10404 rettv->vval.v_float = sinh(f);
10405 else
10406 rettv->vval.v_float = 0.0;
10407}
10408#endif
10409
10410static int
10411#ifdef __BORLANDC__
10412 _RTLENTRYF
10413#endif
10414 item_compare(const void *s1, const void *s2);
10415static int
10416#ifdef __BORLANDC__
10417 _RTLENTRYF
10418#endif
10419 item_compare2(const void *s1, const void *s2);
10420
10421/* struct used in the array that's given to qsort() */
10422typedef struct
10423{
10424 listitem_T *item;
10425 int idx;
10426} sortItem_T;
10427
10428/* struct storing information about current sort */
10429typedef struct
10430{
10431 int item_compare_ic;
10432 int item_compare_numeric;
10433 int item_compare_numbers;
10434#ifdef FEAT_FLOAT
10435 int item_compare_float;
10436#endif
10437 char_u *item_compare_func;
10438 partial_T *item_compare_partial;
10439 dict_T *item_compare_selfdict;
10440 int item_compare_func_err;
10441 int item_compare_keep_zero;
10442} sortinfo_T;
10443static sortinfo_T *sortinfo = NULL;
10444static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10445#define ITEM_COMPARE_FAIL 999
10446
10447/*
10448 * Compare functions for f_sort() and f_uniq() below.
10449 */
10450 static int
10451#ifdef __BORLANDC__
10452_RTLENTRYF
10453#endif
10454item_compare(const void *s1, const void *s2)
10455{
10456 sortItem_T *si1, *si2;
10457 typval_T *tv1, *tv2;
10458 char_u *p1, *p2;
10459 char_u *tofree1 = NULL, *tofree2 = NULL;
10460 int res;
10461 char_u numbuf1[NUMBUFLEN];
10462 char_u numbuf2[NUMBUFLEN];
10463
10464 si1 = (sortItem_T *)s1;
10465 si2 = (sortItem_T *)s2;
10466 tv1 = &si1->item->li_tv;
10467 tv2 = &si2->item->li_tv;
10468
10469 if (sortinfo->item_compare_numbers)
10470 {
10471 varnumber_T v1 = get_tv_number(tv1);
10472 varnumber_T v2 = get_tv_number(tv2);
10473
10474 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10475 }
10476
10477#ifdef FEAT_FLOAT
10478 if (sortinfo->item_compare_float)
10479 {
10480 float_T v1 = get_tv_float(tv1);
10481 float_T v2 = get_tv_float(tv2);
10482
10483 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10484 }
10485#endif
10486
10487 /* tv2string() puts quotes around a string and allocates memory. Don't do
10488 * that for string variables. Use a single quote when comparing with a
10489 * non-string to do what the docs promise. */
10490 if (tv1->v_type == VAR_STRING)
10491 {
10492 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10493 p1 = (char_u *)"'";
10494 else
10495 p1 = tv1->vval.v_string;
10496 }
10497 else
10498 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10499 if (tv2->v_type == VAR_STRING)
10500 {
10501 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10502 p2 = (char_u *)"'";
10503 else
10504 p2 = tv2->vval.v_string;
10505 }
10506 else
10507 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10508 if (p1 == NULL)
10509 p1 = (char_u *)"";
10510 if (p2 == NULL)
10511 p2 = (char_u *)"";
10512 if (!sortinfo->item_compare_numeric)
10513 {
10514 if (sortinfo->item_compare_ic)
10515 res = STRICMP(p1, p2);
10516 else
10517 res = STRCMP(p1, p2);
10518 }
10519 else
10520 {
10521 double n1, n2;
10522 n1 = strtod((char *)p1, (char **)&p1);
10523 n2 = strtod((char *)p2, (char **)&p2);
10524 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10525 }
10526
10527 /* When the result would be zero, compare the item indexes. Makes the
10528 * sort stable. */
10529 if (res == 0 && !sortinfo->item_compare_keep_zero)
10530 res = si1->idx > si2->idx ? 1 : -1;
10531
10532 vim_free(tofree1);
10533 vim_free(tofree2);
10534 return res;
10535}
10536
10537 static int
10538#ifdef __BORLANDC__
10539_RTLENTRYF
10540#endif
10541item_compare2(const void *s1, const void *s2)
10542{
10543 sortItem_T *si1, *si2;
10544 int res;
10545 typval_T rettv;
10546 typval_T argv[3];
10547 int dummy;
10548 char_u *func_name;
10549 partial_T *partial = sortinfo->item_compare_partial;
10550
10551 /* shortcut after failure in previous call; compare all items equal */
10552 if (sortinfo->item_compare_func_err)
10553 return 0;
10554
10555 si1 = (sortItem_T *)s1;
10556 si2 = (sortItem_T *)s2;
10557
10558 if (partial == NULL)
10559 func_name = sortinfo->item_compare_func;
10560 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010561 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010562
10563 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10564 * in the copy without changing the original list items. */
10565 copy_tv(&si1->item->li_tv, &argv[0]);
10566 copy_tv(&si2->item->li_tv, &argv[1]);
10567
10568 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10569 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010570 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010571 partial, sortinfo->item_compare_selfdict);
10572 clear_tv(&argv[0]);
10573 clear_tv(&argv[1]);
10574
10575 if (res == FAIL)
10576 res = ITEM_COMPARE_FAIL;
10577 else
10578 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10579 if (sortinfo->item_compare_func_err)
10580 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10581 clear_tv(&rettv);
10582
10583 /* When the result would be zero, compare the pointers themselves. Makes
10584 * the sort stable. */
10585 if (res == 0 && !sortinfo->item_compare_keep_zero)
10586 res = si1->idx > si2->idx ? 1 : -1;
10587
10588 return res;
10589}
10590
10591/*
10592 * "sort({list})" function
10593 */
10594 static void
10595do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10596{
10597 list_T *l;
10598 listitem_T *li;
10599 sortItem_T *ptrs;
10600 sortinfo_T *old_sortinfo;
10601 sortinfo_T info;
10602 long len;
10603 long i;
10604
10605 /* Pointer to current info struct used in compare function. Save and
10606 * restore the current one for nested calls. */
10607 old_sortinfo = sortinfo;
10608 sortinfo = &info;
10609
10610 if (argvars[0].v_type != VAR_LIST)
10611 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10612 else
10613 {
10614 l = argvars[0].vval.v_list;
10615 if (l == NULL || tv_check_lock(l->lv_lock,
10616 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10617 TRUE))
10618 goto theend;
10619 rettv->vval.v_list = l;
10620 rettv->v_type = VAR_LIST;
10621 ++l->lv_refcount;
10622
10623 len = list_len(l);
10624 if (len <= 1)
10625 goto theend; /* short list sorts pretty quickly */
10626
10627 info.item_compare_ic = FALSE;
10628 info.item_compare_numeric = FALSE;
10629 info.item_compare_numbers = FALSE;
10630#ifdef FEAT_FLOAT
10631 info.item_compare_float = FALSE;
10632#endif
10633 info.item_compare_func = NULL;
10634 info.item_compare_partial = NULL;
10635 info.item_compare_selfdict = NULL;
10636 if (argvars[1].v_type != VAR_UNKNOWN)
10637 {
10638 /* optional second argument: {func} */
10639 if (argvars[1].v_type == VAR_FUNC)
10640 info.item_compare_func = argvars[1].vval.v_string;
10641 else if (argvars[1].v_type == VAR_PARTIAL)
10642 info.item_compare_partial = argvars[1].vval.v_partial;
10643 else
10644 {
10645 int error = FALSE;
10646
10647 i = (long)get_tv_number_chk(&argvars[1], &error);
10648 if (error)
10649 goto theend; /* type error; errmsg already given */
10650 if (i == 1)
10651 info.item_compare_ic = TRUE;
10652 else if (argvars[1].v_type != VAR_NUMBER)
10653 info.item_compare_func = get_tv_string(&argvars[1]);
10654 else if (i != 0)
10655 {
10656 EMSG(_(e_invarg));
10657 goto theend;
10658 }
10659 if (info.item_compare_func != NULL)
10660 {
10661 if (*info.item_compare_func == NUL)
10662 {
10663 /* empty string means default sort */
10664 info.item_compare_func = NULL;
10665 }
10666 else if (STRCMP(info.item_compare_func, "n") == 0)
10667 {
10668 info.item_compare_func = NULL;
10669 info.item_compare_numeric = TRUE;
10670 }
10671 else if (STRCMP(info.item_compare_func, "N") == 0)
10672 {
10673 info.item_compare_func = NULL;
10674 info.item_compare_numbers = TRUE;
10675 }
10676#ifdef FEAT_FLOAT
10677 else if (STRCMP(info.item_compare_func, "f") == 0)
10678 {
10679 info.item_compare_func = NULL;
10680 info.item_compare_float = TRUE;
10681 }
10682#endif
10683 else if (STRCMP(info.item_compare_func, "i") == 0)
10684 {
10685 info.item_compare_func = NULL;
10686 info.item_compare_ic = TRUE;
10687 }
10688 }
10689 }
10690
10691 if (argvars[2].v_type != VAR_UNKNOWN)
10692 {
10693 /* optional third argument: {dict} */
10694 if (argvars[2].v_type != VAR_DICT)
10695 {
10696 EMSG(_(e_dictreq));
10697 goto theend;
10698 }
10699 info.item_compare_selfdict = argvars[2].vval.v_dict;
10700 }
10701 }
10702
10703 /* Make an array with each entry pointing to an item in the List. */
10704 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
10705 if (ptrs == NULL)
10706 goto theend;
10707
10708 i = 0;
10709 if (sort)
10710 {
10711 /* sort(): ptrs will be the list to sort */
10712 for (li = l->lv_first; li != NULL; li = li->li_next)
10713 {
10714 ptrs[i].item = li;
10715 ptrs[i].idx = i;
10716 ++i;
10717 }
10718
10719 info.item_compare_func_err = FALSE;
10720 info.item_compare_keep_zero = FALSE;
10721 /* test the compare function */
10722 if ((info.item_compare_func != NULL
10723 || info.item_compare_partial != NULL)
10724 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
10725 == ITEM_COMPARE_FAIL)
10726 EMSG(_("E702: Sort compare function failed"));
10727 else
10728 {
10729 /* Sort the array with item pointers. */
10730 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
10731 info.item_compare_func == NULL
10732 && info.item_compare_partial == NULL
10733 ? item_compare : item_compare2);
10734
10735 if (!info.item_compare_func_err)
10736 {
10737 /* Clear the List and append the items in sorted order. */
10738 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
10739 l->lv_len = 0;
10740 for (i = 0; i < len; ++i)
10741 list_append(l, ptrs[i].item);
10742 }
10743 }
10744 }
10745 else
10746 {
10747 int (*item_compare_func_ptr)(const void *, const void *);
10748
10749 /* f_uniq(): ptrs will be a stack of items to remove */
10750 info.item_compare_func_err = FALSE;
10751 info.item_compare_keep_zero = TRUE;
10752 item_compare_func_ptr = info.item_compare_func != NULL
10753 || info.item_compare_partial != NULL
10754 ? item_compare2 : item_compare;
10755
10756 for (li = l->lv_first; li != NULL && li->li_next != NULL;
10757 li = li->li_next)
10758 {
10759 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
10760 == 0)
10761 ptrs[i++].item = li;
10762 if (info.item_compare_func_err)
10763 {
10764 EMSG(_("E882: Uniq compare function failed"));
10765 break;
10766 }
10767 }
10768
10769 if (!info.item_compare_func_err)
10770 {
10771 while (--i >= 0)
10772 {
10773 li = ptrs[i].item->li_next;
10774 ptrs[i].item->li_next = li->li_next;
10775 if (li->li_next != NULL)
10776 li->li_next->li_prev = ptrs[i].item;
10777 else
10778 l->lv_last = ptrs[i].item;
10779 list_fix_watch(l, li);
10780 listitem_free(li);
10781 l->lv_len--;
10782 }
10783 }
10784 }
10785
10786 vim_free(ptrs);
10787 }
10788theend:
10789 sortinfo = old_sortinfo;
10790}
10791
10792/*
10793 * "sort({list})" function
10794 */
10795 static void
10796f_sort(typval_T *argvars, typval_T *rettv)
10797{
10798 do_sort_uniq(argvars, rettv, TRUE);
10799}
10800
10801/*
10802 * "uniq({list})" function
10803 */
10804 static void
10805f_uniq(typval_T *argvars, typval_T *rettv)
10806{
10807 do_sort_uniq(argvars, rettv, FALSE);
10808}
10809
10810/*
10811 * "soundfold({word})" function
10812 */
10813 static void
10814f_soundfold(typval_T *argvars, typval_T *rettv)
10815{
10816 char_u *s;
10817
10818 rettv->v_type = VAR_STRING;
10819 s = get_tv_string(&argvars[0]);
10820#ifdef FEAT_SPELL
10821 rettv->vval.v_string = eval_soundfold(s);
10822#else
10823 rettv->vval.v_string = vim_strsave(s);
10824#endif
10825}
10826
10827/*
10828 * "spellbadword()" function
10829 */
10830 static void
10831f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10832{
10833 char_u *word = (char_u *)"";
10834 hlf_T attr = HLF_COUNT;
10835 int len = 0;
10836
10837 if (rettv_list_alloc(rettv) == FAIL)
10838 return;
10839
10840#ifdef FEAT_SPELL
10841 if (argvars[0].v_type == VAR_UNKNOWN)
10842 {
10843 /* Find the start and length of the badly spelled word. */
10844 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10845 if (len != 0)
10846 word = ml_get_cursor();
10847 }
10848 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10849 {
10850 char_u *str = get_tv_string_chk(&argvars[0]);
10851 int capcol = -1;
10852
10853 if (str != NULL)
10854 {
10855 /* Check the argument for spelling. */
10856 while (*str != NUL)
10857 {
10858 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10859 if (attr != HLF_COUNT)
10860 {
10861 word = str;
10862 break;
10863 }
10864 str += len;
10865 }
10866 }
10867 }
10868#endif
10869
10870 list_append_string(rettv->vval.v_list, word, len);
10871 list_append_string(rettv->vval.v_list, (char_u *)(
10872 attr == HLF_SPB ? "bad" :
10873 attr == HLF_SPR ? "rare" :
10874 attr == HLF_SPL ? "local" :
10875 attr == HLF_SPC ? "caps" :
10876 ""), -1);
10877}
10878
10879/*
10880 * "spellsuggest()" function
10881 */
10882 static void
10883f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10884{
10885#ifdef FEAT_SPELL
10886 char_u *str;
10887 int typeerr = FALSE;
10888 int maxcount;
10889 garray_T ga;
10890 int i;
10891 listitem_T *li;
10892 int need_capital = FALSE;
10893#endif
10894
10895 if (rettv_list_alloc(rettv) == FAIL)
10896 return;
10897
10898#ifdef FEAT_SPELL
10899 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10900 {
10901 str = get_tv_string(&argvars[0]);
10902 if (argvars[1].v_type != VAR_UNKNOWN)
10903 {
10904 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
10905 if (maxcount <= 0)
10906 return;
10907 if (argvars[2].v_type != VAR_UNKNOWN)
10908 {
10909 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
10910 if (typeerr)
10911 return;
10912 }
10913 }
10914 else
10915 maxcount = 25;
10916
10917 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10918
10919 for (i = 0; i < ga.ga_len; ++i)
10920 {
10921 str = ((char_u **)ga.ga_data)[i];
10922
10923 li = listitem_alloc();
10924 if (li == NULL)
10925 vim_free(str);
10926 else
10927 {
10928 li->li_tv.v_type = VAR_STRING;
10929 li->li_tv.v_lock = 0;
10930 li->li_tv.vval.v_string = str;
10931 list_append(rettv->vval.v_list, li);
10932 }
10933 }
10934 ga_clear(&ga);
10935 }
10936#endif
10937}
10938
10939 static void
10940f_split(typval_T *argvars, typval_T *rettv)
10941{
10942 char_u *str;
10943 char_u *end;
10944 char_u *pat = NULL;
10945 regmatch_T regmatch;
10946 char_u patbuf[NUMBUFLEN];
10947 char_u *save_cpo;
10948 int match;
10949 colnr_T col = 0;
10950 int keepempty = FALSE;
10951 int typeerr = FALSE;
10952
10953 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10954 save_cpo = p_cpo;
10955 p_cpo = (char_u *)"";
10956
10957 str = get_tv_string(&argvars[0]);
10958 if (argvars[1].v_type != VAR_UNKNOWN)
10959 {
10960 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
10961 if (pat == NULL)
10962 typeerr = TRUE;
10963 if (argvars[2].v_type != VAR_UNKNOWN)
10964 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
10965 }
10966 if (pat == NULL || *pat == NUL)
10967 pat = (char_u *)"[\\x01- ]\\+";
10968
10969 if (rettv_list_alloc(rettv) == FAIL)
10970 return;
10971 if (typeerr)
10972 return;
10973
10974 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10975 if (regmatch.regprog != NULL)
10976 {
10977 regmatch.rm_ic = FALSE;
10978 while (*str != NUL || keepempty)
10979 {
10980 if (*str == NUL)
10981 match = FALSE; /* empty item at the end */
10982 else
10983 match = vim_regexec_nl(&regmatch, str, col);
10984 if (match)
10985 end = regmatch.startp[0];
10986 else
10987 end = str + STRLEN(str);
10988 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10989 && *str != NUL && match && end < regmatch.endp[0]))
10990 {
10991 if (list_append_string(rettv->vval.v_list, str,
10992 (int)(end - str)) == FAIL)
10993 break;
10994 }
10995 if (!match)
10996 break;
10997 /* Advance to just after the match. */
10998 if (regmatch.endp[0] > str)
10999 col = 0;
11000 else
11001 {
11002 /* Don't get stuck at the same match. */
11003#ifdef FEAT_MBYTE
11004 col = (*mb_ptr2len)(regmatch.endp[0]);
11005#else
11006 col = 1;
11007#endif
11008 }
11009 str = regmatch.endp[0];
11010 }
11011
11012 vim_regfree(regmatch.regprog);
11013 }
11014
11015 p_cpo = save_cpo;
11016}
11017
11018#ifdef FEAT_FLOAT
11019/*
11020 * "sqrt()" function
11021 */
11022 static void
11023f_sqrt(typval_T *argvars, typval_T *rettv)
11024{
11025 float_T f = 0.0;
11026
11027 rettv->v_type = VAR_FLOAT;
11028 if (get_float_arg(argvars, &f) == OK)
11029 rettv->vval.v_float = sqrt(f);
11030 else
11031 rettv->vval.v_float = 0.0;
11032}
11033
11034/*
11035 * "str2float()" function
11036 */
11037 static void
11038f_str2float(typval_T *argvars, typval_T *rettv)
11039{
11040 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011041 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011042
Bram Moolenaar08243d22017-01-10 16:12:29 +010011043 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011044 p = skipwhite(p + 1);
11045 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011046 if (isneg)
11047 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011048 rettv->v_type = VAR_FLOAT;
11049}
11050#endif
11051
11052/*
11053 * "str2nr()" function
11054 */
11055 static void
11056f_str2nr(typval_T *argvars, typval_T *rettv)
11057{
11058 int base = 10;
11059 char_u *p;
11060 varnumber_T n;
11061 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011062 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063
11064 if (argvars[1].v_type != VAR_UNKNOWN)
11065 {
11066 base = (int)get_tv_number(&argvars[1]);
11067 if (base != 2 && base != 8 && base != 10 && base != 16)
11068 {
11069 EMSG(_(e_invarg));
11070 return;
11071 }
11072 }
11073
11074 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011075 isneg = (*p == '-');
11076 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011077 p = skipwhite(p + 1);
11078 switch (base)
11079 {
11080 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11081 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11082 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11083 default: what = 0;
11084 }
11085 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011086 if (isneg)
11087 rettv->vval.v_number = -n;
11088 else
11089 rettv->vval.v_number = n;
11090
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011091}
11092
11093#ifdef HAVE_STRFTIME
11094/*
11095 * "strftime({format}[, {time}])" function
11096 */
11097 static void
11098f_strftime(typval_T *argvars, typval_T *rettv)
11099{
11100 char_u result_buf[256];
11101 struct tm *curtime;
11102 time_t seconds;
11103 char_u *p;
11104
11105 rettv->v_type = VAR_STRING;
11106
11107 p = get_tv_string(&argvars[0]);
11108 if (argvars[1].v_type == VAR_UNKNOWN)
11109 seconds = time(NULL);
11110 else
11111 seconds = (time_t)get_tv_number(&argvars[1]);
11112 curtime = localtime(&seconds);
11113 /* MSVC returns NULL for an invalid value of seconds. */
11114 if (curtime == NULL)
11115 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11116 else
11117 {
11118# ifdef FEAT_MBYTE
11119 vimconv_T conv;
11120 char_u *enc;
11121
11122 conv.vc_type = CONV_NONE;
11123 enc = enc_locale();
11124 convert_setup(&conv, p_enc, enc);
11125 if (conv.vc_type != CONV_NONE)
11126 p = string_convert(&conv, p, NULL);
11127# endif
11128 if (p != NULL)
11129 (void)strftime((char *)result_buf, sizeof(result_buf),
11130 (char *)p, curtime);
11131 else
11132 result_buf[0] = NUL;
11133
11134# ifdef FEAT_MBYTE
11135 if (conv.vc_type != CONV_NONE)
11136 vim_free(p);
11137 convert_setup(&conv, enc, p_enc);
11138 if (conv.vc_type != CONV_NONE)
11139 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11140 else
11141# endif
11142 rettv->vval.v_string = vim_strsave(result_buf);
11143
11144# ifdef FEAT_MBYTE
11145 /* Release conversion descriptors */
11146 convert_setup(&conv, NULL, NULL);
11147 vim_free(enc);
11148# endif
11149 }
11150}
11151#endif
11152
11153/*
11154 * "strgetchar()" function
11155 */
11156 static void
11157f_strgetchar(typval_T *argvars, typval_T *rettv)
11158{
11159 char_u *str;
11160 int len;
11161 int error = FALSE;
11162 int charidx;
11163
11164 rettv->vval.v_number = -1;
11165 str = get_tv_string_chk(&argvars[0]);
11166 if (str == NULL)
11167 return;
11168 len = (int)STRLEN(str);
11169 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11170 if (error)
11171 return;
11172#ifdef FEAT_MBYTE
11173 {
11174 int byteidx = 0;
11175
11176 while (charidx >= 0 && byteidx < len)
11177 {
11178 if (charidx == 0)
11179 {
11180 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11181 break;
11182 }
11183 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011184 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011185 }
11186 }
11187#else
11188 if (charidx < len)
11189 rettv->vval.v_number = str[charidx];
11190#endif
11191}
11192
11193/*
11194 * "stridx()" function
11195 */
11196 static void
11197f_stridx(typval_T *argvars, typval_T *rettv)
11198{
11199 char_u buf[NUMBUFLEN];
11200 char_u *needle;
11201 char_u *haystack;
11202 char_u *save_haystack;
11203 char_u *pos;
11204 int start_idx;
11205
11206 needle = get_tv_string_chk(&argvars[1]);
11207 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11208 rettv->vval.v_number = -1;
11209 if (needle == NULL || haystack == NULL)
11210 return; /* type error; errmsg already given */
11211
11212 if (argvars[2].v_type != VAR_UNKNOWN)
11213 {
11214 int error = FALSE;
11215
11216 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11217 if (error || start_idx >= (int)STRLEN(haystack))
11218 return;
11219 if (start_idx >= 0)
11220 haystack += start_idx;
11221 }
11222
11223 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11224 if (pos != NULL)
11225 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11226}
11227
11228/*
11229 * "string()" function
11230 */
11231 static void
11232f_string(typval_T *argvars, typval_T *rettv)
11233{
11234 char_u *tofree;
11235 char_u numbuf[NUMBUFLEN];
11236
11237 rettv->v_type = VAR_STRING;
11238 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11239 get_copyID());
11240 /* Make a copy if we have a value but it's not in allocated memory. */
11241 if (rettv->vval.v_string != NULL && tofree == NULL)
11242 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11243}
11244
11245/*
11246 * "strlen()" function
11247 */
11248 static void
11249f_strlen(typval_T *argvars, typval_T *rettv)
11250{
11251 rettv->vval.v_number = (varnumber_T)(STRLEN(
11252 get_tv_string(&argvars[0])));
11253}
11254
11255/*
11256 * "strchars()" function
11257 */
11258 static void
11259f_strchars(typval_T *argvars, typval_T *rettv)
11260{
11261 char_u *s = get_tv_string(&argvars[0]);
11262 int skipcc = 0;
11263#ifdef FEAT_MBYTE
11264 varnumber_T len = 0;
11265 int (*func_mb_ptr2char_adv)(char_u **pp);
11266#endif
11267
11268 if (argvars[1].v_type != VAR_UNKNOWN)
11269 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11270 if (skipcc < 0 || skipcc > 1)
11271 EMSG(_(e_invarg));
11272 else
11273 {
11274#ifdef FEAT_MBYTE
11275 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11276 while (*s != NUL)
11277 {
11278 func_mb_ptr2char_adv(&s);
11279 ++len;
11280 }
11281 rettv->vval.v_number = len;
11282#else
11283 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11284#endif
11285 }
11286}
11287
11288/*
11289 * "strdisplaywidth()" function
11290 */
11291 static void
11292f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11293{
11294 char_u *s = get_tv_string(&argvars[0]);
11295 int col = 0;
11296
11297 if (argvars[1].v_type != VAR_UNKNOWN)
11298 col = (int)get_tv_number(&argvars[1]);
11299
11300 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11301}
11302
11303/*
11304 * "strwidth()" function
11305 */
11306 static void
11307f_strwidth(typval_T *argvars, typval_T *rettv)
11308{
11309 char_u *s = get_tv_string(&argvars[0]);
11310
11311 rettv->vval.v_number = (varnumber_T)(
11312#ifdef FEAT_MBYTE
11313 mb_string2cells(s, -1)
11314#else
11315 STRLEN(s)
11316#endif
11317 );
11318}
11319
11320/*
11321 * "strcharpart()" function
11322 */
11323 static void
11324f_strcharpart(typval_T *argvars, typval_T *rettv)
11325{
11326#ifdef FEAT_MBYTE
11327 char_u *p;
11328 int nchar;
11329 int nbyte = 0;
11330 int charlen;
11331 int len = 0;
11332 int slen;
11333 int error = FALSE;
11334
11335 p = get_tv_string(&argvars[0]);
11336 slen = (int)STRLEN(p);
11337
11338 nchar = (int)get_tv_number_chk(&argvars[1], &error);
11339 if (!error)
11340 {
11341 if (nchar > 0)
11342 while (nchar > 0 && nbyte < slen)
11343 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011344 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011345 --nchar;
11346 }
11347 else
11348 nbyte = nchar;
11349 if (argvars[2].v_type != VAR_UNKNOWN)
11350 {
11351 charlen = (int)get_tv_number(&argvars[2]);
11352 while (charlen > 0 && nbyte + len < slen)
11353 {
11354 int off = nbyte + len;
11355
11356 if (off < 0)
11357 len += 1;
11358 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011359 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011360 --charlen;
11361 }
11362 }
11363 else
11364 len = slen - nbyte; /* default: all bytes that are available. */
11365 }
11366
11367 /*
11368 * Only return the overlap between the specified part and the actual
11369 * string.
11370 */
11371 if (nbyte < 0)
11372 {
11373 len += nbyte;
11374 nbyte = 0;
11375 }
11376 else if (nbyte > slen)
11377 nbyte = slen;
11378 if (len < 0)
11379 len = 0;
11380 else if (nbyte + len > slen)
11381 len = slen - nbyte;
11382
11383 rettv->v_type = VAR_STRING;
11384 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11385#else
11386 f_strpart(argvars, rettv);
11387#endif
11388}
11389
11390/*
11391 * "strpart()" function
11392 */
11393 static void
11394f_strpart(typval_T *argvars, typval_T *rettv)
11395{
11396 char_u *p;
11397 int n;
11398 int len;
11399 int slen;
11400 int error = FALSE;
11401
11402 p = get_tv_string(&argvars[0]);
11403 slen = (int)STRLEN(p);
11404
11405 n = (int)get_tv_number_chk(&argvars[1], &error);
11406 if (error)
11407 len = 0;
11408 else if (argvars[2].v_type != VAR_UNKNOWN)
11409 len = (int)get_tv_number(&argvars[2]);
11410 else
11411 len = slen - n; /* default len: all bytes that are available. */
11412
11413 /*
11414 * Only return the overlap between the specified part and the actual
11415 * string.
11416 */
11417 if (n < 0)
11418 {
11419 len += n;
11420 n = 0;
11421 }
11422 else if (n > slen)
11423 n = slen;
11424 if (len < 0)
11425 len = 0;
11426 else if (n + len > slen)
11427 len = slen - n;
11428
11429 rettv->v_type = VAR_STRING;
11430 rettv->vval.v_string = vim_strnsave(p + n, len);
11431}
11432
11433/*
11434 * "strridx()" function
11435 */
11436 static void
11437f_strridx(typval_T *argvars, typval_T *rettv)
11438{
11439 char_u buf[NUMBUFLEN];
11440 char_u *needle;
11441 char_u *haystack;
11442 char_u *rest;
11443 char_u *lastmatch = NULL;
11444 int haystack_len, end_idx;
11445
11446 needle = get_tv_string_chk(&argvars[1]);
11447 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11448
11449 rettv->vval.v_number = -1;
11450 if (needle == NULL || haystack == NULL)
11451 return; /* type error; errmsg already given */
11452
11453 haystack_len = (int)STRLEN(haystack);
11454 if (argvars[2].v_type != VAR_UNKNOWN)
11455 {
11456 /* Third argument: upper limit for index */
11457 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11458 if (end_idx < 0)
11459 return; /* can never find a match */
11460 }
11461 else
11462 end_idx = haystack_len;
11463
11464 if (*needle == NUL)
11465 {
11466 /* Empty string matches past the end. */
11467 lastmatch = haystack + end_idx;
11468 }
11469 else
11470 {
11471 for (rest = haystack; *rest != '\0'; ++rest)
11472 {
11473 rest = (char_u *)strstr((char *)rest, (char *)needle);
11474 if (rest == NULL || rest > haystack + end_idx)
11475 break;
11476 lastmatch = rest;
11477 }
11478 }
11479
11480 if (lastmatch == NULL)
11481 rettv->vval.v_number = -1;
11482 else
11483 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11484}
11485
11486/*
11487 * "strtrans()" function
11488 */
11489 static void
11490f_strtrans(typval_T *argvars, typval_T *rettv)
11491{
11492 rettv->v_type = VAR_STRING;
11493 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11494}
11495
11496/*
11497 * "submatch()" function
11498 */
11499 static void
11500f_submatch(typval_T *argvars, typval_T *rettv)
11501{
11502 int error = FALSE;
11503 int no;
11504 int retList = 0;
11505
11506 no = (int)get_tv_number_chk(&argvars[0], &error);
11507 if (error)
11508 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011509 if (no < 0 || no >= NSUBEXP)
11510 {
11511 EMSGN(_("E935: invalid submatch number: %d"), no);
11512 return;
11513 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011514 if (argvars[1].v_type != VAR_UNKNOWN)
11515 retList = (int)get_tv_number_chk(&argvars[1], &error);
11516 if (error)
11517 return;
11518
11519 if (retList == 0)
11520 {
11521 rettv->v_type = VAR_STRING;
11522 rettv->vval.v_string = reg_submatch(no);
11523 }
11524 else
11525 {
11526 rettv->v_type = VAR_LIST;
11527 rettv->vval.v_list = reg_submatch_list(no);
11528 }
11529}
11530
11531/*
11532 * "substitute()" function
11533 */
11534 static void
11535f_substitute(typval_T *argvars, typval_T *rettv)
11536{
11537 char_u patbuf[NUMBUFLEN];
11538 char_u subbuf[NUMBUFLEN];
11539 char_u flagsbuf[NUMBUFLEN];
11540
11541 char_u *str = get_tv_string_chk(&argvars[0]);
11542 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011543 char_u *sub = NULL;
11544 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011545 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11546
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011547 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11548 expr = &argvars[2];
11549 else
11550 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011552 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011553 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11554 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011555 rettv->vval.v_string = NULL;
11556 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011557 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011558}
11559
11560/*
11561 * "synID(lnum, col, trans)" function
11562 */
11563 static void
11564f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11565{
11566 int id = 0;
11567#ifdef FEAT_SYN_HL
11568 linenr_T lnum;
11569 colnr_T col;
11570 int trans;
11571 int transerr = FALSE;
11572
11573 lnum = get_tv_lnum(argvars); /* -1 on type error */
11574 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11575 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11576
11577 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11578 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11579 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11580#endif
11581
11582 rettv->vval.v_number = id;
11583}
11584
11585/*
11586 * "synIDattr(id, what [, mode])" function
11587 */
11588 static void
11589f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11590{
11591 char_u *p = NULL;
11592#ifdef FEAT_SYN_HL
11593 int id;
11594 char_u *what;
11595 char_u *mode;
11596 char_u modebuf[NUMBUFLEN];
11597 int modec;
11598
11599 id = (int)get_tv_number(&argvars[0]);
11600 what = get_tv_string(&argvars[1]);
11601 if (argvars[2].v_type != VAR_UNKNOWN)
11602 {
11603 mode = get_tv_string_buf(&argvars[2], modebuf);
11604 modec = TOLOWER_ASC(mode[0]);
11605 if (modec != 't' && modec != 'c' && modec != 'g')
11606 modec = 0; /* replace invalid with current */
11607 }
11608 else
11609 {
11610#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11611 if (USE_24BIT)
11612 modec = 'g';
11613 else
11614#endif
11615 if (t_colors > 1)
11616 modec = 'c';
11617 else
11618 modec = 't';
11619 }
11620
11621
11622 switch (TOLOWER_ASC(what[0]))
11623 {
11624 case 'b':
11625 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11626 p = highlight_color(id, what, modec);
11627 else /* bold */
11628 p = highlight_has_attr(id, HL_BOLD, modec);
11629 break;
11630
11631 case 'f': /* fg[#] or font */
11632 p = highlight_color(id, what, modec);
11633 break;
11634
11635 case 'i':
11636 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11637 p = highlight_has_attr(id, HL_INVERSE, modec);
11638 else /* italic */
11639 p = highlight_has_attr(id, HL_ITALIC, modec);
11640 break;
11641
11642 case 'n': /* name */
11643 p = get_highlight_name(NULL, id - 1);
11644 break;
11645
11646 case 'r': /* reverse */
11647 p = highlight_has_attr(id, HL_INVERSE, modec);
11648 break;
11649
11650 case 's':
11651 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11652 p = highlight_color(id, what, modec);
11653 else /* standout */
11654 p = highlight_has_attr(id, HL_STANDOUT, modec);
11655 break;
11656
11657 case 'u':
11658 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11659 /* underline */
11660 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11661 else
11662 /* undercurl */
11663 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11664 break;
11665 }
11666
11667 if (p != NULL)
11668 p = vim_strsave(p);
11669#endif
11670 rettv->v_type = VAR_STRING;
11671 rettv->vval.v_string = p;
11672}
11673
11674/*
11675 * "synIDtrans(id)" function
11676 */
11677 static void
11678f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11679{
11680 int id;
11681
11682#ifdef FEAT_SYN_HL
11683 id = (int)get_tv_number(&argvars[0]);
11684
11685 if (id > 0)
11686 id = syn_get_final_id(id);
11687 else
11688#endif
11689 id = 0;
11690
11691 rettv->vval.v_number = id;
11692}
11693
11694/*
11695 * "synconcealed(lnum, col)" function
11696 */
11697 static void
11698f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11699{
11700#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11701 linenr_T lnum;
11702 colnr_T col;
11703 int syntax_flags = 0;
11704 int cchar;
11705 int matchid = 0;
11706 char_u str[NUMBUFLEN];
11707#endif
11708
11709 rettv->v_type = VAR_LIST;
11710 rettv->vval.v_list = NULL;
11711
11712#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11713 lnum = get_tv_lnum(argvars); /* -1 on type error */
11714 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11715
11716 vim_memset(str, NUL, sizeof(str));
11717
11718 if (rettv_list_alloc(rettv) != FAIL)
11719 {
11720 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11721 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11722 && curwin->w_p_cole > 0)
11723 {
11724 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11725 syntax_flags = get_syntax_info(&matchid);
11726
11727 /* get the conceal character */
11728 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11729 {
11730 cchar = syn_get_sub_char();
11731 if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL)
11732 cchar = lcs_conceal;
11733 if (cchar != NUL)
11734 {
11735# ifdef FEAT_MBYTE
11736 if (has_mbyte)
11737 (*mb_char2bytes)(cchar, str);
11738 else
11739# endif
11740 str[0] = cchar;
11741 }
11742 }
11743 }
11744
11745 list_append_number(rettv->vval.v_list,
11746 (syntax_flags & HL_CONCEAL) != 0);
11747 /* -1 to auto-determine strlen */
11748 list_append_string(rettv->vval.v_list, str, -1);
11749 list_append_number(rettv->vval.v_list, matchid);
11750 }
11751#endif
11752}
11753
11754/*
11755 * "synstack(lnum, col)" function
11756 */
11757 static void
11758f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11759{
11760#ifdef FEAT_SYN_HL
11761 linenr_T lnum;
11762 colnr_T col;
11763 int i;
11764 int id;
11765#endif
11766
11767 rettv->v_type = VAR_LIST;
11768 rettv->vval.v_list = NULL;
11769
11770#ifdef FEAT_SYN_HL
11771 lnum = get_tv_lnum(argvars); /* -1 on type error */
11772 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11773
11774 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11775 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11776 && rettv_list_alloc(rettv) != FAIL)
11777 {
11778 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11779 for (i = 0; ; ++i)
11780 {
11781 id = syn_get_stack_item(i);
11782 if (id < 0)
11783 break;
11784 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11785 break;
11786 }
11787 }
11788#endif
11789}
11790
11791 static void
11792get_cmd_output_as_rettv(
11793 typval_T *argvars,
11794 typval_T *rettv,
11795 int retlist)
11796{
11797 char_u *res = NULL;
11798 char_u *p;
11799 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011800 int err = FALSE;
11801 FILE *fd;
11802 list_T *list = NULL;
11803 int flags = SHELL_SILENT;
11804
11805 rettv->v_type = VAR_STRING;
11806 rettv->vval.v_string = NULL;
11807 if (check_restricted() || check_secure())
11808 goto errret;
11809
11810 if (argvars[1].v_type != VAR_UNKNOWN)
11811 {
11812 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011813 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011814 * command.
11815 */
11816 if ((infile = vim_tempname('i', TRUE)) == NULL)
11817 {
11818 EMSG(_(e_notmp));
11819 goto errret;
11820 }
11821
11822 fd = mch_fopen((char *)infile, WRITEBIN);
11823 if (fd == NULL)
11824 {
11825 EMSG2(_(e_notopen), infile);
11826 goto errret;
11827 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011828 if (argvars[1].v_type == VAR_NUMBER)
11829 {
11830 linenr_T lnum;
11831 buf_T *buf;
11832
11833 buf = buflist_findnr(argvars[1].vval.v_number);
11834 if (buf == NULL)
11835 {
11836 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
11837 goto errret;
11838 }
11839
11840 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11841 {
11842 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11843 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11844 {
11845 err = TRUE;
11846 break;
11847 }
11848 if (putc(NL, fd) == EOF)
11849 {
11850 err = TRUE;
11851 break;
11852 }
11853 }
11854 }
11855 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011856 {
11857 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11858 err = TRUE;
11859 }
11860 else
11861 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011862 size_t len;
11863 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011864
11865 p = get_tv_string_buf_chk(&argvars[1], buf);
11866 if (p == NULL)
11867 {
11868 fclose(fd);
11869 goto errret; /* type error; errmsg already given */
11870 }
11871 len = STRLEN(p);
11872 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11873 err = TRUE;
11874 }
11875 if (fclose(fd) != 0)
11876 err = TRUE;
11877 if (err)
11878 {
11879 EMSG(_("E677: Error writing temp file"));
11880 goto errret;
11881 }
11882 }
11883
11884 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11885 * echoes typeahead, that messes up the display. */
11886 if (!msg_silent)
11887 flags += SHELL_COOKED;
11888
11889 if (retlist)
11890 {
11891 int len;
11892 listitem_T *li;
11893 char_u *s = NULL;
11894 char_u *start;
11895 char_u *end;
11896 int i;
11897
11898 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
11899 if (res == NULL)
11900 goto errret;
11901
11902 list = list_alloc();
11903 if (list == NULL)
11904 goto errret;
11905
11906 for (i = 0; i < len; ++i)
11907 {
11908 start = res + i;
11909 while (i < len && res[i] != NL)
11910 ++i;
11911 end = res + i;
11912
11913 s = alloc((unsigned)(end - start + 1));
11914 if (s == NULL)
11915 goto errret;
11916
11917 for (p = s; start < end; ++p, ++start)
11918 *p = *start == NUL ? NL : *start;
11919 *p = NUL;
11920
11921 li = listitem_alloc();
11922 if (li == NULL)
11923 {
11924 vim_free(s);
11925 goto errret;
11926 }
11927 li->li_tv.v_type = VAR_STRING;
11928 li->li_tv.v_lock = 0;
11929 li->li_tv.vval.v_string = s;
11930 list_append(list, li);
11931 }
11932
11933 ++list->lv_refcount;
11934 rettv->v_type = VAR_LIST;
11935 rettv->vval.v_list = list;
11936 list = NULL;
11937 }
11938 else
11939 {
11940 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
11941#ifdef USE_CR
11942 /* translate <CR> into <NL> */
11943 if (res != NULL)
11944 {
11945 char_u *s;
11946
11947 for (s = res; *s; ++s)
11948 {
11949 if (*s == CAR)
11950 *s = NL;
11951 }
11952 }
11953#else
11954# ifdef USE_CRNL
11955 /* translate <CR><NL> into <NL> */
11956 if (res != NULL)
11957 {
11958 char_u *s, *d;
11959
11960 d = res;
11961 for (s = res; *s; ++s)
11962 {
11963 if (s[0] == CAR && s[1] == NL)
11964 ++s;
11965 *d++ = *s;
11966 }
11967 *d = NUL;
11968 }
11969# endif
11970#endif
11971 rettv->vval.v_string = res;
11972 res = NULL;
11973 }
11974
11975errret:
11976 if (infile != NULL)
11977 {
11978 mch_remove(infile);
11979 vim_free(infile);
11980 }
11981 if (res != NULL)
11982 vim_free(res);
11983 if (list != NULL)
11984 list_free(list);
11985}
11986
11987/*
11988 * "system()" function
11989 */
11990 static void
11991f_system(typval_T *argvars, typval_T *rettv)
11992{
11993 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11994}
11995
11996/*
11997 * "systemlist()" function
11998 */
11999 static void
12000f_systemlist(typval_T *argvars, typval_T *rettv)
12001{
12002 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12003}
12004
12005/*
12006 * "tabpagebuflist()" function
12007 */
12008 static void
12009f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12010{
12011#ifdef FEAT_WINDOWS
12012 tabpage_T *tp;
12013 win_T *wp = NULL;
12014
12015 if (argvars[0].v_type == VAR_UNKNOWN)
12016 wp = firstwin;
12017 else
12018 {
12019 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12020 if (tp != NULL)
12021 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12022 }
12023 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12024 {
12025 for (; wp != NULL; wp = wp->w_next)
12026 if (list_append_number(rettv->vval.v_list,
12027 wp->w_buffer->b_fnum) == FAIL)
12028 break;
12029 }
12030#endif
12031}
12032
12033
12034/*
12035 * "tabpagenr()" function
12036 */
12037 static void
12038f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12039{
12040 int nr = 1;
12041#ifdef FEAT_WINDOWS
12042 char_u *arg;
12043
12044 if (argvars[0].v_type != VAR_UNKNOWN)
12045 {
12046 arg = get_tv_string_chk(&argvars[0]);
12047 nr = 0;
12048 if (arg != NULL)
12049 {
12050 if (STRCMP(arg, "$") == 0)
12051 nr = tabpage_index(NULL) - 1;
12052 else
12053 EMSG2(_(e_invexpr2), arg);
12054 }
12055 }
12056 else
12057 nr = tabpage_index(curtab);
12058#endif
12059 rettv->vval.v_number = nr;
12060}
12061
12062
12063#ifdef FEAT_WINDOWS
12064static int get_winnr(tabpage_T *tp, typval_T *argvar);
12065
12066/*
12067 * Common code for tabpagewinnr() and winnr().
12068 */
12069 static int
12070get_winnr(tabpage_T *tp, typval_T *argvar)
12071{
12072 win_T *twin;
12073 int nr = 1;
12074 win_T *wp;
12075 char_u *arg;
12076
12077 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12078 if (argvar->v_type != VAR_UNKNOWN)
12079 {
12080 arg = get_tv_string_chk(argvar);
12081 if (arg == NULL)
12082 nr = 0; /* type error; errmsg already given */
12083 else if (STRCMP(arg, "$") == 0)
12084 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12085 else if (STRCMP(arg, "#") == 0)
12086 {
12087 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12088 if (twin == NULL)
12089 nr = 0;
12090 }
12091 else
12092 {
12093 EMSG2(_(e_invexpr2), arg);
12094 nr = 0;
12095 }
12096 }
12097
12098 if (nr > 0)
12099 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12100 wp != twin; wp = wp->w_next)
12101 {
12102 if (wp == NULL)
12103 {
12104 /* didn't find it in this tabpage */
12105 nr = 0;
12106 break;
12107 }
12108 ++nr;
12109 }
12110 return nr;
12111}
12112#endif
12113
12114/*
12115 * "tabpagewinnr()" function
12116 */
12117 static void
12118f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12119{
12120 int nr = 1;
12121#ifdef FEAT_WINDOWS
12122 tabpage_T *tp;
12123
12124 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12125 if (tp == NULL)
12126 nr = 0;
12127 else
12128 nr = get_winnr(tp, &argvars[1]);
12129#endif
12130 rettv->vval.v_number = nr;
12131}
12132
12133
12134/*
12135 * "tagfiles()" function
12136 */
12137 static void
12138f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12139{
12140 char_u *fname;
12141 tagname_T tn;
12142 int first;
12143
12144 if (rettv_list_alloc(rettv) == FAIL)
12145 return;
12146 fname = alloc(MAXPATHL);
12147 if (fname == NULL)
12148 return;
12149
12150 for (first = TRUE; ; first = FALSE)
12151 if (get_tagfname(&tn, first, fname) == FAIL
12152 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12153 break;
12154 tagname_free(&tn);
12155 vim_free(fname);
12156}
12157
12158/*
12159 * "taglist()" function
12160 */
12161 static void
12162f_taglist(typval_T *argvars, typval_T *rettv)
12163{
12164 char_u *tag_pattern;
12165
12166 tag_pattern = get_tv_string(&argvars[0]);
12167
12168 rettv->vval.v_number = FALSE;
12169 if (*tag_pattern == NUL)
12170 return;
12171
12172 if (rettv_list_alloc(rettv) == OK)
12173 (void)get_tags(rettv->vval.v_list, tag_pattern);
12174}
12175
12176/*
12177 * "tempname()" function
12178 */
12179 static void
12180f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12181{
12182 static int x = 'A';
12183
12184 rettv->v_type = VAR_STRING;
12185 rettv->vval.v_string = vim_tempname(x, FALSE);
12186
12187 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12188 * names. Skip 'I' and 'O', they are used for shell redirection. */
12189 do
12190 {
12191 if (x == 'Z')
12192 x = '0';
12193 else if (x == '9')
12194 x = 'A';
12195 else
12196 {
12197#ifdef EBCDIC
12198 if (x == 'I')
12199 x = 'J';
12200 else if (x == 'R')
12201 x = 'S';
12202 else
12203#endif
12204 ++x;
12205 }
12206 } while (x == 'I' || x == 'O');
12207}
12208
12209#ifdef FEAT_FLOAT
12210/*
12211 * "tan()" function
12212 */
12213 static void
12214f_tan(typval_T *argvars, typval_T *rettv)
12215{
12216 float_T f = 0.0;
12217
12218 rettv->v_type = VAR_FLOAT;
12219 if (get_float_arg(argvars, &f) == OK)
12220 rettv->vval.v_float = tan(f);
12221 else
12222 rettv->vval.v_float = 0.0;
12223}
12224
12225/*
12226 * "tanh()" function
12227 */
12228 static void
12229f_tanh(typval_T *argvars, typval_T *rettv)
12230{
12231 float_T f = 0.0;
12232
12233 rettv->v_type = VAR_FLOAT;
12234 if (get_float_arg(argvars, &f) == OK)
12235 rettv->vval.v_float = tanh(f);
12236 else
12237 rettv->vval.v_float = 0.0;
12238}
12239#endif
12240
12241/*
12242 * "test_alloc_fail(id, countdown, repeat)" function
12243 */
12244 static void
12245f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12246{
12247 if (argvars[0].v_type != VAR_NUMBER
12248 || argvars[0].vval.v_number <= 0
12249 || argvars[1].v_type != VAR_NUMBER
12250 || argvars[1].vval.v_number < 0
12251 || argvars[2].v_type != VAR_NUMBER)
12252 EMSG(_(e_invarg));
12253 else
12254 {
12255 alloc_fail_id = argvars[0].vval.v_number;
12256 if (alloc_fail_id >= aid_last)
12257 EMSG(_(e_invarg));
12258 alloc_fail_countdown = argvars[1].vval.v_number;
12259 alloc_fail_repeat = argvars[2].vval.v_number;
12260 did_outofmem_msg = FALSE;
12261 }
12262}
12263
12264/*
12265 * "test_autochdir()"
12266 */
12267 static void
12268f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12269{
12270#if defined(FEAT_AUTOCHDIR)
12271 test_autochdir = TRUE;
12272#endif
12273}
12274
12275/*
12276 * "test_disable_char_avail({expr})" function
12277 */
12278 static void
12279f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED)
12280{
12281 disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]);
12282}
12283
12284/*
12285 * "test_garbagecollect_now()" function
12286 */
12287 static void
12288f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12289{
12290 /* This is dangerous, any Lists and Dicts used internally may be freed
12291 * while still in use. */
12292 garbage_collect(TRUE);
12293}
12294
12295#ifdef FEAT_JOB_CHANNEL
12296 static void
12297f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12298{
12299 rettv->v_type = VAR_CHANNEL;
12300 rettv->vval.v_channel = NULL;
12301}
12302#endif
12303
12304 static void
12305f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12306{
12307 rettv->v_type = VAR_DICT;
12308 rettv->vval.v_dict = NULL;
12309}
12310
12311#ifdef FEAT_JOB_CHANNEL
12312 static void
12313f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12314{
12315 rettv->v_type = VAR_JOB;
12316 rettv->vval.v_job = NULL;
12317}
12318#endif
12319
12320 static void
12321f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12322{
12323 rettv->v_type = VAR_LIST;
12324 rettv->vval.v_list = NULL;
12325}
12326
12327 static void
12328f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12329{
12330 rettv->v_type = VAR_PARTIAL;
12331 rettv->vval.v_partial = NULL;
12332}
12333
12334 static void
12335f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12336{
12337 rettv->v_type = VAR_STRING;
12338 rettv->vval.v_string = NULL;
12339}
12340
12341 static void
12342f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12343{
12344 time_for_testing = (time_t)get_tv_number(&argvars[0]);
12345}
12346
12347#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12348/*
12349 * Get a callback from "arg". It can be a Funcref or a function name.
12350 * When "arg" is zero return an empty string.
12351 * Return NULL for an invalid argument.
12352 */
12353 char_u *
12354get_callback(typval_T *arg, partial_T **pp)
12355{
12356 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12357 {
12358 *pp = arg->vval.v_partial;
12359 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012360 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012361 }
12362 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012363 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012364 {
12365 func_ref(arg->vval.v_string);
12366 return arg->vval.v_string;
12367 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012368 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12369 return (char_u *)"";
12370 EMSG(_("E921: Invalid callback argument"));
12371 return NULL;
12372}
12373
12374/*
12375 * Unref/free "callback" and "partial" retured by get_callback().
12376 */
12377 void
12378free_callback(char_u *callback, partial_T *partial)
12379{
12380 if (partial != NULL)
12381 partial_unref(partial);
12382 else if (callback != NULL)
12383 {
12384 func_unref(callback);
12385 vim_free(callback);
12386 }
12387}
12388#endif
12389
12390#ifdef FEAT_TIMERS
12391/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012392 * "timer_info([timer])" function
12393 */
12394 static void
12395f_timer_info(typval_T *argvars, typval_T *rettv)
12396{
12397 timer_T *timer = NULL;
12398
12399 if (rettv_list_alloc(rettv) != OK)
12400 return;
12401 if (argvars[0].v_type != VAR_UNKNOWN)
12402 {
12403 if (argvars[0].v_type != VAR_NUMBER)
12404 EMSG(_(e_number_exp));
12405 else
12406 {
12407 timer = find_timer((int)get_tv_number(&argvars[0]));
12408 if (timer != NULL)
12409 add_timer_info(rettv, timer);
12410 }
12411 }
12412 else
12413 add_timer_info_all(rettv);
12414}
12415
12416/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012417 * "timer_pause(timer, paused)" function
12418 */
12419 static void
12420f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12421{
12422 timer_T *timer = NULL;
12423 int paused = (int)get_tv_number(&argvars[1]);
12424
12425 if (argvars[0].v_type != VAR_NUMBER)
12426 EMSG(_(e_number_exp));
12427 else
12428 {
12429 timer = find_timer((int)get_tv_number(&argvars[0]));
12430 if (timer != NULL)
12431 timer->tr_paused = paused;
12432 }
12433}
12434
12435/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012436 * "timer_start(time, callback [, options])" function
12437 */
12438 static void
12439f_timer_start(typval_T *argvars, typval_T *rettv)
12440{
Bram Moolenaar75537a92016-09-05 22:45:28 +020012441 long msec = (long)get_tv_number(&argvars[0]);
12442 timer_T *timer;
12443 int repeat = 0;
12444 char_u *callback;
12445 dict_T *dict;
12446 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012447
Bram Moolenaar75537a92016-09-05 22:45:28 +020012448 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012449 if (check_secure())
12450 return;
12451 if (argvars[2].v_type != VAR_UNKNOWN)
12452 {
12453 if (argvars[2].v_type != VAR_DICT
12454 || (dict = argvars[2].vval.v_dict) == NULL)
12455 {
12456 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12457 return;
12458 }
12459 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12460 repeat = get_dict_number(dict, (char_u *)"repeat");
12461 }
12462
Bram Moolenaar75537a92016-09-05 22:45:28 +020012463 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012464 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012465 return;
12466
12467 timer = create_timer(msec, repeat);
12468 if (timer == NULL)
12469 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012470 else
12471 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020012472 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020012473 timer->tr_callback = vim_strsave(callback);
12474 else
12475 /* pointer into the partial */
12476 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012477 timer->tr_partial = partial;
12478 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012479 }
12480}
12481
12482/*
12483 * "timer_stop(timer)" function
12484 */
12485 static void
12486f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12487{
12488 timer_T *timer;
12489
12490 if (argvars[0].v_type != VAR_NUMBER)
12491 {
12492 EMSG(_(e_number_exp));
12493 return;
12494 }
12495 timer = find_timer((int)get_tv_number(&argvars[0]));
12496 if (timer != NULL)
12497 stop_timer(timer);
12498}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012499
12500/*
12501 * "timer_stopall()" function
12502 */
12503 static void
12504f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12505{
12506 stop_all_timers();
12507}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012508#endif
12509
12510/*
12511 * "tolower(string)" function
12512 */
12513 static void
12514f_tolower(typval_T *argvars, typval_T *rettv)
12515{
12516 char_u *p;
12517
12518 p = vim_strsave(get_tv_string(&argvars[0]));
12519 rettv->v_type = VAR_STRING;
12520 rettv->vval.v_string = p;
12521
12522 if (p != NULL)
12523 while (*p != NUL)
12524 {
12525#ifdef FEAT_MBYTE
12526 int l;
12527
12528 if (enc_utf8)
12529 {
12530 int c, lc;
12531
12532 c = utf_ptr2char(p);
12533 lc = utf_tolower(c);
12534 l = utf_ptr2len(p);
12535 /* TODO: reallocate string when byte count changes. */
12536 if (utf_char2len(lc) == l)
12537 utf_char2bytes(lc, p);
12538 p += l;
12539 }
12540 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
12541 p += l; /* skip multi-byte character */
12542 else
12543#endif
12544 {
12545 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */
12546 ++p;
12547 }
12548 }
12549}
12550
12551/*
12552 * "toupper(string)" function
12553 */
12554 static void
12555f_toupper(typval_T *argvars, typval_T *rettv)
12556{
12557 rettv->v_type = VAR_STRING;
12558 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12559}
12560
12561/*
12562 * "tr(string, fromstr, tostr)" function
12563 */
12564 static void
12565f_tr(typval_T *argvars, typval_T *rettv)
12566{
12567 char_u *in_str;
12568 char_u *fromstr;
12569 char_u *tostr;
12570 char_u *p;
12571#ifdef FEAT_MBYTE
12572 int inlen;
12573 int fromlen;
12574 int tolen;
12575 int idx;
12576 char_u *cpstr;
12577 int cplen;
12578 int first = TRUE;
12579#endif
12580 char_u buf[NUMBUFLEN];
12581 char_u buf2[NUMBUFLEN];
12582 garray_T ga;
12583
12584 in_str = get_tv_string(&argvars[0]);
12585 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12586 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12587
12588 /* Default return value: empty string. */
12589 rettv->v_type = VAR_STRING;
12590 rettv->vval.v_string = NULL;
12591 if (fromstr == NULL || tostr == NULL)
12592 return; /* type error; errmsg already given */
12593 ga_init2(&ga, (int)sizeof(char), 80);
12594
12595#ifdef FEAT_MBYTE
12596 if (!has_mbyte)
12597#endif
12598 /* not multi-byte: fromstr and tostr must be the same length */
12599 if (STRLEN(fromstr) != STRLEN(tostr))
12600 {
12601#ifdef FEAT_MBYTE
12602error:
12603#endif
12604 EMSG2(_(e_invarg2), fromstr);
12605 ga_clear(&ga);
12606 return;
12607 }
12608
12609 /* fromstr and tostr have to contain the same number of chars */
12610 while (*in_str != NUL)
12611 {
12612#ifdef FEAT_MBYTE
12613 if (has_mbyte)
12614 {
12615 inlen = (*mb_ptr2len)(in_str);
12616 cpstr = in_str;
12617 cplen = inlen;
12618 idx = 0;
12619 for (p = fromstr; *p != NUL; p += fromlen)
12620 {
12621 fromlen = (*mb_ptr2len)(p);
12622 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12623 {
12624 for (p = tostr; *p != NUL; p += tolen)
12625 {
12626 tolen = (*mb_ptr2len)(p);
12627 if (idx-- == 0)
12628 {
12629 cplen = tolen;
12630 cpstr = p;
12631 break;
12632 }
12633 }
12634 if (*p == NUL) /* tostr is shorter than fromstr */
12635 goto error;
12636 break;
12637 }
12638 ++idx;
12639 }
12640
12641 if (first && cpstr == in_str)
12642 {
12643 /* Check that fromstr and tostr have the same number of
12644 * (multi-byte) characters. Done only once when a character
12645 * of in_str doesn't appear in fromstr. */
12646 first = FALSE;
12647 for (p = tostr; *p != NUL; p += tolen)
12648 {
12649 tolen = (*mb_ptr2len)(p);
12650 --idx;
12651 }
12652 if (idx != 0)
12653 goto error;
12654 }
12655
12656 (void)ga_grow(&ga, cplen);
12657 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12658 ga.ga_len += cplen;
12659
12660 in_str += inlen;
12661 }
12662 else
12663#endif
12664 {
12665 /* When not using multi-byte chars we can do it faster. */
12666 p = vim_strchr(fromstr, *in_str);
12667 if (p != NULL)
12668 ga_append(&ga, tostr[p - fromstr]);
12669 else
12670 ga_append(&ga, *in_str);
12671 ++in_str;
12672 }
12673 }
12674
12675 /* add a terminating NUL */
12676 (void)ga_grow(&ga, 1);
12677 ga_append(&ga, NUL);
12678
12679 rettv->vval.v_string = ga.ga_data;
12680}
12681
12682#ifdef FEAT_FLOAT
12683/*
12684 * "trunc({float})" function
12685 */
12686 static void
12687f_trunc(typval_T *argvars, typval_T *rettv)
12688{
12689 float_T f = 0.0;
12690
12691 rettv->v_type = VAR_FLOAT;
12692 if (get_float_arg(argvars, &f) == OK)
12693 /* trunc() is not in C90, use floor() or ceil() instead. */
12694 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12695 else
12696 rettv->vval.v_float = 0.0;
12697}
12698#endif
12699
12700/*
12701 * "type(expr)" function
12702 */
12703 static void
12704f_type(typval_T *argvars, typval_T *rettv)
12705{
12706 int n = -1;
12707
12708 switch (argvars[0].v_type)
12709 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012710 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12711 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012712 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012713 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12714 case VAR_LIST: n = VAR_TYPE_LIST; break;
12715 case VAR_DICT: n = VAR_TYPE_DICT; break;
12716 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012717 case VAR_SPECIAL:
12718 if (argvars[0].vval.v_number == VVAL_FALSE
12719 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012720 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012721 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012722 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012723 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012724 case VAR_JOB: n = VAR_TYPE_JOB; break;
12725 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012726 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012727 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012728 n = -1;
12729 break;
12730 }
12731 rettv->vval.v_number = n;
12732}
12733
12734/*
12735 * "undofile(name)" function
12736 */
12737 static void
12738f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12739{
12740 rettv->v_type = VAR_STRING;
12741#ifdef FEAT_PERSISTENT_UNDO
12742 {
12743 char_u *fname = get_tv_string(&argvars[0]);
12744
12745 if (*fname == NUL)
12746 {
12747 /* If there is no file name there will be no undo file. */
12748 rettv->vval.v_string = NULL;
12749 }
12750 else
12751 {
12752 char_u *ffname = FullName_save(fname, FALSE);
12753
12754 if (ffname != NULL)
12755 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12756 vim_free(ffname);
12757 }
12758 }
12759#else
12760 rettv->vval.v_string = NULL;
12761#endif
12762}
12763
12764/*
12765 * "undotree()" function
12766 */
12767 static void
12768f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12769{
12770 if (rettv_dict_alloc(rettv) == OK)
12771 {
12772 dict_T *dict = rettv->vval.v_dict;
12773 list_T *list;
12774
12775 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
12776 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
12777 dict_add_nr_str(dict, "save_last",
12778 (long)curbuf->b_u_save_nr_last, NULL);
12779 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
12780 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
12781 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
12782
12783 list = list_alloc();
12784 if (list != NULL)
12785 {
12786 u_eval_tree(curbuf->b_u_oldhead, list);
12787 dict_add_list(dict, "entries", list);
12788 }
12789 }
12790}
12791
12792/*
12793 * "values(dict)" function
12794 */
12795 static void
12796f_values(typval_T *argvars, typval_T *rettv)
12797{
12798 dict_list(argvars, rettv, 1);
12799}
12800
12801/*
12802 * "virtcol(string)" function
12803 */
12804 static void
12805f_virtcol(typval_T *argvars, typval_T *rettv)
12806{
12807 colnr_T vcol = 0;
12808 pos_T *fp;
12809 int fnum = curbuf->b_fnum;
12810
12811 fp = var2fpos(&argvars[0], FALSE, &fnum);
12812 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12813 && fnum == curbuf->b_fnum)
12814 {
12815 getvvcol(curwin, fp, NULL, NULL, &vcol);
12816 ++vcol;
12817 }
12818
12819 rettv->vval.v_number = vcol;
12820}
12821
12822/*
12823 * "visualmode()" function
12824 */
12825 static void
12826f_visualmode(typval_T *argvars, typval_T *rettv)
12827{
12828 char_u str[2];
12829
12830 rettv->v_type = VAR_STRING;
12831 str[0] = curbuf->b_visual_mode_eval;
12832 str[1] = NUL;
12833 rettv->vval.v_string = vim_strsave(str);
12834
12835 /* A non-zero number or non-empty string argument: reset mode. */
12836 if (non_zero_arg(&argvars[0]))
12837 curbuf->b_visual_mode_eval = NUL;
12838}
12839
12840/*
12841 * "wildmenumode()" function
12842 */
12843 static void
12844f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12845{
12846#ifdef FEAT_WILDMENU
12847 if (wild_menu_showing)
12848 rettv->vval.v_number = 1;
12849#endif
12850}
12851
12852/*
12853 * "winbufnr(nr)" function
12854 */
12855 static void
12856f_winbufnr(typval_T *argvars, typval_T *rettv)
12857{
12858 win_T *wp;
12859
12860 wp = find_win_by_nr(&argvars[0], NULL);
12861 if (wp == NULL)
12862 rettv->vval.v_number = -1;
12863 else
12864 rettv->vval.v_number = wp->w_buffer->b_fnum;
12865}
12866
12867/*
12868 * "wincol()" function
12869 */
12870 static void
12871f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12872{
12873 validate_cursor();
12874 rettv->vval.v_number = curwin->w_wcol + 1;
12875}
12876
12877/*
12878 * "winheight(nr)" function
12879 */
12880 static void
12881f_winheight(typval_T *argvars, typval_T *rettv)
12882{
12883 win_T *wp;
12884
12885 wp = find_win_by_nr(&argvars[0], NULL);
12886 if (wp == NULL)
12887 rettv->vval.v_number = -1;
12888 else
12889 rettv->vval.v_number = wp->w_height;
12890}
12891
12892/*
12893 * "winline()" function
12894 */
12895 static void
12896f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12897{
12898 validate_cursor();
12899 rettv->vval.v_number = curwin->w_wrow + 1;
12900}
12901
12902/*
12903 * "winnr()" function
12904 */
12905 static void
12906f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12907{
12908 int nr = 1;
12909
12910#ifdef FEAT_WINDOWS
12911 nr = get_winnr(curtab, &argvars[0]);
12912#endif
12913 rettv->vval.v_number = nr;
12914}
12915
12916/*
12917 * "winrestcmd()" function
12918 */
12919 static void
12920f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12921{
12922#ifdef FEAT_WINDOWS
12923 win_T *wp;
12924 int winnr = 1;
12925 garray_T ga;
12926 char_u buf[50];
12927
12928 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012929 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012930 {
12931 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12932 ga_concat(&ga, buf);
12933 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12934 ga_concat(&ga, buf);
12935 ++winnr;
12936 }
12937 ga_append(&ga, NUL);
12938
12939 rettv->vval.v_string = ga.ga_data;
12940#else
12941 rettv->vval.v_string = NULL;
12942#endif
12943 rettv->v_type = VAR_STRING;
12944}
12945
12946/*
12947 * "winrestview()" function
12948 */
12949 static void
12950f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12951{
12952 dict_T *dict;
12953
12954 if (argvars[0].v_type != VAR_DICT
12955 || (dict = argvars[0].vval.v_dict) == NULL)
12956 EMSG(_(e_invarg));
12957 else
12958 {
12959 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
12960 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
12961 if (dict_find(dict, (char_u *)"col", -1) != NULL)
12962 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
12963#ifdef FEAT_VIRTUALEDIT
12964 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
12965 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
12966#endif
12967 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12968 {
12969 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
12970 curwin->w_set_curswant = FALSE;
12971 }
12972
12973 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
12974 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
12975#ifdef FEAT_DIFF
12976 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
12977 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
12978#endif
12979 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
12980 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
12981 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
12982 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
12983
12984 check_cursor();
12985 win_new_height(curwin, curwin->w_height);
12986# ifdef FEAT_WINDOWS
12987 win_new_width(curwin, W_WIDTH(curwin));
12988# endif
12989 changed_window_setting();
12990
12991 if (curwin->w_topline <= 0)
12992 curwin->w_topline = 1;
12993 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12994 curwin->w_topline = curbuf->b_ml.ml_line_count;
12995#ifdef FEAT_DIFF
12996 check_topfill(curwin, TRUE);
12997#endif
12998 }
12999}
13000
13001/*
13002 * "winsaveview()" function
13003 */
13004 static void
13005f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13006{
13007 dict_T *dict;
13008
13009 if (rettv_dict_alloc(rettv) == FAIL)
13010 return;
13011 dict = rettv->vval.v_dict;
13012
13013 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13014 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13015#ifdef FEAT_VIRTUALEDIT
13016 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13017#endif
13018 update_curswant();
13019 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13020
13021 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13022#ifdef FEAT_DIFF
13023 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13024#endif
13025 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13026 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13027}
13028
13029/*
13030 * "winwidth(nr)" function
13031 */
13032 static void
13033f_winwidth(typval_T *argvars, typval_T *rettv)
13034{
13035 win_T *wp;
13036
13037 wp = find_win_by_nr(&argvars[0], NULL);
13038 if (wp == NULL)
13039 rettv->vval.v_number = -1;
13040 else
13041#ifdef FEAT_WINDOWS
13042 rettv->vval.v_number = wp->w_width;
13043#else
13044 rettv->vval.v_number = Columns;
13045#endif
13046}
13047
13048/*
13049 * "wordcount()" function
13050 */
13051 static void
13052f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13053{
13054 if (rettv_dict_alloc(rettv) == FAIL)
13055 return;
13056 cursor_pos_info(rettv->vval.v_dict);
13057}
13058
13059/*
13060 * "writefile()" function
13061 */
13062 static void
13063f_writefile(typval_T *argvars, typval_T *rettv)
13064{
13065 int binary = FALSE;
13066 int append = FALSE;
13067 char_u *fname;
13068 FILE *fd;
13069 int ret = 0;
13070
13071 if (check_restricted() || check_secure())
13072 return;
13073
13074 if (argvars[0].v_type != VAR_LIST)
13075 {
13076 EMSG2(_(e_listarg), "writefile()");
13077 return;
13078 }
13079 if (argvars[0].vval.v_list == NULL)
13080 return;
13081
13082 if (argvars[2].v_type != VAR_UNKNOWN)
13083 {
13084 if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL)
13085 binary = TRUE;
13086 if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL)
13087 append = TRUE;
13088 }
13089
13090 /* Always open the file in binary mode, library functions have a mind of
13091 * their own about CR-LF conversion. */
13092 fname = get_tv_string(&argvars[1]);
13093 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13094 append ? APPENDBIN : WRITEBIN)) == NULL)
13095 {
13096 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13097 ret = -1;
13098 }
13099 else
13100 {
13101 if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL)
13102 ret = -1;
13103 fclose(fd);
13104 }
13105
13106 rettv->vval.v_number = ret;
13107}
13108
13109/*
13110 * "xor(expr, expr)" function
13111 */
13112 static void
13113f_xor(typval_T *argvars, typval_T *rettv)
13114{
13115 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13116 ^ get_tv_number_chk(&argvars[1], NULL);
13117}
13118
13119
13120#endif /* FEAT_EVAL */