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