blob: ff545893e90286b35ccab5ac9d9d1542ad2c23a2 [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
Bram Moolenaard0573012017-10-28 21:11:06 +020027#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028# 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);
Bram Moolenaarca851592018-06-06 21:04:07 +020043static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_argc(typval_T *argvars, typval_T *rettv);
45static void f_argidx(typval_T *argvars, typval_T *rettv);
46static void f_arglistid(typval_T *argvars, typval_T *rettv);
47static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010048static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010050static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_assert_exception(typval_T *argvars, typval_T *rettv);
52static void f_assert_fails(typval_T *argvars, typval_T *rettv);
53static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020054static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_assert_match(typval_T *argvars, typval_T *rettv);
56static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
57static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010058static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020059static void f_assert_true(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_asin(typval_T *argvars, typval_T *rettv);
62static void f_atan(typval_T *argvars, typval_T *rettv);
63static void f_atan2(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010065#ifdef FEAT_BEVAL
66static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010067# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010068static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010069# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010070#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020071static void f_browse(typval_T *argvars, typval_T *rettv);
72static void f_browsedir(typval_T *argvars, typval_T *rettv);
73static void f_bufexists(typval_T *argvars, typval_T *rettv);
74static void f_buflisted(typval_T *argvars, typval_T *rettv);
75static void f_bufloaded(typval_T *argvars, typval_T *rettv);
76static void f_bufname(typval_T *argvars, typval_T *rettv);
77static void f_bufnr(typval_T *argvars, typval_T *rettv);
78static void f_bufwinid(typval_T *argvars, typval_T *rettv);
79static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
80static void f_byte2line(typval_T *argvars, typval_T *rettv);
81static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
82static void f_byteidx(typval_T *argvars, typval_T *rettv);
83static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
84static void f_call(typval_T *argvars, typval_T *rettv);
85#ifdef FEAT_FLOAT
86static void f_ceil(typval_T *argvars, typval_T *rettv);
87#endif
88#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010089static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020090static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020091static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
93static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
94static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
95static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
96static void f_ch_info(typval_T *argvars, typval_T *rettv);
97static void f_ch_log(typval_T *argvars, typval_T *rettv);
98static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
99static void f_ch_open(typval_T *argvars, typval_T *rettv);
100static void f_ch_read(typval_T *argvars, typval_T *rettv);
101static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
102static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
103static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
104static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
105static void f_ch_status(typval_T *argvars, typval_T *rettv);
106#endif
107static void f_changenr(typval_T *argvars, typval_T *rettv);
108static void f_char2nr(typval_T *argvars, typval_T *rettv);
109static void f_cindent(typval_T *argvars, typval_T *rettv);
110static void f_clearmatches(typval_T *argvars, typval_T *rettv);
111static void f_col(typval_T *argvars, typval_T *rettv);
112#if defined(FEAT_INS_EXPAND)
113static void f_complete(typval_T *argvars, typval_T *rettv);
114static void f_complete_add(typval_T *argvars, typval_T *rettv);
115static void f_complete_check(typval_T *argvars, typval_T *rettv);
116#endif
117static void f_confirm(typval_T *argvars, typval_T *rettv);
118static void f_copy(typval_T *argvars, typval_T *rettv);
119#ifdef FEAT_FLOAT
120static void f_cos(typval_T *argvars, typval_T *rettv);
121static void f_cosh(typval_T *argvars, typval_T *rettv);
122#endif
123static void f_count(typval_T *argvars, typval_T *rettv);
124static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
125static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200126#ifdef WIN3264
127static void f_debugbreak(typval_T *argvars, typval_T *rettv);
128#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_deepcopy(typval_T *argvars, typval_T *rettv);
130static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200131static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_did_filetype(typval_T *argvars, typval_T *rettv);
133static void f_diff_filler(typval_T *argvars, typval_T *rettv);
134static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
135static void f_empty(typval_T *argvars, typval_T *rettv);
136static void f_escape(typval_T *argvars, typval_T *rettv);
137static void f_eval(typval_T *argvars, typval_T *rettv);
138static void f_eventhandler(typval_T *argvars, typval_T *rettv);
139static void f_executable(typval_T *argvars, typval_T *rettv);
140static void f_execute(typval_T *argvars, typval_T *rettv);
141static void f_exepath(typval_T *argvars, typval_T *rettv);
142static void f_exists(typval_T *argvars, typval_T *rettv);
143#ifdef FEAT_FLOAT
144static void f_exp(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_expand(typval_T *argvars, typval_T *rettv);
147static void f_extend(typval_T *argvars, typval_T *rettv);
148static void f_feedkeys(typval_T *argvars, typval_T *rettv);
149static void f_filereadable(typval_T *argvars, typval_T *rettv);
150static void f_filewritable(typval_T *argvars, typval_T *rettv);
151static void f_filter(typval_T *argvars, typval_T *rettv);
152static void f_finddir(typval_T *argvars, typval_T *rettv);
153static void f_findfile(typval_T *argvars, typval_T *rettv);
154#ifdef FEAT_FLOAT
155static void f_float2nr(typval_T *argvars, typval_T *rettv);
156static void f_floor(typval_T *argvars, typval_T *rettv);
157static void f_fmod(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_fnameescape(typval_T *argvars, typval_T *rettv);
160static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
161static void f_foldclosed(typval_T *argvars, typval_T *rettv);
162static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
163static void f_foldlevel(typval_T *argvars, typval_T *rettv);
164static void f_foldtext(typval_T *argvars, typval_T *rettv);
165static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
166static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200167static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_function(typval_T *argvars, typval_T *rettv);
169static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
170static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200171static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_getbufline(typval_T *argvars, typval_T *rettv);
173static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100174static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_getchar(typval_T *argvars, typval_T *rettv);
176static void f_getcharmod(typval_T *argvars, typval_T *rettv);
177static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
178static void f_getcmdline(typval_T *argvars, typval_T *rettv);
179#if defined(FEAT_CMDL_COMPL)
180static void f_getcompletion(typval_T *argvars, typval_T *rettv);
181#endif
182static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
183static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
184static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
185static void f_getcwd(typval_T *argvars, typval_T *rettv);
186static void f_getfontname(typval_T *argvars, typval_T *rettv);
187static void f_getfperm(typval_T *argvars, typval_T *rettv);
188static void f_getfsize(typval_T *argvars, typval_T *rettv);
189static void f_getftime(typval_T *argvars, typval_T *rettv);
190static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100191static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200193static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getmatches(typval_T *argvars, typval_T *rettv);
195static void f_getpid(typval_T *argvars, typval_T *rettv);
196static void f_getcurpos(typval_T *argvars, typval_T *rettv);
197static void f_getpos(typval_T *argvars, typval_T *rettv);
198static void f_getqflist(typval_T *argvars, typval_T *rettv);
199static void f_getreg(typval_T *argvars, typval_T *rettv);
200static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200201static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_gettabvar(typval_T *argvars, typval_T *rettv);
203static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200204static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100205static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200206static void f_getwinposx(typval_T *argvars, typval_T *rettv);
207static void f_getwinposy(typval_T *argvars, typval_T *rettv);
208static void f_getwinvar(typval_T *argvars, typval_T *rettv);
209static void f_glob(typval_T *argvars, typval_T *rettv);
210static void f_globpath(typval_T *argvars, typval_T *rettv);
211static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
212static void f_has(typval_T *argvars, typval_T *rettv);
213static void f_has_key(typval_T *argvars, typval_T *rettv);
214static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
215static void f_hasmapto(typval_T *argvars, typval_T *rettv);
216static void f_histadd(typval_T *argvars, typval_T *rettv);
217static void f_histdel(typval_T *argvars, typval_T *rettv);
218static void f_histget(typval_T *argvars, typval_T *rettv);
219static void f_histnr(typval_T *argvars, typval_T *rettv);
220static void f_hlID(typval_T *argvars, typval_T *rettv);
221static void f_hlexists(typval_T *argvars, typval_T *rettv);
222static void f_hostname(typval_T *argvars, typval_T *rettv);
223static void f_iconv(typval_T *argvars, typval_T *rettv);
224static void f_indent(typval_T *argvars, typval_T *rettv);
225static void f_index(typval_T *argvars, typval_T *rettv);
226static void f_input(typval_T *argvars, typval_T *rettv);
227static void f_inputdialog(typval_T *argvars, typval_T *rettv);
228static void f_inputlist(typval_T *argvars, typval_T *rettv);
229static void f_inputrestore(typval_T *argvars, typval_T *rettv);
230static void f_inputsave(typval_T *argvars, typval_T *rettv);
231static void f_inputsecret(typval_T *argvars, typval_T *rettv);
232static void f_insert(typval_T *argvars, typval_T *rettv);
233static void f_invert(typval_T *argvars, typval_T *rettv);
234static void f_isdirectory(typval_T *argvars, typval_T *rettv);
235static void f_islocked(typval_T *argvars, typval_T *rettv);
236#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
237static void f_isnan(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_items(typval_T *argvars, typval_T *rettv);
240#ifdef FEAT_JOB_CHANNEL
241static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
242static void f_job_info(typval_T *argvars, typval_T *rettv);
243static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
244static void f_job_start(typval_T *argvars, typval_T *rettv);
245static void f_job_stop(typval_T *argvars, typval_T *rettv);
246static void f_job_status(typval_T *argvars, typval_T *rettv);
247#endif
248static void f_join(typval_T *argvars, typval_T *rettv);
249static void f_js_decode(typval_T *argvars, typval_T *rettv);
250static void f_js_encode(typval_T *argvars, typval_T *rettv);
251static void f_json_decode(typval_T *argvars, typval_T *rettv);
252static void f_json_encode(typval_T *argvars, typval_T *rettv);
253static void f_keys(typval_T *argvars, typval_T *rettv);
254static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
255static void f_len(typval_T *argvars, typval_T *rettv);
256static void f_libcall(typval_T *argvars, typval_T *rettv);
257static void f_libcallnr(typval_T *argvars, typval_T *rettv);
258static void f_line(typval_T *argvars, typval_T *rettv);
259static void f_line2byte(typval_T *argvars, typval_T *rettv);
260static void f_lispindent(typval_T *argvars, typval_T *rettv);
261static void f_localtime(typval_T *argvars, typval_T *rettv);
262#ifdef FEAT_FLOAT
263static void f_log(typval_T *argvars, typval_T *rettv);
264static void f_log10(typval_T *argvars, typval_T *rettv);
265#endif
266#ifdef FEAT_LUA
267static void f_luaeval(typval_T *argvars, typval_T *rettv);
268#endif
269static void f_map(typval_T *argvars, typval_T *rettv);
270static void f_maparg(typval_T *argvars, typval_T *rettv);
271static void f_mapcheck(typval_T *argvars, typval_T *rettv);
272static void f_match(typval_T *argvars, typval_T *rettv);
273static void f_matchadd(typval_T *argvars, typval_T *rettv);
274static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
275static void f_matcharg(typval_T *argvars, typval_T *rettv);
276static void f_matchdelete(typval_T *argvars, typval_T *rettv);
277static void f_matchend(typval_T *argvars, typval_T *rettv);
278static void f_matchlist(typval_T *argvars, typval_T *rettv);
279static void f_matchstr(typval_T *argvars, typval_T *rettv);
280static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
281static void f_max(typval_T *argvars, typval_T *rettv);
282static void f_min(typval_T *argvars, typval_T *rettv);
283#ifdef vim_mkdir
284static void f_mkdir(typval_T *argvars, typval_T *rettv);
285#endif
286static void f_mode(typval_T *argvars, typval_T *rettv);
287#ifdef FEAT_MZSCHEME
288static void f_mzeval(typval_T *argvars, typval_T *rettv);
289#endif
290static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
291static void f_nr2char(typval_T *argvars, typval_T *rettv);
292static void f_or(typval_T *argvars, typval_T *rettv);
293static void f_pathshorten(typval_T *argvars, typval_T *rettv);
294#ifdef FEAT_PERL
295static void f_perleval(typval_T *argvars, typval_T *rettv);
296#endif
297#ifdef FEAT_FLOAT
298static void f_pow(typval_T *argvars, typval_T *rettv);
299#endif
300static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
301static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200302#ifdef FEAT_JOB_CHANNEL
303static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200304static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200305static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
306#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200307static void f_pumvisible(typval_T *argvars, typval_T *rettv);
308#ifdef FEAT_PYTHON3
309static void f_py3eval(typval_T *argvars, typval_T *rettv);
310#endif
311#ifdef FEAT_PYTHON
312static void f_pyeval(typval_T *argvars, typval_T *rettv);
313#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100314#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
315static void f_pyxeval(typval_T *argvars, typval_T *rettv);
316#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317static void f_range(typval_T *argvars, typval_T *rettv);
318static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200319static void f_reg_executing(typval_T *argvars, typval_T *rettv);
320static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200321static void f_reltime(typval_T *argvars, typval_T *rettv);
322#ifdef FEAT_FLOAT
323static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
324#endif
325static void f_reltimestr(typval_T *argvars, typval_T *rettv);
326static void f_remote_expr(typval_T *argvars, typval_T *rettv);
327static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
328static void f_remote_peek(typval_T *argvars, typval_T *rettv);
329static void f_remote_read(typval_T *argvars, typval_T *rettv);
330static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100331static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200332static void f_remove(typval_T *argvars, typval_T *rettv);
333static void f_rename(typval_T *argvars, typval_T *rettv);
334static void f_repeat(typval_T *argvars, typval_T *rettv);
335static void f_resolve(typval_T *argvars, typval_T *rettv);
336static void f_reverse(typval_T *argvars, typval_T *rettv);
337#ifdef FEAT_FLOAT
338static void f_round(typval_T *argvars, typval_T *rettv);
339#endif
340static void f_screenattr(typval_T *argvars, typval_T *rettv);
341static void f_screenchar(typval_T *argvars, typval_T *rettv);
342static void f_screencol(typval_T *argvars, typval_T *rettv);
343static void f_screenrow(typval_T *argvars, typval_T *rettv);
344static void f_search(typval_T *argvars, typval_T *rettv);
345static void f_searchdecl(typval_T *argvars, typval_T *rettv);
346static void f_searchpair(typval_T *argvars, typval_T *rettv);
347static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
348static void f_searchpos(typval_T *argvars, typval_T *rettv);
349static void f_server2client(typval_T *argvars, typval_T *rettv);
350static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200351static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352static void f_setbufvar(typval_T *argvars, typval_T *rettv);
353static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
354static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
355static void f_setfperm(typval_T *argvars, typval_T *rettv);
356static void f_setline(typval_T *argvars, typval_T *rettv);
357static void f_setloclist(typval_T *argvars, typval_T *rettv);
358static void f_setmatches(typval_T *argvars, typval_T *rettv);
359static void f_setpos(typval_T *argvars, typval_T *rettv);
360static void f_setqflist(typval_T *argvars, typval_T *rettv);
361static void f_setreg(typval_T *argvars, typval_T *rettv);
362static void f_settabvar(typval_T *argvars, typval_T *rettv);
363static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
364static void f_setwinvar(typval_T *argvars, typval_T *rettv);
365#ifdef FEAT_CRYPT
366static void f_sha256(typval_T *argvars, typval_T *rettv);
367#endif /* FEAT_CRYPT */
368static void f_shellescape(typval_T *argvars, typval_T *rettv);
369static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
370static void f_simplify(typval_T *argvars, typval_T *rettv);
371#ifdef FEAT_FLOAT
372static void f_sin(typval_T *argvars, typval_T *rettv);
373static void f_sinh(typval_T *argvars, typval_T *rettv);
374#endif
375static void f_sort(typval_T *argvars, typval_T *rettv);
376static void f_soundfold(typval_T *argvars, typval_T *rettv);
377static void f_spellbadword(typval_T *argvars, typval_T *rettv);
378static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
379static void f_split(typval_T *argvars, typval_T *rettv);
380#ifdef FEAT_FLOAT
381static void f_sqrt(typval_T *argvars, typval_T *rettv);
382static void f_str2float(typval_T *argvars, typval_T *rettv);
383#endif
384static void f_str2nr(typval_T *argvars, typval_T *rettv);
385static void f_strchars(typval_T *argvars, typval_T *rettv);
386#ifdef HAVE_STRFTIME
387static void f_strftime(typval_T *argvars, typval_T *rettv);
388#endif
389static void f_strgetchar(typval_T *argvars, typval_T *rettv);
390static void f_stridx(typval_T *argvars, typval_T *rettv);
391static void f_string(typval_T *argvars, typval_T *rettv);
392static void f_strlen(typval_T *argvars, typval_T *rettv);
393static void f_strcharpart(typval_T *argvars, typval_T *rettv);
394static void f_strpart(typval_T *argvars, typval_T *rettv);
395static void f_strridx(typval_T *argvars, typval_T *rettv);
396static void f_strtrans(typval_T *argvars, typval_T *rettv);
397static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
398static void f_strwidth(typval_T *argvars, typval_T *rettv);
399static void f_submatch(typval_T *argvars, typval_T *rettv);
400static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200401static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200402static void f_synID(typval_T *argvars, typval_T *rettv);
403static void f_synIDattr(typval_T *argvars, typval_T *rettv);
404static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
405static void f_synstack(typval_T *argvars, typval_T *rettv);
406static void f_synconcealed(typval_T *argvars, typval_T *rettv);
407static void f_system(typval_T *argvars, typval_T *rettv);
408static void f_systemlist(typval_T *argvars, typval_T *rettv);
409static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
410static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
411static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
412static void f_taglist(typval_T *argvars, typval_T *rettv);
413static void f_tagfiles(typval_T *argvars, typval_T *rettv);
414static void f_tempname(typval_T *argvars, typval_T *rettv);
415static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
416static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200417static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100418static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100420static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421#ifdef FEAT_JOB_CHANNEL
422static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
423#endif
424static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
425#ifdef FEAT_JOB_CHANNEL
426static void f_test_null_job(typval_T *argvars, typval_T *rettv);
427#endif
428static void f_test_null_list(typval_T *argvars, typval_T *rettv);
429static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
430static void f_test_null_string(typval_T *argvars, typval_T *rettv);
431static void f_test_settime(typval_T *argvars, typval_T *rettv);
432#ifdef FEAT_FLOAT
433static void f_tan(typval_T *argvars, typval_T *rettv);
434static void f_tanh(typval_T *argvars, typval_T *rettv);
435#endif
436#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200437static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200438static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439static void f_timer_start(typval_T *argvars, typval_T *rettv);
440static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200441static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442#endif
443static void f_tolower(typval_T *argvars, typval_T *rettv);
444static void f_toupper(typval_T *argvars, typval_T *rettv);
445static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100446static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447#ifdef FEAT_FLOAT
448static void f_trunc(typval_T *argvars, typval_T *rettv);
449#endif
450static void f_type(typval_T *argvars, typval_T *rettv);
451static void f_undofile(typval_T *argvars, typval_T *rettv);
452static void f_undotree(typval_T *argvars, typval_T *rettv);
453static void f_uniq(typval_T *argvars, typval_T *rettv);
454static void f_values(typval_T *argvars, typval_T *rettv);
455static void f_virtcol(typval_T *argvars, typval_T *rettv);
456static void f_visualmode(typval_T *argvars, typval_T *rettv);
457static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
458static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
459static void f_win_getid(typval_T *argvars, typval_T *rettv);
460static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
461static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
462static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100463static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200464static void f_winbufnr(typval_T *argvars, typval_T *rettv);
465static void f_wincol(typval_T *argvars, typval_T *rettv);
466static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200467static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200468static void f_winline(typval_T *argvars, typval_T *rettv);
469static void f_winnr(typval_T *argvars, typval_T *rettv);
470static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
471static void f_winrestview(typval_T *argvars, typval_T *rettv);
472static void f_winsaveview(typval_T *argvars, typval_T *rettv);
473static void f_winwidth(typval_T *argvars, typval_T *rettv);
474static void f_writefile(typval_T *argvars, typval_T *rettv);
475static void f_wordcount(typval_T *argvars, typval_T *rettv);
476static void f_xor(typval_T *argvars, typval_T *rettv);
477
478/*
479 * Array with names and number of arguments of all internal functions
480 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
481 */
482static struct fst
483{
484 char *f_name; /* function name */
485 char f_min_argc; /* minimal number of arguments */
486 char f_max_argc; /* maximal number of arguments */
487 void (*f_func)(typval_T *args, typval_T *rvar);
488 /* implementation of function */
489} functions[] =
490{
491#ifdef FEAT_FLOAT
492 {"abs", 1, 1, f_abs},
493 {"acos", 1, 1, f_acos}, /* WJMc */
494#endif
495 {"add", 2, 2, f_add},
496 {"and", 2, 2, f_and},
497 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200498 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200499 {"argc", 0, 0, f_argc},
500 {"argidx", 0, 0, f_argidx},
501 {"arglistid", 0, 2, f_arglistid},
502 {"argv", 0, 1, f_argv},
503#ifdef FEAT_FLOAT
504 {"asin", 1, 1, f_asin}, /* WJMc */
505#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100506 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200507 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100508 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509 {"assert_exception", 1, 2, f_assert_exception},
510 {"assert_fails", 1, 2, f_assert_fails},
511 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100512 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513 {"assert_match", 2, 3, f_assert_match},
514 {"assert_notequal", 2, 3, f_assert_notequal},
515 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100516 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517 {"assert_true", 1, 2, f_assert_true},
518#ifdef FEAT_FLOAT
519 {"atan", 1, 1, f_atan},
520 {"atan2", 2, 2, f_atan2},
521#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100522#ifdef FEAT_BEVAL
523 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100524# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100525 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100526# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100527#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528 {"browse", 4, 4, f_browse},
529 {"browsedir", 2, 2, f_browsedir},
530 {"bufexists", 1, 1, f_bufexists},
531 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
532 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
533 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
534 {"buflisted", 1, 1, f_buflisted},
535 {"bufloaded", 1, 1, f_bufloaded},
536 {"bufname", 1, 1, f_bufname},
537 {"bufnr", 1, 2, f_bufnr},
538 {"bufwinid", 1, 1, f_bufwinid},
539 {"bufwinnr", 1, 1, f_bufwinnr},
540 {"byte2line", 1, 1, f_byte2line},
541 {"byteidx", 2, 2, f_byteidx},
542 {"byteidxcomp", 2, 2, f_byteidxcomp},
543 {"call", 2, 3, f_call},
544#ifdef FEAT_FLOAT
545 {"ceil", 1, 1, f_ceil},
546#endif
547#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100548 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200549 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200550 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200551 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
552 {"ch_evalraw", 2, 3, f_ch_evalraw},
553 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
554 {"ch_getjob", 1, 1, f_ch_getjob},
555 {"ch_info", 1, 1, f_ch_info},
556 {"ch_log", 1, 2, f_ch_log},
557 {"ch_logfile", 1, 2, f_ch_logfile},
558 {"ch_open", 1, 2, f_ch_open},
559 {"ch_read", 1, 2, f_ch_read},
560 {"ch_readraw", 1, 2, f_ch_readraw},
561 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
562 {"ch_sendraw", 2, 3, f_ch_sendraw},
563 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200564 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200565#endif
566 {"changenr", 0, 0, f_changenr},
567 {"char2nr", 1, 2, f_char2nr},
568 {"cindent", 1, 1, f_cindent},
569 {"clearmatches", 0, 0, f_clearmatches},
570 {"col", 1, 1, f_col},
571#if defined(FEAT_INS_EXPAND)
572 {"complete", 2, 2, f_complete},
573 {"complete_add", 1, 1, f_complete_add},
574 {"complete_check", 0, 0, f_complete_check},
575#endif
576 {"confirm", 1, 4, f_confirm},
577 {"copy", 1, 1, f_copy},
578#ifdef FEAT_FLOAT
579 {"cos", 1, 1, f_cos},
580 {"cosh", 1, 1, f_cosh},
581#endif
582 {"count", 2, 4, f_count},
583 {"cscope_connection",0,3, f_cscope_connection},
584 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200585#ifdef WIN3264
586 {"debugbreak", 1, 1, f_debugbreak},
587#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588 {"deepcopy", 1, 2, f_deepcopy},
589 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200590 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200591 {"did_filetype", 0, 0, f_did_filetype},
592 {"diff_filler", 1, 1, f_diff_filler},
593 {"diff_hlID", 2, 2, f_diff_hlID},
594 {"empty", 1, 1, f_empty},
595 {"escape", 2, 2, f_escape},
596 {"eval", 1, 1, f_eval},
597 {"eventhandler", 0, 0, f_eventhandler},
598 {"executable", 1, 1, f_executable},
599 {"execute", 1, 2, f_execute},
600 {"exepath", 1, 1, f_exepath},
601 {"exists", 1, 1, f_exists},
602#ifdef FEAT_FLOAT
603 {"exp", 1, 1, f_exp},
604#endif
605 {"expand", 1, 3, f_expand},
606 {"extend", 2, 3, f_extend},
607 {"feedkeys", 1, 2, f_feedkeys},
608 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
609 {"filereadable", 1, 1, f_filereadable},
610 {"filewritable", 1, 1, f_filewritable},
611 {"filter", 2, 2, f_filter},
612 {"finddir", 1, 3, f_finddir},
613 {"findfile", 1, 3, f_findfile},
614#ifdef FEAT_FLOAT
615 {"float2nr", 1, 1, f_float2nr},
616 {"floor", 1, 1, f_floor},
617 {"fmod", 2, 2, f_fmod},
618#endif
619 {"fnameescape", 1, 1, f_fnameescape},
620 {"fnamemodify", 2, 2, f_fnamemodify},
621 {"foldclosed", 1, 1, f_foldclosed},
622 {"foldclosedend", 1, 1, f_foldclosedend},
623 {"foldlevel", 1, 1, f_foldlevel},
624 {"foldtext", 0, 0, f_foldtext},
625 {"foldtextresult", 1, 1, f_foldtextresult},
626 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200627 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200628 {"function", 1, 3, f_function},
629 {"garbagecollect", 0, 1, f_garbagecollect},
630 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200631 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632 {"getbufline", 2, 3, f_getbufline},
633 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100634 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635 {"getchar", 0, 1, f_getchar},
636 {"getcharmod", 0, 0, f_getcharmod},
637 {"getcharsearch", 0, 0, f_getcharsearch},
638 {"getcmdline", 0, 0, f_getcmdline},
639 {"getcmdpos", 0, 0, f_getcmdpos},
640 {"getcmdtype", 0, 0, f_getcmdtype},
641 {"getcmdwintype", 0, 0, f_getcmdwintype},
642#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200643 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644#endif
645 {"getcurpos", 0, 0, f_getcurpos},
646 {"getcwd", 0, 2, f_getcwd},
647 {"getfontname", 0, 1, f_getfontname},
648 {"getfperm", 1, 1, f_getfperm},
649 {"getfsize", 1, 1, f_getfsize},
650 {"getftime", 1, 1, f_getftime},
651 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100652 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200654 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655 {"getmatches", 0, 0, f_getmatches},
656 {"getpid", 0, 0, f_getpid},
657 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200658 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200659 {"getreg", 0, 3, f_getreg},
660 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200661 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662 {"gettabvar", 2, 3, f_gettabvar},
663 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200664 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100665 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666 {"getwinposx", 0, 0, f_getwinposx},
667 {"getwinposy", 0, 0, f_getwinposy},
668 {"getwinvar", 2, 3, f_getwinvar},
669 {"glob", 1, 4, f_glob},
670 {"glob2regpat", 1, 1, f_glob2regpat},
671 {"globpath", 2, 5, f_globpath},
672 {"has", 1, 1, f_has},
673 {"has_key", 2, 2, f_has_key},
674 {"haslocaldir", 0, 2, f_haslocaldir},
675 {"hasmapto", 1, 3, f_hasmapto},
676 {"highlightID", 1, 1, f_hlID}, /* obsolete */
677 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
678 {"histadd", 2, 2, f_histadd},
679 {"histdel", 1, 2, f_histdel},
680 {"histget", 1, 2, f_histget},
681 {"histnr", 1, 1, f_histnr},
682 {"hlID", 1, 1, f_hlID},
683 {"hlexists", 1, 1, f_hlexists},
684 {"hostname", 0, 0, f_hostname},
685 {"iconv", 3, 3, f_iconv},
686 {"indent", 1, 1, f_indent},
687 {"index", 2, 4, f_index},
688 {"input", 1, 3, f_input},
689 {"inputdialog", 1, 3, f_inputdialog},
690 {"inputlist", 1, 1, f_inputlist},
691 {"inputrestore", 0, 0, f_inputrestore},
692 {"inputsave", 0, 0, f_inputsave},
693 {"inputsecret", 1, 2, f_inputsecret},
694 {"insert", 2, 3, f_insert},
695 {"invert", 1, 1, f_invert},
696 {"isdirectory", 1, 1, f_isdirectory},
697 {"islocked", 1, 1, f_islocked},
698#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
699 {"isnan", 1, 1, f_isnan},
700#endif
701 {"items", 1, 1, f_items},
702#ifdef FEAT_JOB_CHANNEL
703 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200704 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200705 {"job_setoptions", 2, 2, f_job_setoptions},
706 {"job_start", 1, 2, f_job_start},
707 {"job_status", 1, 1, f_job_status},
708 {"job_stop", 1, 2, f_job_stop},
709#endif
710 {"join", 1, 2, f_join},
711 {"js_decode", 1, 1, f_js_decode},
712 {"js_encode", 1, 1, f_js_encode},
713 {"json_decode", 1, 1, f_json_decode},
714 {"json_encode", 1, 1, f_json_encode},
715 {"keys", 1, 1, f_keys},
716 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
717 {"len", 1, 1, f_len},
718 {"libcall", 3, 3, f_libcall},
719 {"libcallnr", 3, 3, f_libcallnr},
720 {"line", 1, 1, f_line},
721 {"line2byte", 1, 1, f_line2byte},
722 {"lispindent", 1, 1, f_lispindent},
723 {"localtime", 0, 0, f_localtime},
724#ifdef FEAT_FLOAT
725 {"log", 1, 1, f_log},
726 {"log10", 1, 1, f_log10},
727#endif
728#ifdef FEAT_LUA
729 {"luaeval", 1, 2, f_luaeval},
730#endif
731 {"map", 2, 2, f_map},
732 {"maparg", 1, 4, f_maparg},
733 {"mapcheck", 1, 3, f_mapcheck},
734 {"match", 2, 4, f_match},
735 {"matchadd", 2, 5, f_matchadd},
736 {"matchaddpos", 2, 5, f_matchaddpos},
737 {"matcharg", 1, 1, f_matcharg},
738 {"matchdelete", 1, 1, f_matchdelete},
739 {"matchend", 2, 4, f_matchend},
740 {"matchlist", 2, 4, f_matchlist},
741 {"matchstr", 2, 4, f_matchstr},
742 {"matchstrpos", 2, 4, f_matchstrpos},
743 {"max", 1, 1, f_max},
744 {"min", 1, 1, f_min},
745#ifdef vim_mkdir
746 {"mkdir", 1, 3, f_mkdir},
747#endif
748 {"mode", 0, 1, f_mode},
749#ifdef FEAT_MZSCHEME
750 {"mzeval", 1, 1, f_mzeval},
751#endif
752 {"nextnonblank", 1, 1, f_nextnonblank},
753 {"nr2char", 1, 2, f_nr2char},
754 {"or", 2, 2, f_or},
755 {"pathshorten", 1, 1, f_pathshorten},
756#ifdef FEAT_PERL
757 {"perleval", 1, 1, f_perleval},
758#endif
759#ifdef FEAT_FLOAT
760 {"pow", 2, 2, f_pow},
761#endif
762 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100763 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200764#ifdef FEAT_JOB_CHANNEL
765 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200766 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200767 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
768#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200769 {"pumvisible", 0, 0, f_pumvisible},
770#ifdef FEAT_PYTHON3
771 {"py3eval", 1, 1, f_py3eval},
772#endif
773#ifdef FEAT_PYTHON
774 {"pyeval", 1, 1, f_pyeval},
775#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100776#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
777 {"pyxeval", 1, 1, f_pyxeval},
778#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779 {"range", 1, 3, f_range},
780 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200781 {"reg_executing", 0, 0, f_reg_executing},
782 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783 {"reltime", 0, 2, f_reltime},
784#ifdef FEAT_FLOAT
785 {"reltimefloat", 1, 1, f_reltimefloat},
786#endif
787 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100788 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200789 {"remote_foreground", 1, 1, f_remote_foreground},
790 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100791 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200792 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100793 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794 {"remove", 2, 3, f_remove},
795 {"rename", 2, 2, f_rename},
796 {"repeat", 2, 2, f_repeat},
797 {"resolve", 1, 1, f_resolve},
798 {"reverse", 1, 1, f_reverse},
799#ifdef FEAT_FLOAT
800 {"round", 1, 1, f_round},
801#endif
802 {"screenattr", 2, 2, f_screenattr},
803 {"screenchar", 2, 2, f_screenchar},
804 {"screencol", 0, 0, f_screencol},
805 {"screenrow", 0, 0, f_screenrow},
806 {"search", 1, 4, f_search},
807 {"searchdecl", 1, 3, f_searchdecl},
808 {"searchpair", 3, 7, f_searchpair},
809 {"searchpairpos", 3, 7, f_searchpairpos},
810 {"searchpos", 1, 4, f_searchpos},
811 {"server2client", 2, 2, f_server2client},
812 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200813 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814 {"setbufvar", 3, 3, f_setbufvar},
815 {"setcharsearch", 1, 1, f_setcharsearch},
816 {"setcmdpos", 1, 1, f_setcmdpos},
817 {"setfperm", 2, 2, f_setfperm},
818 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200819 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820 {"setmatches", 1, 1, f_setmatches},
821 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200822 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823 {"setreg", 2, 3, f_setreg},
824 {"settabvar", 3, 3, f_settabvar},
825 {"settabwinvar", 4, 4, f_settabwinvar},
826 {"setwinvar", 3, 3, f_setwinvar},
827#ifdef FEAT_CRYPT
828 {"sha256", 1, 1, f_sha256},
829#endif
830 {"shellescape", 1, 2, f_shellescape},
831 {"shiftwidth", 0, 0, f_shiftwidth},
832 {"simplify", 1, 1, f_simplify},
833#ifdef FEAT_FLOAT
834 {"sin", 1, 1, f_sin},
835 {"sinh", 1, 1, f_sinh},
836#endif
837 {"sort", 1, 3, f_sort},
838 {"soundfold", 1, 1, f_soundfold},
839 {"spellbadword", 0, 1, f_spellbadword},
840 {"spellsuggest", 1, 3, f_spellsuggest},
841 {"split", 1, 3, f_split},
842#ifdef FEAT_FLOAT
843 {"sqrt", 1, 1, f_sqrt},
844 {"str2float", 1, 1, f_str2float},
845#endif
846 {"str2nr", 1, 2, f_str2nr},
847 {"strcharpart", 2, 3, f_strcharpart},
848 {"strchars", 1, 2, f_strchars},
849 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
850#ifdef HAVE_STRFTIME
851 {"strftime", 1, 2, f_strftime},
852#endif
853 {"strgetchar", 2, 2, f_strgetchar},
854 {"stridx", 2, 3, f_stridx},
855 {"string", 1, 1, f_string},
856 {"strlen", 1, 1, f_strlen},
857 {"strpart", 2, 3, f_strpart},
858 {"strridx", 2, 3, f_strridx},
859 {"strtrans", 1, 1, f_strtrans},
860 {"strwidth", 1, 1, f_strwidth},
861 {"submatch", 1, 2, f_submatch},
862 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200863 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200864 {"synID", 3, 3, f_synID},
865 {"synIDattr", 2, 3, f_synIDattr},
866 {"synIDtrans", 1, 1, f_synIDtrans},
867 {"synconcealed", 2, 2, f_synconcealed},
868 {"synstack", 2, 2, f_synstack},
869 {"system", 1, 2, f_system},
870 {"systemlist", 1, 2, f_systemlist},
871 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
872 {"tabpagenr", 0, 1, f_tabpagenr},
873 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
874 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100875 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876#ifdef FEAT_FLOAT
877 {"tan", 1, 1, f_tan},
878 {"tanh", 1, 1, f_tanh},
879#endif
880 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200881#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100882 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
883 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100884 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200885 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200886# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
887 {"term_getansicolors", 1, 1, f_term_getansicolors},
888# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200889 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200890 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200891 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200892 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200893 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200894 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200895 {"term_getstatus", 1, 1, f_term_getstatus},
896 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200897 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200898 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200899 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200900 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200901# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
902 {"term_setansicolors", 2, 2, f_term_setansicolors},
903# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100904 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100905 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200906 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200907 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200908 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200909#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200910 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
911 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200912 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200913 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100914 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200915#ifdef FEAT_JOB_CHANNEL
916 {"test_null_channel", 0, 0, f_test_null_channel},
917#endif
918 {"test_null_dict", 0, 0, f_test_null_dict},
919#ifdef FEAT_JOB_CHANNEL
920 {"test_null_job", 0, 0, f_test_null_job},
921#endif
922 {"test_null_list", 0, 0, f_test_null_list},
923 {"test_null_partial", 0, 0, f_test_null_partial},
924 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100925 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926 {"test_settime", 1, 1, f_test_settime},
927#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200928 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200929 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930 {"timer_start", 2, 3, f_timer_start},
931 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200932 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200933#endif
934 {"tolower", 1, 1, f_tolower},
935 {"toupper", 1, 1, f_toupper},
936 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100937 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200938#ifdef FEAT_FLOAT
939 {"trunc", 1, 1, f_trunc},
940#endif
941 {"type", 1, 1, f_type},
942 {"undofile", 1, 1, f_undofile},
943 {"undotree", 0, 0, f_undotree},
944 {"uniq", 1, 3, f_uniq},
945 {"values", 1, 1, f_values},
946 {"virtcol", 1, 1, f_virtcol},
947 {"visualmode", 0, 1, f_visualmode},
948 {"wildmenumode", 0, 0, f_wildmenumode},
949 {"win_findbuf", 1, 1, f_win_findbuf},
950 {"win_getid", 0, 2, f_win_getid},
951 {"win_gotoid", 1, 1, f_win_gotoid},
952 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
953 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100954 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955 {"winbufnr", 1, 1, f_winbufnr},
956 {"wincol", 0, 0, f_wincol},
957 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200958 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200959 {"winline", 0, 0, f_winline},
960 {"winnr", 0, 1, f_winnr},
961 {"winrestcmd", 0, 0, f_winrestcmd},
962 {"winrestview", 1, 1, f_winrestview},
963 {"winsaveview", 0, 0, f_winsaveview},
964 {"winwidth", 1, 1, f_winwidth},
965 {"wordcount", 0, 0, f_wordcount},
966 {"writefile", 2, 3, f_writefile},
967 {"xor", 2, 2, f_xor},
968};
969
970#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
971
972/*
973 * Function given to ExpandGeneric() to obtain the list of internal
974 * or user defined function names.
975 */
976 char_u *
977get_function_name(expand_T *xp, int idx)
978{
979 static int intidx = -1;
980 char_u *name;
981
982 if (idx == 0)
983 intidx = -1;
984 if (intidx < 0)
985 {
986 name = get_user_func_name(xp, idx);
987 if (name != NULL)
988 return name;
989 }
990 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
991 {
992 STRCPY(IObuff, functions[intidx].f_name);
993 STRCAT(IObuff, "(");
994 if (functions[intidx].f_max_argc == 0)
995 STRCAT(IObuff, ")");
996 return IObuff;
997 }
998
999 return NULL;
1000}
1001
1002/*
1003 * Function given to ExpandGeneric() to obtain the list of internal or
1004 * user defined variable or function names.
1005 */
1006 char_u *
1007get_expr_name(expand_T *xp, int idx)
1008{
1009 static int intidx = -1;
1010 char_u *name;
1011
1012 if (idx == 0)
1013 intidx = -1;
1014 if (intidx < 0)
1015 {
1016 name = get_function_name(xp, idx);
1017 if (name != NULL)
1018 return name;
1019 }
1020 return get_user_var_name(xp, ++intidx);
1021}
1022
1023#endif /* FEAT_CMDL_COMPL */
1024
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001025/*
1026 * Find internal function in table above.
1027 * Return index, or -1 if not found
1028 */
1029 int
1030find_internal_func(
1031 char_u *name) /* name of the function */
1032{
1033 int first = 0;
1034 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1035 int cmp;
1036 int x;
1037
1038 /*
1039 * Find the function name in the table. Binary search.
1040 */
1041 while (first <= last)
1042 {
1043 x = first + ((unsigned)(last - first) >> 1);
1044 cmp = STRCMP(name, functions[x].f_name);
1045 if (cmp < 0)
1046 last = x - 1;
1047 else if (cmp > 0)
1048 first = x + 1;
1049 else
1050 return x;
1051 }
1052 return -1;
1053}
1054
1055 int
1056call_internal_func(
1057 char_u *name,
1058 int argcount,
1059 typval_T *argvars,
1060 typval_T *rettv)
1061{
1062 int i;
1063
1064 i = find_internal_func(name);
1065 if (i < 0)
1066 return ERROR_UNKNOWN;
1067 if (argcount < functions[i].f_min_argc)
1068 return ERROR_TOOFEW;
1069 if (argcount > functions[i].f_max_argc)
1070 return ERROR_TOOMANY;
1071 argvars[argcount].v_type = VAR_UNKNOWN;
1072 functions[i].f_func(argvars, rettv);
1073 return ERROR_NONE;
1074}
1075
1076/*
1077 * Return TRUE for a non-zero Number and a non-empty String.
1078 */
1079 static int
1080non_zero_arg(typval_T *argvars)
1081{
1082 return ((argvars[0].v_type == VAR_NUMBER
1083 && argvars[0].vval.v_number != 0)
1084 || (argvars[0].v_type == VAR_SPECIAL
1085 && argvars[0].vval.v_number == VVAL_TRUE)
1086 || (argvars[0].v_type == VAR_STRING
1087 && argvars[0].vval.v_string != NULL
1088 && *argvars[0].vval.v_string != NUL));
1089}
1090
1091/*
1092 * Get the lnum from the first argument.
1093 * Also accepts ".", "$", etc., but that only works for the current buffer.
1094 * Returns -1 on error.
1095 */
1096 static linenr_T
1097get_tv_lnum(typval_T *argvars)
1098{
1099 typval_T rettv;
1100 linenr_T lnum;
1101
1102 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1103 if (lnum == 0) /* no valid number, try using line() */
1104 {
1105 rettv.v_type = VAR_NUMBER;
1106 f_line(argvars, &rettv);
1107 lnum = (linenr_T)rettv.vval.v_number;
1108 clear_tv(&rettv);
1109 }
1110 return lnum;
1111}
1112
1113#ifdef FEAT_FLOAT
1114static int get_float_arg(typval_T *argvars, float_T *f);
1115
1116/*
1117 * Get the float value of "argvars[0]" into "f".
1118 * Returns FAIL when the argument is not a Number or Float.
1119 */
1120 static int
1121get_float_arg(typval_T *argvars, float_T *f)
1122{
1123 if (argvars[0].v_type == VAR_FLOAT)
1124 {
1125 *f = argvars[0].vval.v_float;
1126 return OK;
1127 }
1128 if (argvars[0].v_type == VAR_NUMBER)
1129 {
1130 *f = (float_T)argvars[0].vval.v_number;
1131 return OK;
1132 }
1133 EMSG(_("E808: Number or Float required"));
1134 return FAIL;
1135}
1136
1137/*
1138 * "abs(expr)" function
1139 */
1140 static void
1141f_abs(typval_T *argvars, typval_T *rettv)
1142{
1143 if (argvars[0].v_type == VAR_FLOAT)
1144 {
1145 rettv->v_type = VAR_FLOAT;
1146 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1147 }
1148 else
1149 {
1150 varnumber_T n;
1151 int error = FALSE;
1152
1153 n = get_tv_number_chk(&argvars[0], &error);
1154 if (error)
1155 rettv->vval.v_number = -1;
1156 else if (n > 0)
1157 rettv->vval.v_number = n;
1158 else
1159 rettv->vval.v_number = -n;
1160 }
1161}
1162
1163/*
1164 * "acos()" function
1165 */
1166 static void
1167f_acos(typval_T *argvars, typval_T *rettv)
1168{
1169 float_T f = 0.0;
1170
1171 rettv->v_type = VAR_FLOAT;
1172 if (get_float_arg(argvars, &f) == OK)
1173 rettv->vval.v_float = acos(f);
1174 else
1175 rettv->vval.v_float = 0.0;
1176}
1177#endif
1178
1179/*
1180 * "add(list, item)" function
1181 */
1182 static void
1183f_add(typval_T *argvars, typval_T *rettv)
1184{
1185 list_T *l;
1186
1187 rettv->vval.v_number = 1; /* Default: Failed */
1188 if (argvars[0].v_type == VAR_LIST)
1189 {
1190 if ((l = argvars[0].vval.v_list) != NULL
1191 && !tv_check_lock(l->lv_lock,
1192 (char_u *)N_("add() argument"), TRUE)
1193 && list_append_tv(l, &argvars[1]) == OK)
1194 copy_tv(&argvars[0], rettv);
1195 }
1196 else
1197 EMSG(_(e_listreq));
1198}
1199
1200/*
1201 * "and(expr, expr)" function
1202 */
1203 static void
1204f_and(typval_T *argvars, typval_T *rettv)
1205{
1206 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1207 & get_tv_number_chk(&argvars[1], NULL);
1208}
1209
1210/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001211 * Get the lnum from the first argument.
1212 * Also accepts "$", then "buf" is used.
1213 * Returns 0 on error.
1214 */
1215 static linenr_T
1216get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
1217{
1218 if (argvars[0].v_type == VAR_STRING
1219 && argvars[0].vval.v_string != NULL
1220 && argvars[0].vval.v_string[0] == '$'
1221 && buf != NULL)
1222 return buf->b_ml.ml_line_count;
1223 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1224}
1225
1226/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001227 * If there is a window for "curbuf", make it the current window.
1228 */
1229 static void
1230find_win_for_curbuf(void)
1231{
1232 wininfo_T *wip;
1233
1234 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1235 {
1236 if (wip->wi_win != NULL)
1237 {
1238 curwin = wip->wi_win;
1239 break;
1240 }
1241 }
1242}
1243
1244/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001245 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001246 */
1247 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001248set_buffer_lines(
1249 buf_T *buf,
1250 linenr_T lnum_arg,
1251 int append,
1252 typval_T *lines,
1253 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254{
Bram Moolenaarca851592018-06-06 21:04:07 +02001255 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1256 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001257 list_T *l = NULL;
1258 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001259 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001260 linenr_T append_lnum;
1261 buf_T *curbuf_save = NULL;
1262 win_T *curwin_save = NULL;
1263 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001264
Bram Moolenaarca851592018-06-06 21:04:07 +02001265 /* When using the current buffer ml_mfp will be set if needed. Useful when
1266 * setline() is used on startup. For other buffers the buffer must be
1267 * loaded. */
1268 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001269 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001270 rettv->vval.v_number = 1; /* FAIL */
1271 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001272 }
1273
Bram Moolenaarca851592018-06-06 21:04:07 +02001274 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001275 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001276 curbuf_save = curbuf;
1277 curwin_save = curwin;
1278 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001279 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001280 }
1281
1282 if (append)
1283 // appendbufline() uses the line number below which we insert
1284 append_lnum = lnum - 1;
1285 else
1286 // setbufline() uses the line number above which we insert, we only
1287 // append if it's below the last line
1288 append_lnum = curbuf->b_ml.ml_line_count;
1289
1290 if (lines->v_type == VAR_LIST)
1291 {
1292 l = lines->vval.v_list;
1293 li = l->lv_first;
1294 }
1295 else
1296 line = get_tv_string_chk(lines);
1297
1298 /* default result is zero == OK */
1299 for (;;)
1300 {
1301 if (l != NULL)
1302 {
1303 /* list argument, get next string */
1304 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001305 break;
Bram Moolenaarca851592018-06-06 21:04:07 +02001306 line = get_tv_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 li = li->li_next;
1308 }
1309
Bram Moolenaarca851592018-06-06 21:04:07 +02001310 rettv->vval.v_number = 1; /* FAIL */
1311 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1312 break;
1313
1314 /* When coming here from Insert mode, sync undo, so that this can be
1315 * undone separately from what was previously inserted. */
1316 if (u_sync_once == 2)
1317 {
1318 u_sync_once = 1; /* notify that u_sync() was called */
1319 u_sync(TRUE);
1320 }
1321
1322 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1323 {
1324 /* existing line, replace it */
1325 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1326 {
1327 changed_bytes(lnum, 0);
1328 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1329 check_cursor_col();
1330 rettv->vval.v_number = 0; /* OK */
1331 }
1332 }
1333 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1334 {
1335 /* append the line */
1336 ++added;
1337 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1338 rettv->vval.v_number = 0; /* OK */
1339 }
1340
1341 if (l == NULL) /* only one string argument */
1342 break;
1343 ++lnum;
1344 }
1345
1346 if (added > 0)
1347 {
1348 win_T *wp;
1349 tabpage_T *tp;
1350
1351 appended_lines_mark(append_lnum, added);
1352 FOR_ALL_TAB_WINDOWS(tp, wp)
1353 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1354 wp->w_cursor.lnum += added;
1355 check_cursor_col();
1356
Bram Moolenaarf2732452018-06-03 14:47:35 +02001357#ifdef FEAT_JOB_CHANNEL
1358 if (bt_prompt(curbuf) && (State & INSERT))
1359 // show the line with the prompt
1360 update_topline();
1361#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001363
1364 if (!is_curbuf)
1365 {
1366 curbuf = curbuf_save;
1367 curwin = curwin_save;
1368 }
1369}
1370
1371/*
1372 * "append(lnum, string/list)" function
1373 */
1374 static void
1375f_append(typval_T *argvars, typval_T *rettv)
1376{
1377 linenr_T lnum = get_tv_lnum(&argvars[0]);
1378
1379 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1380}
1381
1382/*
1383 * "appendbufline(buf, lnum, string/list)" function
1384 */
1385 static void
1386f_appendbufline(typval_T *argvars, typval_T *rettv)
1387{
1388 linenr_T lnum;
1389 buf_T *buf;
1390
1391 buf = get_buf_tv(&argvars[0], FALSE);
1392 if (buf == NULL)
1393 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001394 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001395 {
1396 lnum = get_tv_lnum_buf(&argvars[1], buf);
1397 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1398 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001399}
1400
1401/*
1402 * "argc()" function
1403 */
1404 static void
1405f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1406{
1407 rettv->vval.v_number = ARGCOUNT;
1408}
1409
1410/*
1411 * "argidx()" function
1412 */
1413 static void
1414f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1415{
1416 rettv->vval.v_number = curwin->w_arg_idx;
1417}
1418
1419/*
1420 * "arglistid()" function
1421 */
1422 static void
1423f_arglistid(typval_T *argvars, typval_T *rettv)
1424{
1425 win_T *wp;
1426
1427 rettv->vval.v_number = -1;
1428 wp = find_tabwin(&argvars[0], &argvars[1]);
1429 if (wp != NULL)
1430 rettv->vval.v_number = wp->w_alist->id;
1431}
1432
1433/*
1434 * "argv(nr)" function
1435 */
1436 static void
1437f_argv(typval_T *argvars, typval_T *rettv)
1438{
1439 int idx;
1440
1441 if (argvars[0].v_type != VAR_UNKNOWN)
1442 {
1443 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1444 if (idx >= 0 && idx < ARGCOUNT)
1445 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1446 else
1447 rettv->vval.v_string = NULL;
1448 rettv->v_type = VAR_STRING;
1449 }
1450 else if (rettv_list_alloc(rettv) == OK)
1451 for (idx = 0; idx < ARGCOUNT; ++idx)
1452 list_append_string(rettv->vval.v_list,
1453 alist_name(&ARGLIST[idx]), -1);
1454}
1455
1456/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001457 * "assert_beeps(cmd [, error])" function
1458 */
1459 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001460f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001461{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001462 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001463}
1464
1465/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001466 * "assert_equal(expected, actual[, msg])" function
1467 */
1468 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001469f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001470{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001471 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001472}
1473
1474/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001475 * "assert_equalfile(fname-one, fname-two)" function
1476 */
1477 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001478f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001479{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001480 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001481}
1482
1483/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001484 * "assert_notequal(expected, actual[, msg])" function
1485 */
1486 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001487f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001489 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001490}
1491
1492/*
1493 * "assert_exception(string[, msg])" function
1494 */
1495 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001496f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001498 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499}
1500
1501/*
1502 * "assert_fails(cmd [, error])" function
1503 */
1504 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001505f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001507 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508}
1509
1510/*
1511 * "assert_false(actual[, msg])" function
1512 */
1513 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001514f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001515{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001516 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001517}
1518
1519/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001520 * "assert_inrange(lower, upper[, msg])" function
1521 */
1522 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001523f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001524{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001525 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001526}
1527
1528/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529 * "assert_match(pattern, actual[, msg])" function
1530 */
1531 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001532f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001534 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535}
1536
1537/*
1538 * "assert_notmatch(pattern, actual[, msg])" function
1539 */
1540 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001541f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001543 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001544}
1545
1546/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001547 * "assert_report(msg)" function
1548 */
1549 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001550f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001551{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001552 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001553}
1554
1555/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 * "assert_true(actual[, msg])" function
1557 */
1558 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001559f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001560{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001561 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001562}
1563
1564#ifdef FEAT_FLOAT
1565/*
1566 * "asin()" function
1567 */
1568 static void
1569f_asin(typval_T *argvars, typval_T *rettv)
1570{
1571 float_T f = 0.0;
1572
1573 rettv->v_type = VAR_FLOAT;
1574 if (get_float_arg(argvars, &f) == OK)
1575 rettv->vval.v_float = asin(f);
1576 else
1577 rettv->vval.v_float = 0.0;
1578}
1579
1580/*
1581 * "atan()" function
1582 */
1583 static void
1584f_atan(typval_T *argvars, typval_T *rettv)
1585{
1586 float_T f = 0.0;
1587
1588 rettv->v_type = VAR_FLOAT;
1589 if (get_float_arg(argvars, &f) == OK)
1590 rettv->vval.v_float = atan(f);
1591 else
1592 rettv->vval.v_float = 0.0;
1593}
1594
1595/*
1596 * "atan2()" function
1597 */
1598 static void
1599f_atan2(typval_T *argvars, typval_T *rettv)
1600{
1601 float_T fx = 0.0, fy = 0.0;
1602
1603 rettv->v_type = VAR_FLOAT;
1604 if (get_float_arg(argvars, &fx) == OK
1605 && get_float_arg(&argvars[1], &fy) == OK)
1606 rettv->vval.v_float = atan2(fx, fy);
1607 else
1608 rettv->vval.v_float = 0.0;
1609}
1610#endif
1611
1612/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001613 * "balloon_show()" function
1614 */
1615#ifdef FEAT_BEVAL
1616 static void
1617f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1618{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001619 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001620 {
1621 if (argvars[0].v_type == VAR_LIST
1622# ifdef FEAT_GUI
1623 && !gui.in_use
1624# endif
1625 )
1626 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1627 else
1628 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1629 }
1630}
1631
Bram Moolenaar669a8282017-11-19 20:13:05 +01001632# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001633 static void
1634f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1635{
1636 if (rettv_list_alloc(rettv) == OK)
1637 {
1638 char_u *msg = get_tv_string_chk(&argvars[0]);
1639
1640 if (msg != NULL)
1641 {
1642 pumitem_T *array;
1643 int size = split_message(msg, &array);
1644 int i;
1645
1646 /* Skip the first and last item, they are always empty. */
1647 for (i = 1; i < size - 1; ++i)
1648 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001649 while (size > 0)
1650 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001651 vim_free(array);
1652 }
1653 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001654}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001655# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001656#endif
1657
1658/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001659 * "browse(save, title, initdir, default)" function
1660 */
1661 static void
1662f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1663{
1664#ifdef FEAT_BROWSE
1665 int save;
1666 char_u *title;
1667 char_u *initdir;
1668 char_u *defname;
1669 char_u buf[NUMBUFLEN];
1670 char_u buf2[NUMBUFLEN];
1671 int error = FALSE;
1672
1673 save = (int)get_tv_number_chk(&argvars[0], &error);
1674 title = get_tv_string_chk(&argvars[1]);
1675 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1676 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1677
1678 if (error || title == NULL || initdir == NULL || defname == NULL)
1679 rettv->vval.v_string = NULL;
1680 else
1681 rettv->vval.v_string =
1682 do_browse(save ? BROWSE_SAVE : 0,
1683 title, defname, NULL, initdir, NULL, curbuf);
1684#else
1685 rettv->vval.v_string = NULL;
1686#endif
1687 rettv->v_type = VAR_STRING;
1688}
1689
1690/*
1691 * "browsedir(title, initdir)" function
1692 */
1693 static void
1694f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1695{
1696#ifdef FEAT_BROWSE
1697 char_u *title;
1698 char_u *initdir;
1699 char_u buf[NUMBUFLEN];
1700
1701 title = get_tv_string_chk(&argvars[0]);
1702 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1703
1704 if (title == NULL || initdir == NULL)
1705 rettv->vval.v_string = NULL;
1706 else
1707 rettv->vval.v_string = do_browse(BROWSE_DIR,
1708 title, NULL, NULL, initdir, NULL, curbuf);
1709#else
1710 rettv->vval.v_string = NULL;
1711#endif
1712 rettv->v_type = VAR_STRING;
1713}
1714
1715static buf_T *find_buffer(typval_T *avar);
1716
1717/*
1718 * Find a buffer by number or exact name.
1719 */
1720 static buf_T *
1721find_buffer(typval_T *avar)
1722{
1723 buf_T *buf = NULL;
1724
1725 if (avar->v_type == VAR_NUMBER)
1726 buf = buflist_findnr((int)avar->vval.v_number);
1727 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1728 {
1729 buf = buflist_findname_exp(avar->vval.v_string);
1730 if (buf == NULL)
1731 {
1732 /* No full path name match, try a match with a URL or a "nofile"
1733 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001734 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001735 if (buf->b_fname != NULL
1736 && (path_with_url(buf->b_fname)
1737#ifdef FEAT_QUICKFIX
1738 || bt_nofile(buf)
1739#endif
1740 )
1741 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1742 break;
1743 }
1744 }
1745 return buf;
1746}
1747
1748/*
1749 * "bufexists(expr)" function
1750 */
1751 static void
1752f_bufexists(typval_T *argvars, typval_T *rettv)
1753{
1754 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1755}
1756
1757/*
1758 * "buflisted(expr)" function
1759 */
1760 static void
1761f_buflisted(typval_T *argvars, typval_T *rettv)
1762{
1763 buf_T *buf;
1764
1765 buf = find_buffer(&argvars[0]);
1766 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1767}
1768
1769/*
1770 * "bufloaded(expr)" function
1771 */
1772 static void
1773f_bufloaded(typval_T *argvars, typval_T *rettv)
1774{
1775 buf_T *buf;
1776
1777 buf = find_buffer(&argvars[0]);
1778 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1779}
1780
1781 buf_T *
1782buflist_find_by_name(char_u *name, int curtab_only)
1783{
1784 int save_magic;
1785 char_u *save_cpo;
1786 buf_T *buf;
1787
1788 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1789 save_magic = p_magic;
1790 p_magic = TRUE;
1791 save_cpo = p_cpo;
1792 p_cpo = (char_u *)"";
1793
1794 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1795 TRUE, FALSE, curtab_only));
1796
1797 p_magic = save_magic;
1798 p_cpo = save_cpo;
1799 return buf;
1800}
1801
1802/*
1803 * Get buffer by number or pattern.
1804 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001805 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001806get_buf_tv(typval_T *tv, int curtab_only)
1807{
1808 char_u *name = tv->vval.v_string;
1809 buf_T *buf;
1810
1811 if (tv->v_type == VAR_NUMBER)
1812 return buflist_findnr((int)tv->vval.v_number);
1813 if (tv->v_type != VAR_STRING)
1814 return NULL;
1815 if (name == NULL || *name == NUL)
1816 return curbuf;
1817 if (name[0] == '$' && name[1] == NUL)
1818 return lastbuf;
1819
1820 buf = buflist_find_by_name(name, curtab_only);
1821
1822 /* If not found, try expanding the name, like done for bufexists(). */
1823 if (buf == NULL)
1824 buf = find_buffer(tv);
1825
1826 return buf;
1827}
1828
1829/*
1830 * "bufname(expr)" function
1831 */
1832 static void
1833f_bufname(typval_T *argvars, typval_T *rettv)
1834{
1835 buf_T *buf;
1836
1837 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1838 ++emsg_off;
1839 buf = get_buf_tv(&argvars[0], FALSE);
1840 rettv->v_type = VAR_STRING;
1841 if (buf != NULL && buf->b_fname != NULL)
1842 rettv->vval.v_string = vim_strsave(buf->b_fname);
1843 else
1844 rettv->vval.v_string = NULL;
1845 --emsg_off;
1846}
1847
1848/*
1849 * "bufnr(expr)" function
1850 */
1851 static void
1852f_bufnr(typval_T *argvars, typval_T *rettv)
1853{
1854 buf_T *buf;
1855 int error = FALSE;
1856 char_u *name;
1857
1858 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1859 ++emsg_off;
1860 buf = get_buf_tv(&argvars[0], FALSE);
1861 --emsg_off;
1862
1863 /* If the buffer isn't found and the second argument is not zero create a
1864 * new buffer. */
1865 if (buf == NULL
1866 && argvars[1].v_type != VAR_UNKNOWN
1867 && get_tv_number_chk(&argvars[1], &error) != 0
1868 && !error
1869 && (name = get_tv_string_chk(&argvars[0])) != NULL
1870 && !error)
1871 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1872
1873 if (buf != NULL)
1874 rettv->vval.v_number = buf->b_fnum;
1875 else
1876 rettv->vval.v_number = -1;
1877}
1878
1879 static void
1880buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1881{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001882 win_T *wp;
1883 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001884 buf_T *buf;
1885
1886 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1887 ++emsg_off;
1888 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001889 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001890 {
1891 ++winnr;
1892 if (wp->w_buffer == buf)
1893 break;
1894 }
1895 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001896 --emsg_off;
1897}
1898
1899/*
1900 * "bufwinid(nr)" function
1901 */
1902 static void
1903f_bufwinid(typval_T *argvars, typval_T *rettv)
1904{
1905 buf_win_common(argvars, rettv, FALSE);
1906}
1907
1908/*
1909 * "bufwinnr(nr)" function
1910 */
1911 static void
1912f_bufwinnr(typval_T *argvars, typval_T *rettv)
1913{
1914 buf_win_common(argvars, rettv, TRUE);
1915}
1916
1917/*
1918 * "byte2line(byte)" function
1919 */
1920 static void
1921f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1922{
1923#ifndef FEAT_BYTEOFF
1924 rettv->vval.v_number = -1;
1925#else
1926 long boff = 0;
1927
1928 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1929 if (boff < 0)
1930 rettv->vval.v_number = -1;
1931 else
1932 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1933 (linenr_T)0, &boff);
1934#endif
1935}
1936
1937 static void
1938byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1939{
1940#ifdef FEAT_MBYTE
1941 char_u *t;
1942#endif
1943 char_u *str;
1944 varnumber_T idx;
1945
1946 str = get_tv_string_chk(&argvars[0]);
1947 idx = get_tv_number_chk(&argvars[1], NULL);
1948 rettv->vval.v_number = -1;
1949 if (str == NULL || idx < 0)
1950 return;
1951
1952#ifdef FEAT_MBYTE
1953 t = str;
1954 for ( ; idx > 0; idx--)
1955 {
1956 if (*t == NUL) /* EOL reached */
1957 return;
1958 if (enc_utf8 && comp)
1959 t += utf_ptr2len(t);
1960 else
1961 t += (*mb_ptr2len)(t);
1962 }
1963 rettv->vval.v_number = (varnumber_T)(t - str);
1964#else
1965 if ((size_t)idx <= STRLEN(str))
1966 rettv->vval.v_number = idx;
1967#endif
1968}
1969
1970/*
1971 * "byteidx()" function
1972 */
1973 static void
1974f_byteidx(typval_T *argvars, typval_T *rettv)
1975{
1976 byteidx(argvars, rettv, FALSE);
1977}
1978
1979/*
1980 * "byteidxcomp()" function
1981 */
1982 static void
1983f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1984{
1985 byteidx(argvars, rettv, TRUE);
1986}
1987
1988/*
1989 * "call(func, arglist [, dict])" function
1990 */
1991 static void
1992f_call(typval_T *argvars, typval_T *rettv)
1993{
1994 char_u *func;
1995 partial_T *partial = NULL;
1996 dict_T *selfdict = NULL;
1997
1998 if (argvars[1].v_type != VAR_LIST)
1999 {
2000 EMSG(_(e_listreq));
2001 return;
2002 }
2003 if (argvars[1].vval.v_list == NULL)
2004 return;
2005
2006 if (argvars[0].v_type == VAR_FUNC)
2007 func = argvars[0].vval.v_string;
2008 else if (argvars[0].v_type == VAR_PARTIAL)
2009 {
2010 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002011 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 }
2013 else
2014 func = get_tv_string(&argvars[0]);
2015 if (*func == NUL)
2016 return; /* type error or empty name */
2017
2018 if (argvars[2].v_type != VAR_UNKNOWN)
2019 {
2020 if (argvars[2].v_type != VAR_DICT)
2021 {
2022 EMSG(_(e_dictreq));
2023 return;
2024 }
2025 selfdict = argvars[2].vval.v_dict;
2026 }
2027
2028 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2029}
2030
2031#ifdef FEAT_FLOAT
2032/*
2033 * "ceil({float})" function
2034 */
2035 static void
2036f_ceil(typval_T *argvars, typval_T *rettv)
2037{
2038 float_T f = 0.0;
2039
2040 rettv->v_type = VAR_FLOAT;
2041 if (get_float_arg(argvars, &f) == OK)
2042 rettv->vval.v_float = ceil(f);
2043 else
2044 rettv->vval.v_float = 0.0;
2045}
2046#endif
2047
2048#ifdef FEAT_JOB_CHANNEL
2049/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002050 * "ch_canread()" function
2051 */
2052 static void
2053f_ch_canread(typval_T *argvars, typval_T *rettv)
2054{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002055 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002056
2057 rettv->vval.v_number = 0;
2058 if (channel != NULL)
2059 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2060 || channel_has_readahead(channel, PART_OUT)
2061 || channel_has_readahead(channel, PART_ERR);
2062}
2063
2064/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002065 * "ch_close()" function
2066 */
2067 static void
2068f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2069{
2070 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2071
2072 if (channel != NULL)
2073 {
2074 channel_close(channel, FALSE);
2075 channel_clear(channel);
2076 }
2077}
2078
2079/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002080 * "ch_close()" function
2081 */
2082 static void
2083f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2084{
2085 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2086
2087 if (channel != NULL)
2088 channel_close_in(channel);
2089}
2090
2091/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002092 * "ch_getbufnr()" function
2093 */
2094 static void
2095f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2096{
2097 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2098
2099 rettv->vval.v_number = -1;
2100 if (channel != NULL)
2101 {
2102 char_u *what = get_tv_string(&argvars[1]);
2103 int part;
2104
2105 if (STRCMP(what, "err") == 0)
2106 part = PART_ERR;
2107 else if (STRCMP(what, "out") == 0)
2108 part = PART_OUT;
2109 else if (STRCMP(what, "in") == 0)
2110 part = PART_IN;
2111 else
2112 part = PART_SOCK;
2113 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2114 rettv->vval.v_number =
2115 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2116 }
2117}
2118
2119/*
2120 * "ch_getjob()" function
2121 */
2122 static void
2123f_ch_getjob(typval_T *argvars, typval_T *rettv)
2124{
2125 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2126
2127 if (channel != NULL)
2128 {
2129 rettv->v_type = VAR_JOB;
2130 rettv->vval.v_job = channel->ch_job;
2131 if (channel->ch_job != NULL)
2132 ++channel->ch_job->jv_refcount;
2133 }
2134}
2135
2136/*
2137 * "ch_info()" function
2138 */
2139 static void
2140f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2141{
2142 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2143
2144 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2145 channel_info(channel, rettv->vval.v_dict);
2146}
2147
2148/*
2149 * "ch_log()" function
2150 */
2151 static void
2152f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2153{
2154 char_u *msg = get_tv_string(&argvars[0]);
2155 channel_T *channel = NULL;
2156
2157 if (argvars[1].v_type != VAR_UNKNOWN)
2158 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2159
Bram Moolenaard5359b22018-04-05 22:44:39 +02002160 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161}
2162
2163/*
2164 * "ch_logfile()" function
2165 */
2166 static void
2167f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2168{
2169 char_u *fname;
2170 char_u *opt = (char_u *)"";
2171 char_u buf[NUMBUFLEN];
2172
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002173 /* Don't open a file in restricted mode. */
2174 if (check_restricted() || check_secure())
2175 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 fname = get_tv_string(&argvars[0]);
2177 if (argvars[1].v_type == VAR_STRING)
2178 opt = get_tv_string_buf(&argvars[1], buf);
2179 ch_logfile(fname, opt);
2180}
2181
2182/*
2183 * "ch_open()" function
2184 */
2185 static void
2186f_ch_open(typval_T *argvars, typval_T *rettv)
2187{
2188 rettv->v_type = VAR_CHANNEL;
2189 if (check_restricted() || check_secure())
2190 return;
2191 rettv->vval.v_channel = channel_open_func(argvars);
2192}
2193
2194/*
2195 * "ch_read()" function
2196 */
2197 static void
2198f_ch_read(typval_T *argvars, typval_T *rettv)
2199{
2200 common_channel_read(argvars, rettv, FALSE);
2201}
2202
2203/*
2204 * "ch_readraw()" function
2205 */
2206 static void
2207f_ch_readraw(typval_T *argvars, typval_T *rettv)
2208{
2209 common_channel_read(argvars, rettv, TRUE);
2210}
2211
2212/*
2213 * "ch_evalexpr()" function
2214 */
2215 static void
2216f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2217{
2218 ch_expr_common(argvars, rettv, TRUE);
2219}
2220
2221/*
2222 * "ch_sendexpr()" function
2223 */
2224 static void
2225f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2226{
2227 ch_expr_common(argvars, rettv, FALSE);
2228}
2229
2230/*
2231 * "ch_evalraw()" function
2232 */
2233 static void
2234f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2235{
2236 ch_raw_common(argvars, rettv, TRUE);
2237}
2238
2239/*
2240 * "ch_sendraw()" function
2241 */
2242 static void
2243f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2244{
2245 ch_raw_common(argvars, rettv, FALSE);
2246}
2247
2248/*
2249 * "ch_setoptions()" function
2250 */
2251 static void
2252f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2253{
2254 channel_T *channel;
2255 jobopt_T opt;
2256
2257 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2258 if (channel == NULL)
2259 return;
2260 clear_job_options(&opt);
2261 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002262 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263 channel_set_options(channel, &opt);
2264 free_job_options(&opt);
2265}
2266
2267/*
2268 * "ch_status()" function
2269 */
2270 static void
2271f_ch_status(typval_T *argvars, typval_T *rettv)
2272{
2273 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002274 jobopt_T opt;
2275 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002276
2277 /* return an empty string by default */
2278 rettv->v_type = VAR_STRING;
2279 rettv->vval.v_string = NULL;
2280
2281 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002282
2283 if (argvars[1].v_type != VAR_UNKNOWN)
2284 {
2285 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002286 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002287 && (opt.jo_set & JO_PART))
2288 part = opt.jo_part;
2289 }
2290
2291 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292}
2293#endif
2294
2295/*
2296 * "changenr()" function
2297 */
2298 static void
2299f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2300{
2301 rettv->vval.v_number = curbuf->b_u_seq_cur;
2302}
2303
2304/*
2305 * "char2nr(string)" function
2306 */
2307 static void
2308f_char2nr(typval_T *argvars, typval_T *rettv)
2309{
2310#ifdef FEAT_MBYTE
2311 if (has_mbyte)
2312 {
2313 int utf8 = 0;
2314
2315 if (argvars[1].v_type != VAR_UNKNOWN)
2316 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2317
2318 if (utf8)
2319 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2320 else
2321 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2322 }
2323 else
2324#endif
2325 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2326}
2327
2328/*
2329 * "cindent(lnum)" function
2330 */
2331 static void
2332f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2333{
2334#ifdef FEAT_CINDENT
2335 pos_T pos;
2336 linenr_T lnum;
2337
2338 pos = curwin->w_cursor;
2339 lnum = get_tv_lnum(argvars);
2340 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2341 {
2342 curwin->w_cursor.lnum = lnum;
2343 rettv->vval.v_number = get_c_indent();
2344 curwin->w_cursor = pos;
2345 }
2346 else
2347#endif
2348 rettv->vval.v_number = -1;
2349}
2350
2351/*
2352 * "clearmatches()" function
2353 */
2354 static void
2355f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2356{
2357#ifdef FEAT_SEARCH_EXTRA
2358 clear_matches(curwin);
2359#endif
2360}
2361
2362/*
2363 * "col(string)" function
2364 */
2365 static void
2366f_col(typval_T *argvars, typval_T *rettv)
2367{
2368 colnr_T col = 0;
2369 pos_T *fp;
2370 int fnum = curbuf->b_fnum;
2371
2372 fp = var2fpos(&argvars[0], FALSE, &fnum);
2373 if (fp != NULL && fnum == curbuf->b_fnum)
2374 {
2375 if (fp->col == MAXCOL)
2376 {
2377 /* '> can be MAXCOL, get the length of the line then */
2378 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2379 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2380 else
2381 col = MAXCOL;
2382 }
2383 else
2384 {
2385 col = fp->col + 1;
2386#ifdef FEAT_VIRTUALEDIT
2387 /* col(".") when the cursor is on the NUL at the end of the line
2388 * because of "coladd" can be seen as an extra column. */
2389 if (virtual_active() && fp == &curwin->w_cursor)
2390 {
2391 char_u *p = ml_get_cursor();
2392
2393 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2394 curwin->w_virtcol - curwin->w_cursor.coladd))
2395 {
2396# ifdef FEAT_MBYTE
2397 int l;
2398
2399 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2400 col += l;
2401# else
2402 if (*p != NUL && p[1] == NUL)
2403 ++col;
2404# endif
2405 }
2406 }
2407#endif
2408 }
2409 }
2410 rettv->vval.v_number = col;
2411}
2412
2413#if defined(FEAT_INS_EXPAND)
2414/*
2415 * "complete()" function
2416 */
2417 static void
2418f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2419{
2420 int startcol;
2421
2422 if ((State & INSERT) == 0)
2423 {
2424 EMSG(_("E785: complete() can only be used in Insert mode"));
2425 return;
2426 }
2427
2428 /* Check for undo allowed here, because if something was already inserted
2429 * the line was already saved for undo and this check isn't done. */
2430 if (!undo_allowed())
2431 return;
2432
2433 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2434 {
2435 EMSG(_(e_invarg));
2436 return;
2437 }
2438
2439 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2440 if (startcol <= 0)
2441 return;
2442
2443 set_completion(startcol - 1, argvars[1].vval.v_list);
2444}
2445
2446/*
2447 * "complete_add()" function
2448 */
2449 static void
2450f_complete_add(typval_T *argvars, typval_T *rettv)
2451{
2452 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2453}
2454
2455/*
2456 * "complete_check()" function
2457 */
2458 static void
2459f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2460{
2461 int saved = RedrawingDisabled;
2462
2463 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002464 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 rettv->vval.v_number = compl_interrupted;
2466 RedrawingDisabled = saved;
2467}
2468#endif
2469
2470/*
2471 * "confirm(message, buttons[, default [, type]])" function
2472 */
2473 static void
2474f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2475{
2476#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2477 char_u *message;
2478 char_u *buttons = NULL;
2479 char_u buf[NUMBUFLEN];
2480 char_u buf2[NUMBUFLEN];
2481 int def = 1;
2482 int type = VIM_GENERIC;
2483 char_u *typestr;
2484 int error = FALSE;
2485
2486 message = get_tv_string_chk(&argvars[0]);
2487 if (message == NULL)
2488 error = TRUE;
2489 if (argvars[1].v_type != VAR_UNKNOWN)
2490 {
2491 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2492 if (buttons == NULL)
2493 error = TRUE;
2494 if (argvars[2].v_type != VAR_UNKNOWN)
2495 {
2496 def = (int)get_tv_number_chk(&argvars[2], &error);
2497 if (argvars[3].v_type != VAR_UNKNOWN)
2498 {
2499 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2500 if (typestr == NULL)
2501 error = TRUE;
2502 else
2503 {
2504 switch (TOUPPER_ASC(*typestr))
2505 {
2506 case 'E': type = VIM_ERROR; break;
2507 case 'Q': type = VIM_QUESTION; break;
2508 case 'I': type = VIM_INFO; break;
2509 case 'W': type = VIM_WARNING; break;
2510 case 'G': type = VIM_GENERIC; break;
2511 }
2512 }
2513 }
2514 }
2515 }
2516
2517 if (buttons == NULL || *buttons == NUL)
2518 buttons = (char_u *)_("&Ok");
2519
2520 if (!error)
2521 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2522 def, NULL, FALSE);
2523#endif
2524}
2525
2526/*
2527 * "copy()" function
2528 */
2529 static void
2530f_copy(typval_T *argvars, typval_T *rettv)
2531{
2532 item_copy(&argvars[0], rettv, FALSE, 0);
2533}
2534
2535#ifdef FEAT_FLOAT
2536/*
2537 * "cos()" function
2538 */
2539 static void
2540f_cos(typval_T *argvars, typval_T *rettv)
2541{
2542 float_T f = 0.0;
2543
2544 rettv->v_type = VAR_FLOAT;
2545 if (get_float_arg(argvars, &f) == OK)
2546 rettv->vval.v_float = cos(f);
2547 else
2548 rettv->vval.v_float = 0.0;
2549}
2550
2551/*
2552 * "cosh()" function
2553 */
2554 static void
2555f_cosh(typval_T *argvars, typval_T *rettv)
2556{
2557 float_T f = 0.0;
2558
2559 rettv->v_type = VAR_FLOAT;
2560 if (get_float_arg(argvars, &f) == OK)
2561 rettv->vval.v_float = cosh(f);
2562 else
2563 rettv->vval.v_float = 0.0;
2564}
2565#endif
2566
2567/*
2568 * "count()" function
2569 */
2570 static void
2571f_count(typval_T *argvars, typval_T *rettv)
2572{
2573 long n = 0;
2574 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002575 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002576
Bram Moolenaar9966b212017-07-28 16:46:57 +02002577 if (argvars[2].v_type != VAR_UNKNOWN)
2578 ic = (int)get_tv_number_chk(&argvars[2], &error);
2579
2580 if (argvars[0].v_type == VAR_STRING)
2581 {
2582 char_u *expr = get_tv_string_chk(&argvars[1]);
2583 char_u *p = argvars[0].vval.v_string;
2584 char_u *next;
2585
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002586 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002587 {
2588 if (ic)
2589 {
2590 size_t len = STRLEN(expr);
2591
2592 while (*p != NUL)
2593 {
2594 if (MB_STRNICMP(p, expr, len) == 0)
2595 {
2596 ++n;
2597 p += len;
2598 }
2599 else
2600 MB_PTR_ADV(p);
2601 }
2602 }
2603 else
2604 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2605 != NULL)
2606 {
2607 ++n;
2608 p = next + STRLEN(expr);
2609 }
2610 }
2611
2612 }
2613 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614 {
2615 listitem_T *li;
2616 list_T *l;
2617 long idx;
2618
2619 if ((l = argvars[0].vval.v_list) != NULL)
2620 {
2621 li = l->lv_first;
2622 if (argvars[2].v_type != VAR_UNKNOWN)
2623 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002624 if (argvars[3].v_type != VAR_UNKNOWN)
2625 {
2626 idx = (long)get_tv_number_chk(&argvars[3], &error);
2627 if (!error)
2628 {
2629 li = list_find(l, idx);
2630 if (li == NULL)
2631 EMSGN(_(e_listidx), idx);
2632 }
2633 }
2634 if (error)
2635 li = NULL;
2636 }
2637
2638 for ( ; li != NULL; li = li->li_next)
2639 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2640 ++n;
2641 }
2642 }
2643 else if (argvars[0].v_type == VAR_DICT)
2644 {
2645 int todo;
2646 dict_T *d;
2647 hashitem_T *hi;
2648
2649 if ((d = argvars[0].vval.v_dict) != NULL)
2650 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 if (argvars[2].v_type != VAR_UNKNOWN)
2652 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 if (argvars[3].v_type != VAR_UNKNOWN)
2654 EMSG(_(e_invarg));
2655 }
2656
2657 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2658 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2659 {
2660 if (!HASHITEM_EMPTY(hi))
2661 {
2662 --todo;
2663 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2664 ++n;
2665 }
2666 }
2667 }
2668 }
2669 else
2670 EMSG2(_(e_listdictarg), "count()");
2671 rettv->vval.v_number = n;
2672}
2673
2674/*
2675 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2676 *
2677 * Checks the existence of a cscope connection.
2678 */
2679 static void
2680f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2681{
2682#ifdef FEAT_CSCOPE
2683 int num = 0;
2684 char_u *dbpath = NULL;
2685 char_u *prepend = NULL;
2686 char_u buf[NUMBUFLEN];
2687
2688 if (argvars[0].v_type != VAR_UNKNOWN
2689 && argvars[1].v_type != VAR_UNKNOWN)
2690 {
2691 num = (int)get_tv_number(&argvars[0]);
2692 dbpath = get_tv_string(&argvars[1]);
2693 if (argvars[2].v_type != VAR_UNKNOWN)
2694 prepend = get_tv_string_buf(&argvars[2], buf);
2695 }
2696
2697 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2698#endif
2699}
2700
2701/*
2702 * "cursor(lnum, col)" function, or
2703 * "cursor(list)"
2704 *
2705 * Moves the cursor to the specified line and column.
2706 * Returns 0 when the position could be set, -1 otherwise.
2707 */
2708 static void
2709f_cursor(typval_T *argvars, typval_T *rettv)
2710{
2711 long line, col;
2712#ifdef FEAT_VIRTUALEDIT
2713 long coladd = 0;
2714#endif
2715 int set_curswant = TRUE;
2716
2717 rettv->vval.v_number = -1;
2718 if (argvars[1].v_type == VAR_UNKNOWN)
2719 {
2720 pos_T pos;
2721 colnr_T curswant = -1;
2722
2723 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2724 {
2725 EMSG(_(e_invarg));
2726 return;
2727 }
2728 line = pos.lnum;
2729 col = pos.col;
2730#ifdef FEAT_VIRTUALEDIT
2731 coladd = pos.coladd;
2732#endif
2733 if (curswant >= 0)
2734 {
2735 curwin->w_curswant = curswant - 1;
2736 set_curswant = FALSE;
2737 }
2738 }
2739 else
2740 {
2741 line = get_tv_lnum(argvars);
2742 col = (long)get_tv_number_chk(&argvars[1], NULL);
2743#ifdef FEAT_VIRTUALEDIT
2744 if (argvars[2].v_type != VAR_UNKNOWN)
2745 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2746#endif
2747 }
2748 if (line < 0 || col < 0
2749#ifdef FEAT_VIRTUALEDIT
2750 || coladd < 0
2751#endif
2752 )
2753 return; /* type error; errmsg already given */
2754 if (line > 0)
2755 curwin->w_cursor.lnum = line;
2756 if (col > 0)
2757 curwin->w_cursor.col = col - 1;
2758#ifdef FEAT_VIRTUALEDIT
2759 curwin->w_cursor.coladd = coladd;
2760#endif
2761
2762 /* Make sure the cursor is in a valid position. */
2763 check_cursor();
2764#ifdef FEAT_MBYTE
2765 /* Correct cursor for multi-byte character. */
2766 if (has_mbyte)
2767 mb_adjust_cursor();
2768#endif
2769
2770 curwin->w_set_curswant = set_curswant;
2771 rettv->vval.v_number = 0;
2772}
2773
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002774#ifdef WIN3264
2775/*
2776 * "debugbreak()" function
2777 */
2778 static void
2779f_debugbreak(typval_T *argvars, typval_T *rettv)
2780{
2781 int pid;
2782
2783 rettv->vval.v_number = FAIL;
2784 pid = (int)get_tv_number(&argvars[0]);
2785 if (pid == 0)
2786 EMSG(_(e_invarg));
2787 else
2788 {
2789 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2790
2791 if (hProcess != NULL)
2792 {
2793 DebugBreakProcess(hProcess);
2794 CloseHandle(hProcess);
2795 rettv->vval.v_number = OK;
2796 }
2797 }
2798}
2799#endif
2800
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002801/*
2802 * "deepcopy()" function
2803 */
2804 static void
2805f_deepcopy(typval_T *argvars, typval_T *rettv)
2806{
2807 int noref = 0;
2808 int copyID;
2809
2810 if (argvars[1].v_type != VAR_UNKNOWN)
2811 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2812 if (noref < 0 || noref > 1)
2813 EMSG(_(e_invarg));
2814 else
2815 {
2816 copyID = get_copyID();
2817 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2818 }
2819}
2820
2821/*
2822 * "delete()" function
2823 */
2824 static void
2825f_delete(typval_T *argvars, typval_T *rettv)
2826{
2827 char_u nbuf[NUMBUFLEN];
2828 char_u *name;
2829 char_u *flags;
2830
2831 rettv->vval.v_number = -1;
2832 if (check_restricted() || check_secure())
2833 return;
2834
2835 name = get_tv_string(&argvars[0]);
2836 if (name == NULL || *name == NUL)
2837 {
2838 EMSG(_(e_invarg));
2839 return;
2840 }
2841
2842 if (argvars[1].v_type != VAR_UNKNOWN)
2843 flags = get_tv_string_buf(&argvars[1], nbuf);
2844 else
2845 flags = (char_u *)"";
2846
2847 if (*flags == NUL)
2848 /* delete a file */
2849 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2850 else if (STRCMP(flags, "d") == 0)
2851 /* delete an empty directory */
2852 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2853 else if (STRCMP(flags, "rf") == 0)
2854 /* delete a directory recursively */
2855 rettv->vval.v_number = delete_recursive(name);
2856 else
2857 EMSG2(_(e_invexpr2), flags);
2858}
2859
2860/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002861 * "deletebufline()" function
2862 */
2863 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002864f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002865{
2866 buf_T *buf;
2867 linenr_T first, last;
2868 linenr_T lnum;
2869 long count;
2870 int is_curbuf;
2871 buf_T *curbuf_save = NULL;
2872 win_T *curwin_save = NULL;
2873 tabpage_T *tp;
2874 win_T *wp;
2875
2876 buf = get_buf_tv(&argvars[0], FALSE);
2877 if (buf == NULL)
2878 {
2879 rettv->vval.v_number = 1; /* FAIL */
2880 return;
2881 }
2882 is_curbuf = buf == curbuf;
2883
2884 first = get_tv_lnum_buf(&argvars[1], buf);
2885 if (argvars[2].v_type != VAR_UNKNOWN)
2886 last = get_tv_lnum_buf(&argvars[2], buf);
2887 else
2888 last = first;
2889
2890 if (buf->b_ml.ml_mfp == NULL || first < 1
2891 || first > buf->b_ml.ml_line_count || last < first)
2892 {
2893 rettv->vval.v_number = 1; /* FAIL */
2894 return;
2895 }
2896
2897 if (!is_curbuf)
2898 {
2899 curbuf_save = curbuf;
2900 curwin_save = curwin;
2901 curbuf = buf;
2902 find_win_for_curbuf();
2903 }
2904 if (last > curbuf->b_ml.ml_line_count)
2905 last = curbuf->b_ml.ml_line_count;
2906 count = last - first + 1;
2907
2908 // When coming here from Insert mode, sync undo, so that this can be
2909 // undone separately from what was previously inserted.
2910 if (u_sync_once == 2)
2911 {
2912 u_sync_once = 1; // notify that u_sync() was called
2913 u_sync(TRUE);
2914 }
2915
2916 if (u_save(first - 1, last + 1) == FAIL)
2917 {
2918 rettv->vval.v_number = 1; /* FAIL */
2919 return;
2920 }
2921
2922 for (lnum = first; lnum <= last; ++lnum)
2923 ml_delete(first, TRUE);
2924
2925 FOR_ALL_TAB_WINDOWS(tp, wp)
2926 if (wp->w_buffer == buf)
2927 {
2928 if (wp->w_cursor.lnum > last)
2929 wp->w_cursor.lnum -= count;
2930 else if (wp->w_cursor.lnum> first)
2931 wp->w_cursor.lnum = first;
2932 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2933 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2934 }
2935 check_cursor_col();
2936 deleted_lines_mark(first, count);
2937
2938 if (!is_curbuf)
2939 {
2940 curbuf = curbuf_save;
2941 curwin = curwin_save;
2942 }
2943}
2944
2945/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002946 * "did_filetype()" function
2947 */
2948 static void
2949f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2950{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002951 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002952}
2953
2954/*
2955 * "diff_filler()" function
2956 */
2957 static void
2958f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2959{
2960#ifdef FEAT_DIFF
2961 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2962#endif
2963}
2964
2965/*
2966 * "diff_hlID()" function
2967 */
2968 static void
2969f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2970{
2971#ifdef FEAT_DIFF
2972 linenr_T lnum = get_tv_lnum(argvars);
2973 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002974 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975 static int fnum = 0;
2976 static int change_start = 0;
2977 static int change_end = 0;
2978 static hlf_T hlID = (hlf_T)0;
2979 int filler_lines;
2980 int col;
2981
2982 if (lnum < 0) /* ignore type error in {lnum} arg */
2983 lnum = 0;
2984 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002985 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002986 || fnum != curbuf->b_fnum)
2987 {
2988 /* New line, buffer, change: need to get the values. */
2989 filler_lines = diff_check(curwin, lnum);
2990 if (filler_lines < 0)
2991 {
2992 if (filler_lines == -1)
2993 {
2994 change_start = MAXCOL;
2995 change_end = -1;
2996 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2997 hlID = HLF_ADD; /* added line */
2998 else
2999 hlID = HLF_CHD; /* changed line */
3000 }
3001 else
3002 hlID = HLF_ADD; /* added line */
3003 }
3004 else
3005 hlID = (hlf_T)0;
3006 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003007 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003008 fnum = curbuf->b_fnum;
3009 }
3010
3011 if (hlID == HLF_CHD || hlID == HLF_TXD)
3012 {
3013 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
3014 if (col >= change_start && col <= change_end)
3015 hlID = HLF_TXD; /* changed text */
3016 else
3017 hlID = HLF_CHD; /* changed line */
3018 }
3019 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3020#endif
3021}
3022
3023/*
3024 * "empty({expr})" function
3025 */
3026 static void
3027f_empty(typval_T *argvars, typval_T *rettv)
3028{
3029 int n = FALSE;
3030
3031 switch (argvars[0].v_type)
3032 {
3033 case VAR_STRING:
3034 case VAR_FUNC:
3035 n = argvars[0].vval.v_string == NULL
3036 || *argvars[0].vval.v_string == NUL;
3037 break;
3038 case VAR_PARTIAL:
3039 n = FALSE;
3040 break;
3041 case VAR_NUMBER:
3042 n = argvars[0].vval.v_number == 0;
3043 break;
3044 case VAR_FLOAT:
3045#ifdef FEAT_FLOAT
3046 n = argvars[0].vval.v_float == 0.0;
3047 break;
3048#endif
3049 case VAR_LIST:
3050 n = argvars[0].vval.v_list == NULL
3051 || argvars[0].vval.v_list->lv_first == NULL;
3052 break;
3053 case VAR_DICT:
3054 n = argvars[0].vval.v_dict == NULL
3055 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3056 break;
3057 case VAR_SPECIAL:
3058 n = argvars[0].vval.v_number != VVAL_TRUE;
3059 break;
3060
3061 case VAR_JOB:
3062#ifdef FEAT_JOB_CHANNEL
3063 n = argvars[0].vval.v_job == NULL
3064 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3065 break;
3066#endif
3067 case VAR_CHANNEL:
3068#ifdef FEAT_JOB_CHANNEL
3069 n = argvars[0].vval.v_channel == NULL
3070 || !channel_is_open(argvars[0].vval.v_channel);
3071 break;
3072#endif
3073 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003074 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 n = TRUE;
3076 break;
3077 }
3078
3079 rettv->vval.v_number = n;
3080}
3081
3082/*
3083 * "escape({string}, {chars})" function
3084 */
3085 static void
3086f_escape(typval_T *argvars, typval_T *rettv)
3087{
3088 char_u buf[NUMBUFLEN];
3089
3090 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
3091 get_tv_string_buf(&argvars[1], buf));
3092 rettv->v_type = VAR_STRING;
3093}
3094
3095/*
3096 * "eval()" function
3097 */
3098 static void
3099f_eval(typval_T *argvars, typval_T *rettv)
3100{
3101 char_u *s, *p;
3102
3103 s = get_tv_string_chk(&argvars[0]);
3104 if (s != NULL)
3105 s = skipwhite(s);
3106
3107 p = s;
3108 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3109 {
3110 if (p != NULL && !aborting())
3111 EMSG2(_(e_invexpr2), p);
3112 need_clr_eos = FALSE;
3113 rettv->v_type = VAR_NUMBER;
3114 rettv->vval.v_number = 0;
3115 }
3116 else if (*s != NUL)
3117 EMSG(_(e_trailing));
3118}
3119
3120/*
3121 * "eventhandler()" function
3122 */
3123 static void
3124f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3125{
3126 rettv->vval.v_number = vgetc_busy;
3127}
3128
3129/*
3130 * "executable()" function
3131 */
3132 static void
3133f_executable(typval_T *argvars, typval_T *rettv)
3134{
3135 char_u *name = get_tv_string(&argvars[0]);
3136
3137 /* Check in $PATH and also check directly if there is a directory name. */
3138 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3139 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3140}
3141
3142static garray_T redir_execute_ga;
3143
3144/*
3145 * Append "value[value_len]" to the execute() output.
3146 */
3147 void
3148execute_redir_str(char_u *value, int value_len)
3149{
3150 int len;
3151
3152 if (value_len == -1)
3153 len = (int)STRLEN(value); /* Append the entire string */
3154 else
3155 len = value_len; /* Append only "value_len" characters */
3156 if (ga_grow(&redir_execute_ga, len) == OK)
3157 {
3158 mch_memmove((char *)redir_execute_ga.ga_data
3159 + redir_execute_ga.ga_len, value, len);
3160 redir_execute_ga.ga_len += len;
3161 }
3162}
3163
3164/*
3165 * Get next line from a list.
3166 * Called by do_cmdline() to get the next line.
3167 * Returns allocated string, or NULL for end of function.
3168 */
3169
3170 static char_u *
3171get_list_line(
3172 int c UNUSED,
3173 void *cookie,
3174 int indent UNUSED)
3175{
3176 listitem_T **p = (listitem_T **)cookie;
3177 listitem_T *item = *p;
3178 char_u buf[NUMBUFLEN];
3179 char_u *s;
3180
3181 if (item == NULL)
3182 return NULL;
3183 s = get_tv_string_buf_chk(&item->li_tv, buf);
3184 *p = item->li_next;
3185 return s == NULL ? NULL : vim_strsave(s);
3186}
3187
3188/*
3189 * "execute()" function
3190 */
3191 static void
3192f_execute(typval_T *argvars, typval_T *rettv)
3193{
3194 char_u *cmd = NULL;
3195 list_T *list = NULL;
3196 int save_msg_silent = msg_silent;
3197 int save_emsg_silent = emsg_silent;
3198 int save_emsg_noredir = emsg_noredir;
3199 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003200 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003201 garray_T save_ga;
3202
3203 rettv->vval.v_string = NULL;
3204 rettv->v_type = VAR_STRING;
3205
3206 if (argvars[0].v_type == VAR_LIST)
3207 {
3208 list = argvars[0].vval.v_list;
3209 if (list == NULL || list->lv_first == NULL)
3210 /* empty list, no commands, empty output */
3211 return;
3212 ++list->lv_refcount;
3213 }
3214 else
3215 {
3216 cmd = get_tv_string_chk(&argvars[0]);
3217 if (cmd == NULL)
3218 return;
3219 }
3220
3221 if (argvars[1].v_type != VAR_UNKNOWN)
3222 {
3223 char_u buf[NUMBUFLEN];
3224 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
3225
3226 if (s == NULL)
3227 return;
3228 if (STRNCMP(s, "silent", 6) == 0)
3229 ++msg_silent;
3230 if (STRCMP(s, "silent!") == 0)
3231 {
3232 emsg_silent = TRUE;
3233 emsg_noredir = TRUE;
3234 }
3235 }
3236 else
3237 ++msg_silent;
3238
3239 if (redir_execute)
3240 save_ga = redir_execute_ga;
3241 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3242 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003243 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003244
3245 if (cmd != NULL)
3246 do_cmdline_cmd(cmd);
3247 else
3248 {
3249 listitem_T *item = list->lv_first;
3250
3251 do_cmdline(NULL, get_list_line, (void *)&item,
3252 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3253 --list->lv_refcount;
3254 }
3255
Bram Moolenaard297f352017-01-29 20:31:21 +01003256 /* Need to append a NUL to the result. */
3257 if (ga_grow(&redir_execute_ga, 1) == OK)
3258 {
3259 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3260 rettv->vval.v_string = redir_execute_ga.ga_data;
3261 }
3262 else
3263 {
3264 ga_clear(&redir_execute_ga);
3265 rettv->vval.v_string = NULL;
3266 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267 msg_silent = save_msg_silent;
3268 emsg_silent = save_emsg_silent;
3269 emsg_noredir = save_emsg_noredir;
3270
3271 redir_execute = save_redir_execute;
3272 if (redir_execute)
3273 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003274 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003275
3276 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3277 * line. Put it back in the first column. */
3278 msg_col = 0;
3279}
3280
3281/*
3282 * "exepath()" function
3283 */
3284 static void
3285f_exepath(typval_T *argvars, typval_T *rettv)
3286{
3287 char_u *p = NULL;
3288
3289 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3290 rettv->v_type = VAR_STRING;
3291 rettv->vval.v_string = p;
3292}
3293
3294/*
3295 * "exists()" function
3296 */
3297 static void
3298f_exists(typval_T *argvars, typval_T *rettv)
3299{
3300 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003302
3303 p = get_tv_string(&argvars[0]);
3304 if (*p == '$') /* environment variable */
3305 {
3306 /* first try "normal" environment variables (fast) */
3307 if (mch_getenv(p + 1) != NULL)
3308 n = TRUE;
3309 else
3310 {
3311 /* try expanding things like $VIM and ${HOME} */
3312 p = expand_env_save(p);
3313 if (p != NULL && *p != '$')
3314 n = TRUE;
3315 vim_free(p);
3316 }
3317 }
3318 else if (*p == '&' || *p == '+') /* option */
3319 {
3320 n = (get_option_tv(&p, NULL, TRUE) == OK);
3321 if (*skipwhite(p) != NUL)
3322 n = FALSE; /* trailing garbage */
3323 }
3324 else if (*p == '*') /* internal or user defined function */
3325 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003326 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003327 }
3328 else if (*p == ':')
3329 {
3330 n = cmd_exists(p + 1);
3331 }
3332 else if (*p == '#')
3333 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003334 if (p[1] == '#')
3335 n = autocmd_supported(p + 2);
3336 else
3337 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003338 }
3339 else /* internal variable */
3340 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003341 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342 }
3343
3344 rettv->vval.v_number = n;
3345}
3346
3347#ifdef FEAT_FLOAT
3348/*
3349 * "exp()" function
3350 */
3351 static void
3352f_exp(typval_T *argvars, typval_T *rettv)
3353{
3354 float_T f = 0.0;
3355
3356 rettv->v_type = VAR_FLOAT;
3357 if (get_float_arg(argvars, &f) == OK)
3358 rettv->vval.v_float = exp(f);
3359 else
3360 rettv->vval.v_float = 0.0;
3361}
3362#endif
3363
3364/*
3365 * "expand()" function
3366 */
3367 static void
3368f_expand(typval_T *argvars, typval_T *rettv)
3369{
3370 char_u *s;
3371 int len;
3372 char_u *errormsg;
3373 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3374 expand_T xpc;
3375 int error = FALSE;
3376 char_u *result;
3377
3378 rettv->v_type = VAR_STRING;
3379 if (argvars[1].v_type != VAR_UNKNOWN
3380 && argvars[2].v_type != VAR_UNKNOWN
3381 && get_tv_number_chk(&argvars[2], &error)
3382 && !error)
3383 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003384 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003385 }
3386
3387 s = get_tv_string(&argvars[0]);
3388 if (*s == '%' || *s == '#' || *s == '<')
3389 {
3390 ++emsg_off;
3391 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3392 --emsg_off;
3393 if (rettv->v_type == VAR_LIST)
3394 {
3395 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3396 list_append_string(rettv->vval.v_list, result, -1);
3397 else
3398 vim_free(result);
3399 }
3400 else
3401 rettv->vval.v_string = result;
3402 }
3403 else
3404 {
3405 /* When the optional second argument is non-zero, don't remove matches
3406 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3407 if (argvars[1].v_type != VAR_UNKNOWN
3408 && get_tv_number_chk(&argvars[1], &error))
3409 options |= WILD_KEEP_ALL;
3410 if (!error)
3411 {
3412 ExpandInit(&xpc);
3413 xpc.xp_context = EXPAND_FILES;
3414 if (p_wic)
3415 options += WILD_ICASE;
3416 if (rettv->v_type == VAR_STRING)
3417 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3418 options, WILD_ALL);
3419 else if (rettv_list_alloc(rettv) != FAIL)
3420 {
3421 int i;
3422
3423 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3424 for (i = 0; i < xpc.xp_numfiles; i++)
3425 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3426 ExpandCleanup(&xpc);
3427 }
3428 }
3429 else
3430 rettv->vval.v_string = NULL;
3431 }
3432}
3433
3434/*
3435 * "extend(list, list [, idx])" function
3436 * "extend(dict, dict [, action])" function
3437 */
3438 static void
3439f_extend(typval_T *argvars, typval_T *rettv)
3440{
3441 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3442
3443 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3444 {
3445 list_T *l1, *l2;
3446 listitem_T *item;
3447 long before;
3448 int error = FALSE;
3449
3450 l1 = argvars[0].vval.v_list;
3451 l2 = argvars[1].vval.v_list;
3452 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3453 && l2 != NULL)
3454 {
3455 if (argvars[2].v_type != VAR_UNKNOWN)
3456 {
3457 before = (long)get_tv_number_chk(&argvars[2], &error);
3458 if (error)
3459 return; /* type error; errmsg already given */
3460
3461 if (before == l1->lv_len)
3462 item = NULL;
3463 else
3464 {
3465 item = list_find(l1, before);
3466 if (item == NULL)
3467 {
3468 EMSGN(_(e_listidx), before);
3469 return;
3470 }
3471 }
3472 }
3473 else
3474 item = NULL;
3475 list_extend(l1, l2, item);
3476
3477 copy_tv(&argvars[0], rettv);
3478 }
3479 }
3480 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3481 {
3482 dict_T *d1, *d2;
3483 char_u *action;
3484 int i;
3485
3486 d1 = argvars[0].vval.v_dict;
3487 d2 = argvars[1].vval.v_dict;
3488 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3489 && d2 != NULL)
3490 {
3491 /* Check the third argument. */
3492 if (argvars[2].v_type != VAR_UNKNOWN)
3493 {
3494 static char *(av[]) = {"keep", "force", "error"};
3495
3496 action = get_tv_string_chk(&argvars[2]);
3497 if (action == NULL)
3498 return; /* type error; errmsg already given */
3499 for (i = 0; i < 3; ++i)
3500 if (STRCMP(action, av[i]) == 0)
3501 break;
3502 if (i == 3)
3503 {
3504 EMSG2(_(e_invarg2), action);
3505 return;
3506 }
3507 }
3508 else
3509 action = (char_u *)"force";
3510
3511 dict_extend(d1, d2, action);
3512
3513 copy_tv(&argvars[0], rettv);
3514 }
3515 }
3516 else
3517 EMSG2(_(e_listdictarg), "extend()");
3518}
3519
3520/*
3521 * "feedkeys()" function
3522 */
3523 static void
3524f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3525{
3526 int remap = TRUE;
3527 int insert = FALSE;
3528 char_u *keys, *flags;
3529 char_u nbuf[NUMBUFLEN];
3530 int typed = FALSE;
3531 int execute = FALSE;
3532 int dangerous = FALSE;
3533 char_u *keys_esc;
3534
3535 /* This is not allowed in the sandbox. If the commands would still be
3536 * executed in the sandbox it would be OK, but it probably happens later,
3537 * when "sandbox" is no longer set. */
3538 if (check_secure())
3539 return;
3540
3541 keys = get_tv_string(&argvars[0]);
3542
3543 if (argvars[1].v_type != VAR_UNKNOWN)
3544 {
3545 flags = get_tv_string_buf(&argvars[1], nbuf);
3546 for ( ; *flags != NUL; ++flags)
3547 {
3548 switch (*flags)
3549 {
3550 case 'n': remap = FALSE; break;
3551 case 'm': remap = TRUE; break;
3552 case 't': typed = TRUE; break;
3553 case 'i': insert = TRUE; break;
3554 case 'x': execute = TRUE; break;
3555 case '!': dangerous = TRUE; break;
3556 }
3557 }
3558 }
3559
3560 if (*keys != NUL || execute)
3561 {
3562 /* Need to escape K_SPECIAL and CSI before putting the string in the
3563 * typeahead buffer. */
3564 keys_esc = vim_strsave_escape_csi(keys);
3565 if (keys_esc != NULL)
3566 {
3567 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3568 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3569 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003570 if (vgetc_busy
3571#ifdef FEAT_TIMERS
3572 || timer_busy
3573#endif
3574 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003575 typebuf_was_filled = TRUE;
3576 if (execute)
3577 {
3578 int save_msg_scroll = msg_scroll;
3579
3580 /* Avoid a 1 second delay when the keys start Insert mode. */
3581 msg_scroll = FALSE;
3582
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003583 if (!dangerous)
3584 ++ex_normal_busy;
Bram Moolenaar655a82a2018-05-08 22:01:07 +02003585 exec_normal(TRUE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003586 if (!dangerous)
3587 --ex_normal_busy;
3588
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589 msg_scroll |= save_msg_scroll;
3590 }
3591 }
3592 }
3593}
3594
3595/*
3596 * "filereadable()" function
3597 */
3598 static void
3599f_filereadable(typval_T *argvars, typval_T *rettv)
3600{
3601 int fd;
3602 char_u *p;
3603 int n;
3604
3605#ifndef O_NONBLOCK
3606# define O_NONBLOCK 0
3607#endif
3608 p = get_tv_string(&argvars[0]);
3609 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3610 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3611 {
3612 n = TRUE;
3613 close(fd);
3614 }
3615 else
3616 n = FALSE;
3617
3618 rettv->vval.v_number = n;
3619}
3620
3621/*
3622 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3623 * rights to write into.
3624 */
3625 static void
3626f_filewritable(typval_T *argvars, typval_T *rettv)
3627{
3628 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3629}
3630
3631 static void
3632findfilendir(
3633 typval_T *argvars UNUSED,
3634 typval_T *rettv,
3635 int find_what UNUSED)
3636{
3637#ifdef FEAT_SEARCHPATH
3638 char_u *fname;
3639 char_u *fresult = NULL;
3640 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3641 char_u *p;
3642 char_u pathbuf[NUMBUFLEN];
3643 int count = 1;
3644 int first = TRUE;
3645 int error = FALSE;
3646#endif
3647
3648 rettv->vval.v_string = NULL;
3649 rettv->v_type = VAR_STRING;
3650
3651#ifdef FEAT_SEARCHPATH
3652 fname = get_tv_string(&argvars[0]);
3653
3654 if (argvars[1].v_type != VAR_UNKNOWN)
3655 {
3656 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3657 if (p == NULL)
3658 error = TRUE;
3659 else
3660 {
3661 if (*p != NUL)
3662 path = p;
3663
3664 if (argvars[2].v_type != VAR_UNKNOWN)
3665 count = (int)get_tv_number_chk(&argvars[2], &error);
3666 }
3667 }
3668
3669 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3670 error = TRUE;
3671
3672 if (*fname != NUL && !error)
3673 {
3674 do
3675 {
3676 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3677 vim_free(fresult);
3678 fresult = find_file_in_path_option(first ? fname : NULL,
3679 first ? (int)STRLEN(fname) : 0,
3680 0, first, path,
3681 find_what,
3682 curbuf->b_ffname,
3683 find_what == FINDFILE_DIR
3684 ? (char_u *)"" : curbuf->b_p_sua);
3685 first = FALSE;
3686
3687 if (fresult != NULL && rettv->v_type == VAR_LIST)
3688 list_append_string(rettv->vval.v_list, fresult, -1);
3689
3690 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3691 }
3692
3693 if (rettv->v_type == VAR_STRING)
3694 rettv->vval.v_string = fresult;
3695#endif
3696}
3697
3698/*
3699 * "filter()" function
3700 */
3701 static void
3702f_filter(typval_T *argvars, typval_T *rettv)
3703{
3704 filter_map(argvars, rettv, FALSE);
3705}
3706
3707/*
3708 * "finddir({fname}[, {path}[, {count}]])" function
3709 */
3710 static void
3711f_finddir(typval_T *argvars, typval_T *rettv)
3712{
3713 findfilendir(argvars, rettv, FINDFILE_DIR);
3714}
3715
3716/*
3717 * "findfile({fname}[, {path}[, {count}]])" function
3718 */
3719 static void
3720f_findfile(typval_T *argvars, typval_T *rettv)
3721{
3722 findfilendir(argvars, rettv, FINDFILE_FILE);
3723}
3724
3725#ifdef FEAT_FLOAT
3726/*
3727 * "float2nr({float})" function
3728 */
3729 static void
3730f_float2nr(typval_T *argvars, typval_T *rettv)
3731{
3732 float_T f = 0.0;
3733
3734 if (get_float_arg(argvars, &f) == OK)
3735 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003736 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003737 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003738 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003739 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740 else
3741 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742 }
3743}
3744
3745/*
3746 * "floor({float})" function
3747 */
3748 static void
3749f_floor(typval_T *argvars, typval_T *rettv)
3750{
3751 float_T f = 0.0;
3752
3753 rettv->v_type = VAR_FLOAT;
3754 if (get_float_arg(argvars, &f) == OK)
3755 rettv->vval.v_float = floor(f);
3756 else
3757 rettv->vval.v_float = 0.0;
3758}
3759
3760/*
3761 * "fmod()" function
3762 */
3763 static void
3764f_fmod(typval_T *argvars, typval_T *rettv)
3765{
3766 float_T fx = 0.0, fy = 0.0;
3767
3768 rettv->v_type = VAR_FLOAT;
3769 if (get_float_arg(argvars, &fx) == OK
3770 && get_float_arg(&argvars[1], &fy) == OK)
3771 rettv->vval.v_float = fmod(fx, fy);
3772 else
3773 rettv->vval.v_float = 0.0;
3774}
3775#endif
3776
3777/*
3778 * "fnameescape({string})" function
3779 */
3780 static void
3781f_fnameescape(typval_T *argvars, typval_T *rettv)
3782{
3783 rettv->vval.v_string = vim_strsave_fnameescape(
3784 get_tv_string(&argvars[0]), FALSE);
3785 rettv->v_type = VAR_STRING;
3786}
3787
3788/*
3789 * "fnamemodify({fname}, {mods})" function
3790 */
3791 static void
3792f_fnamemodify(typval_T *argvars, typval_T *rettv)
3793{
3794 char_u *fname;
3795 char_u *mods;
3796 int usedlen = 0;
3797 int len;
3798 char_u *fbuf = NULL;
3799 char_u buf[NUMBUFLEN];
3800
3801 fname = get_tv_string_chk(&argvars[0]);
3802 mods = get_tv_string_buf_chk(&argvars[1], buf);
3803 if (fname == NULL || mods == NULL)
3804 fname = NULL;
3805 else
3806 {
3807 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003808 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003809 }
3810
3811 rettv->v_type = VAR_STRING;
3812 if (fname == NULL)
3813 rettv->vval.v_string = NULL;
3814 else
3815 rettv->vval.v_string = vim_strnsave(fname, len);
3816 vim_free(fbuf);
3817}
3818
3819static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3820
3821/*
3822 * "foldclosed()" function
3823 */
3824 static void
3825foldclosed_both(
3826 typval_T *argvars UNUSED,
3827 typval_T *rettv,
3828 int end UNUSED)
3829{
3830#ifdef FEAT_FOLDING
3831 linenr_T lnum;
3832 linenr_T first, last;
3833
3834 lnum = get_tv_lnum(argvars);
3835 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3836 {
3837 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3838 {
3839 if (end)
3840 rettv->vval.v_number = (varnumber_T)last;
3841 else
3842 rettv->vval.v_number = (varnumber_T)first;
3843 return;
3844 }
3845 }
3846#endif
3847 rettv->vval.v_number = -1;
3848}
3849
3850/*
3851 * "foldclosed()" function
3852 */
3853 static void
3854f_foldclosed(typval_T *argvars, typval_T *rettv)
3855{
3856 foldclosed_both(argvars, rettv, FALSE);
3857}
3858
3859/*
3860 * "foldclosedend()" function
3861 */
3862 static void
3863f_foldclosedend(typval_T *argvars, typval_T *rettv)
3864{
3865 foldclosed_both(argvars, rettv, TRUE);
3866}
3867
3868/*
3869 * "foldlevel()" function
3870 */
3871 static void
3872f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3873{
3874#ifdef FEAT_FOLDING
3875 linenr_T lnum;
3876
3877 lnum = get_tv_lnum(argvars);
3878 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3879 rettv->vval.v_number = foldLevel(lnum);
3880#endif
3881}
3882
3883/*
3884 * "foldtext()" function
3885 */
3886 static void
3887f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3888{
3889#ifdef FEAT_FOLDING
3890 linenr_T foldstart;
3891 linenr_T foldend;
3892 char_u *dashes;
3893 linenr_T lnum;
3894 char_u *s;
3895 char_u *r;
3896 int len;
3897 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003898 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003899#endif
3900
3901 rettv->v_type = VAR_STRING;
3902 rettv->vval.v_string = NULL;
3903#ifdef FEAT_FOLDING
3904 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3905 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3906 dashes = get_vim_var_str(VV_FOLDDASHES);
3907 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3908 && dashes != NULL)
3909 {
3910 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003911 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912 if (!linewhite(lnum))
3913 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003914
3915 /* Find interesting text in this line. */
3916 s = skipwhite(ml_get(lnum));
3917 /* skip C comment-start */
3918 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3919 {
3920 s = skipwhite(s + 2);
3921 if (*skipwhite(s) == NUL
3922 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3923 {
3924 s = skipwhite(ml_get(lnum + 1));
3925 if (*s == '*')
3926 s = skipwhite(s + 1);
3927 }
3928 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003929 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003930 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931 r = alloc((unsigned)(STRLEN(txt)
3932 + STRLEN(dashes) /* for %s */
3933 + 20 /* for %3ld */
3934 + STRLEN(s))); /* concatenated */
3935 if (r != NULL)
3936 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003937 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003938 len = (int)STRLEN(r);
3939 STRCAT(r, s);
3940 /* remove 'foldmarker' and 'commentstring' */
3941 foldtext_cleanup(r + len);
3942 rettv->vval.v_string = r;
3943 }
3944 }
3945#endif
3946}
3947
3948/*
3949 * "foldtextresult(lnum)" function
3950 */
3951 static void
3952f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3953{
3954#ifdef FEAT_FOLDING
3955 linenr_T lnum;
3956 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003957 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003958 foldinfo_T foldinfo;
3959 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003960 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003961#endif
3962
3963 rettv->v_type = VAR_STRING;
3964 rettv->vval.v_string = NULL;
3965#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003966 if (entered)
3967 return; /* reject recursive use */
3968 entered = TRUE;
3969
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003970 lnum = get_tv_lnum(argvars);
3971 /* treat illegal types and illegal string values for {lnum} the same */
3972 if (lnum < 0)
3973 lnum = 0;
3974 fold_count = foldedCount(curwin, lnum, &foldinfo);
3975 if (fold_count > 0)
3976 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003977 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3978 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003979 if (text == buf)
3980 text = vim_strsave(text);
3981 rettv->vval.v_string = text;
3982 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003983
3984 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003985#endif
3986}
3987
3988/*
3989 * "foreground()" function
3990 */
3991 static void
3992f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3993{
3994#ifdef FEAT_GUI
3995 if (gui.in_use)
3996 gui_mch_set_foreground();
3997#else
3998# ifdef WIN32
3999 win32_set_foreground();
4000# endif
4001#endif
4002}
4003
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004004 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004005common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004006{
4007 char_u *s;
4008 char_u *name;
4009 int use_string = FALSE;
4010 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004011 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012
4013 if (argvars[0].v_type == VAR_FUNC)
4014 {
4015 /* function(MyFunc, [arg], dict) */
4016 s = argvars[0].vval.v_string;
4017 }
4018 else if (argvars[0].v_type == VAR_PARTIAL
4019 && argvars[0].vval.v_partial != NULL)
4020 {
4021 /* function(dict.MyFunc, [arg]) */
4022 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004023 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004024 }
4025 else
4026 {
4027 /* function('MyFunc', [arg], dict) */
4028 s = get_tv_string(&argvars[0]);
4029 use_string = TRUE;
4030 }
4031
Bram Moolenaar843b8842016-08-21 14:36:15 +02004032 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004033 {
4034 name = s;
4035 trans_name = trans_function_name(&name, FALSE,
4036 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4037 if (*name != NUL)
4038 s = NULL;
4039 }
4040
Bram Moolenaar843b8842016-08-21 14:36:15 +02004041 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4042 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02004043 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004045 else if (trans_name != NULL && (is_funcref
4046 ? find_func(trans_name) == NULL
4047 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004048 EMSG2(_("E700: Unknown function: %s"), s);
4049 else
4050 {
4051 int dict_idx = 0;
4052 int arg_idx = 0;
4053 list_T *list = NULL;
4054
4055 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4056 {
4057 char sid_buf[25];
4058 int off = *s == 's' ? 2 : 5;
4059
4060 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4061 * also be called from another script. Using trans_function_name()
4062 * would also work, but some plugins depend on the name being
4063 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004064 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004065 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4066 if (name != NULL)
4067 {
4068 STRCPY(name, sid_buf);
4069 STRCAT(name, s + off);
4070 }
4071 }
4072 else
4073 name = vim_strsave(s);
4074
4075 if (argvars[1].v_type != VAR_UNKNOWN)
4076 {
4077 if (argvars[2].v_type != VAR_UNKNOWN)
4078 {
4079 /* function(name, [args], dict) */
4080 arg_idx = 1;
4081 dict_idx = 2;
4082 }
4083 else if (argvars[1].v_type == VAR_DICT)
4084 /* function(name, dict) */
4085 dict_idx = 1;
4086 else
4087 /* function(name, [args]) */
4088 arg_idx = 1;
4089 if (dict_idx > 0)
4090 {
4091 if (argvars[dict_idx].v_type != VAR_DICT)
4092 {
4093 EMSG(_("E922: expected a dict"));
4094 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004095 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004096 }
4097 if (argvars[dict_idx].vval.v_dict == NULL)
4098 dict_idx = 0;
4099 }
4100 if (arg_idx > 0)
4101 {
4102 if (argvars[arg_idx].v_type != VAR_LIST)
4103 {
4104 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4105 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004106 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107 }
4108 list = argvars[arg_idx].vval.v_list;
4109 if (list == NULL || list->lv_len == 0)
4110 arg_idx = 0;
4111 }
4112 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004113 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004114 {
4115 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4116
4117 /* result is a VAR_PARTIAL */
4118 if (pt == NULL)
4119 vim_free(name);
4120 else
4121 {
4122 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4123 {
4124 listitem_T *li;
4125 int i = 0;
4126 int arg_len = 0;
4127 int lv_len = 0;
4128
4129 if (arg_pt != NULL)
4130 arg_len = arg_pt->pt_argc;
4131 if (list != NULL)
4132 lv_len = list->lv_len;
4133 pt->pt_argc = arg_len + lv_len;
4134 pt->pt_argv = (typval_T *)alloc(
4135 sizeof(typval_T) * pt->pt_argc);
4136 if (pt->pt_argv == NULL)
4137 {
4138 vim_free(pt);
4139 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004140 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004142 for (i = 0; i < arg_len; i++)
4143 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4144 if (lv_len > 0)
4145 for (li = list->lv_first; li != NULL;
4146 li = li->li_next)
4147 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 }
4149
4150 /* For "function(dict.func, [], dict)" and "func" is a partial
4151 * use "dict". That is backwards compatible. */
4152 if (dict_idx > 0)
4153 {
4154 /* The dict is bound explicitly, pt_auto is FALSE. */
4155 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4156 ++pt->pt_dict->dv_refcount;
4157 }
4158 else if (arg_pt != NULL)
4159 {
4160 /* If the dict was bound automatically the result is also
4161 * bound automatically. */
4162 pt->pt_dict = arg_pt->pt_dict;
4163 pt->pt_auto = arg_pt->pt_auto;
4164 if (pt->pt_dict != NULL)
4165 ++pt->pt_dict->dv_refcount;
4166 }
4167
4168 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004169 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4170 {
4171 pt->pt_func = arg_pt->pt_func;
4172 func_ptr_ref(pt->pt_func);
4173 vim_free(name);
4174 }
4175 else if (is_funcref)
4176 {
4177 pt->pt_func = find_func(trans_name);
4178 func_ptr_ref(pt->pt_func);
4179 vim_free(name);
4180 }
4181 else
4182 {
4183 pt->pt_name = name;
4184 func_ref(name);
4185 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004186 }
4187 rettv->v_type = VAR_PARTIAL;
4188 rettv->vval.v_partial = pt;
4189 }
4190 else
4191 {
4192 /* result is a VAR_FUNC */
4193 rettv->v_type = VAR_FUNC;
4194 rettv->vval.v_string = name;
4195 func_ref(name);
4196 }
4197 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004198theend:
4199 vim_free(trans_name);
4200}
4201
4202/*
4203 * "funcref()" function
4204 */
4205 static void
4206f_funcref(typval_T *argvars, typval_T *rettv)
4207{
4208 common_function(argvars, rettv, TRUE);
4209}
4210
4211/*
4212 * "function()" function
4213 */
4214 static void
4215f_function(typval_T *argvars, typval_T *rettv)
4216{
4217 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004218}
4219
4220/*
4221 * "garbagecollect()" function
4222 */
4223 static void
4224f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4225{
4226 /* This is postponed until we are back at the toplevel, because we may be
4227 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4228 want_garbage_collect = TRUE;
4229
4230 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
4231 garbage_collect_at_exit = TRUE;
4232}
4233
4234/*
4235 * "get()" function
4236 */
4237 static void
4238f_get(typval_T *argvars, typval_T *rettv)
4239{
4240 listitem_T *li;
4241 list_T *l;
4242 dictitem_T *di;
4243 dict_T *d;
4244 typval_T *tv = NULL;
4245
4246 if (argvars[0].v_type == VAR_LIST)
4247 {
4248 if ((l = argvars[0].vval.v_list) != NULL)
4249 {
4250 int error = FALSE;
4251
4252 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
4253 if (!error && li != NULL)
4254 tv = &li->li_tv;
4255 }
4256 }
4257 else if (argvars[0].v_type == VAR_DICT)
4258 {
4259 if ((d = argvars[0].vval.v_dict) != NULL)
4260 {
4261 di = dict_find(d, get_tv_string(&argvars[1]), -1);
4262 if (di != NULL)
4263 tv = &di->di_tv;
4264 }
4265 }
4266 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4267 {
4268 partial_T *pt;
4269 partial_T fref_pt;
4270
4271 if (argvars[0].v_type == VAR_PARTIAL)
4272 pt = argvars[0].vval.v_partial;
4273 else
4274 {
4275 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4276 fref_pt.pt_name = argvars[0].vval.v_string;
4277 pt = &fref_pt;
4278 }
4279
4280 if (pt != NULL)
4281 {
4282 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004283 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004284
4285 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4286 {
4287 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004288 n = partial_name(pt);
4289 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004290 rettv->vval.v_string = NULL;
4291 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004292 {
4293 rettv->vval.v_string = vim_strsave(n);
4294 if (rettv->v_type == VAR_FUNC)
4295 func_ref(rettv->vval.v_string);
4296 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004297 }
4298 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004299 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004300 else if (STRCMP(what, "args") == 0)
4301 {
4302 rettv->v_type = VAR_LIST;
4303 if (rettv_list_alloc(rettv) == OK)
4304 {
4305 int i;
4306
4307 for (i = 0; i < pt->pt_argc; ++i)
4308 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4309 }
4310 }
4311 else
4312 EMSG2(_(e_invarg2), what);
4313 return;
4314 }
4315 }
4316 else
4317 EMSG2(_(e_listdictarg), "get()");
4318
4319 if (tv == NULL)
4320 {
4321 if (argvars[2].v_type != VAR_UNKNOWN)
4322 copy_tv(&argvars[2], rettv);
4323 }
4324 else
4325 copy_tv(tv, rettv);
4326}
4327
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004328#ifdef FEAT_SIGNS
4329/*
4330 * Returns information about signs placed in a buffer as list of dicts.
4331 */
4332 static void
4333get_buffer_signs(buf_T *buf, list_T *l)
4334{
4335 signlist_T *sign;
4336
4337 for (sign = buf->b_signlist; sign; sign = sign->next)
4338 {
4339 dict_T *d = dict_alloc();
4340
4341 if (d != NULL)
4342 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02004343 dict_add_number(d, "id", sign->id);
4344 dict_add_number(d, "lnum", sign->lnum);
4345 dict_add_string(d, "name", sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004346
4347 list_append_dict(l, d);
4348 }
4349 }
4350}
4351#endif
4352
4353/*
4354 * Returns buffer options, variables and other attributes in a dictionary.
4355 */
4356 static dict_T *
4357get_buffer_info(buf_T *buf)
4358{
4359 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004360 tabpage_T *tp;
4361 win_T *wp;
4362 list_T *windows;
4363
4364 dict = dict_alloc();
4365 if (dict == NULL)
4366 return NULL;
4367
Bram Moolenaare0be1672018-07-08 16:50:37 +02004368 dict_add_number(dict, "bufnr", buf->b_fnum);
4369 dict_add_string(dict, "name", buf->b_ffname);
4370 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4371 : buflist_findlnum(buf));
4372 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4373 dict_add_number(dict, "listed", buf->b_p_bl);
4374 dict_add_number(dict, "changed", bufIsChanged(buf));
4375 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4376 dict_add_number(dict, "hidden",
4377 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004378
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004379 /* Get a reference to buffer variables */
4380 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004381
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004382 /* List of windows displaying this buffer */
4383 windows = list_alloc();
4384 if (windows != NULL)
4385 {
4386 FOR_ALL_TAB_WINDOWS(tp, wp)
4387 if (wp->w_buffer == buf)
4388 list_append_number(windows, (varnumber_T)wp->w_id);
4389 dict_add_list(dict, "windows", windows);
4390 }
4391
4392#ifdef FEAT_SIGNS
4393 if (buf->b_signlist != NULL)
4394 {
4395 /* List of signs placed in this buffer */
4396 list_T *signs = list_alloc();
4397 if (signs != NULL)
4398 {
4399 get_buffer_signs(buf, signs);
4400 dict_add_list(dict, "signs", signs);
4401 }
4402 }
4403#endif
4404
4405 return dict;
4406}
4407
4408/*
4409 * "getbufinfo()" function
4410 */
4411 static void
4412f_getbufinfo(typval_T *argvars, typval_T *rettv)
4413{
4414 buf_T *buf = NULL;
4415 buf_T *argbuf = NULL;
4416 dict_T *d;
4417 int filtered = FALSE;
4418 int sel_buflisted = FALSE;
4419 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004420 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004421
4422 if (rettv_list_alloc(rettv) != OK)
4423 return;
4424
4425 /* List of all the buffers or selected buffers */
4426 if (argvars[0].v_type == VAR_DICT)
4427 {
4428 dict_T *sel_d = argvars[0].vval.v_dict;
4429
4430 if (sel_d != NULL)
4431 {
4432 dictitem_T *di;
4433
4434 filtered = TRUE;
4435
4436 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4437 if (di != NULL && get_tv_number(&di->di_tv))
4438 sel_buflisted = TRUE;
4439
4440 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4441 if (di != NULL && get_tv_number(&di->di_tv))
4442 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004443
4444 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4445 if (di != NULL && get_tv_number(&di->di_tv))
4446 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004447 }
4448 }
4449 else if (argvars[0].v_type != VAR_UNKNOWN)
4450 {
4451 /* Information about one buffer. Argument specifies the buffer */
4452 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4453 ++emsg_off;
4454 argbuf = get_buf_tv(&argvars[0], FALSE);
4455 --emsg_off;
4456 if (argbuf == NULL)
4457 return;
4458 }
4459
4460 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004461 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004462 {
4463 if (argbuf != NULL && argbuf != buf)
4464 continue;
4465 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004466 || (sel_buflisted && !buf->b_p_bl)
4467 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004468 continue;
4469
4470 d = get_buffer_info(buf);
4471 if (d != NULL)
4472 list_append_dict(rettv->vval.v_list, d);
4473 if (argbuf != NULL)
4474 return;
4475 }
4476}
4477
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004478static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4479
4480/*
4481 * Get line or list of lines from buffer "buf" into "rettv".
4482 * Return a range (from start to end) of lines in rettv from the specified
4483 * buffer.
4484 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4485 */
4486 static void
4487get_buffer_lines(
4488 buf_T *buf,
4489 linenr_T start,
4490 linenr_T end,
4491 int retlist,
4492 typval_T *rettv)
4493{
4494 char_u *p;
4495
4496 rettv->v_type = VAR_STRING;
4497 rettv->vval.v_string = NULL;
4498 if (retlist && rettv_list_alloc(rettv) == FAIL)
4499 return;
4500
4501 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4502 return;
4503
4504 if (!retlist)
4505 {
4506 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4507 p = ml_get_buf(buf, start, FALSE);
4508 else
4509 p = (char_u *)"";
4510 rettv->vval.v_string = vim_strsave(p);
4511 }
4512 else
4513 {
4514 if (end < start)
4515 return;
4516
4517 if (start < 1)
4518 start = 1;
4519 if (end > buf->b_ml.ml_line_count)
4520 end = buf->b_ml.ml_line_count;
4521 while (start <= end)
4522 if (list_append_string(rettv->vval.v_list,
4523 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4524 break;
4525 }
4526}
4527
4528/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004529 * "getbufline()" function
4530 */
4531 static void
4532f_getbufline(typval_T *argvars, typval_T *rettv)
4533{
4534 linenr_T lnum;
4535 linenr_T end;
4536 buf_T *buf;
4537
4538 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4539 ++emsg_off;
4540 buf = get_buf_tv(&argvars[0], FALSE);
4541 --emsg_off;
4542
4543 lnum = get_tv_lnum_buf(&argvars[1], buf);
4544 if (argvars[2].v_type == VAR_UNKNOWN)
4545 end = lnum;
4546 else
4547 end = get_tv_lnum_buf(&argvars[2], buf);
4548
4549 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4550}
4551
4552/*
4553 * "getbufvar()" function
4554 */
4555 static void
4556f_getbufvar(typval_T *argvars, typval_T *rettv)
4557{
4558 buf_T *buf;
4559 buf_T *save_curbuf;
4560 char_u *varname;
4561 dictitem_T *v;
4562 int done = FALSE;
4563
4564 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4565 varname = get_tv_string_chk(&argvars[1]);
4566 ++emsg_off;
4567 buf = get_buf_tv(&argvars[0], FALSE);
4568
4569 rettv->v_type = VAR_STRING;
4570 rettv->vval.v_string = NULL;
4571
4572 if (buf != NULL && varname != NULL)
4573 {
4574 /* set curbuf to be our buf, temporarily */
4575 save_curbuf = curbuf;
4576 curbuf = buf;
4577
Bram Moolenaar30567352016-08-27 21:25:44 +02004578 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004579 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004580 if (varname[1] == NUL)
4581 {
4582 /* get all buffer-local options in a dict */
4583 dict_T *opts = get_winbuf_options(TRUE);
4584
4585 if (opts != NULL)
4586 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004587 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004588 done = TRUE;
4589 }
4590 }
4591 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4592 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004593 done = TRUE;
4594 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004595 else
4596 {
4597 /* Look up the variable. */
4598 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4599 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4600 'b', varname, FALSE);
4601 if (v != NULL)
4602 {
4603 copy_tv(&v->di_tv, rettv);
4604 done = TRUE;
4605 }
4606 }
4607
4608 /* restore previous notion of curbuf */
4609 curbuf = save_curbuf;
4610 }
4611
4612 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4613 /* use the default value */
4614 copy_tv(&argvars[2], rettv);
4615
4616 --emsg_off;
4617}
4618
4619/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004620 * "getchangelist()" function
4621 */
4622 static void
4623f_getchangelist(typval_T *argvars, typval_T *rettv)
4624{
4625#ifdef FEAT_JUMPLIST
4626 buf_T *buf;
4627 int i;
4628 list_T *l;
4629 dict_T *d;
4630#endif
4631
4632 if (rettv_list_alloc(rettv) != OK)
4633 return;
4634
4635#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004636 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4637 ++emsg_off;
4638 buf = get_buf_tv(&argvars[0], FALSE);
4639 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004640 if (buf == NULL)
4641 return;
4642
4643 l = list_alloc();
4644 if (l == NULL)
4645 return;
4646
4647 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4648 return;
4649 /*
4650 * The current window change list index tracks only the position in the
4651 * current buffer change list. For other buffers, use the change list
4652 * length as the current index.
4653 */
4654 list_append_number(rettv->vval.v_list,
4655 (varnumber_T)((buf == curwin->w_buffer)
4656 ? curwin->w_changelistidx : buf->b_changelistlen));
4657
4658 for (i = 0; i < buf->b_changelistlen; ++i)
4659 {
4660 if (buf->b_changelist[i].lnum == 0)
4661 continue;
4662 if ((d = dict_alloc()) == NULL)
4663 return;
4664 if (list_append_dict(l, d) == FAIL)
4665 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004666 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4667 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004668# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004669 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004670# endif
4671 }
4672#endif
4673}
4674/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675 * "getchar()" function
4676 */
4677 static void
4678f_getchar(typval_T *argvars, typval_T *rettv)
4679{
4680 varnumber_T n;
4681 int error = FALSE;
4682
Bram Moolenaar84d93902018-09-11 20:10:20 +02004683#ifdef MESSAGE_QUEUE
4684 // vpeekc() used to check for messages, but that caused problems, invoking
4685 // a callback where it was not expected. Some plugins use getchar(1) in a
4686 // loop to await a message, therefore make sure we check for messages here.
4687 parse_queued_messages();
4688#endif
4689
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004690 /* Position the cursor. Needed after a message that ends in a space. */
4691 windgoto(msg_row, msg_col);
4692
4693 ++no_mapping;
4694 ++allow_keys;
4695 for (;;)
4696 {
4697 if (argvars[0].v_type == VAR_UNKNOWN)
4698 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004699 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4701 /* getchar(1): only check if char avail */
4702 n = vpeekc_any();
4703 else if (error || vpeekc_any() == NUL)
4704 /* illegal argument or getchar(0) and no char avail: return zero */
4705 n = 0;
4706 else
4707 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004708 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004709
4710 if (n == K_IGNORE)
4711 continue;
4712 break;
4713 }
4714 --no_mapping;
4715 --allow_keys;
4716
4717 set_vim_var_nr(VV_MOUSE_WIN, 0);
4718 set_vim_var_nr(VV_MOUSE_WINID, 0);
4719 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4720 set_vim_var_nr(VV_MOUSE_COL, 0);
4721
4722 rettv->vval.v_number = n;
4723 if (IS_SPECIAL(n) || mod_mask != 0)
4724 {
4725 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4726 int i = 0;
4727
4728 /* Turn a special key into three bytes, plus modifier. */
4729 if (mod_mask != 0)
4730 {
4731 temp[i++] = K_SPECIAL;
4732 temp[i++] = KS_MODIFIER;
4733 temp[i++] = mod_mask;
4734 }
4735 if (IS_SPECIAL(n))
4736 {
4737 temp[i++] = K_SPECIAL;
4738 temp[i++] = K_SECOND(n);
4739 temp[i++] = K_THIRD(n);
4740 }
4741#ifdef FEAT_MBYTE
4742 else if (has_mbyte)
4743 i += (*mb_char2bytes)(n, temp + i);
4744#endif
4745 else
4746 temp[i++] = n;
4747 temp[i++] = NUL;
4748 rettv->v_type = VAR_STRING;
4749 rettv->vval.v_string = vim_strsave(temp);
4750
4751#ifdef FEAT_MOUSE
4752 if (is_mouse_key(n))
4753 {
4754 int row = mouse_row;
4755 int col = mouse_col;
4756 win_T *win;
4757 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004759 int winnr = 1;
4760
4761 if (row >= 0 && col >= 0)
4762 {
4763 /* Find the window at the mouse coordinates and compute the
4764 * text position. */
4765 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004766 if (win == NULL)
4767 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004769 for (wp = firstwin; wp != win; wp = wp->w_next)
4770 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004771 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4772 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4773 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4774 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4775 }
4776 }
4777#endif
4778 }
4779}
4780
4781/*
4782 * "getcharmod()" function
4783 */
4784 static void
4785f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4786{
4787 rettv->vval.v_number = mod_mask;
4788}
4789
4790/*
4791 * "getcharsearch()" function
4792 */
4793 static void
4794f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4795{
4796 if (rettv_dict_alloc(rettv) != FAIL)
4797 {
4798 dict_T *dict = rettv->vval.v_dict;
4799
Bram Moolenaare0be1672018-07-08 16:50:37 +02004800 dict_add_string(dict, "char", last_csearch());
4801 dict_add_number(dict, "forward", last_csearch_forward());
4802 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004803 }
4804}
4805
4806/*
4807 * "getcmdline()" function
4808 */
4809 static void
4810f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4811{
4812 rettv->v_type = VAR_STRING;
4813 rettv->vval.v_string = get_cmdline_str();
4814}
4815
4816/*
4817 * "getcmdpos()" function
4818 */
4819 static void
4820f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4821{
4822 rettv->vval.v_number = get_cmdline_pos() + 1;
4823}
4824
4825/*
4826 * "getcmdtype()" function
4827 */
4828 static void
4829f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4830{
4831 rettv->v_type = VAR_STRING;
4832 rettv->vval.v_string = alloc(2);
4833 if (rettv->vval.v_string != NULL)
4834 {
4835 rettv->vval.v_string[0] = get_cmdline_type();
4836 rettv->vval.v_string[1] = NUL;
4837 }
4838}
4839
4840/*
4841 * "getcmdwintype()" function
4842 */
4843 static void
4844f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4845{
4846 rettv->v_type = VAR_STRING;
4847 rettv->vval.v_string = NULL;
4848#ifdef FEAT_CMDWIN
4849 rettv->vval.v_string = alloc(2);
4850 if (rettv->vval.v_string != NULL)
4851 {
4852 rettv->vval.v_string[0] = cmdwin_type;
4853 rettv->vval.v_string[1] = NUL;
4854 }
4855#endif
4856}
4857
4858#if defined(FEAT_CMDL_COMPL)
4859/*
4860 * "getcompletion()" function
4861 */
4862 static void
4863f_getcompletion(typval_T *argvars, typval_T *rettv)
4864{
4865 char_u *pat;
4866 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004867 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004868 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4869 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004870
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004871 if (argvars[2].v_type != VAR_UNKNOWN)
4872 filtered = get_tv_number_chk(&argvars[2], NULL);
4873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004874 if (p_wic)
4875 options |= WILD_ICASE;
4876
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004877 /* For filtered results, 'wildignore' is used */
4878 if (!filtered)
4879 options |= WILD_KEEP_ALL;
4880
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004881 ExpandInit(&xpc);
4882 xpc.xp_pattern = get_tv_string(&argvars[0]);
4883 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4884 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4885 if (xpc.xp_context == EXPAND_NOTHING)
4886 {
4887 if (argvars[1].v_type == VAR_STRING)
4888 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4889 else
4890 EMSG(_(e_invarg));
4891 return;
4892 }
4893
4894# if defined(FEAT_MENU)
4895 if (xpc.xp_context == EXPAND_MENUS)
4896 {
4897 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4898 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4899 }
4900# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004901#ifdef FEAT_CSCOPE
4902 if (xpc.xp_context == EXPAND_CSCOPE)
4903 {
4904 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4905 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4906 }
4907#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004908#ifdef FEAT_SIGNS
4909 if (xpc.xp_context == EXPAND_SIGN)
4910 {
4911 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4912 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4913 }
4914#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915
4916 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4917 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4918 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004919 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004920
4921 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4922
4923 for (i = 0; i < xpc.xp_numfiles; i++)
4924 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4925 }
4926 vim_free(pat);
4927 ExpandCleanup(&xpc);
4928}
4929#endif
4930
4931/*
4932 * "getcwd()" function
4933 */
4934 static void
4935f_getcwd(typval_T *argvars, typval_T *rettv)
4936{
4937 win_T *wp = NULL;
4938 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004939 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940
4941 rettv->v_type = VAR_STRING;
4942 rettv->vval.v_string = NULL;
4943
Bram Moolenaar54591292018-02-09 20:53:59 +01004944 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4945 global = TRUE;
4946 else
4947 wp = find_tabwin(&argvars[0], &argvars[1]);
4948
4949 if (wp != NULL && wp->w_localdir != NULL)
4950 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4951 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004952 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004953 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004954 rettv->vval.v_string = vim_strsave(globaldir);
4955 else
4956 {
4957 cwd = alloc(MAXPATHL);
4958 if (cwd != NULL)
4959 {
4960 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4961 rettv->vval.v_string = vim_strsave(cwd);
4962 vim_free(cwd);
4963 }
4964 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004966#ifdef BACKSLASH_IN_FILENAME
4967 if (rettv->vval.v_string != NULL)
4968 slash_adjust(rettv->vval.v_string);
4969#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004970}
4971
4972/*
4973 * "getfontname()" function
4974 */
4975 static void
4976f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4977{
4978 rettv->v_type = VAR_STRING;
4979 rettv->vval.v_string = NULL;
4980#ifdef FEAT_GUI
4981 if (gui.in_use)
4982 {
4983 GuiFont font;
4984 char_u *name = NULL;
4985
4986 if (argvars[0].v_type == VAR_UNKNOWN)
4987 {
4988 /* Get the "Normal" font. Either the name saved by
4989 * hl_set_font_name() or from the font ID. */
4990 font = gui.norm_font;
4991 name = hl_get_font_name();
4992 }
4993 else
4994 {
4995 name = get_tv_string(&argvars[0]);
4996 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4997 return;
4998 font = gui_mch_get_font(name, FALSE);
4999 if (font == NOFONT)
5000 return; /* Invalid font name, return empty string. */
5001 }
5002 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5003 if (argvars[0].v_type != VAR_UNKNOWN)
5004 gui_mch_free_font(font);
5005 }
5006#endif
5007}
5008
5009/*
5010 * "getfperm({fname})" function
5011 */
5012 static void
5013f_getfperm(typval_T *argvars, typval_T *rettv)
5014{
5015 char_u *fname;
5016 stat_T st;
5017 char_u *perm = NULL;
5018 char_u flags[] = "rwx";
5019 int i;
5020
5021 fname = get_tv_string(&argvars[0]);
5022
5023 rettv->v_type = VAR_STRING;
5024 if (mch_stat((char *)fname, &st) >= 0)
5025 {
5026 perm = vim_strsave((char_u *)"---------");
5027 if (perm != NULL)
5028 {
5029 for (i = 0; i < 9; i++)
5030 {
5031 if (st.st_mode & (1 << (8 - i)))
5032 perm[i] = flags[i % 3];
5033 }
5034 }
5035 }
5036 rettv->vval.v_string = perm;
5037}
5038
5039/*
5040 * "getfsize({fname})" function
5041 */
5042 static void
5043f_getfsize(typval_T *argvars, typval_T *rettv)
5044{
5045 char_u *fname;
5046 stat_T st;
5047
5048 fname = get_tv_string(&argvars[0]);
5049
5050 rettv->v_type = VAR_NUMBER;
5051
5052 if (mch_stat((char *)fname, &st) >= 0)
5053 {
5054 if (mch_isdir(fname))
5055 rettv->vval.v_number = 0;
5056 else
5057 {
5058 rettv->vval.v_number = (varnumber_T)st.st_size;
5059
5060 /* non-perfect check for overflow */
5061 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5062 rettv->vval.v_number = -2;
5063 }
5064 }
5065 else
5066 rettv->vval.v_number = -1;
5067}
5068
5069/*
5070 * "getftime({fname})" function
5071 */
5072 static void
5073f_getftime(typval_T *argvars, typval_T *rettv)
5074{
5075 char_u *fname;
5076 stat_T st;
5077
5078 fname = get_tv_string(&argvars[0]);
5079
5080 if (mch_stat((char *)fname, &st) >= 0)
5081 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5082 else
5083 rettv->vval.v_number = -1;
5084}
5085
5086/*
5087 * "getftype({fname})" function
5088 */
5089 static void
5090f_getftype(typval_T *argvars, typval_T *rettv)
5091{
5092 char_u *fname;
5093 stat_T st;
5094 char_u *type = NULL;
5095 char *t;
5096
5097 fname = get_tv_string(&argvars[0]);
5098
5099 rettv->v_type = VAR_STRING;
5100 if (mch_lstat((char *)fname, &st) >= 0)
5101 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 if (S_ISREG(st.st_mode))
5103 t = "file";
5104 else if (S_ISDIR(st.st_mode))
5105 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106 else if (S_ISLNK(st.st_mode))
5107 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108 else if (S_ISBLK(st.st_mode))
5109 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110 else if (S_ISCHR(st.st_mode))
5111 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005112 else if (S_ISFIFO(st.st_mode))
5113 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005115 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005116 else
5117 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005118 type = vim_strsave((char_u *)t);
5119 }
5120 rettv->vval.v_string = type;
5121}
5122
5123/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005124 * "getjumplist()" function
5125 */
5126 static void
5127f_getjumplist(typval_T *argvars, typval_T *rettv)
5128{
5129#ifdef FEAT_JUMPLIST
5130 win_T *wp;
5131 int i;
5132 list_T *l;
5133 dict_T *d;
5134#endif
5135
5136 if (rettv_list_alloc(rettv) != OK)
5137 return;
5138
5139#ifdef FEAT_JUMPLIST
5140 wp = find_tabwin(&argvars[0], &argvars[1]);
5141 if (wp == NULL)
5142 return;
5143
5144 l = list_alloc();
5145 if (l == NULL)
5146 return;
5147
5148 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5149 return;
5150 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5151
Bram Moolenaar48679742018-02-13 13:33:29 +01005152 cleanup_jumplist(wp, TRUE);
5153
Bram Moolenaar4f505882018-02-10 21:06:32 +01005154 for (i = 0; i < wp->w_jumplistlen; ++i)
5155 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005156 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5157 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005158 if ((d = dict_alloc()) == NULL)
5159 return;
5160 if (list_append_dict(l, d) == FAIL)
5161 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005162 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5163 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005164# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005165 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005166# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005167 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005168 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005169 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005170 }
5171#endif
5172}
5173
5174/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005175 * "getline(lnum, [end])" function
5176 */
5177 static void
5178f_getline(typval_T *argvars, typval_T *rettv)
5179{
5180 linenr_T lnum;
5181 linenr_T end;
5182 int retlist;
5183
5184 lnum = get_tv_lnum(argvars);
5185 if (argvars[1].v_type == VAR_UNKNOWN)
5186 {
5187 end = 0;
5188 retlist = FALSE;
5189 }
5190 else
5191 {
5192 end = get_tv_lnum(&argvars[1]);
5193 retlist = TRUE;
5194 }
5195
5196 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5197}
5198
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005199#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005200 static void
5201get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5202{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005203 if (what_arg->v_type == VAR_UNKNOWN)
5204 {
5205 if (rettv_list_alloc(rettv) == OK)
5206 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005207 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005208 }
5209 else
5210 {
5211 if (rettv_dict_alloc(rettv) == OK)
5212 if (is_qf || (wp != NULL))
5213 {
5214 if (what_arg->v_type == VAR_DICT)
5215 {
5216 dict_T *d = what_arg->vval.v_dict;
5217
5218 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005219 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005220 }
5221 else
5222 EMSG(_(e_dictreq));
5223 }
5224 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005225}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005226#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005227
5228/*
5229 * "getloclist()" function
5230 */
5231 static void
5232f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5233{
5234#ifdef FEAT_QUICKFIX
5235 win_T *wp;
5236
5237 wp = find_win_by_nr(&argvars[0], NULL);
5238 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5239#endif
5240}
5241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242/*
5243 * "getmatches()" function
5244 */
5245 static void
5246f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5247{
5248#ifdef FEAT_SEARCH_EXTRA
5249 dict_T *dict;
5250 matchitem_T *cur = curwin->w_match_head;
5251 int i;
5252
5253 if (rettv_list_alloc(rettv) == OK)
5254 {
5255 while (cur != NULL)
5256 {
5257 dict = dict_alloc();
5258 if (dict == NULL)
5259 return;
5260 if (cur->match.regprog == NULL)
5261 {
5262 /* match added with matchaddpos() */
5263 for (i = 0; i < MAXPOSMATCH; ++i)
5264 {
5265 llpos_T *llpos;
5266 char buf[6];
5267 list_T *l;
5268
5269 llpos = &cur->pos.pos[i];
5270 if (llpos->lnum == 0)
5271 break;
5272 l = list_alloc();
5273 if (l == NULL)
5274 break;
5275 list_append_number(l, (varnumber_T)llpos->lnum);
5276 if (llpos->col > 0)
5277 {
5278 list_append_number(l, (varnumber_T)llpos->col);
5279 list_append_number(l, (varnumber_T)llpos->len);
5280 }
5281 sprintf(buf, "pos%d", i + 1);
5282 dict_add_list(dict, buf, l);
5283 }
5284 }
5285 else
5286 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005287 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005289 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5290 dict_add_number(dict, "priority", (long)cur->priority);
5291 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5293 if (cur->conceal_char)
5294 {
5295 char_u buf[MB_MAXBYTES + 1];
5296
5297 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005298 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005299 }
5300# endif
5301 list_append_dict(rettv->vval.v_list, dict);
5302 cur = cur->next;
5303 }
5304 }
5305#endif
5306}
5307
5308/*
5309 * "getpid()" function
5310 */
5311 static void
5312f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5313{
5314 rettv->vval.v_number = mch_get_pid();
5315}
5316
5317 static void
5318getpos_both(
5319 typval_T *argvars,
5320 typval_T *rettv,
5321 int getcurpos)
5322{
5323 pos_T *fp;
5324 list_T *l;
5325 int fnum = -1;
5326
5327 if (rettv_list_alloc(rettv) == OK)
5328 {
5329 l = rettv->vval.v_list;
5330 if (getcurpos)
5331 fp = &curwin->w_cursor;
5332 else
5333 fp = var2fpos(&argvars[0], TRUE, &fnum);
5334 if (fnum != -1)
5335 list_append_number(l, (varnumber_T)fnum);
5336 else
5337 list_append_number(l, (varnumber_T)0);
5338 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5339 : (varnumber_T)0);
5340 list_append_number(l, (fp != NULL)
5341 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5342 : (varnumber_T)0);
5343 list_append_number(l,
5344#ifdef FEAT_VIRTUALEDIT
5345 (fp != NULL) ? (varnumber_T)fp->coladd :
5346#endif
5347 (varnumber_T)0);
5348 if (getcurpos)
5349 {
5350 update_curswant();
5351 list_append_number(l, curwin->w_curswant == MAXCOL ?
5352 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5353 }
5354 }
5355 else
5356 rettv->vval.v_number = FALSE;
5357}
5358
5359
5360/*
5361 * "getcurpos()" function
5362 */
5363 static void
5364f_getcurpos(typval_T *argvars, typval_T *rettv)
5365{
5366 getpos_both(argvars, rettv, TRUE);
5367}
5368
5369/*
5370 * "getpos(string)" function
5371 */
5372 static void
5373f_getpos(typval_T *argvars, typval_T *rettv)
5374{
5375 getpos_both(argvars, rettv, FALSE);
5376}
5377
5378/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005379 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005380 */
5381 static void
5382f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5383{
5384#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005385 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005386#endif
5387}
5388
5389/*
5390 * "getreg()" function
5391 */
5392 static void
5393f_getreg(typval_T *argvars, typval_T *rettv)
5394{
5395 char_u *strregname;
5396 int regname;
5397 int arg2 = FALSE;
5398 int return_list = FALSE;
5399 int error = FALSE;
5400
5401 if (argvars[0].v_type != VAR_UNKNOWN)
5402 {
5403 strregname = get_tv_string_chk(&argvars[0]);
5404 error = strregname == NULL;
5405 if (argvars[1].v_type != VAR_UNKNOWN)
5406 {
5407 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5408 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5409 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5410 }
5411 }
5412 else
5413 strregname = get_vim_var_str(VV_REG);
5414
5415 if (error)
5416 return;
5417
5418 regname = (strregname == NULL ? '"' : *strregname);
5419 if (regname == 0)
5420 regname = '"';
5421
5422 if (return_list)
5423 {
5424 rettv->v_type = VAR_LIST;
5425 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5426 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5427 if (rettv->vval.v_list == NULL)
5428 (void)rettv_list_alloc(rettv);
5429 else
5430 ++rettv->vval.v_list->lv_refcount;
5431 }
5432 else
5433 {
5434 rettv->v_type = VAR_STRING;
5435 rettv->vval.v_string = get_reg_contents(regname,
5436 arg2 ? GREG_EXPR_SRC : 0);
5437 }
5438}
5439
5440/*
5441 * "getregtype()" function
5442 */
5443 static void
5444f_getregtype(typval_T *argvars, typval_T *rettv)
5445{
5446 char_u *strregname;
5447 int regname;
5448 char_u buf[NUMBUFLEN + 2];
5449 long reglen = 0;
5450
5451 if (argvars[0].v_type != VAR_UNKNOWN)
5452 {
5453 strregname = get_tv_string_chk(&argvars[0]);
5454 if (strregname == NULL) /* type error; errmsg already given */
5455 {
5456 rettv->v_type = VAR_STRING;
5457 rettv->vval.v_string = NULL;
5458 return;
5459 }
5460 }
5461 else
5462 /* Default to v:register */
5463 strregname = get_vim_var_str(VV_REG);
5464
5465 regname = (strregname == NULL ? '"' : *strregname);
5466 if (regname == 0)
5467 regname = '"';
5468
5469 buf[0] = NUL;
5470 buf[1] = NUL;
5471 switch (get_reg_type(regname, &reglen))
5472 {
5473 case MLINE: buf[0] = 'V'; break;
5474 case MCHAR: buf[0] = 'v'; break;
5475 case MBLOCK:
5476 buf[0] = Ctrl_V;
5477 sprintf((char *)buf + 1, "%ld", reglen + 1);
5478 break;
5479 }
5480 rettv->v_type = VAR_STRING;
5481 rettv->vval.v_string = vim_strsave(buf);
5482}
5483
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005484/*
5485 * Returns information (variables, options, etc.) about a tab page
5486 * as a dictionary.
5487 */
5488 static dict_T *
5489get_tabpage_info(tabpage_T *tp, int tp_idx)
5490{
5491 win_T *wp;
5492 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005493 list_T *l;
5494
5495 dict = dict_alloc();
5496 if (dict == NULL)
5497 return NULL;
5498
Bram Moolenaare0be1672018-07-08 16:50:37 +02005499 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005500
5501 l = list_alloc();
5502 if (l != NULL)
5503 {
5504 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5505 wp; wp = wp->w_next)
5506 list_append_number(l, (varnumber_T)wp->w_id);
5507 dict_add_list(dict, "windows", l);
5508 }
5509
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005510 /* Make a reference to tabpage variables */
5511 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005512
5513 return dict;
5514}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005515
5516/*
5517 * "gettabinfo()" function
5518 */
5519 static void
5520f_gettabinfo(typval_T *argvars, typval_T *rettv)
5521{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005522 tabpage_T *tp, *tparg = NULL;
5523 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005524 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005525
5526 if (rettv_list_alloc(rettv) != OK)
5527 return;
5528
5529 if (argvars[0].v_type != VAR_UNKNOWN)
5530 {
5531 /* Information about one tab page */
5532 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5533 if (tparg == NULL)
5534 return;
5535 }
5536
5537 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005538 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005539 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005540 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005541 if (tparg != NULL && tp != tparg)
5542 continue;
5543 d = get_tabpage_info(tp, tpnr);
5544 if (d != NULL)
5545 list_append_dict(rettv->vval.v_list, d);
5546 if (tparg != NULL)
5547 return;
5548 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005549}
5550
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005551/*
5552 * "gettabvar()" function
5553 */
5554 static void
5555f_gettabvar(typval_T *argvars, typval_T *rettv)
5556{
5557 win_T *oldcurwin;
5558 tabpage_T *tp, *oldtabpage;
5559 dictitem_T *v;
5560 char_u *varname;
5561 int done = FALSE;
5562
5563 rettv->v_type = VAR_STRING;
5564 rettv->vval.v_string = NULL;
5565
5566 varname = get_tv_string_chk(&argvars[1]);
5567 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5568 if (tp != NULL && varname != NULL)
5569 {
5570 /* Set tp to be our tabpage, temporarily. Also set the window to the
5571 * first window in the tabpage, otherwise the window is not valid. */
5572 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005573 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5574 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005575 {
5576 /* look up the variable */
5577 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5578 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5579 if (v != NULL)
5580 {
5581 copy_tv(&v->di_tv, rettv);
5582 done = TRUE;
5583 }
5584 }
5585
5586 /* restore previous notion of curwin */
5587 restore_win(oldcurwin, oldtabpage, TRUE);
5588 }
5589
5590 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5591 copy_tv(&argvars[2], rettv);
5592}
5593
5594/*
5595 * "gettabwinvar()" function
5596 */
5597 static void
5598f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5599{
5600 getwinvar(argvars, rettv, 1);
5601}
5602
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005603/*
5604 * Returns information about a window as a dictionary.
5605 */
5606 static dict_T *
5607get_win_info(win_T *wp, short tpnr, short winnr)
5608{
5609 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005610
5611 dict = dict_alloc();
5612 if (dict == NULL)
5613 return NULL;
5614
Bram Moolenaare0be1672018-07-08 16:50:37 +02005615 dict_add_number(dict, "tabnr", tpnr);
5616 dict_add_number(dict, "winnr", winnr);
5617 dict_add_number(dict, "winid", wp->w_id);
5618 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005619 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005620#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005621 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005622#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005623 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005624 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005625 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005626
Bram Moolenaar69905d12017-08-13 18:14:47 +02005627#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005628 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005629#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005630#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005631 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5632 dict_add_number(dict, "loclist",
5633 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005634#endif
5635
Bram Moolenaar30567352016-08-27 21:25:44 +02005636 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005637 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005638
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005639 return dict;
5640}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005641
5642/*
5643 * "getwininfo()" function
5644 */
5645 static void
5646f_getwininfo(typval_T *argvars, typval_T *rettv)
5647{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005648 tabpage_T *tp;
5649 win_T *wp = NULL, *wparg = NULL;
5650 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005651 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005652
5653 if (rettv_list_alloc(rettv) != OK)
5654 return;
5655
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005656 if (argvars[0].v_type != VAR_UNKNOWN)
5657 {
5658 wparg = win_id2wp(argvars);
5659 if (wparg == NULL)
5660 return;
5661 }
5662
5663 /* Collect information about either all the windows across all the tab
5664 * pages or one particular window.
5665 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005666 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005667 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005668 tabnr++;
5669 winnr = 0;
5670 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005671 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005672 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005673 if (wparg != NULL && wp != wparg)
5674 continue;
5675 d = get_win_info(wp, tabnr, winnr);
5676 if (d != NULL)
5677 list_append_dict(rettv->vval.v_list, d);
5678 if (wparg != NULL)
5679 /* found information about a specific window */
5680 return;
5681 }
5682 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005683}
5684
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005686 * "win_findbuf()" function
5687 */
5688 static void
5689f_win_findbuf(typval_T *argvars, typval_T *rettv)
5690{
5691 if (rettv_list_alloc(rettv) != FAIL)
5692 win_findbuf(argvars, rettv->vval.v_list);
5693}
5694
5695/*
5696 * "win_getid()" function
5697 */
5698 static void
5699f_win_getid(typval_T *argvars, typval_T *rettv)
5700{
5701 rettv->vval.v_number = win_getid(argvars);
5702}
5703
5704/*
5705 * "win_gotoid()" function
5706 */
5707 static void
5708f_win_gotoid(typval_T *argvars, typval_T *rettv)
5709{
5710 rettv->vval.v_number = win_gotoid(argvars);
5711}
5712
5713/*
5714 * "win_id2tabwin()" function
5715 */
5716 static void
5717f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5718{
5719 if (rettv_list_alloc(rettv) != FAIL)
5720 win_id2tabwin(argvars, rettv->vval.v_list);
5721}
5722
5723/*
5724 * "win_id2win()" function
5725 */
5726 static void
5727f_win_id2win(typval_T *argvars, typval_T *rettv)
5728{
5729 rettv->vval.v_number = win_id2win(argvars);
5730}
5731
5732/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005733 * "win_screenpos()" function
5734 */
5735 static void
5736f_win_screenpos(typval_T *argvars, typval_T *rettv)
5737{
5738 win_T *wp;
5739
5740 if (rettv_list_alloc(rettv) == FAIL)
5741 return;
5742
5743 wp = find_win_by_nr(&argvars[0], NULL);
5744 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5745 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5746}
5747
5748/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005749 * "getwinpos({timeout})" function
5750 */
5751 static void
5752f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5753{
5754 int x = -1;
5755 int y = -1;
5756
5757 if (rettv_list_alloc(rettv) == FAIL)
5758 return;
5759#ifdef FEAT_GUI
5760 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005761 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005762# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5763 else
5764# endif
5765#endif
5766#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5767 {
5768 varnumber_T timeout = 100;
5769
5770 if (argvars[0].v_type != VAR_UNKNOWN)
5771 timeout = get_tv_number(&argvars[0]);
5772 term_get_winpos(&x, &y, timeout);
5773 }
5774#endif
5775 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5776 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5777}
5778
5779
5780/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005781 * "getwinposx()" function
5782 */
5783 static void
5784f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5785{
5786 rettv->vval.v_number = -1;
5787#ifdef FEAT_GUI
5788 if (gui.in_use)
5789 {
5790 int x, y;
5791
5792 if (gui_mch_get_winpos(&x, &y) == OK)
5793 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005794 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005795 }
5796#endif
5797#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5798 {
5799 int x, y;
5800
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005801 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005802 rettv->vval.v_number = x;
5803 }
5804#endif
5805}
5806
5807/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808 * "getwinposy()" function
5809 */
5810 static void
5811f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5812{
5813 rettv->vval.v_number = -1;
5814#ifdef FEAT_GUI
5815 if (gui.in_use)
5816 {
5817 int x, y;
5818
5819 if (gui_mch_get_winpos(&x, &y) == OK)
5820 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005821 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005822 }
5823#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005824#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5825 {
5826 int x, y;
5827
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005828 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005829 rettv->vval.v_number = y;
5830 }
5831#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005832}
5833
5834/*
5835 * "getwinvar()" function
5836 */
5837 static void
5838f_getwinvar(typval_T *argvars, typval_T *rettv)
5839{
5840 getwinvar(argvars, rettv, 0);
5841}
5842
5843/*
5844 * "glob()" function
5845 */
5846 static void
5847f_glob(typval_T *argvars, typval_T *rettv)
5848{
5849 int options = WILD_SILENT|WILD_USE_NL;
5850 expand_T xpc;
5851 int error = FALSE;
5852
5853 /* When the optional second argument is non-zero, don't remove matches
5854 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5855 rettv->v_type = VAR_STRING;
5856 if (argvars[1].v_type != VAR_UNKNOWN)
5857 {
5858 if (get_tv_number_chk(&argvars[1], &error))
5859 options |= WILD_KEEP_ALL;
5860 if (argvars[2].v_type != VAR_UNKNOWN)
5861 {
5862 if (get_tv_number_chk(&argvars[2], &error))
5863 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005864 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005865 }
5866 if (argvars[3].v_type != VAR_UNKNOWN
5867 && get_tv_number_chk(&argvars[3], &error))
5868 options |= WILD_ALLLINKS;
5869 }
5870 }
5871 if (!error)
5872 {
5873 ExpandInit(&xpc);
5874 xpc.xp_context = EXPAND_FILES;
5875 if (p_wic)
5876 options += WILD_ICASE;
5877 if (rettv->v_type == VAR_STRING)
5878 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5879 NULL, options, WILD_ALL);
5880 else if (rettv_list_alloc(rettv) != FAIL)
5881 {
5882 int i;
5883
5884 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5885 NULL, options, WILD_ALL_KEEP);
5886 for (i = 0; i < xpc.xp_numfiles; i++)
5887 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5888
5889 ExpandCleanup(&xpc);
5890 }
5891 }
5892 else
5893 rettv->vval.v_string = NULL;
5894}
5895
5896/*
5897 * "globpath()" function
5898 */
5899 static void
5900f_globpath(typval_T *argvars, typval_T *rettv)
5901{
5902 int flags = 0;
5903 char_u buf1[NUMBUFLEN];
5904 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5905 int error = FALSE;
5906 garray_T ga;
5907 int i;
5908
5909 /* When the optional second argument is non-zero, don't remove matches
5910 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5911 rettv->v_type = VAR_STRING;
5912 if (argvars[2].v_type != VAR_UNKNOWN)
5913 {
5914 if (get_tv_number_chk(&argvars[2], &error))
5915 flags |= WILD_KEEP_ALL;
5916 if (argvars[3].v_type != VAR_UNKNOWN)
5917 {
5918 if (get_tv_number_chk(&argvars[3], &error))
5919 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005920 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005921 }
5922 if (argvars[4].v_type != VAR_UNKNOWN
5923 && get_tv_number_chk(&argvars[4], &error))
5924 flags |= WILD_ALLLINKS;
5925 }
5926 }
5927 if (file != NULL && !error)
5928 {
5929 ga_init2(&ga, (int)sizeof(char_u *), 10);
5930 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5931 if (rettv->v_type == VAR_STRING)
5932 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5933 else if (rettv_list_alloc(rettv) != FAIL)
5934 for (i = 0; i < ga.ga_len; ++i)
5935 list_append_string(rettv->vval.v_list,
5936 ((char_u **)(ga.ga_data))[i], -1);
5937 ga_clear_strings(&ga);
5938 }
5939 else
5940 rettv->vval.v_string = NULL;
5941}
5942
5943/*
5944 * "glob2regpat()" function
5945 */
5946 static void
5947f_glob2regpat(typval_T *argvars, typval_T *rettv)
5948{
5949 char_u *pat = get_tv_string_chk(&argvars[0]);
5950
5951 rettv->v_type = VAR_STRING;
5952 rettv->vval.v_string = (pat == NULL)
5953 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5954}
5955
5956/* for VIM_VERSION_ defines */
5957#include "version.h"
5958
5959/*
5960 * "has()" function
5961 */
5962 static void
5963f_has(typval_T *argvars, typval_T *rettv)
5964{
5965 int i;
5966 char_u *name;
5967 int n = FALSE;
5968 static char *(has_list[]) =
5969 {
5970#ifdef AMIGA
5971 "amiga",
5972# ifdef FEAT_ARP
5973 "arp",
5974# endif
5975#endif
5976#ifdef __BEOS__
5977 "beos",
5978#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005979#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005980 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5981 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005982# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005983 "macunix", /* Mac OS X, with the darwin feature */
5984 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005985# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005986#endif
5987#ifdef __QNX__
5988 "qnx",
5989#endif
5990#ifdef UNIX
5991 "unix",
5992#endif
5993#ifdef VMS
5994 "vms",
5995#endif
5996#ifdef WIN32
5997 "win32",
5998#endif
5999#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6000 "win32unix",
6001#endif
6002#if defined(WIN64) || defined(_WIN64)
6003 "win64",
6004#endif
6005#ifdef EBCDIC
6006 "ebcdic",
6007#endif
6008#ifndef CASE_INSENSITIVE_FILENAME
6009 "fname_case",
6010#endif
6011#ifdef HAVE_ACL
6012 "acl",
6013#endif
6014#ifdef FEAT_ARABIC
6015 "arabic",
6016#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006017 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006018#ifdef FEAT_AUTOCHDIR
6019 "autochdir",
6020#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006021#ifdef FEAT_AUTOSERVERNAME
6022 "autoservername",
6023#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006024#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006025 "balloon_eval",
6026# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6027 "balloon_multiline",
6028# endif
6029#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006030#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006031 "balloon_eval_term",
6032#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006033#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6034 "builtin_terms",
6035# ifdef ALL_BUILTIN_TCAPS
6036 "all_builtin_terms",
6037# endif
6038#endif
6039#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6040 || defined(FEAT_GUI_W32) \
6041 || defined(FEAT_GUI_MOTIF))
6042 "browsefilter",
6043#endif
6044#ifdef FEAT_BYTEOFF
6045 "byte_offset",
6046#endif
6047#ifdef FEAT_JOB_CHANNEL
6048 "channel",
6049#endif
6050#ifdef FEAT_CINDENT
6051 "cindent",
6052#endif
6053#ifdef FEAT_CLIENTSERVER
6054 "clientserver",
6055#endif
6056#ifdef FEAT_CLIPBOARD
6057 "clipboard",
6058#endif
6059#ifdef FEAT_CMDL_COMPL
6060 "cmdline_compl",
6061#endif
6062#ifdef FEAT_CMDHIST
6063 "cmdline_hist",
6064#endif
6065#ifdef FEAT_COMMENTS
6066 "comments",
6067#endif
6068#ifdef FEAT_CONCEAL
6069 "conceal",
6070#endif
6071#ifdef FEAT_CRYPT
6072 "cryptv",
6073 "crypt-blowfish",
6074 "crypt-blowfish2",
6075#endif
6076#ifdef FEAT_CSCOPE
6077 "cscope",
6078#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006079 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006080#ifdef CURSOR_SHAPE
6081 "cursorshape",
6082#endif
6083#ifdef DEBUG
6084 "debug",
6085#endif
6086#ifdef FEAT_CON_DIALOG
6087 "dialog_con",
6088#endif
6089#ifdef FEAT_GUI_DIALOG
6090 "dialog_gui",
6091#endif
6092#ifdef FEAT_DIFF
6093 "diff",
6094#endif
6095#ifdef FEAT_DIGRAPHS
6096 "digraphs",
6097#endif
6098#ifdef FEAT_DIRECTX
6099 "directx",
6100#endif
6101#ifdef FEAT_DND
6102 "dnd",
6103#endif
6104#ifdef FEAT_EMACS_TAGS
6105 "emacs_tags",
6106#endif
6107 "eval", /* always present, of course! */
6108 "ex_extra", /* graduated feature */
6109#ifdef FEAT_SEARCH_EXTRA
6110 "extra_search",
6111#endif
6112#ifdef FEAT_FKMAP
6113 "farsi",
6114#endif
6115#ifdef FEAT_SEARCHPATH
6116 "file_in_path",
6117#endif
6118#ifdef FEAT_FILTERPIPE
6119 "filterpipe",
6120#endif
6121#ifdef FEAT_FIND_ID
6122 "find_in_path",
6123#endif
6124#ifdef FEAT_FLOAT
6125 "float",
6126#endif
6127#ifdef FEAT_FOLDING
6128 "folding",
6129#endif
6130#ifdef FEAT_FOOTER
6131 "footer",
6132#endif
6133#if !defined(USE_SYSTEM) && defined(UNIX)
6134 "fork",
6135#endif
6136#ifdef FEAT_GETTEXT
6137 "gettext",
6138#endif
6139#ifdef FEAT_GUI
6140 "gui",
6141#endif
6142#ifdef FEAT_GUI_ATHENA
6143# ifdef FEAT_GUI_NEXTAW
6144 "gui_neXtaw",
6145# else
6146 "gui_athena",
6147# endif
6148#endif
6149#ifdef FEAT_GUI_GTK
6150 "gui_gtk",
6151# ifdef USE_GTK3
6152 "gui_gtk3",
6153# else
6154 "gui_gtk2",
6155# endif
6156#endif
6157#ifdef FEAT_GUI_GNOME
6158 "gui_gnome",
6159#endif
6160#ifdef FEAT_GUI_MAC
6161 "gui_mac",
6162#endif
6163#ifdef FEAT_GUI_MOTIF
6164 "gui_motif",
6165#endif
6166#ifdef FEAT_GUI_PHOTON
6167 "gui_photon",
6168#endif
6169#ifdef FEAT_GUI_W32
6170 "gui_win32",
6171#endif
6172#ifdef FEAT_HANGULIN
6173 "hangul_input",
6174#endif
6175#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6176 "iconv",
6177#endif
6178#ifdef FEAT_INS_EXPAND
6179 "insert_expand",
6180#endif
6181#ifdef FEAT_JOB_CHANNEL
6182 "job",
6183#endif
6184#ifdef FEAT_JUMPLIST
6185 "jumplist",
6186#endif
6187#ifdef FEAT_KEYMAP
6188 "keymap",
6189#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006190 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006191#ifdef FEAT_LANGMAP
6192 "langmap",
6193#endif
6194#ifdef FEAT_LIBCALL
6195 "libcall",
6196#endif
6197#ifdef FEAT_LINEBREAK
6198 "linebreak",
6199#endif
6200#ifdef FEAT_LISP
6201 "lispindent",
6202#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006203 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006204#ifdef FEAT_LOCALMAP
6205 "localmap",
6206#endif
6207#ifdef FEAT_LUA
6208# ifndef DYNAMIC_LUA
6209 "lua",
6210# endif
6211#endif
6212#ifdef FEAT_MENU
6213 "menu",
6214#endif
6215#ifdef FEAT_SESSION
6216 "mksession",
6217#endif
6218#ifdef FEAT_MODIFY_FNAME
6219 "modify_fname",
6220#endif
6221#ifdef FEAT_MOUSE
6222 "mouse",
6223#endif
6224#ifdef FEAT_MOUSESHAPE
6225 "mouseshape",
6226#endif
6227#if defined(UNIX) || defined(VMS)
6228# ifdef FEAT_MOUSE_DEC
6229 "mouse_dec",
6230# endif
6231# ifdef FEAT_MOUSE_GPM
6232 "mouse_gpm",
6233# endif
6234# ifdef FEAT_MOUSE_JSB
6235 "mouse_jsbterm",
6236# endif
6237# ifdef FEAT_MOUSE_NET
6238 "mouse_netterm",
6239# endif
6240# ifdef FEAT_MOUSE_PTERM
6241 "mouse_pterm",
6242# endif
6243# ifdef FEAT_MOUSE_SGR
6244 "mouse_sgr",
6245# endif
6246# ifdef FEAT_SYSMOUSE
6247 "mouse_sysmouse",
6248# endif
6249# ifdef FEAT_MOUSE_URXVT
6250 "mouse_urxvt",
6251# endif
6252# ifdef FEAT_MOUSE_XTERM
6253 "mouse_xterm",
6254# endif
6255#endif
6256#ifdef FEAT_MBYTE
6257 "multi_byte",
6258#endif
6259#ifdef FEAT_MBYTE_IME
6260 "multi_byte_ime",
6261#endif
6262#ifdef FEAT_MULTI_LANG
6263 "multi_lang",
6264#endif
6265#ifdef FEAT_MZSCHEME
6266#ifndef DYNAMIC_MZSCHEME
6267 "mzscheme",
6268#endif
6269#endif
6270#ifdef FEAT_NUM64
6271 "num64",
6272#endif
6273#ifdef FEAT_OLE
6274 "ole",
6275#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006276#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006277 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006278#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006279#ifdef FEAT_PATH_EXTRA
6280 "path_extra",
6281#endif
6282#ifdef FEAT_PERL
6283#ifndef DYNAMIC_PERL
6284 "perl",
6285#endif
6286#endif
6287#ifdef FEAT_PERSISTENT_UNDO
6288 "persistent_undo",
6289#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006290#if defined(FEAT_PYTHON)
6291 "python_compiled",
6292# if defined(DYNAMIC_PYTHON)
6293 "python_dynamic",
6294# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006295 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006296 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006297# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006298#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006299#if defined(FEAT_PYTHON3)
6300 "python3_compiled",
6301# if defined(DYNAMIC_PYTHON3)
6302 "python3_dynamic",
6303# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006304 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006305 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006306# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307#endif
6308#ifdef FEAT_POSTSCRIPT
6309 "postscript",
6310#endif
6311#ifdef FEAT_PRINTER
6312 "printer",
6313#endif
6314#ifdef FEAT_PROFILE
6315 "profile",
6316#endif
6317#ifdef FEAT_RELTIME
6318 "reltime",
6319#endif
6320#ifdef FEAT_QUICKFIX
6321 "quickfix",
6322#endif
6323#ifdef FEAT_RIGHTLEFT
6324 "rightleft",
6325#endif
6326#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6327 "ruby",
6328#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006329 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006330#ifdef FEAT_CMDL_INFO
6331 "showcmd",
6332 "cmdline_info",
6333#endif
6334#ifdef FEAT_SIGNS
6335 "signs",
6336#endif
6337#ifdef FEAT_SMARTINDENT
6338 "smartindent",
6339#endif
6340#ifdef STARTUPTIME
6341 "startuptime",
6342#endif
6343#ifdef FEAT_STL_OPT
6344 "statusline",
6345#endif
6346#ifdef FEAT_SUN_WORKSHOP
6347 "sun_workshop",
6348#endif
6349#ifdef FEAT_NETBEANS_INTG
6350 "netbeans_intg",
6351#endif
6352#ifdef FEAT_SPELL
6353 "spell",
6354#endif
6355#ifdef FEAT_SYN_HL
6356 "syntax",
6357#endif
6358#if defined(USE_SYSTEM) || !defined(UNIX)
6359 "system",
6360#endif
6361#ifdef FEAT_TAG_BINS
6362 "tag_binary",
6363#endif
6364#ifdef FEAT_TAG_OLDSTATIC
6365 "tag_old_static",
6366#endif
6367#ifdef FEAT_TAG_ANYWHITE
6368 "tag_any_white",
6369#endif
6370#ifdef FEAT_TCL
6371# ifndef DYNAMIC_TCL
6372 "tcl",
6373# endif
6374#endif
6375#ifdef FEAT_TERMGUICOLORS
6376 "termguicolors",
6377#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006378#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006379 "terminal",
6380#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006381#ifdef TERMINFO
6382 "terminfo",
6383#endif
6384#ifdef FEAT_TERMRESPONSE
6385 "termresponse",
6386#endif
6387#ifdef FEAT_TEXTOBJ
6388 "textobjects",
6389#endif
6390#ifdef HAVE_TGETENT
6391 "tgetent",
6392#endif
6393#ifdef FEAT_TIMERS
6394 "timers",
6395#endif
6396#ifdef FEAT_TITLE
6397 "title",
6398#endif
6399#ifdef FEAT_TOOLBAR
6400 "toolbar",
6401#endif
6402#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6403 "unnamedplus",
6404#endif
6405#ifdef FEAT_USR_CMDS
6406 "user-commands", /* was accidentally included in 5.4 */
6407 "user_commands",
6408#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006409#ifdef FEAT_VARTABS
6410 "vartabs",
6411#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412#ifdef FEAT_VIMINFO
6413 "viminfo",
6414#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416#ifdef FEAT_VIRTUALEDIT
6417 "virtualedit",
6418#endif
6419 "visual",
6420#ifdef FEAT_VISUALEXTRA
6421 "visualextra",
6422#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006423 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006424#ifdef FEAT_VTP
6425 "vtp",
6426#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427#ifdef FEAT_WILDIGN
6428 "wildignore",
6429#endif
6430#ifdef FEAT_WILDMENU
6431 "wildmenu",
6432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006433 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006434#ifdef FEAT_WAK
6435 "winaltkeys",
6436#endif
6437#ifdef FEAT_WRITEBACKUP
6438 "writebackup",
6439#endif
6440#ifdef FEAT_XIM
6441 "xim",
6442#endif
6443#ifdef FEAT_XFONTSET
6444 "xfontset",
6445#endif
6446#ifdef FEAT_XPM_W32
6447 "xpm",
6448 "xpm_w32", /* for backward compatibility */
6449#else
6450# if defined(HAVE_XPM)
6451 "xpm",
6452# endif
6453#endif
6454#ifdef USE_XSMP
6455 "xsmp",
6456#endif
6457#ifdef USE_XSMP_INTERACT
6458 "xsmp_interact",
6459#endif
6460#ifdef FEAT_XCLIPBOARD
6461 "xterm_clipboard",
6462#endif
6463#ifdef FEAT_XTERM_SAVE
6464 "xterm_save",
6465#endif
6466#if defined(UNIX) && defined(FEAT_X11)
6467 "X11",
6468#endif
6469 NULL
6470 };
6471
6472 name = get_tv_string(&argvars[0]);
6473 for (i = 0; has_list[i] != NULL; ++i)
6474 if (STRICMP(name, has_list[i]) == 0)
6475 {
6476 n = TRUE;
6477 break;
6478 }
6479
6480 if (n == FALSE)
6481 {
6482 if (STRNICMP(name, "patch", 5) == 0)
6483 {
6484 if (name[5] == '-'
6485 && STRLEN(name) >= 11
6486 && vim_isdigit(name[6])
6487 && vim_isdigit(name[8])
6488 && vim_isdigit(name[10]))
6489 {
6490 int major = atoi((char *)name + 6);
6491 int minor = atoi((char *)name + 8);
6492
6493 /* Expect "patch-9.9.01234". */
6494 n = (major < VIM_VERSION_MAJOR
6495 || (major == VIM_VERSION_MAJOR
6496 && (minor < VIM_VERSION_MINOR
6497 || (minor == VIM_VERSION_MINOR
6498 && has_patch(atoi((char *)name + 10))))));
6499 }
6500 else
6501 n = has_patch(atoi((char *)name + 5));
6502 }
6503 else if (STRICMP(name, "vim_starting") == 0)
6504 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006505 else if (STRICMP(name, "ttyin") == 0)
6506 n = mch_input_isatty();
6507 else if (STRICMP(name, "ttyout") == 0)
6508 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006509#ifdef FEAT_MBYTE
6510 else if (STRICMP(name, "multi_byte_encoding") == 0)
6511 n = has_mbyte;
6512#endif
6513#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6514 else if (STRICMP(name, "balloon_multiline") == 0)
6515 n = multiline_balloon_available();
6516#endif
6517#ifdef DYNAMIC_TCL
6518 else if (STRICMP(name, "tcl") == 0)
6519 n = tcl_enabled(FALSE);
6520#endif
6521#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6522 else if (STRICMP(name, "iconv") == 0)
6523 n = iconv_enabled(FALSE);
6524#endif
6525#ifdef DYNAMIC_LUA
6526 else if (STRICMP(name, "lua") == 0)
6527 n = lua_enabled(FALSE);
6528#endif
6529#ifdef DYNAMIC_MZSCHEME
6530 else if (STRICMP(name, "mzscheme") == 0)
6531 n = mzscheme_enabled(FALSE);
6532#endif
6533#ifdef DYNAMIC_RUBY
6534 else if (STRICMP(name, "ruby") == 0)
6535 n = ruby_enabled(FALSE);
6536#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537#ifdef DYNAMIC_PYTHON
6538 else if (STRICMP(name, "python") == 0)
6539 n = python_enabled(FALSE);
6540#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541#ifdef DYNAMIC_PYTHON3
6542 else if (STRICMP(name, "python3") == 0)
6543 n = python3_enabled(FALSE);
6544#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006545#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6546 else if (STRICMP(name, "pythonx") == 0)
6547 {
6548# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6549 if (p_pyx == 0)
6550 n = python3_enabled(FALSE) || python_enabled(FALSE);
6551 else if (p_pyx == 3)
6552 n = python3_enabled(FALSE);
6553 else if (p_pyx == 2)
6554 n = python_enabled(FALSE);
6555# elif defined(DYNAMIC_PYTHON)
6556 n = python_enabled(FALSE);
6557# elif defined(DYNAMIC_PYTHON3)
6558 n = python3_enabled(FALSE);
6559# endif
6560 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006561#endif
6562#ifdef DYNAMIC_PERL
6563 else if (STRICMP(name, "perl") == 0)
6564 n = perl_enabled(FALSE);
6565#endif
6566#ifdef FEAT_GUI
6567 else if (STRICMP(name, "gui_running") == 0)
6568 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006569# ifdef FEAT_BROWSE
6570 else if (STRICMP(name, "browse") == 0)
6571 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6572# endif
6573#endif
6574#ifdef FEAT_SYN_HL
6575 else if (STRICMP(name, "syntax_items") == 0)
6576 n = syntax_present(curwin);
6577#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006578#ifdef FEAT_VTP
6579 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006580 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006581#endif
6582#ifdef FEAT_NETBEANS_INTG
6583 else if (STRICMP(name, "netbeans_enabled") == 0)
6584 n = netbeans_active();
6585#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006586#if defined(FEAT_TERMINAL) && defined(WIN3264)
6587 else if (STRICMP(name, "terminal") == 0)
6588 n = terminal_enabled();
6589#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590 }
6591
6592 rettv->vval.v_number = n;
6593}
6594
6595/*
6596 * "has_key()" function
6597 */
6598 static void
6599f_has_key(typval_T *argvars, typval_T *rettv)
6600{
6601 if (argvars[0].v_type != VAR_DICT)
6602 {
6603 EMSG(_(e_dictreq));
6604 return;
6605 }
6606 if (argvars[0].vval.v_dict == NULL)
6607 return;
6608
6609 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6610 get_tv_string(&argvars[1]), -1) != NULL;
6611}
6612
6613/*
6614 * "haslocaldir()" function
6615 */
6616 static void
6617f_haslocaldir(typval_T *argvars, typval_T *rettv)
6618{
6619 win_T *wp = NULL;
6620
6621 wp = find_tabwin(&argvars[0], &argvars[1]);
6622 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6623}
6624
6625/*
6626 * "hasmapto()" function
6627 */
6628 static void
6629f_hasmapto(typval_T *argvars, typval_T *rettv)
6630{
6631 char_u *name;
6632 char_u *mode;
6633 char_u buf[NUMBUFLEN];
6634 int abbr = FALSE;
6635
6636 name = get_tv_string(&argvars[0]);
6637 if (argvars[1].v_type == VAR_UNKNOWN)
6638 mode = (char_u *)"nvo";
6639 else
6640 {
6641 mode = get_tv_string_buf(&argvars[1], buf);
6642 if (argvars[2].v_type != VAR_UNKNOWN)
6643 abbr = (int)get_tv_number(&argvars[2]);
6644 }
6645
6646 if (map_to_exists(name, mode, abbr))
6647 rettv->vval.v_number = TRUE;
6648 else
6649 rettv->vval.v_number = FALSE;
6650}
6651
6652/*
6653 * "histadd()" function
6654 */
6655 static void
6656f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6657{
6658#ifdef FEAT_CMDHIST
6659 int histype;
6660 char_u *str;
6661 char_u buf[NUMBUFLEN];
6662#endif
6663
6664 rettv->vval.v_number = FALSE;
6665 if (check_restricted() || check_secure())
6666 return;
6667#ifdef FEAT_CMDHIST
6668 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6669 histype = str != NULL ? get_histtype(str) : -1;
6670 if (histype >= 0)
6671 {
6672 str = get_tv_string_buf(&argvars[1], buf);
6673 if (*str != NUL)
6674 {
6675 init_history();
6676 add_to_history(histype, str, FALSE, NUL);
6677 rettv->vval.v_number = TRUE;
6678 return;
6679 }
6680 }
6681#endif
6682}
6683
6684/*
6685 * "histdel()" function
6686 */
6687 static void
6688f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6689{
6690#ifdef FEAT_CMDHIST
6691 int n;
6692 char_u buf[NUMBUFLEN];
6693 char_u *str;
6694
6695 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6696 if (str == NULL)
6697 n = 0;
6698 else if (argvars[1].v_type == VAR_UNKNOWN)
6699 /* only one argument: clear entire history */
6700 n = clr_history(get_histtype(str));
6701 else if (argvars[1].v_type == VAR_NUMBER)
6702 /* index given: remove that entry */
6703 n = del_history_idx(get_histtype(str),
6704 (int)get_tv_number(&argvars[1]));
6705 else
6706 /* string given: remove all matching entries */
6707 n = del_history_entry(get_histtype(str),
6708 get_tv_string_buf(&argvars[1], buf));
6709 rettv->vval.v_number = n;
6710#endif
6711}
6712
6713/*
6714 * "histget()" function
6715 */
6716 static void
6717f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6718{
6719#ifdef FEAT_CMDHIST
6720 int type;
6721 int idx;
6722 char_u *str;
6723
6724 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6725 if (str == NULL)
6726 rettv->vval.v_string = NULL;
6727 else
6728 {
6729 type = get_histtype(str);
6730 if (argvars[1].v_type == VAR_UNKNOWN)
6731 idx = get_history_idx(type);
6732 else
6733 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6734 /* -1 on type error */
6735 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6736 }
6737#else
6738 rettv->vval.v_string = NULL;
6739#endif
6740 rettv->v_type = VAR_STRING;
6741}
6742
6743/*
6744 * "histnr()" function
6745 */
6746 static void
6747f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6748{
6749 int i;
6750
6751#ifdef FEAT_CMDHIST
6752 char_u *history = get_tv_string_chk(&argvars[0]);
6753
6754 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6755 if (i >= HIST_CMD && i < HIST_COUNT)
6756 i = get_history_idx(i);
6757 else
6758#endif
6759 i = -1;
6760 rettv->vval.v_number = i;
6761}
6762
6763/*
6764 * "highlightID(name)" function
6765 */
6766 static void
6767f_hlID(typval_T *argvars, typval_T *rettv)
6768{
6769 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6770}
6771
6772/*
6773 * "highlight_exists()" function
6774 */
6775 static void
6776f_hlexists(typval_T *argvars, typval_T *rettv)
6777{
6778 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6779}
6780
6781/*
6782 * "hostname()" function
6783 */
6784 static void
6785f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6786{
6787 char_u hostname[256];
6788
6789 mch_get_host_name(hostname, 256);
6790 rettv->v_type = VAR_STRING;
6791 rettv->vval.v_string = vim_strsave(hostname);
6792}
6793
6794/*
6795 * iconv() function
6796 */
6797 static void
6798f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6799{
6800#ifdef FEAT_MBYTE
6801 char_u buf1[NUMBUFLEN];
6802 char_u buf2[NUMBUFLEN];
6803 char_u *from, *to, *str;
6804 vimconv_T vimconv;
6805#endif
6806
6807 rettv->v_type = VAR_STRING;
6808 rettv->vval.v_string = NULL;
6809
6810#ifdef FEAT_MBYTE
6811 str = get_tv_string(&argvars[0]);
6812 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6813 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6814 vimconv.vc_type = CONV_NONE;
6815 convert_setup(&vimconv, from, to);
6816
6817 /* If the encodings are equal, no conversion needed. */
6818 if (vimconv.vc_type == CONV_NONE)
6819 rettv->vval.v_string = vim_strsave(str);
6820 else
6821 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6822
6823 convert_setup(&vimconv, NULL, NULL);
6824 vim_free(from);
6825 vim_free(to);
6826#endif
6827}
6828
6829/*
6830 * "indent()" function
6831 */
6832 static void
6833f_indent(typval_T *argvars, typval_T *rettv)
6834{
6835 linenr_T lnum;
6836
6837 lnum = get_tv_lnum(argvars);
6838 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6839 rettv->vval.v_number = get_indent_lnum(lnum);
6840 else
6841 rettv->vval.v_number = -1;
6842}
6843
6844/*
6845 * "index()" function
6846 */
6847 static void
6848f_index(typval_T *argvars, typval_T *rettv)
6849{
6850 list_T *l;
6851 listitem_T *item;
6852 long idx = 0;
6853 int ic = FALSE;
6854
6855 rettv->vval.v_number = -1;
6856 if (argvars[0].v_type != VAR_LIST)
6857 {
6858 EMSG(_(e_listreq));
6859 return;
6860 }
6861 l = argvars[0].vval.v_list;
6862 if (l != NULL)
6863 {
6864 item = l->lv_first;
6865 if (argvars[2].v_type != VAR_UNKNOWN)
6866 {
6867 int error = FALSE;
6868
6869 /* Start at specified item. Use the cached index that list_find()
6870 * sets, so that a negative number also works. */
6871 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6872 idx = l->lv_idx;
6873 if (argvars[3].v_type != VAR_UNKNOWN)
6874 ic = (int)get_tv_number_chk(&argvars[3], &error);
6875 if (error)
6876 item = NULL;
6877 }
6878
6879 for ( ; item != NULL; item = item->li_next, ++idx)
6880 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6881 {
6882 rettv->vval.v_number = idx;
6883 break;
6884 }
6885 }
6886}
6887
6888static int inputsecret_flag = 0;
6889
6890/*
6891 * "input()" function
6892 * Also handles inputsecret() when inputsecret is set.
6893 */
6894 static void
6895f_input(typval_T *argvars, typval_T *rettv)
6896{
6897 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6898}
6899
6900/*
6901 * "inputdialog()" function
6902 */
6903 static void
6904f_inputdialog(typval_T *argvars, typval_T *rettv)
6905{
6906#if defined(FEAT_GUI_TEXTDIALOG)
6907 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6908 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6909 {
6910 char_u *message;
6911 char_u buf[NUMBUFLEN];
6912 char_u *defstr = (char_u *)"";
6913
6914 message = get_tv_string_chk(&argvars[0]);
6915 if (argvars[1].v_type != VAR_UNKNOWN
6916 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6917 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6918 else
6919 IObuff[0] = NUL;
6920 if (message != NULL && defstr != NULL
6921 && do_dialog(VIM_QUESTION, NULL, message,
6922 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6923 rettv->vval.v_string = vim_strsave(IObuff);
6924 else
6925 {
6926 if (message != NULL && defstr != NULL
6927 && argvars[1].v_type != VAR_UNKNOWN
6928 && argvars[2].v_type != VAR_UNKNOWN)
6929 rettv->vval.v_string = vim_strsave(
6930 get_tv_string_buf(&argvars[2], buf));
6931 else
6932 rettv->vval.v_string = NULL;
6933 }
6934 rettv->v_type = VAR_STRING;
6935 }
6936 else
6937#endif
6938 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6939}
6940
6941/*
6942 * "inputlist()" function
6943 */
6944 static void
6945f_inputlist(typval_T *argvars, typval_T *rettv)
6946{
6947 listitem_T *li;
6948 int selected;
6949 int mouse_used;
6950
6951#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006952 /* While starting up, there is no place to enter text. When running tests
6953 * with --not-a-term we assume feedkeys() will be used. */
6954 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006955 return;
6956#endif
6957 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6958 {
6959 EMSG2(_(e_listarg), "inputlist()");
6960 return;
6961 }
6962
6963 msg_start();
6964 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6965 lines_left = Rows; /* avoid more prompt */
6966 msg_scroll = TRUE;
6967 msg_clr_eos();
6968
6969 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6970 {
6971 msg_puts(get_tv_string(&li->li_tv));
6972 msg_putchar('\n');
6973 }
6974
6975 /* Ask for choice. */
6976 selected = prompt_for_number(&mouse_used);
6977 if (mouse_used)
6978 selected -= lines_left;
6979
6980 rettv->vval.v_number = selected;
6981}
6982
6983
6984static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6985
6986/*
6987 * "inputrestore()" function
6988 */
6989 static void
6990f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6991{
6992 if (ga_userinput.ga_len > 0)
6993 {
6994 --ga_userinput.ga_len;
6995 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6996 + ga_userinput.ga_len);
6997 /* default return is zero == OK */
6998 }
6999 else if (p_verbose > 1)
7000 {
7001 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
7002 rettv->vval.v_number = 1; /* Failed */
7003 }
7004}
7005
7006/*
7007 * "inputsave()" function
7008 */
7009 static void
7010f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7011{
7012 /* Add an entry to the stack of typeahead storage. */
7013 if (ga_grow(&ga_userinput, 1) == OK)
7014 {
7015 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7016 + ga_userinput.ga_len);
7017 ++ga_userinput.ga_len;
7018 /* default return is zero == OK */
7019 }
7020 else
7021 rettv->vval.v_number = 1; /* Failed */
7022}
7023
7024/*
7025 * "inputsecret()" function
7026 */
7027 static void
7028f_inputsecret(typval_T *argvars, typval_T *rettv)
7029{
7030 ++cmdline_star;
7031 ++inputsecret_flag;
7032 f_input(argvars, rettv);
7033 --cmdline_star;
7034 --inputsecret_flag;
7035}
7036
7037/*
7038 * "insert()" function
7039 */
7040 static void
7041f_insert(typval_T *argvars, typval_T *rettv)
7042{
7043 long before = 0;
7044 listitem_T *item;
7045 list_T *l;
7046 int error = FALSE;
7047
7048 if (argvars[0].v_type != VAR_LIST)
7049 EMSG2(_(e_listarg), "insert()");
7050 else if ((l = argvars[0].vval.v_list) != NULL
7051 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7052 {
7053 if (argvars[2].v_type != VAR_UNKNOWN)
7054 before = (long)get_tv_number_chk(&argvars[2], &error);
7055 if (error)
7056 return; /* type error; errmsg already given */
7057
7058 if (before == l->lv_len)
7059 item = NULL;
7060 else
7061 {
7062 item = list_find(l, before);
7063 if (item == NULL)
7064 {
7065 EMSGN(_(e_listidx), before);
7066 l = NULL;
7067 }
7068 }
7069 if (l != NULL)
7070 {
7071 list_insert_tv(l, &argvars[1], item);
7072 copy_tv(&argvars[0], rettv);
7073 }
7074 }
7075}
7076
7077/*
7078 * "invert(expr)" function
7079 */
7080 static void
7081f_invert(typval_T *argvars, typval_T *rettv)
7082{
7083 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
7084}
7085
7086/*
7087 * "isdirectory()" function
7088 */
7089 static void
7090f_isdirectory(typval_T *argvars, typval_T *rettv)
7091{
7092 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
7093}
7094
7095/*
7096 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7097 * or it refers to a List or Dictionary that is locked.
7098 */
7099 static int
7100tv_islocked(typval_T *tv)
7101{
7102 return (tv->v_lock & VAR_LOCKED)
7103 || (tv->v_type == VAR_LIST
7104 && tv->vval.v_list != NULL
7105 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7106 || (tv->v_type == VAR_DICT
7107 && tv->vval.v_dict != NULL
7108 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7109}
7110
7111/*
7112 * "islocked()" function
7113 */
7114 static void
7115f_islocked(typval_T *argvars, typval_T *rettv)
7116{
7117 lval_T lv;
7118 char_u *end;
7119 dictitem_T *di;
7120
7121 rettv->vval.v_number = -1;
7122 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007123 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124 if (end != NULL && lv.ll_name != NULL)
7125 {
7126 if (*end != NUL)
7127 EMSG(_(e_trailing));
7128 else
7129 {
7130 if (lv.ll_tv == NULL)
7131 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007132 di = find_var(lv.ll_name, NULL, TRUE);
7133 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007134 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007135 /* Consider a variable locked when:
7136 * 1. the variable itself is locked
7137 * 2. the value of the variable is locked.
7138 * 3. the List or Dict value is locked.
7139 */
7140 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7141 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 }
7143 }
7144 else if (lv.ll_range)
7145 EMSG(_("E786: Range not allowed"));
7146 else if (lv.ll_newkey != NULL)
7147 EMSG2(_(e_dictkey), lv.ll_newkey);
7148 else if (lv.ll_list != NULL)
7149 /* List item. */
7150 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7151 else
7152 /* Dictionary item. */
7153 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7154 }
7155 }
7156
7157 clear_lval(&lv);
7158}
7159
7160#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7161/*
7162 * "isnan()" function
7163 */
7164 static void
7165f_isnan(typval_T *argvars, typval_T *rettv)
7166{
7167 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7168 && isnan(argvars[0].vval.v_float);
7169}
7170#endif
7171
7172/*
7173 * "items(dict)" function
7174 */
7175 static void
7176f_items(typval_T *argvars, typval_T *rettv)
7177{
7178 dict_list(argvars, rettv, 2);
7179}
7180
7181#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7182/*
7183 * Get the job from the argument.
7184 * Returns NULL if the job is invalid.
7185 */
7186 static job_T *
7187get_job_arg(typval_T *tv)
7188{
7189 job_T *job;
7190
7191 if (tv->v_type != VAR_JOB)
7192 {
7193 EMSG2(_(e_invarg2), get_tv_string(tv));
7194 return NULL;
7195 }
7196 job = tv->vval.v_job;
7197
7198 if (job == NULL)
7199 EMSG(_("E916: not a valid job"));
7200 return job;
7201}
7202
7203/*
7204 * "job_getchannel()" function
7205 */
7206 static void
7207f_job_getchannel(typval_T *argvars, typval_T *rettv)
7208{
7209 job_T *job = get_job_arg(&argvars[0]);
7210
7211 if (job != NULL)
7212 {
7213 rettv->v_type = VAR_CHANNEL;
7214 rettv->vval.v_channel = job->jv_channel;
7215 if (job->jv_channel != NULL)
7216 ++job->jv_channel->ch_refcount;
7217 }
7218}
7219
7220/*
7221 * "job_info()" function
7222 */
7223 static void
7224f_job_info(typval_T *argvars, typval_T *rettv)
7225{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007226 if (argvars[0].v_type != VAR_UNKNOWN)
7227 {
7228 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007230 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7231 job_info(job, rettv->vval.v_dict);
7232 }
7233 else if (rettv_list_alloc(rettv) == OK)
7234 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007235}
7236
7237/*
7238 * "job_setoptions()" function
7239 */
7240 static void
7241f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7242{
7243 job_T *job = get_job_arg(&argvars[0]);
7244 jobopt_T opt;
7245
7246 if (job == NULL)
7247 return;
7248 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007249 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250 job_set_options(job, &opt);
7251 free_job_options(&opt);
7252}
7253
7254/*
7255 * "job_start()" function
7256 */
7257 static void
7258f_job_start(typval_T *argvars, typval_T *rettv)
7259{
7260 rettv->v_type = VAR_JOB;
7261 if (check_restricted() || check_secure())
7262 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007263 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007264}
7265
7266/*
7267 * "job_status()" function
7268 */
7269 static void
7270f_job_status(typval_T *argvars, typval_T *rettv)
7271{
7272 job_T *job = get_job_arg(&argvars[0]);
7273
7274 if (job != NULL)
7275 {
7276 rettv->v_type = VAR_STRING;
7277 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7278 }
7279}
7280
7281/*
7282 * "job_stop()" function
7283 */
7284 static void
7285f_job_stop(typval_T *argvars, typval_T *rettv)
7286{
7287 job_T *job = get_job_arg(&argvars[0]);
7288
7289 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007290 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007291}
7292#endif
7293
7294/*
7295 * "join()" function
7296 */
7297 static void
7298f_join(typval_T *argvars, typval_T *rettv)
7299{
7300 garray_T ga;
7301 char_u *sep;
7302
7303 if (argvars[0].v_type != VAR_LIST)
7304 {
7305 EMSG(_(e_listreq));
7306 return;
7307 }
7308 if (argvars[0].vval.v_list == NULL)
7309 return;
7310 if (argvars[1].v_type == VAR_UNKNOWN)
7311 sep = (char_u *)" ";
7312 else
7313 sep = get_tv_string_chk(&argvars[1]);
7314
7315 rettv->v_type = VAR_STRING;
7316
7317 if (sep != NULL)
7318 {
7319 ga_init2(&ga, (int)sizeof(char), 80);
7320 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7321 ga_append(&ga, NUL);
7322 rettv->vval.v_string = (char_u *)ga.ga_data;
7323 }
7324 else
7325 rettv->vval.v_string = NULL;
7326}
7327
7328/*
7329 * "js_decode()" function
7330 */
7331 static void
7332f_js_decode(typval_T *argvars, typval_T *rettv)
7333{
7334 js_read_T reader;
7335
7336 reader.js_buf = get_tv_string(&argvars[0]);
7337 reader.js_fill = NULL;
7338 reader.js_used = 0;
7339 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7340 EMSG(_(e_invarg));
7341}
7342
7343/*
7344 * "js_encode()" function
7345 */
7346 static void
7347f_js_encode(typval_T *argvars, typval_T *rettv)
7348{
7349 rettv->v_type = VAR_STRING;
7350 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7351}
7352
7353/*
7354 * "json_decode()" function
7355 */
7356 static void
7357f_json_decode(typval_T *argvars, typval_T *rettv)
7358{
7359 js_read_T reader;
7360
7361 reader.js_buf = get_tv_string(&argvars[0]);
7362 reader.js_fill = NULL;
7363 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007364 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365}
7366
7367/*
7368 * "json_encode()" function
7369 */
7370 static void
7371f_json_encode(typval_T *argvars, typval_T *rettv)
7372{
7373 rettv->v_type = VAR_STRING;
7374 rettv->vval.v_string = json_encode(&argvars[0], 0);
7375}
7376
7377/*
7378 * "keys()" function
7379 */
7380 static void
7381f_keys(typval_T *argvars, typval_T *rettv)
7382{
7383 dict_list(argvars, rettv, 0);
7384}
7385
7386/*
7387 * "last_buffer_nr()" function.
7388 */
7389 static void
7390f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7391{
7392 int n = 0;
7393 buf_T *buf;
7394
Bram Moolenaar29323592016-07-24 22:04:11 +02007395 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396 if (n < buf->b_fnum)
7397 n = buf->b_fnum;
7398
7399 rettv->vval.v_number = n;
7400}
7401
7402/*
7403 * "len()" function
7404 */
7405 static void
7406f_len(typval_T *argvars, typval_T *rettv)
7407{
7408 switch (argvars[0].v_type)
7409 {
7410 case VAR_STRING:
7411 case VAR_NUMBER:
7412 rettv->vval.v_number = (varnumber_T)STRLEN(
7413 get_tv_string(&argvars[0]));
7414 break;
7415 case VAR_LIST:
7416 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7417 break;
7418 case VAR_DICT:
7419 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7420 break;
7421 case VAR_UNKNOWN:
7422 case VAR_SPECIAL:
7423 case VAR_FLOAT:
7424 case VAR_FUNC:
7425 case VAR_PARTIAL:
7426 case VAR_JOB:
7427 case VAR_CHANNEL:
7428 EMSG(_("E701: Invalid type for len()"));
7429 break;
7430 }
7431}
7432
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007434libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007435{
7436#ifdef FEAT_LIBCALL
7437 char_u *string_in;
7438 char_u **string_result;
7439 int nr_result;
7440#endif
7441
7442 rettv->v_type = type;
7443 if (type != VAR_NUMBER)
7444 rettv->vval.v_string = NULL;
7445
7446 if (check_restricted() || check_secure())
7447 return;
7448
7449#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007450 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007451 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7452 {
7453 string_in = NULL;
7454 if (argvars[2].v_type == VAR_STRING)
7455 string_in = argvars[2].vval.v_string;
7456 if (type == VAR_NUMBER)
7457 string_result = NULL;
7458 else
7459 string_result = &rettv->vval.v_string;
7460 if (mch_libcall(argvars[0].vval.v_string,
7461 argvars[1].vval.v_string,
7462 string_in,
7463 argvars[2].vval.v_number,
7464 string_result,
7465 &nr_result) == OK
7466 && type == VAR_NUMBER)
7467 rettv->vval.v_number = nr_result;
7468 }
7469#endif
7470}
7471
7472/*
7473 * "libcall()" function
7474 */
7475 static void
7476f_libcall(typval_T *argvars, typval_T *rettv)
7477{
7478 libcall_common(argvars, rettv, VAR_STRING);
7479}
7480
7481/*
7482 * "libcallnr()" function
7483 */
7484 static void
7485f_libcallnr(typval_T *argvars, typval_T *rettv)
7486{
7487 libcall_common(argvars, rettv, VAR_NUMBER);
7488}
7489
7490/*
7491 * "line(string)" function
7492 */
7493 static void
7494f_line(typval_T *argvars, typval_T *rettv)
7495{
7496 linenr_T lnum = 0;
7497 pos_T *fp;
7498 int fnum;
7499
7500 fp = var2fpos(&argvars[0], TRUE, &fnum);
7501 if (fp != NULL)
7502 lnum = fp->lnum;
7503 rettv->vval.v_number = lnum;
7504}
7505
7506/*
7507 * "line2byte(lnum)" function
7508 */
7509 static void
7510f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7511{
7512#ifndef FEAT_BYTEOFF
7513 rettv->vval.v_number = -1;
7514#else
7515 linenr_T lnum;
7516
7517 lnum = get_tv_lnum(argvars);
7518 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7519 rettv->vval.v_number = -1;
7520 else
7521 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7522 if (rettv->vval.v_number >= 0)
7523 ++rettv->vval.v_number;
7524#endif
7525}
7526
7527/*
7528 * "lispindent(lnum)" function
7529 */
7530 static void
7531f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7532{
7533#ifdef FEAT_LISP
7534 pos_T pos;
7535 linenr_T lnum;
7536
7537 pos = curwin->w_cursor;
7538 lnum = get_tv_lnum(argvars);
7539 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7540 {
7541 curwin->w_cursor.lnum = lnum;
7542 rettv->vval.v_number = get_lisp_indent();
7543 curwin->w_cursor = pos;
7544 }
7545 else
7546#endif
7547 rettv->vval.v_number = -1;
7548}
7549
7550/*
7551 * "localtime()" function
7552 */
7553 static void
7554f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7555{
7556 rettv->vval.v_number = (varnumber_T)time(NULL);
7557}
7558
7559static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7560
7561 static void
7562get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7563{
7564 char_u *keys;
7565 char_u *which;
7566 char_u buf[NUMBUFLEN];
7567 char_u *keys_buf = NULL;
7568 char_u *rhs;
7569 int mode;
7570 int abbr = FALSE;
7571 int get_dict = FALSE;
7572 mapblock_T *mp;
7573 int buffer_local;
7574
7575 /* return empty string for failure */
7576 rettv->v_type = VAR_STRING;
7577 rettv->vval.v_string = NULL;
7578
7579 keys = get_tv_string(&argvars[0]);
7580 if (*keys == NUL)
7581 return;
7582
7583 if (argvars[1].v_type != VAR_UNKNOWN)
7584 {
7585 which = get_tv_string_buf_chk(&argvars[1], buf);
7586 if (argvars[2].v_type != VAR_UNKNOWN)
7587 {
7588 abbr = (int)get_tv_number(&argvars[2]);
7589 if (argvars[3].v_type != VAR_UNKNOWN)
7590 get_dict = (int)get_tv_number(&argvars[3]);
7591 }
7592 }
7593 else
7594 which = (char_u *)"";
7595 if (which == NULL)
7596 return;
7597
7598 mode = get_map_mode(&which, 0);
7599
7600 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7601 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7602 vim_free(keys_buf);
7603
7604 if (!get_dict)
7605 {
7606 /* Return a string. */
7607 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007608 {
7609 if (*rhs == NUL)
7610 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7611 else
7612 rettv->vval.v_string = str2special_save(rhs, FALSE);
7613 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007614
7615 }
7616 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7617 {
7618 /* Return a dictionary. */
7619 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7620 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7621 dict_T *dict = rettv->vval.v_dict;
7622
Bram Moolenaare0be1672018-07-08 16:50:37 +02007623 dict_add_string(dict, "lhs", lhs);
7624 dict_add_string(dict, "rhs", mp->m_orig_str);
7625 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7626 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7627 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007628 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7629 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007630 dict_add_number(dict, "buffer", (long)buffer_local);
7631 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7632 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633
7634 vim_free(lhs);
7635 vim_free(mapmode);
7636 }
7637}
7638
7639#ifdef FEAT_FLOAT
7640/*
7641 * "log()" function
7642 */
7643 static void
7644f_log(typval_T *argvars, typval_T *rettv)
7645{
7646 float_T f = 0.0;
7647
7648 rettv->v_type = VAR_FLOAT;
7649 if (get_float_arg(argvars, &f) == OK)
7650 rettv->vval.v_float = log(f);
7651 else
7652 rettv->vval.v_float = 0.0;
7653}
7654
7655/*
7656 * "log10()" function
7657 */
7658 static void
7659f_log10(typval_T *argvars, typval_T *rettv)
7660{
7661 float_T f = 0.0;
7662
7663 rettv->v_type = VAR_FLOAT;
7664 if (get_float_arg(argvars, &f) == OK)
7665 rettv->vval.v_float = log10(f);
7666 else
7667 rettv->vval.v_float = 0.0;
7668}
7669#endif
7670
7671#ifdef FEAT_LUA
7672/*
7673 * "luaeval()" function
7674 */
7675 static void
7676f_luaeval(typval_T *argvars, typval_T *rettv)
7677{
7678 char_u *str;
7679 char_u buf[NUMBUFLEN];
7680
7681 str = get_tv_string_buf(&argvars[0], buf);
7682 do_luaeval(str, argvars + 1, rettv);
7683}
7684#endif
7685
7686/*
7687 * "map()" function
7688 */
7689 static void
7690f_map(typval_T *argvars, typval_T *rettv)
7691{
7692 filter_map(argvars, rettv, TRUE);
7693}
7694
7695/*
7696 * "maparg()" function
7697 */
7698 static void
7699f_maparg(typval_T *argvars, typval_T *rettv)
7700{
7701 get_maparg(argvars, rettv, TRUE);
7702}
7703
7704/*
7705 * "mapcheck()" function
7706 */
7707 static void
7708f_mapcheck(typval_T *argvars, typval_T *rettv)
7709{
7710 get_maparg(argvars, rettv, FALSE);
7711}
7712
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007713typedef enum
7714{
7715 MATCH_END, /* matchend() */
7716 MATCH_MATCH, /* match() */
7717 MATCH_STR, /* matchstr() */
7718 MATCH_LIST, /* matchlist() */
7719 MATCH_POS /* matchstrpos() */
7720} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007721
7722 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007723find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007724{
7725 char_u *str = NULL;
7726 long len = 0;
7727 char_u *expr = NULL;
7728 char_u *pat;
7729 regmatch_T regmatch;
7730 char_u patbuf[NUMBUFLEN];
7731 char_u strbuf[NUMBUFLEN];
7732 char_u *save_cpo;
7733 long start = 0;
7734 long nth = 1;
7735 colnr_T startcol = 0;
7736 int match = 0;
7737 list_T *l = NULL;
7738 listitem_T *li = NULL;
7739 long idx = 0;
7740 char_u *tofree = NULL;
7741
7742 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7743 save_cpo = p_cpo;
7744 p_cpo = (char_u *)"";
7745
7746 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007747 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007749 /* type MATCH_LIST: return empty list when there are no matches.
7750 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007751 if (rettv_list_alloc(rettv) == FAIL)
7752 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007753 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007754 && (list_append_string(rettv->vval.v_list,
7755 (char_u *)"", 0) == FAIL
7756 || list_append_number(rettv->vval.v_list,
7757 (varnumber_T)-1) == FAIL
7758 || list_append_number(rettv->vval.v_list,
7759 (varnumber_T)-1) == FAIL
7760 || list_append_number(rettv->vval.v_list,
7761 (varnumber_T)-1) == FAIL))
7762 {
7763 list_free(rettv->vval.v_list);
7764 rettv->vval.v_list = NULL;
7765 goto theend;
7766 }
7767 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007768 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007769 {
7770 rettv->v_type = VAR_STRING;
7771 rettv->vval.v_string = NULL;
7772 }
7773
7774 if (argvars[0].v_type == VAR_LIST)
7775 {
7776 if ((l = argvars[0].vval.v_list) == NULL)
7777 goto theend;
7778 li = l->lv_first;
7779 }
7780 else
7781 {
7782 expr = str = get_tv_string(&argvars[0]);
7783 len = (long)STRLEN(str);
7784 }
7785
7786 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7787 if (pat == NULL)
7788 goto theend;
7789
7790 if (argvars[2].v_type != VAR_UNKNOWN)
7791 {
7792 int error = FALSE;
7793
7794 start = (long)get_tv_number_chk(&argvars[2], &error);
7795 if (error)
7796 goto theend;
7797 if (l != NULL)
7798 {
7799 li = list_find(l, start);
7800 if (li == NULL)
7801 goto theend;
7802 idx = l->lv_idx; /* use the cached index */
7803 }
7804 else
7805 {
7806 if (start < 0)
7807 start = 0;
7808 if (start > len)
7809 goto theend;
7810 /* When "count" argument is there ignore matches before "start",
7811 * otherwise skip part of the string. Differs when pattern is "^"
7812 * or "\<". */
7813 if (argvars[3].v_type != VAR_UNKNOWN)
7814 startcol = start;
7815 else
7816 {
7817 str += start;
7818 len -= start;
7819 }
7820 }
7821
7822 if (argvars[3].v_type != VAR_UNKNOWN)
7823 nth = (long)get_tv_number_chk(&argvars[3], &error);
7824 if (error)
7825 goto theend;
7826 }
7827
7828 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7829 if (regmatch.regprog != NULL)
7830 {
7831 regmatch.rm_ic = p_ic;
7832
7833 for (;;)
7834 {
7835 if (l != NULL)
7836 {
7837 if (li == NULL)
7838 {
7839 match = FALSE;
7840 break;
7841 }
7842 vim_free(tofree);
7843 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7844 if (str == NULL)
7845 break;
7846 }
7847
7848 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7849
7850 if (match && --nth <= 0)
7851 break;
7852 if (l == NULL && !match)
7853 break;
7854
7855 /* Advance to just after the match. */
7856 if (l != NULL)
7857 {
7858 li = li->li_next;
7859 ++idx;
7860 }
7861 else
7862 {
7863#ifdef FEAT_MBYTE
7864 startcol = (colnr_T)(regmatch.startp[0]
7865 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7866#else
7867 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7868#endif
7869 if (startcol > (colnr_T)len
7870 || str + startcol <= regmatch.startp[0])
7871 {
7872 match = FALSE;
7873 break;
7874 }
7875 }
7876 }
7877
7878 if (match)
7879 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007880 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007881 {
7882 listitem_T *li1 = rettv->vval.v_list->lv_first;
7883 listitem_T *li2 = li1->li_next;
7884 listitem_T *li3 = li2->li_next;
7885 listitem_T *li4 = li3->li_next;
7886
7887 vim_free(li1->li_tv.vval.v_string);
7888 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7889 (int)(regmatch.endp[0] - regmatch.startp[0]));
7890 li3->li_tv.vval.v_number =
7891 (varnumber_T)(regmatch.startp[0] - expr);
7892 li4->li_tv.vval.v_number =
7893 (varnumber_T)(regmatch.endp[0] - expr);
7894 if (l != NULL)
7895 li2->li_tv.vval.v_number = (varnumber_T)idx;
7896 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007897 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007898 {
7899 int i;
7900
7901 /* return list with matched string and submatches */
7902 for (i = 0; i < NSUBEXP; ++i)
7903 {
7904 if (regmatch.endp[i] == NULL)
7905 {
7906 if (list_append_string(rettv->vval.v_list,
7907 (char_u *)"", 0) == FAIL)
7908 break;
7909 }
7910 else if (list_append_string(rettv->vval.v_list,
7911 regmatch.startp[i],
7912 (int)(regmatch.endp[i] - regmatch.startp[i]))
7913 == FAIL)
7914 break;
7915 }
7916 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007917 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918 {
7919 /* return matched string */
7920 if (l != NULL)
7921 copy_tv(&li->li_tv, rettv);
7922 else
7923 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7924 (int)(regmatch.endp[0] - regmatch.startp[0]));
7925 }
7926 else if (l != NULL)
7927 rettv->vval.v_number = idx;
7928 else
7929 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007930 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931 rettv->vval.v_number =
7932 (varnumber_T)(regmatch.startp[0] - str);
7933 else
7934 rettv->vval.v_number =
7935 (varnumber_T)(regmatch.endp[0] - str);
7936 rettv->vval.v_number += (varnumber_T)(str - expr);
7937 }
7938 }
7939 vim_regfree(regmatch.regprog);
7940 }
7941
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007942theend:
7943 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007944 /* matchstrpos() without a list: drop the second item. */
7945 listitem_remove(rettv->vval.v_list,
7946 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007947 vim_free(tofree);
7948 p_cpo = save_cpo;
7949}
7950
7951/*
7952 * "match()" function
7953 */
7954 static void
7955f_match(typval_T *argvars, typval_T *rettv)
7956{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007957 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007958}
7959
Bram Moolenaar95e51472018-07-28 16:55:56 +02007960#ifdef FEAT_SEARCH_EXTRA
7961 static int
7962matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
7963{
7964 dictitem_T *di;
7965
7966 if (tv->v_type != VAR_DICT)
7967 {
7968 EMSG(_(e_dictreq));
7969 return FAIL;
7970 }
7971
7972 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
7973 *conceal_char = get_dict_string(tv->vval.v_dict,
7974 (char_u *)"conceal", FALSE);
7975
7976 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
7977 {
7978 *win = find_win_by_nr(&di->di_tv, NULL);
7979 if (*win == NULL)
7980 {
7981 EMSG(_("E957: Invalid window number"));
7982 return FAIL;
7983 }
7984 }
7985
7986 return OK;
7987}
7988#endif
7989
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007990/*
7991 * "matchadd()" function
7992 */
7993 static void
7994f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7995{
7996#ifdef FEAT_SEARCH_EXTRA
7997 char_u buf[NUMBUFLEN];
7998 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7999 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
8000 int prio = 10; /* default priority */
8001 int id = -1;
8002 int error = FALSE;
8003 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008004 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008005
8006 rettv->vval.v_number = -1;
8007
8008 if (grp == NULL || pat == NULL)
8009 return;
8010 if (argvars[2].v_type != VAR_UNKNOWN)
8011 {
8012 prio = (int)get_tv_number_chk(&argvars[2], &error);
8013 if (argvars[3].v_type != VAR_UNKNOWN)
8014 {
8015 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008016 if (argvars[4].v_type != VAR_UNKNOWN
8017 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8018 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019 }
8020 }
8021 if (error == TRUE)
8022 return;
8023 if (id >= 1 && id <= 3)
8024 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008025 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008026 return;
8027 }
8028
Bram Moolenaar95e51472018-07-28 16:55:56 +02008029 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030 conceal_char);
8031#endif
8032}
8033
8034/*
8035 * "matchaddpos()" function
8036 */
8037 static void
8038f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8039{
8040#ifdef FEAT_SEARCH_EXTRA
8041 char_u buf[NUMBUFLEN];
8042 char_u *group;
8043 int prio = 10;
8044 int id = -1;
8045 int error = FALSE;
8046 list_T *l;
8047 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008048 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008049
8050 rettv->vval.v_number = -1;
8051
8052 group = get_tv_string_buf_chk(&argvars[0], buf);
8053 if (group == NULL)
8054 return;
8055
8056 if (argvars[1].v_type != VAR_LIST)
8057 {
8058 EMSG2(_(e_listarg), "matchaddpos()");
8059 return;
8060 }
8061 l = argvars[1].vval.v_list;
8062 if (l == NULL)
8063 return;
8064
8065 if (argvars[2].v_type != VAR_UNKNOWN)
8066 {
8067 prio = (int)get_tv_number_chk(&argvars[2], &error);
8068 if (argvars[3].v_type != VAR_UNKNOWN)
8069 {
8070 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008071
8072 if (argvars[4].v_type != VAR_UNKNOWN
8073 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8074 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008075 }
8076 }
8077 if (error == TRUE)
8078 return;
8079
8080 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8081 if (id == 1 || id == 2)
8082 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008083 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084 return;
8085 }
8086
Bram Moolenaar95e51472018-07-28 16:55:56 +02008087 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008088 conceal_char);
8089#endif
8090}
8091
8092/*
8093 * "matcharg()" function
8094 */
8095 static void
8096f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8097{
8098 if (rettv_list_alloc(rettv) == OK)
8099 {
8100#ifdef FEAT_SEARCH_EXTRA
8101 int id = (int)get_tv_number(&argvars[0]);
8102 matchitem_T *m;
8103
8104 if (id >= 1 && id <= 3)
8105 {
8106 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8107 {
8108 list_append_string(rettv->vval.v_list,
8109 syn_id2name(m->hlg_id), -1);
8110 list_append_string(rettv->vval.v_list, m->pattern, -1);
8111 }
8112 else
8113 {
8114 list_append_string(rettv->vval.v_list, NULL, -1);
8115 list_append_string(rettv->vval.v_list, NULL, -1);
8116 }
8117 }
8118#endif
8119 }
8120}
8121
8122/*
8123 * "matchdelete()" function
8124 */
8125 static void
8126f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8127{
8128#ifdef FEAT_SEARCH_EXTRA
8129 rettv->vval.v_number = match_delete(curwin,
8130 (int)get_tv_number(&argvars[0]), TRUE);
8131#endif
8132}
8133
8134/*
8135 * "matchend()" function
8136 */
8137 static void
8138f_matchend(typval_T *argvars, typval_T *rettv)
8139{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008140 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141}
8142
8143/*
8144 * "matchlist()" function
8145 */
8146 static void
8147f_matchlist(typval_T *argvars, typval_T *rettv)
8148{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008149 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150}
8151
8152/*
8153 * "matchstr()" function
8154 */
8155 static void
8156f_matchstr(typval_T *argvars, typval_T *rettv)
8157{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008158 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159}
8160
8161/*
8162 * "matchstrpos()" function
8163 */
8164 static void
8165f_matchstrpos(typval_T *argvars, typval_T *rettv)
8166{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008167 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008168}
8169
8170static void max_min(typval_T *argvars, typval_T *rettv, int domax);
8171
8172 static void
8173max_min(typval_T *argvars, typval_T *rettv, int domax)
8174{
8175 varnumber_T n = 0;
8176 varnumber_T i;
8177 int error = FALSE;
8178
8179 if (argvars[0].v_type == VAR_LIST)
8180 {
8181 list_T *l;
8182 listitem_T *li;
8183
8184 l = argvars[0].vval.v_list;
8185 if (l != NULL)
8186 {
8187 li = l->lv_first;
8188 if (li != NULL)
8189 {
8190 n = get_tv_number_chk(&li->li_tv, &error);
8191 for (;;)
8192 {
8193 li = li->li_next;
8194 if (li == NULL)
8195 break;
8196 i = get_tv_number_chk(&li->li_tv, &error);
8197 if (domax ? i > n : i < n)
8198 n = i;
8199 }
8200 }
8201 }
8202 }
8203 else if (argvars[0].v_type == VAR_DICT)
8204 {
8205 dict_T *d;
8206 int first = TRUE;
8207 hashitem_T *hi;
8208 int todo;
8209
8210 d = argvars[0].vval.v_dict;
8211 if (d != NULL)
8212 {
8213 todo = (int)d->dv_hashtab.ht_used;
8214 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8215 {
8216 if (!HASHITEM_EMPTY(hi))
8217 {
8218 --todo;
8219 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8220 if (first)
8221 {
8222 n = i;
8223 first = FALSE;
8224 }
8225 else if (domax ? i > n : i < n)
8226 n = i;
8227 }
8228 }
8229 }
8230 }
8231 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008232 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008233 rettv->vval.v_number = error ? 0 : n;
8234}
8235
8236/*
8237 * "max()" function
8238 */
8239 static void
8240f_max(typval_T *argvars, typval_T *rettv)
8241{
8242 max_min(argvars, rettv, TRUE);
8243}
8244
8245/*
8246 * "min()" function
8247 */
8248 static void
8249f_min(typval_T *argvars, typval_T *rettv)
8250{
8251 max_min(argvars, rettv, FALSE);
8252}
8253
8254static int mkdir_recurse(char_u *dir, int prot);
8255
8256/*
8257 * Create the directory in which "dir" is located, and higher levels when
8258 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008259 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008260 */
8261 static int
8262mkdir_recurse(char_u *dir, int prot)
8263{
8264 char_u *p;
8265 char_u *updir;
8266 int r = FAIL;
8267
8268 /* Get end of directory name in "dir".
8269 * We're done when it's "/" or "c:/". */
8270 p = gettail_sep(dir);
8271 if (p <= get_past_head(dir))
8272 return OK;
8273
8274 /* If the directory exists we're done. Otherwise: create it.*/
8275 updir = vim_strnsave(dir, (int)(p - dir));
8276 if (updir == NULL)
8277 return FAIL;
8278 if (mch_isdir(updir))
8279 r = OK;
8280 else if (mkdir_recurse(updir, prot) == OK)
8281 r = vim_mkdir_emsg(updir, prot);
8282 vim_free(updir);
8283 return r;
8284}
8285
8286#ifdef vim_mkdir
8287/*
8288 * "mkdir()" function
8289 */
8290 static void
8291f_mkdir(typval_T *argvars, typval_T *rettv)
8292{
8293 char_u *dir;
8294 char_u buf[NUMBUFLEN];
8295 int prot = 0755;
8296
8297 rettv->vval.v_number = FAIL;
8298 if (check_restricted() || check_secure())
8299 return;
8300
8301 dir = get_tv_string_buf(&argvars[0], buf);
8302 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008303 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008305 if (*gettail(dir) == NUL)
8306 /* remove trailing slashes */
8307 *gettail_sep(dir) = NUL;
8308
8309 if (argvars[1].v_type != VAR_UNKNOWN)
8310 {
8311 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008312 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008313 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8314 if (prot == -1)
8315 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008317 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8318 {
8319 if (mch_isdir(dir))
8320 {
8321 /* With the "p" flag it's OK if the dir already exists. */
8322 rettv->vval.v_number = OK;
8323 return;
8324 }
8325 mkdir_recurse(dir, prot);
8326 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008327 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008328 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329}
8330#endif
8331
8332/*
8333 * "mode()" function
8334 */
8335 static void
8336f_mode(typval_T *argvars, typval_T *rettv)
8337{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008338 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339
Bram Moolenaar612cc382018-07-29 15:34:26 +02008340 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008341
8342 if (time_for_testing == 93784)
8343 {
8344 /* Testing the two-character code. */
8345 buf[0] = 'x';
8346 buf[1] = '!';
8347 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008348#ifdef FEAT_TERMINAL
8349 else if (term_use_loop())
8350 buf[0] = 't';
8351#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008352 else if (VIsual_active)
8353 {
8354 if (VIsual_select)
8355 buf[0] = VIsual_mode + 's' - 'v';
8356 else
8357 buf[0] = VIsual_mode;
8358 }
8359 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8360 || State == CONFIRM)
8361 {
8362 buf[0] = 'r';
8363 if (State == ASKMORE)
8364 buf[1] = 'm';
8365 else if (State == CONFIRM)
8366 buf[1] = '?';
8367 }
8368 else if (State == EXTERNCMD)
8369 buf[0] = '!';
8370 else if (State & INSERT)
8371 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008372 if (State & VREPLACE_FLAG)
8373 {
8374 buf[0] = 'R';
8375 buf[1] = 'v';
8376 }
8377 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008378 {
8379 if (State & REPLACE_FLAG)
8380 buf[0] = 'R';
8381 else
8382 buf[0] = 'i';
8383#ifdef FEAT_INS_EXPAND
8384 if (ins_compl_active())
8385 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008386 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008387 buf[1] = 'x';
8388#endif
8389 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008391 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008392 {
8393 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008394 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008395 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008396 else if (exmode_active == EXMODE_NORMAL)
8397 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398 }
8399 else
8400 {
8401 buf[0] = 'n';
8402 if (finish_op)
8403 buf[1] = 'o';
Bram Moolenaar612cc382018-07-29 15:34:26 +02008404 else if (restart_edit == 'I' || restart_edit == 'R'
8405 || restart_edit == 'V')
8406 {
8407 buf[1] = 'i';
8408 buf[2] = restart_edit;
8409 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008410 }
8411
8412 /* Clear out the minor mode when the argument is not a non-zero number or
8413 * non-empty string. */
8414 if (!non_zero_arg(&argvars[0]))
8415 buf[1] = NUL;
8416
8417 rettv->vval.v_string = vim_strsave(buf);
8418 rettv->v_type = VAR_STRING;
8419}
8420
8421#if defined(FEAT_MZSCHEME) || defined(PROTO)
8422/*
8423 * "mzeval()" function
8424 */
8425 static void
8426f_mzeval(typval_T *argvars, typval_T *rettv)
8427{
8428 char_u *str;
8429 char_u buf[NUMBUFLEN];
8430
8431 str = get_tv_string_buf(&argvars[0], buf);
8432 do_mzeval(str, rettv);
8433}
8434
8435 void
8436mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8437{
8438 typval_T argvars[3];
8439
8440 argvars[0].v_type = VAR_STRING;
8441 argvars[0].vval.v_string = name;
8442 copy_tv(args, &argvars[1]);
8443 argvars[2].v_type = VAR_UNKNOWN;
8444 f_call(argvars, rettv);
8445 clear_tv(&argvars[1]);
8446}
8447#endif
8448
8449/*
8450 * "nextnonblank()" function
8451 */
8452 static void
8453f_nextnonblank(typval_T *argvars, typval_T *rettv)
8454{
8455 linenr_T lnum;
8456
8457 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8458 {
8459 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8460 {
8461 lnum = 0;
8462 break;
8463 }
8464 if (*skipwhite(ml_get(lnum)) != NUL)
8465 break;
8466 }
8467 rettv->vval.v_number = lnum;
8468}
8469
8470/*
8471 * "nr2char()" function
8472 */
8473 static void
8474f_nr2char(typval_T *argvars, typval_T *rettv)
8475{
8476 char_u buf[NUMBUFLEN];
8477
8478#ifdef FEAT_MBYTE
8479 if (has_mbyte)
8480 {
8481 int utf8 = 0;
8482
8483 if (argvars[1].v_type != VAR_UNKNOWN)
8484 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8485 if (utf8)
8486 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8487 else
8488 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8489 }
8490 else
8491#endif
8492 {
8493 buf[0] = (char_u)get_tv_number(&argvars[0]);
8494 buf[1] = NUL;
8495 }
8496 rettv->v_type = VAR_STRING;
8497 rettv->vval.v_string = vim_strsave(buf);
8498}
8499
8500/*
8501 * "or(expr, expr)" function
8502 */
8503 static void
8504f_or(typval_T *argvars, typval_T *rettv)
8505{
8506 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8507 | get_tv_number_chk(&argvars[1], NULL);
8508}
8509
8510/*
8511 * "pathshorten()" function
8512 */
8513 static void
8514f_pathshorten(typval_T *argvars, typval_T *rettv)
8515{
8516 char_u *p;
8517
8518 rettv->v_type = VAR_STRING;
8519 p = get_tv_string_chk(&argvars[0]);
8520 if (p == NULL)
8521 rettv->vval.v_string = NULL;
8522 else
8523 {
8524 p = vim_strsave(p);
8525 rettv->vval.v_string = p;
8526 if (p != NULL)
8527 shorten_dir(p);
8528 }
8529}
8530
8531#ifdef FEAT_PERL
8532/*
8533 * "perleval()" function
8534 */
8535 static void
8536f_perleval(typval_T *argvars, typval_T *rettv)
8537{
8538 char_u *str;
8539 char_u buf[NUMBUFLEN];
8540
8541 str = get_tv_string_buf(&argvars[0], buf);
8542 do_perleval(str, rettv);
8543}
8544#endif
8545
8546#ifdef FEAT_FLOAT
8547/*
8548 * "pow()" function
8549 */
8550 static void
8551f_pow(typval_T *argvars, typval_T *rettv)
8552{
8553 float_T fx = 0.0, fy = 0.0;
8554
8555 rettv->v_type = VAR_FLOAT;
8556 if (get_float_arg(argvars, &fx) == OK
8557 && get_float_arg(&argvars[1], &fy) == OK)
8558 rettv->vval.v_float = pow(fx, fy);
8559 else
8560 rettv->vval.v_float = 0.0;
8561}
8562#endif
8563
8564/*
8565 * "prevnonblank()" function
8566 */
8567 static void
8568f_prevnonblank(typval_T *argvars, typval_T *rettv)
8569{
8570 linenr_T lnum;
8571
8572 lnum = get_tv_lnum(argvars);
8573 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8574 lnum = 0;
8575 else
8576 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8577 --lnum;
8578 rettv->vval.v_number = lnum;
8579}
8580
8581/* This dummy va_list is here because:
8582 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8583 * - locally in the function results in a "used before set" warning
8584 * - using va_start() to initialize it gives "function with fixed args" error */
8585static va_list ap;
8586
8587/*
8588 * "printf()" function
8589 */
8590 static void
8591f_printf(typval_T *argvars, typval_T *rettv)
8592{
8593 char_u buf[NUMBUFLEN];
8594 int len;
8595 char_u *s;
8596 int saved_did_emsg = did_emsg;
8597 char *fmt;
8598
8599 rettv->v_type = VAR_STRING;
8600 rettv->vval.v_string = NULL;
8601
8602 /* Get the required length, allocate the buffer and do it for real. */
8603 did_emsg = FALSE;
8604 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008605 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008606 if (!did_emsg)
8607 {
8608 s = alloc(len + 1);
8609 if (s != NULL)
8610 {
8611 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008612 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8613 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008614 }
8615 }
8616 did_emsg |= saved_did_emsg;
8617}
8618
Bram Moolenaarf2732452018-06-03 14:47:35 +02008619#ifdef FEAT_JOB_CHANNEL
8620/*
8621 * "prompt_setcallback({buffer}, {callback})" function
8622 */
8623 static void
8624f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8625{
8626 buf_T *buf;
8627 char_u *callback;
8628 partial_T *partial;
8629
8630 if (check_secure())
8631 return;
8632 buf = get_buf_tv(&argvars[0], FALSE);
8633 if (buf == NULL)
8634 return;
8635
8636 callback = get_callback(&argvars[1], &partial);
8637 if (callback == NULL)
8638 return;
8639
8640 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8641 if (partial == NULL)
8642 buf->b_prompt_callback = vim_strsave(callback);
8643 else
8644 /* pointer into the partial */
8645 buf->b_prompt_callback = callback;
8646 buf->b_prompt_partial = partial;
8647}
8648
8649/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008650 * "prompt_setinterrupt({buffer}, {callback})" function
8651 */
8652 static void
8653f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8654{
8655 buf_T *buf;
8656 char_u *callback;
8657 partial_T *partial;
8658
8659 if (check_secure())
8660 return;
8661 buf = get_buf_tv(&argvars[0], FALSE);
8662 if (buf == NULL)
8663 return;
8664
8665 callback = get_callback(&argvars[1], &partial);
8666 if (callback == NULL)
8667 return;
8668
8669 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8670 if (partial == NULL)
8671 buf->b_prompt_interrupt = vim_strsave(callback);
8672 else
8673 /* pointer into the partial */
8674 buf->b_prompt_interrupt = callback;
8675 buf->b_prompt_int_partial = partial;
8676}
8677
8678/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008679 * "prompt_setprompt({buffer}, {text})" function
8680 */
8681 static void
8682f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8683{
8684 buf_T *buf;
8685 char_u *text;
8686
8687 if (check_secure())
8688 return;
8689 buf = get_buf_tv(&argvars[0], FALSE);
8690 if (buf == NULL)
8691 return;
8692
8693 text = get_tv_string(&argvars[1]);
8694 vim_free(buf->b_prompt_text);
8695 buf->b_prompt_text = vim_strsave(text);
8696}
8697#endif
8698
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008699/*
8700 * "pumvisible()" function
8701 */
8702 static void
8703f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8704{
8705#ifdef FEAT_INS_EXPAND
8706 if (pum_visible())
8707 rettv->vval.v_number = 1;
8708#endif
8709}
8710
8711#ifdef FEAT_PYTHON3
8712/*
8713 * "py3eval()" function
8714 */
8715 static void
8716f_py3eval(typval_T *argvars, typval_T *rettv)
8717{
8718 char_u *str;
8719 char_u buf[NUMBUFLEN];
8720
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008721 if (p_pyx == 0)
8722 p_pyx = 3;
8723
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724 str = get_tv_string_buf(&argvars[0], buf);
8725 do_py3eval(str, rettv);
8726}
8727#endif
8728
8729#ifdef FEAT_PYTHON
8730/*
8731 * "pyeval()" function
8732 */
8733 static void
8734f_pyeval(typval_T *argvars, typval_T *rettv)
8735{
8736 char_u *str;
8737 char_u buf[NUMBUFLEN];
8738
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008739 if (p_pyx == 0)
8740 p_pyx = 2;
8741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008742 str = get_tv_string_buf(&argvars[0], buf);
8743 do_pyeval(str, rettv);
8744}
8745#endif
8746
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008747#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8748/*
8749 * "pyxeval()" function
8750 */
8751 static void
8752f_pyxeval(typval_T *argvars, typval_T *rettv)
8753{
8754# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8755 init_pyxversion();
8756 if (p_pyx == 2)
8757 f_pyeval(argvars, rettv);
8758 else
8759 f_py3eval(argvars, rettv);
8760# elif defined(FEAT_PYTHON)
8761 f_pyeval(argvars, rettv);
8762# elif defined(FEAT_PYTHON3)
8763 f_py3eval(argvars, rettv);
8764# endif
8765}
8766#endif
8767
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008768/*
8769 * "range()" function
8770 */
8771 static void
8772f_range(typval_T *argvars, typval_T *rettv)
8773{
8774 varnumber_T start;
8775 varnumber_T end;
8776 varnumber_T stride = 1;
8777 varnumber_T i;
8778 int error = FALSE;
8779
8780 start = get_tv_number_chk(&argvars[0], &error);
8781 if (argvars[1].v_type == VAR_UNKNOWN)
8782 {
8783 end = start - 1;
8784 start = 0;
8785 }
8786 else
8787 {
8788 end = get_tv_number_chk(&argvars[1], &error);
8789 if (argvars[2].v_type != VAR_UNKNOWN)
8790 stride = get_tv_number_chk(&argvars[2], &error);
8791 }
8792
8793 if (error)
8794 return; /* type error; errmsg already given */
8795 if (stride == 0)
8796 EMSG(_("E726: Stride is zero"));
8797 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8798 EMSG(_("E727: Start past end"));
8799 else
8800 {
8801 if (rettv_list_alloc(rettv) == OK)
8802 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8803 if (list_append_number(rettv->vval.v_list,
8804 (varnumber_T)i) == FAIL)
8805 break;
8806 }
8807}
8808
8809/*
8810 * "readfile()" function
8811 */
8812 static void
8813f_readfile(typval_T *argvars, typval_T *rettv)
8814{
8815 int binary = FALSE;
8816 int failed = FALSE;
8817 char_u *fname;
8818 FILE *fd;
8819 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8820 int io_size = sizeof(buf);
8821 int readlen; /* size of last fread() */
8822 char_u *prev = NULL; /* previously read bytes, if any */
8823 long prevlen = 0; /* length of data in prev */
8824 long prevsize = 0; /* size of prev buffer */
8825 long maxline = MAXLNUM;
8826 long cnt = 0;
8827 char_u *p; /* position in buf */
8828 char_u *start; /* start of current line */
8829
8830 if (argvars[1].v_type != VAR_UNKNOWN)
8831 {
8832 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8833 binary = TRUE;
8834 if (argvars[2].v_type != VAR_UNKNOWN)
8835 maxline = (long)get_tv_number(&argvars[2]);
8836 }
8837
8838 if (rettv_list_alloc(rettv) == FAIL)
8839 return;
8840
8841 /* Always open the file in binary mode, library functions have a mind of
8842 * their own about CR-LF conversion. */
8843 fname = get_tv_string(&argvars[0]);
8844 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8845 {
8846 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8847 return;
8848 }
8849
8850 while (cnt < maxline || maxline < 0)
8851 {
8852 readlen = (int)fread(buf, 1, io_size, fd);
8853
8854 /* This for loop processes what was read, but is also entered at end
8855 * of file so that either:
8856 * - an incomplete line gets written
8857 * - a "binary" file gets an empty line at the end if it ends in a
8858 * newline. */
8859 for (p = buf, start = buf;
8860 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8861 ++p)
8862 {
8863 if (*p == '\n' || readlen <= 0)
8864 {
8865 listitem_T *li;
8866 char_u *s = NULL;
8867 long_u len = p - start;
8868
8869 /* Finished a line. Remove CRs before NL. */
8870 if (readlen > 0 && !binary)
8871 {
8872 while (len > 0 && start[len - 1] == '\r')
8873 --len;
8874 /* removal may cross back to the "prev" string */
8875 if (len == 0)
8876 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8877 --prevlen;
8878 }
8879 if (prevlen == 0)
8880 s = vim_strnsave(start, (int)len);
8881 else
8882 {
8883 /* Change "prev" buffer to be the right size. This way
8884 * the bytes are only copied once, and very long lines are
8885 * allocated only once. */
8886 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8887 {
8888 mch_memmove(s + prevlen, start, len);
8889 s[prevlen + len] = NUL;
8890 prev = NULL; /* the list will own the string */
8891 prevlen = prevsize = 0;
8892 }
8893 }
8894 if (s == NULL)
8895 {
8896 do_outofmem_msg((long_u) prevlen + len + 1);
8897 failed = TRUE;
8898 break;
8899 }
8900
8901 if ((li = listitem_alloc()) == NULL)
8902 {
8903 vim_free(s);
8904 failed = TRUE;
8905 break;
8906 }
8907 li->li_tv.v_type = VAR_STRING;
8908 li->li_tv.v_lock = 0;
8909 li->li_tv.vval.v_string = s;
8910 list_append(rettv->vval.v_list, li);
8911
8912 start = p + 1; /* step over newline */
8913 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8914 break;
8915 }
8916 else if (*p == NUL)
8917 *p = '\n';
8918#ifdef FEAT_MBYTE
8919 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8920 * when finding the BF and check the previous two bytes. */
8921 else if (*p == 0xbf && enc_utf8 && !binary)
8922 {
8923 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8924 * + 1, these may be in the "prev" string. */
8925 char_u back1 = p >= buf + 1 ? p[-1]
8926 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8927 char_u back2 = p >= buf + 2 ? p[-2]
8928 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8929 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8930
8931 if (back2 == 0xef && back1 == 0xbb)
8932 {
8933 char_u *dest = p - 2;
8934
8935 /* Usually a BOM is at the beginning of a file, and so at
8936 * the beginning of a line; then we can just step over it.
8937 */
8938 if (start == dest)
8939 start = p + 1;
8940 else
8941 {
8942 /* have to shuffle buf to close gap */
8943 int adjust_prevlen = 0;
8944
8945 if (dest < buf)
8946 {
8947 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8948 dest = buf;
8949 }
8950 if (readlen > p - buf + 1)
8951 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8952 readlen -= 3 - adjust_prevlen;
8953 prevlen -= adjust_prevlen;
8954 p = dest - 1;
8955 }
8956 }
8957 }
8958#endif
8959 } /* for */
8960
8961 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8962 break;
8963 if (start < p)
8964 {
8965 /* There's part of a line in buf, store it in "prev". */
8966 if (p - start + prevlen >= prevsize)
8967 {
8968 /* need bigger "prev" buffer */
8969 char_u *newprev;
8970
8971 /* A common use case is ordinary text files and "prev" gets a
8972 * fragment of a line, so the first allocation is made
8973 * small, to avoid repeatedly 'allocing' large and
8974 * 'reallocing' small. */
8975 if (prevsize == 0)
8976 prevsize = (long)(p - start);
8977 else
8978 {
8979 long grow50pc = (prevsize * 3) / 2;
8980 long growmin = (long)((p - start) * 2 + prevlen);
8981 prevsize = grow50pc > growmin ? grow50pc : growmin;
8982 }
8983 newprev = prev == NULL ? alloc(prevsize)
8984 : vim_realloc(prev, prevsize);
8985 if (newprev == NULL)
8986 {
8987 do_outofmem_msg((long_u)prevsize);
8988 failed = TRUE;
8989 break;
8990 }
8991 prev = newprev;
8992 }
8993 /* Add the line part to end of "prev". */
8994 mch_memmove(prev + prevlen, start, p - start);
8995 prevlen += (long)(p - start);
8996 }
8997 } /* while */
8998
8999 /*
9000 * For a negative line count use only the lines at the end of the file,
9001 * free the rest.
9002 */
9003 if (!failed && maxline < 0)
9004 while (cnt > -maxline)
9005 {
9006 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9007 --cnt;
9008 }
9009
9010 if (failed)
9011 {
9012 list_free(rettv->vval.v_list);
9013 /* readfile doc says an empty list is returned on error */
9014 rettv->vval.v_list = list_alloc();
9015 }
9016
9017 vim_free(prev);
9018 fclose(fd);
9019}
9020
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009021 static void
9022return_register(int regname, typval_T *rettv)
9023{
9024 char_u buf[2] = {0, 0};
9025
9026 buf[0] = (char_u)regname;
9027 rettv->v_type = VAR_STRING;
9028 rettv->vval.v_string = vim_strsave(buf);
9029}
9030
9031/*
9032 * "reg_executing()" function
9033 */
9034 static void
9035f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9036{
9037 return_register(reg_executing, rettv);
9038}
9039
9040/*
9041 * "reg_recording()" function
9042 */
9043 static void
9044f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9045{
9046 return_register(reg_recording, rettv);
9047}
9048
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009049#if defined(FEAT_RELTIME)
9050static int list2proftime(typval_T *arg, proftime_T *tm);
9051
9052/*
9053 * Convert a List to proftime_T.
9054 * Return FAIL when there is something wrong.
9055 */
9056 static int
9057list2proftime(typval_T *arg, proftime_T *tm)
9058{
9059 long n1, n2;
9060 int error = FALSE;
9061
9062 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9063 || arg->vval.v_list->lv_len != 2)
9064 return FAIL;
9065 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9066 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9067# ifdef WIN3264
9068 tm->HighPart = n1;
9069 tm->LowPart = n2;
9070# else
9071 tm->tv_sec = n1;
9072 tm->tv_usec = n2;
9073# endif
9074 return error ? FAIL : OK;
9075}
9076#endif /* FEAT_RELTIME */
9077
9078/*
9079 * "reltime()" function
9080 */
9081 static void
9082f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9083{
9084#ifdef FEAT_RELTIME
9085 proftime_T res;
9086 proftime_T start;
9087
9088 if (argvars[0].v_type == VAR_UNKNOWN)
9089 {
9090 /* No arguments: get current time. */
9091 profile_start(&res);
9092 }
9093 else if (argvars[1].v_type == VAR_UNKNOWN)
9094 {
9095 if (list2proftime(&argvars[0], &res) == FAIL)
9096 return;
9097 profile_end(&res);
9098 }
9099 else
9100 {
9101 /* Two arguments: compute the difference. */
9102 if (list2proftime(&argvars[0], &start) == FAIL
9103 || list2proftime(&argvars[1], &res) == FAIL)
9104 return;
9105 profile_sub(&res, &start);
9106 }
9107
9108 if (rettv_list_alloc(rettv) == OK)
9109 {
9110 long n1, n2;
9111
9112# ifdef WIN3264
9113 n1 = res.HighPart;
9114 n2 = res.LowPart;
9115# else
9116 n1 = res.tv_sec;
9117 n2 = res.tv_usec;
9118# endif
9119 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9120 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9121 }
9122#endif
9123}
9124
9125#ifdef FEAT_FLOAT
9126/*
9127 * "reltimefloat()" function
9128 */
9129 static void
9130f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9131{
9132# ifdef FEAT_RELTIME
9133 proftime_T tm;
9134# endif
9135
9136 rettv->v_type = VAR_FLOAT;
9137 rettv->vval.v_float = 0;
9138# ifdef FEAT_RELTIME
9139 if (list2proftime(&argvars[0], &tm) == OK)
9140 rettv->vval.v_float = profile_float(&tm);
9141# endif
9142}
9143#endif
9144
9145/*
9146 * "reltimestr()" function
9147 */
9148 static void
9149f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9150{
9151#ifdef FEAT_RELTIME
9152 proftime_T tm;
9153#endif
9154
9155 rettv->v_type = VAR_STRING;
9156 rettv->vval.v_string = NULL;
9157#ifdef FEAT_RELTIME
9158 if (list2proftime(&argvars[0], &tm) == OK)
9159 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9160#endif
9161}
9162
9163#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9164static void make_connection(void);
9165static int check_connection(void);
9166
9167 static void
9168make_connection(void)
9169{
9170 if (X_DISPLAY == NULL
9171# ifdef FEAT_GUI
9172 && !gui.in_use
9173# endif
9174 )
9175 {
9176 x_force_connect = TRUE;
9177 setup_term_clip();
9178 x_force_connect = FALSE;
9179 }
9180}
9181
9182 static int
9183check_connection(void)
9184{
9185 make_connection();
9186 if (X_DISPLAY == NULL)
9187 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009188 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009189 return FAIL;
9190 }
9191 return OK;
9192}
9193#endif
9194
9195#ifdef FEAT_CLIENTSERVER
9196 static void
9197remote_common(typval_T *argvars, typval_T *rettv, int expr)
9198{
9199 char_u *server_name;
9200 char_u *keys;
9201 char_u *r = NULL;
9202 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009203 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009204# ifdef WIN32
9205 HWND w;
9206# else
9207 Window w;
9208# endif
9209
9210 if (check_restricted() || check_secure())
9211 return;
9212
9213# ifdef FEAT_X11
9214 if (check_connection() == FAIL)
9215 return;
9216# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009217 if (argvars[2].v_type != VAR_UNKNOWN
9218 && argvars[3].v_type != VAR_UNKNOWN)
9219 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009220
9221 server_name = get_tv_string_chk(&argvars[0]);
9222 if (server_name == NULL)
9223 return; /* type error; errmsg already given */
9224 keys = get_tv_string_buf(&argvars[1], buf);
9225# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009226 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009227# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009228 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9229 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009230# endif
9231 {
9232 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009233 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009234 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009235 vim_free(r);
9236 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009237 else
9238 EMSG2(_("E241: Unable to send to %s"), server_name);
9239 return;
9240 }
9241
9242 rettv->vval.v_string = r;
9243
9244 if (argvars[2].v_type != VAR_UNKNOWN)
9245 {
9246 dictitem_T v;
9247 char_u str[30];
9248 char_u *idvar;
9249
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009250 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009251 if (idvar != NULL && *idvar != NUL)
9252 {
9253 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9254 v.di_tv.v_type = VAR_STRING;
9255 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009256 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009257 vim_free(v.di_tv.vval.v_string);
9258 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009259 }
9260}
9261#endif
9262
9263/*
9264 * "remote_expr()" function
9265 */
9266 static void
9267f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9268{
9269 rettv->v_type = VAR_STRING;
9270 rettv->vval.v_string = NULL;
9271#ifdef FEAT_CLIENTSERVER
9272 remote_common(argvars, rettv, TRUE);
9273#endif
9274}
9275
9276/*
9277 * "remote_foreground()" function
9278 */
9279 static void
9280f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9281{
9282#ifdef FEAT_CLIENTSERVER
9283# ifdef WIN32
9284 /* On Win32 it's done in this application. */
9285 {
9286 char_u *server_name = get_tv_string_chk(&argvars[0]);
9287
9288 if (server_name != NULL)
9289 serverForeground(server_name);
9290 }
9291# else
9292 /* Send a foreground() expression to the server. */
9293 argvars[1].v_type = VAR_STRING;
9294 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9295 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009296 rettv->v_type = VAR_STRING;
9297 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009298 remote_common(argvars, rettv, TRUE);
9299 vim_free(argvars[1].vval.v_string);
9300# endif
9301#endif
9302}
9303
9304 static void
9305f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9306{
9307#ifdef FEAT_CLIENTSERVER
9308 dictitem_T v;
9309 char_u *s = NULL;
9310# ifdef WIN32
9311 long_u n = 0;
9312# endif
9313 char_u *serverid;
9314
9315 if (check_restricted() || check_secure())
9316 {
9317 rettv->vval.v_number = -1;
9318 return;
9319 }
9320 serverid = get_tv_string_chk(&argvars[0]);
9321 if (serverid == NULL)
9322 {
9323 rettv->vval.v_number = -1;
9324 return; /* type error; errmsg already given */
9325 }
9326# ifdef WIN32
9327 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9328 if (n == 0)
9329 rettv->vval.v_number = -1;
9330 else
9331 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009332 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333 rettv->vval.v_number = (s != NULL);
9334 }
9335# else
9336 if (check_connection() == FAIL)
9337 return;
9338
9339 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9340 serverStrToWin(serverid), &s);
9341# endif
9342
9343 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9344 {
9345 char_u *retvar;
9346
9347 v.di_tv.v_type = VAR_STRING;
9348 v.di_tv.vval.v_string = vim_strsave(s);
9349 retvar = get_tv_string_chk(&argvars[1]);
9350 if (retvar != NULL)
9351 set_var(retvar, &v.di_tv, FALSE);
9352 vim_free(v.di_tv.vval.v_string);
9353 }
9354#else
9355 rettv->vval.v_number = -1;
9356#endif
9357}
9358
9359 static void
9360f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9361{
9362 char_u *r = NULL;
9363
9364#ifdef FEAT_CLIENTSERVER
9365 char_u *serverid = get_tv_string_chk(&argvars[0]);
9366
9367 if (serverid != NULL && !check_restricted() && !check_secure())
9368 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009369 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009370# ifdef WIN32
9371 /* The server's HWND is encoded in the 'id' parameter */
9372 long_u n = 0;
9373# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009374
9375 if (argvars[1].v_type != VAR_UNKNOWN)
9376 timeout = get_tv_number(&argvars[1]);
9377
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009378# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009379 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9380 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009381 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009382 if (r == NULL)
9383# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009384 if (check_connection() == FAIL
9385 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9386 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009387# endif
9388 EMSG(_("E277: Unable to read a server reply"));
9389 }
9390#endif
9391 rettv->v_type = VAR_STRING;
9392 rettv->vval.v_string = r;
9393}
9394
9395/*
9396 * "remote_send()" function
9397 */
9398 static void
9399f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9400{
9401 rettv->v_type = VAR_STRING;
9402 rettv->vval.v_string = NULL;
9403#ifdef FEAT_CLIENTSERVER
9404 remote_common(argvars, rettv, FALSE);
9405#endif
9406}
9407
9408/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009409 * "remote_startserver()" function
9410 */
9411 static void
9412f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9413{
9414#ifdef FEAT_CLIENTSERVER
9415 char_u *server = get_tv_string_chk(&argvars[0]);
9416
9417 if (server == NULL)
9418 return; /* type error; errmsg already given */
9419 if (serverName != NULL)
9420 EMSG(_("E941: already started a server"));
9421 else
9422 {
9423# ifdef FEAT_X11
9424 if (check_connection() == OK)
9425 serverRegisterName(X_DISPLAY, server);
9426# else
9427 serverSetName(server);
9428# endif
9429 }
9430#else
9431 EMSG(_("E942: +clientserver feature not available"));
9432#endif
9433}
9434
9435/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009436 * "remove()" function
9437 */
9438 static void
9439f_remove(typval_T *argvars, typval_T *rettv)
9440{
9441 list_T *l;
9442 listitem_T *item, *item2;
9443 listitem_T *li;
9444 long idx;
9445 long end;
9446 char_u *key;
9447 dict_T *d;
9448 dictitem_T *di;
9449 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9450
9451 if (argvars[0].v_type == VAR_DICT)
9452 {
9453 if (argvars[2].v_type != VAR_UNKNOWN)
9454 EMSG2(_(e_toomanyarg), "remove()");
9455 else if ((d = argvars[0].vval.v_dict) != NULL
9456 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9457 {
9458 key = get_tv_string_chk(&argvars[1]);
9459 if (key != NULL)
9460 {
9461 di = dict_find(d, key, -1);
9462 if (di == NULL)
9463 EMSG2(_(e_dictkey), key);
9464 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9465 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9466 {
9467 *rettv = di->di_tv;
9468 init_tv(&di->di_tv);
9469 dictitem_remove(d, di);
9470 }
9471 }
9472 }
9473 }
9474 else if (argvars[0].v_type != VAR_LIST)
9475 EMSG2(_(e_listdictarg), "remove()");
9476 else if ((l = argvars[0].vval.v_list) != NULL
9477 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9478 {
9479 int error = FALSE;
9480
9481 idx = (long)get_tv_number_chk(&argvars[1], &error);
9482 if (error)
9483 ; /* type error: do nothing, errmsg already given */
9484 else if ((item = list_find(l, idx)) == NULL)
9485 EMSGN(_(e_listidx), idx);
9486 else
9487 {
9488 if (argvars[2].v_type == VAR_UNKNOWN)
9489 {
9490 /* Remove one item, return its value. */
9491 vimlist_remove(l, item, item);
9492 *rettv = item->li_tv;
9493 vim_free(item);
9494 }
9495 else
9496 {
9497 /* Remove range of items, return list with values. */
9498 end = (long)get_tv_number_chk(&argvars[2], &error);
9499 if (error)
9500 ; /* type error: do nothing */
9501 else if ((item2 = list_find(l, end)) == NULL)
9502 EMSGN(_(e_listidx), end);
9503 else
9504 {
9505 int cnt = 0;
9506
9507 for (li = item; li != NULL; li = li->li_next)
9508 {
9509 ++cnt;
9510 if (li == item2)
9511 break;
9512 }
9513 if (li == NULL) /* didn't find "item2" after "item" */
9514 EMSG(_(e_invrange));
9515 else
9516 {
9517 vimlist_remove(l, item, item2);
9518 if (rettv_list_alloc(rettv) == OK)
9519 {
9520 l = rettv->vval.v_list;
9521 l->lv_first = item;
9522 l->lv_last = item2;
9523 item->li_prev = NULL;
9524 item2->li_next = NULL;
9525 l->lv_len = cnt;
9526 }
9527 }
9528 }
9529 }
9530 }
9531 }
9532}
9533
9534/*
9535 * "rename({from}, {to})" function
9536 */
9537 static void
9538f_rename(typval_T *argvars, typval_T *rettv)
9539{
9540 char_u buf[NUMBUFLEN];
9541
9542 if (check_restricted() || check_secure())
9543 rettv->vval.v_number = -1;
9544 else
9545 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9546 get_tv_string_buf(&argvars[1], buf));
9547}
9548
9549/*
9550 * "repeat()" function
9551 */
9552 static void
9553f_repeat(typval_T *argvars, typval_T *rettv)
9554{
9555 char_u *p;
9556 int n;
9557 int slen;
9558 int len;
9559 char_u *r;
9560 int i;
9561
9562 n = (int)get_tv_number(&argvars[1]);
9563 if (argvars[0].v_type == VAR_LIST)
9564 {
9565 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9566 while (n-- > 0)
9567 if (list_extend(rettv->vval.v_list,
9568 argvars[0].vval.v_list, NULL) == FAIL)
9569 break;
9570 }
9571 else
9572 {
9573 p = get_tv_string(&argvars[0]);
9574 rettv->v_type = VAR_STRING;
9575 rettv->vval.v_string = NULL;
9576
9577 slen = (int)STRLEN(p);
9578 len = slen * n;
9579 if (len <= 0)
9580 return;
9581
9582 r = alloc(len + 1);
9583 if (r != NULL)
9584 {
9585 for (i = 0; i < n; i++)
9586 mch_memmove(r + i * slen, p, (size_t)slen);
9587 r[len] = NUL;
9588 }
9589
9590 rettv->vval.v_string = r;
9591 }
9592}
9593
9594/*
9595 * "resolve()" function
9596 */
9597 static void
9598f_resolve(typval_T *argvars, typval_T *rettv)
9599{
9600 char_u *p;
9601#ifdef HAVE_READLINK
9602 char_u *buf = NULL;
9603#endif
9604
9605 p = get_tv_string(&argvars[0]);
9606#ifdef FEAT_SHORTCUT
9607 {
9608 char_u *v = NULL;
9609
9610 v = mch_resolve_shortcut(p);
9611 if (v != NULL)
9612 rettv->vval.v_string = v;
9613 else
9614 rettv->vval.v_string = vim_strsave(p);
9615 }
9616#else
9617# ifdef HAVE_READLINK
9618 {
9619 char_u *cpy;
9620 int len;
9621 char_u *remain = NULL;
9622 char_u *q;
9623 int is_relative_to_current = FALSE;
9624 int has_trailing_pathsep = FALSE;
9625 int limit = 100;
9626
9627 p = vim_strsave(p);
9628
9629 if (p[0] == '.' && (vim_ispathsep(p[1])
9630 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9631 is_relative_to_current = TRUE;
9632
9633 len = STRLEN(p);
9634 if (len > 0 && after_pathsep(p, p + len))
9635 {
9636 has_trailing_pathsep = TRUE;
9637 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9638 }
9639
9640 q = getnextcomp(p);
9641 if (*q != NUL)
9642 {
9643 /* Separate the first path component in "p", and keep the
9644 * remainder (beginning with the path separator). */
9645 remain = vim_strsave(q - 1);
9646 q[-1] = NUL;
9647 }
9648
9649 buf = alloc(MAXPATHL + 1);
9650 if (buf == NULL)
9651 goto fail;
9652
9653 for (;;)
9654 {
9655 for (;;)
9656 {
9657 len = readlink((char *)p, (char *)buf, MAXPATHL);
9658 if (len <= 0)
9659 break;
9660 buf[len] = NUL;
9661
9662 if (limit-- == 0)
9663 {
9664 vim_free(p);
9665 vim_free(remain);
9666 EMSG(_("E655: Too many symbolic links (cycle?)"));
9667 rettv->vval.v_string = NULL;
9668 goto fail;
9669 }
9670
9671 /* Ensure that the result will have a trailing path separator
9672 * if the argument has one. */
9673 if (remain == NULL && has_trailing_pathsep)
9674 add_pathsep(buf);
9675
9676 /* Separate the first path component in the link value and
9677 * concatenate the remainders. */
9678 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9679 if (*q != NUL)
9680 {
9681 if (remain == NULL)
9682 remain = vim_strsave(q - 1);
9683 else
9684 {
9685 cpy = concat_str(q - 1, remain);
9686 if (cpy != NULL)
9687 {
9688 vim_free(remain);
9689 remain = cpy;
9690 }
9691 }
9692 q[-1] = NUL;
9693 }
9694
9695 q = gettail(p);
9696 if (q > p && *q == NUL)
9697 {
9698 /* Ignore trailing path separator. */
9699 q[-1] = NUL;
9700 q = gettail(p);
9701 }
9702 if (q > p && !mch_isFullName(buf))
9703 {
9704 /* symlink is relative to directory of argument */
9705 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9706 if (cpy != NULL)
9707 {
9708 STRCPY(cpy, p);
9709 STRCPY(gettail(cpy), buf);
9710 vim_free(p);
9711 p = cpy;
9712 }
9713 }
9714 else
9715 {
9716 vim_free(p);
9717 p = vim_strsave(buf);
9718 }
9719 }
9720
9721 if (remain == NULL)
9722 break;
9723
9724 /* Append the first path component of "remain" to "p". */
9725 q = getnextcomp(remain + 1);
9726 len = q - remain - (*q != NUL);
9727 cpy = vim_strnsave(p, STRLEN(p) + len);
9728 if (cpy != NULL)
9729 {
9730 STRNCAT(cpy, remain, len);
9731 vim_free(p);
9732 p = cpy;
9733 }
9734 /* Shorten "remain". */
9735 if (*q != NUL)
9736 STRMOVE(remain, q - 1);
9737 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009738 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009739 }
9740
9741 /* If the result is a relative path name, make it explicitly relative to
9742 * the current directory if and only if the argument had this form. */
9743 if (!vim_ispathsep(*p))
9744 {
9745 if (is_relative_to_current
9746 && *p != NUL
9747 && !(p[0] == '.'
9748 && (p[1] == NUL
9749 || vim_ispathsep(p[1])
9750 || (p[1] == '.'
9751 && (p[2] == NUL
9752 || vim_ispathsep(p[2]))))))
9753 {
9754 /* Prepend "./". */
9755 cpy = concat_str((char_u *)"./", p);
9756 if (cpy != NULL)
9757 {
9758 vim_free(p);
9759 p = cpy;
9760 }
9761 }
9762 else if (!is_relative_to_current)
9763 {
9764 /* Strip leading "./". */
9765 q = p;
9766 while (q[0] == '.' && vim_ispathsep(q[1]))
9767 q += 2;
9768 if (q > p)
9769 STRMOVE(p, p + 2);
9770 }
9771 }
9772
9773 /* Ensure that the result will have no trailing path separator
9774 * if the argument had none. But keep "/" or "//". */
9775 if (!has_trailing_pathsep)
9776 {
9777 q = p + STRLEN(p);
9778 if (after_pathsep(p, q))
9779 *gettail_sep(p) = NUL;
9780 }
9781
9782 rettv->vval.v_string = p;
9783 }
9784# else
9785 rettv->vval.v_string = vim_strsave(p);
9786# endif
9787#endif
9788
9789 simplify_filename(rettv->vval.v_string);
9790
9791#ifdef HAVE_READLINK
9792fail:
9793 vim_free(buf);
9794#endif
9795 rettv->v_type = VAR_STRING;
9796}
9797
9798/*
9799 * "reverse({list})" function
9800 */
9801 static void
9802f_reverse(typval_T *argvars, typval_T *rettv)
9803{
9804 list_T *l;
9805 listitem_T *li, *ni;
9806
9807 if (argvars[0].v_type != VAR_LIST)
9808 EMSG2(_(e_listarg), "reverse()");
9809 else if ((l = argvars[0].vval.v_list) != NULL
9810 && !tv_check_lock(l->lv_lock,
9811 (char_u *)N_("reverse() argument"), TRUE))
9812 {
9813 li = l->lv_last;
9814 l->lv_first = l->lv_last = NULL;
9815 l->lv_len = 0;
9816 while (li != NULL)
9817 {
9818 ni = li->li_prev;
9819 list_append(l, li);
9820 li = ni;
9821 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009822 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009823 l->lv_idx = l->lv_len - l->lv_idx - 1;
9824 }
9825}
9826
9827#define SP_NOMOVE 0x01 /* don't move cursor */
9828#define SP_REPEAT 0x02 /* repeat to find outer pair */
9829#define SP_RETCOUNT 0x04 /* return matchcount */
9830#define SP_SETPCMARK 0x08 /* set previous context mark */
9831#define SP_START 0x10 /* accept match at start position */
9832#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9833#define SP_END 0x40 /* leave cursor at end of match */
9834#define SP_COLUMN 0x80 /* start at cursor column */
9835
9836static int get_search_arg(typval_T *varp, int *flagsp);
9837
9838/*
9839 * Get flags for a search function.
9840 * Possibly sets "p_ws".
9841 * Returns BACKWARD, FORWARD or zero (for an error).
9842 */
9843 static int
9844get_search_arg(typval_T *varp, int *flagsp)
9845{
9846 int dir = FORWARD;
9847 char_u *flags;
9848 char_u nbuf[NUMBUFLEN];
9849 int mask;
9850
9851 if (varp->v_type != VAR_UNKNOWN)
9852 {
9853 flags = get_tv_string_buf_chk(varp, nbuf);
9854 if (flags == NULL)
9855 return 0; /* type error; errmsg already given */
9856 while (*flags != NUL)
9857 {
9858 switch (*flags)
9859 {
9860 case 'b': dir = BACKWARD; break;
9861 case 'w': p_ws = TRUE; break;
9862 case 'W': p_ws = FALSE; break;
9863 default: mask = 0;
9864 if (flagsp != NULL)
9865 switch (*flags)
9866 {
9867 case 'c': mask = SP_START; break;
9868 case 'e': mask = SP_END; break;
9869 case 'm': mask = SP_RETCOUNT; break;
9870 case 'n': mask = SP_NOMOVE; break;
9871 case 'p': mask = SP_SUBPAT; break;
9872 case 'r': mask = SP_REPEAT; break;
9873 case 's': mask = SP_SETPCMARK; break;
9874 case 'z': mask = SP_COLUMN; break;
9875 }
9876 if (mask == 0)
9877 {
9878 EMSG2(_(e_invarg2), flags);
9879 dir = 0;
9880 }
9881 else
9882 *flagsp |= mask;
9883 }
9884 if (dir == 0)
9885 break;
9886 ++flags;
9887 }
9888 }
9889 return dir;
9890}
9891
9892/*
9893 * Shared by search() and searchpos() functions.
9894 */
9895 static int
9896search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9897{
9898 int flags;
9899 char_u *pat;
9900 pos_T pos;
9901 pos_T save_cursor;
9902 int save_p_ws = p_ws;
9903 int dir;
9904 int retval = 0; /* default: FAIL */
9905 long lnum_stop = 0;
9906 proftime_T tm;
9907#ifdef FEAT_RELTIME
9908 long time_limit = 0;
9909#endif
9910 int options = SEARCH_KEEP;
9911 int subpatnum;
9912
9913 pat = get_tv_string(&argvars[0]);
9914 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9915 if (dir == 0)
9916 goto theend;
9917 flags = *flagsp;
9918 if (flags & SP_START)
9919 options |= SEARCH_START;
9920 if (flags & SP_END)
9921 options |= SEARCH_END;
9922 if (flags & SP_COLUMN)
9923 options |= SEARCH_COL;
9924
9925 /* Optional arguments: line number to stop searching and timeout. */
9926 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9927 {
9928 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9929 if (lnum_stop < 0)
9930 goto theend;
9931#ifdef FEAT_RELTIME
9932 if (argvars[3].v_type != VAR_UNKNOWN)
9933 {
9934 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9935 if (time_limit < 0)
9936 goto theend;
9937 }
9938#endif
9939 }
9940
9941#ifdef FEAT_RELTIME
9942 /* Set the time limit, if there is one. */
9943 profile_setlimit(time_limit, &tm);
9944#endif
9945
9946 /*
9947 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9948 * Check to make sure only those flags are set.
9949 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9950 * flags cannot be set. Check for that condition also.
9951 */
9952 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9953 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9954 {
9955 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9956 goto theend;
9957 }
9958
9959 pos = save_cursor = curwin->w_cursor;
9960 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009961 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009962 if (subpatnum != FAIL)
9963 {
9964 if (flags & SP_SUBPAT)
9965 retval = subpatnum;
9966 else
9967 retval = pos.lnum;
9968 if (flags & SP_SETPCMARK)
9969 setpcmark();
9970 curwin->w_cursor = pos;
9971 if (match_pos != NULL)
9972 {
9973 /* Store the match cursor position */
9974 match_pos->lnum = pos.lnum;
9975 match_pos->col = pos.col + 1;
9976 }
9977 /* "/$" will put the cursor after the end of the line, may need to
9978 * correct that here */
9979 check_cursor();
9980 }
9981
9982 /* If 'n' flag is used: restore cursor position. */
9983 if (flags & SP_NOMOVE)
9984 curwin->w_cursor = save_cursor;
9985 else
9986 curwin->w_set_curswant = TRUE;
9987theend:
9988 p_ws = save_p_ws;
9989
9990 return retval;
9991}
9992
9993#ifdef FEAT_FLOAT
9994
9995/*
9996 * round() is not in C90, use ceil() or floor() instead.
9997 */
9998 float_T
9999vim_round(float_T f)
10000{
10001 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10002}
10003
10004/*
10005 * "round({float})" function
10006 */
10007 static void
10008f_round(typval_T *argvars, typval_T *rettv)
10009{
10010 float_T f = 0.0;
10011
10012 rettv->v_type = VAR_FLOAT;
10013 if (get_float_arg(argvars, &f) == OK)
10014 rettv->vval.v_float = vim_round(f);
10015 else
10016 rettv->vval.v_float = 0.0;
10017}
10018#endif
10019
10020/*
10021 * "screenattr()" function
10022 */
10023 static void
10024f_screenattr(typval_T *argvars, typval_T *rettv)
10025{
10026 int row;
10027 int col;
10028 int c;
10029
10030 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10031 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10032 if (row < 0 || row >= screen_Rows
10033 || col < 0 || col >= screen_Columns)
10034 c = -1;
10035 else
10036 c = ScreenAttrs[LineOffset[row] + col];
10037 rettv->vval.v_number = c;
10038}
10039
10040/*
10041 * "screenchar()" function
10042 */
10043 static void
10044f_screenchar(typval_T *argvars, typval_T *rettv)
10045{
10046 int row;
10047 int col;
10048 int off;
10049 int c;
10050
10051 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10052 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10053 if (row < 0 || row >= screen_Rows
10054 || col < 0 || col >= screen_Columns)
10055 c = -1;
10056 else
10057 {
10058 off = LineOffset[row] + col;
10059#ifdef FEAT_MBYTE
10060 if (enc_utf8 && ScreenLinesUC[off] != 0)
10061 c = ScreenLinesUC[off];
10062 else
10063#endif
10064 c = ScreenLines[off];
10065 }
10066 rettv->vval.v_number = c;
10067}
10068
10069/*
10070 * "screencol()" function
10071 *
10072 * First column is 1 to be consistent with virtcol().
10073 */
10074 static void
10075f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10076{
10077 rettv->vval.v_number = screen_screencol() + 1;
10078}
10079
10080/*
10081 * "screenrow()" function
10082 */
10083 static void
10084f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10085{
10086 rettv->vval.v_number = screen_screenrow() + 1;
10087}
10088
10089/*
10090 * "search()" function
10091 */
10092 static void
10093f_search(typval_T *argvars, typval_T *rettv)
10094{
10095 int flags = 0;
10096
10097 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10098}
10099
10100/*
10101 * "searchdecl()" function
10102 */
10103 static void
10104f_searchdecl(typval_T *argvars, typval_T *rettv)
10105{
10106 int locally = 1;
10107 int thisblock = 0;
10108 int error = FALSE;
10109 char_u *name;
10110
10111 rettv->vval.v_number = 1; /* default: FAIL */
10112
10113 name = get_tv_string_chk(&argvars[0]);
10114 if (argvars[1].v_type != VAR_UNKNOWN)
10115 {
10116 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
10117 if (!error && argvars[2].v_type != VAR_UNKNOWN)
10118 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
10119 }
10120 if (!error && name != NULL)
10121 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10122 locally, thisblock, SEARCH_KEEP) == FAIL;
10123}
10124
10125/*
10126 * Used by searchpair() and searchpairpos()
10127 */
10128 static int
10129searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10130{
10131 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010132 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010133 int save_p_ws = p_ws;
10134 int dir;
10135 int flags = 0;
10136 char_u nbuf1[NUMBUFLEN];
10137 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010138 int retval = 0; /* default: FAIL */
10139 long lnum_stop = 0;
10140 long time_limit = 0;
10141
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010142 /* Get the three pattern arguments: start, middle, end. Will result in an
10143 * error if not a valid argument. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010144 spat = get_tv_string_chk(&argvars[0]);
10145 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
10146 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
10147 if (spat == NULL || mpat == NULL || epat == NULL)
10148 goto theend; /* type error */
10149
10150 /* Handle the optional fourth argument: flags */
10151 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10152 if (dir == 0)
10153 goto theend;
10154
10155 /* Don't accept SP_END or SP_SUBPAT.
10156 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10157 */
10158 if ((flags & (SP_END | SP_SUBPAT)) != 0
10159 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10160 {
10161 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10162 goto theend;
10163 }
10164
10165 /* Using 'r' implies 'W', otherwise it doesn't work. */
10166 if (flags & SP_REPEAT)
10167 p_ws = FALSE;
10168
10169 /* Optional fifth argument: skip expression */
10170 if (argvars[3].v_type == VAR_UNKNOWN
10171 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010172 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010173 else
10174 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010175 skip = &argvars[4];
10176 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10177 && skip->v_type != VAR_STRING)
10178 {
10179 /* Type error */
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010180 EMSG2(_(e_invarg2), get_tv_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010181 goto theend;
10182 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010183 if (argvars[5].v_type != VAR_UNKNOWN)
10184 {
10185 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10186 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010187 {
10188 EMSG2(_(e_invarg2), get_tv_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010189 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010190 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010191#ifdef FEAT_RELTIME
10192 if (argvars[6].v_type != VAR_UNKNOWN)
10193 {
10194 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10195 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010196 {
10197 EMSG2(_(e_invarg2), get_tv_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010198 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010199 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010200 }
10201#endif
10202 }
10203 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010204
10205 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10206 match_pos, lnum_stop, time_limit);
10207
10208theend:
10209 p_ws = save_p_ws;
10210
10211 return retval;
10212}
10213
10214/*
10215 * "searchpair()" function
10216 */
10217 static void
10218f_searchpair(typval_T *argvars, typval_T *rettv)
10219{
10220 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10221}
10222
10223/*
10224 * "searchpairpos()" function
10225 */
10226 static void
10227f_searchpairpos(typval_T *argvars, typval_T *rettv)
10228{
10229 pos_T match_pos;
10230 int lnum = 0;
10231 int col = 0;
10232
10233 if (rettv_list_alloc(rettv) == FAIL)
10234 return;
10235
10236 if (searchpair_cmn(argvars, &match_pos) > 0)
10237 {
10238 lnum = match_pos.lnum;
10239 col = match_pos.col;
10240 }
10241
10242 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10243 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10244}
10245
10246/*
10247 * Search for a start/middle/end thing.
10248 * Used by searchpair(), see its documentation for the details.
10249 * Returns 0 or -1 for no match,
10250 */
10251 long
10252do_searchpair(
10253 char_u *spat, /* start pattern */
10254 char_u *mpat, /* middle pattern */
10255 char_u *epat, /* end pattern */
10256 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010257 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010258 int flags, /* SP_SETPCMARK and other SP_ values */
10259 pos_T *match_pos,
10260 linenr_T lnum_stop, /* stop at this line if not zero */
10261 long time_limit UNUSED) /* stop after this many msec */
10262{
10263 char_u *save_cpo;
10264 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10265 long retval = 0;
10266 pos_T pos;
10267 pos_T firstpos;
10268 pos_T foundpos;
10269 pos_T save_cursor;
10270 pos_T save_pos;
10271 int n;
10272 int r;
10273 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010274 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010275 int err;
10276 int options = SEARCH_KEEP;
10277 proftime_T tm;
10278
10279 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10280 save_cpo = p_cpo;
10281 p_cpo = empty_option;
10282
10283#ifdef FEAT_RELTIME
10284 /* Set the time limit, if there is one. */
10285 profile_setlimit(time_limit, &tm);
10286#endif
10287
10288 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10289 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010290 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10291 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010292 if (pat2 == NULL || pat3 == NULL)
10293 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010294 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010295 if (*mpat == NUL)
10296 STRCPY(pat3, pat2);
10297 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010298 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010299 spat, epat, mpat);
10300 if (flags & SP_START)
10301 options |= SEARCH_START;
10302
Bram Moolenaar48570482017-10-30 21:48:41 +010010303 if (skip != NULL)
10304 {
10305 /* Empty string means to not use the skip expression. */
10306 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10307 use_skip = skip->vval.v_string != NULL
10308 && *skip->vval.v_string != NUL;
10309 }
10310
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010311 save_cursor = curwin->w_cursor;
10312 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010313 CLEAR_POS(&firstpos);
10314 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010315 pat = pat3;
10316 for (;;)
10317 {
10318 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010319 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010320 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010321 /* didn't find it or found the first match again: FAIL */
10322 break;
10323
10324 if (firstpos.lnum == 0)
10325 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010326 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010327 {
10328 /* Found the same position again. Can happen with a pattern that
10329 * has "\zs" at the end and searching backwards. Advance one
10330 * character and try again. */
10331 if (dir == BACKWARD)
10332 decl(&pos);
10333 else
10334 incl(&pos);
10335 }
10336 foundpos = pos;
10337
10338 /* clear the start flag to avoid getting stuck here */
10339 options &= ~SEARCH_START;
10340
10341 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010342 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010343 {
10344 save_pos = curwin->w_cursor;
10345 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010346 err = FALSE;
10347 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010348 curwin->w_cursor = save_pos;
10349 if (err)
10350 {
10351 /* Evaluating {skip} caused an error, break here. */
10352 curwin->w_cursor = save_cursor;
10353 retval = -1;
10354 break;
10355 }
10356 if (r)
10357 continue;
10358 }
10359
10360 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10361 {
10362 /* Found end when searching backwards or start when searching
10363 * forward: nested pair. */
10364 ++nest;
10365 pat = pat2; /* nested, don't search for middle */
10366 }
10367 else
10368 {
10369 /* Found end when searching forward or start when searching
10370 * backward: end of (nested) pair; or found middle in outer pair. */
10371 if (--nest == 1)
10372 pat = pat3; /* outer level, search for middle */
10373 }
10374
10375 if (nest == 0)
10376 {
10377 /* Found the match: return matchcount or line number. */
10378 if (flags & SP_RETCOUNT)
10379 ++retval;
10380 else
10381 retval = pos.lnum;
10382 if (flags & SP_SETPCMARK)
10383 setpcmark();
10384 curwin->w_cursor = pos;
10385 if (!(flags & SP_REPEAT))
10386 break;
10387 nest = 1; /* search for next unmatched */
10388 }
10389 }
10390
10391 if (match_pos != NULL)
10392 {
10393 /* Store the match cursor position */
10394 match_pos->lnum = curwin->w_cursor.lnum;
10395 match_pos->col = curwin->w_cursor.col + 1;
10396 }
10397
10398 /* If 'n' flag is used or search failed: restore cursor position. */
10399 if ((flags & SP_NOMOVE) || retval == 0)
10400 curwin->w_cursor = save_cursor;
10401
10402theend:
10403 vim_free(pat2);
10404 vim_free(pat3);
10405 if (p_cpo == empty_option)
10406 p_cpo = save_cpo;
10407 else
10408 /* Darn, evaluating the {skip} expression changed the value. */
10409 free_string_option(save_cpo);
10410
10411 return retval;
10412}
10413
10414/*
10415 * "searchpos()" function
10416 */
10417 static void
10418f_searchpos(typval_T *argvars, typval_T *rettv)
10419{
10420 pos_T match_pos;
10421 int lnum = 0;
10422 int col = 0;
10423 int n;
10424 int flags = 0;
10425
10426 if (rettv_list_alloc(rettv) == FAIL)
10427 return;
10428
10429 n = search_cmn(argvars, &match_pos, &flags);
10430 if (n > 0)
10431 {
10432 lnum = match_pos.lnum;
10433 col = match_pos.col;
10434 }
10435
10436 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10437 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10438 if (flags & SP_SUBPAT)
10439 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10440}
10441
10442 static void
10443f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10444{
10445#ifdef FEAT_CLIENTSERVER
10446 char_u buf[NUMBUFLEN];
10447 char_u *server = get_tv_string_chk(&argvars[0]);
10448 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10449
10450 rettv->vval.v_number = -1;
10451 if (server == NULL || reply == NULL)
10452 return;
10453 if (check_restricted() || check_secure())
10454 return;
10455# ifdef FEAT_X11
10456 if (check_connection() == FAIL)
10457 return;
10458# endif
10459
10460 if (serverSendReply(server, reply) < 0)
10461 {
10462 EMSG(_("E258: Unable to send to client"));
10463 return;
10464 }
10465 rettv->vval.v_number = 0;
10466#else
10467 rettv->vval.v_number = -1;
10468#endif
10469}
10470
10471 static void
10472f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10473{
10474 char_u *r = NULL;
10475
10476#ifdef FEAT_CLIENTSERVER
10477# ifdef WIN32
10478 r = serverGetVimNames();
10479# else
10480 make_connection();
10481 if (X_DISPLAY != NULL)
10482 r = serverGetVimNames(X_DISPLAY);
10483# endif
10484#endif
10485 rettv->v_type = VAR_STRING;
10486 rettv->vval.v_string = r;
10487}
10488
10489/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010490 * "setbufline()" function
10491 */
10492 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010493f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010494{
10495 linenr_T lnum;
10496 buf_T *buf;
10497
10498 buf = get_buf_tv(&argvars[0], FALSE);
10499 if (buf == NULL)
10500 rettv->vval.v_number = 1; /* FAIL */
10501 else
10502 {
10503 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010504 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010505 }
10506}
10507
10508/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010509 * "setbufvar()" function
10510 */
10511 static void
10512f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10513{
10514 buf_T *buf;
10515 char_u *varname, *bufvarname;
10516 typval_T *varp;
10517 char_u nbuf[NUMBUFLEN];
10518
10519 if (check_restricted() || check_secure())
10520 return;
10521 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10522 varname = get_tv_string_chk(&argvars[1]);
10523 buf = get_buf_tv(&argvars[0], FALSE);
10524 varp = &argvars[2];
10525
10526 if (buf != NULL && varname != NULL && varp != NULL)
10527 {
10528 if (*varname == '&')
10529 {
10530 long numval;
10531 char_u *strval;
10532 int error = FALSE;
10533 aco_save_T aco;
10534
10535 /* set curbuf to be our buf, temporarily */
10536 aucmd_prepbuf(&aco, buf);
10537
10538 ++varname;
10539 numval = (long)get_tv_number_chk(varp, &error);
10540 strval = get_tv_string_buf_chk(varp, nbuf);
10541 if (!error && strval != NULL)
10542 set_option_value(varname, numval, strval, OPT_LOCAL);
10543
10544 /* reset notion of buffer */
10545 aucmd_restbuf(&aco);
10546 }
10547 else
10548 {
10549 buf_T *save_curbuf = curbuf;
10550
10551 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10552 if (bufvarname != NULL)
10553 {
10554 curbuf = buf;
10555 STRCPY(bufvarname, "b:");
10556 STRCPY(bufvarname + 2, varname);
10557 set_var(bufvarname, varp, TRUE);
10558 vim_free(bufvarname);
10559 curbuf = save_curbuf;
10560 }
10561 }
10562 }
10563}
10564
10565 static void
10566f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10567{
10568 dict_T *d;
10569 dictitem_T *di;
10570 char_u *csearch;
10571
10572 if (argvars[0].v_type != VAR_DICT)
10573 {
10574 EMSG(_(e_dictreq));
10575 return;
10576 }
10577
10578 if ((d = argvars[0].vval.v_dict) != NULL)
10579 {
10580 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10581 if (csearch != NULL)
10582 {
10583#ifdef FEAT_MBYTE
10584 if (enc_utf8)
10585 {
10586 int pcc[MAX_MCO];
10587 int c = utfc_ptr2char(csearch, pcc);
10588
10589 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10590 }
10591 else
10592#endif
10593 set_last_csearch(PTR2CHAR(csearch),
10594 csearch, MB_PTR2LEN(csearch));
10595 }
10596
10597 di = dict_find(d, (char_u *)"forward", -1);
10598 if (di != NULL)
10599 set_csearch_direction((int)get_tv_number(&di->di_tv)
10600 ? FORWARD : BACKWARD);
10601
10602 di = dict_find(d, (char_u *)"until", -1);
10603 if (di != NULL)
10604 set_csearch_until(!!get_tv_number(&di->di_tv));
10605 }
10606}
10607
10608/*
10609 * "setcmdpos()" function
10610 */
10611 static void
10612f_setcmdpos(typval_T *argvars, typval_T *rettv)
10613{
10614 int pos = (int)get_tv_number(&argvars[0]) - 1;
10615
10616 if (pos >= 0)
10617 rettv->vval.v_number = set_cmdline_pos(pos);
10618}
10619
10620/*
10621 * "setfperm({fname}, {mode})" function
10622 */
10623 static void
10624f_setfperm(typval_T *argvars, typval_T *rettv)
10625{
10626 char_u *fname;
10627 char_u modebuf[NUMBUFLEN];
10628 char_u *mode_str;
10629 int i;
10630 int mask;
10631 int mode = 0;
10632
10633 rettv->vval.v_number = 0;
10634 fname = get_tv_string_chk(&argvars[0]);
10635 if (fname == NULL)
10636 return;
10637 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10638 if (mode_str == NULL)
10639 return;
10640 if (STRLEN(mode_str) != 9)
10641 {
10642 EMSG2(_(e_invarg2), mode_str);
10643 return;
10644 }
10645
10646 mask = 1;
10647 for (i = 8; i >= 0; --i)
10648 {
10649 if (mode_str[i] != '-')
10650 mode |= mask;
10651 mask = mask << 1;
10652 }
10653 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10654}
10655
10656/*
10657 * "setline()" function
10658 */
10659 static void
10660f_setline(typval_T *argvars, typval_T *rettv)
10661{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010662 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010663
Bram Moolenaarca851592018-06-06 21:04:07 +020010664 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010665}
10666
Bram Moolenaard823fa92016-08-12 16:29:27 +020010667static 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 +020010668
10669/*
10670 * Used by "setqflist()" and "setloclist()" functions
10671 */
10672 static void
10673set_qf_ll_list(
10674 win_T *wp UNUSED,
10675 typval_T *list_arg UNUSED,
10676 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010677 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010678 typval_T *rettv)
10679{
10680#ifdef FEAT_QUICKFIX
10681 static char *e_invact = N_("E927: Invalid action: '%s'");
10682 char_u *act;
10683 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010684 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010685#endif
10686
10687 rettv->vval.v_number = -1;
10688
10689#ifdef FEAT_QUICKFIX
10690 if (list_arg->v_type != VAR_LIST)
10691 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010692 else if (recursive != 0)
10693 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010694 else
10695 {
10696 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010697 dict_T *d = NULL;
10698 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010699
10700 if (action_arg->v_type == VAR_STRING)
10701 {
10702 act = get_tv_string_chk(action_arg);
10703 if (act == NULL)
10704 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010705 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10706 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010707 action = *act;
10708 else
10709 EMSG2(_(e_invact), act);
10710 }
10711 else if (action_arg->v_type == VAR_UNKNOWN)
10712 action = ' ';
10713 else
10714 EMSG(_(e_stringreq));
10715
Bram Moolenaard823fa92016-08-12 16:29:27 +020010716 if (action_arg->v_type != VAR_UNKNOWN
10717 && what_arg->v_type != VAR_UNKNOWN)
10718 {
10719 if (what_arg->v_type == VAR_DICT)
10720 d = what_arg->vval.v_dict;
10721 else
10722 {
10723 EMSG(_(e_dictreq));
10724 valid_dict = FALSE;
10725 }
10726 }
10727
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010728 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010729 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010730 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10731 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010732 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010733 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010734 }
10735#endif
10736}
10737
10738/*
10739 * "setloclist()" function
10740 */
10741 static void
10742f_setloclist(typval_T *argvars, typval_T *rettv)
10743{
10744 win_T *win;
10745
10746 rettv->vval.v_number = -1;
10747
10748 win = find_win_by_nr(&argvars[0], NULL);
10749 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010750 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010751}
10752
10753/*
10754 * "setmatches()" function
10755 */
10756 static void
10757f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10758{
10759#ifdef FEAT_SEARCH_EXTRA
10760 list_T *l;
10761 listitem_T *li;
10762 dict_T *d;
10763 list_T *s = NULL;
10764
10765 rettv->vval.v_number = -1;
10766 if (argvars[0].v_type != VAR_LIST)
10767 {
10768 EMSG(_(e_listreq));
10769 return;
10770 }
10771 if ((l = argvars[0].vval.v_list) != NULL)
10772 {
10773
10774 /* To some extent make sure that we are dealing with a list from
10775 * "getmatches()". */
10776 li = l->lv_first;
10777 while (li != NULL)
10778 {
10779 if (li->li_tv.v_type != VAR_DICT
10780 || (d = li->li_tv.vval.v_dict) == NULL)
10781 {
10782 EMSG(_(e_invarg));
10783 return;
10784 }
10785 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10786 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10787 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10788 && dict_find(d, (char_u *)"priority", -1) != NULL
10789 && dict_find(d, (char_u *)"id", -1) != NULL))
10790 {
10791 EMSG(_(e_invarg));
10792 return;
10793 }
10794 li = li->li_next;
10795 }
10796
10797 clear_matches(curwin);
10798 li = l->lv_first;
10799 while (li != NULL)
10800 {
10801 int i = 0;
10802 char_u buf[5];
10803 dictitem_T *di;
10804 char_u *group;
10805 int priority;
10806 int id;
10807 char_u *conceal;
10808
10809 d = li->li_tv.vval.v_dict;
10810 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10811 {
10812 if (s == NULL)
10813 {
10814 s = list_alloc();
10815 if (s == NULL)
10816 return;
10817 }
10818
10819 /* match from matchaddpos() */
10820 for (i = 1; i < 9; i++)
10821 {
10822 sprintf((char *)buf, (char *)"pos%d", i);
10823 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10824 {
10825 if (di->di_tv.v_type != VAR_LIST)
10826 return;
10827
10828 list_append_tv(s, &di->di_tv);
10829 s->lv_refcount++;
10830 }
10831 else
10832 break;
10833 }
10834 }
10835
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010836 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010837 priority = (int)get_dict_number(d, (char_u *)"priority");
10838 id = (int)get_dict_number(d, (char_u *)"id");
10839 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010840 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010841 : NULL;
10842 if (i == 0)
10843 {
10844 match_add(curwin, group,
10845 get_dict_string(d, (char_u *)"pattern", FALSE),
10846 priority, id, NULL, conceal);
10847 }
10848 else
10849 {
10850 match_add(curwin, group, NULL, priority, id, s, conceal);
10851 list_unref(s);
10852 s = NULL;
10853 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010854 vim_free(group);
10855 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010856
10857 li = li->li_next;
10858 }
10859 rettv->vval.v_number = 0;
10860 }
10861#endif
10862}
10863
10864/*
10865 * "setpos()" function
10866 */
10867 static void
10868f_setpos(typval_T *argvars, typval_T *rettv)
10869{
10870 pos_T pos;
10871 int fnum;
10872 char_u *name;
10873 colnr_T curswant = -1;
10874
10875 rettv->vval.v_number = -1;
10876 name = get_tv_string_chk(argvars);
10877 if (name != NULL)
10878 {
10879 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10880 {
10881 if (--pos.col < 0)
10882 pos.col = 0;
10883 if (name[0] == '.' && name[1] == NUL)
10884 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010885 /* set cursor; "fnum" is ignored */
10886 curwin->w_cursor = pos;
10887 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010888 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010889 curwin->w_curswant = curswant - 1;
10890 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010891 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010892 check_cursor();
10893 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010894 }
10895 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10896 {
10897 /* set mark */
10898 if (setmark_pos(name[1], &pos, fnum) == OK)
10899 rettv->vval.v_number = 0;
10900 }
10901 else
10902 EMSG(_(e_invarg));
10903 }
10904 }
10905}
10906
10907/*
10908 * "setqflist()" function
10909 */
10910 static void
10911f_setqflist(typval_T *argvars, typval_T *rettv)
10912{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010913 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010914}
10915
10916/*
10917 * "setreg()" function
10918 */
10919 static void
10920f_setreg(typval_T *argvars, typval_T *rettv)
10921{
10922 int regname;
10923 char_u *strregname;
10924 char_u *stropt;
10925 char_u *strval;
10926 int append;
10927 char_u yank_type;
10928 long block_len;
10929
10930 block_len = -1;
10931 yank_type = MAUTO;
10932 append = FALSE;
10933
10934 strregname = get_tv_string_chk(argvars);
10935 rettv->vval.v_number = 1; /* FAIL is default */
10936
10937 if (strregname == NULL)
10938 return; /* type error; errmsg already given */
10939 regname = *strregname;
10940 if (regname == 0 || regname == '@')
10941 regname = '"';
10942
10943 if (argvars[2].v_type != VAR_UNKNOWN)
10944 {
10945 stropt = get_tv_string_chk(&argvars[2]);
10946 if (stropt == NULL)
10947 return; /* type error */
10948 for (; *stropt != NUL; ++stropt)
10949 switch (*stropt)
10950 {
10951 case 'a': case 'A': /* append */
10952 append = TRUE;
10953 break;
10954 case 'v': case 'c': /* character-wise selection */
10955 yank_type = MCHAR;
10956 break;
10957 case 'V': case 'l': /* line-wise selection */
10958 yank_type = MLINE;
10959 break;
10960 case 'b': case Ctrl_V: /* block-wise selection */
10961 yank_type = MBLOCK;
10962 if (VIM_ISDIGIT(stropt[1]))
10963 {
10964 ++stropt;
10965 block_len = getdigits(&stropt) - 1;
10966 --stropt;
10967 }
10968 break;
10969 }
10970 }
10971
10972 if (argvars[1].v_type == VAR_LIST)
10973 {
10974 char_u **lstval;
10975 char_u **allocval;
10976 char_u buf[NUMBUFLEN];
10977 char_u **curval;
10978 char_u **curallocval;
10979 list_T *ll = argvars[1].vval.v_list;
10980 listitem_T *li;
10981 int len;
10982
10983 /* If the list is NULL handle like an empty list. */
10984 len = ll == NULL ? 0 : ll->lv_len;
10985
10986 /* First half: use for pointers to result lines; second half: use for
10987 * pointers to allocated copies. */
10988 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10989 if (lstval == NULL)
10990 return;
10991 curval = lstval;
10992 allocval = lstval + len + 2;
10993 curallocval = allocval;
10994
10995 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10996 li = li->li_next)
10997 {
10998 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10999 if (strval == NULL)
11000 goto free_lstval;
11001 if (strval == buf)
11002 {
11003 /* Need to make a copy, next get_tv_string_buf_chk() will
11004 * overwrite the string. */
11005 strval = vim_strsave(buf);
11006 if (strval == NULL)
11007 goto free_lstval;
11008 *curallocval++ = strval;
11009 }
11010 *curval++ = strval;
11011 }
11012 *curval++ = NULL;
11013
11014 write_reg_contents_lst(regname, lstval, -1,
11015 append, yank_type, block_len);
11016free_lstval:
11017 while (curallocval > allocval)
11018 vim_free(*--curallocval);
11019 vim_free(lstval);
11020 }
11021 else
11022 {
11023 strval = get_tv_string_chk(&argvars[1]);
11024 if (strval == NULL)
11025 return;
11026 write_reg_contents_ex(regname, strval, -1,
11027 append, yank_type, block_len);
11028 }
11029 rettv->vval.v_number = 0;
11030}
11031
11032/*
11033 * "settabvar()" function
11034 */
11035 static void
11036f_settabvar(typval_T *argvars, typval_T *rettv)
11037{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038 tabpage_T *save_curtab;
11039 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011040 char_u *varname, *tabvarname;
11041 typval_T *varp;
11042
11043 rettv->vval.v_number = 0;
11044
11045 if (check_restricted() || check_secure())
11046 return;
11047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011048 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011049 varname = get_tv_string_chk(&argvars[1]);
11050 varp = &argvars[2];
11051
Bram Moolenaar4033c552017-09-16 20:54:51 +020011052 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011053 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011054 save_curtab = curtab;
11055 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011056
11057 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11058 if (tabvarname != NULL)
11059 {
11060 STRCPY(tabvarname, "t:");
11061 STRCPY(tabvarname + 2, varname);
11062 set_var(tabvarname, varp, TRUE);
11063 vim_free(tabvarname);
11064 }
11065
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011066 /* Restore current tabpage */
11067 if (valid_tabpage(save_curtab))
11068 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011069 }
11070}
11071
11072/*
11073 * "settabwinvar()" function
11074 */
11075 static void
11076f_settabwinvar(typval_T *argvars, typval_T *rettv)
11077{
11078 setwinvar(argvars, rettv, 1);
11079}
11080
11081/*
11082 * "setwinvar()" function
11083 */
11084 static void
11085f_setwinvar(typval_T *argvars, typval_T *rettv)
11086{
11087 setwinvar(argvars, rettv, 0);
11088}
11089
11090#ifdef FEAT_CRYPT
11091/*
11092 * "sha256({string})" function
11093 */
11094 static void
11095f_sha256(typval_T *argvars, typval_T *rettv)
11096{
11097 char_u *p;
11098
11099 p = get_tv_string(&argvars[0]);
11100 rettv->vval.v_string = vim_strsave(
11101 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11102 rettv->v_type = VAR_STRING;
11103}
11104#endif /* FEAT_CRYPT */
11105
11106/*
11107 * "shellescape({string})" function
11108 */
11109 static void
11110f_shellescape(typval_T *argvars, typval_T *rettv)
11111{
Bram Moolenaar20615522017-06-05 18:46:26 +020011112 int do_special = non_zero_arg(&argvars[1]);
11113
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011114 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020011115 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011116 rettv->v_type = VAR_STRING;
11117}
11118
11119/*
11120 * shiftwidth() function
11121 */
11122 static void
11123f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11124{
11125 rettv->vval.v_number = get_sw_value(curbuf);
11126}
11127
11128/*
11129 * "simplify()" function
11130 */
11131 static void
11132f_simplify(typval_T *argvars, typval_T *rettv)
11133{
11134 char_u *p;
11135
11136 p = get_tv_string(&argvars[0]);
11137 rettv->vval.v_string = vim_strsave(p);
11138 simplify_filename(rettv->vval.v_string); /* simplify in place */
11139 rettv->v_type = VAR_STRING;
11140}
11141
11142#ifdef FEAT_FLOAT
11143/*
11144 * "sin()" function
11145 */
11146 static void
11147f_sin(typval_T *argvars, typval_T *rettv)
11148{
11149 float_T f = 0.0;
11150
11151 rettv->v_type = VAR_FLOAT;
11152 if (get_float_arg(argvars, &f) == OK)
11153 rettv->vval.v_float = sin(f);
11154 else
11155 rettv->vval.v_float = 0.0;
11156}
11157
11158/*
11159 * "sinh()" function
11160 */
11161 static void
11162f_sinh(typval_T *argvars, typval_T *rettv)
11163{
11164 float_T f = 0.0;
11165
11166 rettv->v_type = VAR_FLOAT;
11167 if (get_float_arg(argvars, &f) == OK)
11168 rettv->vval.v_float = sinh(f);
11169 else
11170 rettv->vval.v_float = 0.0;
11171}
11172#endif
11173
11174static int
11175#ifdef __BORLANDC__
11176 _RTLENTRYF
11177#endif
11178 item_compare(const void *s1, const void *s2);
11179static int
11180#ifdef __BORLANDC__
11181 _RTLENTRYF
11182#endif
11183 item_compare2(const void *s1, const void *s2);
11184
11185/* struct used in the array that's given to qsort() */
11186typedef struct
11187{
11188 listitem_T *item;
11189 int idx;
11190} sortItem_T;
11191
11192/* struct storing information about current sort */
11193typedef struct
11194{
11195 int item_compare_ic;
11196 int item_compare_numeric;
11197 int item_compare_numbers;
11198#ifdef FEAT_FLOAT
11199 int item_compare_float;
11200#endif
11201 char_u *item_compare_func;
11202 partial_T *item_compare_partial;
11203 dict_T *item_compare_selfdict;
11204 int item_compare_func_err;
11205 int item_compare_keep_zero;
11206} sortinfo_T;
11207static sortinfo_T *sortinfo = NULL;
11208static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
11209#define ITEM_COMPARE_FAIL 999
11210
11211/*
11212 * Compare functions for f_sort() and f_uniq() below.
11213 */
11214 static int
11215#ifdef __BORLANDC__
11216_RTLENTRYF
11217#endif
11218item_compare(const void *s1, const void *s2)
11219{
11220 sortItem_T *si1, *si2;
11221 typval_T *tv1, *tv2;
11222 char_u *p1, *p2;
11223 char_u *tofree1 = NULL, *tofree2 = NULL;
11224 int res;
11225 char_u numbuf1[NUMBUFLEN];
11226 char_u numbuf2[NUMBUFLEN];
11227
11228 si1 = (sortItem_T *)s1;
11229 si2 = (sortItem_T *)s2;
11230 tv1 = &si1->item->li_tv;
11231 tv2 = &si2->item->li_tv;
11232
11233 if (sortinfo->item_compare_numbers)
11234 {
11235 varnumber_T v1 = get_tv_number(tv1);
11236 varnumber_T v2 = get_tv_number(tv2);
11237
11238 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11239 }
11240
11241#ifdef FEAT_FLOAT
11242 if (sortinfo->item_compare_float)
11243 {
11244 float_T v1 = get_tv_float(tv1);
11245 float_T v2 = get_tv_float(tv2);
11246
11247 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11248 }
11249#endif
11250
11251 /* tv2string() puts quotes around a string and allocates memory. Don't do
11252 * that for string variables. Use a single quote when comparing with a
11253 * non-string to do what the docs promise. */
11254 if (tv1->v_type == VAR_STRING)
11255 {
11256 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11257 p1 = (char_u *)"'";
11258 else
11259 p1 = tv1->vval.v_string;
11260 }
11261 else
11262 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11263 if (tv2->v_type == VAR_STRING)
11264 {
11265 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11266 p2 = (char_u *)"'";
11267 else
11268 p2 = tv2->vval.v_string;
11269 }
11270 else
11271 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11272 if (p1 == NULL)
11273 p1 = (char_u *)"";
11274 if (p2 == NULL)
11275 p2 = (char_u *)"";
11276 if (!sortinfo->item_compare_numeric)
11277 {
11278 if (sortinfo->item_compare_ic)
11279 res = STRICMP(p1, p2);
11280 else
11281 res = STRCMP(p1, p2);
11282 }
11283 else
11284 {
11285 double n1, n2;
11286 n1 = strtod((char *)p1, (char **)&p1);
11287 n2 = strtod((char *)p2, (char **)&p2);
11288 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11289 }
11290
11291 /* When the result would be zero, compare the item indexes. Makes the
11292 * sort stable. */
11293 if (res == 0 && !sortinfo->item_compare_keep_zero)
11294 res = si1->idx > si2->idx ? 1 : -1;
11295
11296 vim_free(tofree1);
11297 vim_free(tofree2);
11298 return res;
11299}
11300
11301 static int
11302#ifdef __BORLANDC__
11303_RTLENTRYF
11304#endif
11305item_compare2(const void *s1, const void *s2)
11306{
11307 sortItem_T *si1, *si2;
11308 int res;
11309 typval_T rettv;
11310 typval_T argv[3];
11311 int dummy;
11312 char_u *func_name;
11313 partial_T *partial = sortinfo->item_compare_partial;
11314
11315 /* shortcut after failure in previous call; compare all items equal */
11316 if (sortinfo->item_compare_func_err)
11317 return 0;
11318
11319 si1 = (sortItem_T *)s1;
11320 si2 = (sortItem_T *)s2;
11321
11322 if (partial == NULL)
11323 func_name = sortinfo->item_compare_func;
11324 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011325 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011326
11327 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11328 * in the copy without changing the original list items. */
11329 copy_tv(&si1->item->li_tv, &argv[0]);
11330 copy_tv(&si2->item->li_tv, &argv[1]);
11331
11332 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11333 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011334 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011335 partial, sortinfo->item_compare_selfdict);
11336 clear_tv(&argv[0]);
11337 clear_tv(&argv[1]);
11338
11339 if (res == FAIL)
11340 res = ITEM_COMPARE_FAIL;
11341 else
11342 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11343 if (sortinfo->item_compare_func_err)
11344 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11345 clear_tv(&rettv);
11346
11347 /* When the result would be zero, compare the pointers themselves. Makes
11348 * the sort stable. */
11349 if (res == 0 && !sortinfo->item_compare_keep_zero)
11350 res = si1->idx > si2->idx ? 1 : -1;
11351
11352 return res;
11353}
11354
11355/*
11356 * "sort({list})" function
11357 */
11358 static void
11359do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11360{
11361 list_T *l;
11362 listitem_T *li;
11363 sortItem_T *ptrs;
11364 sortinfo_T *old_sortinfo;
11365 sortinfo_T info;
11366 long len;
11367 long i;
11368
11369 /* Pointer to current info struct used in compare function. Save and
11370 * restore the current one for nested calls. */
11371 old_sortinfo = sortinfo;
11372 sortinfo = &info;
11373
11374 if (argvars[0].v_type != VAR_LIST)
11375 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11376 else
11377 {
11378 l = argvars[0].vval.v_list;
11379 if (l == NULL || tv_check_lock(l->lv_lock,
11380 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11381 TRUE))
11382 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011383 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384
11385 len = list_len(l);
11386 if (len <= 1)
11387 goto theend; /* short list sorts pretty quickly */
11388
11389 info.item_compare_ic = FALSE;
11390 info.item_compare_numeric = FALSE;
11391 info.item_compare_numbers = FALSE;
11392#ifdef FEAT_FLOAT
11393 info.item_compare_float = FALSE;
11394#endif
11395 info.item_compare_func = NULL;
11396 info.item_compare_partial = NULL;
11397 info.item_compare_selfdict = NULL;
11398 if (argvars[1].v_type != VAR_UNKNOWN)
11399 {
11400 /* optional second argument: {func} */
11401 if (argvars[1].v_type == VAR_FUNC)
11402 info.item_compare_func = argvars[1].vval.v_string;
11403 else if (argvars[1].v_type == VAR_PARTIAL)
11404 info.item_compare_partial = argvars[1].vval.v_partial;
11405 else
11406 {
11407 int error = FALSE;
11408
11409 i = (long)get_tv_number_chk(&argvars[1], &error);
11410 if (error)
11411 goto theend; /* type error; errmsg already given */
11412 if (i == 1)
11413 info.item_compare_ic = TRUE;
11414 else if (argvars[1].v_type != VAR_NUMBER)
11415 info.item_compare_func = get_tv_string(&argvars[1]);
11416 else if (i != 0)
11417 {
11418 EMSG(_(e_invarg));
11419 goto theend;
11420 }
11421 if (info.item_compare_func != NULL)
11422 {
11423 if (*info.item_compare_func == NUL)
11424 {
11425 /* empty string means default sort */
11426 info.item_compare_func = NULL;
11427 }
11428 else if (STRCMP(info.item_compare_func, "n") == 0)
11429 {
11430 info.item_compare_func = NULL;
11431 info.item_compare_numeric = TRUE;
11432 }
11433 else if (STRCMP(info.item_compare_func, "N") == 0)
11434 {
11435 info.item_compare_func = NULL;
11436 info.item_compare_numbers = TRUE;
11437 }
11438#ifdef FEAT_FLOAT
11439 else if (STRCMP(info.item_compare_func, "f") == 0)
11440 {
11441 info.item_compare_func = NULL;
11442 info.item_compare_float = TRUE;
11443 }
11444#endif
11445 else if (STRCMP(info.item_compare_func, "i") == 0)
11446 {
11447 info.item_compare_func = NULL;
11448 info.item_compare_ic = TRUE;
11449 }
11450 }
11451 }
11452
11453 if (argvars[2].v_type != VAR_UNKNOWN)
11454 {
11455 /* optional third argument: {dict} */
11456 if (argvars[2].v_type != VAR_DICT)
11457 {
11458 EMSG(_(e_dictreq));
11459 goto theend;
11460 }
11461 info.item_compare_selfdict = argvars[2].vval.v_dict;
11462 }
11463 }
11464
11465 /* Make an array with each entry pointing to an item in the List. */
11466 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11467 if (ptrs == NULL)
11468 goto theend;
11469
11470 i = 0;
11471 if (sort)
11472 {
11473 /* sort(): ptrs will be the list to sort */
11474 for (li = l->lv_first; li != NULL; li = li->li_next)
11475 {
11476 ptrs[i].item = li;
11477 ptrs[i].idx = i;
11478 ++i;
11479 }
11480
11481 info.item_compare_func_err = FALSE;
11482 info.item_compare_keep_zero = FALSE;
11483 /* test the compare function */
11484 if ((info.item_compare_func != NULL
11485 || info.item_compare_partial != NULL)
11486 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11487 == ITEM_COMPARE_FAIL)
11488 EMSG(_("E702: Sort compare function failed"));
11489 else
11490 {
11491 /* Sort the array with item pointers. */
11492 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11493 info.item_compare_func == NULL
11494 && info.item_compare_partial == NULL
11495 ? item_compare : item_compare2);
11496
11497 if (!info.item_compare_func_err)
11498 {
11499 /* Clear the List and append the items in sorted order. */
11500 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11501 l->lv_len = 0;
11502 for (i = 0; i < len; ++i)
11503 list_append(l, ptrs[i].item);
11504 }
11505 }
11506 }
11507 else
11508 {
11509 int (*item_compare_func_ptr)(const void *, const void *);
11510
11511 /* f_uniq(): ptrs will be a stack of items to remove */
11512 info.item_compare_func_err = FALSE;
11513 info.item_compare_keep_zero = TRUE;
11514 item_compare_func_ptr = info.item_compare_func != NULL
11515 || info.item_compare_partial != NULL
11516 ? item_compare2 : item_compare;
11517
11518 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11519 li = li->li_next)
11520 {
11521 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11522 == 0)
11523 ptrs[i++].item = li;
11524 if (info.item_compare_func_err)
11525 {
11526 EMSG(_("E882: Uniq compare function failed"));
11527 break;
11528 }
11529 }
11530
11531 if (!info.item_compare_func_err)
11532 {
11533 while (--i >= 0)
11534 {
11535 li = ptrs[i].item->li_next;
11536 ptrs[i].item->li_next = li->li_next;
11537 if (li->li_next != NULL)
11538 li->li_next->li_prev = ptrs[i].item;
11539 else
11540 l->lv_last = ptrs[i].item;
11541 list_fix_watch(l, li);
11542 listitem_free(li);
11543 l->lv_len--;
11544 }
11545 }
11546 }
11547
11548 vim_free(ptrs);
11549 }
11550theend:
11551 sortinfo = old_sortinfo;
11552}
11553
11554/*
11555 * "sort({list})" function
11556 */
11557 static void
11558f_sort(typval_T *argvars, typval_T *rettv)
11559{
11560 do_sort_uniq(argvars, rettv, TRUE);
11561}
11562
11563/*
11564 * "uniq({list})" function
11565 */
11566 static void
11567f_uniq(typval_T *argvars, typval_T *rettv)
11568{
11569 do_sort_uniq(argvars, rettv, FALSE);
11570}
11571
11572/*
11573 * "soundfold({word})" function
11574 */
11575 static void
11576f_soundfold(typval_T *argvars, typval_T *rettv)
11577{
11578 char_u *s;
11579
11580 rettv->v_type = VAR_STRING;
11581 s = get_tv_string(&argvars[0]);
11582#ifdef FEAT_SPELL
11583 rettv->vval.v_string = eval_soundfold(s);
11584#else
11585 rettv->vval.v_string = vim_strsave(s);
11586#endif
11587}
11588
11589/*
11590 * "spellbadword()" function
11591 */
11592 static void
11593f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11594{
11595 char_u *word = (char_u *)"";
11596 hlf_T attr = HLF_COUNT;
11597 int len = 0;
11598
11599 if (rettv_list_alloc(rettv) == FAIL)
11600 return;
11601
11602#ifdef FEAT_SPELL
11603 if (argvars[0].v_type == VAR_UNKNOWN)
11604 {
11605 /* Find the start and length of the badly spelled word. */
11606 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11607 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011608 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011609 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011610 curwin->w_set_curswant = TRUE;
11611 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011612 }
11613 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11614 {
11615 char_u *str = get_tv_string_chk(&argvars[0]);
11616 int capcol = -1;
11617
11618 if (str != NULL)
11619 {
11620 /* Check the argument for spelling. */
11621 while (*str != NUL)
11622 {
11623 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11624 if (attr != HLF_COUNT)
11625 {
11626 word = str;
11627 break;
11628 }
11629 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020011630 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011631 }
11632 }
11633 }
11634#endif
11635
11636 list_append_string(rettv->vval.v_list, word, len);
11637 list_append_string(rettv->vval.v_list, (char_u *)(
11638 attr == HLF_SPB ? "bad" :
11639 attr == HLF_SPR ? "rare" :
11640 attr == HLF_SPL ? "local" :
11641 attr == HLF_SPC ? "caps" :
11642 ""), -1);
11643}
11644
11645/*
11646 * "spellsuggest()" function
11647 */
11648 static void
11649f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11650{
11651#ifdef FEAT_SPELL
11652 char_u *str;
11653 int typeerr = FALSE;
11654 int maxcount;
11655 garray_T ga;
11656 int i;
11657 listitem_T *li;
11658 int need_capital = FALSE;
11659#endif
11660
11661 if (rettv_list_alloc(rettv) == FAIL)
11662 return;
11663
11664#ifdef FEAT_SPELL
11665 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11666 {
11667 str = get_tv_string(&argvars[0]);
11668 if (argvars[1].v_type != VAR_UNKNOWN)
11669 {
11670 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11671 if (maxcount <= 0)
11672 return;
11673 if (argvars[2].v_type != VAR_UNKNOWN)
11674 {
11675 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11676 if (typeerr)
11677 return;
11678 }
11679 }
11680 else
11681 maxcount = 25;
11682
11683 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11684
11685 for (i = 0; i < ga.ga_len; ++i)
11686 {
11687 str = ((char_u **)ga.ga_data)[i];
11688
11689 li = listitem_alloc();
11690 if (li == NULL)
11691 vim_free(str);
11692 else
11693 {
11694 li->li_tv.v_type = VAR_STRING;
11695 li->li_tv.v_lock = 0;
11696 li->li_tv.vval.v_string = str;
11697 list_append(rettv->vval.v_list, li);
11698 }
11699 }
11700 ga_clear(&ga);
11701 }
11702#endif
11703}
11704
11705 static void
11706f_split(typval_T *argvars, typval_T *rettv)
11707{
11708 char_u *str;
11709 char_u *end;
11710 char_u *pat = NULL;
11711 regmatch_T regmatch;
11712 char_u patbuf[NUMBUFLEN];
11713 char_u *save_cpo;
11714 int match;
11715 colnr_T col = 0;
11716 int keepempty = FALSE;
11717 int typeerr = FALSE;
11718
11719 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11720 save_cpo = p_cpo;
11721 p_cpo = (char_u *)"";
11722
11723 str = get_tv_string(&argvars[0]);
11724 if (argvars[1].v_type != VAR_UNKNOWN)
11725 {
11726 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11727 if (pat == NULL)
11728 typeerr = TRUE;
11729 if (argvars[2].v_type != VAR_UNKNOWN)
11730 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11731 }
11732 if (pat == NULL || *pat == NUL)
11733 pat = (char_u *)"[\\x01- ]\\+";
11734
11735 if (rettv_list_alloc(rettv) == FAIL)
11736 return;
11737 if (typeerr)
11738 return;
11739
11740 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11741 if (regmatch.regprog != NULL)
11742 {
11743 regmatch.rm_ic = FALSE;
11744 while (*str != NUL || keepempty)
11745 {
11746 if (*str == NUL)
11747 match = FALSE; /* empty item at the end */
11748 else
11749 match = vim_regexec_nl(&regmatch, str, col);
11750 if (match)
11751 end = regmatch.startp[0];
11752 else
11753 end = str + STRLEN(str);
11754 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11755 && *str != NUL && match && end < regmatch.endp[0]))
11756 {
11757 if (list_append_string(rettv->vval.v_list, str,
11758 (int)(end - str)) == FAIL)
11759 break;
11760 }
11761 if (!match)
11762 break;
11763 /* Advance to just after the match. */
11764 if (regmatch.endp[0] > str)
11765 col = 0;
11766 else
11767 {
11768 /* Don't get stuck at the same match. */
11769#ifdef FEAT_MBYTE
11770 col = (*mb_ptr2len)(regmatch.endp[0]);
11771#else
11772 col = 1;
11773#endif
11774 }
11775 str = regmatch.endp[0];
11776 }
11777
11778 vim_regfree(regmatch.regprog);
11779 }
11780
11781 p_cpo = save_cpo;
11782}
11783
11784#ifdef FEAT_FLOAT
11785/*
11786 * "sqrt()" function
11787 */
11788 static void
11789f_sqrt(typval_T *argvars, typval_T *rettv)
11790{
11791 float_T f = 0.0;
11792
11793 rettv->v_type = VAR_FLOAT;
11794 if (get_float_arg(argvars, &f) == OK)
11795 rettv->vval.v_float = sqrt(f);
11796 else
11797 rettv->vval.v_float = 0.0;
11798}
11799
11800/*
11801 * "str2float()" function
11802 */
11803 static void
11804f_str2float(typval_T *argvars, typval_T *rettv)
11805{
11806 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011807 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011808
Bram Moolenaar08243d22017-01-10 16:12:29 +010011809 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011810 p = skipwhite(p + 1);
11811 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011812 if (isneg)
11813 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011814 rettv->v_type = VAR_FLOAT;
11815}
11816#endif
11817
11818/*
11819 * "str2nr()" function
11820 */
11821 static void
11822f_str2nr(typval_T *argvars, typval_T *rettv)
11823{
11824 int base = 10;
11825 char_u *p;
11826 varnumber_T n;
11827 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011828 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011829
11830 if (argvars[1].v_type != VAR_UNKNOWN)
11831 {
11832 base = (int)get_tv_number(&argvars[1]);
11833 if (base != 2 && base != 8 && base != 10 && base != 16)
11834 {
11835 EMSG(_(e_invarg));
11836 return;
11837 }
11838 }
11839
11840 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011841 isneg = (*p == '-');
11842 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011843 p = skipwhite(p + 1);
11844 switch (base)
11845 {
11846 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11847 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11848 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11849 default: what = 0;
11850 }
11851 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011852 if (isneg)
11853 rettv->vval.v_number = -n;
11854 else
11855 rettv->vval.v_number = n;
11856
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011857}
11858
11859#ifdef HAVE_STRFTIME
11860/*
11861 * "strftime({format}[, {time}])" function
11862 */
11863 static void
11864f_strftime(typval_T *argvars, typval_T *rettv)
11865{
11866 char_u result_buf[256];
11867 struct tm *curtime;
11868 time_t seconds;
11869 char_u *p;
11870
11871 rettv->v_type = VAR_STRING;
11872
11873 p = get_tv_string(&argvars[0]);
11874 if (argvars[1].v_type == VAR_UNKNOWN)
11875 seconds = time(NULL);
11876 else
11877 seconds = (time_t)get_tv_number(&argvars[1]);
11878 curtime = localtime(&seconds);
11879 /* MSVC returns NULL for an invalid value of seconds. */
11880 if (curtime == NULL)
11881 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11882 else
11883 {
11884# ifdef FEAT_MBYTE
11885 vimconv_T conv;
11886 char_u *enc;
11887
11888 conv.vc_type = CONV_NONE;
11889 enc = enc_locale();
11890 convert_setup(&conv, p_enc, enc);
11891 if (conv.vc_type != CONV_NONE)
11892 p = string_convert(&conv, p, NULL);
11893# endif
11894 if (p != NULL)
11895 (void)strftime((char *)result_buf, sizeof(result_buf),
11896 (char *)p, curtime);
11897 else
11898 result_buf[0] = NUL;
11899
11900# ifdef FEAT_MBYTE
11901 if (conv.vc_type != CONV_NONE)
11902 vim_free(p);
11903 convert_setup(&conv, enc, p_enc);
11904 if (conv.vc_type != CONV_NONE)
11905 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11906 else
11907# endif
11908 rettv->vval.v_string = vim_strsave(result_buf);
11909
11910# ifdef FEAT_MBYTE
11911 /* Release conversion descriptors */
11912 convert_setup(&conv, NULL, NULL);
11913 vim_free(enc);
11914# endif
11915 }
11916}
11917#endif
11918
11919/*
11920 * "strgetchar()" function
11921 */
11922 static void
11923f_strgetchar(typval_T *argvars, typval_T *rettv)
11924{
11925 char_u *str;
11926 int len;
11927 int error = FALSE;
11928 int charidx;
11929
11930 rettv->vval.v_number = -1;
11931 str = get_tv_string_chk(&argvars[0]);
11932 if (str == NULL)
11933 return;
11934 len = (int)STRLEN(str);
11935 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11936 if (error)
11937 return;
11938#ifdef FEAT_MBYTE
11939 {
11940 int byteidx = 0;
11941
11942 while (charidx >= 0 && byteidx < len)
11943 {
11944 if (charidx == 0)
11945 {
11946 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11947 break;
11948 }
11949 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011950 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011951 }
11952 }
11953#else
11954 if (charidx < len)
11955 rettv->vval.v_number = str[charidx];
11956#endif
11957}
11958
11959/*
11960 * "stridx()" function
11961 */
11962 static void
11963f_stridx(typval_T *argvars, typval_T *rettv)
11964{
11965 char_u buf[NUMBUFLEN];
11966 char_u *needle;
11967 char_u *haystack;
11968 char_u *save_haystack;
11969 char_u *pos;
11970 int start_idx;
11971
11972 needle = get_tv_string_chk(&argvars[1]);
11973 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11974 rettv->vval.v_number = -1;
11975 if (needle == NULL || haystack == NULL)
11976 return; /* type error; errmsg already given */
11977
11978 if (argvars[2].v_type != VAR_UNKNOWN)
11979 {
11980 int error = FALSE;
11981
11982 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11983 if (error || start_idx >= (int)STRLEN(haystack))
11984 return;
11985 if (start_idx >= 0)
11986 haystack += start_idx;
11987 }
11988
11989 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11990 if (pos != NULL)
11991 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11992}
11993
11994/*
11995 * "string()" function
11996 */
11997 static void
11998f_string(typval_T *argvars, typval_T *rettv)
11999{
12000 char_u *tofree;
12001 char_u numbuf[NUMBUFLEN];
12002
12003 rettv->v_type = VAR_STRING;
12004 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12005 get_copyID());
12006 /* Make a copy if we have a value but it's not in allocated memory. */
12007 if (rettv->vval.v_string != NULL && tofree == NULL)
12008 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12009}
12010
12011/*
12012 * "strlen()" function
12013 */
12014 static void
12015f_strlen(typval_T *argvars, typval_T *rettv)
12016{
12017 rettv->vval.v_number = (varnumber_T)(STRLEN(
12018 get_tv_string(&argvars[0])));
12019}
12020
12021/*
12022 * "strchars()" function
12023 */
12024 static void
12025f_strchars(typval_T *argvars, typval_T *rettv)
12026{
12027 char_u *s = get_tv_string(&argvars[0]);
12028 int skipcc = 0;
12029#ifdef FEAT_MBYTE
12030 varnumber_T len = 0;
12031 int (*func_mb_ptr2char_adv)(char_u **pp);
12032#endif
12033
12034 if (argvars[1].v_type != VAR_UNKNOWN)
12035 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
12036 if (skipcc < 0 || skipcc > 1)
12037 EMSG(_(e_invarg));
12038 else
12039 {
12040#ifdef FEAT_MBYTE
12041 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12042 while (*s != NUL)
12043 {
12044 func_mb_ptr2char_adv(&s);
12045 ++len;
12046 }
12047 rettv->vval.v_number = len;
12048#else
12049 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12050#endif
12051 }
12052}
12053
12054/*
12055 * "strdisplaywidth()" function
12056 */
12057 static void
12058f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12059{
12060 char_u *s = get_tv_string(&argvars[0]);
12061 int col = 0;
12062
12063 if (argvars[1].v_type != VAR_UNKNOWN)
12064 col = (int)get_tv_number(&argvars[1]);
12065
12066 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12067}
12068
12069/*
12070 * "strwidth()" function
12071 */
12072 static void
12073f_strwidth(typval_T *argvars, typval_T *rettv)
12074{
12075 char_u *s = get_tv_string(&argvars[0]);
12076
12077 rettv->vval.v_number = (varnumber_T)(
12078#ifdef FEAT_MBYTE
12079 mb_string2cells(s, -1)
12080#else
12081 STRLEN(s)
12082#endif
12083 );
12084}
12085
12086/*
12087 * "strcharpart()" function
12088 */
12089 static void
12090f_strcharpart(typval_T *argvars, typval_T *rettv)
12091{
12092#ifdef FEAT_MBYTE
12093 char_u *p;
12094 int nchar;
12095 int nbyte = 0;
12096 int charlen;
12097 int len = 0;
12098 int slen;
12099 int error = FALSE;
12100
12101 p = get_tv_string(&argvars[0]);
12102 slen = (int)STRLEN(p);
12103
12104 nchar = (int)get_tv_number_chk(&argvars[1], &error);
12105 if (!error)
12106 {
12107 if (nchar > 0)
12108 while (nchar > 0 && nbyte < slen)
12109 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012110 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012111 --nchar;
12112 }
12113 else
12114 nbyte = nchar;
12115 if (argvars[2].v_type != VAR_UNKNOWN)
12116 {
12117 charlen = (int)get_tv_number(&argvars[2]);
12118 while (charlen > 0 && nbyte + len < slen)
12119 {
12120 int off = nbyte + len;
12121
12122 if (off < 0)
12123 len += 1;
12124 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012125 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012126 --charlen;
12127 }
12128 }
12129 else
12130 len = slen - nbyte; /* default: all bytes that are available. */
12131 }
12132
12133 /*
12134 * Only return the overlap between the specified part and the actual
12135 * string.
12136 */
12137 if (nbyte < 0)
12138 {
12139 len += nbyte;
12140 nbyte = 0;
12141 }
12142 else if (nbyte > slen)
12143 nbyte = slen;
12144 if (len < 0)
12145 len = 0;
12146 else if (nbyte + len > slen)
12147 len = slen - nbyte;
12148
12149 rettv->v_type = VAR_STRING;
12150 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12151#else
12152 f_strpart(argvars, rettv);
12153#endif
12154}
12155
12156/*
12157 * "strpart()" function
12158 */
12159 static void
12160f_strpart(typval_T *argvars, typval_T *rettv)
12161{
12162 char_u *p;
12163 int n;
12164 int len;
12165 int slen;
12166 int error = FALSE;
12167
12168 p = get_tv_string(&argvars[0]);
12169 slen = (int)STRLEN(p);
12170
12171 n = (int)get_tv_number_chk(&argvars[1], &error);
12172 if (error)
12173 len = 0;
12174 else if (argvars[2].v_type != VAR_UNKNOWN)
12175 len = (int)get_tv_number(&argvars[2]);
12176 else
12177 len = slen - n; /* default len: all bytes that are available. */
12178
12179 /*
12180 * Only return the overlap between the specified part and the actual
12181 * string.
12182 */
12183 if (n < 0)
12184 {
12185 len += n;
12186 n = 0;
12187 }
12188 else if (n > slen)
12189 n = slen;
12190 if (len < 0)
12191 len = 0;
12192 else if (n + len > slen)
12193 len = slen - n;
12194
12195 rettv->v_type = VAR_STRING;
12196 rettv->vval.v_string = vim_strnsave(p + n, len);
12197}
12198
12199/*
12200 * "strridx()" function
12201 */
12202 static void
12203f_strridx(typval_T *argvars, typval_T *rettv)
12204{
12205 char_u buf[NUMBUFLEN];
12206 char_u *needle;
12207 char_u *haystack;
12208 char_u *rest;
12209 char_u *lastmatch = NULL;
12210 int haystack_len, end_idx;
12211
12212 needle = get_tv_string_chk(&argvars[1]);
12213 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12214
12215 rettv->vval.v_number = -1;
12216 if (needle == NULL || haystack == NULL)
12217 return; /* type error; errmsg already given */
12218
12219 haystack_len = (int)STRLEN(haystack);
12220 if (argvars[2].v_type != VAR_UNKNOWN)
12221 {
12222 /* Third argument: upper limit for index */
12223 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12224 if (end_idx < 0)
12225 return; /* can never find a match */
12226 }
12227 else
12228 end_idx = haystack_len;
12229
12230 if (*needle == NUL)
12231 {
12232 /* Empty string matches past the end. */
12233 lastmatch = haystack + end_idx;
12234 }
12235 else
12236 {
12237 for (rest = haystack; *rest != '\0'; ++rest)
12238 {
12239 rest = (char_u *)strstr((char *)rest, (char *)needle);
12240 if (rest == NULL || rest > haystack + end_idx)
12241 break;
12242 lastmatch = rest;
12243 }
12244 }
12245
12246 if (lastmatch == NULL)
12247 rettv->vval.v_number = -1;
12248 else
12249 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12250}
12251
12252/*
12253 * "strtrans()" function
12254 */
12255 static void
12256f_strtrans(typval_T *argvars, typval_T *rettv)
12257{
12258 rettv->v_type = VAR_STRING;
12259 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12260}
12261
12262/*
12263 * "submatch()" function
12264 */
12265 static void
12266f_submatch(typval_T *argvars, typval_T *rettv)
12267{
12268 int error = FALSE;
12269 int no;
12270 int retList = 0;
12271
12272 no = (int)get_tv_number_chk(&argvars[0], &error);
12273 if (error)
12274 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012275 if (no < 0 || no >= NSUBEXP)
12276 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012277 EMSGN(_("E935: invalid submatch number: %d"), no);
12278 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012279 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012280 if (argvars[1].v_type != VAR_UNKNOWN)
12281 retList = (int)get_tv_number_chk(&argvars[1], &error);
12282 if (error)
12283 return;
12284
12285 if (retList == 0)
12286 {
12287 rettv->v_type = VAR_STRING;
12288 rettv->vval.v_string = reg_submatch(no);
12289 }
12290 else
12291 {
12292 rettv->v_type = VAR_LIST;
12293 rettv->vval.v_list = reg_submatch_list(no);
12294 }
12295}
12296
12297/*
12298 * "substitute()" function
12299 */
12300 static void
12301f_substitute(typval_T *argvars, typval_T *rettv)
12302{
12303 char_u patbuf[NUMBUFLEN];
12304 char_u subbuf[NUMBUFLEN];
12305 char_u flagsbuf[NUMBUFLEN];
12306
12307 char_u *str = get_tv_string_chk(&argvars[0]);
12308 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012309 char_u *sub = NULL;
12310 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012311 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12312
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012313 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12314 expr = &argvars[2];
12315 else
12316 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12317
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012318 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012319 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12320 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012321 rettv->vval.v_string = NULL;
12322 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012323 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012324}
12325
12326/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012327 * "swapinfo(swap_filename)" function
12328 */
12329 static void
12330f_swapinfo(typval_T *argvars, typval_T *rettv)
12331{
12332 if (rettv_dict_alloc(rettv) == OK)
12333 get_b0_dict(get_tv_string(argvars), rettv->vval.v_dict);
12334}
12335
12336/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012337 * "synID(lnum, col, trans)" function
12338 */
12339 static void
12340f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12341{
12342 int id = 0;
12343#ifdef FEAT_SYN_HL
12344 linenr_T lnum;
12345 colnr_T col;
12346 int trans;
12347 int transerr = FALSE;
12348
12349 lnum = get_tv_lnum(argvars); /* -1 on type error */
12350 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12351 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12352
12353 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12354 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12355 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12356#endif
12357
12358 rettv->vval.v_number = id;
12359}
12360
12361/*
12362 * "synIDattr(id, what [, mode])" function
12363 */
12364 static void
12365f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12366{
12367 char_u *p = NULL;
12368#ifdef FEAT_SYN_HL
12369 int id;
12370 char_u *what;
12371 char_u *mode;
12372 char_u modebuf[NUMBUFLEN];
12373 int modec;
12374
12375 id = (int)get_tv_number(&argvars[0]);
12376 what = get_tv_string(&argvars[1]);
12377 if (argvars[2].v_type != VAR_UNKNOWN)
12378 {
12379 mode = get_tv_string_buf(&argvars[2], modebuf);
12380 modec = TOLOWER_ASC(mode[0]);
12381 if (modec != 't' && modec != 'c' && modec != 'g')
12382 modec = 0; /* replace invalid with current */
12383 }
12384 else
12385 {
12386#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12387 if (USE_24BIT)
12388 modec = 'g';
12389 else
12390#endif
12391 if (t_colors > 1)
12392 modec = 'c';
12393 else
12394 modec = 't';
12395 }
12396
12397
12398 switch (TOLOWER_ASC(what[0]))
12399 {
12400 case 'b':
12401 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12402 p = highlight_color(id, what, modec);
12403 else /* bold */
12404 p = highlight_has_attr(id, HL_BOLD, modec);
12405 break;
12406
12407 case 'f': /* fg[#] or font */
12408 p = highlight_color(id, what, modec);
12409 break;
12410
12411 case 'i':
12412 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12413 p = highlight_has_attr(id, HL_INVERSE, modec);
12414 else /* italic */
12415 p = highlight_has_attr(id, HL_ITALIC, modec);
12416 break;
12417
12418 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012419 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012420 break;
12421
12422 case 'r': /* reverse */
12423 p = highlight_has_attr(id, HL_INVERSE, modec);
12424 break;
12425
12426 case 's':
12427 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12428 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012429 /* strikeout */
12430 else if (TOLOWER_ASC(what[1]) == 't' &&
12431 TOLOWER_ASC(what[2]) == 'r')
12432 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012433 else /* standout */
12434 p = highlight_has_attr(id, HL_STANDOUT, modec);
12435 break;
12436
12437 case 'u':
12438 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12439 /* underline */
12440 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12441 else
12442 /* undercurl */
12443 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12444 break;
12445 }
12446
12447 if (p != NULL)
12448 p = vim_strsave(p);
12449#endif
12450 rettv->v_type = VAR_STRING;
12451 rettv->vval.v_string = p;
12452}
12453
12454/*
12455 * "synIDtrans(id)" function
12456 */
12457 static void
12458f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12459{
12460 int id;
12461
12462#ifdef FEAT_SYN_HL
12463 id = (int)get_tv_number(&argvars[0]);
12464
12465 if (id > 0)
12466 id = syn_get_final_id(id);
12467 else
12468#endif
12469 id = 0;
12470
12471 rettv->vval.v_number = id;
12472}
12473
12474/*
12475 * "synconcealed(lnum, col)" function
12476 */
12477 static void
12478f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12479{
12480#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12481 linenr_T lnum;
12482 colnr_T col;
12483 int syntax_flags = 0;
12484 int cchar;
12485 int matchid = 0;
12486 char_u str[NUMBUFLEN];
12487#endif
12488
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012489 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012490
12491#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12492 lnum = get_tv_lnum(argvars); /* -1 on type error */
12493 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12494
12495 vim_memset(str, NUL, sizeof(str));
12496
12497 if (rettv_list_alloc(rettv) != FAIL)
12498 {
12499 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12500 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12501 && curwin->w_p_cole > 0)
12502 {
12503 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12504 syntax_flags = get_syntax_info(&matchid);
12505
12506 /* get the conceal character */
12507 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12508 {
12509 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012510 if (cchar == NUL && curwin->w_p_cole == 1)
12511 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012512 if (cchar != NUL)
12513 {
12514# ifdef FEAT_MBYTE
12515 if (has_mbyte)
12516 (*mb_char2bytes)(cchar, str);
12517 else
12518# endif
12519 str[0] = cchar;
12520 }
12521 }
12522 }
12523
12524 list_append_number(rettv->vval.v_list,
12525 (syntax_flags & HL_CONCEAL) != 0);
12526 /* -1 to auto-determine strlen */
12527 list_append_string(rettv->vval.v_list, str, -1);
12528 list_append_number(rettv->vval.v_list, matchid);
12529 }
12530#endif
12531}
12532
12533/*
12534 * "synstack(lnum, col)" function
12535 */
12536 static void
12537f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12538{
12539#ifdef FEAT_SYN_HL
12540 linenr_T lnum;
12541 colnr_T col;
12542 int i;
12543 int id;
12544#endif
12545
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012546 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012547
12548#ifdef FEAT_SYN_HL
12549 lnum = get_tv_lnum(argvars); /* -1 on type error */
12550 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12551
12552 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12553 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12554 && rettv_list_alloc(rettv) != FAIL)
12555 {
12556 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12557 for (i = 0; ; ++i)
12558 {
12559 id = syn_get_stack_item(i);
12560 if (id < 0)
12561 break;
12562 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12563 break;
12564 }
12565 }
12566#endif
12567}
12568
12569 static void
12570get_cmd_output_as_rettv(
12571 typval_T *argvars,
12572 typval_T *rettv,
12573 int retlist)
12574{
12575 char_u *res = NULL;
12576 char_u *p;
12577 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012578 int err = FALSE;
12579 FILE *fd;
12580 list_T *list = NULL;
12581 int flags = SHELL_SILENT;
12582
12583 rettv->v_type = VAR_STRING;
12584 rettv->vval.v_string = NULL;
12585 if (check_restricted() || check_secure())
12586 goto errret;
12587
12588 if (argvars[1].v_type != VAR_UNKNOWN)
12589 {
12590 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012591 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012592 * command.
12593 */
12594 if ((infile = vim_tempname('i', TRUE)) == NULL)
12595 {
12596 EMSG(_(e_notmp));
12597 goto errret;
12598 }
12599
12600 fd = mch_fopen((char *)infile, WRITEBIN);
12601 if (fd == NULL)
12602 {
12603 EMSG2(_(e_notopen), infile);
12604 goto errret;
12605 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012606 if (argvars[1].v_type == VAR_NUMBER)
12607 {
12608 linenr_T lnum;
12609 buf_T *buf;
12610
12611 buf = buflist_findnr(argvars[1].vval.v_number);
12612 if (buf == NULL)
12613 {
12614 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012615 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012616 goto errret;
12617 }
12618
12619 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12620 {
12621 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12622 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12623 {
12624 err = TRUE;
12625 break;
12626 }
12627 if (putc(NL, fd) == EOF)
12628 {
12629 err = TRUE;
12630 break;
12631 }
12632 }
12633 }
12634 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012635 {
12636 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12637 err = TRUE;
12638 }
12639 else
12640 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012641 size_t len;
12642 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012643
12644 p = get_tv_string_buf_chk(&argvars[1], buf);
12645 if (p == NULL)
12646 {
12647 fclose(fd);
12648 goto errret; /* type error; errmsg already given */
12649 }
12650 len = STRLEN(p);
12651 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12652 err = TRUE;
12653 }
12654 if (fclose(fd) != 0)
12655 err = TRUE;
12656 if (err)
12657 {
12658 EMSG(_("E677: Error writing temp file"));
12659 goto errret;
12660 }
12661 }
12662
12663 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12664 * echoes typeahead, that messes up the display. */
12665 if (!msg_silent)
12666 flags += SHELL_COOKED;
12667
12668 if (retlist)
12669 {
12670 int len;
12671 listitem_T *li;
12672 char_u *s = NULL;
12673 char_u *start;
12674 char_u *end;
12675 int i;
12676
12677 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12678 if (res == NULL)
12679 goto errret;
12680
12681 list = list_alloc();
12682 if (list == NULL)
12683 goto errret;
12684
12685 for (i = 0; i < len; ++i)
12686 {
12687 start = res + i;
12688 while (i < len && res[i] != NL)
12689 ++i;
12690 end = res + i;
12691
12692 s = alloc((unsigned)(end - start + 1));
12693 if (s == NULL)
12694 goto errret;
12695
12696 for (p = s; start < end; ++p, ++start)
12697 *p = *start == NUL ? NL : *start;
12698 *p = NUL;
12699
12700 li = listitem_alloc();
12701 if (li == NULL)
12702 {
12703 vim_free(s);
12704 goto errret;
12705 }
12706 li->li_tv.v_type = VAR_STRING;
12707 li->li_tv.v_lock = 0;
12708 li->li_tv.vval.v_string = s;
12709 list_append(list, li);
12710 }
12711
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012712 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012713 list = NULL;
12714 }
12715 else
12716 {
12717 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12718#ifdef USE_CR
12719 /* translate <CR> into <NL> */
12720 if (res != NULL)
12721 {
12722 char_u *s;
12723
12724 for (s = res; *s; ++s)
12725 {
12726 if (*s == CAR)
12727 *s = NL;
12728 }
12729 }
12730#else
12731# ifdef USE_CRNL
12732 /* translate <CR><NL> into <NL> */
12733 if (res != NULL)
12734 {
12735 char_u *s, *d;
12736
12737 d = res;
12738 for (s = res; *s; ++s)
12739 {
12740 if (s[0] == CAR && s[1] == NL)
12741 ++s;
12742 *d++ = *s;
12743 }
12744 *d = NUL;
12745 }
12746# endif
12747#endif
12748 rettv->vval.v_string = res;
12749 res = NULL;
12750 }
12751
12752errret:
12753 if (infile != NULL)
12754 {
12755 mch_remove(infile);
12756 vim_free(infile);
12757 }
12758 if (res != NULL)
12759 vim_free(res);
12760 if (list != NULL)
12761 list_free(list);
12762}
12763
12764/*
12765 * "system()" function
12766 */
12767 static void
12768f_system(typval_T *argvars, typval_T *rettv)
12769{
12770 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12771}
12772
12773/*
12774 * "systemlist()" function
12775 */
12776 static void
12777f_systemlist(typval_T *argvars, typval_T *rettv)
12778{
12779 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12780}
12781
12782/*
12783 * "tabpagebuflist()" function
12784 */
12785 static void
12786f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12787{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012788 tabpage_T *tp;
12789 win_T *wp = NULL;
12790
12791 if (argvars[0].v_type == VAR_UNKNOWN)
12792 wp = firstwin;
12793 else
12794 {
12795 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12796 if (tp != NULL)
12797 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12798 }
12799 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12800 {
12801 for (; wp != NULL; wp = wp->w_next)
12802 if (list_append_number(rettv->vval.v_list,
12803 wp->w_buffer->b_fnum) == FAIL)
12804 break;
12805 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012806}
12807
12808
12809/*
12810 * "tabpagenr()" function
12811 */
12812 static void
12813f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12814{
12815 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012816 char_u *arg;
12817
12818 if (argvars[0].v_type != VAR_UNKNOWN)
12819 {
12820 arg = get_tv_string_chk(&argvars[0]);
12821 nr = 0;
12822 if (arg != NULL)
12823 {
12824 if (STRCMP(arg, "$") == 0)
12825 nr = tabpage_index(NULL) - 1;
12826 else
12827 EMSG2(_(e_invexpr2), arg);
12828 }
12829 }
12830 else
12831 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012832 rettv->vval.v_number = nr;
12833}
12834
12835
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012836static int get_winnr(tabpage_T *tp, typval_T *argvar);
12837
12838/*
12839 * Common code for tabpagewinnr() and winnr().
12840 */
12841 static int
12842get_winnr(tabpage_T *tp, typval_T *argvar)
12843{
12844 win_T *twin;
12845 int nr = 1;
12846 win_T *wp;
12847 char_u *arg;
12848
12849 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12850 if (argvar->v_type != VAR_UNKNOWN)
12851 {
12852 arg = get_tv_string_chk(argvar);
12853 if (arg == NULL)
12854 nr = 0; /* type error; errmsg already given */
12855 else if (STRCMP(arg, "$") == 0)
12856 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12857 else if (STRCMP(arg, "#") == 0)
12858 {
12859 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12860 if (twin == NULL)
12861 nr = 0;
12862 }
12863 else
12864 {
12865 EMSG2(_(e_invexpr2), arg);
12866 nr = 0;
12867 }
12868 }
12869
12870 if (nr > 0)
12871 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12872 wp != twin; wp = wp->w_next)
12873 {
12874 if (wp == NULL)
12875 {
12876 /* didn't find it in this tabpage */
12877 nr = 0;
12878 break;
12879 }
12880 ++nr;
12881 }
12882 return nr;
12883}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012884
12885/*
12886 * "tabpagewinnr()" function
12887 */
12888 static void
12889f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12890{
12891 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012892 tabpage_T *tp;
12893
12894 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12895 if (tp == NULL)
12896 nr = 0;
12897 else
12898 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012899 rettv->vval.v_number = nr;
12900}
12901
12902
12903/*
12904 * "tagfiles()" function
12905 */
12906 static void
12907f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12908{
12909 char_u *fname;
12910 tagname_T tn;
12911 int first;
12912
12913 if (rettv_list_alloc(rettv) == FAIL)
12914 return;
12915 fname = alloc(MAXPATHL);
12916 if (fname == NULL)
12917 return;
12918
12919 for (first = TRUE; ; first = FALSE)
12920 if (get_tagfname(&tn, first, fname) == FAIL
12921 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12922 break;
12923 tagname_free(&tn);
12924 vim_free(fname);
12925}
12926
12927/*
12928 * "taglist()" function
12929 */
12930 static void
12931f_taglist(typval_T *argvars, typval_T *rettv)
12932{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012933 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012934 char_u *tag_pattern;
12935
12936 tag_pattern = get_tv_string(&argvars[0]);
12937
12938 rettv->vval.v_number = FALSE;
12939 if (*tag_pattern == NUL)
12940 return;
12941
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012942 if (argvars[1].v_type != VAR_UNKNOWN)
12943 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012944 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012945 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012946}
12947
12948/*
12949 * "tempname()" function
12950 */
12951 static void
12952f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12953{
12954 static int x = 'A';
12955
12956 rettv->v_type = VAR_STRING;
12957 rettv->vval.v_string = vim_tempname(x, FALSE);
12958
12959 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12960 * names. Skip 'I' and 'O', they are used for shell redirection. */
12961 do
12962 {
12963 if (x == 'Z')
12964 x = '0';
12965 else if (x == '9')
12966 x = 'A';
12967 else
12968 {
12969#ifdef EBCDIC
12970 if (x == 'I')
12971 x = 'J';
12972 else if (x == 'R')
12973 x = 'S';
12974 else
12975#endif
12976 ++x;
12977 }
12978 } while (x == 'I' || x == 'O');
12979}
12980
12981#ifdef FEAT_FLOAT
12982/*
12983 * "tan()" function
12984 */
12985 static void
12986f_tan(typval_T *argvars, typval_T *rettv)
12987{
12988 float_T f = 0.0;
12989
12990 rettv->v_type = VAR_FLOAT;
12991 if (get_float_arg(argvars, &f) == OK)
12992 rettv->vval.v_float = tan(f);
12993 else
12994 rettv->vval.v_float = 0.0;
12995}
12996
12997/*
12998 * "tanh()" function
12999 */
13000 static void
13001f_tanh(typval_T *argvars, typval_T *rettv)
13002{
13003 float_T f = 0.0;
13004
13005 rettv->v_type = VAR_FLOAT;
13006 if (get_float_arg(argvars, &f) == OK)
13007 rettv->vval.v_float = tanh(f);
13008 else
13009 rettv->vval.v_float = 0.0;
13010}
13011#endif
13012
13013/*
13014 * "test_alloc_fail(id, countdown, repeat)" function
13015 */
13016 static void
13017f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13018{
13019 if (argvars[0].v_type != VAR_NUMBER
13020 || argvars[0].vval.v_number <= 0
13021 || argvars[1].v_type != VAR_NUMBER
13022 || argvars[1].vval.v_number < 0
13023 || argvars[2].v_type != VAR_NUMBER)
13024 EMSG(_(e_invarg));
13025 else
13026 {
13027 alloc_fail_id = argvars[0].vval.v_number;
13028 if (alloc_fail_id >= aid_last)
13029 EMSG(_(e_invarg));
13030 alloc_fail_countdown = argvars[1].vval.v_number;
13031 alloc_fail_repeat = argvars[2].vval.v_number;
13032 did_outofmem_msg = FALSE;
13033 }
13034}
13035
13036/*
13037 * "test_autochdir()"
13038 */
13039 static void
13040f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13041{
13042#if defined(FEAT_AUTOCHDIR)
13043 test_autochdir = TRUE;
13044#endif
13045}
13046
13047/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013048 * "test_feedinput()"
13049 */
13050 static void
13051f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13052{
13053#ifdef USE_INPUT_BUF
13054 char_u *val = get_tv_string_chk(&argvars[0]);
13055
13056 if (val != NULL)
13057 {
13058 trash_input_buf();
13059 add_to_input_buf_csi(val, (int)STRLEN(val));
13060 }
13061#endif
13062}
13063
13064/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013065 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013066 */
13067 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013068f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013069{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013070 char_u *name = (char_u *)"";
13071 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013072 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013073
13074 if (argvars[0].v_type != VAR_STRING
13075 || (argvars[1].v_type) != VAR_NUMBER)
13076 EMSG(_(e_invarg));
13077 else
13078 {
13079 name = get_tv_string_chk(&argvars[0]);
13080 val = (int)get_tv_number(&argvars[1]);
13081
13082 if (STRCMP(name, (char_u *)"redraw") == 0)
13083 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013084 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13085 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013086 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13087 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013088 else if (STRCMP(name, (char_u *)"starting") == 0)
13089 {
13090 if (val)
13091 {
13092 if (save_starting < 0)
13093 save_starting = starting;
13094 starting = 0;
13095 }
13096 else
13097 {
13098 starting = save_starting;
13099 save_starting = -1;
13100 }
13101 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013102 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13103 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013104 else if (STRCMP(name, (char_u *)"ALL") == 0)
13105 {
13106 disable_char_avail_for_testing = FALSE;
13107 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013108 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013109 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013110 if (save_starting >= 0)
13111 {
13112 starting = save_starting;
13113 save_starting = -1;
13114 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013115 }
13116 else
13117 EMSG2(_(e_invarg2), name);
13118 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013119}
13120
13121/*
13122 * "test_garbagecollect_now()" function
13123 */
13124 static void
13125f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13126{
13127 /* This is dangerous, any Lists and Dicts used internally may be freed
13128 * while still in use. */
13129 garbage_collect(TRUE);
13130}
13131
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013132/*
13133 * "test_ignore_error()" function
13134 */
13135 static void
13136f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13137{
13138 ignore_error_for_testing(get_tv_string(&argvars[0]));
13139}
13140
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013141#ifdef FEAT_JOB_CHANNEL
13142 static void
13143f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13144{
13145 rettv->v_type = VAR_CHANNEL;
13146 rettv->vval.v_channel = NULL;
13147}
13148#endif
13149
13150 static void
13151f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13152{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013153 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013154}
13155
13156#ifdef FEAT_JOB_CHANNEL
13157 static void
13158f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13159{
13160 rettv->v_type = VAR_JOB;
13161 rettv->vval.v_job = NULL;
13162}
13163#endif
13164
13165 static void
13166f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13167{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013168 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013169}
13170
13171 static void
13172f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13173{
13174 rettv->v_type = VAR_PARTIAL;
13175 rettv->vval.v_partial = NULL;
13176}
13177
13178 static void
13179f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13180{
13181 rettv->v_type = VAR_STRING;
13182 rettv->vval.v_string = NULL;
13183}
13184
13185 static void
13186f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13187{
13188 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13189}
13190
13191#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13192/*
13193 * Get a callback from "arg". It can be a Funcref or a function name.
13194 * When "arg" is zero return an empty string.
13195 * Return NULL for an invalid argument.
13196 */
13197 char_u *
13198get_callback(typval_T *arg, partial_T **pp)
13199{
13200 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13201 {
13202 *pp = arg->vval.v_partial;
13203 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013204 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013205 }
13206 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013207 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013208 {
13209 func_ref(arg->vval.v_string);
13210 return arg->vval.v_string;
13211 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013212 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13213 return (char_u *)"";
13214 EMSG(_("E921: Invalid callback argument"));
13215 return NULL;
13216}
13217
13218/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013219 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013220 */
13221 void
13222free_callback(char_u *callback, partial_T *partial)
13223{
13224 if (partial != NULL)
13225 partial_unref(partial);
13226 else if (callback != NULL)
13227 {
13228 func_unref(callback);
13229 vim_free(callback);
13230 }
13231}
13232#endif
13233
13234#ifdef FEAT_TIMERS
13235/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013236 * "timer_info([timer])" function
13237 */
13238 static void
13239f_timer_info(typval_T *argvars, typval_T *rettv)
13240{
13241 timer_T *timer = NULL;
13242
13243 if (rettv_list_alloc(rettv) != OK)
13244 return;
13245 if (argvars[0].v_type != VAR_UNKNOWN)
13246 {
13247 if (argvars[0].v_type != VAR_NUMBER)
13248 EMSG(_(e_number_exp));
13249 else
13250 {
13251 timer = find_timer((int)get_tv_number(&argvars[0]));
13252 if (timer != NULL)
13253 add_timer_info(rettv, timer);
13254 }
13255 }
13256 else
13257 add_timer_info_all(rettv);
13258}
13259
13260/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013261 * "timer_pause(timer, paused)" function
13262 */
13263 static void
13264f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13265{
13266 timer_T *timer = NULL;
13267 int paused = (int)get_tv_number(&argvars[1]);
13268
13269 if (argvars[0].v_type != VAR_NUMBER)
13270 EMSG(_(e_number_exp));
13271 else
13272 {
13273 timer = find_timer((int)get_tv_number(&argvars[0]));
13274 if (timer != NULL)
13275 timer->tr_paused = paused;
13276 }
13277}
13278
13279/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013280 * "timer_start(time, callback [, options])" function
13281 */
13282 static void
13283f_timer_start(typval_T *argvars, typval_T *rettv)
13284{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013285 long msec = (long)get_tv_number(&argvars[0]);
13286 timer_T *timer;
13287 int repeat = 0;
13288 char_u *callback;
13289 dict_T *dict;
13290 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013291
Bram Moolenaar75537a92016-09-05 22:45:28 +020013292 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013293 if (check_secure())
13294 return;
13295 if (argvars[2].v_type != VAR_UNKNOWN)
13296 {
13297 if (argvars[2].v_type != VAR_DICT
13298 || (dict = argvars[2].vval.v_dict) == NULL)
13299 {
13300 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13301 return;
13302 }
13303 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13304 repeat = get_dict_number(dict, (char_u *)"repeat");
13305 }
13306
Bram Moolenaar75537a92016-09-05 22:45:28 +020013307 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013308 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013309 return;
13310
13311 timer = create_timer(msec, repeat);
13312 if (timer == NULL)
13313 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013314 else
13315 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013316 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013317 timer->tr_callback = vim_strsave(callback);
13318 else
13319 /* pointer into the partial */
13320 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013321 timer->tr_partial = partial;
13322 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013323 }
13324}
13325
13326/*
13327 * "timer_stop(timer)" function
13328 */
13329 static void
13330f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13331{
13332 timer_T *timer;
13333
13334 if (argvars[0].v_type != VAR_NUMBER)
13335 {
13336 EMSG(_(e_number_exp));
13337 return;
13338 }
13339 timer = find_timer((int)get_tv_number(&argvars[0]));
13340 if (timer != NULL)
13341 stop_timer(timer);
13342}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013343
13344/*
13345 * "timer_stopall()" function
13346 */
13347 static void
13348f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13349{
13350 stop_all_timers();
13351}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013352#endif
13353
13354/*
13355 * "tolower(string)" function
13356 */
13357 static void
13358f_tolower(typval_T *argvars, typval_T *rettv)
13359{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013360 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013361 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013362}
13363
13364/*
13365 * "toupper(string)" function
13366 */
13367 static void
13368f_toupper(typval_T *argvars, typval_T *rettv)
13369{
13370 rettv->v_type = VAR_STRING;
13371 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13372}
13373
13374/*
13375 * "tr(string, fromstr, tostr)" function
13376 */
13377 static void
13378f_tr(typval_T *argvars, typval_T *rettv)
13379{
13380 char_u *in_str;
13381 char_u *fromstr;
13382 char_u *tostr;
13383 char_u *p;
13384#ifdef FEAT_MBYTE
13385 int inlen;
13386 int fromlen;
13387 int tolen;
13388 int idx;
13389 char_u *cpstr;
13390 int cplen;
13391 int first = TRUE;
13392#endif
13393 char_u buf[NUMBUFLEN];
13394 char_u buf2[NUMBUFLEN];
13395 garray_T ga;
13396
13397 in_str = get_tv_string(&argvars[0]);
13398 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13399 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13400
13401 /* Default return value: empty string. */
13402 rettv->v_type = VAR_STRING;
13403 rettv->vval.v_string = NULL;
13404 if (fromstr == NULL || tostr == NULL)
13405 return; /* type error; errmsg already given */
13406 ga_init2(&ga, (int)sizeof(char), 80);
13407
13408#ifdef FEAT_MBYTE
13409 if (!has_mbyte)
13410#endif
13411 /* not multi-byte: fromstr and tostr must be the same length */
13412 if (STRLEN(fromstr) != STRLEN(tostr))
13413 {
13414#ifdef FEAT_MBYTE
13415error:
13416#endif
13417 EMSG2(_(e_invarg2), fromstr);
13418 ga_clear(&ga);
13419 return;
13420 }
13421
13422 /* fromstr and tostr have to contain the same number of chars */
13423 while (*in_str != NUL)
13424 {
13425#ifdef FEAT_MBYTE
13426 if (has_mbyte)
13427 {
13428 inlen = (*mb_ptr2len)(in_str);
13429 cpstr = in_str;
13430 cplen = inlen;
13431 idx = 0;
13432 for (p = fromstr; *p != NUL; p += fromlen)
13433 {
13434 fromlen = (*mb_ptr2len)(p);
13435 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13436 {
13437 for (p = tostr; *p != NUL; p += tolen)
13438 {
13439 tolen = (*mb_ptr2len)(p);
13440 if (idx-- == 0)
13441 {
13442 cplen = tolen;
13443 cpstr = p;
13444 break;
13445 }
13446 }
13447 if (*p == NUL) /* tostr is shorter than fromstr */
13448 goto error;
13449 break;
13450 }
13451 ++idx;
13452 }
13453
13454 if (first && cpstr == in_str)
13455 {
13456 /* Check that fromstr and tostr have the same number of
13457 * (multi-byte) characters. Done only once when a character
13458 * of in_str doesn't appear in fromstr. */
13459 first = FALSE;
13460 for (p = tostr; *p != NUL; p += tolen)
13461 {
13462 tolen = (*mb_ptr2len)(p);
13463 --idx;
13464 }
13465 if (idx != 0)
13466 goto error;
13467 }
13468
13469 (void)ga_grow(&ga, cplen);
13470 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13471 ga.ga_len += cplen;
13472
13473 in_str += inlen;
13474 }
13475 else
13476#endif
13477 {
13478 /* When not using multi-byte chars we can do it faster. */
13479 p = vim_strchr(fromstr, *in_str);
13480 if (p != NULL)
13481 ga_append(&ga, tostr[p - fromstr]);
13482 else
13483 ga_append(&ga, *in_str);
13484 ++in_str;
13485 }
13486 }
13487
13488 /* add a terminating NUL */
13489 (void)ga_grow(&ga, 1);
13490 ga_append(&ga, NUL);
13491
13492 rettv->vval.v_string = ga.ga_data;
13493}
13494
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013495/*
13496 * "trim({expr})" function
13497 */
13498 static void
13499f_trim(typval_T *argvars, typval_T *rettv)
13500{
13501 char_u buf1[NUMBUFLEN];
13502 char_u buf2[NUMBUFLEN];
13503 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13504 char_u *mask = NULL;
13505 char_u *tail;
13506 char_u *prev;
13507 char_u *p;
13508 int c1;
13509
13510 rettv->v_type = VAR_STRING;
13511 if (head == NULL)
13512 {
13513 rettv->vval.v_string = NULL;
13514 return;
13515 }
13516
13517 if (argvars[1].v_type == VAR_STRING)
13518 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13519
13520 while (*head != NUL)
13521 {
13522 c1 = PTR2CHAR(head);
13523 if (mask == NULL)
13524 {
13525 if (c1 > ' ' && c1 != 0xa0)
13526 break;
13527 }
13528 else
13529 {
13530 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13531 if (c1 == PTR2CHAR(p))
13532 break;
13533 if (*p == NUL)
13534 break;
13535 }
13536 MB_PTR_ADV(head);
13537 }
13538
13539 for (tail = head + STRLEN(head); tail > head; tail = prev)
13540 {
13541 prev = tail;
13542 MB_PTR_BACK(head, prev);
13543 c1 = PTR2CHAR(prev);
13544 if (mask == NULL)
13545 {
13546 if (c1 > ' ' && c1 != 0xa0)
13547 break;
13548 }
13549 else
13550 {
13551 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13552 if (c1 == PTR2CHAR(p))
13553 break;
13554 if (*p == NUL)
13555 break;
13556 }
13557 }
13558 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13559}
13560
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013561#ifdef FEAT_FLOAT
13562/*
13563 * "trunc({float})" function
13564 */
13565 static void
13566f_trunc(typval_T *argvars, typval_T *rettv)
13567{
13568 float_T f = 0.0;
13569
13570 rettv->v_type = VAR_FLOAT;
13571 if (get_float_arg(argvars, &f) == OK)
13572 /* trunc() is not in C90, use floor() or ceil() instead. */
13573 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13574 else
13575 rettv->vval.v_float = 0.0;
13576}
13577#endif
13578
13579/*
13580 * "type(expr)" function
13581 */
13582 static void
13583f_type(typval_T *argvars, typval_T *rettv)
13584{
13585 int n = -1;
13586
13587 switch (argvars[0].v_type)
13588 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013589 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13590 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013591 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013592 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13593 case VAR_LIST: n = VAR_TYPE_LIST; break;
13594 case VAR_DICT: n = VAR_TYPE_DICT; break;
13595 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013596 case VAR_SPECIAL:
13597 if (argvars[0].vval.v_number == VVAL_FALSE
13598 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013599 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013600 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013601 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013602 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013603 case VAR_JOB: n = VAR_TYPE_JOB; break;
13604 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013605 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013606 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013607 n = -1;
13608 break;
13609 }
13610 rettv->vval.v_number = n;
13611}
13612
13613/*
13614 * "undofile(name)" function
13615 */
13616 static void
13617f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13618{
13619 rettv->v_type = VAR_STRING;
13620#ifdef FEAT_PERSISTENT_UNDO
13621 {
13622 char_u *fname = get_tv_string(&argvars[0]);
13623
13624 if (*fname == NUL)
13625 {
13626 /* If there is no file name there will be no undo file. */
13627 rettv->vval.v_string = NULL;
13628 }
13629 else
13630 {
13631 char_u *ffname = FullName_save(fname, FALSE);
13632
13633 if (ffname != NULL)
13634 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13635 vim_free(ffname);
13636 }
13637 }
13638#else
13639 rettv->vval.v_string = NULL;
13640#endif
13641}
13642
13643/*
13644 * "undotree()" function
13645 */
13646 static void
13647f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13648{
13649 if (rettv_dict_alloc(rettv) == OK)
13650 {
13651 dict_T *dict = rettv->vval.v_dict;
13652 list_T *list;
13653
Bram Moolenaare0be1672018-07-08 16:50:37 +020013654 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
13655 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
13656 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
13657 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
13658 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
13659 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013660
13661 list = list_alloc();
13662 if (list != NULL)
13663 {
13664 u_eval_tree(curbuf->b_u_oldhead, list);
13665 dict_add_list(dict, "entries", list);
13666 }
13667 }
13668}
13669
13670/*
13671 * "values(dict)" function
13672 */
13673 static void
13674f_values(typval_T *argvars, typval_T *rettv)
13675{
13676 dict_list(argvars, rettv, 1);
13677}
13678
13679/*
13680 * "virtcol(string)" function
13681 */
13682 static void
13683f_virtcol(typval_T *argvars, typval_T *rettv)
13684{
13685 colnr_T vcol = 0;
13686 pos_T *fp;
13687 int fnum = curbuf->b_fnum;
13688
13689 fp = var2fpos(&argvars[0], FALSE, &fnum);
13690 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13691 && fnum == curbuf->b_fnum)
13692 {
13693 getvvcol(curwin, fp, NULL, NULL, &vcol);
13694 ++vcol;
13695 }
13696
13697 rettv->vval.v_number = vcol;
13698}
13699
13700/*
13701 * "visualmode()" function
13702 */
13703 static void
13704f_visualmode(typval_T *argvars, typval_T *rettv)
13705{
13706 char_u str[2];
13707
13708 rettv->v_type = VAR_STRING;
13709 str[0] = curbuf->b_visual_mode_eval;
13710 str[1] = NUL;
13711 rettv->vval.v_string = vim_strsave(str);
13712
13713 /* A non-zero number or non-empty string argument: reset mode. */
13714 if (non_zero_arg(&argvars[0]))
13715 curbuf->b_visual_mode_eval = NUL;
13716}
13717
13718/*
13719 * "wildmenumode()" function
13720 */
13721 static void
13722f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13723{
13724#ifdef FEAT_WILDMENU
13725 if (wild_menu_showing)
13726 rettv->vval.v_number = 1;
13727#endif
13728}
13729
13730/*
13731 * "winbufnr(nr)" function
13732 */
13733 static void
13734f_winbufnr(typval_T *argvars, typval_T *rettv)
13735{
13736 win_T *wp;
13737
13738 wp = find_win_by_nr(&argvars[0], NULL);
13739 if (wp == NULL)
13740 rettv->vval.v_number = -1;
13741 else
13742 rettv->vval.v_number = wp->w_buffer->b_fnum;
13743}
13744
13745/*
13746 * "wincol()" function
13747 */
13748 static void
13749f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13750{
13751 validate_cursor();
13752 rettv->vval.v_number = curwin->w_wcol + 1;
13753}
13754
13755/*
13756 * "winheight(nr)" function
13757 */
13758 static void
13759f_winheight(typval_T *argvars, typval_T *rettv)
13760{
13761 win_T *wp;
13762
13763 wp = find_win_by_nr(&argvars[0], NULL);
13764 if (wp == NULL)
13765 rettv->vval.v_number = -1;
13766 else
13767 rettv->vval.v_number = wp->w_height;
13768}
13769
13770/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020013771 * "winlayout()" function
13772 */
13773 static void
13774f_winlayout(typval_T *argvars, typval_T *rettv)
13775{
13776 tabpage_T *tp;
13777
13778 if (rettv_list_alloc(rettv) != OK)
13779 return;
13780
13781 if (argvars[0].v_type == VAR_UNKNOWN)
13782 tp = curtab;
13783 else
13784 {
13785 tp = find_tabpage((int)get_tv_number(&argvars[0]));
13786 if (tp == NULL)
13787 return;
13788 }
13789
13790 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
13791}
13792
13793/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013794 * "winline()" function
13795 */
13796 static void
13797f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13798{
13799 validate_cursor();
13800 rettv->vval.v_number = curwin->w_wrow + 1;
13801}
13802
13803/*
13804 * "winnr()" function
13805 */
13806 static void
13807f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13808{
13809 int nr = 1;
13810
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013811 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013812 rettv->vval.v_number = nr;
13813}
13814
13815/*
13816 * "winrestcmd()" function
13817 */
13818 static void
13819f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13820{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013821 win_T *wp;
13822 int winnr = 1;
13823 garray_T ga;
13824 char_u buf[50];
13825
13826 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013827 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013828 {
13829 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13830 ga_concat(&ga, buf);
13831 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13832 ga_concat(&ga, buf);
13833 ++winnr;
13834 }
13835 ga_append(&ga, NUL);
13836
13837 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013838 rettv->v_type = VAR_STRING;
13839}
13840
13841/*
13842 * "winrestview()" function
13843 */
13844 static void
13845f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13846{
13847 dict_T *dict;
13848
13849 if (argvars[0].v_type != VAR_DICT
13850 || (dict = argvars[0].vval.v_dict) == NULL)
13851 EMSG(_(e_invarg));
13852 else
13853 {
13854 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13855 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13856 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13857 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13858#ifdef FEAT_VIRTUALEDIT
13859 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13860 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13861#endif
13862 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13863 {
13864 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13865 curwin->w_set_curswant = FALSE;
13866 }
13867
13868 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13869 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13870#ifdef FEAT_DIFF
13871 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13872 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13873#endif
13874 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13875 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13876 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13877 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13878
13879 check_cursor();
13880 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013881 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013882 changed_window_setting();
13883
13884 if (curwin->w_topline <= 0)
13885 curwin->w_topline = 1;
13886 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13887 curwin->w_topline = curbuf->b_ml.ml_line_count;
13888#ifdef FEAT_DIFF
13889 check_topfill(curwin, TRUE);
13890#endif
13891 }
13892}
13893
13894/*
13895 * "winsaveview()" function
13896 */
13897 static void
13898f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13899{
13900 dict_T *dict;
13901
13902 if (rettv_dict_alloc(rettv) == FAIL)
13903 return;
13904 dict = rettv->vval.v_dict;
13905
Bram Moolenaare0be1672018-07-08 16:50:37 +020013906 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13907 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013908#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020013909 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013910#endif
13911 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013912 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013913
Bram Moolenaare0be1672018-07-08 16:50:37 +020013914 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013915#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013916 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013917#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013918 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13919 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013920}
13921
13922/*
13923 * "winwidth(nr)" function
13924 */
13925 static void
13926f_winwidth(typval_T *argvars, typval_T *rettv)
13927{
13928 win_T *wp;
13929
13930 wp = find_win_by_nr(&argvars[0], NULL);
13931 if (wp == NULL)
13932 rettv->vval.v_number = -1;
13933 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013934 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013935}
13936
13937/*
13938 * "wordcount()" function
13939 */
13940 static void
13941f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13942{
13943 if (rettv_dict_alloc(rettv) == FAIL)
13944 return;
13945 cursor_pos_info(rettv->vval.v_dict);
13946}
13947
13948/*
13949 * "writefile()" function
13950 */
13951 static void
13952f_writefile(typval_T *argvars, typval_T *rettv)
13953{
13954 int binary = FALSE;
13955 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013956#ifdef HAVE_FSYNC
13957 int do_fsync = p_fs;
13958#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013959 char_u *fname;
13960 FILE *fd;
13961 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013962 listitem_T *li;
13963 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013964
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013965 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013966 if (check_restricted() || check_secure())
13967 return;
13968
13969 if (argvars[0].v_type != VAR_LIST)
13970 {
13971 EMSG2(_(e_listarg), "writefile()");
13972 return;
13973 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013974 list = argvars[0].vval.v_list;
13975 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013976 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013977 for (li = list->lv_first; li != NULL; li = li->li_next)
13978 if (get_tv_string_chk(&li->li_tv) == NULL)
13979 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013980
13981 if (argvars[2].v_type != VAR_UNKNOWN)
13982 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013983 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13984
13985 if (arg2 == NULL)
13986 return;
13987 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013988 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013989 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013990 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013991#ifdef HAVE_FSYNC
13992 if (vim_strchr(arg2, 's') != NULL)
13993 do_fsync = TRUE;
13994 else if (vim_strchr(arg2, 'S') != NULL)
13995 do_fsync = FALSE;
13996#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013997 }
13998
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013999 fname = get_tv_string_chk(&argvars[1]);
14000 if (fname == NULL)
14001 return;
14002
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014003 /* Always open the file in binary mode, library functions have a mind of
14004 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014005 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14006 append ? APPENDBIN : WRITEBIN)) == NULL)
14007 {
14008 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14009 ret = -1;
14010 }
14011 else
14012 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014013 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014014 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014015#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014016 else if (do_fsync)
14017 /* Ignore the error, the user wouldn't know what to do about it.
14018 * May happen for a device. */
Bram Moolenaar42335f52018-09-13 15:33:43 +020014019 vim_ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014020#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014021 fclose(fd);
14022 }
14023
14024 rettv->vval.v_number = ret;
14025}
14026
14027/*
14028 * "xor(expr, expr)" function
14029 */
14030 static void
14031f_xor(typval_T *argvars, typval_T *rettv)
14032{
14033 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
14034 ^ get_tv_number_chk(&argvars[1], NULL);
14035}
14036
14037
14038#endif /* FEAT_EVAL */