blob: 54e7dcdd39255d8f755a381651b3fe1ff62f2f82 [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
4683 /* Position the cursor. Needed after a message that ends in a space. */
4684 windgoto(msg_row, msg_col);
4685
4686 ++no_mapping;
4687 ++allow_keys;
4688 for (;;)
4689 {
4690 if (argvars[0].v_type == VAR_UNKNOWN)
4691 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004692 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4694 /* getchar(1): only check if char avail */
4695 n = vpeekc_any();
4696 else if (error || vpeekc_any() == NUL)
4697 /* illegal argument or getchar(0) and no char avail: return zero */
4698 n = 0;
4699 else
4700 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004701 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702
4703 if (n == K_IGNORE)
4704 continue;
4705 break;
4706 }
4707 --no_mapping;
4708 --allow_keys;
4709
4710 set_vim_var_nr(VV_MOUSE_WIN, 0);
4711 set_vim_var_nr(VV_MOUSE_WINID, 0);
4712 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4713 set_vim_var_nr(VV_MOUSE_COL, 0);
4714
4715 rettv->vval.v_number = n;
4716 if (IS_SPECIAL(n) || mod_mask != 0)
4717 {
4718 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4719 int i = 0;
4720
4721 /* Turn a special key into three bytes, plus modifier. */
4722 if (mod_mask != 0)
4723 {
4724 temp[i++] = K_SPECIAL;
4725 temp[i++] = KS_MODIFIER;
4726 temp[i++] = mod_mask;
4727 }
4728 if (IS_SPECIAL(n))
4729 {
4730 temp[i++] = K_SPECIAL;
4731 temp[i++] = K_SECOND(n);
4732 temp[i++] = K_THIRD(n);
4733 }
4734#ifdef FEAT_MBYTE
4735 else if (has_mbyte)
4736 i += (*mb_char2bytes)(n, temp + i);
4737#endif
4738 else
4739 temp[i++] = n;
4740 temp[i++] = NUL;
4741 rettv->v_type = VAR_STRING;
4742 rettv->vval.v_string = vim_strsave(temp);
4743
4744#ifdef FEAT_MOUSE
4745 if (is_mouse_key(n))
4746 {
4747 int row = mouse_row;
4748 int col = mouse_col;
4749 win_T *win;
4750 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004751 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004752 int winnr = 1;
4753
4754 if (row >= 0 && col >= 0)
4755 {
4756 /* Find the window at the mouse coordinates and compute the
4757 * text position. */
4758 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004759 if (win == NULL)
4760 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004761 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004762 for (wp = firstwin; wp != win; wp = wp->w_next)
4763 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004764 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4765 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4766 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4767 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4768 }
4769 }
4770#endif
4771 }
4772}
4773
4774/*
4775 * "getcharmod()" function
4776 */
4777 static void
4778f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4779{
4780 rettv->vval.v_number = mod_mask;
4781}
4782
4783/*
4784 * "getcharsearch()" function
4785 */
4786 static void
4787f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4788{
4789 if (rettv_dict_alloc(rettv) != FAIL)
4790 {
4791 dict_T *dict = rettv->vval.v_dict;
4792
Bram Moolenaare0be1672018-07-08 16:50:37 +02004793 dict_add_string(dict, "char", last_csearch());
4794 dict_add_number(dict, "forward", last_csearch_forward());
4795 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796 }
4797}
4798
4799/*
4800 * "getcmdline()" function
4801 */
4802 static void
4803f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4804{
4805 rettv->v_type = VAR_STRING;
4806 rettv->vval.v_string = get_cmdline_str();
4807}
4808
4809/*
4810 * "getcmdpos()" function
4811 */
4812 static void
4813f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4814{
4815 rettv->vval.v_number = get_cmdline_pos() + 1;
4816}
4817
4818/*
4819 * "getcmdtype()" function
4820 */
4821 static void
4822f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4823{
4824 rettv->v_type = VAR_STRING;
4825 rettv->vval.v_string = alloc(2);
4826 if (rettv->vval.v_string != NULL)
4827 {
4828 rettv->vval.v_string[0] = get_cmdline_type();
4829 rettv->vval.v_string[1] = NUL;
4830 }
4831}
4832
4833/*
4834 * "getcmdwintype()" function
4835 */
4836 static void
4837f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4838{
4839 rettv->v_type = VAR_STRING;
4840 rettv->vval.v_string = NULL;
4841#ifdef FEAT_CMDWIN
4842 rettv->vval.v_string = alloc(2);
4843 if (rettv->vval.v_string != NULL)
4844 {
4845 rettv->vval.v_string[0] = cmdwin_type;
4846 rettv->vval.v_string[1] = NUL;
4847 }
4848#endif
4849}
4850
4851#if defined(FEAT_CMDL_COMPL)
4852/*
4853 * "getcompletion()" function
4854 */
4855 static void
4856f_getcompletion(typval_T *argvars, typval_T *rettv)
4857{
4858 char_u *pat;
4859 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004860 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004861 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4862 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004863
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004864 if (argvars[2].v_type != VAR_UNKNOWN)
4865 filtered = get_tv_number_chk(&argvars[2], NULL);
4866
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004867 if (p_wic)
4868 options |= WILD_ICASE;
4869
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004870 /* For filtered results, 'wildignore' is used */
4871 if (!filtered)
4872 options |= WILD_KEEP_ALL;
4873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004874 ExpandInit(&xpc);
4875 xpc.xp_pattern = get_tv_string(&argvars[0]);
4876 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4877 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4878 if (xpc.xp_context == EXPAND_NOTHING)
4879 {
4880 if (argvars[1].v_type == VAR_STRING)
4881 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4882 else
4883 EMSG(_(e_invarg));
4884 return;
4885 }
4886
4887# if defined(FEAT_MENU)
4888 if (xpc.xp_context == EXPAND_MENUS)
4889 {
4890 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4891 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4892 }
4893# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004894#ifdef FEAT_CSCOPE
4895 if (xpc.xp_context == EXPAND_CSCOPE)
4896 {
4897 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4898 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4899 }
4900#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004901#ifdef FEAT_SIGNS
4902 if (xpc.xp_context == EXPAND_SIGN)
4903 {
4904 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4905 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4906 }
4907#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908
4909 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4910 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4911 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004912 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004913
4914 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4915
4916 for (i = 0; i < xpc.xp_numfiles; i++)
4917 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4918 }
4919 vim_free(pat);
4920 ExpandCleanup(&xpc);
4921}
4922#endif
4923
4924/*
4925 * "getcwd()" function
4926 */
4927 static void
4928f_getcwd(typval_T *argvars, typval_T *rettv)
4929{
4930 win_T *wp = NULL;
4931 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004932 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933
4934 rettv->v_type = VAR_STRING;
4935 rettv->vval.v_string = NULL;
4936
Bram Moolenaar54591292018-02-09 20:53:59 +01004937 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4938 global = TRUE;
4939 else
4940 wp = find_tabwin(&argvars[0], &argvars[1]);
4941
4942 if (wp != NULL && wp->w_localdir != NULL)
4943 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4944 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004946 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 rettv->vval.v_string = vim_strsave(globaldir);
4948 else
4949 {
4950 cwd = alloc(MAXPATHL);
4951 if (cwd != NULL)
4952 {
4953 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4954 rettv->vval.v_string = vim_strsave(cwd);
4955 vim_free(cwd);
4956 }
4957 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004959#ifdef BACKSLASH_IN_FILENAME
4960 if (rettv->vval.v_string != NULL)
4961 slash_adjust(rettv->vval.v_string);
4962#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004963}
4964
4965/*
4966 * "getfontname()" function
4967 */
4968 static void
4969f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4970{
4971 rettv->v_type = VAR_STRING;
4972 rettv->vval.v_string = NULL;
4973#ifdef FEAT_GUI
4974 if (gui.in_use)
4975 {
4976 GuiFont font;
4977 char_u *name = NULL;
4978
4979 if (argvars[0].v_type == VAR_UNKNOWN)
4980 {
4981 /* Get the "Normal" font. Either the name saved by
4982 * hl_set_font_name() or from the font ID. */
4983 font = gui.norm_font;
4984 name = hl_get_font_name();
4985 }
4986 else
4987 {
4988 name = get_tv_string(&argvars[0]);
4989 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4990 return;
4991 font = gui_mch_get_font(name, FALSE);
4992 if (font == NOFONT)
4993 return; /* Invalid font name, return empty string. */
4994 }
4995 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4996 if (argvars[0].v_type != VAR_UNKNOWN)
4997 gui_mch_free_font(font);
4998 }
4999#endif
5000}
5001
5002/*
5003 * "getfperm({fname})" function
5004 */
5005 static void
5006f_getfperm(typval_T *argvars, typval_T *rettv)
5007{
5008 char_u *fname;
5009 stat_T st;
5010 char_u *perm = NULL;
5011 char_u flags[] = "rwx";
5012 int i;
5013
5014 fname = get_tv_string(&argvars[0]);
5015
5016 rettv->v_type = VAR_STRING;
5017 if (mch_stat((char *)fname, &st) >= 0)
5018 {
5019 perm = vim_strsave((char_u *)"---------");
5020 if (perm != NULL)
5021 {
5022 for (i = 0; i < 9; i++)
5023 {
5024 if (st.st_mode & (1 << (8 - i)))
5025 perm[i] = flags[i % 3];
5026 }
5027 }
5028 }
5029 rettv->vval.v_string = perm;
5030}
5031
5032/*
5033 * "getfsize({fname})" function
5034 */
5035 static void
5036f_getfsize(typval_T *argvars, typval_T *rettv)
5037{
5038 char_u *fname;
5039 stat_T st;
5040
5041 fname = get_tv_string(&argvars[0]);
5042
5043 rettv->v_type = VAR_NUMBER;
5044
5045 if (mch_stat((char *)fname, &st) >= 0)
5046 {
5047 if (mch_isdir(fname))
5048 rettv->vval.v_number = 0;
5049 else
5050 {
5051 rettv->vval.v_number = (varnumber_T)st.st_size;
5052
5053 /* non-perfect check for overflow */
5054 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5055 rettv->vval.v_number = -2;
5056 }
5057 }
5058 else
5059 rettv->vval.v_number = -1;
5060}
5061
5062/*
5063 * "getftime({fname})" function
5064 */
5065 static void
5066f_getftime(typval_T *argvars, typval_T *rettv)
5067{
5068 char_u *fname;
5069 stat_T st;
5070
5071 fname = get_tv_string(&argvars[0]);
5072
5073 if (mch_stat((char *)fname, &st) >= 0)
5074 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5075 else
5076 rettv->vval.v_number = -1;
5077}
5078
5079/*
5080 * "getftype({fname})" function
5081 */
5082 static void
5083f_getftype(typval_T *argvars, typval_T *rettv)
5084{
5085 char_u *fname;
5086 stat_T st;
5087 char_u *type = NULL;
5088 char *t;
5089
5090 fname = get_tv_string(&argvars[0]);
5091
5092 rettv->v_type = VAR_STRING;
5093 if (mch_lstat((char *)fname, &st) >= 0)
5094 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005095 if (S_ISREG(st.st_mode))
5096 t = "file";
5097 else if (S_ISDIR(st.st_mode))
5098 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 else if (S_ISLNK(st.st_mode))
5100 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005101 else if (S_ISBLK(st.st_mode))
5102 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103 else if (S_ISCHR(st.st_mode))
5104 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 else if (S_ISFIFO(st.st_mode))
5106 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005108 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 else
5110 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005111 type = vim_strsave((char_u *)t);
5112 }
5113 rettv->vval.v_string = type;
5114}
5115
5116/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005117 * "getjumplist()" function
5118 */
5119 static void
5120f_getjumplist(typval_T *argvars, typval_T *rettv)
5121{
5122#ifdef FEAT_JUMPLIST
5123 win_T *wp;
5124 int i;
5125 list_T *l;
5126 dict_T *d;
5127#endif
5128
5129 if (rettv_list_alloc(rettv) != OK)
5130 return;
5131
5132#ifdef FEAT_JUMPLIST
5133 wp = find_tabwin(&argvars[0], &argvars[1]);
5134 if (wp == NULL)
5135 return;
5136
5137 l = list_alloc();
5138 if (l == NULL)
5139 return;
5140
5141 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5142 return;
5143 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5144
Bram Moolenaar48679742018-02-13 13:33:29 +01005145 cleanup_jumplist(wp, TRUE);
5146
Bram Moolenaar4f505882018-02-10 21:06:32 +01005147 for (i = 0; i < wp->w_jumplistlen; ++i)
5148 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005149 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5150 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005151 if ((d = dict_alloc()) == NULL)
5152 return;
5153 if (list_append_dict(l, d) == FAIL)
5154 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005155 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5156 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005157# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005158 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005159# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005160 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005161 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005162 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005163 }
5164#endif
5165}
5166
5167/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005168 * "getline(lnum, [end])" function
5169 */
5170 static void
5171f_getline(typval_T *argvars, typval_T *rettv)
5172{
5173 linenr_T lnum;
5174 linenr_T end;
5175 int retlist;
5176
5177 lnum = get_tv_lnum(argvars);
5178 if (argvars[1].v_type == VAR_UNKNOWN)
5179 {
5180 end = 0;
5181 retlist = FALSE;
5182 }
5183 else
5184 {
5185 end = get_tv_lnum(&argvars[1]);
5186 retlist = TRUE;
5187 }
5188
5189 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5190}
5191
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005192#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005193 static void
5194get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5195{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005196 if (what_arg->v_type == VAR_UNKNOWN)
5197 {
5198 if (rettv_list_alloc(rettv) == OK)
5199 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005200 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005201 }
5202 else
5203 {
5204 if (rettv_dict_alloc(rettv) == OK)
5205 if (is_qf || (wp != NULL))
5206 {
5207 if (what_arg->v_type == VAR_DICT)
5208 {
5209 dict_T *d = what_arg->vval.v_dict;
5210
5211 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005212 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005213 }
5214 else
5215 EMSG(_(e_dictreq));
5216 }
5217 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005218}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005219#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005220
5221/*
5222 * "getloclist()" function
5223 */
5224 static void
5225f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5226{
5227#ifdef FEAT_QUICKFIX
5228 win_T *wp;
5229
5230 wp = find_win_by_nr(&argvars[0], NULL);
5231 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5232#endif
5233}
5234
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005235/*
5236 * "getmatches()" function
5237 */
5238 static void
5239f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5240{
5241#ifdef FEAT_SEARCH_EXTRA
5242 dict_T *dict;
5243 matchitem_T *cur = curwin->w_match_head;
5244 int i;
5245
5246 if (rettv_list_alloc(rettv) == OK)
5247 {
5248 while (cur != NULL)
5249 {
5250 dict = dict_alloc();
5251 if (dict == NULL)
5252 return;
5253 if (cur->match.regprog == NULL)
5254 {
5255 /* match added with matchaddpos() */
5256 for (i = 0; i < MAXPOSMATCH; ++i)
5257 {
5258 llpos_T *llpos;
5259 char buf[6];
5260 list_T *l;
5261
5262 llpos = &cur->pos.pos[i];
5263 if (llpos->lnum == 0)
5264 break;
5265 l = list_alloc();
5266 if (l == NULL)
5267 break;
5268 list_append_number(l, (varnumber_T)llpos->lnum);
5269 if (llpos->col > 0)
5270 {
5271 list_append_number(l, (varnumber_T)llpos->col);
5272 list_append_number(l, (varnumber_T)llpos->len);
5273 }
5274 sprintf(buf, "pos%d", i + 1);
5275 dict_add_list(dict, buf, l);
5276 }
5277 }
5278 else
5279 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005280 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005281 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005282 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5283 dict_add_number(dict, "priority", (long)cur->priority);
5284 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005285# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5286 if (cur->conceal_char)
5287 {
5288 char_u buf[MB_MAXBYTES + 1];
5289
5290 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005291 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 }
5293# endif
5294 list_append_dict(rettv->vval.v_list, dict);
5295 cur = cur->next;
5296 }
5297 }
5298#endif
5299}
5300
5301/*
5302 * "getpid()" function
5303 */
5304 static void
5305f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5306{
5307 rettv->vval.v_number = mch_get_pid();
5308}
5309
5310 static void
5311getpos_both(
5312 typval_T *argvars,
5313 typval_T *rettv,
5314 int getcurpos)
5315{
5316 pos_T *fp;
5317 list_T *l;
5318 int fnum = -1;
5319
5320 if (rettv_list_alloc(rettv) == OK)
5321 {
5322 l = rettv->vval.v_list;
5323 if (getcurpos)
5324 fp = &curwin->w_cursor;
5325 else
5326 fp = var2fpos(&argvars[0], TRUE, &fnum);
5327 if (fnum != -1)
5328 list_append_number(l, (varnumber_T)fnum);
5329 else
5330 list_append_number(l, (varnumber_T)0);
5331 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5332 : (varnumber_T)0);
5333 list_append_number(l, (fp != NULL)
5334 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5335 : (varnumber_T)0);
5336 list_append_number(l,
5337#ifdef FEAT_VIRTUALEDIT
5338 (fp != NULL) ? (varnumber_T)fp->coladd :
5339#endif
5340 (varnumber_T)0);
5341 if (getcurpos)
5342 {
5343 update_curswant();
5344 list_append_number(l, curwin->w_curswant == MAXCOL ?
5345 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5346 }
5347 }
5348 else
5349 rettv->vval.v_number = FALSE;
5350}
5351
5352
5353/*
5354 * "getcurpos()" function
5355 */
5356 static void
5357f_getcurpos(typval_T *argvars, typval_T *rettv)
5358{
5359 getpos_both(argvars, rettv, TRUE);
5360}
5361
5362/*
5363 * "getpos(string)" function
5364 */
5365 static void
5366f_getpos(typval_T *argvars, typval_T *rettv)
5367{
5368 getpos_both(argvars, rettv, FALSE);
5369}
5370
5371/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005372 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005373 */
5374 static void
5375f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5376{
5377#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005378 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379#endif
5380}
5381
5382/*
5383 * "getreg()" function
5384 */
5385 static void
5386f_getreg(typval_T *argvars, typval_T *rettv)
5387{
5388 char_u *strregname;
5389 int regname;
5390 int arg2 = FALSE;
5391 int return_list = FALSE;
5392 int error = FALSE;
5393
5394 if (argvars[0].v_type != VAR_UNKNOWN)
5395 {
5396 strregname = get_tv_string_chk(&argvars[0]);
5397 error = strregname == NULL;
5398 if (argvars[1].v_type != VAR_UNKNOWN)
5399 {
5400 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5401 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5402 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5403 }
5404 }
5405 else
5406 strregname = get_vim_var_str(VV_REG);
5407
5408 if (error)
5409 return;
5410
5411 regname = (strregname == NULL ? '"' : *strregname);
5412 if (regname == 0)
5413 regname = '"';
5414
5415 if (return_list)
5416 {
5417 rettv->v_type = VAR_LIST;
5418 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5419 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5420 if (rettv->vval.v_list == NULL)
5421 (void)rettv_list_alloc(rettv);
5422 else
5423 ++rettv->vval.v_list->lv_refcount;
5424 }
5425 else
5426 {
5427 rettv->v_type = VAR_STRING;
5428 rettv->vval.v_string = get_reg_contents(regname,
5429 arg2 ? GREG_EXPR_SRC : 0);
5430 }
5431}
5432
5433/*
5434 * "getregtype()" function
5435 */
5436 static void
5437f_getregtype(typval_T *argvars, typval_T *rettv)
5438{
5439 char_u *strregname;
5440 int regname;
5441 char_u buf[NUMBUFLEN + 2];
5442 long reglen = 0;
5443
5444 if (argvars[0].v_type != VAR_UNKNOWN)
5445 {
5446 strregname = get_tv_string_chk(&argvars[0]);
5447 if (strregname == NULL) /* type error; errmsg already given */
5448 {
5449 rettv->v_type = VAR_STRING;
5450 rettv->vval.v_string = NULL;
5451 return;
5452 }
5453 }
5454 else
5455 /* Default to v:register */
5456 strregname = get_vim_var_str(VV_REG);
5457
5458 regname = (strregname == NULL ? '"' : *strregname);
5459 if (regname == 0)
5460 regname = '"';
5461
5462 buf[0] = NUL;
5463 buf[1] = NUL;
5464 switch (get_reg_type(regname, &reglen))
5465 {
5466 case MLINE: buf[0] = 'V'; break;
5467 case MCHAR: buf[0] = 'v'; break;
5468 case MBLOCK:
5469 buf[0] = Ctrl_V;
5470 sprintf((char *)buf + 1, "%ld", reglen + 1);
5471 break;
5472 }
5473 rettv->v_type = VAR_STRING;
5474 rettv->vval.v_string = vim_strsave(buf);
5475}
5476
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005477/*
5478 * Returns information (variables, options, etc.) about a tab page
5479 * as a dictionary.
5480 */
5481 static dict_T *
5482get_tabpage_info(tabpage_T *tp, int tp_idx)
5483{
5484 win_T *wp;
5485 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005486 list_T *l;
5487
5488 dict = dict_alloc();
5489 if (dict == NULL)
5490 return NULL;
5491
Bram Moolenaare0be1672018-07-08 16:50:37 +02005492 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005493
5494 l = list_alloc();
5495 if (l != NULL)
5496 {
5497 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5498 wp; wp = wp->w_next)
5499 list_append_number(l, (varnumber_T)wp->w_id);
5500 dict_add_list(dict, "windows", l);
5501 }
5502
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005503 /* Make a reference to tabpage variables */
5504 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005505
5506 return dict;
5507}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005508
5509/*
5510 * "gettabinfo()" function
5511 */
5512 static void
5513f_gettabinfo(typval_T *argvars, typval_T *rettv)
5514{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005515 tabpage_T *tp, *tparg = NULL;
5516 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005517 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005518
5519 if (rettv_list_alloc(rettv) != OK)
5520 return;
5521
5522 if (argvars[0].v_type != VAR_UNKNOWN)
5523 {
5524 /* Information about one tab page */
5525 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5526 if (tparg == NULL)
5527 return;
5528 }
5529
5530 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005531 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005532 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005533 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005534 if (tparg != NULL && tp != tparg)
5535 continue;
5536 d = get_tabpage_info(tp, tpnr);
5537 if (d != NULL)
5538 list_append_dict(rettv->vval.v_list, d);
5539 if (tparg != NULL)
5540 return;
5541 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005542}
5543
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544/*
5545 * "gettabvar()" function
5546 */
5547 static void
5548f_gettabvar(typval_T *argvars, typval_T *rettv)
5549{
5550 win_T *oldcurwin;
5551 tabpage_T *tp, *oldtabpage;
5552 dictitem_T *v;
5553 char_u *varname;
5554 int done = FALSE;
5555
5556 rettv->v_type = VAR_STRING;
5557 rettv->vval.v_string = NULL;
5558
5559 varname = get_tv_string_chk(&argvars[1]);
5560 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5561 if (tp != NULL && varname != NULL)
5562 {
5563 /* Set tp to be our tabpage, temporarily. Also set the window to the
5564 * first window in the tabpage, otherwise the window is not valid. */
5565 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005566 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5567 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005568 {
5569 /* look up the variable */
5570 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5571 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5572 if (v != NULL)
5573 {
5574 copy_tv(&v->di_tv, rettv);
5575 done = TRUE;
5576 }
5577 }
5578
5579 /* restore previous notion of curwin */
5580 restore_win(oldcurwin, oldtabpage, TRUE);
5581 }
5582
5583 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5584 copy_tv(&argvars[2], rettv);
5585}
5586
5587/*
5588 * "gettabwinvar()" function
5589 */
5590 static void
5591f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5592{
5593 getwinvar(argvars, rettv, 1);
5594}
5595
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005596/*
5597 * Returns information about a window as a dictionary.
5598 */
5599 static dict_T *
5600get_win_info(win_T *wp, short tpnr, short winnr)
5601{
5602 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005603
5604 dict = dict_alloc();
5605 if (dict == NULL)
5606 return NULL;
5607
Bram Moolenaare0be1672018-07-08 16:50:37 +02005608 dict_add_number(dict, "tabnr", tpnr);
5609 dict_add_number(dict, "winnr", winnr);
5610 dict_add_number(dict, "winid", wp->w_id);
5611 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005612 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005613#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005614 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005615#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005616 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005617 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005618 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005619
Bram Moolenaar69905d12017-08-13 18:14:47 +02005620#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005621 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005622#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005623#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005624 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5625 dict_add_number(dict, "loclist",
5626 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005627#endif
5628
Bram Moolenaar30567352016-08-27 21:25:44 +02005629 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005630 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005631
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632 return dict;
5633}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005634
5635/*
5636 * "getwininfo()" function
5637 */
5638 static void
5639f_getwininfo(typval_T *argvars, typval_T *rettv)
5640{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005641 tabpage_T *tp;
5642 win_T *wp = NULL, *wparg = NULL;
5643 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005644 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005645
5646 if (rettv_list_alloc(rettv) != OK)
5647 return;
5648
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005649 if (argvars[0].v_type != VAR_UNKNOWN)
5650 {
5651 wparg = win_id2wp(argvars);
5652 if (wparg == NULL)
5653 return;
5654 }
5655
5656 /* Collect information about either all the windows across all the tab
5657 * pages or one particular window.
5658 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005659 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005660 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005661 tabnr++;
5662 winnr = 0;
5663 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005664 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005665 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005666 if (wparg != NULL && wp != wparg)
5667 continue;
5668 d = get_win_info(wp, tabnr, winnr);
5669 if (d != NULL)
5670 list_append_dict(rettv->vval.v_list, d);
5671 if (wparg != NULL)
5672 /* found information about a specific window */
5673 return;
5674 }
5675 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005676}
5677
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005678/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005679 * "win_findbuf()" function
5680 */
5681 static void
5682f_win_findbuf(typval_T *argvars, typval_T *rettv)
5683{
5684 if (rettv_list_alloc(rettv) != FAIL)
5685 win_findbuf(argvars, rettv->vval.v_list);
5686}
5687
5688/*
5689 * "win_getid()" function
5690 */
5691 static void
5692f_win_getid(typval_T *argvars, typval_T *rettv)
5693{
5694 rettv->vval.v_number = win_getid(argvars);
5695}
5696
5697/*
5698 * "win_gotoid()" function
5699 */
5700 static void
5701f_win_gotoid(typval_T *argvars, typval_T *rettv)
5702{
5703 rettv->vval.v_number = win_gotoid(argvars);
5704}
5705
5706/*
5707 * "win_id2tabwin()" function
5708 */
5709 static void
5710f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5711{
5712 if (rettv_list_alloc(rettv) != FAIL)
5713 win_id2tabwin(argvars, rettv->vval.v_list);
5714}
5715
5716/*
5717 * "win_id2win()" function
5718 */
5719 static void
5720f_win_id2win(typval_T *argvars, typval_T *rettv)
5721{
5722 rettv->vval.v_number = win_id2win(argvars);
5723}
5724
5725/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005726 * "win_screenpos()" function
5727 */
5728 static void
5729f_win_screenpos(typval_T *argvars, typval_T *rettv)
5730{
5731 win_T *wp;
5732
5733 if (rettv_list_alloc(rettv) == FAIL)
5734 return;
5735
5736 wp = find_win_by_nr(&argvars[0], NULL);
5737 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5738 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5739}
5740
5741/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005742 * "getwinpos({timeout})" function
5743 */
5744 static void
5745f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5746{
5747 int x = -1;
5748 int y = -1;
5749
5750 if (rettv_list_alloc(rettv) == FAIL)
5751 return;
5752#ifdef FEAT_GUI
5753 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005754 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005755# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5756 else
5757# endif
5758#endif
5759#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5760 {
5761 varnumber_T timeout = 100;
5762
5763 if (argvars[0].v_type != VAR_UNKNOWN)
5764 timeout = get_tv_number(&argvars[0]);
5765 term_get_winpos(&x, &y, timeout);
5766 }
5767#endif
5768 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5769 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5770}
5771
5772
5773/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005774 * "getwinposx()" function
5775 */
5776 static void
5777f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5778{
5779 rettv->vval.v_number = -1;
5780#ifdef FEAT_GUI
5781 if (gui.in_use)
5782 {
5783 int x, y;
5784
5785 if (gui_mch_get_winpos(&x, &y) == OK)
5786 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005787 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005788 }
5789#endif
5790#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5791 {
5792 int x, y;
5793
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005794 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005795 rettv->vval.v_number = x;
5796 }
5797#endif
5798}
5799
5800/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 * "getwinposy()" function
5802 */
5803 static void
5804f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5805{
5806 rettv->vval.v_number = -1;
5807#ifdef FEAT_GUI
5808 if (gui.in_use)
5809 {
5810 int x, y;
5811
5812 if (gui_mch_get_winpos(&x, &y) == OK)
5813 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005814 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005815 }
5816#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005817#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5818 {
5819 int x, y;
5820
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005821 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005822 rettv->vval.v_number = y;
5823 }
5824#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005825}
5826
5827/*
5828 * "getwinvar()" function
5829 */
5830 static void
5831f_getwinvar(typval_T *argvars, typval_T *rettv)
5832{
5833 getwinvar(argvars, rettv, 0);
5834}
5835
5836/*
5837 * "glob()" function
5838 */
5839 static void
5840f_glob(typval_T *argvars, typval_T *rettv)
5841{
5842 int options = WILD_SILENT|WILD_USE_NL;
5843 expand_T xpc;
5844 int error = FALSE;
5845
5846 /* When the optional second argument is non-zero, don't remove matches
5847 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5848 rettv->v_type = VAR_STRING;
5849 if (argvars[1].v_type != VAR_UNKNOWN)
5850 {
5851 if (get_tv_number_chk(&argvars[1], &error))
5852 options |= WILD_KEEP_ALL;
5853 if (argvars[2].v_type != VAR_UNKNOWN)
5854 {
5855 if (get_tv_number_chk(&argvars[2], &error))
5856 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005857 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005858 }
5859 if (argvars[3].v_type != VAR_UNKNOWN
5860 && get_tv_number_chk(&argvars[3], &error))
5861 options |= WILD_ALLLINKS;
5862 }
5863 }
5864 if (!error)
5865 {
5866 ExpandInit(&xpc);
5867 xpc.xp_context = EXPAND_FILES;
5868 if (p_wic)
5869 options += WILD_ICASE;
5870 if (rettv->v_type == VAR_STRING)
5871 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5872 NULL, options, WILD_ALL);
5873 else if (rettv_list_alloc(rettv) != FAIL)
5874 {
5875 int i;
5876
5877 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5878 NULL, options, WILD_ALL_KEEP);
5879 for (i = 0; i < xpc.xp_numfiles; i++)
5880 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5881
5882 ExpandCleanup(&xpc);
5883 }
5884 }
5885 else
5886 rettv->vval.v_string = NULL;
5887}
5888
5889/*
5890 * "globpath()" function
5891 */
5892 static void
5893f_globpath(typval_T *argvars, typval_T *rettv)
5894{
5895 int flags = 0;
5896 char_u buf1[NUMBUFLEN];
5897 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5898 int error = FALSE;
5899 garray_T ga;
5900 int i;
5901
5902 /* When the optional second argument is non-zero, don't remove matches
5903 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5904 rettv->v_type = VAR_STRING;
5905 if (argvars[2].v_type != VAR_UNKNOWN)
5906 {
5907 if (get_tv_number_chk(&argvars[2], &error))
5908 flags |= WILD_KEEP_ALL;
5909 if (argvars[3].v_type != VAR_UNKNOWN)
5910 {
5911 if (get_tv_number_chk(&argvars[3], &error))
5912 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005913 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914 }
5915 if (argvars[4].v_type != VAR_UNKNOWN
5916 && get_tv_number_chk(&argvars[4], &error))
5917 flags |= WILD_ALLLINKS;
5918 }
5919 }
5920 if (file != NULL && !error)
5921 {
5922 ga_init2(&ga, (int)sizeof(char_u *), 10);
5923 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5924 if (rettv->v_type == VAR_STRING)
5925 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5926 else if (rettv_list_alloc(rettv) != FAIL)
5927 for (i = 0; i < ga.ga_len; ++i)
5928 list_append_string(rettv->vval.v_list,
5929 ((char_u **)(ga.ga_data))[i], -1);
5930 ga_clear_strings(&ga);
5931 }
5932 else
5933 rettv->vval.v_string = NULL;
5934}
5935
5936/*
5937 * "glob2regpat()" function
5938 */
5939 static void
5940f_glob2regpat(typval_T *argvars, typval_T *rettv)
5941{
5942 char_u *pat = get_tv_string_chk(&argvars[0]);
5943
5944 rettv->v_type = VAR_STRING;
5945 rettv->vval.v_string = (pat == NULL)
5946 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5947}
5948
5949/* for VIM_VERSION_ defines */
5950#include "version.h"
5951
5952/*
5953 * "has()" function
5954 */
5955 static void
5956f_has(typval_T *argvars, typval_T *rettv)
5957{
5958 int i;
5959 char_u *name;
5960 int n = FALSE;
5961 static char *(has_list[]) =
5962 {
5963#ifdef AMIGA
5964 "amiga",
5965# ifdef FEAT_ARP
5966 "arp",
5967# endif
5968#endif
5969#ifdef __BEOS__
5970 "beos",
5971#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005972#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005973 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5974 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005975# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005976 "macunix", /* Mac OS X, with the darwin feature */
5977 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005978# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005979#endif
5980#ifdef __QNX__
5981 "qnx",
5982#endif
5983#ifdef UNIX
5984 "unix",
5985#endif
5986#ifdef VMS
5987 "vms",
5988#endif
5989#ifdef WIN32
5990 "win32",
5991#endif
5992#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5993 "win32unix",
5994#endif
5995#if defined(WIN64) || defined(_WIN64)
5996 "win64",
5997#endif
5998#ifdef EBCDIC
5999 "ebcdic",
6000#endif
6001#ifndef CASE_INSENSITIVE_FILENAME
6002 "fname_case",
6003#endif
6004#ifdef HAVE_ACL
6005 "acl",
6006#endif
6007#ifdef FEAT_ARABIC
6008 "arabic",
6009#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006010 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006011#ifdef FEAT_AUTOCHDIR
6012 "autochdir",
6013#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006014#ifdef FEAT_AUTOSERVERNAME
6015 "autoservername",
6016#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006017#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 "balloon_eval",
6019# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6020 "balloon_multiline",
6021# endif
6022#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006023#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006024 "balloon_eval_term",
6025#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006026#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6027 "builtin_terms",
6028# ifdef ALL_BUILTIN_TCAPS
6029 "all_builtin_terms",
6030# endif
6031#endif
6032#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6033 || defined(FEAT_GUI_W32) \
6034 || defined(FEAT_GUI_MOTIF))
6035 "browsefilter",
6036#endif
6037#ifdef FEAT_BYTEOFF
6038 "byte_offset",
6039#endif
6040#ifdef FEAT_JOB_CHANNEL
6041 "channel",
6042#endif
6043#ifdef FEAT_CINDENT
6044 "cindent",
6045#endif
6046#ifdef FEAT_CLIENTSERVER
6047 "clientserver",
6048#endif
6049#ifdef FEAT_CLIPBOARD
6050 "clipboard",
6051#endif
6052#ifdef FEAT_CMDL_COMPL
6053 "cmdline_compl",
6054#endif
6055#ifdef FEAT_CMDHIST
6056 "cmdline_hist",
6057#endif
6058#ifdef FEAT_COMMENTS
6059 "comments",
6060#endif
6061#ifdef FEAT_CONCEAL
6062 "conceal",
6063#endif
6064#ifdef FEAT_CRYPT
6065 "cryptv",
6066 "crypt-blowfish",
6067 "crypt-blowfish2",
6068#endif
6069#ifdef FEAT_CSCOPE
6070 "cscope",
6071#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006072 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006073#ifdef CURSOR_SHAPE
6074 "cursorshape",
6075#endif
6076#ifdef DEBUG
6077 "debug",
6078#endif
6079#ifdef FEAT_CON_DIALOG
6080 "dialog_con",
6081#endif
6082#ifdef FEAT_GUI_DIALOG
6083 "dialog_gui",
6084#endif
6085#ifdef FEAT_DIFF
6086 "diff",
6087#endif
6088#ifdef FEAT_DIGRAPHS
6089 "digraphs",
6090#endif
6091#ifdef FEAT_DIRECTX
6092 "directx",
6093#endif
6094#ifdef FEAT_DND
6095 "dnd",
6096#endif
6097#ifdef FEAT_EMACS_TAGS
6098 "emacs_tags",
6099#endif
6100 "eval", /* always present, of course! */
6101 "ex_extra", /* graduated feature */
6102#ifdef FEAT_SEARCH_EXTRA
6103 "extra_search",
6104#endif
6105#ifdef FEAT_FKMAP
6106 "farsi",
6107#endif
6108#ifdef FEAT_SEARCHPATH
6109 "file_in_path",
6110#endif
6111#ifdef FEAT_FILTERPIPE
6112 "filterpipe",
6113#endif
6114#ifdef FEAT_FIND_ID
6115 "find_in_path",
6116#endif
6117#ifdef FEAT_FLOAT
6118 "float",
6119#endif
6120#ifdef FEAT_FOLDING
6121 "folding",
6122#endif
6123#ifdef FEAT_FOOTER
6124 "footer",
6125#endif
6126#if !defined(USE_SYSTEM) && defined(UNIX)
6127 "fork",
6128#endif
6129#ifdef FEAT_GETTEXT
6130 "gettext",
6131#endif
6132#ifdef FEAT_GUI
6133 "gui",
6134#endif
6135#ifdef FEAT_GUI_ATHENA
6136# ifdef FEAT_GUI_NEXTAW
6137 "gui_neXtaw",
6138# else
6139 "gui_athena",
6140# endif
6141#endif
6142#ifdef FEAT_GUI_GTK
6143 "gui_gtk",
6144# ifdef USE_GTK3
6145 "gui_gtk3",
6146# else
6147 "gui_gtk2",
6148# endif
6149#endif
6150#ifdef FEAT_GUI_GNOME
6151 "gui_gnome",
6152#endif
6153#ifdef FEAT_GUI_MAC
6154 "gui_mac",
6155#endif
6156#ifdef FEAT_GUI_MOTIF
6157 "gui_motif",
6158#endif
6159#ifdef FEAT_GUI_PHOTON
6160 "gui_photon",
6161#endif
6162#ifdef FEAT_GUI_W32
6163 "gui_win32",
6164#endif
6165#ifdef FEAT_HANGULIN
6166 "hangul_input",
6167#endif
6168#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6169 "iconv",
6170#endif
6171#ifdef FEAT_INS_EXPAND
6172 "insert_expand",
6173#endif
6174#ifdef FEAT_JOB_CHANNEL
6175 "job",
6176#endif
6177#ifdef FEAT_JUMPLIST
6178 "jumplist",
6179#endif
6180#ifdef FEAT_KEYMAP
6181 "keymap",
6182#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006183 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006184#ifdef FEAT_LANGMAP
6185 "langmap",
6186#endif
6187#ifdef FEAT_LIBCALL
6188 "libcall",
6189#endif
6190#ifdef FEAT_LINEBREAK
6191 "linebreak",
6192#endif
6193#ifdef FEAT_LISP
6194 "lispindent",
6195#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197#ifdef FEAT_LOCALMAP
6198 "localmap",
6199#endif
6200#ifdef FEAT_LUA
6201# ifndef DYNAMIC_LUA
6202 "lua",
6203# endif
6204#endif
6205#ifdef FEAT_MENU
6206 "menu",
6207#endif
6208#ifdef FEAT_SESSION
6209 "mksession",
6210#endif
6211#ifdef FEAT_MODIFY_FNAME
6212 "modify_fname",
6213#endif
6214#ifdef FEAT_MOUSE
6215 "mouse",
6216#endif
6217#ifdef FEAT_MOUSESHAPE
6218 "mouseshape",
6219#endif
6220#if defined(UNIX) || defined(VMS)
6221# ifdef FEAT_MOUSE_DEC
6222 "mouse_dec",
6223# endif
6224# ifdef FEAT_MOUSE_GPM
6225 "mouse_gpm",
6226# endif
6227# ifdef FEAT_MOUSE_JSB
6228 "mouse_jsbterm",
6229# endif
6230# ifdef FEAT_MOUSE_NET
6231 "mouse_netterm",
6232# endif
6233# ifdef FEAT_MOUSE_PTERM
6234 "mouse_pterm",
6235# endif
6236# ifdef FEAT_MOUSE_SGR
6237 "mouse_sgr",
6238# endif
6239# ifdef FEAT_SYSMOUSE
6240 "mouse_sysmouse",
6241# endif
6242# ifdef FEAT_MOUSE_URXVT
6243 "mouse_urxvt",
6244# endif
6245# ifdef FEAT_MOUSE_XTERM
6246 "mouse_xterm",
6247# endif
6248#endif
6249#ifdef FEAT_MBYTE
6250 "multi_byte",
6251#endif
6252#ifdef FEAT_MBYTE_IME
6253 "multi_byte_ime",
6254#endif
6255#ifdef FEAT_MULTI_LANG
6256 "multi_lang",
6257#endif
6258#ifdef FEAT_MZSCHEME
6259#ifndef DYNAMIC_MZSCHEME
6260 "mzscheme",
6261#endif
6262#endif
6263#ifdef FEAT_NUM64
6264 "num64",
6265#endif
6266#ifdef FEAT_OLE
6267 "ole",
6268#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006269#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006271#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272#ifdef FEAT_PATH_EXTRA
6273 "path_extra",
6274#endif
6275#ifdef FEAT_PERL
6276#ifndef DYNAMIC_PERL
6277 "perl",
6278#endif
6279#endif
6280#ifdef FEAT_PERSISTENT_UNDO
6281 "persistent_undo",
6282#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006283#if defined(FEAT_PYTHON)
6284 "python_compiled",
6285# if defined(DYNAMIC_PYTHON)
6286 "python_dynamic",
6287# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006288 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006289 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006290# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006292#if defined(FEAT_PYTHON3)
6293 "python3_compiled",
6294# if defined(DYNAMIC_PYTHON3)
6295 "python3_dynamic",
6296# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006298 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006299# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300#endif
6301#ifdef FEAT_POSTSCRIPT
6302 "postscript",
6303#endif
6304#ifdef FEAT_PRINTER
6305 "printer",
6306#endif
6307#ifdef FEAT_PROFILE
6308 "profile",
6309#endif
6310#ifdef FEAT_RELTIME
6311 "reltime",
6312#endif
6313#ifdef FEAT_QUICKFIX
6314 "quickfix",
6315#endif
6316#ifdef FEAT_RIGHTLEFT
6317 "rightleft",
6318#endif
6319#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6320 "ruby",
6321#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323#ifdef FEAT_CMDL_INFO
6324 "showcmd",
6325 "cmdline_info",
6326#endif
6327#ifdef FEAT_SIGNS
6328 "signs",
6329#endif
6330#ifdef FEAT_SMARTINDENT
6331 "smartindent",
6332#endif
6333#ifdef STARTUPTIME
6334 "startuptime",
6335#endif
6336#ifdef FEAT_STL_OPT
6337 "statusline",
6338#endif
6339#ifdef FEAT_SUN_WORKSHOP
6340 "sun_workshop",
6341#endif
6342#ifdef FEAT_NETBEANS_INTG
6343 "netbeans_intg",
6344#endif
6345#ifdef FEAT_SPELL
6346 "spell",
6347#endif
6348#ifdef FEAT_SYN_HL
6349 "syntax",
6350#endif
6351#if defined(USE_SYSTEM) || !defined(UNIX)
6352 "system",
6353#endif
6354#ifdef FEAT_TAG_BINS
6355 "tag_binary",
6356#endif
6357#ifdef FEAT_TAG_OLDSTATIC
6358 "tag_old_static",
6359#endif
6360#ifdef FEAT_TAG_ANYWHITE
6361 "tag_any_white",
6362#endif
6363#ifdef FEAT_TCL
6364# ifndef DYNAMIC_TCL
6365 "tcl",
6366# endif
6367#endif
6368#ifdef FEAT_TERMGUICOLORS
6369 "termguicolors",
6370#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006371#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006372 "terminal",
6373#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006374#ifdef TERMINFO
6375 "terminfo",
6376#endif
6377#ifdef FEAT_TERMRESPONSE
6378 "termresponse",
6379#endif
6380#ifdef FEAT_TEXTOBJ
6381 "textobjects",
6382#endif
6383#ifdef HAVE_TGETENT
6384 "tgetent",
6385#endif
6386#ifdef FEAT_TIMERS
6387 "timers",
6388#endif
6389#ifdef FEAT_TITLE
6390 "title",
6391#endif
6392#ifdef FEAT_TOOLBAR
6393 "toolbar",
6394#endif
6395#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6396 "unnamedplus",
6397#endif
6398#ifdef FEAT_USR_CMDS
6399 "user-commands", /* was accidentally included in 5.4 */
6400 "user_commands",
6401#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006402#ifdef FEAT_VARTABS
6403 "vartabs",
6404#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006405#ifdef FEAT_VIMINFO
6406 "viminfo",
6407#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006408 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006409#ifdef FEAT_VIRTUALEDIT
6410 "virtualedit",
6411#endif
6412 "visual",
6413#ifdef FEAT_VISUALEXTRA
6414 "visualextra",
6415#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006417#ifdef FEAT_VTP
6418 "vtp",
6419#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420#ifdef FEAT_WILDIGN
6421 "wildignore",
6422#endif
6423#ifdef FEAT_WILDMENU
6424 "wildmenu",
6425#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427#ifdef FEAT_WAK
6428 "winaltkeys",
6429#endif
6430#ifdef FEAT_WRITEBACKUP
6431 "writebackup",
6432#endif
6433#ifdef FEAT_XIM
6434 "xim",
6435#endif
6436#ifdef FEAT_XFONTSET
6437 "xfontset",
6438#endif
6439#ifdef FEAT_XPM_W32
6440 "xpm",
6441 "xpm_w32", /* for backward compatibility */
6442#else
6443# if defined(HAVE_XPM)
6444 "xpm",
6445# endif
6446#endif
6447#ifdef USE_XSMP
6448 "xsmp",
6449#endif
6450#ifdef USE_XSMP_INTERACT
6451 "xsmp_interact",
6452#endif
6453#ifdef FEAT_XCLIPBOARD
6454 "xterm_clipboard",
6455#endif
6456#ifdef FEAT_XTERM_SAVE
6457 "xterm_save",
6458#endif
6459#if defined(UNIX) && defined(FEAT_X11)
6460 "X11",
6461#endif
6462 NULL
6463 };
6464
6465 name = get_tv_string(&argvars[0]);
6466 for (i = 0; has_list[i] != NULL; ++i)
6467 if (STRICMP(name, has_list[i]) == 0)
6468 {
6469 n = TRUE;
6470 break;
6471 }
6472
6473 if (n == FALSE)
6474 {
6475 if (STRNICMP(name, "patch", 5) == 0)
6476 {
6477 if (name[5] == '-'
6478 && STRLEN(name) >= 11
6479 && vim_isdigit(name[6])
6480 && vim_isdigit(name[8])
6481 && vim_isdigit(name[10]))
6482 {
6483 int major = atoi((char *)name + 6);
6484 int minor = atoi((char *)name + 8);
6485
6486 /* Expect "patch-9.9.01234". */
6487 n = (major < VIM_VERSION_MAJOR
6488 || (major == VIM_VERSION_MAJOR
6489 && (minor < VIM_VERSION_MINOR
6490 || (minor == VIM_VERSION_MINOR
6491 && has_patch(atoi((char *)name + 10))))));
6492 }
6493 else
6494 n = has_patch(atoi((char *)name + 5));
6495 }
6496 else if (STRICMP(name, "vim_starting") == 0)
6497 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006498 else if (STRICMP(name, "ttyin") == 0)
6499 n = mch_input_isatty();
6500 else if (STRICMP(name, "ttyout") == 0)
6501 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502#ifdef FEAT_MBYTE
6503 else if (STRICMP(name, "multi_byte_encoding") == 0)
6504 n = has_mbyte;
6505#endif
6506#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6507 else if (STRICMP(name, "balloon_multiline") == 0)
6508 n = multiline_balloon_available();
6509#endif
6510#ifdef DYNAMIC_TCL
6511 else if (STRICMP(name, "tcl") == 0)
6512 n = tcl_enabled(FALSE);
6513#endif
6514#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6515 else if (STRICMP(name, "iconv") == 0)
6516 n = iconv_enabled(FALSE);
6517#endif
6518#ifdef DYNAMIC_LUA
6519 else if (STRICMP(name, "lua") == 0)
6520 n = lua_enabled(FALSE);
6521#endif
6522#ifdef DYNAMIC_MZSCHEME
6523 else if (STRICMP(name, "mzscheme") == 0)
6524 n = mzscheme_enabled(FALSE);
6525#endif
6526#ifdef DYNAMIC_RUBY
6527 else if (STRICMP(name, "ruby") == 0)
6528 n = ruby_enabled(FALSE);
6529#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006530#ifdef DYNAMIC_PYTHON
6531 else if (STRICMP(name, "python") == 0)
6532 n = python_enabled(FALSE);
6533#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006534#ifdef DYNAMIC_PYTHON3
6535 else if (STRICMP(name, "python3") == 0)
6536 n = python3_enabled(FALSE);
6537#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006538#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6539 else if (STRICMP(name, "pythonx") == 0)
6540 {
6541# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6542 if (p_pyx == 0)
6543 n = python3_enabled(FALSE) || python_enabled(FALSE);
6544 else if (p_pyx == 3)
6545 n = python3_enabled(FALSE);
6546 else if (p_pyx == 2)
6547 n = python_enabled(FALSE);
6548# elif defined(DYNAMIC_PYTHON)
6549 n = python_enabled(FALSE);
6550# elif defined(DYNAMIC_PYTHON3)
6551 n = python3_enabled(FALSE);
6552# endif
6553 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554#endif
6555#ifdef DYNAMIC_PERL
6556 else if (STRICMP(name, "perl") == 0)
6557 n = perl_enabled(FALSE);
6558#endif
6559#ifdef FEAT_GUI
6560 else if (STRICMP(name, "gui_running") == 0)
6561 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562# ifdef FEAT_BROWSE
6563 else if (STRICMP(name, "browse") == 0)
6564 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6565# endif
6566#endif
6567#ifdef FEAT_SYN_HL
6568 else if (STRICMP(name, "syntax_items") == 0)
6569 n = syntax_present(curwin);
6570#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006571#ifdef FEAT_VTP
6572 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006573 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574#endif
6575#ifdef FEAT_NETBEANS_INTG
6576 else if (STRICMP(name, "netbeans_enabled") == 0)
6577 n = netbeans_active();
6578#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006579#if defined(FEAT_TERMINAL) && defined(WIN3264)
6580 else if (STRICMP(name, "terminal") == 0)
6581 n = terminal_enabled();
6582#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583 }
6584
6585 rettv->vval.v_number = n;
6586}
6587
6588/*
6589 * "has_key()" function
6590 */
6591 static void
6592f_has_key(typval_T *argvars, typval_T *rettv)
6593{
6594 if (argvars[0].v_type != VAR_DICT)
6595 {
6596 EMSG(_(e_dictreq));
6597 return;
6598 }
6599 if (argvars[0].vval.v_dict == NULL)
6600 return;
6601
6602 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6603 get_tv_string(&argvars[1]), -1) != NULL;
6604}
6605
6606/*
6607 * "haslocaldir()" function
6608 */
6609 static void
6610f_haslocaldir(typval_T *argvars, typval_T *rettv)
6611{
6612 win_T *wp = NULL;
6613
6614 wp = find_tabwin(&argvars[0], &argvars[1]);
6615 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6616}
6617
6618/*
6619 * "hasmapto()" function
6620 */
6621 static void
6622f_hasmapto(typval_T *argvars, typval_T *rettv)
6623{
6624 char_u *name;
6625 char_u *mode;
6626 char_u buf[NUMBUFLEN];
6627 int abbr = FALSE;
6628
6629 name = get_tv_string(&argvars[0]);
6630 if (argvars[1].v_type == VAR_UNKNOWN)
6631 mode = (char_u *)"nvo";
6632 else
6633 {
6634 mode = get_tv_string_buf(&argvars[1], buf);
6635 if (argvars[2].v_type != VAR_UNKNOWN)
6636 abbr = (int)get_tv_number(&argvars[2]);
6637 }
6638
6639 if (map_to_exists(name, mode, abbr))
6640 rettv->vval.v_number = TRUE;
6641 else
6642 rettv->vval.v_number = FALSE;
6643}
6644
6645/*
6646 * "histadd()" function
6647 */
6648 static void
6649f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6650{
6651#ifdef FEAT_CMDHIST
6652 int histype;
6653 char_u *str;
6654 char_u buf[NUMBUFLEN];
6655#endif
6656
6657 rettv->vval.v_number = FALSE;
6658 if (check_restricted() || check_secure())
6659 return;
6660#ifdef FEAT_CMDHIST
6661 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6662 histype = str != NULL ? get_histtype(str) : -1;
6663 if (histype >= 0)
6664 {
6665 str = get_tv_string_buf(&argvars[1], buf);
6666 if (*str != NUL)
6667 {
6668 init_history();
6669 add_to_history(histype, str, FALSE, NUL);
6670 rettv->vval.v_number = TRUE;
6671 return;
6672 }
6673 }
6674#endif
6675}
6676
6677/*
6678 * "histdel()" function
6679 */
6680 static void
6681f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6682{
6683#ifdef FEAT_CMDHIST
6684 int n;
6685 char_u buf[NUMBUFLEN];
6686 char_u *str;
6687
6688 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6689 if (str == NULL)
6690 n = 0;
6691 else if (argvars[1].v_type == VAR_UNKNOWN)
6692 /* only one argument: clear entire history */
6693 n = clr_history(get_histtype(str));
6694 else if (argvars[1].v_type == VAR_NUMBER)
6695 /* index given: remove that entry */
6696 n = del_history_idx(get_histtype(str),
6697 (int)get_tv_number(&argvars[1]));
6698 else
6699 /* string given: remove all matching entries */
6700 n = del_history_entry(get_histtype(str),
6701 get_tv_string_buf(&argvars[1], buf));
6702 rettv->vval.v_number = n;
6703#endif
6704}
6705
6706/*
6707 * "histget()" function
6708 */
6709 static void
6710f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6711{
6712#ifdef FEAT_CMDHIST
6713 int type;
6714 int idx;
6715 char_u *str;
6716
6717 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6718 if (str == NULL)
6719 rettv->vval.v_string = NULL;
6720 else
6721 {
6722 type = get_histtype(str);
6723 if (argvars[1].v_type == VAR_UNKNOWN)
6724 idx = get_history_idx(type);
6725 else
6726 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6727 /* -1 on type error */
6728 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6729 }
6730#else
6731 rettv->vval.v_string = NULL;
6732#endif
6733 rettv->v_type = VAR_STRING;
6734}
6735
6736/*
6737 * "histnr()" function
6738 */
6739 static void
6740f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6741{
6742 int i;
6743
6744#ifdef FEAT_CMDHIST
6745 char_u *history = get_tv_string_chk(&argvars[0]);
6746
6747 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6748 if (i >= HIST_CMD && i < HIST_COUNT)
6749 i = get_history_idx(i);
6750 else
6751#endif
6752 i = -1;
6753 rettv->vval.v_number = i;
6754}
6755
6756/*
6757 * "highlightID(name)" function
6758 */
6759 static void
6760f_hlID(typval_T *argvars, typval_T *rettv)
6761{
6762 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6763}
6764
6765/*
6766 * "highlight_exists()" function
6767 */
6768 static void
6769f_hlexists(typval_T *argvars, typval_T *rettv)
6770{
6771 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6772}
6773
6774/*
6775 * "hostname()" function
6776 */
6777 static void
6778f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6779{
6780 char_u hostname[256];
6781
6782 mch_get_host_name(hostname, 256);
6783 rettv->v_type = VAR_STRING;
6784 rettv->vval.v_string = vim_strsave(hostname);
6785}
6786
6787/*
6788 * iconv() function
6789 */
6790 static void
6791f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6792{
6793#ifdef FEAT_MBYTE
6794 char_u buf1[NUMBUFLEN];
6795 char_u buf2[NUMBUFLEN];
6796 char_u *from, *to, *str;
6797 vimconv_T vimconv;
6798#endif
6799
6800 rettv->v_type = VAR_STRING;
6801 rettv->vval.v_string = NULL;
6802
6803#ifdef FEAT_MBYTE
6804 str = get_tv_string(&argvars[0]);
6805 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6806 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6807 vimconv.vc_type = CONV_NONE;
6808 convert_setup(&vimconv, from, to);
6809
6810 /* If the encodings are equal, no conversion needed. */
6811 if (vimconv.vc_type == CONV_NONE)
6812 rettv->vval.v_string = vim_strsave(str);
6813 else
6814 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6815
6816 convert_setup(&vimconv, NULL, NULL);
6817 vim_free(from);
6818 vim_free(to);
6819#endif
6820}
6821
6822/*
6823 * "indent()" function
6824 */
6825 static void
6826f_indent(typval_T *argvars, typval_T *rettv)
6827{
6828 linenr_T lnum;
6829
6830 lnum = get_tv_lnum(argvars);
6831 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6832 rettv->vval.v_number = get_indent_lnum(lnum);
6833 else
6834 rettv->vval.v_number = -1;
6835}
6836
6837/*
6838 * "index()" function
6839 */
6840 static void
6841f_index(typval_T *argvars, typval_T *rettv)
6842{
6843 list_T *l;
6844 listitem_T *item;
6845 long idx = 0;
6846 int ic = FALSE;
6847
6848 rettv->vval.v_number = -1;
6849 if (argvars[0].v_type != VAR_LIST)
6850 {
6851 EMSG(_(e_listreq));
6852 return;
6853 }
6854 l = argvars[0].vval.v_list;
6855 if (l != NULL)
6856 {
6857 item = l->lv_first;
6858 if (argvars[2].v_type != VAR_UNKNOWN)
6859 {
6860 int error = FALSE;
6861
6862 /* Start at specified item. Use the cached index that list_find()
6863 * sets, so that a negative number also works. */
6864 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6865 idx = l->lv_idx;
6866 if (argvars[3].v_type != VAR_UNKNOWN)
6867 ic = (int)get_tv_number_chk(&argvars[3], &error);
6868 if (error)
6869 item = NULL;
6870 }
6871
6872 for ( ; item != NULL; item = item->li_next, ++idx)
6873 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6874 {
6875 rettv->vval.v_number = idx;
6876 break;
6877 }
6878 }
6879}
6880
6881static int inputsecret_flag = 0;
6882
6883/*
6884 * "input()" function
6885 * Also handles inputsecret() when inputsecret is set.
6886 */
6887 static void
6888f_input(typval_T *argvars, typval_T *rettv)
6889{
6890 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6891}
6892
6893/*
6894 * "inputdialog()" function
6895 */
6896 static void
6897f_inputdialog(typval_T *argvars, typval_T *rettv)
6898{
6899#if defined(FEAT_GUI_TEXTDIALOG)
6900 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6901 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6902 {
6903 char_u *message;
6904 char_u buf[NUMBUFLEN];
6905 char_u *defstr = (char_u *)"";
6906
6907 message = get_tv_string_chk(&argvars[0]);
6908 if (argvars[1].v_type != VAR_UNKNOWN
6909 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6910 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6911 else
6912 IObuff[0] = NUL;
6913 if (message != NULL && defstr != NULL
6914 && do_dialog(VIM_QUESTION, NULL, message,
6915 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6916 rettv->vval.v_string = vim_strsave(IObuff);
6917 else
6918 {
6919 if (message != NULL && defstr != NULL
6920 && argvars[1].v_type != VAR_UNKNOWN
6921 && argvars[2].v_type != VAR_UNKNOWN)
6922 rettv->vval.v_string = vim_strsave(
6923 get_tv_string_buf(&argvars[2], buf));
6924 else
6925 rettv->vval.v_string = NULL;
6926 }
6927 rettv->v_type = VAR_STRING;
6928 }
6929 else
6930#endif
6931 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6932}
6933
6934/*
6935 * "inputlist()" function
6936 */
6937 static void
6938f_inputlist(typval_T *argvars, typval_T *rettv)
6939{
6940 listitem_T *li;
6941 int selected;
6942 int mouse_used;
6943
6944#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006945 /* While starting up, there is no place to enter text. When running tests
6946 * with --not-a-term we assume feedkeys() will be used. */
6947 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 return;
6949#endif
6950 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6951 {
6952 EMSG2(_(e_listarg), "inputlist()");
6953 return;
6954 }
6955
6956 msg_start();
6957 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6958 lines_left = Rows; /* avoid more prompt */
6959 msg_scroll = TRUE;
6960 msg_clr_eos();
6961
6962 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6963 {
6964 msg_puts(get_tv_string(&li->li_tv));
6965 msg_putchar('\n');
6966 }
6967
6968 /* Ask for choice. */
6969 selected = prompt_for_number(&mouse_used);
6970 if (mouse_used)
6971 selected -= lines_left;
6972
6973 rettv->vval.v_number = selected;
6974}
6975
6976
6977static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6978
6979/*
6980 * "inputrestore()" function
6981 */
6982 static void
6983f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6984{
6985 if (ga_userinput.ga_len > 0)
6986 {
6987 --ga_userinput.ga_len;
6988 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6989 + ga_userinput.ga_len);
6990 /* default return is zero == OK */
6991 }
6992 else if (p_verbose > 1)
6993 {
6994 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6995 rettv->vval.v_number = 1; /* Failed */
6996 }
6997}
6998
6999/*
7000 * "inputsave()" function
7001 */
7002 static void
7003f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7004{
7005 /* Add an entry to the stack of typeahead storage. */
7006 if (ga_grow(&ga_userinput, 1) == OK)
7007 {
7008 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7009 + ga_userinput.ga_len);
7010 ++ga_userinput.ga_len;
7011 /* default return is zero == OK */
7012 }
7013 else
7014 rettv->vval.v_number = 1; /* Failed */
7015}
7016
7017/*
7018 * "inputsecret()" function
7019 */
7020 static void
7021f_inputsecret(typval_T *argvars, typval_T *rettv)
7022{
7023 ++cmdline_star;
7024 ++inputsecret_flag;
7025 f_input(argvars, rettv);
7026 --cmdline_star;
7027 --inputsecret_flag;
7028}
7029
7030/*
7031 * "insert()" function
7032 */
7033 static void
7034f_insert(typval_T *argvars, typval_T *rettv)
7035{
7036 long before = 0;
7037 listitem_T *item;
7038 list_T *l;
7039 int error = FALSE;
7040
7041 if (argvars[0].v_type != VAR_LIST)
7042 EMSG2(_(e_listarg), "insert()");
7043 else if ((l = argvars[0].vval.v_list) != NULL
7044 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7045 {
7046 if (argvars[2].v_type != VAR_UNKNOWN)
7047 before = (long)get_tv_number_chk(&argvars[2], &error);
7048 if (error)
7049 return; /* type error; errmsg already given */
7050
7051 if (before == l->lv_len)
7052 item = NULL;
7053 else
7054 {
7055 item = list_find(l, before);
7056 if (item == NULL)
7057 {
7058 EMSGN(_(e_listidx), before);
7059 l = NULL;
7060 }
7061 }
7062 if (l != NULL)
7063 {
7064 list_insert_tv(l, &argvars[1], item);
7065 copy_tv(&argvars[0], rettv);
7066 }
7067 }
7068}
7069
7070/*
7071 * "invert(expr)" function
7072 */
7073 static void
7074f_invert(typval_T *argvars, typval_T *rettv)
7075{
7076 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
7077}
7078
7079/*
7080 * "isdirectory()" function
7081 */
7082 static void
7083f_isdirectory(typval_T *argvars, typval_T *rettv)
7084{
7085 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
7086}
7087
7088/*
7089 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7090 * or it refers to a List or Dictionary that is locked.
7091 */
7092 static int
7093tv_islocked(typval_T *tv)
7094{
7095 return (tv->v_lock & VAR_LOCKED)
7096 || (tv->v_type == VAR_LIST
7097 && tv->vval.v_list != NULL
7098 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7099 || (tv->v_type == VAR_DICT
7100 && tv->vval.v_dict != NULL
7101 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7102}
7103
7104/*
7105 * "islocked()" function
7106 */
7107 static void
7108f_islocked(typval_T *argvars, typval_T *rettv)
7109{
7110 lval_T lv;
7111 char_u *end;
7112 dictitem_T *di;
7113
7114 rettv->vval.v_number = -1;
7115 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007116 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007117 if (end != NULL && lv.ll_name != NULL)
7118 {
7119 if (*end != NUL)
7120 EMSG(_(e_trailing));
7121 else
7122 {
7123 if (lv.ll_tv == NULL)
7124 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007125 di = find_var(lv.ll_name, NULL, TRUE);
7126 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007127 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007128 /* Consider a variable locked when:
7129 * 1. the variable itself is locked
7130 * 2. the value of the variable is locked.
7131 * 3. the List or Dict value is locked.
7132 */
7133 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7134 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 }
7136 }
7137 else if (lv.ll_range)
7138 EMSG(_("E786: Range not allowed"));
7139 else if (lv.ll_newkey != NULL)
7140 EMSG2(_(e_dictkey), lv.ll_newkey);
7141 else if (lv.ll_list != NULL)
7142 /* List item. */
7143 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7144 else
7145 /* Dictionary item. */
7146 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7147 }
7148 }
7149
7150 clear_lval(&lv);
7151}
7152
7153#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7154/*
7155 * "isnan()" function
7156 */
7157 static void
7158f_isnan(typval_T *argvars, typval_T *rettv)
7159{
7160 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7161 && isnan(argvars[0].vval.v_float);
7162}
7163#endif
7164
7165/*
7166 * "items(dict)" function
7167 */
7168 static void
7169f_items(typval_T *argvars, typval_T *rettv)
7170{
7171 dict_list(argvars, rettv, 2);
7172}
7173
7174#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7175/*
7176 * Get the job from the argument.
7177 * Returns NULL if the job is invalid.
7178 */
7179 static job_T *
7180get_job_arg(typval_T *tv)
7181{
7182 job_T *job;
7183
7184 if (tv->v_type != VAR_JOB)
7185 {
7186 EMSG2(_(e_invarg2), get_tv_string(tv));
7187 return NULL;
7188 }
7189 job = tv->vval.v_job;
7190
7191 if (job == NULL)
7192 EMSG(_("E916: not a valid job"));
7193 return job;
7194}
7195
7196/*
7197 * "job_getchannel()" function
7198 */
7199 static void
7200f_job_getchannel(typval_T *argvars, typval_T *rettv)
7201{
7202 job_T *job = get_job_arg(&argvars[0]);
7203
7204 if (job != NULL)
7205 {
7206 rettv->v_type = VAR_CHANNEL;
7207 rettv->vval.v_channel = job->jv_channel;
7208 if (job->jv_channel != NULL)
7209 ++job->jv_channel->ch_refcount;
7210 }
7211}
7212
7213/*
7214 * "job_info()" function
7215 */
7216 static void
7217f_job_info(typval_T *argvars, typval_T *rettv)
7218{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007219 if (argvars[0].v_type != VAR_UNKNOWN)
7220 {
7221 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007222
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007223 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7224 job_info(job, rettv->vval.v_dict);
7225 }
7226 else if (rettv_list_alloc(rettv) == OK)
7227 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228}
7229
7230/*
7231 * "job_setoptions()" function
7232 */
7233 static void
7234f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7235{
7236 job_T *job = get_job_arg(&argvars[0]);
7237 jobopt_T opt;
7238
7239 if (job == NULL)
7240 return;
7241 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007242 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007243 job_set_options(job, &opt);
7244 free_job_options(&opt);
7245}
7246
7247/*
7248 * "job_start()" function
7249 */
7250 static void
7251f_job_start(typval_T *argvars, typval_T *rettv)
7252{
7253 rettv->v_type = VAR_JOB;
7254 if (check_restricted() || check_secure())
7255 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007256 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007257}
7258
7259/*
7260 * "job_status()" function
7261 */
7262 static void
7263f_job_status(typval_T *argvars, typval_T *rettv)
7264{
7265 job_T *job = get_job_arg(&argvars[0]);
7266
7267 if (job != NULL)
7268 {
7269 rettv->v_type = VAR_STRING;
7270 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7271 }
7272}
7273
7274/*
7275 * "job_stop()" function
7276 */
7277 static void
7278f_job_stop(typval_T *argvars, typval_T *rettv)
7279{
7280 job_T *job = get_job_arg(&argvars[0]);
7281
7282 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007283 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007284}
7285#endif
7286
7287/*
7288 * "join()" function
7289 */
7290 static void
7291f_join(typval_T *argvars, typval_T *rettv)
7292{
7293 garray_T ga;
7294 char_u *sep;
7295
7296 if (argvars[0].v_type != VAR_LIST)
7297 {
7298 EMSG(_(e_listreq));
7299 return;
7300 }
7301 if (argvars[0].vval.v_list == NULL)
7302 return;
7303 if (argvars[1].v_type == VAR_UNKNOWN)
7304 sep = (char_u *)" ";
7305 else
7306 sep = get_tv_string_chk(&argvars[1]);
7307
7308 rettv->v_type = VAR_STRING;
7309
7310 if (sep != NULL)
7311 {
7312 ga_init2(&ga, (int)sizeof(char), 80);
7313 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7314 ga_append(&ga, NUL);
7315 rettv->vval.v_string = (char_u *)ga.ga_data;
7316 }
7317 else
7318 rettv->vval.v_string = NULL;
7319}
7320
7321/*
7322 * "js_decode()" function
7323 */
7324 static void
7325f_js_decode(typval_T *argvars, typval_T *rettv)
7326{
7327 js_read_T reader;
7328
7329 reader.js_buf = get_tv_string(&argvars[0]);
7330 reader.js_fill = NULL;
7331 reader.js_used = 0;
7332 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7333 EMSG(_(e_invarg));
7334}
7335
7336/*
7337 * "js_encode()" function
7338 */
7339 static void
7340f_js_encode(typval_T *argvars, typval_T *rettv)
7341{
7342 rettv->v_type = VAR_STRING;
7343 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7344}
7345
7346/*
7347 * "json_decode()" function
7348 */
7349 static void
7350f_json_decode(typval_T *argvars, typval_T *rettv)
7351{
7352 js_read_T reader;
7353
7354 reader.js_buf = get_tv_string(&argvars[0]);
7355 reader.js_fill = NULL;
7356 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007357 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358}
7359
7360/*
7361 * "json_encode()" function
7362 */
7363 static void
7364f_json_encode(typval_T *argvars, typval_T *rettv)
7365{
7366 rettv->v_type = VAR_STRING;
7367 rettv->vval.v_string = json_encode(&argvars[0], 0);
7368}
7369
7370/*
7371 * "keys()" function
7372 */
7373 static void
7374f_keys(typval_T *argvars, typval_T *rettv)
7375{
7376 dict_list(argvars, rettv, 0);
7377}
7378
7379/*
7380 * "last_buffer_nr()" function.
7381 */
7382 static void
7383f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7384{
7385 int n = 0;
7386 buf_T *buf;
7387
Bram Moolenaar29323592016-07-24 22:04:11 +02007388 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389 if (n < buf->b_fnum)
7390 n = buf->b_fnum;
7391
7392 rettv->vval.v_number = n;
7393}
7394
7395/*
7396 * "len()" function
7397 */
7398 static void
7399f_len(typval_T *argvars, typval_T *rettv)
7400{
7401 switch (argvars[0].v_type)
7402 {
7403 case VAR_STRING:
7404 case VAR_NUMBER:
7405 rettv->vval.v_number = (varnumber_T)STRLEN(
7406 get_tv_string(&argvars[0]));
7407 break;
7408 case VAR_LIST:
7409 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7410 break;
7411 case VAR_DICT:
7412 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7413 break;
7414 case VAR_UNKNOWN:
7415 case VAR_SPECIAL:
7416 case VAR_FLOAT:
7417 case VAR_FUNC:
7418 case VAR_PARTIAL:
7419 case VAR_JOB:
7420 case VAR_CHANNEL:
7421 EMSG(_("E701: Invalid type for len()"));
7422 break;
7423 }
7424}
7425
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007427libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428{
7429#ifdef FEAT_LIBCALL
7430 char_u *string_in;
7431 char_u **string_result;
7432 int nr_result;
7433#endif
7434
7435 rettv->v_type = type;
7436 if (type != VAR_NUMBER)
7437 rettv->vval.v_string = NULL;
7438
7439 if (check_restricted() || check_secure())
7440 return;
7441
7442#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007443 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007444 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7445 {
7446 string_in = NULL;
7447 if (argvars[2].v_type == VAR_STRING)
7448 string_in = argvars[2].vval.v_string;
7449 if (type == VAR_NUMBER)
7450 string_result = NULL;
7451 else
7452 string_result = &rettv->vval.v_string;
7453 if (mch_libcall(argvars[0].vval.v_string,
7454 argvars[1].vval.v_string,
7455 string_in,
7456 argvars[2].vval.v_number,
7457 string_result,
7458 &nr_result) == OK
7459 && type == VAR_NUMBER)
7460 rettv->vval.v_number = nr_result;
7461 }
7462#endif
7463}
7464
7465/*
7466 * "libcall()" function
7467 */
7468 static void
7469f_libcall(typval_T *argvars, typval_T *rettv)
7470{
7471 libcall_common(argvars, rettv, VAR_STRING);
7472}
7473
7474/*
7475 * "libcallnr()" function
7476 */
7477 static void
7478f_libcallnr(typval_T *argvars, typval_T *rettv)
7479{
7480 libcall_common(argvars, rettv, VAR_NUMBER);
7481}
7482
7483/*
7484 * "line(string)" function
7485 */
7486 static void
7487f_line(typval_T *argvars, typval_T *rettv)
7488{
7489 linenr_T lnum = 0;
7490 pos_T *fp;
7491 int fnum;
7492
7493 fp = var2fpos(&argvars[0], TRUE, &fnum);
7494 if (fp != NULL)
7495 lnum = fp->lnum;
7496 rettv->vval.v_number = lnum;
7497}
7498
7499/*
7500 * "line2byte(lnum)" function
7501 */
7502 static void
7503f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7504{
7505#ifndef FEAT_BYTEOFF
7506 rettv->vval.v_number = -1;
7507#else
7508 linenr_T lnum;
7509
7510 lnum = get_tv_lnum(argvars);
7511 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7512 rettv->vval.v_number = -1;
7513 else
7514 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7515 if (rettv->vval.v_number >= 0)
7516 ++rettv->vval.v_number;
7517#endif
7518}
7519
7520/*
7521 * "lispindent(lnum)" function
7522 */
7523 static void
7524f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7525{
7526#ifdef FEAT_LISP
7527 pos_T pos;
7528 linenr_T lnum;
7529
7530 pos = curwin->w_cursor;
7531 lnum = get_tv_lnum(argvars);
7532 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7533 {
7534 curwin->w_cursor.lnum = lnum;
7535 rettv->vval.v_number = get_lisp_indent();
7536 curwin->w_cursor = pos;
7537 }
7538 else
7539#endif
7540 rettv->vval.v_number = -1;
7541}
7542
7543/*
7544 * "localtime()" function
7545 */
7546 static void
7547f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7548{
7549 rettv->vval.v_number = (varnumber_T)time(NULL);
7550}
7551
7552static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7553
7554 static void
7555get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7556{
7557 char_u *keys;
7558 char_u *which;
7559 char_u buf[NUMBUFLEN];
7560 char_u *keys_buf = NULL;
7561 char_u *rhs;
7562 int mode;
7563 int abbr = FALSE;
7564 int get_dict = FALSE;
7565 mapblock_T *mp;
7566 int buffer_local;
7567
7568 /* return empty string for failure */
7569 rettv->v_type = VAR_STRING;
7570 rettv->vval.v_string = NULL;
7571
7572 keys = get_tv_string(&argvars[0]);
7573 if (*keys == NUL)
7574 return;
7575
7576 if (argvars[1].v_type != VAR_UNKNOWN)
7577 {
7578 which = get_tv_string_buf_chk(&argvars[1], buf);
7579 if (argvars[2].v_type != VAR_UNKNOWN)
7580 {
7581 abbr = (int)get_tv_number(&argvars[2]);
7582 if (argvars[3].v_type != VAR_UNKNOWN)
7583 get_dict = (int)get_tv_number(&argvars[3]);
7584 }
7585 }
7586 else
7587 which = (char_u *)"";
7588 if (which == NULL)
7589 return;
7590
7591 mode = get_map_mode(&which, 0);
7592
7593 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7594 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7595 vim_free(keys_buf);
7596
7597 if (!get_dict)
7598 {
7599 /* Return a string. */
7600 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007601 {
7602 if (*rhs == NUL)
7603 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7604 else
7605 rettv->vval.v_string = str2special_save(rhs, FALSE);
7606 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007607
7608 }
7609 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7610 {
7611 /* Return a dictionary. */
7612 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7613 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7614 dict_T *dict = rettv->vval.v_dict;
7615
Bram Moolenaare0be1672018-07-08 16:50:37 +02007616 dict_add_string(dict, "lhs", lhs);
7617 dict_add_string(dict, "rhs", mp->m_orig_str);
7618 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7619 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7620 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007621 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7622 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007623 dict_add_number(dict, "buffer", (long)buffer_local);
7624 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7625 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626
7627 vim_free(lhs);
7628 vim_free(mapmode);
7629 }
7630}
7631
7632#ifdef FEAT_FLOAT
7633/*
7634 * "log()" function
7635 */
7636 static void
7637f_log(typval_T *argvars, typval_T *rettv)
7638{
7639 float_T f = 0.0;
7640
7641 rettv->v_type = VAR_FLOAT;
7642 if (get_float_arg(argvars, &f) == OK)
7643 rettv->vval.v_float = log(f);
7644 else
7645 rettv->vval.v_float = 0.0;
7646}
7647
7648/*
7649 * "log10()" function
7650 */
7651 static void
7652f_log10(typval_T *argvars, typval_T *rettv)
7653{
7654 float_T f = 0.0;
7655
7656 rettv->v_type = VAR_FLOAT;
7657 if (get_float_arg(argvars, &f) == OK)
7658 rettv->vval.v_float = log10(f);
7659 else
7660 rettv->vval.v_float = 0.0;
7661}
7662#endif
7663
7664#ifdef FEAT_LUA
7665/*
7666 * "luaeval()" function
7667 */
7668 static void
7669f_luaeval(typval_T *argvars, typval_T *rettv)
7670{
7671 char_u *str;
7672 char_u buf[NUMBUFLEN];
7673
7674 str = get_tv_string_buf(&argvars[0], buf);
7675 do_luaeval(str, argvars + 1, rettv);
7676}
7677#endif
7678
7679/*
7680 * "map()" function
7681 */
7682 static void
7683f_map(typval_T *argvars, typval_T *rettv)
7684{
7685 filter_map(argvars, rettv, TRUE);
7686}
7687
7688/*
7689 * "maparg()" function
7690 */
7691 static void
7692f_maparg(typval_T *argvars, typval_T *rettv)
7693{
7694 get_maparg(argvars, rettv, TRUE);
7695}
7696
7697/*
7698 * "mapcheck()" function
7699 */
7700 static void
7701f_mapcheck(typval_T *argvars, typval_T *rettv)
7702{
7703 get_maparg(argvars, rettv, FALSE);
7704}
7705
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007706typedef enum
7707{
7708 MATCH_END, /* matchend() */
7709 MATCH_MATCH, /* match() */
7710 MATCH_STR, /* matchstr() */
7711 MATCH_LIST, /* matchlist() */
7712 MATCH_POS /* matchstrpos() */
7713} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714
7715 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007716find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717{
7718 char_u *str = NULL;
7719 long len = 0;
7720 char_u *expr = NULL;
7721 char_u *pat;
7722 regmatch_T regmatch;
7723 char_u patbuf[NUMBUFLEN];
7724 char_u strbuf[NUMBUFLEN];
7725 char_u *save_cpo;
7726 long start = 0;
7727 long nth = 1;
7728 colnr_T startcol = 0;
7729 int match = 0;
7730 list_T *l = NULL;
7731 listitem_T *li = NULL;
7732 long idx = 0;
7733 char_u *tofree = NULL;
7734
7735 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7736 save_cpo = p_cpo;
7737 p_cpo = (char_u *)"";
7738
7739 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007740 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007741 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007742 /* type MATCH_LIST: return empty list when there are no matches.
7743 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 if (rettv_list_alloc(rettv) == FAIL)
7745 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007746 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747 && (list_append_string(rettv->vval.v_list,
7748 (char_u *)"", 0) == FAIL
7749 || list_append_number(rettv->vval.v_list,
7750 (varnumber_T)-1) == FAIL
7751 || list_append_number(rettv->vval.v_list,
7752 (varnumber_T)-1) == FAIL
7753 || list_append_number(rettv->vval.v_list,
7754 (varnumber_T)-1) == FAIL))
7755 {
7756 list_free(rettv->vval.v_list);
7757 rettv->vval.v_list = NULL;
7758 goto theend;
7759 }
7760 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007761 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007762 {
7763 rettv->v_type = VAR_STRING;
7764 rettv->vval.v_string = NULL;
7765 }
7766
7767 if (argvars[0].v_type == VAR_LIST)
7768 {
7769 if ((l = argvars[0].vval.v_list) == NULL)
7770 goto theend;
7771 li = l->lv_first;
7772 }
7773 else
7774 {
7775 expr = str = get_tv_string(&argvars[0]);
7776 len = (long)STRLEN(str);
7777 }
7778
7779 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7780 if (pat == NULL)
7781 goto theend;
7782
7783 if (argvars[2].v_type != VAR_UNKNOWN)
7784 {
7785 int error = FALSE;
7786
7787 start = (long)get_tv_number_chk(&argvars[2], &error);
7788 if (error)
7789 goto theend;
7790 if (l != NULL)
7791 {
7792 li = list_find(l, start);
7793 if (li == NULL)
7794 goto theend;
7795 idx = l->lv_idx; /* use the cached index */
7796 }
7797 else
7798 {
7799 if (start < 0)
7800 start = 0;
7801 if (start > len)
7802 goto theend;
7803 /* When "count" argument is there ignore matches before "start",
7804 * otherwise skip part of the string. Differs when pattern is "^"
7805 * or "\<". */
7806 if (argvars[3].v_type != VAR_UNKNOWN)
7807 startcol = start;
7808 else
7809 {
7810 str += start;
7811 len -= start;
7812 }
7813 }
7814
7815 if (argvars[3].v_type != VAR_UNKNOWN)
7816 nth = (long)get_tv_number_chk(&argvars[3], &error);
7817 if (error)
7818 goto theend;
7819 }
7820
7821 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7822 if (regmatch.regprog != NULL)
7823 {
7824 regmatch.rm_ic = p_ic;
7825
7826 for (;;)
7827 {
7828 if (l != NULL)
7829 {
7830 if (li == NULL)
7831 {
7832 match = FALSE;
7833 break;
7834 }
7835 vim_free(tofree);
7836 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7837 if (str == NULL)
7838 break;
7839 }
7840
7841 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7842
7843 if (match && --nth <= 0)
7844 break;
7845 if (l == NULL && !match)
7846 break;
7847
7848 /* Advance to just after the match. */
7849 if (l != NULL)
7850 {
7851 li = li->li_next;
7852 ++idx;
7853 }
7854 else
7855 {
7856#ifdef FEAT_MBYTE
7857 startcol = (colnr_T)(regmatch.startp[0]
7858 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7859#else
7860 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7861#endif
7862 if (startcol > (colnr_T)len
7863 || str + startcol <= regmatch.startp[0])
7864 {
7865 match = FALSE;
7866 break;
7867 }
7868 }
7869 }
7870
7871 if (match)
7872 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007873 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 {
7875 listitem_T *li1 = rettv->vval.v_list->lv_first;
7876 listitem_T *li2 = li1->li_next;
7877 listitem_T *li3 = li2->li_next;
7878 listitem_T *li4 = li3->li_next;
7879
7880 vim_free(li1->li_tv.vval.v_string);
7881 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7882 (int)(regmatch.endp[0] - regmatch.startp[0]));
7883 li3->li_tv.vval.v_number =
7884 (varnumber_T)(regmatch.startp[0] - expr);
7885 li4->li_tv.vval.v_number =
7886 (varnumber_T)(regmatch.endp[0] - expr);
7887 if (l != NULL)
7888 li2->li_tv.vval.v_number = (varnumber_T)idx;
7889 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007890 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007891 {
7892 int i;
7893
7894 /* return list with matched string and submatches */
7895 for (i = 0; i < NSUBEXP; ++i)
7896 {
7897 if (regmatch.endp[i] == NULL)
7898 {
7899 if (list_append_string(rettv->vval.v_list,
7900 (char_u *)"", 0) == FAIL)
7901 break;
7902 }
7903 else if (list_append_string(rettv->vval.v_list,
7904 regmatch.startp[i],
7905 (int)(regmatch.endp[i] - regmatch.startp[i]))
7906 == FAIL)
7907 break;
7908 }
7909 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007910 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007911 {
7912 /* return matched string */
7913 if (l != NULL)
7914 copy_tv(&li->li_tv, rettv);
7915 else
7916 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7917 (int)(regmatch.endp[0] - regmatch.startp[0]));
7918 }
7919 else if (l != NULL)
7920 rettv->vval.v_number = idx;
7921 else
7922 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007923 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924 rettv->vval.v_number =
7925 (varnumber_T)(regmatch.startp[0] - str);
7926 else
7927 rettv->vval.v_number =
7928 (varnumber_T)(regmatch.endp[0] - str);
7929 rettv->vval.v_number += (varnumber_T)(str - expr);
7930 }
7931 }
7932 vim_regfree(regmatch.regprog);
7933 }
7934
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007935theend:
7936 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 /* matchstrpos() without a list: drop the second item. */
7938 listitem_remove(rettv->vval.v_list,
7939 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007940 vim_free(tofree);
7941 p_cpo = save_cpo;
7942}
7943
7944/*
7945 * "match()" function
7946 */
7947 static void
7948f_match(typval_T *argvars, typval_T *rettv)
7949{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007950 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951}
7952
Bram Moolenaar95e51472018-07-28 16:55:56 +02007953#ifdef FEAT_SEARCH_EXTRA
7954 static int
7955matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
7956{
7957 dictitem_T *di;
7958
7959 if (tv->v_type != VAR_DICT)
7960 {
7961 EMSG(_(e_dictreq));
7962 return FAIL;
7963 }
7964
7965 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
7966 *conceal_char = get_dict_string(tv->vval.v_dict,
7967 (char_u *)"conceal", FALSE);
7968
7969 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
7970 {
7971 *win = find_win_by_nr(&di->di_tv, NULL);
7972 if (*win == NULL)
7973 {
7974 EMSG(_("E957: Invalid window number"));
7975 return FAIL;
7976 }
7977 }
7978
7979 return OK;
7980}
7981#endif
7982
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007983/*
7984 * "matchadd()" function
7985 */
7986 static void
7987f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7988{
7989#ifdef FEAT_SEARCH_EXTRA
7990 char_u buf[NUMBUFLEN];
7991 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7992 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7993 int prio = 10; /* default priority */
7994 int id = -1;
7995 int error = FALSE;
7996 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02007997 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007998
7999 rettv->vval.v_number = -1;
8000
8001 if (grp == NULL || pat == NULL)
8002 return;
8003 if (argvars[2].v_type != VAR_UNKNOWN)
8004 {
8005 prio = (int)get_tv_number_chk(&argvars[2], &error);
8006 if (argvars[3].v_type != VAR_UNKNOWN)
8007 {
8008 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008009 if (argvars[4].v_type != VAR_UNKNOWN
8010 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8011 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008012 }
8013 }
8014 if (error == TRUE)
8015 return;
8016 if (id >= 1 && id <= 3)
8017 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008018 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019 return;
8020 }
8021
Bram Moolenaar95e51472018-07-28 16:55:56 +02008022 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023 conceal_char);
8024#endif
8025}
8026
8027/*
8028 * "matchaddpos()" function
8029 */
8030 static void
8031f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8032{
8033#ifdef FEAT_SEARCH_EXTRA
8034 char_u buf[NUMBUFLEN];
8035 char_u *group;
8036 int prio = 10;
8037 int id = -1;
8038 int error = FALSE;
8039 list_T *l;
8040 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008041 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042
8043 rettv->vval.v_number = -1;
8044
8045 group = get_tv_string_buf_chk(&argvars[0], buf);
8046 if (group == NULL)
8047 return;
8048
8049 if (argvars[1].v_type != VAR_LIST)
8050 {
8051 EMSG2(_(e_listarg), "matchaddpos()");
8052 return;
8053 }
8054 l = argvars[1].vval.v_list;
8055 if (l == NULL)
8056 return;
8057
8058 if (argvars[2].v_type != VAR_UNKNOWN)
8059 {
8060 prio = (int)get_tv_number_chk(&argvars[2], &error);
8061 if (argvars[3].v_type != VAR_UNKNOWN)
8062 {
8063 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008064
8065 if (argvars[4].v_type != VAR_UNKNOWN
8066 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8067 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008068 }
8069 }
8070 if (error == TRUE)
8071 return;
8072
8073 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8074 if (id == 1 || id == 2)
8075 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008076 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008077 return;
8078 }
8079
Bram Moolenaar95e51472018-07-28 16:55:56 +02008080 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081 conceal_char);
8082#endif
8083}
8084
8085/*
8086 * "matcharg()" function
8087 */
8088 static void
8089f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8090{
8091 if (rettv_list_alloc(rettv) == OK)
8092 {
8093#ifdef FEAT_SEARCH_EXTRA
8094 int id = (int)get_tv_number(&argvars[0]);
8095 matchitem_T *m;
8096
8097 if (id >= 1 && id <= 3)
8098 {
8099 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8100 {
8101 list_append_string(rettv->vval.v_list,
8102 syn_id2name(m->hlg_id), -1);
8103 list_append_string(rettv->vval.v_list, m->pattern, -1);
8104 }
8105 else
8106 {
8107 list_append_string(rettv->vval.v_list, NULL, -1);
8108 list_append_string(rettv->vval.v_list, NULL, -1);
8109 }
8110 }
8111#endif
8112 }
8113}
8114
8115/*
8116 * "matchdelete()" function
8117 */
8118 static void
8119f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8120{
8121#ifdef FEAT_SEARCH_EXTRA
8122 rettv->vval.v_number = match_delete(curwin,
8123 (int)get_tv_number(&argvars[0]), TRUE);
8124#endif
8125}
8126
8127/*
8128 * "matchend()" function
8129 */
8130 static void
8131f_matchend(typval_T *argvars, typval_T *rettv)
8132{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008133 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008134}
8135
8136/*
8137 * "matchlist()" function
8138 */
8139 static void
8140f_matchlist(typval_T *argvars, typval_T *rettv)
8141{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008142 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008143}
8144
8145/*
8146 * "matchstr()" function
8147 */
8148 static void
8149f_matchstr(typval_T *argvars, typval_T *rettv)
8150{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008151 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008152}
8153
8154/*
8155 * "matchstrpos()" function
8156 */
8157 static void
8158f_matchstrpos(typval_T *argvars, typval_T *rettv)
8159{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008160 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161}
8162
8163static void max_min(typval_T *argvars, typval_T *rettv, int domax);
8164
8165 static void
8166max_min(typval_T *argvars, typval_T *rettv, int domax)
8167{
8168 varnumber_T n = 0;
8169 varnumber_T i;
8170 int error = FALSE;
8171
8172 if (argvars[0].v_type == VAR_LIST)
8173 {
8174 list_T *l;
8175 listitem_T *li;
8176
8177 l = argvars[0].vval.v_list;
8178 if (l != NULL)
8179 {
8180 li = l->lv_first;
8181 if (li != NULL)
8182 {
8183 n = get_tv_number_chk(&li->li_tv, &error);
8184 for (;;)
8185 {
8186 li = li->li_next;
8187 if (li == NULL)
8188 break;
8189 i = get_tv_number_chk(&li->li_tv, &error);
8190 if (domax ? i > n : i < n)
8191 n = i;
8192 }
8193 }
8194 }
8195 }
8196 else if (argvars[0].v_type == VAR_DICT)
8197 {
8198 dict_T *d;
8199 int first = TRUE;
8200 hashitem_T *hi;
8201 int todo;
8202
8203 d = argvars[0].vval.v_dict;
8204 if (d != NULL)
8205 {
8206 todo = (int)d->dv_hashtab.ht_used;
8207 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8208 {
8209 if (!HASHITEM_EMPTY(hi))
8210 {
8211 --todo;
8212 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8213 if (first)
8214 {
8215 n = i;
8216 first = FALSE;
8217 }
8218 else if (domax ? i > n : i < n)
8219 n = i;
8220 }
8221 }
8222 }
8223 }
8224 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008225 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226 rettv->vval.v_number = error ? 0 : n;
8227}
8228
8229/*
8230 * "max()" function
8231 */
8232 static void
8233f_max(typval_T *argvars, typval_T *rettv)
8234{
8235 max_min(argvars, rettv, TRUE);
8236}
8237
8238/*
8239 * "min()" function
8240 */
8241 static void
8242f_min(typval_T *argvars, typval_T *rettv)
8243{
8244 max_min(argvars, rettv, FALSE);
8245}
8246
8247static int mkdir_recurse(char_u *dir, int prot);
8248
8249/*
8250 * Create the directory in which "dir" is located, and higher levels when
8251 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008252 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008253 */
8254 static int
8255mkdir_recurse(char_u *dir, int prot)
8256{
8257 char_u *p;
8258 char_u *updir;
8259 int r = FAIL;
8260
8261 /* Get end of directory name in "dir".
8262 * We're done when it's "/" or "c:/". */
8263 p = gettail_sep(dir);
8264 if (p <= get_past_head(dir))
8265 return OK;
8266
8267 /* If the directory exists we're done. Otherwise: create it.*/
8268 updir = vim_strnsave(dir, (int)(p - dir));
8269 if (updir == NULL)
8270 return FAIL;
8271 if (mch_isdir(updir))
8272 r = OK;
8273 else if (mkdir_recurse(updir, prot) == OK)
8274 r = vim_mkdir_emsg(updir, prot);
8275 vim_free(updir);
8276 return r;
8277}
8278
8279#ifdef vim_mkdir
8280/*
8281 * "mkdir()" function
8282 */
8283 static void
8284f_mkdir(typval_T *argvars, typval_T *rettv)
8285{
8286 char_u *dir;
8287 char_u buf[NUMBUFLEN];
8288 int prot = 0755;
8289
8290 rettv->vval.v_number = FAIL;
8291 if (check_restricted() || check_secure())
8292 return;
8293
8294 dir = get_tv_string_buf(&argvars[0], buf);
8295 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008296 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008297
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008298 if (*gettail(dir) == NUL)
8299 /* remove trailing slashes */
8300 *gettail_sep(dir) = NUL;
8301
8302 if (argvars[1].v_type != VAR_UNKNOWN)
8303 {
8304 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008306 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8307 if (prot == -1)
8308 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008309 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008310 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8311 {
8312 if (mch_isdir(dir))
8313 {
8314 /* With the "p" flag it's OK if the dir already exists. */
8315 rettv->vval.v_number = OK;
8316 return;
8317 }
8318 mkdir_recurse(dir, prot);
8319 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008320 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008321 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008322}
8323#endif
8324
8325/*
8326 * "mode()" function
8327 */
8328 static void
8329f_mode(typval_T *argvars, typval_T *rettv)
8330{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008331 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008332
Bram Moolenaar612cc382018-07-29 15:34:26 +02008333 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008334
8335 if (time_for_testing == 93784)
8336 {
8337 /* Testing the two-character code. */
8338 buf[0] = 'x';
8339 buf[1] = '!';
8340 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008341#ifdef FEAT_TERMINAL
8342 else if (term_use_loop())
8343 buf[0] = 't';
8344#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008345 else if (VIsual_active)
8346 {
8347 if (VIsual_select)
8348 buf[0] = VIsual_mode + 's' - 'v';
8349 else
8350 buf[0] = VIsual_mode;
8351 }
8352 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8353 || State == CONFIRM)
8354 {
8355 buf[0] = 'r';
8356 if (State == ASKMORE)
8357 buf[1] = 'm';
8358 else if (State == CONFIRM)
8359 buf[1] = '?';
8360 }
8361 else if (State == EXTERNCMD)
8362 buf[0] = '!';
8363 else if (State & INSERT)
8364 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008365 if (State & VREPLACE_FLAG)
8366 {
8367 buf[0] = 'R';
8368 buf[1] = 'v';
8369 }
8370 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008371 {
8372 if (State & REPLACE_FLAG)
8373 buf[0] = 'R';
8374 else
8375 buf[0] = 'i';
8376#ifdef FEAT_INS_EXPAND
8377 if (ins_compl_active())
8378 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008379 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008380 buf[1] = 'x';
8381#endif
8382 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008383 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008384 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008385 {
8386 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008387 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008389 else if (exmode_active == EXMODE_NORMAL)
8390 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008391 }
8392 else
8393 {
8394 buf[0] = 'n';
8395 if (finish_op)
8396 buf[1] = 'o';
Bram Moolenaar612cc382018-07-29 15:34:26 +02008397 else if (restart_edit == 'I' || restart_edit == 'R'
8398 || restart_edit == 'V')
8399 {
8400 buf[1] = 'i';
8401 buf[2] = restart_edit;
8402 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008403 }
8404
8405 /* Clear out the minor mode when the argument is not a non-zero number or
8406 * non-empty string. */
8407 if (!non_zero_arg(&argvars[0]))
8408 buf[1] = NUL;
8409
8410 rettv->vval.v_string = vim_strsave(buf);
8411 rettv->v_type = VAR_STRING;
8412}
8413
8414#if defined(FEAT_MZSCHEME) || defined(PROTO)
8415/*
8416 * "mzeval()" function
8417 */
8418 static void
8419f_mzeval(typval_T *argvars, typval_T *rettv)
8420{
8421 char_u *str;
8422 char_u buf[NUMBUFLEN];
8423
8424 str = get_tv_string_buf(&argvars[0], buf);
8425 do_mzeval(str, rettv);
8426}
8427
8428 void
8429mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8430{
8431 typval_T argvars[3];
8432
8433 argvars[0].v_type = VAR_STRING;
8434 argvars[0].vval.v_string = name;
8435 copy_tv(args, &argvars[1]);
8436 argvars[2].v_type = VAR_UNKNOWN;
8437 f_call(argvars, rettv);
8438 clear_tv(&argvars[1]);
8439}
8440#endif
8441
8442/*
8443 * "nextnonblank()" function
8444 */
8445 static void
8446f_nextnonblank(typval_T *argvars, typval_T *rettv)
8447{
8448 linenr_T lnum;
8449
8450 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8451 {
8452 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8453 {
8454 lnum = 0;
8455 break;
8456 }
8457 if (*skipwhite(ml_get(lnum)) != NUL)
8458 break;
8459 }
8460 rettv->vval.v_number = lnum;
8461}
8462
8463/*
8464 * "nr2char()" function
8465 */
8466 static void
8467f_nr2char(typval_T *argvars, typval_T *rettv)
8468{
8469 char_u buf[NUMBUFLEN];
8470
8471#ifdef FEAT_MBYTE
8472 if (has_mbyte)
8473 {
8474 int utf8 = 0;
8475
8476 if (argvars[1].v_type != VAR_UNKNOWN)
8477 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8478 if (utf8)
8479 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8480 else
8481 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8482 }
8483 else
8484#endif
8485 {
8486 buf[0] = (char_u)get_tv_number(&argvars[0]);
8487 buf[1] = NUL;
8488 }
8489 rettv->v_type = VAR_STRING;
8490 rettv->vval.v_string = vim_strsave(buf);
8491}
8492
8493/*
8494 * "or(expr, expr)" function
8495 */
8496 static void
8497f_or(typval_T *argvars, typval_T *rettv)
8498{
8499 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8500 | get_tv_number_chk(&argvars[1], NULL);
8501}
8502
8503/*
8504 * "pathshorten()" function
8505 */
8506 static void
8507f_pathshorten(typval_T *argvars, typval_T *rettv)
8508{
8509 char_u *p;
8510
8511 rettv->v_type = VAR_STRING;
8512 p = get_tv_string_chk(&argvars[0]);
8513 if (p == NULL)
8514 rettv->vval.v_string = NULL;
8515 else
8516 {
8517 p = vim_strsave(p);
8518 rettv->vval.v_string = p;
8519 if (p != NULL)
8520 shorten_dir(p);
8521 }
8522}
8523
8524#ifdef FEAT_PERL
8525/*
8526 * "perleval()" function
8527 */
8528 static void
8529f_perleval(typval_T *argvars, typval_T *rettv)
8530{
8531 char_u *str;
8532 char_u buf[NUMBUFLEN];
8533
8534 str = get_tv_string_buf(&argvars[0], buf);
8535 do_perleval(str, rettv);
8536}
8537#endif
8538
8539#ifdef FEAT_FLOAT
8540/*
8541 * "pow()" function
8542 */
8543 static void
8544f_pow(typval_T *argvars, typval_T *rettv)
8545{
8546 float_T fx = 0.0, fy = 0.0;
8547
8548 rettv->v_type = VAR_FLOAT;
8549 if (get_float_arg(argvars, &fx) == OK
8550 && get_float_arg(&argvars[1], &fy) == OK)
8551 rettv->vval.v_float = pow(fx, fy);
8552 else
8553 rettv->vval.v_float = 0.0;
8554}
8555#endif
8556
8557/*
8558 * "prevnonblank()" function
8559 */
8560 static void
8561f_prevnonblank(typval_T *argvars, typval_T *rettv)
8562{
8563 linenr_T lnum;
8564
8565 lnum = get_tv_lnum(argvars);
8566 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8567 lnum = 0;
8568 else
8569 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8570 --lnum;
8571 rettv->vval.v_number = lnum;
8572}
8573
8574/* This dummy va_list is here because:
8575 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8576 * - locally in the function results in a "used before set" warning
8577 * - using va_start() to initialize it gives "function with fixed args" error */
8578static va_list ap;
8579
8580/*
8581 * "printf()" function
8582 */
8583 static void
8584f_printf(typval_T *argvars, typval_T *rettv)
8585{
8586 char_u buf[NUMBUFLEN];
8587 int len;
8588 char_u *s;
8589 int saved_did_emsg = did_emsg;
8590 char *fmt;
8591
8592 rettv->v_type = VAR_STRING;
8593 rettv->vval.v_string = NULL;
8594
8595 /* Get the required length, allocate the buffer and do it for real. */
8596 did_emsg = FALSE;
8597 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008598 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008599 if (!did_emsg)
8600 {
8601 s = alloc(len + 1);
8602 if (s != NULL)
8603 {
8604 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008605 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8606 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 }
8608 }
8609 did_emsg |= saved_did_emsg;
8610}
8611
Bram Moolenaarf2732452018-06-03 14:47:35 +02008612#ifdef FEAT_JOB_CHANNEL
8613/*
8614 * "prompt_setcallback({buffer}, {callback})" function
8615 */
8616 static void
8617f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8618{
8619 buf_T *buf;
8620 char_u *callback;
8621 partial_T *partial;
8622
8623 if (check_secure())
8624 return;
8625 buf = get_buf_tv(&argvars[0], FALSE);
8626 if (buf == NULL)
8627 return;
8628
8629 callback = get_callback(&argvars[1], &partial);
8630 if (callback == NULL)
8631 return;
8632
8633 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8634 if (partial == NULL)
8635 buf->b_prompt_callback = vim_strsave(callback);
8636 else
8637 /* pointer into the partial */
8638 buf->b_prompt_callback = callback;
8639 buf->b_prompt_partial = partial;
8640}
8641
8642/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008643 * "prompt_setinterrupt({buffer}, {callback})" function
8644 */
8645 static void
8646f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8647{
8648 buf_T *buf;
8649 char_u *callback;
8650 partial_T *partial;
8651
8652 if (check_secure())
8653 return;
8654 buf = get_buf_tv(&argvars[0], FALSE);
8655 if (buf == NULL)
8656 return;
8657
8658 callback = get_callback(&argvars[1], &partial);
8659 if (callback == NULL)
8660 return;
8661
8662 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8663 if (partial == NULL)
8664 buf->b_prompt_interrupt = vim_strsave(callback);
8665 else
8666 /* pointer into the partial */
8667 buf->b_prompt_interrupt = callback;
8668 buf->b_prompt_int_partial = partial;
8669}
8670
8671/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008672 * "prompt_setprompt({buffer}, {text})" function
8673 */
8674 static void
8675f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8676{
8677 buf_T *buf;
8678 char_u *text;
8679
8680 if (check_secure())
8681 return;
8682 buf = get_buf_tv(&argvars[0], FALSE);
8683 if (buf == NULL)
8684 return;
8685
8686 text = get_tv_string(&argvars[1]);
8687 vim_free(buf->b_prompt_text);
8688 buf->b_prompt_text = vim_strsave(text);
8689}
8690#endif
8691
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008692/*
8693 * "pumvisible()" function
8694 */
8695 static void
8696f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8697{
8698#ifdef FEAT_INS_EXPAND
8699 if (pum_visible())
8700 rettv->vval.v_number = 1;
8701#endif
8702}
8703
8704#ifdef FEAT_PYTHON3
8705/*
8706 * "py3eval()" function
8707 */
8708 static void
8709f_py3eval(typval_T *argvars, typval_T *rettv)
8710{
8711 char_u *str;
8712 char_u buf[NUMBUFLEN];
8713
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008714 if (p_pyx == 0)
8715 p_pyx = 3;
8716
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008717 str = get_tv_string_buf(&argvars[0], buf);
8718 do_py3eval(str, rettv);
8719}
8720#endif
8721
8722#ifdef FEAT_PYTHON
8723/*
8724 * "pyeval()" function
8725 */
8726 static void
8727f_pyeval(typval_T *argvars, typval_T *rettv)
8728{
8729 char_u *str;
8730 char_u buf[NUMBUFLEN];
8731
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008732 if (p_pyx == 0)
8733 p_pyx = 2;
8734
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008735 str = get_tv_string_buf(&argvars[0], buf);
8736 do_pyeval(str, rettv);
8737}
8738#endif
8739
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008740#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8741/*
8742 * "pyxeval()" function
8743 */
8744 static void
8745f_pyxeval(typval_T *argvars, typval_T *rettv)
8746{
8747# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8748 init_pyxversion();
8749 if (p_pyx == 2)
8750 f_pyeval(argvars, rettv);
8751 else
8752 f_py3eval(argvars, rettv);
8753# elif defined(FEAT_PYTHON)
8754 f_pyeval(argvars, rettv);
8755# elif defined(FEAT_PYTHON3)
8756 f_py3eval(argvars, rettv);
8757# endif
8758}
8759#endif
8760
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008761/*
8762 * "range()" function
8763 */
8764 static void
8765f_range(typval_T *argvars, typval_T *rettv)
8766{
8767 varnumber_T start;
8768 varnumber_T end;
8769 varnumber_T stride = 1;
8770 varnumber_T i;
8771 int error = FALSE;
8772
8773 start = get_tv_number_chk(&argvars[0], &error);
8774 if (argvars[1].v_type == VAR_UNKNOWN)
8775 {
8776 end = start - 1;
8777 start = 0;
8778 }
8779 else
8780 {
8781 end = get_tv_number_chk(&argvars[1], &error);
8782 if (argvars[2].v_type != VAR_UNKNOWN)
8783 stride = get_tv_number_chk(&argvars[2], &error);
8784 }
8785
8786 if (error)
8787 return; /* type error; errmsg already given */
8788 if (stride == 0)
8789 EMSG(_("E726: Stride is zero"));
8790 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8791 EMSG(_("E727: Start past end"));
8792 else
8793 {
8794 if (rettv_list_alloc(rettv) == OK)
8795 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8796 if (list_append_number(rettv->vval.v_list,
8797 (varnumber_T)i) == FAIL)
8798 break;
8799 }
8800}
8801
8802/*
8803 * "readfile()" function
8804 */
8805 static void
8806f_readfile(typval_T *argvars, typval_T *rettv)
8807{
8808 int binary = FALSE;
8809 int failed = FALSE;
8810 char_u *fname;
8811 FILE *fd;
8812 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8813 int io_size = sizeof(buf);
8814 int readlen; /* size of last fread() */
8815 char_u *prev = NULL; /* previously read bytes, if any */
8816 long prevlen = 0; /* length of data in prev */
8817 long prevsize = 0; /* size of prev buffer */
8818 long maxline = MAXLNUM;
8819 long cnt = 0;
8820 char_u *p; /* position in buf */
8821 char_u *start; /* start of current line */
8822
8823 if (argvars[1].v_type != VAR_UNKNOWN)
8824 {
8825 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8826 binary = TRUE;
8827 if (argvars[2].v_type != VAR_UNKNOWN)
8828 maxline = (long)get_tv_number(&argvars[2]);
8829 }
8830
8831 if (rettv_list_alloc(rettv) == FAIL)
8832 return;
8833
8834 /* Always open the file in binary mode, library functions have a mind of
8835 * their own about CR-LF conversion. */
8836 fname = get_tv_string(&argvars[0]);
8837 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8838 {
8839 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8840 return;
8841 }
8842
8843 while (cnt < maxline || maxline < 0)
8844 {
8845 readlen = (int)fread(buf, 1, io_size, fd);
8846
8847 /* This for loop processes what was read, but is also entered at end
8848 * of file so that either:
8849 * - an incomplete line gets written
8850 * - a "binary" file gets an empty line at the end if it ends in a
8851 * newline. */
8852 for (p = buf, start = buf;
8853 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8854 ++p)
8855 {
8856 if (*p == '\n' || readlen <= 0)
8857 {
8858 listitem_T *li;
8859 char_u *s = NULL;
8860 long_u len = p - start;
8861
8862 /* Finished a line. Remove CRs before NL. */
8863 if (readlen > 0 && !binary)
8864 {
8865 while (len > 0 && start[len - 1] == '\r')
8866 --len;
8867 /* removal may cross back to the "prev" string */
8868 if (len == 0)
8869 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8870 --prevlen;
8871 }
8872 if (prevlen == 0)
8873 s = vim_strnsave(start, (int)len);
8874 else
8875 {
8876 /* Change "prev" buffer to be the right size. This way
8877 * the bytes are only copied once, and very long lines are
8878 * allocated only once. */
8879 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8880 {
8881 mch_memmove(s + prevlen, start, len);
8882 s[prevlen + len] = NUL;
8883 prev = NULL; /* the list will own the string */
8884 prevlen = prevsize = 0;
8885 }
8886 }
8887 if (s == NULL)
8888 {
8889 do_outofmem_msg((long_u) prevlen + len + 1);
8890 failed = TRUE;
8891 break;
8892 }
8893
8894 if ((li = listitem_alloc()) == NULL)
8895 {
8896 vim_free(s);
8897 failed = TRUE;
8898 break;
8899 }
8900 li->li_tv.v_type = VAR_STRING;
8901 li->li_tv.v_lock = 0;
8902 li->li_tv.vval.v_string = s;
8903 list_append(rettv->vval.v_list, li);
8904
8905 start = p + 1; /* step over newline */
8906 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8907 break;
8908 }
8909 else if (*p == NUL)
8910 *p = '\n';
8911#ifdef FEAT_MBYTE
8912 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8913 * when finding the BF and check the previous two bytes. */
8914 else if (*p == 0xbf && enc_utf8 && !binary)
8915 {
8916 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8917 * + 1, these may be in the "prev" string. */
8918 char_u back1 = p >= buf + 1 ? p[-1]
8919 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8920 char_u back2 = p >= buf + 2 ? p[-2]
8921 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8922 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8923
8924 if (back2 == 0xef && back1 == 0xbb)
8925 {
8926 char_u *dest = p - 2;
8927
8928 /* Usually a BOM is at the beginning of a file, and so at
8929 * the beginning of a line; then we can just step over it.
8930 */
8931 if (start == dest)
8932 start = p + 1;
8933 else
8934 {
8935 /* have to shuffle buf to close gap */
8936 int adjust_prevlen = 0;
8937
8938 if (dest < buf)
8939 {
8940 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8941 dest = buf;
8942 }
8943 if (readlen > p - buf + 1)
8944 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8945 readlen -= 3 - adjust_prevlen;
8946 prevlen -= adjust_prevlen;
8947 p = dest - 1;
8948 }
8949 }
8950 }
8951#endif
8952 } /* for */
8953
8954 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8955 break;
8956 if (start < p)
8957 {
8958 /* There's part of a line in buf, store it in "prev". */
8959 if (p - start + prevlen >= prevsize)
8960 {
8961 /* need bigger "prev" buffer */
8962 char_u *newprev;
8963
8964 /* A common use case is ordinary text files and "prev" gets a
8965 * fragment of a line, so the first allocation is made
8966 * small, to avoid repeatedly 'allocing' large and
8967 * 'reallocing' small. */
8968 if (prevsize == 0)
8969 prevsize = (long)(p - start);
8970 else
8971 {
8972 long grow50pc = (prevsize * 3) / 2;
8973 long growmin = (long)((p - start) * 2 + prevlen);
8974 prevsize = grow50pc > growmin ? grow50pc : growmin;
8975 }
8976 newprev = prev == NULL ? alloc(prevsize)
8977 : vim_realloc(prev, prevsize);
8978 if (newprev == NULL)
8979 {
8980 do_outofmem_msg((long_u)prevsize);
8981 failed = TRUE;
8982 break;
8983 }
8984 prev = newprev;
8985 }
8986 /* Add the line part to end of "prev". */
8987 mch_memmove(prev + prevlen, start, p - start);
8988 prevlen += (long)(p - start);
8989 }
8990 } /* while */
8991
8992 /*
8993 * For a negative line count use only the lines at the end of the file,
8994 * free the rest.
8995 */
8996 if (!failed && maxline < 0)
8997 while (cnt > -maxline)
8998 {
8999 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9000 --cnt;
9001 }
9002
9003 if (failed)
9004 {
9005 list_free(rettv->vval.v_list);
9006 /* readfile doc says an empty list is returned on error */
9007 rettv->vval.v_list = list_alloc();
9008 }
9009
9010 vim_free(prev);
9011 fclose(fd);
9012}
9013
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009014 static void
9015return_register(int regname, typval_T *rettv)
9016{
9017 char_u buf[2] = {0, 0};
9018
9019 buf[0] = (char_u)regname;
9020 rettv->v_type = VAR_STRING;
9021 rettv->vval.v_string = vim_strsave(buf);
9022}
9023
9024/*
9025 * "reg_executing()" function
9026 */
9027 static void
9028f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9029{
9030 return_register(reg_executing, rettv);
9031}
9032
9033/*
9034 * "reg_recording()" function
9035 */
9036 static void
9037f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9038{
9039 return_register(reg_recording, rettv);
9040}
9041
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009042#if defined(FEAT_RELTIME)
9043static int list2proftime(typval_T *arg, proftime_T *tm);
9044
9045/*
9046 * Convert a List to proftime_T.
9047 * Return FAIL when there is something wrong.
9048 */
9049 static int
9050list2proftime(typval_T *arg, proftime_T *tm)
9051{
9052 long n1, n2;
9053 int error = FALSE;
9054
9055 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9056 || arg->vval.v_list->lv_len != 2)
9057 return FAIL;
9058 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9059 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9060# ifdef WIN3264
9061 tm->HighPart = n1;
9062 tm->LowPart = n2;
9063# else
9064 tm->tv_sec = n1;
9065 tm->tv_usec = n2;
9066# endif
9067 return error ? FAIL : OK;
9068}
9069#endif /* FEAT_RELTIME */
9070
9071/*
9072 * "reltime()" function
9073 */
9074 static void
9075f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9076{
9077#ifdef FEAT_RELTIME
9078 proftime_T res;
9079 proftime_T start;
9080
9081 if (argvars[0].v_type == VAR_UNKNOWN)
9082 {
9083 /* No arguments: get current time. */
9084 profile_start(&res);
9085 }
9086 else if (argvars[1].v_type == VAR_UNKNOWN)
9087 {
9088 if (list2proftime(&argvars[0], &res) == FAIL)
9089 return;
9090 profile_end(&res);
9091 }
9092 else
9093 {
9094 /* Two arguments: compute the difference. */
9095 if (list2proftime(&argvars[0], &start) == FAIL
9096 || list2proftime(&argvars[1], &res) == FAIL)
9097 return;
9098 profile_sub(&res, &start);
9099 }
9100
9101 if (rettv_list_alloc(rettv) == OK)
9102 {
9103 long n1, n2;
9104
9105# ifdef WIN3264
9106 n1 = res.HighPart;
9107 n2 = res.LowPart;
9108# else
9109 n1 = res.tv_sec;
9110 n2 = res.tv_usec;
9111# endif
9112 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9113 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9114 }
9115#endif
9116}
9117
9118#ifdef FEAT_FLOAT
9119/*
9120 * "reltimefloat()" function
9121 */
9122 static void
9123f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9124{
9125# ifdef FEAT_RELTIME
9126 proftime_T tm;
9127# endif
9128
9129 rettv->v_type = VAR_FLOAT;
9130 rettv->vval.v_float = 0;
9131# ifdef FEAT_RELTIME
9132 if (list2proftime(&argvars[0], &tm) == OK)
9133 rettv->vval.v_float = profile_float(&tm);
9134# endif
9135}
9136#endif
9137
9138/*
9139 * "reltimestr()" function
9140 */
9141 static void
9142f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9143{
9144#ifdef FEAT_RELTIME
9145 proftime_T tm;
9146#endif
9147
9148 rettv->v_type = VAR_STRING;
9149 rettv->vval.v_string = NULL;
9150#ifdef FEAT_RELTIME
9151 if (list2proftime(&argvars[0], &tm) == OK)
9152 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9153#endif
9154}
9155
9156#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9157static void make_connection(void);
9158static int check_connection(void);
9159
9160 static void
9161make_connection(void)
9162{
9163 if (X_DISPLAY == NULL
9164# ifdef FEAT_GUI
9165 && !gui.in_use
9166# endif
9167 )
9168 {
9169 x_force_connect = TRUE;
9170 setup_term_clip();
9171 x_force_connect = FALSE;
9172 }
9173}
9174
9175 static int
9176check_connection(void)
9177{
9178 make_connection();
9179 if (X_DISPLAY == NULL)
9180 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009181 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009182 return FAIL;
9183 }
9184 return OK;
9185}
9186#endif
9187
9188#ifdef FEAT_CLIENTSERVER
9189 static void
9190remote_common(typval_T *argvars, typval_T *rettv, int expr)
9191{
9192 char_u *server_name;
9193 char_u *keys;
9194 char_u *r = NULL;
9195 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009196 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009197# ifdef WIN32
9198 HWND w;
9199# else
9200 Window w;
9201# endif
9202
9203 if (check_restricted() || check_secure())
9204 return;
9205
9206# ifdef FEAT_X11
9207 if (check_connection() == FAIL)
9208 return;
9209# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009210 if (argvars[2].v_type != VAR_UNKNOWN
9211 && argvars[3].v_type != VAR_UNKNOWN)
9212 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009213
9214 server_name = get_tv_string_chk(&argvars[0]);
9215 if (server_name == NULL)
9216 return; /* type error; errmsg already given */
9217 keys = get_tv_string_buf(&argvars[1], buf);
9218# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009219 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009220# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009221 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9222 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009223# endif
9224 {
9225 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009226 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009227 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009228 vim_free(r);
9229 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009230 else
9231 EMSG2(_("E241: Unable to send to %s"), server_name);
9232 return;
9233 }
9234
9235 rettv->vval.v_string = r;
9236
9237 if (argvars[2].v_type != VAR_UNKNOWN)
9238 {
9239 dictitem_T v;
9240 char_u str[30];
9241 char_u *idvar;
9242
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009243 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009244 if (idvar != NULL && *idvar != NUL)
9245 {
9246 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9247 v.di_tv.v_type = VAR_STRING;
9248 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009249 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009250 vim_free(v.di_tv.vval.v_string);
9251 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009252 }
9253}
9254#endif
9255
9256/*
9257 * "remote_expr()" function
9258 */
9259 static void
9260f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9261{
9262 rettv->v_type = VAR_STRING;
9263 rettv->vval.v_string = NULL;
9264#ifdef FEAT_CLIENTSERVER
9265 remote_common(argvars, rettv, TRUE);
9266#endif
9267}
9268
9269/*
9270 * "remote_foreground()" function
9271 */
9272 static void
9273f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9274{
9275#ifdef FEAT_CLIENTSERVER
9276# ifdef WIN32
9277 /* On Win32 it's done in this application. */
9278 {
9279 char_u *server_name = get_tv_string_chk(&argvars[0]);
9280
9281 if (server_name != NULL)
9282 serverForeground(server_name);
9283 }
9284# else
9285 /* Send a foreground() expression to the server. */
9286 argvars[1].v_type = VAR_STRING;
9287 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9288 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009289 rettv->v_type = VAR_STRING;
9290 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009291 remote_common(argvars, rettv, TRUE);
9292 vim_free(argvars[1].vval.v_string);
9293# endif
9294#endif
9295}
9296
9297 static void
9298f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9299{
9300#ifdef FEAT_CLIENTSERVER
9301 dictitem_T v;
9302 char_u *s = NULL;
9303# ifdef WIN32
9304 long_u n = 0;
9305# endif
9306 char_u *serverid;
9307
9308 if (check_restricted() || check_secure())
9309 {
9310 rettv->vval.v_number = -1;
9311 return;
9312 }
9313 serverid = get_tv_string_chk(&argvars[0]);
9314 if (serverid == NULL)
9315 {
9316 rettv->vval.v_number = -1;
9317 return; /* type error; errmsg already given */
9318 }
9319# ifdef WIN32
9320 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9321 if (n == 0)
9322 rettv->vval.v_number = -1;
9323 else
9324 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009325 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009326 rettv->vval.v_number = (s != NULL);
9327 }
9328# else
9329 if (check_connection() == FAIL)
9330 return;
9331
9332 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9333 serverStrToWin(serverid), &s);
9334# endif
9335
9336 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9337 {
9338 char_u *retvar;
9339
9340 v.di_tv.v_type = VAR_STRING;
9341 v.di_tv.vval.v_string = vim_strsave(s);
9342 retvar = get_tv_string_chk(&argvars[1]);
9343 if (retvar != NULL)
9344 set_var(retvar, &v.di_tv, FALSE);
9345 vim_free(v.di_tv.vval.v_string);
9346 }
9347#else
9348 rettv->vval.v_number = -1;
9349#endif
9350}
9351
9352 static void
9353f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9354{
9355 char_u *r = NULL;
9356
9357#ifdef FEAT_CLIENTSERVER
9358 char_u *serverid = get_tv_string_chk(&argvars[0]);
9359
9360 if (serverid != NULL && !check_restricted() && !check_secure())
9361 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009362 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009363# ifdef WIN32
9364 /* The server's HWND is encoded in the 'id' parameter */
9365 long_u n = 0;
9366# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009367
9368 if (argvars[1].v_type != VAR_UNKNOWN)
9369 timeout = get_tv_number(&argvars[1]);
9370
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009371# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009372 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9373 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009374 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009375 if (r == NULL)
9376# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009377 if (check_connection() == FAIL
9378 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9379 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009380# endif
9381 EMSG(_("E277: Unable to read a server reply"));
9382 }
9383#endif
9384 rettv->v_type = VAR_STRING;
9385 rettv->vval.v_string = r;
9386}
9387
9388/*
9389 * "remote_send()" function
9390 */
9391 static void
9392f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9393{
9394 rettv->v_type = VAR_STRING;
9395 rettv->vval.v_string = NULL;
9396#ifdef FEAT_CLIENTSERVER
9397 remote_common(argvars, rettv, FALSE);
9398#endif
9399}
9400
9401/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009402 * "remote_startserver()" function
9403 */
9404 static void
9405f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9406{
9407#ifdef FEAT_CLIENTSERVER
9408 char_u *server = get_tv_string_chk(&argvars[0]);
9409
9410 if (server == NULL)
9411 return; /* type error; errmsg already given */
9412 if (serverName != NULL)
9413 EMSG(_("E941: already started a server"));
9414 else
9415 {
9416# ifdef FEAT_X11
9417 if (check_connection() == OK)
9418 serverRegisterName(X_DISPLAY, server);
9419# else
9420 serverSetName(server);
9421# endif
9422 }
9423#else
9424 EMSG(_("E942: +clientserver feature not available"));
9425#endif
9426}
9427
9428/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009429 * "remove()" function
9430 */
9431 static void
9432f_remove(typval_T *argvars, typval_T *rettv)
9433{
9434 list_T *l;
9435 listitem_T *item, *item2;
9436 listitem_T *li;
9437 long idx;
9438 long end;
9439 char_u *key;
9440 dict_T *d;
9441 dictitem_T *di;
9442 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9443
9444 if (argvars[0].v_type == VAR_DICT)
9445 {
9446 if (argvars[2].v_type != VAR_UNKNOWN)
9447 EMSG2(_(e_toomanyarg), "remove()");
9448 else if ((d = argvars[0].vval.v_dict) != NULL
9449 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9450 {
9451 key = get_tv_string_chk(&argvars[1]);
9452 if (key != NULL)
9453 {
9454 di = dict_find(d, key, -1);
9455 if (di == NULL)
9456 EMSG2(_(e_dictkey), key);
9457 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9458 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9459 {
9460 *rettv = di->di_tv;
9461 init_tv(&di->di_tv);
9462 dictitem_remove(d, di);
9463 }
9464 }
9465 }
9466 }
9467 else if (argvars[0].v_type != VAR_LIST)
9468 EMSG2(_(e_listdictarg), "remove()");
9469 else if ((l = argvars[0].vval.v_list) != NULL
9470 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9471 {
9472 int error = FALSE;
9473
9474 idx = (long)get_tv_number_chk(&argvars[1], &error);
9475 if (error)
9476 ; /* type error: do nothing, errmsg already given */
9477 else if ((item = list_find(l, idx)) == NULL)
9478 EMSGN(_(e_listidx), idx);
9479 else
9480 {
9481 if (argvars[2].v_type == VAR_UNKNOWN)
9482 {
9483 /* Remove one item, return its value. */
9484 vimlist_remove(l, item, item);
9485 *rettv = item->li_tv;
9486 vim_free(item);
9487 }
9488 else
9489 {
9490 /* Remove range of items, return list with values. */
9491 end = (long)get_tv_number_chk(&argvars[2], &error);
9492 if (error)
9493 ; /* type error: do nothing */
9494 else if ((item2 = list_find(l, end)) == NULL)
9495 EMSGN(_(e_listidx), end);
9496 else
9497 {
9498 int cnt = 0;
9499
9500 for (li = item; li != NULL; li = li->li_next)
9501 {
9502 ++cnt;
9503 if (li == item2)
9504 break;
9505 }
9506 if (li == NULL) /* didn't find "item2" after "item" */
9507 EMSG(_(e_invrange));
9508 else
9509 {
9510 vimlist_remove(l, item, item2);
9511 if (rettv_list_alloc(rettv) == OK)
9512 {
9513 l = rettv->vval.v_list;
9514 l->lv_first = item;
9515 l->lv_last = item2;
9516 item->li_prev = NULL;
9517 item2->li_next = NULL;
9518 l->lv_len = cnt;
9519 }
9520 }
9521 }
9522 }
9523 }
9524 }
9525}
9526
9527/*
9528 * "rename({from}, {to})" function
9529 */
9530 static void
9531f_rename(typval_T *argvars, typval_T *rettv)
9532{
9533 char_u buf[NUMBUFLEN];
9534
9535 if (check_restricted() || check_secure())
9536 rettv->vval.v_number = -1;
9537 else
9538 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9539 get_tv_string_buf(&argvars[1], buf));
9540}
9541
9542/*
9543 * "repeat()" function
9544 */
9545 static void
9546f_repeat(typval_T *argvars, typval_T *rettv)
9547{
9548 char_u *p;
9549 int n;
9550 int slen;
9551 int len;
9552 char_u *r;
9553 int i;
9554
9555 n = (int)get_tv_number(&argvars[1]);
9556 if (argvars[0].v_type == VAR_LIST)
9557 {
9558 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9559 while (n-- > 0)
9560 if (list_extend(rettv->vval.v_list,
9561 argvars[0].vval.v_list, NULL) == FAIL)
9562 break;
9563 }
9564 else
9565 {
9566 p = get_tv_string(&argvars[0]);
9567 rettv->v_type = VAR_STRING;
9568 rettv->vval.v_string = NULL;
9569
9570 slen = (int)STRLEN(p);
9571 len = slen * n;
9572 if (len <= 0)
9573 return;
9574
9575 r = alloc(len + 1);
9576 if (r != NULL)
9577 {
9578 for (i = 0; i < n; i++)
9579 mch_memmove(r + i * slen, p, (size_t)slen);
9580 r[len] = NUL;
9581 }
9582
9583 rettv->vval.v_string = r;
9584 }
9585}
9586
9587/*
9588 * "resolve()" function
9589 */
9590 static void
9591f_resolve(typval_T *argvars, typval_T *rettv)
9592{
9593 char_u *p;
9594#ifdef HAVE_READLINK
9595 char_u *buf = NULL;
9596#endif
9597
9598 p = get_tv_string(&argvars[0]);
9599#ifdef FEAT_SHORTCUT
9600 {
9601 char_u *v = NULL;
9602
9603 v = mch_resolve_shortcut(p);
9604 if (v != NULL)
9605 rettv->vval.v_string = v;
9606 else
9607 rettv->vval.v_string = vim_strsave(p);
9608 }
9609#else
9610# ifdef HAVE_READLINK
9611 {
9612 char_u *cpy;
9613 int len;
9614 char_u *remain = NULL;
9615 char_u *q;
9616 int is_relative_to_current = FALSE;
9617 int has_trailing_pathsep = FALSE;
9618 int limit = 100;
9619
9620 p = vim_strsave(p);
9621
9622 if (p[0] == '.' && (vim_ispathsep(p[1])
9623 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9624 is_relative_to_current = TRUE;
9625
9626 len = STRLEN(p);
9627 if (len > 0 && after_pathsep(p, p + len))
9628 {
9629 has_trailing_pathsep = TRUE;
9630 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9631 }
9632
9633 q = getnextcomp(p);
9634 if (*q != NUL)
9635 {
9636 /* Separate the first path component in "p", and keep the
9637 * remainder (beginning with the path separator). */
9638 remain = vim_strsave(q - 1);
9639 q[-1] = NUL;
9640 }
9641
9642 buf = alloc(MAXPATHL + 1);
9643 if (buf == NULL)
9644 goto fail;
9645
9646 for (;;)
9647 {
9648 for (;;)
9649 {
9650 len = readlink((char *)p, (char *)buf, MAXPATHL);
9651 if (len <= 0)
9652 break;
9653 buf[len] = NUL;
9654
9655 if (limit-- == 0)
9656 {
9657 vim_free(p);
9658 vim_free(remain);
9659 EMSG(_("E655: Too many symbolic links (cycle?)"));
9660 rettv->vval.v_string = NULL;
9661 goto fail;
9662 }
9663
9664 /* Ensure that the result will have a trailing path separator
9665 * if the argument has one. */
9666 if (remain == NULL && has_trailing_pathsep)
9667 add_pathsep(buf);
9668
9669 /* Separate the first path component in the link value and
9670 * concatenate the remainders. */
9671 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9672 if (*q != NUL)
9673 {
9674 if (remain == NULL)
9675 remain = vim_strsave(q - 1);
9676 else
9677 {
9678 cpy = concat_str(q - 1, remain);
9679 if (cpy != NULL)
9680 {
9681 vim_free(remain);
9682 remain = cpy;
9683 }
9684 }
9685 q[-1] = NUL;
9686 }
9687
9688 q = gettail(p);
9689 if (q > p && *q == NUL)
9690 {
9691 /* Ignore trailing path separator. */
9692 q[-1] = NUL;
9693 q = gettail(p);
9694 }
9695 if (q > p && !mch_isFullName(buf))
9696 {
9697 /* symlink is relative to directory of argument */
9698 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9699 if (cpy != NULL)
9700 {
9701 STRCPY(cpy, p);
9702 STRCPY(gettail(cpy), buf);
9703 vim_free(p);
9704 p = cpy;
9705 }
9706 }
9707 else
9708 {
9709 vim_free(p);
9710 p = vim_strsave(buf);
9711 }
9712 }
9713
9714 if (remain == NULL)
9715 break;
9716
9717 /* Append the first path component of "remain" to "p". */
9718 q = getnextcomp(remain + 1);
9719 len = q - remain - (*q != NUL);
9720 cpy = vim_strnsave(p, STRLEN(p) + len);
9721 if (cpy != NULL)
9722 {
9723 STRNCAT(cpy, remain, len);
9724 vim_free(p);
9725 p = cpy;
9726 }
9727 /* Shorten "remain". */
9728 if (*q != NUL)
9729 STRMOVE(remain, q - 1);
9730 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009731 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009732 }
9733
9734 /* If the result is a relative path name, make it explicitly relative to
9735 * the current directory if and only if the argument had this form. */
9736 if (!vim_ispathsep(*p))
9737 {
9738 if (is_relative_to_current
9739 && *p != NUL
9740 && !(p[0] == '.'
9741 && (p[1] == NUL
9742 || vim_ispathsep(p[1])
9743 || (p[1] == '.'
9744 && (p[2] == NUL
9745 || vim_ispathsep(p[2]))))))
9746 {
9747 /* Prepend "./". */
9748 cpy = concat_str((char_u *)"./", p);
9749 if (cpy != NULL)
9750 {
9751 vim_free(p);
9752 p = cpy;
9753 }
9754 }
9755 else if (!is_relative_to_current)
9756 {
9757 /* Strip leading "./". */
9758 q = p;
9759 while (q[0] == '.' && vim_ispathsep(q[1]))
9760 q += 2;
9761 if (q > p)
9762 STRMOVE(p, p + 2);
9763 }
9764 }
9765
9766 /* Ensure that the result will have no trailing path separator
9767 * if the argument had none. But keep "/" or "//". */
9768 if (!has_trailing_pathsep)
9769 {
9770 q = p + STRLEN(p);
9771 if (after_pathsep(p, q))
9772 *gettail_sep(p) = NUL;
9773 }
9774
9775 rettv->vval.v_string = p;
9776 }
9777# else
9778 rettv->vval.v_string = vim_strsave(p);
9779# endif
9780#endif
9781
9782 simplify_filename(rettv->vval.v_string);
9783
9784#ifdef HAVE_READLINK
9785fail:
9786 vim_free(buf);
9787#endif
9788 rettv->v_type = VAR_STRING;
9789}
9790
9791/*
9792 * "reverse({list})" function
9793 */
9794 static void
9795f_reverse(typval_T *argvars, typval_T *rettv)
9796{
9797 list_T *l;
9798 listitem_T *li, *ni;
9799
9800 if (argvars[0].v_type != VAR_LIST)
9801 EMSG2(_(e_listarg), "reverse()");
9802 else if ((l = argvars[0].vval.v_list) != NULL
9803 && !tv_check_lock(l->lv_lock,
9804 (char_u *)N_("reverse() argument"), TRUE))
9805 {
9806 li = l->lv_last;
9807 l->lv_first = l->lv_last = NULL;
9808 l->lv_len = 0;
9809 while (li != NULL)
9810 {
9811 ni = li->li_prev;
9812 list_append(l, li);
9813 li = ni;
9814 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009815 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009816 l->lv_idx = l->lv_len - l->lv_idx - 1;
9817 }
9818}
9819
9820#define SP_NOMOVE 0x01 /* don't move cursor */
9821#define SP_REPEAT 0x02 /* repeat to find outer pair */
9822#define SP_RETCOUNT 0x04 /* return matchcount */
9823#define SP_SETPCMARK 0x08 /* set previous context mark */
9824#define SP_START 0x10 /* accept match at start position */
9825#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9826#define SP_END 0x40 /* leave cursor at end of match */
9827#define SP_COLUMN 0x80 /* start at cursor column */
9828
9829static int get_search_arg(typval_T *varp, int *flagsp);
9830
9831/*
9832 * Get flags for a search function.
9833 * Possibly sets "p_ws".
9834 * Returns BACKWARD, FORWARD or zero (for an error).
9835 */
9836 static int
9837get_search_arg(typval_T *varp, int *flagsp)
9838{
9839 int dir = FORWARD;
9840 char_u *flags;
9841 char_u nbuf[NUMBUFLEN];
9842 int mask;
9843
9844 if (varp->v_type != VAR_UNKNOWN)
9845 {
9846 flags = get_tv_string_buf_chk(varp, nbuf);
9847 if (flags == NULL)
9848 return 0; /* type error; errmsg already given */
9849 while (*flags != NUL)
9850 {
9851 switch (*flags)
9852 {
9853 case 'b': dir = BACKWARD; break;
9854 case 'w': p_ws = TRUE; break;
9855 case 'W': p_ws = FALSE; break;
9856 default: mask = 0;
9857 if (flagsp != NULL)
9858 switch (*flags)
9859 {
9860 case 'c': mask = SP_START; break;
9861 case 'e': mask = SP_END; break;
9862 case 'm': mask = SP_RETCOUNT; break;
9863 case 'n': mask = SP_NOMOVE; break;
9864 case 'p': mask = SP_SUBPAT; break;
9865 case 'r': mask = SP_REPEAT; break;
9866 case 's': mask = SP_SETPCMARK; break;
9867 case 'z': mask = SP_COLUMN; break;
9868 }
9869 if (mask == 0)
9870 {
9871 EMSG2(_(e_invarg2), flags);
9872 dir = 0;
9873 }
9874 else
9875 *flagsp |= mask;
9876 }
9877 if (dir == 0)
9878 break;
9879 ++flags;
9880 }
9881 }
9882 return dir;
9883}
9884
9885/*
9886 * Shared by search() and searchpos() functions.
9887 */
9888 static int
9889search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9890{
9891 int flags;
9892 char_u *pat;
9893 pos_T pos;
9894 pos_T save_cursor;
9895 int save_p_ws = p_ws;
9896 int dir;
9897 int retval = 0; /* default: FAIL */
9898 long lnum_stop = 0;
9899 proftime_T tm;
9900#ifdef FEAT_RELTIME
9901 long time_limit = 0;
9902#endif
9903 int options = SEARCH_KEEP;
9904 int subpatnum;
9905
9906 pat = get_tv_string(&argvars[0]);
9907 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9908 if (dir == 0)
9909 goto theend;
9910 flags = *flagsp;
9911 if (flags & SP_START)
9912 options |= SEARCH_START;
9913 if (flags & SP_END)
9914 options |= SEARCH_END;
9915 if (flags & SP_COLUMN)
9916 options |= SEARCH_COL;
9917
9918 /* Optional arguments: line number to stop searching and timeout. */
9919 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9920 {
9921 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9922 if (lnum_stop < 0)
9923 goto theend;
9924#ifdef FEAT_RELTIME
9925 if (argvars[3].v_type != VAR_UNKNOWN)
9926 {
9927 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9928 if (time_limit < 0)
9929 goto theend;
9930 }
9931#endif
9932 }
9933
9934#ifdef FEAT_RELTIME
9935 /* Set the time limit, if there is one. */
9936 profile_setlimit(time_limit, &tm);
9937#endif
9938
9939 /*
9940 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9941 * Check to make sure only those flags are set.
9942 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9943 * flags cannot be set. Check for that condition also.
9944 */
9945 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9946 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9947 {
9948 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9949 goto theend;
9950 }
9951
9952 pos = save_cursor = curwin->w_cursor;
9953 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009954 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009955 if (subpatnum != FAIL)
9956 {
9957 if (flags & SP_SUBPAT)
9958 retval = subpatnum;
9959 else
9960 retval = pos.lnum;
9961 if (flags & SP_SETPCMARK)
9962 setpcmark();
9963 curwin->w_cursor = pos;
9964 if (match_pos != NULL)
9965 {
9966 /* Store the match cursor position */
9967 match_pos->lnum = pos.lnum;
9968 match_pos->col = pos.col + 1;
9969 }
9970 /* "/$" will put the cursor after the end of the line, may need to
9971 * correct that here */
9972 check_cursor();
9973 }
9974
9975 /* If 'n' flag is used: restore cursor position. */
9976 if (flags & SP_NOMOVE)
9977 curwin->w_cursor = save_cursor;
9978 else
9979 curwin->w_set_curswant = TRUE;
9980theend:
9981 p_ws = save_p_ws;
9982
9983 return retval;
9984}
9985
9986#ifdef FEAT_FLOAT
9987
9988/*
9989 * round() is not in C90, use ceil() or floor() instead.
9990 */
9991 float_T
9992vim_round(float_T f)
9993{
9994 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9995}
9996
9997/*
9998 * "round({float})" function
9999 */
10000 static void
10001f_round(typval_T *argvars, typval_T *rettv)
10002{
10003 float_T f = 0.0;
10004
10005 rettv->v_type = VAR_FLOAT;
10006 if (get_float_arg(argvars, &f) == OK)
10007 rettv->vval.v_float = vim_round(f);
10008 else
10009 rettv->vval.v_float = 0.0;
10010}
10011#endif
10012
10013/*
10014 * "screenattr()" function
10015 */
10016 static void
10017f_screenattr(typval_T *argvars, typval_T *rettv)
10018{
10019 int row;
10020 int col;
10021 int c;
10022
10023 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10024 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10025 if (row < 0 || row >= screen_Rows
10026 || col < 0 || col >= screen_Columns)
10027 c = -1;
10028 else
10029 c = ScreenAttrs[LineOffset[row] + col];
10030 rettv->vval.v_number = c;
10031}
10032
10033/*
10034 * "screenchar()" function
10035 */
10036 static void
10037f_screenchar(typval_T *argvars, typval_T *rettv)
10038{
10039 int row;
10040 int col;
10041 int off;
10042 int c;
10043
10044 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10045 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10046 if (row < 0 || row >= screen_Rows
10047 || col < 0 || col >= screen_Columns)
10048 c = -1;
10049 else
10050 {
10051 off = LineOffset[row] + col;
10052#ifdef FEAT_MBYTE
10053 if (enc_utf8 && ScreenLinesUC[off] != 0)
10054 c = ScreenLinesUC[off];
10055 else
10056#endif
10057 c = ScreenLines[off];
10058 }
10059 rettv->vval.v_number = c;
10060}
10061
10062/*
10063 * "screencol()" function
10064 *
10065 * First column is 1 to be consistent with virtcol().
10066 */
10067 static void
10068f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10069{
10070 rettv->vval.v_number = screen_screencol() + 1;
10071}
10072
10073/*
10074 * "screenrow()" function
10075 */
10076 static void
10077f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10078{
10079 rettv->vval.v_number = screen_screenrow() + 1;
10080}
10081
10082/*
10083 * "search()" function
10084 */
10085 static void
10086f_search(typval_T *argvars, typval_T *rettv)
10087{
10088 int flags = 0;
10089
10090 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10091}
10092
10093/*
10094 * "searchdecl()" function
10095 */
10096 static void
10097f_searchdecl(typval_T *argvars, typval_T *rettv)
10098{
10099 int locally = 1;
10100 int thisblock = 0;
10101 int error = FALSE;
10102 char_u *name;
10103
10104 rettv->vval.v_number = 1; /* default: FAIL */
10105
10106 name = get_tv_string_chk(&argvars[0]);
10107 if (argvars[1].v_type != VAR_UNKNOWN)
10108 {
10109 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
10110 if (!error && argvars[2].v_type != VAR_UNKNOWN)
10111 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
10112 }
10113 if (!error && name != NULL)
10114 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10115 locally, thisblock, SEARCH_KEEP) == FAIL;
10116}
10117
10118/*
10119 * Used by searchpair() and searchpairpos()
10120 */
10121 static int
10122searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10123{
10124 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010125 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010126 int save_p_ws = p_ws;
10127 int dir;
10128 int flags = 0;
10129 char_u nbuf1[NUMBUFLEN];
10130 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010131 int retval = 0; /* default: FAIL */
10132 long lnum_stop = 0;
10133 long time_limit = 0;
10134
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010135 /* Get the three pattern arguments: start, middle, end. Will result in an
10136 * error if not a valid argument. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010137 spat = get_tv_string_chk(&argvars[0]);
10138 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
10139 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
10140 if (spat == NULL || mpat == NULL || epat == NULL)
10141 goto theend; /* type error */
10142
10143 /* Handle the optional fourth argument: flags */
10144 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10145 if (dir == 0)
10146 goto theend;
10147
10148 /* Don't accept SP_END or SP_SUBPAT.
10149 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10150 */
10151 if ((flags & (SP_END | SP_SUBPAT)) != 0
10152 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10153 {
10154 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10155 goto theend;
10156 }
10157
10158 /* Using 'r' implies 'W', otherwise it doesn't work. */
10159 if (flags & SP_REPEAT)
10160 p_ws = FALSE;
10161
10162 /* Optional fifth argument: skip expression */
10163 if (argvars[3].v_type == VAR_UNKNOWN
10164 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010165 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010166 else
10167 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010168 skip = &argvars[4];
10169 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10170 && skip->v_type != VAR_STRING)
10171 {
10172 /* Type error */
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010173 EMSG2(_(e_invarg2), get_tv_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010174 goto theend;
10175 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010176 if (argvars[5].v_type != VAR_UNKNOWN)
10177 {
10178 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10179 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010180 {
10181 EMSG2(_(e_invarg2), get_tv_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010182 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010183 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010184#ifdef FEAT_RELTIME
10185 if (argvars[6].v_type != VAR_UNKNOWN)
10186 {
10187 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10188 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010189 {
10190 EMSG2(_(e_invarg2), get_tv_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010191 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010192 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010193 }
10194#endif
10195 }
10196 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010197
10198 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10199 match_pos, lnum_stop, time_limit);
10200
10201theend:
10202 p_ws = save_p_ws;
10203
10204 return retval;
10205}
10206
10207/*
10208 * "searchpair()" function
10209 */
10210 static void
10211f_searchpair(typval_T *argvars, typval_T *rettv)
10212{
10213 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10214}
10215
10216/*
10217 * "searchpairpos()" function
10218 */
10219 static void
10220f_searchpairpos(typval_T *argvars, typval_T *rettv)
10221{
10222 pos_T match_pos;
10223 int lnum = 0;
10224 int col = 0;
10225
10226 if (rettv_list_alloc(rettv) == FAIL)
10227 return;
10228
10229 if (searchpair_cmn(argvars, &match_pos) > 0)
10230 {
10231 lnum = match_pos.lnum;
10232 col = match_pos.col;
10233 }
10234
10235 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10236 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10237}
10238
10239/*
10240 * Search for a start/middle/end thing.
10241 * Used by searchpair(), see its documentation for the details.
10242 * Returns 0 or -1 for no match,
10243 */
10244 long
10245do_searchpair(
10246 char_u *spat, /* start pattern */
10247 char_u *mpat, /* middle pattern */
10248 char_u *epat, /* end pattern */
10249 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010250 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010251 int flags, /* SP_SETPCMARK and other SP_ values */
10252 pos_T *match_pos,
10253 linenr_T lnum_stop, /* stop at this line if not zero */
10254 long time_limit UNUSED) /* stop after this many msec */
10255{
10256 char_u *save_cpo;
10257 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10258 long retval = 0;
10259 pos_T pos;
10260 pos_T firstpos;
10261 pos_T foundpos;
10262 pos_T save_cursor;
10263 pos_T save_pos;
10264 int n;
10265 int r;
10266 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010267 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010268 int err;
10269 int options = SEARCH_KEEP;
10270 proftime_T tm;
10271
10272 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10273 save_cpo = p_cpo;
10274 p_cpo = empty_option;
10275
10276#ifdef FEAT_RELTIME
10277 /* Set the time limit, if there is one. */
10278 profile_setlimit(time_limit, &tm);
10279#endif
10280
10281 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10282 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010283 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10284 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010285 if (pat2 == NULL || pat3 == NULL)
10286 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010287 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010288 if (*mpat == NUL)
10289 STRCPY(pat3, pat2);
10290 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010291 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010292 spat, epat, mpat);
10293 if (flags & SP_START)
10294 options |= SEARCH_START;
10295
Bram Moolenaar48570482017-10-30 21:48:41 +010010296 if (skip != NULL)
10297 {
10298 /* Empty string means to not use the skip expression. */
10299 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10300 use_skip = skip->vval.v_string != NULL
10301 && *skip->vval.v_string != NUL;
10302 }
10303
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010304 save_cursor = curwin->w_cursor;
10305 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010306 CLEAR_POS(&firstpos);
10307 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010308 pat = pat3;
10309 for (;;)
10310 {
10311 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010312 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010313 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010314 /* didn't find it or found the first match again: FAIL */
10315 break;
10316
10317 if (firstpos.lnum == 0)
10318 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010319 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010320 {
10321 /* Found the same position again. Can happen with a pattern that
10322 * has "\zs" at the end and searching backwards. Advance one
10323 * character and try again. */
10324 if (dir == BACKWARD)
10325 decl(&pos);
10326 else
10327 incl(&pos);
10328 }
10329 foundpos = pos;
10330
10331 /* clear the start flag to avoid getting stuck here */
10332 options &= ~SEARCH_START;
10333
10334 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010335 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010336 {
10337 save_pos = curwin->w_cursor;
10338 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010339 err = FALSE;
10340 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010341 curwin->w_cursor = save_pos;
10342 if (err)
10343 {
10344 /* Evaluating {skip} caused an error, break here. */
10345 curwin->w_cursor = save_cursor;
10346 retval = -1;
10347 break;
10348 }
10349 if (r)
10350 continue;
10351 }
10352
10353 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10354 {
10355 /* Found end when searching backwards or start when searching
10356 * forward: nested pair. */
10357 ++nest;
10358 pat = pat2; /* nested, don't search for middle */
10359 }
10360 else
10361 {
10362 /* Found end when searching forward or start when searching
10363 * backward: end of (nested) pair; or found middle in outer pair. */
10364 if (--nest == 1)
10365 pat = pat3; /* outer level, search for middle */
10366 }
10367
10368 if (nest == 0)
10369 {
10370 /* Found the match: return matchcount or line number. */
10371 if (flags & SP_RETCOUNT)
10372 ++retval;
10373 else
10374 retval = pos.lnum;
10375 if (flags & SP_SETPCMARK)
10376 setpcmark();
10377 curwin->w_cursor = pos;
10378 if (!(flags & SP_REPEAT))
10379 break;
10380 nest = 1; /* search for next unmatched */
10381 }
10382 }
10383
10384 if (match_pos != NULL)
10385 {
10386 /* Store the match cursor position */
10387 match_pos->lnum = curwin->w_cursor.lnum;
10388 match_pos->col = curwin->w_cursor.col + 1;
10389 }
10390
10391 /* If 'n' flag is used or search failed: restore cursor position. */
10392 if ((flags & SP_NOMOVE) || retval == 0)
10393 curwin->w_cursor = save_cursor;
10394
10395theend:
10396 vim_free(pat2);
10397 vim_free(pat3);
10398 if (p_cpo == empty_option)
10399 p_cpo = save_cpo;
10400 else
10401 /* Darn, evaluating the {skip} expression changed the value. */
10402 free_string_option(save_cpo);
10403
10404 return retval;
10405}
10406
10407/*
10408 * "searchpos()" function
10409 */
10410 static void
10411f_searchpos(typval_T *argvars, typval_T *rettv)
10412{
10413 pos_T match_pos;
10414 int lnum = 0;
10415 int col = 0;
10416 int n;
10417 int flags = 0;
10418
10419 if (rettv_list_alloc(rettv) == FAIL)
10420 return;
10421
10422 n = search_cmn(argvars, &match_pos, &flags);
10423 if (n > 0)
10424 {
10425 lnum = match_pos.lnum;
10426 col = match_pos.col;
10427 }
10428
10429 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10430 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10431 if (flags & SP_SUBPAT)
10432 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10433}
10434
10435 static void
10436f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10437{
10438#ifdef FEAT_CLIENTSERVER
10439 char_u buf[NUMBUFLEN];
10440 char_u *server = get_tv_string_chk(&argvars[0]);
10441 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10442
10443 rettv->vval.v_number = -1;
10444 if (server == NULL || reply == NULL)
10445 return;
10446 if (check_restricted() || check_secure())
10447 return;
10448# ifdef FEAT_X11
10449 if (check_connection() == FAIL)
10450 return;
10451# endif
10452
10453 if (serverSendReply(server, reply) < 0)
10454 {
10455 EMSG(_("E258: Unable to send to client"));
10456 return;
10457 }
10458 rettv->vval.v_number = 0;
10459#else
10460 rettv->vval.v_number = -1;
10461#endif
10462}
10463
10464 static void
10465f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10466{
10467 char_u *r = NULL;
10468
10469#ifdef FEAT_CLIENTSERVER
10470# ifdef WIN32
10471 r = serverGetVimNames();
10472# else
10473 make_connection();
10474 if (X_DISPLAY != NULL)
10475 r = serverGetVimNames(X_DISPLAY);
10476# endif
10477#endif
10478 rettv->v_type = VAR_STRING;
10479 rettv->vval.v_string = r;
10480}
10481
10482/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010483 * "setbufline()" function
10484 */
10485 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010486f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010487{
10488 linenr_T lnum;
10489 buf_T *buf;
10490
10491 buf = get_buf_tv(&argvars[0], FALSE);
10492 if (buf == NULL)
10493 rettv->vval.v_number = 1; /* FAIL */
10494 else
10495 {
10496 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010497 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010498 }
10499}
10500
10501/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010502 * "setbufvar()" function
10503 */
10504 static void
10505f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10506{
10507 buf_T *buf;
10508 char_u *varname, *bufvarname;
10509 typval_T *varp;
10510 char_u nbuf[NUMBUFLEN];
10511
10512 if (check_restricted() || check_secure())
10513 return;
10514 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10515 varname = get_tv_string_chk(&argvars[1]);
10516 buf = get_buf_tv(&argvars[0], FALSE);
10517 varp = &argvars[2];
10518
10519 if (buf != NULL && varname != NULL && varp != NULL)
10520 {
10521 if (*varname == '&')
10522 {
10523 long numval;
10524 char_u *strval;
10525 int error = FALSE;
10526 aco_save_T aco;
10527
10528 /* set curbuf to be our buf, temporarily */
10529 aucmd_prepbuf(&aco, buf);
10530
10531 ++varname;
10532 numval = (long)get_tv_number_chk(varp, &error);
10533 strval = get_tv_string_buf_chk(varp, nbuf);
10534 if (!error && strval != NULL)
10535 set_option_value(varname, numval, strval, OPT_LOCAL);
10536
10537 /* reset notion of buffer */
10538 aucmd_restbuf(&aco);
10539 }
10540 else
10541 {
10542 buf_T *save_curbuf = curbuf;
10543
10544 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10545 if (bufvarname != NULL)
10546 {
10547 curbuf = buf;
10548 STRCPY(bufvarname, "b:");
10549 STRCPY(bufvarname + 2, varname);
10550 set_var(bufvarname, varp, TRUE);
10551 vim_free(bufvarname);
10552 curbuf = save_curbuf;
10553 }
10554 }
10555 }
10556}
10557
10558 static void
10559f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10560{
10561 dict_T *d;
10562 dictitem_T *di;
10563 char_u *csearch;
10564
10565 if (argvars[0].v_type != VAR_DICT)
10566 {
10567 EMSG(_(e_dictreq));
10568 return;
10569 }
10570
10571 if ((d = argvars[0].vval.v_dict) != NULL)
10572 {
10573 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10574 if (csearch != NULL)
10575 {
10576#ifdef FEAT_MBYTE
10577 if (enc_utf8)
10578 {
10579 int pcc[MAX_MCO];
10580 int c = utfc_ptr2char(csearch, pcc);
10581
10582 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10583 }
10584 else
10585#endif
10586 set_last_csearch(PTR2CHAR(csearch),
10587 csearch, MB_PTR2LEN(csearch));
10588 }
10589
10590 di = dict_find(d, (char_u *)"forward", -1);
10591 if (di != NULL)
10592 set_csearch_direction((int)get_tv_number(&di->di_tv)
10593 ? FORWARD : BACKWARD);
10594
10595 di = dict_find(d, (char_u *)"until", -1);
10596 if (di != NULL)
10597 set_csearch_until(!!get_tv_number(&di->di_tv));
10598 }
10599}
10600
10601/*
10602 * "setcmdpos()" function
10603 */
10604 static void
10605f_setcmdpos(typval_T *argvars, typval_T *rettv)
10606{
10607 int pos = (int)get_tv_number(&argvars[0]) - 1;
10608
10609 if (pos >= 0)
10610 rettv->vval.v_number = set_cmdline_pos(pos);
10611}
10612
10613/*
10614 * "setfperm({fname}, {mode})" function
10615 */
10616 static void
10617f_setfperm(typval_T *argvars, typval_T *rettv)
10618{
10619 char_u *fname;
10620 char_u modebuf[NUMBUFLEN];
10621 char_u *mode_str;
10622 int i;
10623 int mask;
10624 int mode = 0;
10625
10626 rettv->vval.v_number = 0;
10627 fname = get_tv_string_chk(&argvars[0]);
10628 if (fname == NULL)
10629 return;
10630 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10631 if (mode_str == NULL)
10632 return;
10633 if (STRLEN(mode_str) != 9)
10634 {
10635 EMSG2(_(e_invarg2), mode_str);
10636 return;
10637 }
10638
10639 mask = 1;
10640 for (i = 8; i >= 0; --i)
10641 {
10642 if (mode_str[i] != '-')
10643 mode |= mask;
10644 mask = mask << 1;
10645 }
10646 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10647}
10648
10649/*
10650 * "setline()" function
10651 */
10652 static void
10653f_setline(typval_T *argvars, typval_T *rettv)
10654{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010655 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010656
Bram Moolenaarca851592018-06-06 21:04:07 +020010657 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010658}
10659
Bram Moolenaard823fa92016-08-12 16:29:27 +020010660static 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 +020010661
10662/*
10663 * Used by "setqflist()" and "setloclist()" functions
10664 */
10665 static void
10666set_qf_ll_list(
10667 win_T *wp UNUSED,
10668 typval_T *list_arg UNUSED,
10669 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010670 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010671 typval_T *rettv)
10672{
10673#ifdef FEAT_QUICKFIX
10674 static char *e_invact = N_("E927: Invalid action: '%s'");
10675 char_u *act;
10676 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010677 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010678#endif
10679
10680 rettv->vval.v_number = -1;
10681
10682#ifdef FEAT_QUICKFIX
10683 if (list_arg->v_type != VAR_LIST)
10684 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010685 else if (recursive != 0)
10686 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010687 else
10688 {
10689 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010690 dict_T *d = NULL;
10691 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010692
10693 if (action_arg->v_type == VAR_STRING)
10694 {
10695 act = get_tv_string_chk(action_arg);
10696 if (act == NULL)
10697 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010698 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10699 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010700 action = *act;
10701 else
10702 EMSG2(_(e_invact), act);
10703 }
10704 else if (action_arg->v_type == VAR_UNKNOWN)
10705 action = ' ';
10706 else
10707 EMSG(_(e_stringreq));
10708
Bram Moolenaard823fa92016-08-12 16:29:27 +020010709 if (action_arg->v_type != VAR_UNKNOWN
10710 && what_arg->v_type != VAR_UNKNOWN)
10711 {
10712 if (what_arg->v_type == VAR_DICT)
10713 d = what_arg->vval.v_dict;
10714 else
10715 {
10716 EMSG(_(e_dictreq));
10717 valid_dict = FALSE;
10718 }
10719 }
10720
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010721 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010722 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010723 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10724 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010725 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010726 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010727 }
10728#endif
10729}
10730
10731/*
10732 * "setloclist()" function
10733 */
10734 static void
10735f_setloclist(typval_T *argvars, typval_T *rettv)
10736{
10737 win_T *win;
10738
10739 rettv->vval.v_number = -1;
10740
10741 win = find_win_by_nr(&argvars[0], NULL);
10742 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010743 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010744}
10745
10746/*
10747 * "setmatches()" function
10748 */
10749 static void
10750f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10751{
10752#ifdef FEAT_SEARCH_EXTRA
10753 list_T *l;
10754 listitem_T *li;
10755 dict_T *d;
10756 list_T *s = NULL;
10757
10758 rettv->vval.v_number = -1;
10759 if (argvars[0].v_type != VAR_LIST)
10760 {
10761 EMSG(_(e_listreq));
10762 return;
10763 }
10764 if ((l = argvars[0].vval.v_list) != NULL)
10765 {
10766
10767 /* To some extent make sure that we are dealing with a list from
10768 * "getmatches()". */
10769 li = l->lv_first;
10770 while (li != NULL)
10771 {
10772 if (li->li_tv.v_type != VAR_DICT
10773 || (d = li->li_tv.vval.v_dict) == NULL)
10774 {
10775 EMSG(_(e_invarg));
10776 return;
10777 }
10778 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10779 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10780 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10781 && dict_find(d, (char_u *)"priority", -1) != NULL
10782 && dict_find(d, (char_u *)"id", -1) != NULL))
10783 {
10784 EMSG(_(e_invarg));
10785 return;
10786 }
10787 li = li->li_next;
10788 }
10789
10790 clear_matches(curwin);
10791 li = l->lv_first;
10792 while (li != NULL)
10793 {
10794 int i = 0;
10795 char_u buf[5];
10796 dictitem_T *di;
10797 char_u *group;
10798 int priority;
10799 int id;
10800 char_u *conceal;
10801
10802 d = li->li_tv.vval.v_dict;
10803 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10804 {
10805 if (s == NULL)
10806 {
10807 s = list_alloc();
10808 if (s == NULL)
10809 return;
10810 }
10811
10812 /* match from matchaddpos() */
10813 for (i = 1; i < 9; i++)
10814 {
10815 sprintf((char *)buf, (char *)"pos%d", i);
10816 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10817 {
10818 if (di->di_tv.v_type != VAR_LIST)
10819 return;
10820
10821 list_append_tv(s, &di->di_tv);
10822 s->lv_refcount++;
10823 }
10824 else
10825 break;
10826 }
10827 }
10828
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010829 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830 priority = (int)get_dict_number(d, (char_u *)"priority");
10831 id = (int)get_dict_number(d, (char_u *)"id");
10832 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010833 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010834 : NULL;
10835 if (i == 0)
10836 {
10837 match_add(curwin, group,
10838 get_dict_string(d, (char_u *)"pattern", FALSE),
10839 priority, id, NULL, conceal);
10840 }
10841 else
10842 {
10843 match_add(curwin, group, NULL, priority, id, s, conceal);
10844 list_unref(s);
10845 s = NULL;
10846 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010847 vim_free(group);
10848 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010849
10850 li = li->li_next;
10851 }
10852 rettv->vval.v_number = 0;
10853 }
10854#endif
10855}
10856
10857/*
10858 * "setpos()" function
10859 */
10860 static void
10861f_setpos(typval_T *argvars, typval_T *rettv)
10862{
10863 pos_T pos;
10864 int fnum;
10865 char_u *name;
10866 colnr_T curswant = -1;
10867
10868 rettv->vval.v_number = -1;
10869 name = get_tv_string_chk(argvars);
10870 if (name != NULL)
10871 {
10872 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10873 {
10874 if (--pos.col < 0)
10875 pos.col = 0;
10876 if (name[0] == '.' && name[1] == NUL)
10877 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010878 /* set cursor; "fnum" is ignored */
10879 curwin->w_cursor = pos;
10880 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010881 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010882 curwin->w_curswant = curswant - 1;
10883 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010884 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010885 check_cursor();
10886 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010887 }
10888 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10889 {
10890 /* set mark */
10891 if (setmark_pos(name[1], &pos, fnum) == OK)
10892 rettv->vval.v_number = 0;
10893 }
10894 else
10895 EMSG(_(e_invarg));
10896 }
10897 }
10898}
10899
10900/*
10901 * "setqflist()" function
10902 */
10903 static void
10904f_setqflist(typval_T *argvars, typval_T *rettv)
10905{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010906 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010907}
10908
10909/*
10910 * "setreg()" function
10911 */
10912 static void
10913f_setreg(typval_T *argvars, typval_T *rettv)
10914{
10915 int regname;
10916 char_u *strregname;
10917 char_u *stropt;
10918 char_u *strval;
10919 int append;
10920 char_u yank_type;
10921 long block_len;
10922
10923 block_len = -1;
10924 yank_type = MAUTO;
10925 append = FALSE;
10926
10927 strregname = get_tv_string_chk(argvars);
10928 rettv->vval.v_number = 1; /* FAIL is default */
10929
10930 if (strregname == NULL)
10931 return; /* type error; errmsg already given */
10932 regname = *strregname;
10933 if (regname == 0 || regname == '@')
10934 regname = '"';
10935
10936 if (argvars[2].v_type != VAR_UNKNOWN)
10937 {
10938 stropt = get_tv_string_chk(&argvars[2]);
10939 if (stropt == NULL)
10940 return; /* type error */
10941 for (; *stropt != NUL; ++stropt)
10942 switch (*stropt)
10943 {
10944 case 'a': case 'A': /* append */
10945 append = TRUE;
10946 break;
10947 case 'v': case 'c': /* character-wise selection */
10948 yank_type = MCHAR;
10949 break;
10950 case 'V': case 'l': /* line-wise selection */
10951 yank_type = MLINE;
10952 break;
10953 case 'b': case Ctrl_V: /* block-wise selection */
10954 yank_type = MBLOCK;
10955 if (VIM_ISDIGIT(stropt[1]))
10956 {
10957 ++stropt;
10958 block_len = getdigits(&stropt) - 1;
10959 --stropt;
10960 }
10961 break;
10962 }
10963 }
10964
10965 if (argvars[1].v_type == VAR_LIST)
10966 {
10967 char_u **lstval;
10968 char_u **allocval;
10969 char_u buf[NUMBUFLEN];
10970 char_u **curval;
10971 char_u **curallocval;
10972 list_T *ll = argvars[1].vval.v_list;
10973 listitem_T *li;
10974 int len;
10975
10976 /* If the list is NULL handle like an empty list. */
10977 len = ll == NULL ? 0 : ll->lv_len;
10978
10979 /* First half: use for pointers to result lines; second half: use for
10980 * pointers to allocated copies. */
10981 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10982 if (lstval == NULL)
10983 return;
10984 curval = lstval;
10985 allocval = lstval + len + 2;
10986 curallocval = allocval;
10987
10988 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10989 li = li->li_next)
10990 {
10991 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10992 if (strval == NULL)
10993 goto free_lstval;
10994 if (strval == buf)
10995 {
10996 /* Need to make a copy, next get_tv_string_buf_chk() will
10997 * overwrite the string. */
10998 strval = vim_strsave(buf);
10999 if (strval == NULL)
11000 goto free_lstval;
11001 *curallocval++ = strval;
11002 }
11003 *curval++ = strval;
11004 }
11005 *curval++ = NULL;
11006
11007 write_reg_contents_lst(regname, lstval, -1,
11008 append, yank_type, block_len);
11009free_lstval:
11010 while (curallocval > allocval)
11011 vim_free(*--curallocval);
11012 vim_free(lstval);
11013 }
11014 else
11015 {
11016 strval = get_tv_string_chk(&argvars[1]);
11017 if (strval == NULL)
11018 return;
11019 write_reg_contents_ex(regname, strval, -1,
11020 append, yank_type, block_len);
11021 }
11022 rettv->vval.v_number = 0;
11023}
11024
11025/*
11026 * "settabvar()" function
11027 */
11028 static void
11029f_settabvar(typval_T *argvars, typval_T *rettv)
11030{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011031 tabpage_T *save_curtab;
11032 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011033 char_u *varname, *tabvarname;
11034 typval_T *varp;
11035
11036 rettv->vval.v_number = 0;
11037
11038 if (check_restricted() || check_secure())
11039 return;
11040
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011041 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011042 varname = get_tv_string_chk(&argvars[1]);
11043 varp = &argvars[2];
11044
Bram Moolenaar4033c552017-09-16 20:54:51 +020011045 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011046 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011047 save_curtab = curtab;
11048 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011049
11050 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11051 if (tabvarname != NULL)
11052 {
11053 STRCPY(tabvarname, "t:");
11054 STRCPY(tabvarname + 2, varname);
11055 set_var(tabvarname, varp, TRUE);
11056 vim_free(tabvarname);
11057 }
11058
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059 /* Restore current tabpage */
11060 if (valid_tabpage(save_curtab))
11061 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011062 }
11063}
11064
11065/*
11066 * "settabwinvar()" function
11067 */
11068 static void
11069f_settabwinvar(typval_T *argvars, typval_T *rettv)
11070{
11071 setwinvar(argvars, rettv, 1);
11072}
11073
11074/*
11075 * "setwinvar()" function
11076 */
11077 static void
11078f_setwinvar(typval_T *argvars, typval_T *rettv)
11079{
11080 setwinvar(argvars, rettv, 0);
11081}
11082
11083#ifdef FEAT_CRYPT
11084/*
11085 * "sha256({string})" function
11086 */
11087 static void
11088f_sha256(typval_T *argvars, typval_T *rettv)
11089{
11090 char_u *p;
11091
11092 p = get_tv_string(&argvars[0]);
11093 rettv->vval.v_string = vim_strsave(
11094 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11095 rettv->v_type = VAR_STRING;
11096}
11097#endif /* FEAT_CRYPT */
11098
11099/*
11100 * "shellescape({string})" function
11101 */
11102 static void
11103f_shellescape(typval_T *argvars, typval_T *rettv)
11104{
Bram Moolenaar20615522017-06-05 18:46:26 +020011105 int do_special = non_zero_arg(&argvars[1]);
11106
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011107 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020011108 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011109 rettv->v_type = VAR_STRING;
11110}
11111
11112/*
11113 * shiftwidth() function
11114 */
11115 static void
11116f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11117{
11118 rettv->vval.v_number = get_sw_value(curbuf);
11119}
11120
11121/*
11122 * "simplify()" function
11123 */
11124 static void
11125f_simplify(typval_T *argvars, typval_T *rettv)
11126{
11127 char_u *p;
11128
11129 p = get_tv_string(&argvars[0]);
11130 rettv->vval.v_string = vim_strsave(p);
11131 simplify_filename(rettv->vval.v_string); /* simplify in place */
11132 rettv->v_type = VAR_STRING;
11133}
11134
11135#ifdef FEAT_FLOAT
11136/*
11137 * "sin()" function
11138 */
11139 static void
11140f_sin(typval_T *argvars, typval_T *rettv)
11141{
11142 float_T f = 0.0;
11143
11144 rettv->v_type = VAR_FLOAT;
11145 if (get_float_arg(argvars, &f) == OK)
11146 rettv->vval.v_float = sin(f);
11147 else
11148 rettv->vval.v_float = 0.0;
11149}
11150
11151/*
11152 * "sinh()" function
11153 */
11154 static void
11155f_sinh(typval_T *argvars, typval_T *rettv)
11156{
11157 float_T f = 0.0;
11158
11159 rettv->v_type = VAR_FLOAT;
11160 if (get_float_arg(argvars, &f) == OK)
11161 rettv->vval.v_float = sinh(f);
11162 else
11163 rettv->vval.v_float = 0.0;
11164}
11165#endif
11166
11167static int
11168#ifdef __BORLANDC__
11169 _RTLENTRYF
11170#endif
11171 item_compare(const void *s1, const void *s2);
11172static int
11173#ifdef __BORLANDC__
11174 _RTLENTRYF
11175#endif
11176 item_compare2(const void *s1, const void *s2);
11177
11178/* struct used in the array that's given to qsort() */
11179typedef struct
11180{
11181 listitem_T *item;
11182 int idx;
11183} sortItem_T;
11184
11185/* struct storing information about current sort */
11186typedef struct
11187{
11188 int item_compare_ic;
11189 int item_compare_numeric;
11190 int item_compare_numbers;
11191#ifdef FEAT_FLOAT
11192 int item_compare_float;
11193#endif
11194 char_u *item_compare_func;
11195 partial_T *item_compare_partial;
11196 dict_T *item_compare_selfdict;
11197 int item_compare_func_err;
11198 int item_compare_keep_zero;
11199} sortinfo_T;
11200static sortinfo_T *sortinfo = NULL;
11201static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
11202#define ITEM_COMPARE_FAIL 999
11203
11204/*
11205 * Compare functions for f_sort() and f_uniq() below.
11206 */
11207 static int
11208#ifdef __BORLANDC__
11209_RTLENTRYF
11210#endif
11211item_compare(const void *s1, const void *s2)
11212{
11213 sortItem_T *si1, *si2;
11214 typval_T *tv1, *tv2;
11215 char_u *p1, *p2;
11216 char_u *tofree1 = NULL, *tofree2 = NULL;
11217 int res;
11218 char_u numbuf1[NUMBUFLEN];
11219 char_u numbuf2[NUMBUFLEN];
11220
11221 si1 = (sortItem_T *)s1;
11222 si2 = (sortItem_T *)s2;
11223 tv1 = &si1->item->li_tv;
11224 tv2 = &si2->item->li_tv;
11225
11226 if (sortinfo->item_compare_numbers)
11227 {
11228 varnumber_T v1 = get_tv_number(tv1);
11229 varnumber_T v2 = get_tv_number(tv2);
11230
11231 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11232 }
11233
11234#ifdef FEAT_FLOAT
11235 if (sortinfo->item_compare_float)
11236 {
11237 float_T v1 = get_tv_float(tv1);
11238 float_T v2 = get_tv_float(tv2);
11239
11240 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11241 }
11242#endif
11243
11244 /* tv2string() puts quotes around a string and allocates memory. Don't do
11245 * that for string variables. Use a single quote when comparing with a
11246 * non-string to do what the docs promise. */
11247 if (tv1->v_type == VAR_STRING)
11248 {
11249 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11250 p1 = (char_u *)"'";
11251 else
11252 p1 = tv1->vval.v_string;
11253 }
11254 else
11255 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11256 if (tv2->v_type == VAR_STRING)
11257 {
11258 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11259 p2 = (char_u *)"'";
11260 else
11261 p2 = tv2->vval.v_string;
11262 }
11263 else
11264 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11265 if (p1 == NULL)
11266 p1 = (char_u *)"";
11267 if (p2 == NULL)
11268 p2 = (char_u *)"";
11269 if (!sortinfo->item_compare_numeric)
11270 {
11271 if (sortinfo->item_compare_ic)
11272 res = STRICMP(p1, p2);
11273 else
11274 res = STRCMP(p1, p2);
11275 }
11276 else
11277 {
11278 double n1, n2;
11279 n1 = strtod((char *)p1, (char **)&p1);
11280 n2 = strtod((char *)p2, (char **)&p2);
11281 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11282 }
11283
11284 /* When the result would be zero, compare the item indexes. Makes the
11285 * sort stable. */
11286 if (res == 0 && !sortinfo->item_compare_keep_zero)
11287 res = si1->idx > si2->idx ? 1 : -1;
11288
11289 vim_free(tofree1);
11290 vim_free(tofree2);
11291 return res;
11292}
11293
11294 static int
11295#ifdef __BORLANDC__
11296_RTLENTRYF
11297#endif
11298item_compare2(const void *s1, const void *s2)
11299{
11300 sortItem_T *si1, *si2;
11301 int res;
11302 typval_T rettv;
11303 typval_T argv[3];
11304 int dummy;
11305 char_u *func_name;
11306 partial_T *partial = sortinfo->item_compare_partial;
11307
11308 /* shortcut after failure in previous call; compare all items equal */
11309 if (sortinfo->item_compare_func_err)
11310 return 0;
11311
11312 si1 = (sortItem_T *)s1;
11313 si2 = (sortItem_T *)s2;
11314
11315 if (partial == NULL)
11316 func_name = sortinfo->item_compare_func;
11317 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011318 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011319
11320 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11321 * in the copy without changing the original list items. */
11322 copy_tv(&si1->item->li_tv, &argv[0]);
11323 copy_tv(&si2->item->li_tv, &argv[1]);
11324
11325 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11326 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011327 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011328 partial, sortinfo->item_compare_selfdict);
11329 clear_tv(&argv[0]);
11330 clear_tv(&argv[1]);
11331
11332 if (res == FAIL)
11333 res = ITEM_COMPARE_FAIL;
11334 else
11335 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11336 if (sortinfo->item_compare_func_err)
11337 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11338 clear_tv(&rettv);
11339
11340 /* When the result would be zero, compare the pointers themselves. Makes
11341 * the sort stable. */
11342 if (res == 0 && !sortinfo->item_compare_keep_zero)
11343 res = si1->idx > si2->idx ? 1 : -1;
11344
11345 return res;
11346}
11347
11348/*
11349 * "sort({list})" function
11350 */
11351 static void
11352do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11353{
11354 list_T *l;
11355 listitem_T *li;
11356 sortItem_T *ptrs;
11357 sortinfo_T *old_sortinfo;
11358 sortinfo_T info;
11359 long len;
11360 long i;
11361
11362 /* Pointer to current info struct used in compare function. Save and
11363 * restore the current one for nested calls. */
11364 old_sortinfo = sortinfo;
11365 sortinfo = &info;
11366
11367 if (argvars[0].v_type != VAR_LIST)
11368 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11369 else
11370 {
11371 l = argvars[0].vval.v_list;
11372 if (l == NULL || tv_check_lock(l->lv_lock,
11373 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11374 TRUE))
11375 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011376 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011377
11378 len = list_len(l);
11379 if (len <= 1)
11380 goto theend; /* short list sorts pretty quickly */
11381
11382 info.item_compare_ic = FALSE;
11383 info.item_compare_numeric = FALSE;
11384 info.item_compare_numbers = FALSE;
11385#ifdef FEAT_FLOAT
11386 info.item_compare_float = FALSE;
11387#endif
11388 info.item_compare_func = NULL;
11389 info.item_compare_partial = NULL;
11390 info.item_compare_selfdict = NULL;
11391 if (argvars[1].v_type != VAR_UNKNOWN)
11392 {
11393 /* optional second argument: {func} */
11394 if (argvars[1].v_type == VAR_FUNC)
11395 info.item_compare_func = argvars[1].vval.v_string;
11396 else if (argvars[1].v_type == VAR_PARTIAL)
11397 info.item_compare_partial = argvars[1].vval.v_partial;
11398 else
11399 {
11400 int error = FALSE;
11401
11402 i = (long)get_tv_number_chk(&argvars[1], &error);
11403 if (error)
11404 goto theend; /* type error; errmsg already given */
11405 if (i == 1)
11406 info.item_compare_ic = TRUE;
11407 else if (argvars[1].v_type != VAR_NUMBER)
11408 info.item_compare_func = get_tv_string(&argvars[1]);
11409 else if (i != 0)
11410 {
11411 EMSG(_(e_invarg));
11412 goto theend;
11413 }
11414 if (info.item_compare_func != NULL)
11415 {
11416 if (*info.item_compare_func == NUL)
11417 {
11418 /* empty string means default sort */
11419 info.item_compare_func = NULL;
11420 }
11421 else if (STRCMP(info.item_compare_func, "n") == 0)
11422 {
11423 info.item_compare_func = NULL;
11424 info.item_compare_numeric = TRUE;
11425 }
11426 else if (STRCMP(info.item_compare_func, "N") == 0)
11427 {
11428 info.item_compare_func = NULL;
11429 info.item_compare_numbers = TRUE;
11430 }
11431#ifdef FEAT_FLOAT
11432 else if (STRCMP(info.item_compare_func, "f") == 0)
11433 {
11434 info.item_compare_func = NULL;
11435 info.item_compare_float = TRUE;
11436 }
11437#endif
11438 else if (STRCMP(info.item_compare_func, "i") == 0)
11439 {
11440 info.item_compare_func = NULL;
11441 info.item_compare_ic = TRUE;
11442 }
11443 }
11444 }
11445
11446 if (argvars[2].v_type != VAR_UNKNOWN)
11447 {
11448 /* optional third argument: {dict} */
11449 if (argvars[2].v_type != VAR_DICT)
11450 {
11451 EMSG(_(e_dictreq));
11452 goto theend;
11453 }
11454 info.item_compare_selfdict = argvars[2].vval.v_dict;
11455 }
11456 }
11457
11458 /* Make an array with each entry pointing to an item in the List. */
11459 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11460 if (ptrs == NULL)
11461 goto theend;
11462
11463 i = 0;
11464 if (sort)
11465 {
11466 /* sort(): ptrs will be the list to sort */
11467 for (li = l->lv_first; li != NULL; li = li->li_next)
11468 {
11469 ptrs[i].item = li;
11470 ptrs[i].idx = i;
11471 ++i;
11472 }
11473
11474 info.item_compare_func_err = FALSE;
11475 info.item_compare_keep_zero = FALSE;
11476 /* test the compare function */
11477 if ((info.item_compare_func != NULL
11478 || info.item_compare_partial != NULL)
11479 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11480 == ITEM_COMPARE_FAIL)
11481 EMSG(_("E702: Sort compare function failed"));
11482 else
11483 {
11484 /* Sort the array with item pointers. */
11485 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11486 info.item_compare_func == NULL
11487 && info.item_compare_partial == NULL
11488 ? item_compare : item_compare2);
11489
11490 if (!info.item_compare_func_err)
11491 {
11492 /* Clear the List and append the items in sorted order. */
11493 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11494 l->lv_len = 0;
11495 for (i = 0; i < len; ++i)
11496 list_append(l, ptrs[i].item);
11497 }
11498 }
11499 }
11500 else
11501 {
11502 int (*item_compare_func_ptr)(const void *, const void *);
11503
11504 /* f_uniq(): ptrs will be a stack of items to remove */
11505 info.item_compare_func_err = FALSE;
11506 info.item_compare_keep_zero = TRUE;
11507 item_compare_func_ptr = info.item_compare_func != NULL
11508 || info.item_compare_partial != NULL
11509 ? item_compare2 : item_compare;
11510
11511 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11512 li = li->li_next)
11513 {
11514 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11515 == 0)
11516 ptrs[i++].item = li;
11517 if (info.item_compare_func_err)
11518 {
11519 EMSG(_("E882: Uniq compare function failed"));
11520 break;
11521 }
11522 }
11523
11524 if (!info.item_compare_func_err)
11525 {
11526 while (--i >= 0)
11527 {
11528 li = ptrs[i].item->li_next;
11529 ptrs[i].item->li_next = li->li_next;
11530 if (li->li_next != NULL)
11531 li->li_next->li_prev = ptrs[i].item;
11532 else
11533 l->lv_last = ptrs[i].item;
11534 list_fix_watch(l, li);
11535 listitem_free(li);
11536 l->lv_len--;
11537 }
11538 }
11539 }
11540
11541 vim_free(ptrs);
11542 }
11543theend:
11544 sortinfo = old_sortinfo;
11545}
11546
11547/*
11548 * "sort({list})" function
11549 */
11550 static void
11551f_sort(typval_T *argvars, typval_T *rettv)
11552{
11553 do_sort_uniq(argvars, rettv, TRUE);
11554}
11555
11556/*
11557 * "uniq({list})" function
11558 */
11559 static void
11560f_uniq(typval_T *argvars, typval_T *rettv)
11561{
11562 do_sort_uniq(argvars, rettv, FALSE);
11563}
11564
11565/*
11566 * "soundfold({word})" function
11567 */
11568 static void
11569f_soundfold(typval_T *argvars, typval_T *rettv)
11570{
11571 char_u *s;
11572
11573 rettv->v_type = VAR_STRING;
11574 s = get_tv_string(&argvars[0]);
11575#ifdef FEAT_SPELL
11576 rettv->vval.v_string = eval_soundfold(s);
11577#else
11578 rettv->vval.v_string = vim_strsave(s);
11579#endif
11580}
11581
11582/*
11583 * "spellbadword()" function
11584 */
11585 static void
11586f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11587{
11588 char_u *word = (char_u *)"";
11589 hlf_T attr = HLF_COUNT;
11590 int len = 0;
11591
11592 if (rettv_list_alloc(rettv) == FAIL)
11593 return;
11594
11595#ifdef FEAT_SPELL
11596 if (argvars[0].v_type == VAR_UNKNOWN)
11597 {
11598 /* Find the start and length of the badly spelled word. */
11599 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11600 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011601 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011602 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011603 curwin->w_set_curswant = TRUE;
11604 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011605 }
11606 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11607 {
11608 char_u *str = get_tv_string_chk(&argvars[0]);
11609 int capcol = -1;
11610
11611 if (str != NULL)
11612 {
11613 /* Check the argument for spelling. */
11614 while (*str != NUL)
11615 {
11616 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11617 if (attr != HLF_COUNT)
11618 {
11619 word = str;
11620 break;
11621 }
11622 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020011623 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011624 }
11625 }
11626 }
11627#endif
11628
11629 list_append_string(rettv->vval.v_list, word, len);
11630 list_append_string(rettv->vval.v_list, (char_u *)(
11631 attr == HLF_SPB ? "bad" :
11632 attr == HLF_SPR ? "rare" :
11633 attr == HLF_SPL ? "local" :
11634 attr == HLF_SPC ? "caps" :
11635 ""), -1);
11636}
11637
11638/*
11639 * "spellsuggest()" function
11640 */
11641 static void
11642f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11643{
11644#ifdef FEAT_SPELL
11645 char_u *str;
11646 int typeerr = FALSE;
11647 int maxcount;
11648 garray_T ga;
11649 int i;
11650 listitem_T *li;
11651 int need_capital = FALSE;
11652#endif
11653
11654 if (rettv_list_alloc(rettv) == FAIL)
11655 return;
11656
11657#ifdef FEAT_SPELL
11658 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11659 {
11660 str = get_tv_string(&argvars[0]);
11661 if (argvars[1].v_type != VAR_UNKNOWN)
11662 {
11663 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11664 if (maxcount <= 0)
11665 return;
11666 if (argvars[2].v_type != VAR_UNKNOWN)
11667 {
11668 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11669 if (typeerr)
11670 return;
11671 }
11672 }
11673 else
11674 maxcount = 25;
11675
11676 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11677
11678 for (i = 0; i < ga.ga_len; ++i)
11679 {
11680 str = ((char_u **)ga.ga_data)[i];
11681
11682 li = listitem_alloc();
11683 if (li == NULL)
11684 vim_free(str);
11685 else
11686 {
11687 li->li_tv.v_type = VAR_STRING;
11688 li->li_tv.v_lock = 0;
11689 li->li_tv.vval.v_string = str;
11690 list_append(rettv->vval.v_list, li);
11691 }
11692 }
11693 ga_clear(&ga);
11694 }
11695#endif
11696}
11697
11698 static void
11699f_split(typval_T *argvars, typval_T *rettv)
11700{
11701 char_u *str;
11702 char_u *end;
11703 char_u *pat = NULL;
11704 regmatch_T regmatch;
11705 char_u patbuf[NUMBUFLEN];
11706 char_u *save_cpo;
11707 int match;
11708 colnr_T col = 0;
11709 int keepempty = FALSE;
11710 int typeerr = FALSE;
11711
11712 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11713 save_cpo = p_cpo;
11714 p_cpo = (char_u *)"";
11715
11716 str = get_tv_string(&argvars[0]);
11717 if (argvars[1].v_type != VAR_UNKNOWN)
11718 {
11719 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11720 if (pat == NULL)
11721 typeerr = TRUE;
11722 if (argvars[2].v_type != VAR_UNKNOWN)
11723 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11724 }
11725 if (pat == NULL || *pat == NUL)
11726 pat = (char_u *)"[\\x01- ]\\+";
11727
11728 if (rettv_list_alloc(rettv) == FAIL)
11729 return;
11730 if (typeerr)
11731 return;
11732
11733 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11734 if (regmatch.regprog != NULL)
11735 {
11736 regmatch.rm_ic = FALSE;
11737 while (*str != NUL || keepempty)
11738 {
11739 if (*str == NUL)
11740 match = FALSE; /* empty item at the end */
11741 else
11742 match = vim_regexec_nl(&regmatch, str, col);
11743 if (match)
11744 end = regmatch.startp[0];
11745 else
11746 end = str + STRLEN(str);
11747 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11748 && *str != NUL && match && end < regmatch.endp[0]))
11749 {
11750 if (list_append_string(rettv->vval.v_list, str,
11751 (int)(end - str)) == FAIL)
11752 break;
11753 }
11754 if (!match)
11755 break;
11756 /* Advance to just after the match. */
11757 if (regmatch.endp[0] > str)
11758 col = 0;
11759 else
11760 {
11761 /* Don't get stuck at the same match. */
11762#ifdef FEAT_MBYTE
11763 col = (*mb_ptr2len)(regmatch.endp[0]);
11764#else
11765 col = 1;
11766#endif
11767 }
11768 str = regmatch.endp[0];
11769 }
11770
11771 vim_regfree(regmatch.regprog);
11772 }
11773
11774 p_cpo = save_cpo;
11775}
11776
11777#ifdef FEAT_FLOAT
11778/*
11779 * "sqrt()" function
11780 */
11781 static void
11782f_sqrt(typval_T *argvars, typval_T *rettv)
11783{
11784 float_T f = 0.0;
11785
11786 rettv->v_type = VAR_FLOAT;
11787 if (get_float_arg(argvars, &f) == OK)
11788 rettv->vval.v_float = sqrt(f);
11789 else
11790 rettv->vval.v_float = 0.0;
11791}
11792
11793/*
11794 * "str2float()" function
11795 */
11796 static void
11797f_str2float(typval_T *argvars, typval_T *rettv)
11798{
11799 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011800 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011801
Bram Moolenaar08243d22017-01-10 16:12:29 +010011802 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011803 p = skipwhite(p + 1);
11804 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011805 if (isneg)
11806 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011807 rettv->v_type = VAR_FLOAT;
11808}
11809#endif
11810
11811/*
11812 * "str2nr()" function
11813 */
11814 static void
11815f_str2nr(typval_T *argvars, typval_T *rettv)
11816{
11817 int base = 10;
11818 char_u *p;
11819 varnumber_T n;
11820 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011821 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011822
11823 if (argvars[1].v_type != VAR_UNKNOWN)
11824 {
11825 base = (int)get_tv_number(&argvars[1]);
11826 if (base != 2 && base != 8 && base != 10 && base != 16)
11827 {
11828 EMSG(_(e_invarg));
11829 return;
11830 }
11831 }
11832
11833 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011834 isneg = (*p == '-');
11835 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011836 p = skipwhite(p + 1);
11837 switch (base)
11838 {
11839 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11840 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11841 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11842 default: what = 0;
11843 }
11844 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011845 if (isneg)
11846 rettv->vval.v_number = -n;
11847 else
11848 rettv->vval.v_number = n;
11849
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011850}
11851
11852#ifdef HAVE_STRFTIME
11853/*
11854 * "strftime({format}[, {time}])" function
11855 */
11856 static void
11857f_strftime(typval_T *argvars, typval_T *rettv)
11858{
11859 char_u result_buf[256];
11860 struct tm *curtime;
11861 time_t seconds;
11862 char_u *p;
11863
11864 rettv->v_type = VAR_STRING;
11865
11866 p = get_tv_string(&argvars[0]);
11867 if (argvars[1].v_type == VAR_UNKNOWN)
11868 seconds = time(NULL);
11869 else
11870 seconds = (time_t)get_tv_number(&argvars[1]);
11871 curtime = localtime(&seconds);
11872 /* MSVC returns NULL for an invalid value of seconds. */
11873 if (curtime == NULL)
11874 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11875 else
11876 {
11877# ifdef FEAT_MBYTE
11878 vimconv_T conv;
11879 char_u *enc;
11880
11881 conv.vc_type = CONV_NONE;
11882 enc = enc_locale();
11883 convert_setup(&conv, p_enc, enc);
11884 if (conv.vc_type != CONV_NONE)
11885 p = string_convert(&conv, p, NULL);
11886# endif
11887 if (p != NULL)
11888 (void)strftime((char *)result_buf, sizeof(result_buf),
11889 (char *)p, curtime);
11890 else
11891 result_buf[0] = NUL;
11892
11893# ifdef FEAT_MBYTE
11894 if (conv.vc_type != CONV_NONE)
11895 vim_free(p);
11896 convert_setup(&conv, enc, p_enc);
11897 if (conv.vc_type != CONV_NONE)
11898 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11899 else
11900# endif
11901 rettv->vval.v_string = vim_strsave(result_buf);
11902
11903# ifdef FEAT_MBYTE
11904 /* Release conversion descriptors */
11905 convert_setup(&conv, NULL, NULL);
11906 vim_free(enc);
11907# endif
11908 }
11909}
11910#endif
11911
11912/*
11913 * "strgetchar()" function
11914 */
11915 static void
11916f_strgetchar(typval_T *argvars, typval_T *rettv)
11917{
11918 char_u *str;
11919 int len;
11920 int error = FALSE;
11921 int charidx;
11922
11923 rettv->vval.v_number = -1;
11924 str = get_tv_string_chk(&argvars[0]);
11925 if (str == NULL)
11926 return;
11927 len = (int)STRLEN(str);
11928 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11929 if (error)
11930 return;
11931#ifdef FEAT_MBYTE
11932 {
11933 int byteidx = 0;
11934
11935 while (charidx >= 0 && byteidx < len)
11936 {
11937 if (charidx == 0)
11938 {
11939 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11940 break;
11941 }
11942 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011943 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011944 }
11945 }
11946#else
11947 if (charidx < len)
11948 rettv->vval.v_number = str[charidx];
11949#endif
11950}
11951
11952/*
11953 * "stridx()" function
11954 */
11955 static void
11956f_stridx(typval_T *argvars, typval_T *rettv)
11957{
11958 char_u buf[NUMBUFLEN];
11959 char_u *needle;
11960 char_u *haystack;
11961 char_u *save_haystack;
11962 char_u *pos;
11963 int start_idx;
11964
11965 needle = get_tv_string_chk(&argvars[1]);
11966 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11967 rettv->vval.v_number = -1;
11968 if (needle == NULL || haystack == NULL)
11969 return; /* type error; errmsg already given */
11970
11971 if (argvars[2].v_type != VAR_UNKNOWN)
11972 {
11973 int error = FALSE;
11974
11975 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11976 if (error || start_idx >= (int)STRLEN(haystack))
11977 return;
11978 if (start_idx >= 0)
11979 haystack += start_idx;
11980 }
11981
11982 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11983 if (pos != NULL)
11984 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11985}
11986
11987/*
11988 * "string()" function
11989 */
11990 static void
11991f_string(typval_T *argvars, typval_T *rettv)
11992{
11993 char_u *tofree;
11994 char_u numbuf[NUMBUFLEN];
11995
11996 rettv->v_type = VAR_STRING;
11997 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11998 get_copyID());
11999 /* Make a copy if we have a value but it's not in allocated memory. */
12000 if (rettv->vval.v_string != NULL && tofree == NULL)
12001 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12002}
12003
12004/*
12005 * "strlen()" function
12006 */
12007 static void
12008f_strlen(typval_T *argvars, typval_T *rettv)
12009{
12010 rettv->vval.v_number = (varnumber_T)(STRLEN(
12011 get_tv_string(&argvars[0])));
12012}
12013
12014/*
12015 * "strchars()" function
12016 */
12017 static void
12018f_strchars(typval_T *argvars, typval_T *rettv)
12019{
12020 char_u *s = get_tv_string(&argvars[0]);
12021 int skipcc = 0;
12022#ifdef FEAT_MBYTE
12023 varnumber_T len = 0;
12024 int (*func_mb_ptr2char_adv)(char_u **pp);
12025#endif
12026
12027 if (argvars[1].v_type != VAR_UNKNOWN)
12028 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
12029 if (skipcc < 0 || skipcc > 1)
12030 EMSG(_(e_invarg));
12031 else
12032 {
12033#ifdef FEAT_MBYTE
12034 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12035 while (*s != NUL)
12036 {
12037 func_mb_ptr2char_adv(&s);
12038 ++len;
12039 }
12040 rettv->vval.v_number = len;
12041#else
12042 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12043#endif
12044 }
12045}
12046
12047/*
12048 * "strdisplaywidth()" function
12049 */
12050 static void
12051f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12052{
12053 char_u *s = get_tv_string(&argvars[0]);
12054 int col = 0;
12055
12056 if (argvars[1].v_type != VAR_UNKNOWN)
12057 col = (int)get_tv_number(&argvars[1]);
12058
12059 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12060}
12061
12062/*
12063 * "strwidth()" function
12064 */
12065 static void
12066f_strwidth(typval_T *argvars, typval_T *rettv)
12067{
12068 char_u *s = get_tv_string(&argvars[0]);
12069
12070 rettv->vval.v_number = (varnumber_T)(
12071#ifdef FEAT_MBYTE
12072 mb_string2cells(s, -1)
12073#else
12074 STRLEN(s)
12075#endif
12076 );
12077}
12078
12079/*
12080 * "strcharpart()" function
12081 */
12082 static void
12083f_strcharpart(typval_T *argvars, typval_T *rettv)
12084{
12085#ifdef FEAT_MBYTE
12086 char_u *p;
12087 int nchar;
12088 int nbyte = 0;
12089 int charlen;
12090 int len = 0;
12091 int slen;
12092 int error = FALSE;
12093
12094 p = get_tv_string(&argvars[0]);
12095 slen = (int)STRLEN(p);
12096
12097 nchar = (int)get_tv_number_chk(&argvars[1], &error);
12098 if (!error)
12099 {
12100 if (nchar > 0)
12101 while (nchar > 0 && nbyte < slen)
12102 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012103 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012104 --nchar;
12105 }
12106 else
12107 nbyte = nchar;
12108 if (argvars[2].v_type != VAR_UNKNOWN)
12109 {
12110 charlen = (int)get_tv_number(&argvars[2]);
12111 while (charlen > 0 && nbyte + len < slen)
12112 {
12113 int off = nbyte + len;
12114
12115 if (off < 0)
12116 len += 1;
12117 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012118 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012119 --charlen;
12120 }
12121 }
12122 else
12123 len = slen - nbyte; /* default: all bytes that are available. */
12124 }
12125
12126 /*
12127 * Only return the overlap between the specified part and the actual
12128 * string.
12129 */
12130 if (nbyte < 0)
12131 {
12132 len += nbyte;
12133 nbyte = 0;
12134 }
12135 else if (nbyte > slen)
12136 nbyte = slen;
12137 if (len < 0)
12138 len = 0;
12139 else if (nbyte + len > slen)
12140 len = slen - nbyte;
12141
12142 rettv->v_type = VAR_STRING;
12143 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12144#else
12145 f_strpart(argvars, rettv);
12146#endif
12147}
12148
12149/*
12150 * "strpart()" function
12151 */
12152 static void
12153f_strpart(typval_T *argvars, typval_T *rettv)
12154{
12155 char_u *p;
12156 int n;
12157 int len;
12158 int slen;
12159 int error = FALSE;
12160
12161 p = get_tv_string(&argvars[0]);
12162 slen = (int)STRLEN(p);
12163
12164 n = (int)get_tv_number_chk(&argvars[1], &error);
12165 if (error)
12166 len = 0;
12167 else if (argvars[2].v_type != VAR_UNKNOWN)
12168 len = (int)get_tv_number(&argvars[2]);
12169 else
12170 len = slen - n; /* default len: all bytes that are available. */
12171
12172 /*
12173 * Only return the overlap between the specified part and the actual
12174 * string.
12175 */
12176 if (n < 0)
12177 {
12178 len += n;
12179 n = 0;
12180 }
12181 else if (n > slen)
12182 n = slen;
12183 if (len < 0)
12184 len = 0;
12185 else if (n + len > slen)
12186 len = slen - n;
12187
12188 rettv->v_type = VAR_STRING;
12189 rettv->vval.v_string = vim_strnsave(p + n, len);
12190}
12191
12192/*
12193 * "strridx()" function
12194 */
12195 static void
12196f_strridx(typval_T *argvars, typval_T *rettv)
12197{
12198 char_u buf[NUMBUFLEN];
12199 char_u *needle;
12200 char_u *haystack;
12201 char_u *rest;
12202 char_u *lastmatch = NULL;
12203 int haystack_len, end_idx;
12204
12205 needle = get_tv_string_chk(&argvars[1]);
12206 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12207
12208 rettv->vval.v_number = -1;
12209 if (needle == NULL || haystack == NULL)
12210 return; /* type error; errmsg already given */
12211
12212 haystack_len = (int)STRLEN(haystack);
12213 if (argvars[2].v_type != VAR_UNKNOWN)
12214 {
12215 /* Third argument: upper limit for index */
12216 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12217 if (end_idx < 0)
12218 return; /* can never find a match */
12219 }
12220 else
12221 end_idx = haystack_len;
12222
12223 if (*needle == NUL)
12224 {
12225 /* Empty string matches past the end. */
12226 lastmatch = haystack + end_idx;
12227 }
12228 else
12229 {
12230 for (rest = haystack; *rest != '\0'; ++rest)
12231 {
12232 rest = (char_u *)strstr((char *)rest, (char *)needle);
12233 if (rest == NULL || rest > haystack + end_idx)
12234 break;
12235 lastmatch = rest;
12236 }
12237 }
12238
12239 if (lastmatch == NULL)
12240 rettv->vval.v_number = -1;
12241 else
12242 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12243}
12244
12245/*
12246 * "strtrans()" function
12247 */
12248 static void
12249f_strtrans(typval_T *argvars, typval_T *rettv)
12250{
12251 rettv->v_type = VAR_STRING;
12252 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12253}
12254
12255/*
12256 * "submatch()" function
12257 */
12258 static void
12259f_submatch(typval_T *argvars, typval_T *rettv)
12260{
12261 int error = FALSE;
12262 int no;
12263 int retList = 0;
12264
12265 no = (int)get_tv_number_chk(&argvars[0], &error);
12266 if (error)
12267 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012268 if (no < 0 || no >= NSUBEXP)
12269 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012270 EMSGN(_("E935: invalid submatch number: %d"), no);
12271 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012272 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012273 if (argvars[1].v_type != VAR_UNKNOWN)
12274 retList = (int)get_tv_number_chk(&argvars[1], &error);
12275 if (error)
12276 return;
12277
12278 if (retList == 0)
12279 {
12280 rettv->v_type = VAR_STRING;
12281 rettv->vval.v_string = reg_submatch(no);
12282 }
12283 else
12284 {
12285 rettv->v_type = VAR_LIST;
12286 rettv->vval.v_list = reg_submatch_list(no);
12287 }
12288}
12289
12290/*
12291 * "substitute()" function
12292 */
12293 static void
12294f_substitute(typval_T *argvars, typval_T *rettv)
12295{
12296 char_u patbuf[NUMBUFLEN];
12297 char_u subbuf[NUMBUFLEN];
12298 char_u flagsbuf[NUMBUFLEN];
12299
12300 char_u *str = get_tv_string_chk(&argvars[0]);
12301 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012302 char_u *sub = NULL;
12303 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012304 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12305
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012306 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12307 expr = &argvars[2];
12308 else
12309 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12310
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012311 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012312 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12313 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012314 rettv->vval.v_string = NULL;
12315 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012316 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012317}
12318
12319/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012320 * "swapinfo(swap_filename)" function
12321 */
12322 static void
12323f_swapinfo(typval_T *argvars, typval_T *rettv)
12324{
12325 if (rettv_dict_alloc(rettv) == OK)
12326 get_b0_dict(get_tv_string(argvars), rettv->vval.v_dict);
12327}
12328
12329/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012330 * "synID(lnum, col, trans)" function
12331 */
12332 static void
12333f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12334{
12335 int id = 0;
12336#ifdef FEAT_SYN_HL
12337 linenr_T lnum;
12338 colnr_T col;
12339 int trans;
12340 int transerr = FALSE;
12341
12342 lnum = get_tv_lnum(argvars); /* -1 on type error */
12343 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12344 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12345
12346 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12347 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12348 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12349#endif
12350
12351 rettv->vval.v_number = id;
12352}
12353
12354/*
12355 * "synIDattr(id, what [, mode])" function
12356 */
12357 static void
12358f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12359{
12360 char_u *p = NULL;
12361#ifdef FEAT_SYN_HL
12362 int id;
12363 char_u *what;
12364 char_u *mode;
12365 char_u modebuf[NUMBUFLEN];
12366 int modec;
12367
12368 id = (int)get_tv_number(&argvars[0]);
12369 what = get_tv_string(&argvars[1]);
12370 if (argvars[2].v_type != VAR_UNKNOWN)
12371 {
12372 mode = get_tv_string_buf(&argvars[2], modebuf);
12373 modec = TOLOWER_ASC(mode[0]);
12374 if (modec != 't' && modec != 'c' && modec != 'g')
12375 modec = 0; /* replace invalid with current */
12376 }
12377 else
12378 {
12379#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12380 if (USE_24BIT)
12381 modec = 'g';
12382 else
12383#endif
12384 if (t_colors > 1)
12385 modec = 'c';
12386 else
12387 modec = 't';
12388 }
12389
12390
12391 switch (TOLOWER_ASC(what[0]))
12392 {
12393 case 'b':
12394 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12395 p = highlight_color(id, what, modec);
12396 else /* bold */
12397 p = highlight_has_attr(id, HL_BOLD, modec);
12398 break;
12399
12400 case 'f': /* fg[#] or font */
12401 p = highlight_color(id, what, modec);
12402 break;
12403
12404 case 'i':
12405 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12406 p = highlight_has_attr(id, HL_INVERSE, modec);
12407 else /* italic */
12408 p = highlight_has_attr(id, HL_ITALIC, modec);
12409 break;
12410
12411 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012412 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012413 break;
12414
12415 case 'r': /* reverse */
12416 p = highlight_has_attr(id, HL_INVERSE, modec);
12417 break;
12418
12419 case 's':
12420 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12421 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012422 /* strikeout */
12423 else if (TOLOWER_ASC(what[1]) == 't' &&
12424 TOLOWER_ASC(what[2]) == 'r')
12425 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012426 else /* standout */
12427 p = highlight_has_attr(id, HL_STANDOUT, modec);
12428 break;
12429
12430 case 'u':
12431 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12432 /* underline */
12433 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12434 else
12435 /* undercurl */
12436 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12437 break;
12438 }
12439
12440 if (p != NULL)
12441 p = vim_strsave(p);
12442#endif
12443 rettv->v_type = VAR_STRING;
12444 rettv->vval.v_string = p;
12445}
12446
12447/*
12448 * "synIDtrans(id)" function
12449 */
12450 static void
12451f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12452{
12453 int id;
12454
12455#ifdef FEAT_SYN_HL
12456 id = (int)get_tv_number(&argvars[0]);
12457
12458 if (id > 0)
12459 id = syn_get_final_id(id);
12460 else
12461#endif
12462 id = 0;
12463
12464 rettv->vval.v_number = id;
12465}
12466
12467/*
12468 * "synconcealed(lnum, col)" function
12469 */
12470 static void
12471f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12472{
12473#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12474 linenr_T lnum;
12475 colnr_T col;
12476 int syntax_flags = 0;
12477 int cchar;
12478 int matchid = 0;
12479 char_u str[NUMBUFLEN];
12480#endif
12481
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012482 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012483
12484#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12485 lnum = get_tv_lnum(argvars); /* -1 on type error */
12486 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12487
12488 vim_memset(str, NUL, sizeof(str));
12489
12490 if (rettv_list_alloc(rettv) != FAIL)
12491 {
12492 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12493 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12494 && curwin->w_p_cole > 0)
12495 {
12496 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12497 syntax_flags = get_syntax_info(&matchid);
12498
12499 /* get the conceal character */
12500 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12501 {
12502 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012503 if (cchar == NUL && curwin->w_p_cole == 1)
12504 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012505 if (cchar != NUL)
12506 {
12507# ifdef FEAT_MBYTE
12508 if (has_mbyte)
12509 (*mb_char2bytes)(cchar, str);
12510 else
12511# endif
12512 str[0] = cchar;
12513 }
12514 }
12515 }
12516
12517 list_append_number(rettv->vval.v_list,
12518 (syntax_flags & HL_CONCEAL) != 0);
12519 /* -1 to auto-determine strlen */
12520 list_append_string(rettv->vval.v_list, str, -1);
12521 list_append_number(rettv->vval.v_list, matchid);
12522 }
12523#endif
12524}
12525
12526/*
12527 * "synstack(lnum, col)" function
12528 */
12529 static void
12530f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12531{
12532#ifdef FEAT_SYN_HL
12533 linenr_T lnum;
12534 colnr_T col;
12535 int i;
12536 int id;
12537#endif
12538
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012539 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012540
12541#ifdef FEAT_SYN_HL
12542 lnum = get_tv_lnum(argvars); /* -1 on type error */
12543 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12544
12545 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12546 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12547 && rettv_list_alloc(rettv) != FAIL)
12548 {
12549 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12550 for (i = 0; ; ++i)
12551 {
12552 id = syn_get_stack_item(i);
12553 if (id < 0)
12554 break;
12555 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12556 break;
12557 }
12558 }
12559#endif
12560}
12561
12562 static void
12563get_cmd_output_as_rettv(
12564 typval_T *argvars,
12565 typval_T *rettv,
12566 int retlist)
12567{
12568 char_u *res = NULL;
12569 char_u *p;
12570 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012571 int err = FALSE;
12572 FILE *fd;
12573 list_T *list = NULL;
12574 int flags = SHELL_SILENT;
12575
12576 rettv->v_type = VAR_STRING;
12577 rettv->vval.v_string = NULL;
12578 if (check_restricted() || check_secure())
12579 goto errret;
12580
12581 if (argvars[1].v_type != VAR_UNKNOWN)
12582 {
12583 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012584 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012585 * command.
12586 */
12587 if ((infile = vim_tempname('i', TRUE)) == NULL)
12588 {
12589 EMSG(_(e_notmp));
12590 goto errret;
12591 }
12592
12593 fd = mch_fopen((char *)infile, WRITEBIN);
12594 if (fd == NULL)
12595 {
12596 EMSG2(_(e_notopen), infile);
12597 goto errret;
12598 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012599 if (argvars[1].v_type == VAR_NUMBER)
12600 {
12601 linenr_T lnum;
12602 buf_T *buf;
12603
12604 buf = buflist_findnr(argvars[1].vval.v_number);
12605 if (buf == NULL)
12606 {
12607 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012608 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012609 goto errret;
12610 }
12611
12612 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12613 {
12614 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12615 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12616 {
12617 err = TRUE;
12618 break;
12619 }
12620 if (putc(NL, fd) == EOF)
12621 {
12622 err = TRUE;
12623 break;
12624 }
12625 }
12626 }
12627 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012628 {
12629 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12630 err = TRUE;
12631 }
12632 else
12633 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012634 size_t len;
12635 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012636
12637 p = get_tv_string_buf_chk(&argvars[1], buf);
12638 if (p == NULL)
12639 {
12640 fclose(fd);
12641 goto errret; /* type error; errmsg already given */
12642 }
12643 len = STRLEN(p);
12644 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12645 err = TRUE;
12646 }
12647 if (fclose(fd) != 0)
12648 err = TRUE;
12649 if (err)
12650 {
12651 EMSG(_("E677: Error writing temp file"));
12652 goto errret;
12653 }
12654 }
12655
12656 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12657 * echoes typeahead, that messes up the display. */
12658 if (!msg_silent)
12659 flags += SHELL_COOKED;
12660
12661 if (retlist)
12662 {
12663 int len;
12664 listitem_T *li;
12665 char_u *s = NULL;
12666 char_u *start;
12667 char_u *end;
12668 int i;
12669
12670 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12671 if (res == NULL)
12672 goto errret;
12673
12674 list = list_alloc();
12675 if (list == NULL)
12676 goto errret;
12677
12678 for (i = 0; i < len; ++i)
12679 {
12680 start = res + i;
12681 while (i < len && res[i] != NL)
12682 ++i;
12683 end = res + i;
12684
12685 s = alloc((unsigned)(end - start + 1));
12686 if (s == NULL)
12687 goto errret;
12688
12689 for (p = s; start < end; ++p, ++start)
12690 *p = *start == NUL ? NL : *start;
12691 *p = NUL;
12692
12693 li = listitem_alloc();
12694 if (li == NULL)
12695 {
12696 vim_free(s);
12697 goto errret;
12698 }
12699 li->li_tv.v_type = VAR_STRING;
12700 li->li_tv.v_lock = 0;
12701 li->li_tv.vval.v_string = s;
12702 list_append(list, li);
12703 }
12704
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012705 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012706 list = NULL;
12707 }
12708 else
12709 {
12710 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12711#ifdef USE_CR
12712 /* translate <CR> into <NL> */
12713 if (res != NULL)
12714 {
12715 char_u *s;
12716
12717 for (s = res; *s; ++s)
12718 {
12719 if (*s == CAR)
12720 *s = NL;
12721 }
12722 }
12723#else
12724# ifdef USE_CRNL
12725 /* translate <CR><NL> into <NL> */
12726 if (res != NULL)
12727 {
12728 char_u *s, *d;
12729
12730 d = res;
12731 for (s = res; *s; ++s)
12732 {
12733 if (s[0] == CAR && s[1] == NL)
12734 ++s;
12735 *d++ = *s;
12736 }
12737 *d = NUL;
12738 }
12739# endif
12740#endif
12741 rettv->vval.v_string = res;
12742 res = NULL;
12743 }
12744
12745errret:
12746 if (infile != NULL)
12747 {
12748 mch_remove(infile);
12749 vim_free(infile);
12750 }
12751 if (res != NULL)
12752 vim_free(res);
12753 if (list != NULL)
12754 list_free(list);
12755}
12756
12757/*
12758 * "system()" function
12759 */
12760 static void
12761f_system(typval_T *argvars, typval_T *rettv)
12762{
12763 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12764}
12765
12766/*
12767 * "systemlist()" function
12768 */
12769 static void
12770f_systemlist(typval_T *argvars, typval_T *rettv)
12771{
12772 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12773}
12774
12775/*
12776 * "tabpagebuflist()" function
12777 */
12778 static void
12779f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12780{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012781 tabpage_T *tp;
12782 win_T *wp = NULL;
12783
12784 if (argvars[0].v_type == VAR_UNKNOWN)
12785 wp = firstwin;
12786 else
12787 {
12788 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12789 if (tp != NULL)
12790 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12791 }
12792 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12793 {
12794 for (; wp != NULL; wp = wp->w_next)
12795 if (list_append_number(rettv->vval.v_list,
12796 wp->w_buffer->b_fnum) == FAIL)
12797 break;
12798 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012799}
12800
12801
12802/*
12803 * "tabpagenr()" function
12804 */
12805 static void
12806f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12807{
12808 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012809 char_u *arg;
12810
12811 if (argvars[0].v_type != VAR_UNKNOWN)
12812 {
12813 arg = get_tv_string_chk(&argvars[0]);
12814 nr = 0;
12815 if (arg != NULL)
12816 {
12817 if (STRCMP(arg, "$") == 0)
12818 nr = tabpage_index(NULL) - 1;
12819 else
12820 EMSG2(_(e_invexpr2), arg);
12821 }
12822 }
12823 else
12824 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012825 rettv->vval.v_number = nr;
12826}
12827
12828
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012829static int get_winnr(tabpage_T *tp, typval_T *argvar);
12830
12831/*
12832 * Common code for tabpagewinnr() and winnr().
12833 */
12834 static int
12835get_winnr(tabpage_T *tp, typval_T *argvar)
12836{
12837 win_T *twin;
12838 int nr = 1;
12839 win_T *wp;
12840 char_u *arg;
12841
12842 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12843 if (argvar->v_type != VAR_UNKNOWN)
12844 {
12845 arg = get_tv_string_chk(argvar);
12846 if (arg == NULL)
12847 nr = 0; /* type error; errmsg already given */
12848 else if (STRCMP(arg, "$") == 0)
12849 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12850 else if (STRCMP(arg, "#") == 0)
12851 {
12852 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12853 if (twin == NULL)
12854 nr = 0;
12855 }
12856 else
12857 {
12858 EMSG2(_(e_invexpr2), arg);
12859 nr = 0;
12860 }
12861 }
12862
12863 if (nr > 0)
12864 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12865 wp != twin; wp = wp->w_next)
12866 {
12867 if (wp == NULL)
12868 {
12869 /* didn't find it in this tabpage */
12870 nr = 0;
12871 break;
12872 }
12873 ++nr;
12874 }
12875 return nr;
12876}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012877
12878/*
12879 * "tabpagewinnr()" function
12880 */
12881 static void
12882f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12883{
12884 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012885 tabpage_T *tp;
12886
12887 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12888 if (tp == NULL)
12889 nr = 0;
12890 else
12891 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012892 rettv->vval.v_number = nr;
12893}
12894
12895
12896/*
12897 * "tagfiles()" function
12898 */
12899 static void
12900f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12901{
12902 char_u *fname;
12903 tagname_T tn;
12904 int first;
12905
12906 if (rettv_list_alloc(rettv) == FAIL)
12907 return;
12908 fname = alloc(MAXPATHL);
12909 if (fname == NULL)
12910 return;
12911
12912 for (first = TRUE; ; first = FALSE)
12913 if (get_tagfname(&tn, first, fname) == FAIL
12914 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12915 break;
12916 tagname_free(&tn);
12917 vim_free(fname);
12918}
12919
12920/*
12921 * "taglist()" function
12922 */
12923 static void
12924f_taglist(typval_T *argvars, typval_T *rettv)
12925{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012926 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012927 char_u *tag_pattern;
12928
12929 tag_pattern = get_tv_string(&argvars[0]);
12930
12931 rettv->vval.v_number = FALSE;
12932 if (*tag_pattern == NUL)
12933 return;
12934
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012935 if (argvars[1].v_type != VAR_UNKNOWN)
12936 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012937 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012938 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012939}
12940
12941/*
12942 * "tempname()" function
12943 */
12944 static void
12945f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12946{
12947 static int x = 'A';
12948
12949 rettv->v_type = VAR_STRING;
12950 rettv->vval.v_string = vim_tempname(x, FALSE);
12951
12952 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12953 * names. Skip 'I' and 'O', they are used for shell redirection. */
12954 do
12955 {
12956 if (x == 'Z')
12957 x = '0';
12958 else if (x == '9')
12959 x = 'A';
12960 else
12961 {
12962#ifdef EBCDIC
12963 if (x == 'I')
12964 x = 'J';
12965 else if (x == 'R')
12966 x = 'S';
12967 else
12968#endif
12969 ++x;
12970 }
12971 } while (x == 'I' || x == 'O');
12972}
12973
12974#ifdef FEAT_FLOAT
12975/*
12976 * "tan()" function
12977 */
12978 static void
12979f_tan(typval_T *argvars, typval_T *rettv)
12980{
12981 float_T f = 0.0;
12982
12983 rettv->v_type = VAR_FLOAT;
12984 if (get_float_arg(argvars, &f) == OK)
12985 rettv->vval.v_float = tan(f);
12986 else
12987 rettv->vval.v_float = 0.0;
12988}
12989
12990/*
12991 * "tanh()" function
12992 */
12993 static void
12994f_tanh(typval_T *argvars, typval_T *rettv)
12995{
12996 float_T f = 0.0;
12997
12998 rettv->v_type = VAR_FLOAT;
12999 if (get_float_arg(argvars, &f) == OK)
13000 rettv->vval.v_float = tanh(f);
13001 else
13002 rettv->vval.v_float = 0.0;
13003}
13004#endif
13005
13006/*
13007 * "test_alloc_fail(id, countdown, repeat)" function
13008 */
13009 static void
13010f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13011{
13012 if (argvars[0].v_type != VAR_NUMBER
13013 || argvars[0].vval.v_number <= 0
13014 || argvars[1].v_type != VAR_NUMBER
13015 || argvars[1].vval.v_number < 0
13016 || argvars[2].v_type != VAR_NUMBER)
13017 EMSG(_(e_invarg));
13018 else
13019 {
13020 alloc_fail_id = argvars[0].vval.v_number;
13021 if (alloc_fail_id >= aid_last)
13022 EMSG(_(e_invarg));
13023 alloc_fail_countdown = argvars[1].vval.v_number;
13024 alloc_fail_repeat = argvars[2].vval.v_number;
13025 did_outofmem_msg = FALSE;
13026 }
13027}
13028
13029/*
13030 * "test_autochdir()"
13031 */
13032 static void
13033f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13034{
13035#if defined(FEAT_AUTOCHDIR)
13036 test_autochdir = TRUE;
13037#endif
13038}
13039
13040/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013041 * "test_feedinput()"
13042 */
13043 static void
13044f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13045{
13046#ifdef USE_INPUT_BUF
13047 char_u *val = get_tv_string_chk(&argvars[0]);
13048
13049 if (val != NULL)
13050 {
13051 trash_input_buf();
13052 add_to_input_buf_csi(val, (int)STRLEN(val));
13053 }
13054#endif
13055}
13056
13057/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013058 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013059 */
13060 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013061f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013062{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013063 char_u *name = (char_u *)"";
13064 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013065 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013066
13067 if (argvars[0].v_type != VAR_STRING
13068 || (argvars[1].v_type) != VAR_NUMBER)
13069 EMSG(_(e_invarg));
13070 else
13071 {
13072 name = get_tv_string_chk(&argvars[0]);
13073 val = (int)get_tv_number(&argvars[1]);
13074
13075 if (STRCMP(name, (char_u *)"redraw") == 0)
13076 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013077 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13078 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013079 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13080 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013081 else if (STRCMP(name, (char_u *)"starting") == 0)
13082 {
13083 if (val)
13084 {
13085 if (save_starting < 0)
13086 save_starting = starting;
13087 starting = 0;
13088 }
13089 else
13090 {
13091 starting = save_starting;
13092 save_starting = -1;
13093 }
13094 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013095 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13096 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013097 else if (STRCMP(name, (char_u *)"ALL") == 0)
13098 {
13099 disable_char_avail_for_testing = FALSE;
13100 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013101 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013102 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013103 if (save_starting >= 0)
13104 {
13105 starting = save_starting;
13106 save_starting = -1;
13107 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013108 }
13109 else
13110 EMSG2(_(e_invarg2), name);
13111 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013112}
13113
13114/*
13115 * "test_garbagecollect_now()" function
13116 */
13117 static void
13118f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13119{
13120 /* This is dangerous, any Lists and Dicts used internally may be freed
13121 * while still in use. */
13122 garbage_collect(TRUE);
13123}
13124
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013125/*
13126 * "test_ignore_error()" function
13127 */
13128 static void
13129f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13130{
13131 ignore_error_for_testing(get_tv_string(&argvars[0]));
13132}
13133
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013134#ifdef FEAT_JOB_CHANNEL
13135 static void
13136f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13137{
13138 rettv->v_type = VAR_CHANNEL;
13139 rettv->vval.v_channel = NULL;
13140}
13141#endif
13142
13143 static void
13144f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13145{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013146 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013147}
13148
13149#ifdef FEAT_JOB_CHANNEL
13150 static void
13151f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13152{
13153 rettv->v_type = VAR_JOB;
13154 rettv->vval.v_job = NULL;
13155}
13156#endif
13157
13158 static void
13159f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13160{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013161 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013162}
13163
13164 static void
13165f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13166{
13167 rettv->v_type = VAR_PARTIAL;
13168 rettv->vval.v_partial = NULL;
13169}
13170
13171 static void
13172f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13173{
13174 rettv->v_type = VAR_STRING;
13175 rettv->vval.v_string = NULL;
13176}
13177
13178 static void
13179f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13180{
13181 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13182}
13183
13184#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13185/*
13186 * Get a callback from "arg". It can be a Funcref or a function name.
13187 * When "arg" is zero return an empty string.
13188 * Return NULL for an invalid argument.
13189 */
13190 char_u *
13191get_callback(typval_T *arg, partial_T **pp)
13192{
13193 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13194 {
13195 *pp = arg->vval.v_partial;
13196 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013197 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013198 }
13199 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013200 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013201 {
13202 func_ref(arg->vval.v_string);
13203 return arg->vval.v_string;
13204 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013205 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13206 return (char_u *)"";
13207 EMSG(_("E921: Invalid callback argument"));
13208 return NULL;
13209}
13210
13211/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013212 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013213 */
13214 void
13215free_callback(char_u *callback, partial_T *partial)
13216{
13217 if (partial != NULL)
13218 partial_unref(partial);
13219 else if (callback != NULL)
13220 {
13221 func_unref(callback);
13222 vim_free(callback);
13223 }
13224}
13225#endif
13226
13227#ifdef FEAT_TIMERS
13228/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013229 * "timer_info([timer])" function
13230 */
13231 static void
13232f_timer_info(typval_T *argvars, typval_T *rettv)
13233{
13234 timer_T *timer = NULL;
13235
13236 if (rettv_list_alloc(rettv) != OK)
13237 return;
13238 if (argvars[0].v_type != VAR_UNKNOWN)
13239 {
13240 if (argvars[0].v_type != VAR_NUMBER)
13241 EMSG(_(e_number_exp));
13242 else
13243 {
13244 timer = find_timer((int)get_tv_number(&argvars[0]));
13245 if (timer != NULL)
13246 add_timer_info(rettv, timer);
13247 }
13248 }
13249 else
13250 add_timer_info_all(rettv);
13251}
13252
13253/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013254 * "timer_pause(timer, paused)" function
13255 */
13256 static void
13257f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13258{
13259 timer_T *timer = NULL;
13260 int paused = (int)get_tv_number(&argvars[1]);
13261
13262 if (argvars[0].v_type != VAR_NUMBER)
13263 EMSG(_(e_number_exp));
13264 else
13265 {
13266 timer = find_timer((int)get_tv_number(&argvars[0]));
13267 if (timer != NULL)
13268 timer->tr_paused = paused;
13269 }
13270}
13271
13272/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013273 * "timer_start(time, callback [, options])" function
13274 */
13275 static void
13276f_timer_start(typval_T *argvars, typval_T *rettv)
13277{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013278 long msec = (long)get_tv_number(&argvars[0]);
13279 timer_T *timer;
13280 int repeat = 0;
13281 char_u *callback;
13282 dict_T *dict;
13283 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013284
Bram Moolenaar75537a92016-09-05 22:45:28 +020013285 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013286 if (check_secure())
13287 return;
13288 if (argvars[2].v_type != VAR_UNKNOWN)
13289 {
13290 if (argvars[2].v_type != VAR_DICT
13291 || (dict = argvars[2].vval.v_dict) == NULL)
13292 {
13293 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13294 return;
13295 }
13296 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13297 repeat = get_dict_number(dict, (char_u *)"repeat");
13298 }
13299
Bram Moolenaar75537a92016-09-05 22:45:28 +020013300 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013301 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013302 return;
13303
13304 timer = create_timer(msec, repeat);
13305 if (timer == NULL)
13306 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013307 else
13308 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013309 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013310 timer->tr_callback = vim_strsave(callback);
13311 else
13312 /* pointer into the partial */
13313 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013314 timer->tr_partial = partial;
13315 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013316 }
13317}
13318
13319/*
13320 * "timer_stop(timer)" function
13321 */
13322 static void
13323f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13324{
13325 timer_T *timer;
13326
13327 if (argvars[0].v_type != VAR_NUMBER)
13328 {
13329 EMSG(_(e_number_exp));
13330 return;
13331 }
13332 timer = find_timer((int)get_tv_number(&argvars[0]));
13333 if (timer != NULL)
13334 stop_timer(timer);
13335}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013336
13337/*
13338 * "timer_stopall()" function
13339 */
13340 static void
13341f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13342{
13343 stop_all_timers();
13344}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013345#endif
13346
13347/*
13348 * "tolower(string)" function
13349 */
13350 static void
13351f_tolower(typval_T *argvars, typval_T *rettv)
13352{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013353 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013354 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013355}
13356
13357/*
13358 * "toupper(string)" function
13359 */
13360 static void
13361f_toupper(typval_T *argvars, typval_T *rettv)
13362{
13363 rettv->v_type = VAR_STRING;
13364 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13365}
13366
13367/*
13368 * "tr(string, fromstr, tostr)" function
13369 */
13370 static void
13371f_tr(typval_T *argvars, typval_T *rettv)
13372{
13373 char_u *in_str;
13374 char_u *fromstr;
13375 char_u *tostr;
13376 char_u *p;
13377#ifdef FEAT_MBYTE
13378 int inlen;
13379 int fromlen;
13380 int tolen;
13381 int idx;
13382 char_u *cpstr;
13383 int cplen;
13384 int first = TRUE;
13385#endif
13386 char_u buf[NUMBUFLEN];
13387 char_u buf2[NUMBUFLEN];
13388 garray_T ga;
13389
13390 in_str = get_tv_string(&argvars[0]);
13391 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13392 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13393
13394 /* Default return value: empty string. */
13395 rettv->v_type = VAR_STRING;
13396 rettv->vval.v_string = NULL;
13397 if (fromstr == NULL || tostr == NULL)
13398 return; /* type error; errmsg already given */
13399 ga_init2(&ga, (int)sizeof(char), 80);
13400
13401#ifdef FEAT_MBYTE
13402 if (!has_mbyte)
13403#endif
13404 /* not multi-byte: fromstr and tostr must be the same length */
13405 if (STRLEN(fromstr) != STRLEN(tostr))
13406 {
13407#ifdef FEAT_MBYTE
13408error:
13409#endif
13410 EMSG2(_(e_invarg2), fromstr);
13411 ga_clear(&ga);
13412 return;
13413 }
13414
13415 /* fromstr and tostr have to contain the same number of chars */
13416 while (*in_str != NUL)
13417 {
13418#ifdef FEAT_MBYTE
13419 if (has_mbyte)
13420 {
13421 inlen = (*mb_ptr2len)(in_str);
13422 cpstr = in_str;
13423 cplen = inlen;
13424 idx = 0;
13425 for (p = fromstr; *p != NUL; p += fromlen)
13426 {
13427 fromlen = (*mb_ptr2len)(p);
13428 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13429 {
13430 for (p = tostr; *p != NUL; p += tolen)
13431 {
13432 tolen = (*mb_ptr2len)(p);
13433 if (idx-- == 0)
13434 {
13435 cplen = tolen;
13436 cpstr = p;
13437 break;
13438 }
13439 }
13440 if (*p == NUL) /* tostr is shorter than fromstr */
13441 goto error;
13442 break;
13443 }
13444 ++idx;
13445 }
13446
13447 if (first && cpstr == in_str)
13448 {
13449 /* Check that fromstr and tostr have the same number of
13450 * (multi-byte) characters. Done only once when a character
13451 * of in_str doesn't appear in fromstr. */
13452 first = FALSE;
13453 for (p = tostr; *p != NUL; p += tolen)
13454 {
13455 tolen = (*mb_ptr2len)(p);
13456 --idx;
13457 }
13458 if (idx != 0)
13459 goto error;
13460 }
13461
13462 (void)ga_grow(&ga, cplen);
13463 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13464 ga.ga_len += cplen;
13465
13466 in_str += inlen;
13467 }
13468 else
13469#endif
13470 {
13471 /* When not using multi-byte chars we can do it faster. */
13472 p = vim_strchr(fromstr, *in_str);
13473 if (p != NULL)
13474 ga_append(&ga, tostr[p - fromstr]);
13475 else
13476 ga_append(&ga, *in_str);
13477 ++in_str;
13478 }
13479 }
13480
13481 /* add a terminating NUL */
13482 (void)ga_grow(&ga, 1);
13483 ga_append(&ga, NUL);
13484
13485 rettv->vval.v_string = ga.ga_data;
13486}
13487
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013488/*
13489 * "trim({expr})" function
13490 */
13491 static void
13492f_trim(typval_T *argvars, typval_T *rettv)
13493{
13494 char_u buf1[NUMBUFLEN];
13495 char_u buf2[NUMBUFLEN];
13496 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13497 char_u *mask = NULL;
13498 char_u *tail;
13499 char_u *prev;
13500 char_u *p;
13501 int c1;
13502
13503 rettv->v_type = VAR_STRING;
13504 if (head == NULL)
13505 {
13506 rettv->vval.v_string = NULL;
13507 return;
13508 }
13509
13510 if (argvars[1].v_type == VAR_STRING)
13511 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13512
13513 while (*head != NUL)
13514 {
13515 c1 = PTR2CHAR(head);
13516 if (mask == NULL)
13517 {
13518 if (c1 > ' ' && c1 != 0xa0)
13519 break;
13520 }
13521 else
13522 {
13523 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13524 if (c1 == PTR2CHAR(p))
13525 break;
13526 if (*p == NUL)
13527 break;
13528 }
13529 MB_PTR_ADV(head);
13530 }
13531
13532 for (tail = head + STRLEN(head); tail > head; tail = prev)
13533 {
13534 prev = tail;
13535 MB_PTR_BACK(head, prev);
13536 c1 = PTR2CHAR(prev);
13537 if (mask == NULL)
13538 {
13539 if (c1 > ' ' && c1 != 0xa0)
13540 break;
13541 }
13542 else
13543 {
13544 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13545 if (c1 == PTR2CHAR(p))
13546 break;
13547 if (*p == NUL)
13548 break;
13549 }
13550 }
13551 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13552}
13553
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013554#ifdef FEAT_FLOAT
13555/*
13556 * "trunc({float})" function
13557 */
13558 static void
13559f_trunc(typval_T *argvars, typval_T *rettv)
13560{
13561 float_T f = 0.0;
13562
13563 rettv->v_type = VAR_FLOAT;
13564 if (get_float_arg(argvars, &f) == OK)
13565 /* trunc() is not in C90, use floor() or ceil() instead. */
13566 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13567 else
13568 rettv->vval.v_float = 0.0;
13569}
13570#endif
13571
13572/*
13573 * "type(expr)" function
13574 */
13575 static void
13576f_type(typval_T *argvars, typval_T *rettv)
13577{
13578 int n = -1;
13579
13580 switch (argvars[0].v_type)
13581 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013582 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13583 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013584 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013585 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13586 case VAR_LIST: n = VAR_TYPE_LIST; break;
13587 case VAR_DICT: n = VAR_TYPE_DICT; break;
13588 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013589 case VAR_SPECIAL:
13590 if (argvars[0].vval.v_number == VVAL_FALSE
13591 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013592 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013593 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013594 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013595 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013596 case VAR_JOB: n = VAR_TYPE_JOB; break;
13597 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013598 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013599 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013600 n = -1;
13601 break;
13602 }
13603 rettv->vval.v_number = n;
13604}
13605
13606/*
13607 * "undofile(name)" function
13608 */
13609 static void
13610f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13611{
13612 rettv->v_type = VAR_STRING;
13613#ifdef FEAT_PERSISTENT_UNDO
13614 {
13615 char_u *fname = get_tv_string(&argvars[0]);
13616
13617 if (*fname == NUL)
13618 {
13619 /* If there is no file name there will be no undo file. */
13620 rettv->vval.v_string = NULL;
13621 }
13622 else
13623 {
13624 char_u *ffname = FullName_save(fname, FALSE);
13625
13626 if (ffname != NULL)
13627 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13628 vim_free(ffname);
13629 }
13630 }
13631#else
13632 rettv->vval.v_string = NULL;
13633#endif
13634}
13635
13636/*
13637 * "undotree()" function
13638 */
13639 static void
13640f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13641{
13642 if (rettv_dict_alloc(rettv) == OK)
13643 {
13644 dict_T *dict = rettv->vval.v_dict;
13645 list_T *list;
13646
Bram Moolenaare0be1672018-07-08 16:50:37 +020013647 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
13648 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
13649 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
13650 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
13651 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
13652 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013653
13654 list = list_alloc();
13655 if (list != NULL)
13656 {
13657 u_eval_tree(curbuf->b_u_oldhead, list);
13658 dict_add_list(dict, "entries", list);
13659 }
13660 }
13661}
13662
13663/*
13664 * "values(dict)" function
13665 */
13666 static void
13667f_values(typval_T *argvars, typval_T *rettv)
13668{
13669 dict_list(argvars, rettv, 1);
13670}
13671
13672/*
13673 * "virtcol(string)" function
13674 */
13675 static void
13676f_virtcol(typval_T *argvars, typval_T *rettv)
13677{
13678 colnr_T vcol = 0;
13679 pos_T *fp;
13680 int fnum = curbuf->b_fnum;
13681
13682 fp = var2fpos(&argvars[0], FALSE, &fnum);
13683 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13684 && fnum == curbuf->b_fnum)
13685 {
13686 getvvcol(curwin, fp, NULL, NULL, &vcol);
13687 ++vcol;
13688 }
13689
13690 rettv->vval.v_number = vcol;
13691}
13692
13693/*
13694 * "visualmode()" function
13695 */
13696 static void
13697f_visualmode(typval_T *argvars, typval_T *rettv)
13698{
13699 char_u str[2];
13700
13701 rettv->v_type = VAR_STRING;
13702 str[0] = curbuf->b_visual_mode_eval;
13703 str[1] = NUL;
13704 rettv->vval.v_string = vim_strsave(str);
13705
13706 /* A non-zero number or non-empty string argument: reset mode. */
13707 if (non_zero_arg(&argvars[0]))
13708 curbuf->b_visual_mode_eval = NUL;
13709}
13710
13711/*
13712 * "wildmenumode()" function
13713 */
13714 static void
13715f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13716{
13717#ifdef FEAT_WILDMENU
13718 if (wild_menu_showing)
13719 rettv->vval.v_number = 1;
13720#endif
13721}
13722
13723/*
13724 * "winbufnr(nr)" function
13725 */
13726 static void
13727f_winbufnr(typval_T *argvars, typval_T *rettv)
13728{
13729 win_T *wp;
13730
13731 wp = find_win_by_nr(&argvars[0], NULL);
13732 if (wp == NULL)
13733 rettv->vval.v_number = -1;
13734 else
13735 rettv->vval.v_number = wp->w_buffer->b_fnum;
13736}
13737
13738/*
13739 * "wincol()" function
13740 */
13741 static void
13742f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13743{
13744 validate_cursor();
13745 rettv->vval.v_number = curwin->w_wcol + 1;
13746}
13747
13748/*
13749 * "winheight(nr)" function
13750 */
13751 static void
13752f_winheight(typval_T *argvars, typval_T *rettv)
13753{
13754 win_T *wp;
13755
13756 wp = find_win_by_nr(&argvars[0], NULL);
13757 if (wp == NULL)
13758 rettv->vval.v_number = -1;
13759 else
13760 rettv->vval.v_number = wp->w_height;
13761}
13762
13763/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020013764 * "winlayout()" function
13765 */
13766 static void
13767f_winlayout(typval_T *argvars, typval_T *rettv)
13768{
13769 tabpage_T *tp;
13770
13771 if (rettv_list_alloc(rettv) != OK)
13772 return;
13773
13774 if (argvars[0].v_type == VAR_UNKNOWN)
13775 tp = curtab;
13776 else
13777 {
13778 tp = find_tabpage((int)get_tv_number(&argvars[0]));
13779 if (tp == NULL)
13780 return;
13781 }
13782
13783 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
13784}
13785
13786/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013787 * "winline()" function
13788 */
13789 static void
13790f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13791{
13792 validate_cursor();
13793 rettv->vval.v_number = curwin->w_wrow + 1;
13794}
13795
13796/*
13797 * "winnr()" function
13798 */
13799 static void
13800f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13801{
13802 int nr = 1;
13803
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013804 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013805 rettv->vval.v_number = nr;
13806}
13807
13808/*
13809 * "winrestcmd()" function
13810 */
13811 static void
13812f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13813{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013814 win_T *wp;
13815 int winnr = 1;
13816 garray_T ga;
13817 char_u buf[50];
13818
13819 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013820 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013821 {
13822 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13823 ga_concat(&ga, buf);
13824 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13825 ga_concat(&ga, buf);
13826 ++winnr;
13827 }
13828 ga_append(&ga, NUL);
13829
13830 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013831 rettv->v_type = VAR_STRING;
13832}
13833
13834/*
13835 * "winrestview()" function
13836 */
13837 static void
13838f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13839{
13840 dict_T *dict;
13841
13842 if (argvars[0].v_type != VAR_DICT
13843 || (dict = argvars[0].vval.v_dict) == NULL)
13844 EMSG(_(e_invarg));
13845 else
13846 {
13847 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13848 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13849 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13850 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13851#ifdef FEAT_VIRTUALEDIT
13852 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13853 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13854#endif
13855 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13856 {
13857 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13858 curwin->w_set_curswant = FALSE;
13859 }
13860
13861 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13862 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13863#ifdef FEAT_DIFF
13864 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13865 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13866#endif
13867 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13868 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13869 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13870 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13871
13872 check_cursor();
13873 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013874 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013875 changed_window_setting();
13876
13877 if (curwin->w_topline <= 0)
13878 curwin->w_topline = 1;
13879 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13880 curwin->w_topline = curbuf->b_ml.ml_line_count;
13881#ifdef FEAT_DIFF
13882 check_topfill(curwin, TRUE);
13883#endif
13884 }
13885}
13886
13887/*
13888 * "winsaveview()" function
13889 */
13890 static void
13891f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13892{
13893 dict_T *dict;
13894
13895 if (rettv_dict_alloc(rettv) == FAIL)
13896 return;
13897 dict = rettv->vval.v_dict;
13898
Bram Moolenaare0be1672018-07-08 16:50:37 +020013899 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13900 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013901#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020013902 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013903#endif
13904 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013905 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013906
Bram Moolenaare0be1672018-07-08 16:50:37 +020013907 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013908#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013909 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013910#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013911 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13912 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013913}
13914
13915/*
13916 * "winwidth(nr)" function
13917 */
13918 static void
13919f_winwidth(typval_T *argvars, typval_T *rettv)
13920{
13921 win_T *wp;
13922
13923 wp = find_win_by_nr(&argvars[0], NULL);
13924 if (wp == NULL)
13925 rettv->vval.v_number = -1;
13926 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013927 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013928}
13929
13930/*
13931 * "wordcount()" function
13932 */
13933 static void
13934f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13935{
13936 if (rettv_dict_alloc(rettv) == FAIL)
13937 return;
13938 cursor_pos_info(rettv->vval.v_dict);
13939}
13940
13941/*
13942 * "writefile()" function
13943 */
13944 static void
13945f_writefile(typval_T *argvars, typval_T *rettv)
13946{
13947 int binary = FALSE;
13948 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013949#ifdef HAVE_FSYNC
13950 int do_fsync = p_fs;
13951#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013952 char_u *fname;
13953 FILE *fd;
13954 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013955 listitem_T *li;
13956 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013957
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013958 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013959 if (check_restricted() || check_secure())
13960 return;
13961
13962 if (argvars[0].v_type != VAR_LIST)
13963 {
13964 EMSG2(_(e_listarg), "writefile()");
13965 return;
13966 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013967 list = argvars[0].vval.v_list;
13968 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013969 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013970 for (li = list->lv_first; li != NULL; li = li->li_next)
13971 if (get_tv_string_chk(&li->li_tv) == NULL)
13972 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013973
13974 if (argvars[2].v_type != VAR_UNKNOWN)
13975 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013976 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13977
13978 if (arg2 == NULL)
13979 return;
13980 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013981 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013982 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013983 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013984#ifdef HAVE_FSYNC
13985 if (vim_strchr(arg2, 's') != NULL)
13986 do_fsync = TRUE;
13987 else if (vim_strchr(arg2, 'S') != NULL)
13988 do_fsync = FALSE;
13989#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013990 }
13991
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013992 fname = get_tv_string_chk(&argvars[1]);
13993 if (fname == NULL)
13994 return;
13995
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013996 /* Always open the file in binary mode, library functions have a mind of
13997 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013998 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13999 append ? APPENDBIN : WRITEBIN)) == NULL)
14000 {
14001 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14002 ret = -1;
14003 }
14004 else
14005 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014006 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014007 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014008#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014009 else if (do_fsync)
14010 /* Ignore the error, the user wouldn't know what to do about it.
14011 * May happen for a device. */
14012 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014013#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014014 fclose(fd);
14015 }
14016
14017 rettv->vval.v_number = ret;
14018}
14019
14020/*
14021 * "xor(expr, expr)" function
14022 */
14023 static void
14024f_xor(typval_T *argvars, typval_T *rettv)
14025{
14026 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
14027 ^ get_tv_number_chk(&argvars[1], NULL);
14028}
14029
14030
14031#endif /* FEAT_EVAL */