blob: 5e7c013979e7a0ee4b34cd8de20efd3a714cf946 [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);
401static void f_synID(typval_T *argvars, typval_T *rettv);
402static void f_synIDattr(typval_T *argvars, typval_T *rettv);
403static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
404static void f_synstack(typval_T *argvars, typval_T *rettv);
405static void f_synconcealed(typval_T *argvars, typval_T *rettv);
406static void f_system(typval_T *argvars, typval_T *rettv);
407static void f_systemlist(typval_T *argvars, typval_T *rettv);
408static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
409static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
410static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
411static void f_taglist(typval_T *argvars, typval_T *rettv);
412static void f_tagfiles(typval_T *argvars, typval_T *rettv);
413static void f_tempname(typval_T *argvars, typval_T *rettv);
414static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
415static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200416static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100417static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200418static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100419static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200420#ifdef FEAT_JOB_CHANNEL
421static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
422#endif
423static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
424#ifdef FEAT_JOB_CHANNEL
425static void f_test_null_job(typval_T *argvars, typval_T *rettv);
426#endif
427static void f_test_null_list(typval_T *argvars, typval_T *rettv);
428static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
429static void f_test_null_string(typval_T *argvars, typval_T *rettv);
430static void f_test_settime(typval_T *argvars, typval_T *rettv);
431#ifdef FEAT_FLOAT
432static void f_tan(typval_T *argvars, typval_T *rettv);
433static void f_tanh(typval_T *argvars, typval_T *rettv);
434#endif
435#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200436static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200437static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200438static void f_timer_start(typval_T *argvars, typval_T *rettv);
439static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200440static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200441#endif
442static void f_tolower(typval_T *argvars, typval_T *rettv);
443static void f_toupper(typval_T *argvars, typval_T *rettv);
444static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100445static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200446#ifdef FEAT_FLOAT
447static void f_trunc(typval_T *argvars, typval_T *rettv);
448#endif
449static void f_type(typval_T *argvars, typval_T *rettv);
450static void f_undofile(typval_T *argvars, typval_T *rettv);
451static void f_undotree(typval_T *argvars, typval_T *rettv);
452static void f_uniq(typval_T *argvars, typval_T *rettv);
453static void f_values(typval_T *argvars, typval_T *rettv);
454static void f_virtcol(typval_T *argvars, typval_T *rettv);
455static void f_visualmode(typval_T *argvars, typval_T *rettv);
456static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
457static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
458static void f_win_getid(typval_T *argvars, typval_T *rettv);
459static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
460static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
461static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100462static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200463static void f_winbufnr(typval_T *argvars, typval_T *rettv);
464static void f_wincol(typval_T *argvars, typval_T *rettv);
465static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200466static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200467static void f_winline(typval_T *argvars, typval_T *rettv);
468static void f_winnr(typval_T *argvars, typval_T *rettv);
469static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
470static void f_winrestview(typval_T *argvars, typval_T *rettv);
471static void f_winsaveview(typval_T *argvars, typval_T *rettv);
472static void f_winwidth(typval_T *argvars, typval_T *rettv);
473static void f_writefile(typval_T *argvars, typval_T *rettv);
474static void f_wordcount(typval_T *argvars, typval_T *rettv);
475static void f_xor(typval_T *argvars, typval_T *rettv);
476
477/*
478 * Array with names and number of arguments of all internal functions
479 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
480 */
481static struct fst
482{
483 char *f_name; /* function name */
484 char f_min_argc; /* minimal number of arguments */
485 char f_max_argc; /* maximal number of arguments */
486 void (*f_func)(typval_T *args, typval_T *rvar);
487 /* implementation of function */
488} functions[] =
489{
490#ifdef FEAT_FLOAT
491 {"abs", 1, 1, f_abs},
492 {"acos", 1, 1, f_acos}, /* WJMc */
493#endif
494 {"add", 2, 2, f_add},
495 {"and", 2, 2, f_and},
496 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200497 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498 {"argc", 0, 0, f_argc},
499 {"argidx", 0, 0, f_argidx},
500 {"arglistid", 0, 2, f_arglistid},
501 {"argv", 0, 1, f_argv},
502#ifdef FEAT_FLOAT
503 {"asin", 1, 1, f_asin}, /* WJMc */
504#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100505 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200506 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100507 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508 {"assert_exception", 1, 2, f_assert_exception},
509 {"assert_fails", 1, 2, f_assert_fails},
510 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100511 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200512 {"assert_match", 2, 3, f_assert_match},
513 {"assert_notequal", 2, 3, f_assert_notequal},
514 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100515 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516 {"assert_true", 1, 2, f_assert_true},
517#ifdef FEAT_FLOAT
518 {"atan", 1, 1, f_atan},
519 {"atan2", 2, 2, f_atan2},
520#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100521#ifdef FEAT_BEVAL
522 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100523# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100524 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100525# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100526#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527 {"browse", 4, 4, f_browse},
528 {"browsedir", 2, 2, f_browsedir},
529 {"bufexists", 1, 1, f_bufexists},
530 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
531 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
532 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
533 {"buflisted", 1, 1, f_buflisted},
534 {"bufloaded", 1, 1, f_bufloaded},
535 {"bufname", 1, 1, f_bufname},
536 {"bufnr", 1, 2, f_bufnr},
537 {"bufwinid", 1, 1, f_bufwinid},
538 {"bufwinnr", 1, 1, f_bufwinnr},
539 {"byte2line", 1, 1, f_byte2line},
540 {"byteidx", 2, 2, f_byteidx},
541 {"byteidxcomp", 2, 2, f_byteidxcomp},
542 {"call", 2, 3, f_call},
543#ifdef FEAT_FLOAT
544 {"ceil", 1, 1, f_ceil},
545#endif
546#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100547 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200548 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200549 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
551 {"ch_evalraw", 2, 3, f_ch_evalraw},
552 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
553 {"ch_getjob", 1, 1, f_ch_getjob},
554 {"ch_info", 1, 1, f_ch_info},
555 {"ch_log", 1, 2, f_ch_log},
556 {"ch_logfile", 1, 2, f_ch_logfile},
557 {"ch_open", 1, 2, f_ch_open},
558 {"ch_read", 1, 2, f_ch_read},
559 {"ch_readraw", 1, 2, f_ch_readraw},
560 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
561 {"ch_sendraw", 2, 3, f_ch_sendraw},
562 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200563 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200564#endif
565 {"changenr", 0, 0, f_changenr},
566 {"char2nr", 1, 2, f_char2nr},
567 {"cindent", 1, 1, f_cindent},
568 {"clearmatches", 0, 0, f_clearmatches},
569 {"col", 1, 1, f_col},
570#if defined(FEAT_INS_EXPAND)
571 {"complete", 2, 2, f_complete},
572 {"complete_add", 1, 1, f_complete_add},
573 {"complete_check", 0, 0, f_complete_check},
574#endif
575 {"confirm", 1, 4, f_confirm},
576 {"copy", 1, 1, f_copy},
577#ifdef FEAT_FLOAT
578 {"cos", 1, 1, f_cos},
579 {"cosh", 1, 1, f_cosh},
580#endif
581 {"count", 2, 4, f_count},
582 {"cscope_connection",0,3, f_cscope_connection},
583 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200584#ifdef WIN3264
585 {"debugbreak", 1, 1, f_debugbreak},
586#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200587 {"deepcopy", 1, 2, f_deepcopy},
588 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200589 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200590 {"did_filetype", 0, 0, f_did_filetype},
591 {"diff_filler", 1, 1, f_diff_filler},
592 {"diff_hlID", 2, 2, f_diff_hlID},
593 {"empty", 1, 1, f_empty},
594 {"escape", 2, 2, f_escape},
595 {"eval", 1, 1, f_eval},
596 {"eventhandler", 0, 0, f_eventhandler},
597 {"executable", 1, 1, f_executable},
598 {"execute", 1, 2, f_execute},
599 {"exepath", 1, 1, f_exepath},
600 {"exists", 1, 1, f_exists},
601#ifdef FEAT_FLOAT
602 {"exp", 1, 1, f_exp},
603#endif
604 {"expand", 1, 3, f_expand},
605 {"extend", 2, 3, f_extend},
606 {"feedkeys", 1, 2, f_feedkeys},
607 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
608 {"filereadable", 1, 1, f_filereadable},
609 {"filewritable", 1, 1, f_filewritable},
610 {"filter", 2, 2, f_filter},
611 {"finddir", 1, 3, f_finddir},
612 {"findfile", 1, 3, f_findfile},
613#ifdef FEAT_FLOAT
614 {"float2nr", 1, 1, f_float2nr},
615 {"floor", 1, 1, f_floor},
616 {"fmod", 2, 2, f_fmod},
617#endif
618 {"fnameescape", 1, 1, f_fnameescape},
619 {"fnamemodify", 2, 2, f_fnamemodify},
620 {"foldclosed", 1, 1, f_foldclosed},
621 {"foldclosedend", 1, 1, f_foldclosedend},
622 {"foldlevel", 1, 1, f_foldlevel},
623 {"foldtext", 0, 0, f_foldtext},
624 {"foldtextresult", 1, 1, f_foldtextresult},
625 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200626 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627 {"function", 1, 3, f_function},
628 {"garbagecollect", 0, 1, f_garbagecollect},
629 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200630 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200631 {"getbufline", 2, 3, f_getbufline},
632 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100633 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200634 {"getchar", 0, 1, f_getchar},
635 {"getcharmod", 0, 0, f_getcharmod},
636 {"getcharsearch", 0, 0, f_getcharsearch},
637 {"getcmdline", 0, 0, f_getcmdline},
638 {"getcmdpos", 0, 0, f_getcmdpos},
639 {"getcmdtype", 0, 0, f_getcmdtype},
640 {"getcmdwintype", 0, 0, f_getcmdwintype},
641#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200642 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643#endif
644 {"getcurpos", 0, 0, f_getcurpos},
645 {"getcwd", 0, 2, f_getcwd},
646 {"getfontname", 0, 1, f_getfontname},
647 {"getfperm", 1, 1, f_getfperm},
648 {"getfsize", 1, 1, f_getfsize},
649 {"getftime", 1, 1, f_getftime},
650 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100651 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200653 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200654 {"getmatches", 0, 0, f_getmatches},
655 {"getpid", 0, 0, f_getpid},
656 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200657 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658 {"getreg", 0, 3, f_getreg},
659 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200660 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661 {"gettabvar", 2, 3, f_gettabvar},
662 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200663 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100664 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200665 {"getwinposx", 0, 0, f_getwinposx},
666 {"getwinposy", 0, 0, f_getwinposy},
667 {"getwinvar", 2, 3, f_getwinvar},
668 {"glob", 1, 4, f_glob},
669 {"glob2regpat", 1, 1, f_glob2regpat},
670 {"globpath", 2, 5, f_globpath},
671 {"has", 1, 1, f_has},
672 {"has_key", 2, 2, f_has_key},
673 {"haslocaldir", 0, 2, f_haslocaldir},
674 {"hasmapto", 1, 3, f_hasmapto},
675 {"highlightID", 1, 1, f_hlID}, /* obsolete */
676 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
677 {"histadd", 2, 2, f_histadd},
678 {"histdel", 1, 2, f_histdel},
679 {"histget", 1, 2, f_histget},
680 {"histnr", 1, 1, f_histnr},
681 {"hlID", 1, 1, f_hlID},
682 {"hlexists", 1, 1, f_hlexists},
683 {"hostname", 0, 0, f_hostname},
684 {"iconv", 3, 3, f_iconv},
685 {"indent", 1, 1, f_indent},
686 {"index", 2, 4, f_index},
687 {"input", 1, 3, f_input},
688 {"inputdialog", 1, 3, f_inputdialog},
689 {"inputlist", 1, 1, f_inputlist},
690 {"inputrestore", 0, 0, f_inputrestore},
691 {"inputsave", 0, 0, f_inputsave},
692 {"inputsecret", 1, 2, f_inputsecret},
693 {"insert", 2, 3, f_insert},
694 {"invert", 1, 1, f_invert},
695 {"isdirectory", 1, 1, f_isdirectory},
696 {"islocked", 1, 1, f_islocked},
697#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
698 {"isnan", 1, 1, f_isnan},
699#endif
700 {"items", 1, 1, f_items},
701#ifdef FEAT_JOB_CHANNEL
702 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200703 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200704 {"job_setoptions", 2, 2, f_job_setoptions},
705 {"job_start", 1, 2, f_job_start},
706 {"job_status", 1, 1, f_job_status},
707 {"job_stop", 1, 2, f_job_stop},
708#endif
709 {"join", 1, 2, f_join},
710 {"js_decode", 1, 1, f_js_decode},
711 {"js_encode", 1, 1, f_js_encode},
712 {"json_decode", 1, 1, f_json_decode},
713 {"json_encode", 1, 1, f_json_encode},
714 {"keys", 1, 1, f_keys},
715 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
716 {"len", 1, 1, f_len},
717 {"libcall", 3, 3, f_libcall},
718 {"libcallnr", 3, 3, f_libcallnr},
719 {"line", 1, 1, f_line},
720 {"line2byte", 1, 1, f_line2byte},
721 {"lispindent", 1, 1, f_lispindent},
722 {"localtime", 0, 0, f_localtime},
723#ifdef FEAT_FLOAT
724 {"log", 1, 1, f_log},
725 {"log10", 1, 1, f_log10},
726#endif
727#ifdef FEAT_LUA
728 {"luaeval", 1, 2, f_luaeval},
729#endif
730 {"map", 2, 2, f_map},
731 {"maparg", 1, 4, f_maparg},
732 {"mapcheck", 1, 3, f_mapcheck},
733 {"match", 2, 4, f_match},
734 {"matchadd", 2, 5, f_matchadd},
735 {"matchaddpos", 2, 5, f_matchaddpos},
736 {"matcharg", 1, 1, f_matcharg},
737 {"matchdelete", 1, 1, f_matchdelete},
738 {"matchend", 2, 4, f_matchend},
739 {"matchlist", 2, 4, f_matchlist},
740 {"matchstr", 2, 4, f_matchstr},
741 {"matchstrpos", 2, 4, f_matchstrpos},
742 {"max", 1, 1, f_max},
743 {"min", 1, 1, f_min},
744#ifdef vim_mkdir
745 {"mkdir", 1, 3, f_mkdir},
746#endif
747 {"mode", 0, 1, f_mode},
748#ifdef FEAT_MZSCHEME
749 {"mzeval", 1, 1, f_mzeval},
750#endif
751 {"nextnonblank", 1, 1, f_nextnonblank},
752 {"nr2char", 1, 2, f_nr2char},
753 {"or", 2, 2, f_or},
754 {"pathshorten", 1, 1, f_pathshorten},
755#ifdef FEAT_PERL
756 {"perleval", 1, 1, f_perleval},
757#endif
758#ifdef FEAT_FLOAT
759 {"pow", 2, 2, f_pow},
760#endif
761 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100762 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200763#ifdef FEAT_JOB_CHANNEL
764 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200765 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200766 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
767#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200768 {"pumvisible", 0, 0, f_pumvisible},
769#ifdef FEAT_PYTHON3
770 {"py3eval", 1, 1, f_py3eval},
771#endif
772#ifdef FEAT_PYTHON
773 {"pyeval", 1, 1, f_pyeval},
774#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100775#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
776 {"pyxeval", 1, 1, f_pyxeval},
777#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778 {"range", 1, 3, f_range},
779 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200780 {"reg_executing", 0, 0, f_reg_executing},
781 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200782 {"reltime", 0, 2, f_reltime},
783#ifdef FEAT_FLOAT
784 {"reltimefloat", 1, 1, f_reltimefloat},
785#endif
786 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100787 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"remote_foreground", 1, 1, f_remote_foreground},
789 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100790 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200791 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100792 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793 {"remove", 2, 3, f_remove},
794 {"rename", 2, 2, f_rename},
795 {"repeat", 2, 2, f_repeat},
796 {"resolve", 1, 1, f_resolve},
797 {"reverse", 1, 1, f_reverse},
798#ifdef FEAT_FLOAT
799 {"round", 1, 1, f_round},
800#endif
801 {"screenattr", 2, 2, f_screenattr},
802 {"screenchar", 2, 2, f_screenchar},
803 {"screencol", 0, 0, f_screencol},
804 {"screenrow", 0, 0, f_screenrow},
805 {"search", 1, 4, f_search},
806 {"searchdecl", 1, 3, f_searchdecl},
807 {"searchpair", 3, 7, f_searchpair},
808 {"searchpairpos", 3, 7, f_searchpairpos},
809 {"searchpos", 1, 4, f_searchpos},
810 {"server2client", 2, 2, f_server2client},
811 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200812 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200813 {"setbufvar", 3, 3, f_setbufvar},
814 {"setcharsearch", 1, 1, f_setcharsearch},
815 {"setcmdpos", 1, 1, f_setcmdpos},
816 {"setfperm", 2, 2, f_setfperm},
817 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200818 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819 {"setmatches", 1, 1, f_setmatches},
820 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200821 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822 {"setreg", 2, 3, f_setreg},
823 {"settabvar", 3, 3, f_settabvar},
824 {"settabwinvar", 4, 4, f_settabwinvar},
825 {"setwinvar", 3, 3, f_setwinvar},
826#ifdef FEAT_CRYPT
827 {"sha256", 1, 1, f_sha256},
828#endif
829 {"shellescape", 1, 2, f_shellescape},
830 {"shiftwidth", 0, 0, f_shiftwidth},
831 {"simplify", 1, 1, f_simplify},
832#ifdef FEAT_FLOAT
833 {"sin", 1, 1, f_sin},
834 {"sinh", 1, 1, f_sinh},
835#endif
836 {"sort", 1, 3, f_sort},
837 {"soundfold", 1, 1, f_soundfold},
838 {"spellbadword", 0, 1, f_spellbadword},
839 {"spellsuggest", 1, 3, f_spellsuggest},
840 {"split", 1, 3, f_split},
841#ifdef FEAT_FLOAT
842 {"sqrt", 1, 1, f_sqrt},
843 {"str2float", 1, 1, f_str2float},
844#endif
845 {"str2nr", 1, 2, f_str2nr},
846 {"strcharpart", 2, 3, f_strcharpart},
847 {"strchars", 1, 2, f_strchars},
848 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
849#ifdef HAVE_STRFTIME
850 {"strftime", 1, 2, f_strftime},
851#endif
852 {"strgetchar", 2, 2, f_strgetchar},
853 {"stridx", 2, 3, f_stridx},
854 {"string", 1, 1, f_string},
855 {"strlen", 1, 1, f_strlen},
856 {"strpart", 2, 3, f_strpart},
857 {"strridx", 2, 3, f_strridx},
858 {"strtrans", 1, 1, f_strtrans},
859 {"strwidth", 1, 1, f_strwidth},
860 {"submatch", 1, 2, f_submatch},
861 {"substitute", 4, 4, f_substitute},
862 {"synID", 3, 3, f_synID},
863 {"synIDattr", 2, 3, f_synIDattr},
864 {"synIDtrans", 1, 1, f_synIDtrans},
865 {"synconcealed", 2, 2, f_synconcealed},
866 {"synstack", 2, 2, f_synstack},
867 {"system", 1, 2, f_system},
868 {"systemlist", 1, 2, f_systemlist},
869 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
870 {"tabpagenr", 0, 1, f_tabpagenr},
871 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
872 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100873 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874#ifdef FEAT_FLOAT
875 {"tan", 1, 1, f_tan},
876 {"tanh", 1, 1, f_tanh},
877#endif
878 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200879#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100880 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
881 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100882 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200883 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200884# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
885 {"term_getansicolors", 1, 1, f_term_getansicolors},
886# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200887 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200888 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200889 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200890 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200891 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200892 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200893 {"term_getstatus", 1, 1, f_term_getstatus},
894 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200895 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200896 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200897 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200898 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200899# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
900 {"term_setansicolors", 2, 2, f_term_setansicolors},
901# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100902 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100903 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200904 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200905 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200906 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200907#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200908 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
909 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200910 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200911 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100912 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200913#ifdef FEAT_JOB_CHANNEL
914 {"test_null_channel", 0, 0, f_test_null_channel},
915#endif
916 {"test_null_dict", 0, 0, f_test_null_dict},
917#ifdef FEAT_JOB_CHANNEL
918 {"test_null_job", 0, 0, f_test_null_job},
919#endif
920 {"test_null_list", 0, 0, f_test_null_list},
921 {"test_null_partial", 0, 0, f_test_null_partial},
922 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100923 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200924 {"test_settime", 1, 1, f_test_settime},
925#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200926 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200927 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928 {"timer_start", 2, 3, f_timer_start},
929 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200930 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200931#endif
932 {"tolower", 1, 1, f_tolower},
933 {"toupper", 1, 1, f_toupper},
934 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100935 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200936#ifdef FEAT_FLOAT
937 {"trunc", 1, 1, f_trunc},
938#endif
939 {"type", 1, 1, f_type},
940 {"undofile", 1, 1, f_undofile},
941 {"undotree", 0, 0, f_undotree},
942 {"uniq", 1, 3, f_uniq},
943 {"values", 1, 1, f_values},
944 {"virtcol", 1, 1, f_virtcol},
945 {"visualmode", 0, 1, f_visualmode},
946 {"wildmenumode", 0, 0, f_wildmenumode},
947 {"win_findbuf", 1, 1, f_win_findbuf},
948 {"win_getid", 0, 2, f_win_getid},
949 {"win_gotoid", 1, 1, f_win_gotoid},
950 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
951 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100952 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200953 {"winbufnr", 1, 1, f_winbufnr},
954 {"wincol", 0, 0, f_wincol},
955 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200956 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200957 {"winline", 0, 0, f_winline},
958 {"winnr", 0, 1, f_winnr},
959 {"winrestcmd", 0, 0, f_winrestcmd},
960 {"winrestview", 1, 1, f_winrestview},
961 {"winsaveview", 0, 0, f_winsaveview},
962 {"winwidth", 1, 1, f_winwidth},
963 {"wordcount", 0, 0, f_wordcount},
964 {"writefile", 2, 3, f_writefile},
965 {"xor", 2, 2, f_xor},
966};
967
968#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
969
970/*
971 * Function given to ExpandGeneric() to obtain the list of internal
972 * or user defined function names.
973 */
974 char_u *
975get_function_name(expand_T *xp, int idx)
976{
977 static int intidx = -1;
978 char_u *name;
979
980 if (idx == 0)
981 intidx = -1;
982 if (intidx < 0)
983 {
984 name = get_user_func_name(xp, idx);
985 if (name != NULL)
986 return name;
987 }
988 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
989 {
990 STRCPY(IObuff, functions[intidx].f_name);
991 STRCAT(IObuff, "(");
992 if (functions[intidx].f_max_argc == 0)
993 STRCAT(IObuff, ")");
994 return IObuff;
995 }
996
997 return NULL;
998}
999
1000/*
1001 * Function given to ExpandGeneric() to obtain the list of internal or
1002 * user defined variable or function names.
1003 */
1004 char_u *
1005get_expr_name(expand_T *xp, int idx)
1006{
1007 static int intidx = -1;
1008 char_u *name;
1009
1010 if (idx == 0)
1011 intidx = -1;
1012 if (intidx < 0)
1013 {
1014 name = get_function_name(xp, idx);
1015 if (name != NULL)
1016 return name;
1017 }
1018 return get_user_var_name(xp, ++intidx);
1019}
1020
1021#endif /* FEAT_CMDL_COMPL */
1022
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001023/*
1024 * Find internal function in table above.
1025 * Return index, or -1 if not found
1026 */
1027 int
1028find_internal_func(
1029 char_u *name) /* name of the function */
1030{
1031 int first = 0;
1032 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1033 int cmp;
1034 int x;
1035
1036 /*
1037 * Find the function name in the table. Binary search.
1038 */
1039 while (first <= last)
1040 {
1041 x = first + ((unsigned)(last - first) >> 1);
1042 cmp = STRCMP(name, functions[x].f_name);
1043 if (cmp < 0)
1044 last = x - 1;
1045 else if (cmp > 0)
1046 first = x + 1;
1047 else
1048 return x;
1049 }
1050 return -1;
1051}
1052
1053 int
1054call_internal_func(
1055 char_u *name,
1056 int argcount,
1057 typval_T *argvars,
1058 typval_T *rettv)
1059{
1060 int i;
1061
1062 i = find_internal_func(name);
1063 if (i < 0)
1064 return ERROR_UNKNOWN;
1065 if (argcount < functions[i].f_min_argc)
1066 return ERROR_TOOFEW;
1067 if (argcount > functions[i].f_max_argc)
1068 return ERROR_TOOMANY;
1069 argvars[argcount].v_type = VAR_UNKNOWN;
1070 functions[i].f_func(argvars, rettv);
1071 return ERROR_NONE;
1072}
1073
1074/*
1075 * Return TRUE for a non-zero Number and a non-empty String.
1076 */
1077 static int
1078non_zero_arg(typval_T *argvars)
1079{
1080 return ((argvars[0].v_type == VAR_NUMBER
1081 && argvars[0].vval.v_number != 0)
1082 || (argvars[0].v_type == VAR_SPECIAL
1083 && argvars[0].vval.v_number == VVAL_TRUE)
1084 || (argvars[0].v_type == VAR_STRING
1085 && argvars[0].vval.v_string != NULL
1086 && *argvars[0].vval.v_string != NUL));
1087}
1088
1089/*
1090 * Get the lnum from the first argument.
1091 * Also accepts ".", "$", etc., but that only works for the current buffer.
1092 * Returns -1 on error.
1093 */
1094 static linenr_T
1095get_tv_lnum(typval_T *argvars)
1096{
1097 typval_T rettv;
1098 linenr_T lnum;
1099
1100 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1101 if (lnum == 0) /* no valid number, try using line() */
1102 {
1103 rettv.v_type = VAR_NUMBER;
1104 f_line(argvars, &rettv);
1105 lnum = (linenr_T)rettv.vval.v_number;
1106 clear_tv(&rettv);
1107 }
1108 return lnum;
1109}
1110
1111#ifdef FEAT_FLOAT
1112static int get_float_arg(typval_T *argvars, float_T *f);
1113
1114/*
1115 * Get the float value of "argvars[0]" into "f".
1116 * Returns FAIL when the argument is not a Number or Float.
1117 */
1118 static int
1119get_float_arg(typval_T *argvars, float_T *f)
1120{
1121 if (argvars[0].v_type == VAR_FLOAT)
1122 {
1123 *f = argvars[0].vval.v_float;
1124 return OK;
1125 }
1126 if (argvars[0].v_type == VAR_NUMBER)
1127 {
1128 *f = (float_T)argvars[0].vval.v_number;
1129 return OK;
1130 }
1131 EMSG(_("E808: Number or Float required"));
1132 return FAIL;
1133}
1134
1135/*
1136 * "abs(expr)" function
1137 */
1138 static void
1139f_abs(typval_T *argvars, typval_T *rettv)
1140{
1141 if (argvars[0].v_type == VAR_FLOAT)
1142 {
1143 rettv->v_type = VAR_FLOAT;
1144 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1145 }
1146 else
1147 {
1148 varnumber_T n;
1149 int error = FALSE;
1150
1151 n = get_tv_number_chk(&argvars[0], &error);
1152 if (error)
1153 rettv->vval.v_number = -1;
1154 else if (n > 0)
1155 rettv->vval.v_number = n;
1156 else
1157 rettv->vval.v_number = -n;
1158 }
1159}
1160
1161/*
1162 * "acos()" function
1163 */
1164 static void
1165f_acos(typval_T *argvars, typval_T *rettv)
1166{
1167 float_T f = 0.0;
1168
1169 rettv->v_type = VAR_FLOAT;
1170 if (get_float_arg(argvars, &f) == OK)
1171 rettv->vval.v_float = acos(f);
1172 else
1173 rettv->vval.v_float = 0.0;
1174}
1175#endif
1176
1177/*
1178 * "add(list, item)" function
1179 */
1180 static void
1181f_add(typval_T *argvars, typval_T *rettv)
1182{
1183 list_T *l;
1184
1185 rettv->vval.v_number = 1; /* Default: Failed */
1186 if (argvars[0].v_type == VAR_LIST)
1187 {
1188 if ((l = argvars[0].vval.v_list) != NULL
1189 && !tv_check_lock(l->lv_lock,
1190 (char_u *)N_("add() argument"), TRUE)
1191 && list_append_tv(l, &argvars[1]) == OK)
1192 copy_tv(&argvars[0], rettv);
1193 }
1194 else
1195 EMSG(_(e_listreq));
1196}
1197
1198/*
1199 * "and(expr, expr)" function
1200 */
1201 static void
1202f_and(typval_T *argvars, typval_T *rettv)
1203{
1204 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1205 & get_tv_number_chk(&argvars[1], NULL);
1206}
1207
1208/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001209 * Get the lnum from the first argument.
1210 * Also accepts "$", then "buf" is used.
1211 * Returns 0 on error.
1212 */
1213 static linenr_T
1214get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
1215{
1216 if (argvars[0].v_type == VAR_STRING
1217 && argvars[0].vval.v_string != NULL
1218 && argvars[0].vval.v_string[0] == '$'
1219 && buf != NULL)
1220 return buf->b_ml.ml_line_count;
1221 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1222}
1223
1224/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001225 * If there is a window for "curbuf", make it the current window.
1226 */
1227 static void
1228find_win_for_curbuf(void)
1229{
1230 wininfo_T *wip;
1231
1232 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1233 {
1234 if (wip->wi_win != NULL)
1235 {
1236 curwin = wip->wi_win;
1237 break;
1238 }
1239 }
1240}
1241
1242/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001243 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001244 */
1245 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001246set_buffer_lines(
1247 buf_T *buf,
1248 linenr_T lnum_arg,
1249 int append,
1250 typval_T *lines,
1251 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252{
Bram Moolenaarca851592018-06-06 21:04:07 +02001253 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1254 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001255 list_T *l = NULL;
1256 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001257 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001258 linenr_T append_lnum;
1259 buf_T *curbuf_save = NULL;
1260 win_T *curwin_save = NULL;
1261 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001262
Bram Moolenaarca851592018-06-06 21:04:07 +02001263 /* When using the current buffer ml_mfp will be set if needed. Useful when
1264 * setline() is used on startup. For other buffers the buffer must be
1265 * loaded. */
1266 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001267 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001268 rettv->vval.v_number = 1; /* FAIL */
1269 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001270 }
1271
Bram Moolenaarca851592018-06-06 21:04:07 +02001272 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001273 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001274 curbuf_save = curbuf;
1275 curwin_save = curwin;
1276 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001277 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001278 }
1279
1280 if (append)
1281 // appendbufline() uses the line number below which we insert
1282 append_lnum = lnum - 1;
1283 else
1284 // setbufline() uses the line number above which we insert, we only
1285 // append if it's below the last line
1286 append_lnum = curbuf->b_ml.ml_line_count;
1287
1288 if (lines->v_type == VAR_LIST)
1289 {
1290 l = lines->vval.v_list;
1291 li = l->lv_first;
1292 }
1293 else
1294 line = get_tv_string_chk(lines);
1295
1296 /* default result is zero == OK */
1297 for (;;)
1298 {
1299 if (l != NULL)
1300 {
1301 /* list argument, get next string */
1302 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001303 break;
Bram Moolenaarca851592018-06-06 21:04:07 +02001304 line = get_tv_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001305 li = li->li_next;
1306 }
1307
Bram Moolenaarca851592018-06-06 21:04:07 +02001308 rettv->vval.v_number = 1; /* FAIL */
1309 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1310 break;
1311
1312 /* When coming here from Insert mode, sync undo, so that this can be
1313 * undone separately from what was previously inserted. */
1314 if (u_sync_once == 2)
1315 {
1316 u_sync_once = 1; /* notify that u_sync() was called */
1317 u_sync(TRUE);
1318 }
1319
1320 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1321 {
1322 /* existing line, replace it */
1323 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1324 {
1325 changed_bytes(lnum, 0);
1326 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1327 check_cursor_col();
1328 rettv->vval.v_number = 0; /* OK */
1329 }
1330 }
1331 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1332 {
1333 /* append the line */
1334 ++added;
1335 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1336 rettv->vval.v_number = 0; /* OK */
1337 }
1338
1339 if (l == NULL) /* only one string argument */
1340 break;
1341 ++lnum;
1342 }
1343
1344 if (added > 0)
1345 {
1346 win_T *wp;
1347 tabpage_T *tp;
1348
1349 appended_lines_mark(append_lnum, added);
1350 FOR_ALL_TAB_WINDOWS(tp, wp)
1351 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1352 wp->w_cursor.lnum += added;
1353 check_cursor_col();
1354
Bram Moolenaarf2732452018-06-03 14:47:35 +02001355#ifdef FEAT_JOB_CHANNEL
1356 if (bt_prompt(curbuf) && (State & INSERT))
1357 // show the line with the prompt
1358 update_topline();
1359#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001361
1362 if (!is_curbuf)
1363 {
1364 curbuf = curbuf_save;
1365 curwin = curwin_save;
1366 }
1367}
1368
1369/*
1370 * "append(lnum, string/list)" function
1371 */
1372 static void
1373f_append(typval_T *argvars, typval_T *rettv)
1374{
1375 linenr_T lnum = get_tv_lnum(&argvars[0]);
1376
1377 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1378}
1379
1380/*
1381 * "appendbufline(buf, lnum, string/list)" function
1382 */
1383 static void
1384f_appendbufline(typval_T *argvars, typval_T *rettv)
1385{
1386 linenr_T lnum;
1387 buf_T *buf;
1388
1389 buf = get_buf_tv(&argvars[0], FALSE);
1390 if (buf == NULL)
1391 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001392 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001393 {
1394 lnum = get_tv_lnum_buf(&argvars[1], buf);
1395 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1396 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001397}
1398
1399/*
1400 * "argc()" function
1401 */
1402 static void
1403f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1404{
1405 rettv->vval.v_number = ARGCOUNT;
1406}
1407
1408/*
1409 * "argidx()" function
1410 */
1411 static void
1412f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1413{
1414 rettv->vval.v_number = curwin->w_arg_idx;
1415}
1416
1417/*
1418 * "arglistid()" function
1419 */
1420 static void
1421f_arglistid(typval_T *argvars, typval_T *rettv)
1422{
1423 win_T *wp;
1424
1425 rettv->vval.v_number = -1;
1426 wp = find_tabwin(&argvars[0], &argvars[1]);
1427 if (wp != NULL)
1428 rettv->vval.v_number = wp->w_alist->id;
1429}
1430
1431/*
1432 * "argv(nr)" function
1433 */
1434 static void
1435f_argv(typval_T *argvars, typval_T *rettv)
1436{
1437 int idx;
1438
1439 if (argvars[0].v_type != VAR_UNKNOWN)
1440 {
1441 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1442 if (idx >= 0 && idx < ARGCOUNT)
1443 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1444 else
1445 rettv->vval.v_string = NULL;
1446 rettv->v_type = VAR_STRING;
1447 }
1448 else if (rettv_list_alloc(rettv) == OK)
1449 for (idx = 0; idx < ARGCOUNT; ++idx)
1450 list_append_string(rettv->vval.v_list,
1451 alist_name(&ARGLIST[idx]), -1);
1452}
1453
1454/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001455 * "assert_beeps(cmd [, error])" function
1456 */
1457 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001458f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001459{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001460 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001461}
1462
1463/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001464 * "assert_equal(expected, actual[, msg])" function
1465 */
1466 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001467f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001468{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001469 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001470}
1471
1472/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001473 * "assert_equalfile(fname-one, fname-two)" function
1474 */
1475 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001476f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001477{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001478 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001479}
1480
1481/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001482 * "assert_notequal(expected, actual[, msg])" function
1483 */
1484 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001485f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001487 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488}
1489
1490/*
1491 * "assert_exception(string[, msg])" function
1492 */
1493 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001494f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001496 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497}
1498
1499/*
1500 * "assert_fails(cmd [, error])" function
1501 */
1502 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001503f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001504{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001505 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506}
1507
1508/*
1509 * "assert_false(actual[, msg])" function
1510 */
1511 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001512f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001513{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001514 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001515}
1516
1517/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001518 * "assert_inrange(lower, upper[, msg])" function
1519 */
1520 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001521f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001522{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001523 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001524}
1525
1526/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001527 * "assert_match(pattern, actual[, msg])" function
1528 */
1529 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001530f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001531{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001532 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533}
1534
1535/*
1536 * "assert_notmatch(pattern, actual[, msg])" function
1537 */
1538 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001539f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001540{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001541 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542}
1543
1544/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001545 * "assert_report(msg)" function
1546 */
1547 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001548f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001549{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001550 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001551}
1552
1553/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001554 * "assert_true(actual[, msg])" function
1555 */
1556 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001557f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001558{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001559 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001560}
1561
1562#ifdef FEAT_FLOAT
1563/*
1564 * "asin()" function
1565 */
1566 static void
1567f_asin(typval_T *argvars, typval_T *rettv)
1568{
1569 float_T f = 0.0;
1570
1571 rettv->v_type = VAR_FLOAT;
1572 if (get_float_arg(argvars, &f) == OK)
1573 rettv->vval.v_float = asin(f);
1574 else
1575 rettv->vval.v_float = 0.0;
1576}
1577
1578/*
1579 * "atan()" function
1580 */
1581 static void
1582f_atan(typval_T *argvars, typval_T *rettv)
1583{
1584 float_T f = 0.0;
1585
1586 rettv->v_type = VAR_FLOAT;
1587 if (get_float_arg(argvars, &f) == OK)
1588 rettv->vval.v_float = atan(f);
1589 else
1590 rettv->vval.v_float = 0.0;
1591}
1592
1593/*
1594 * "atan2()" function
1595 */
1596 static void
1597f_atan2(typval_T *argvars, typval_T *rettv)
1598{
1599 float_T fx = 0.0, fy = 0.0;
1600
1601 rettv->v_type = VAR_FLOAT;
1602 if (get_float_arg(argvars, &fx) == OK
1603 && get_float_arg(&argvars[1], &fy) == OK)
1604 rettv->vval.v_float = atan2(fx, fy);
1605 else
1606 rettv->vval.v_float = 0.0;
1607}
1608#endif
1609
1610/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001611 * "balloon_show()" function
1612 */
1613#ifdef FEAT_BEVAL
1614 static void
1615f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1616{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001617 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001618 {
1619 if (argvars[0].v_type == VAR_LIST
1620# ifdef FEAT_GUI
1621 && !gui.in_use
1622# endif
1623 )
1624 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1625 else
1626 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1627 }
1628}
1629
Bram Moolenaar669a8282017-11-19 20:13:05 +01001630# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001631 static void
1632f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1633{
1634 if (rettv_list_alloc(rettv) == OK)
1635 {
1636 char_u *msg = get_tv_string_chk(&argvars[0]);
1637
1638 if (msg != NULL)
1639 {
1640 pumitem_T *array;
1641 int size = split_message(msg, &array);
1642 int i;
1643
1644 /* Skip the first and last item, they are always empty. */
1645 for (i = 1; i < size - 1; ++i)
1646 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001647 while (size > 0)
1648 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001649 vim_free(array);
1650 }
1651 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001652}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001653# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001654#endif
1655
1656/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001657 * "browse(save, title, initdir, default)" function
1658 */
1659 static void
1660f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1661{
1662#ifdef FEAT_BROWSE
1663 int save;
1664 char_u *title;
1665 char_u *initdir;
1666 char_u *defname;
1667 char_u buf[NUMBUFLEN];
1668 char_u buf2[NUMBUFLEN];
1669 int error = FALSE;
1670
1671 save = (int)get_tv_number_chk(&argvars[0], &error);
1672 title = get_tv_string_chk(&argvars[1]);
1673 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1674 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1675
1676 if (error || title == NULL || initdir == NULL || defname == NULL)
1677 rettv->vval.v_string = NULL;
1678 else
1679 rettv->vval.v_string =
1680 do_browse(save ? BROWSE_SAVE : 0,
1681 title, defname, NULL, initdir, NULL, curbuf);
1682#else
1683 rettv->vval.v_string = NULL;
1684#endif
1685 rettv->v_type = VAR_STRING;
1686}
1687
1688/*
1689 * "browsedir(title, initdir)" function
1690 */
1691 static void
1692f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1693{
1694#ifdef FEAT_BROWSE
1695 char_u *title;
1696 char_u *initdir;
1697 char_u buf[NUMBUFLEN];
1698
1699 title = get_tv_string_chk(&argvars[0]);
1700 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1701
1702 if (title == NULL || initdir == NULL)
1703 rettv->vval.v_string = NULL;
1704 else
1705 rettv->vval.v_string = do_browse(BROWSE_DIR,
1706 title, NULL, NULL, initdir, NULL, curbuf);
1707#else
1708 rettv->vval.v_string = NULL;
1709#endif
1710 rettv->v_type = VAR_STRING;
1711}
1712
1713static buf_T *find_buffer(typval_T *avar);
1714
1715/*
1716 * Find a buffer by number or exact name.
1717 */
1718 static buf_T *
1719find_buffer(typval_T *avar)
1720{
1721 buf_T *buf = NULL;
1722
1723 if (avar->v_type == VAR_NUMBER)
1724 buf = buflist_findnr((int)avar->vval.v_number);
1725 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1726 {
1727 buf = buflist_findname_exp(avar->vval.v_string);
1728 if (buf == NULL)
1729 {
1730 /* No full path name match, try a match with a URL or a "nofile"
1731 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001732 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001733 if (buf->b_fname != NULL
1734 && (path_with_url(buf->b_fname)
1735#ifdef FEAT_QUICKFIX
1736 || bt_nofile(buf)
1737#endif
1738 )
1739 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1740 break;
1741 }
1742 }
1743 return buf;
1744}
1745
1746/*
1747 * "bufexists(expr)" function
1748 */
1749 static void
1750f_bufexists(typval_T *argvars, typval_T *rettv)
1751{
1752 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1753}
1754
1755/*
1756 * "buflisted(expr)" function
1757 */
1758 static void
1759f_buflisted(typval_T *argvars, typval_T *rettv)
1760{
1761 buf_T *buf;
1762
1763 buf = find_buffer(&argvars[0]);
1764 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1765}
1766
1767/*
1768 * "bufloaded(expr)" function
1769 */
1770 static void
1771f_bufloaded(typval_T *argvars, typval_T *rettv)
1772{
1773 buf_T *buf;
1774
1775 buf = find_buffer(&argvars[0]);
1776 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1777}
1778
1779 buf_T *
1780buflist_find_by_name(char_u *name, int curtab_only)
1781{
1782 int save_magic;
1783 char_u *save_cpo;
1784 buf_T *buf;
1785
1786 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1787 save_magic = p_magic;
1788 p_magic = TRUE;
1789 save_cpo = p_cpo;
1790 p_cpo = (char_u *)"";
1791
1792 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1793 TRUE, FALSE, curtab_only));
1794
1795 p_magic = save_magic;
1796 p_cpo = save_cpo;
1797 return buf;
1798}
1799
1800/*
1801 * Get buffer by number or pattern.
1802 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001803 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001804get_buf_tv(typval_T *tv, int curtab_only)
1805{
1806 char_u *name = tv->vval.v_string;
1807 buf_T *buf;
1808
1809 if (tv->v_type == VAR_NUMBER)
1810 return buflist_findnr((int)tv->vval.v_number);
1811 if (tv->v_type != VAR_STRING)
1812 return NULL;
1813 if (name == NULL || *name == NUL)
1814 return curbuf;
1815 if (name[0] == '$' && name[1] == NUL)
1816 return lastbuf;
1817
1818 buf = buflist_find_by_name(name, curtab_only);
1819
1820 /* If not found, try expanding the name, like done for bufexists(). */
1821 if (buf == NULL)
1822 buf = find_buffer(tv);
1823
1824 return buf;
1825}
1826
1827/*
1828 * "bufname(expr)" function
1829 */
1830 static void
1831f_bufname(typval_T *argvars, typval_T *rettv)
1832{
1833 buf_T *buf;
1834
1835 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1836 ++emsg_off;
1837 buf = get_buf_tv(&argvars[0], FALSE);
1838 rettv->v_type = VAR_STRING;
1839 if (buf != NULL && buf->b_fname != NULL)
1840 rettv->vval.v_string = vim_strsave(buf->b_fname);
1841 else
1842 rettv->vval.v_string = NULL;
1843 --emsg_off;
1844}
1845
1846/*
1847 * "bufnr(expr)" function
1848 */
1849 static void
1850f_bufnr(typval_T *argvars, typval_T *rettv)
1851{
1852 buf_T *buf;
1853 int error = FALSE;
1854 char_u *name;
1855
1856 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1857 ++emsg_off;
1858 buf = get_buf_tv(&argvars[0], FALSE);
1859 --emsg_off;
1860
1861 /* If the buffer isn't found and the second argument is not zero create a
1862 * new buffer. */
1863 if (buf == NULL
1864 && argvars[1].v_type != VAR_UNKNOWN
1865 && get_tv_number_chk(&argvars[1], &error) != 0
1866 && !error
1867 && (name = get_tv_string_chk(&argvars[0])) != NULL
1868 && !error)
1869 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1870
1871 if (buf != NULL)
1872 rettv->vval.v_number = buf->b_fnum;
1873 else
1874 rettv->vval.v_number = -1;
1875}
1876
1877 static void
1878buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1879{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001880 win_T *wp;
1881 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001882 buf_T *buf;
1883
1884 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1885 ++emsg_off;
1886 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001887 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001888 {
1889 ++winnr;
1890 if (wp->w_buffer == buf)
1891 break;
1892 }
1893 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001894 --emsg_off;
1895}
1896
1897/*
1898 * "bufwinid(nr)" function
1899 */
1900 static void
1901f_bufwinid(typval_T *argvars, typval_T *rettv)
1902{
1903 buf_win_common(argvars, rettv, FALSE);
1904}
1905
1906/*
1907 * "bufwinnr(nr)" function
1908 */
1909 static void
1910f_bufwinnr(typval_T *argvars, typval_T *rettv)
1911{
1912 buf_win_common(argvars, rettv, TRUE);
1913}
1914
1915/*
1916 * "byte2line(byte)" function
1917 */
1918 static void
1919f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1920{
1921#ifndef FEAT_BYTEOFF
1922 rettv->vval.v_number = -1;
1923#else
1924 long boff = 0;
1925
1926 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1927 if (boff < 0)
1928 rettv->vval.v_number = -1;
1929 else
1930 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1931 (linenr_T)0, &boff);
1932#endif
1933}
1934
1935 static void
1936byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1937{
1938#ifdef FEAT_MBYTE
1939 char_u *t;
1940#endif
1941 char_u *str;
1942 varnumber_T idx;
1943
1944 str = get_tv_string_chk(&argvars[0]);
1945 idx = get_tv_number_chk(&argvars[1], NULL);
1946 rettv->vval.v_number = -1;
1947 if (str == NULL || idx < 0)
1948 return;
1949
1950#ifdef FEAT_MBYTE
1951 t = str;
1952 for ( ; idx > 0; idx--)
1953 {
1954 if (*t == NUL) /* EOL reached */
1955 return;
1956 if (enc_utf8 && comp)
1957 t += utf_ptr2len(t);
1958 else
1959 t += (*mb_ptr2len)(t);
1960 }
1961 rettv->vval.v_number = (varnumber_T)(t - str);
1962#else
1963 if ((size_t)idx <= STRLEN(str))
1964 rettv->vval.v_number = idx;
1965#endif
1966}
1967
1968/*
1969 * "byteidx()" function
1970 */
1971 static void
1972f_byteidx(typval_T *argvars, typval_T *rettv)
1973{
1974 byteidx(argvars, rettv, FALSE);
1975}
1976
1977/*
1978 * "byteidxcomp()" function
1979 */
1980 static void
1981f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1982{
1983 byteidx(argvars, rettv, TRUE);
1984}
1985
1986/*
1987 * "call(func, arglist [, dict])" function
1988 */
1989 static void
1990f_call(typval_T *argvars, typval_T *rettv)
1991{
1992 char_u *func;
1993 partial_T *partial = NULL;
1994 dict_T *selfdict = NULL;
1995
1996 if (argvars[1].v_type != VAR_LIST)
1997 {
1998 EMSG(_(e_listreq));
1999 return;
2000 }
2001 if (argvars[1].vval.v_list == NULL)
2002 return;
2003
2004 if (argvars[0].v_type == VAR_FUNC)
2005 func = argvars[0].vval.v_string;
2006 else if (argvars[0].v_type == VAR_PARTIAL)
2007 {
2008 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002009 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 }
2011 else
2012 func = get_tv_string(&argvars[0]);
2013 if (*func == NUL)
2014 return; /* type error or empty name */
2015
2016 if (argvars[2].v_type != VAR_UNKNOWN)
2017 {
2018 if (argvars[2].v_type != VAR_DICT)
2019 {
2020 EMSG(_(e_dictreq));
2021 return;
2022 }
2023 selfdict = argvars[2].vval.v_dict;
2024 }
2025
2026 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2027}
2028
2029#ifdef FEAT_FLOAT
2030/*
2031 * "ceil({float})" function
2032 */
2033 static void
2034f_ceil(typval_T *argvars, typval_T *rettv)
2035{
2036 float_T f = 0.0;
2037
2038 rettv->v_type = VAR_FLOAT;
2039 if (get_float_arg(argvars, &f) == OK)
2040 rettv->vval.v_float = ceil(f);
2041 else
2042 rettv->vval.v_float = 0.0;
2043}
2044#endif
2045
2046#ifdef FEAT_JOB_CHANNEL
2047/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002048 * "ch_canread()" function
2049 */
2050 static void
2051f_ch_canread(typval_T *argvars, typval_T *rettv)
2052{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002053 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002054
2055 rettv->vval.v_number = 0;
2056 if (channel != NULL)
2057 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2058 || channel_has_readahead(channel, PART_OUT)
2059 || channel_has_readahead(channel, PART_ERR);
2060}
2061
2062/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 * "ch_close()" function
2064 */
2065 static void
2066f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2067{
2068 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2069
2070 if (channel != NULL)
2071 {
2072 channel_close(channel, FALSE);
2073 channel_clear(channel);
2074 }
2075}
2076
2077/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002078 * "ch_close()" function
2079 */
2080 static void
2081f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2082{
2083 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2084
2085 if (channel != NULL)
2086 channel_close_in(channel);
2087}
2088
2089/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002090 * "ch_getbufnr()" function
2091 */
2092 static void
2093f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2094{
2095 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2096
2097 rettv->vval.v_number = -1;
2098 if (channel != NULL)
2099 {
2100 char_u *what = get_tv_string(&argvars[1]);
2101 int part;
2102
2103 if (STRCMP(what, "err") == 0)
2104 part = PART_ERR;
2105 else if (STRCMP(what, "out") == 0)
2106 part = PART_OUT;
2107 else if (STRCMP(what, "in") == 0)
2108 part = PART_IN;
2109 else
2110 part = PART_SOCK;
2111 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2112 rettv->vval.v_number =
2113 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2114 }
2115}
2116
2117/*
2118 * "ch_getjob()" function
2119 */
2120 static void
2121f_ch_getjob(typval_T *argvars, typval_T *rettv)
2122{
2123 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2124
2125 if (channel != NULL)
2126 {
2127 rettv->v_type = VAR_JOB;
2128 rettv->vval.v_job = channel->ch_job;
2129 if (channel->ch_job != NULL)
2130 ++channel->ch_job->jv_refcount;
2131 }
2132}
2133
2134/*
2135 * "ch_info()" function
2136 */
2137 static void
2138f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2139{
2140 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2141
2142 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2143 channel_info(channel, rettv->vval.v_dict);
2144}
2145
2146/*
2147 * "ch_log()" function
2148 */
2149 static void
2150f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2151{
2152 char_u *msg = get_tv_string(&argvars[0]);
2153 channel_T *channel = NULL;
2154
2155 if (argvars[1].v_type != VAR_UNKNOWN)
2156 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2157
Bram Moolenaard5359b22018-04-05 22:44:39 +02002158 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002159}
2160
2161/*
2162 * "ch_logfile()" function
2163 */
2164 static void
2165f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2166{
2167 char_u *fname;
2168 char_u *opt = (char_u *)"";
2169 char_u buf[NUMBUFLEN];
2170
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002171 /* Don't open a file in restricted mode. */
2172 if (check_restricted() || check_secure())
2173 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002174 fname = get_tv_string(&argvars[0]);
2175 if (argvars[1].v_type == VAR_STRING)
2176 opt = get_tv_string_buf(&argvars[1], buf);
2177 ch_logfile(fname, opt);
2178}
2179
2180/*
2181 * "ch_open()" function
2182 */
2183 static void
2184f_ch_open(typval_T *argvars, typval_T *rettv)
2185{
2186 rettv->v_type = VAR_CHANNEL;
2187 if (check_restricted() || check_secure())
2188 return;
2189 rettv->vval.v_channel = channel_open_func(argvars);
2190}
2191
2192/*
2193 * "ch_read()" function
2194 */
2195 static void
2196f_ch_read(typval_T *argvars, typval_T *rettv)
2197{
2198 common_channel_read(argvars, rettv, FALSE);
2199}
2200
2201/*
2202 * "ch_readraw()" function
2203 */
2204 static void
2205f_ch_readraw(typval_T *argvars, typval_T *rettv)
2206{
2207 common_channel_read(argvars, rettv, TRUE);
2208}
2209
2210/*
2211 * "ch_evalexpr()" function
2212 */
2213 static void
2214f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2215{
2216 ch_expr_common(argvars, rettv, TRUE);
2217}
2218
2219/*
2220 * "ch_sendexpr()" function
2221 */
2222 static void
2223f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2224{
2225 ch_expr_common(argvars, rettv, FALSE);
2226}
2227
2228/*
2229 * "ch_evalraw()" function
2230 */
2231 static void
2232f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2233{
2234 ch_raw_common(argvars, rettv, TRUE);
2235}
2236
2237/*
2238 * "ch_sendraw()" function
2239 */
2240 static void
2241f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2242{
2243 ch_raw_common(argvars, rettv, FALSE);
2244}
2245
2246/*
2247 * "ch_setoptions()" function
2248 */
2249 static void
2250f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2251{
2252 channel_T *channel;
2253 jobopt_T opt;
2254
2255 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2256 if (channel == NULL)
2257 return;
2258 clear_job_options(&opt);
2259 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002260 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002261 channel_set_options(channel, &opt);
2262 free_job_options(&opt);
2263}
2264
2265/*
2266 * "ch_status()" function
2267 */
2268 static void
2269f_ch_status(typval_T *argvars, typval_T *rettv)
2270{
2271 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002272 jobopt_T opt;
2273 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002274
2275 /* return an empty string by default */
2276 rettv->v_type = VAR_STRING;
2277 rettv->vval.v_string = NULL;
2278
2279 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002280
2281 if (argvars[1].v_type != VAR_UNKNOWN)
2282 {
2283 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002284 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002285 && (opt.jo_set & JO_PART))
2286 part = opt.jo_part;
2287 }
2288
2289 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290}
2291#endif
2292
2293/*
2294 * "changenr()" function
2295 */
2296 static void
2297f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2298{
2299 rettv->vval.v_number = curbuf->b_u_seq_cur;
2300}
2301
2302/*
2303 * "char2nr(string)" function
2304 */
2305 static void
2306f_char2nr(typval_T *argvars, typval_T *rettv)
2307{
2308#ifdef FEAT_MBYTE
2309 if (has_mbyte)
2310 {
2311 int utf8 = 0;
2312
2313 if (argvars[1].v_type != VAR_UNKNOWN)
2314 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2315
2316 if (utf8)
2317 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2318 else
2319 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2320 }
2321 else
2322#endif
2323 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2324}
2325
2326/*
2327 * "cindent(lnum)" function
2328 */
2329 static void
2330f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2331{
2332#ifdef FEAT_CINDENT
2333 pos_T pos;
2334 linenr_T lnum;
2335
2336 pos = curwin->w_cursor;
2337 lnum = get_tv_lnum(argvars);
2338 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2339 {
2340 curwin->w_cursor.lnum = lnum;
2341 rettv->vval.v_number = get_c_indent();
2342 curwin->w_cursor = pos;
2343 }
2344 else
2345#endif
2346 rettv->vval.v_number = -1;
2347}
2348
2349/*
2350 * "clearmatches()" function
2351 */
2352 static void
2353f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2354{
2355#ifdef FEAT_SEARCH_EXTRA
2356 clear_matches(curwin);
2357#endif
2358}
2359
2360/*
2361 * "col(string)" function
2362 */
2363 static void
2364f_col(typval_T *argvars, typval_T *rettv)
2365{
2366 colnr_T col = 0;
2367 pos_T *fp;
2368 int fnum = curbuf->b_fnum;
2369
2370 fp = var2fpos(&argvars[0], FALSE, &fnum);
2371 if (fp != NULL && fnum == curbuf->b_fnum)
2372 {
2373 if (fp->col == MAXCOL)
2374 {
2375 /* '> can be MAXCOL, get the length of the line then */
2376 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2377 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2378 else
2379 col = MAXCOL;
2380 }
2381 else
2382 {
2383 col = fp->col + 1;
2384#ifdef FEAT_VIRTUALEDIT
2385 /* col(".") when the cursor is on the NUL at the end of the line
2386 * because of "coladd" can be seen as an extra column. */
2387 if (virtual_active() && fp == &curwin->w_cursor)
2388 {
2389 char_u *p = ml_get_cursor();
2390
2391 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2392 curwin->w_virtcol - curwin->w_cursor.coladd))
2393 {
2394# ifdef FEAT_MBYTE
2395 int l;
2396
2397 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2398 col += l;
2399# else
2400 if (*p != NUL && p[1] == NUL)
2401 ++col;
2402# endif
2403 }
2404 }
2405#endif
2406 }
2407 }
2408 rettv->vval.v_number = col;
2409}
2410
2411#if defined(FEAT_INS_EXPAND)
2412/*
2413 * "complete()" function
2414 */
2415 static void
2416f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2417{
2418 int startcol;
2419
2420 if ((State & INSERT) == 0)
2421 {
2422 EMSG(_("E785: complete() can only be used in Insert mode"));
2423 return;
2424 }
2425
2426 /* Check for undo allowed here, because if something was already inserted
2427 * the line was already saved for undo and this check isn't done. */
2428 if (!undo_allowed())
2429 return;
2430
2431 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2432 {
2433 EMSG(_(e_invarg));
2434 return;
2435 }
2436
2437 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2438 if (startcol <= 0)
2439 return;
2440
2441 set_completion(startcol - 1, argvars[1].vval.v_list);
2442}
2443
2444/*
2445 * "complete_add()" function
2446 */
2447 static void
2448f_complete_add(typval_T *argvars, typval_T *rettv)
2449{
2450 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2451}
2452
2453/*
2454 * "complete_check()" function
2455 */
2456 static void
2457f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2458{
2459 int saved = RedrawingDisabled;
2460
2461 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002462 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002463 rettv->vval.v_number = compl_interrupted;
2464 RedrawingDisabled = saved;
2465}
2466#endif
2467
2468/*
2469 * "confirm(message, buttons[, default [, type]])" function
2470 */
2471 static void
2472f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2473{
2474#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2475 char_u *message;
2476 char_u *buttons = NULL;
2477 char_u buf[NUMBUFLEN];
2478 char_u buf2[NUMBUFLEN];
2479 int def = 1;
2480 int type = VIM_GENERIC;
2481 char_u *typestr;
2482 int error = FALSE;
2483
2484 message = get_tv_string_chk(&argvars[0]);
2485 if (message == NULL)
2486 error = TRUE;
2487 if (argvars[1].v_type != VAR_UNKNOWN)
2488 {
2489 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2490 if (buttons == NULL)
2491 error = TRUE;
2492 if (argvars[2].v_type != VAR_UNKNOWN)
2493 {
2494 def = (int)get_tv_number_chk(&argvars[2], &error);
2495 if (argvars[3].v_type != VAR_UNKNOWN)
2496 {
2497 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2498 if (typestr == NULL)
2499 error = TRUE;
2500 else
2501 {
2502 switch (TOUPPER_ASC(*typestr))
2503 {
2504 case 'E': type = VIM_ERROR; break;
2505 case 'Q': type = VIM_QUESTION; break;
2506 case 'I': type = VIM_INFO; break;
2507 case 'W': type = VIM_WARNING; break;
2508 case 'G': type = VIM_GENERIC; break;
2509 }
2510 }
2511 }
2512 }
2513 }
2514
2515 if (buttons == NULL || *buttons == NUL)
2516 buttons = (char_u *)_("&Ok");
2517
2518 if (!error)
2519 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2520 def, NULL, FALSE);
2521#endif
2522}
2523
2524/*
2525 * "copy()" function
2526 */
2527 static void
2528f_copy(typval_T *argvars, typval_T *rettv)
2529{
2530 item_copy(&argvars[0], rettv, FALSE, 0);
2531}
2532
2533#ifdef FEAT_FLOAT
2534/*
2535 * "cos()" function
2536 */
2537 static void
2538f_cos(typval_T *argvars, typval_T *rettv)
2539{
2540 float_T f = 0.0;
2541
2542 rettv->v_type = VAR_FLOAT;
2543 if (get_float_arg(argvars, &f) == OK)
2544 rettv->vval.v_float = cos(f);
2545 else
2546 rettv->vval.v_float = 0.0;
2547}
2548
2549/*
2550 * "cosh()" function
2551 */
2552 static void
2553f_cosh(typval_T *argvars, typval_T *rettv)
2554{
2555 float_T f = 0.0;
2556
2557 rettv->v_type = VAR_FLOAT;
2558 if (get_float_arg(argvars, &f) == OK)
2559 rettv->vval.v_float = cosh(f);
2560 else
2561 rettv->vval.v_float = 0.0;
2562}
2563#endif
2564
2565/*
2566 * "count()" function
2567 */
2568 static void
2569f_count(typval_T *argvars, typval_T *rettv)
2570{
2571 long n = 0;
2572 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002573 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574
Bram Moolenaar9966b212017-07-28 16:46:57 +02002575 if (argvars[2].v_type != VAR_UNKNOWN)
2576 ic = (int)get_tv_number_chk(&argvars[2], &error);
2577
2578 if (argvars[0].v_type == VAR_STRING)
2579 {
2580 char_u *expr = get_tv_string_chk(&argvars[1]);
2581 char_u *p = argvars[0].vval.v_string;
2582 char_u *next;
2583
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002584 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002585 {
2586 if (ic)
2587 {
2588 size_t len = STRLEN(expr);
2589
2590 while (*p != NUL)
2591 {
2592 if (MB_STRNICMP(p, expr, len) == 0)
2593 {
2594 ++n;
2595 p += len;
2596 }
2597 else
2598 MB_PTR_ADV(p);
2599 }
2600 }
2601 else
2602 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2603 != NULL)
2604 {
2605 ++n;
2606 p = next + STRLEN(expr);
2607 }
2608 }
2609
2610 }
2611 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002612 {
2613 listitem_T *li;
2614 list_T *l;
2615 long idx;
2616
2617 if ((l = argvars[0].vval.v_list) != NULL)
2618 {
2619 li = l->lv_first;
2620 if (argvars[2].v_type != VAR_UNKNOWN)
2621 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002622 if (argvars[3].v_type != VAR_UNKNOWN)
2623 {
2624 idx = (long)get_tv_number_chk(&argvars[3], &error);
2625 if (!error)
2626 {
2627 li = list_find(l, idx);
2628 if (li == NULL)
2629 EMSGN(_(e_listidx), idx);
2630 }
2631 }
2632 if (error)
2633 li = NULL;
2634 }
2635
2636 for ( ; li != NULL; li = li->li_next)
2637 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2638 ++n;
2639 }
2640 }
2641 else if (argvars[0].v_type == VAR_DICT)
2642 {
2643 int todo;
2644 dict_T *d;
2645 hashitem_T *hi;
2646
2647 if ((d = argvars[0].vval.v_dict) != NULL)
2648 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002649 if (argvars[2].v_type != VAR_UNKNOWN)
2650 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 if (argvars[3].v_type != VAR_UNKNOWN)
2652 EMSG(_(e_invarg));
2653 }
2654
2655 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2656 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2657 {
2658 if (!HASHITEM_EMPTY(hi))
2659 {
2660 --todo;
2661 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2662 ++n;
2663 }
2664 }
2665 }
2666 }
2667 else
2668 EMSG2(_(e_listdictarg), "count()");
2669 rettv->vval.v_number = n;
2670}
2671
2672/*
2673 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2674 *
2675 * Checks the existence of a cscope connection.
2676 */
2677 static void
2678f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2679{
2680#ifdef FEAT_CSCOPE
2681 int num = 0;
2682 char_u *dbpath = NULL;
2683 char_u *prepend = NULL;
2684 char_u buf[NUMBUFLEN];
2685
2686 if (argvars[0].v_type != VAR_UNKNOWN
2687 && argvars[1].v_type != VAR_UNKNOWN)
2688 {
2689 num = (int)get_tv_number(&argvars[0]);
2690 dbpath = get_tv_string(&argvars[1]);
2691 if (argvars[2].v_type != VAR_UNKNOWN)
2692 prepend = get_tv_string_buf(&argvars[2], buf);
2693 }
2694
2695 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2696#endif
2697}
2698
2699/*
2700 * "cursor(lnum, col)" function, or
2701 * "cursor(list)"
2702 *
2703 * Moves the cursor to the specified line and column.
2704 * Returns 0 when the position could be set, -1 otherwise.
2705 */
2706 static void
2707f_cursor(typval_T *argvars, typval_T *rettv)
2708{
2709 long line, col;
2710#ifdef FEAT_VIRTUALEDIT
2711 long coladd = 0;
2712#endif
2713 int set_curswant = TRUE;
2714
2715 rettv->vval.v_number = -1;
2716 if (argvars[1].v_type == VAR_UNKNOWN)
2717 {
2718 pos_T pos;
2719 colnr_T curswant = -1;
2720
2721 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2722 {
2723 EMSG(_(e_invarg));
2724 return;
2725 }
2726 line = pos.lnum;
2727 col = pos.col;
2728#ifdef FEAT_VIRTUALEDIT
2729 coladd = pos.coladd;
2730#endif
2731 if (curswant >= 0)
2732 {
2733 curwin->w_curswant = curswant - 1;
2734 set_curswant = FALSE;
2735 }
2736 }
2737 else
2738 {
2739 line = get_tv_lnum(argvars);
2740 col = (long)get_tv_number_chk(&argvars[1], NULL);
2741#ifdef FEAT_VIRTUALEDIT
2742 if (argvars[2].v_type != VAR_UNKNOWN)
2743 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2744#endif
2745 }
2746 if (line < 0 || col < 0
2747#ifdef FEAT_VIRTUALEDIT
2748 || coladd < 0
2749#endif
2750 )
2751 return; /* type error; errmsg already given */
2752 if (line > 0)
2753 curwin->w_cursor.lnum = line;
2754 if (col > 0)
2755 curwin->w_cursor.col = col - 1;
2756#ifdef FEAT_VIRTUALEDIT
2757 curwin->w_cursor.coladd = coladd;
2758#endif
2759
2760 /* Make sure the cursor is in a valid position. */
2761 check_cursor();
2762#ifdef FEAT_MBYTE
2763 /* Correct cursor for multi-byte character. */
2764 if (has_mbyte)
2765 mb_adjust_cursor();
2766#endif
2767
2768 curwin->w_set_curswant = set_curswant;
2769 rettv->vval.v_number = 0;
2770}
2771
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002772#ifdef WIN3264
2773/*
2774 * "debugbreak()" function
2775 */
2776 static void
2777f_debugbreak(typval_T *argvars, typval_T *rettv)
2778{
2779 int pid;
2780
2781 rettv->vval.v_number = FAIL;
2782 pid = (int)get_tv_number(&argvars[0]);
2783 if (pid == 0)
2784 EMSG(_(e_invarg));
2785 else
2786 {
2787 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2788
2789 if (hProcess != NULL)
2790 {
2791 DebugBreakProcess(hProcess);
2792 CloseHandle(hProcess);
2793 rettv->vval.v_number = OK;
2794 }
2795 }
2796}
2797#endif
2798
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002799/*
2800 * "deepcopy()" function
2801 */
2802 static void
2803f_deepcopy(typval_T *argvars, typval_T *rettv)
2804{
2805 int noref = 0;
2806 int copyID;
2807
2808 if (argvars[1].v_type != VAR_UNKNOWN)
2809 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2810 if (noref < 0 || noref > 1)
2811 EMSG(_(e_invarg));
2812 else
2813 {
2814 copyID = get_copyID();
2815 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2816 }
2817}
2818
2819/*
2820 * "delete()" function
2821 */
2822 static void
2823f_delete(typval_T *argvars, typval_T *rettv)
2824{
2825 char_u nbuf[NUMBUFLEN];
2826 char_u *name;
2827 char_u *flags;
2828
2829 rettv->vval.v_number = -1;
2830 if (check_restricted() || check_secure())
2831 return;
2832
2833 name = get_tv_string(&argvars[0]);
2834 if (name == NULL || *name == NUL)
2835 {
2836 EMSG(_(e_invarg));
2837 return;
2838 }
2839
2840 if (argvars[1].v_type != VAR_UNKNOWN)
2841 flags = get_tv_string_buf(&argvars[1], nbuf);
2842 else
2843 flags = (char_u *)"";
2844
2845 if (*flags == NUL)
2846 /* delete a file */
2847 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2848 else if (STRCMP(flags, "d") == 0)
2849 /* delete an empty directory */
2850 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2851 else if (STRCMP(flags, "rf") == 0)
2852 /* delete a directory recursively */
2853 rettv->vval.v_number = delete_recursive(name);
2854 else
2855 EMSG2(_(e_invexpr2), flags);
2856}
2857
2858/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002859 * "deletebufline()" function
2860 */
2861 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002862f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002863{
2864 buf_T *buf;
2865 linenr_T first, last;
2866 linenr_T lnum;
2867 long count;
2868 int is_curbuf;
2869 buf_T *curbuf_save = NULL;
2870 win_T *curwin_save = NULL;
2871 tabpage_T *tp;
2872 win_T *wp;
2873
2874 buf = get_buf_tv(&argvars[0], FALSE);
2875 if (buf == NULL)
2876 {
2877 rettv->vval.v_number = 1; /* FAIL */
2878 return;
2879 }
2880 is_curbuf = buf == curbuf;
2881
2882 first = get_tv_lnum_buf(&argvars[1], buf);
2883 if (argvars[2].v_type != VAR_UNKNOWN)
2884 last = get_tv_lnum_buf(&argvars[2], buf);
2885 else
2886 last = first;
2887
2888 if (buf->b_ml.ml_mfp == NULL || first < 1
2889 || first > buf->b_ml.ml_line_count || last < first)
2890 {
2891 rettv->vval.v_number = 1; /* FAIL */
2892 return;
2893 }
2894
2895 if (!is_curbuf)
2896 {
2897 curbuf_save = curbuf;
2898 curwin_save = curwin;
2899 curbuf = buf;
2900 find_win_for_curbuf();
2901 }
2902 if (last > curbuf->b_ml.ml_line_count)
2903 last = curbuf->b_ml.ml_line_count;
2904 count = last - first + 1;
2905
2906 // When coming here from Insert mode, sync undo, so that this can be
2907 // undone separately from what was previously inserted.
2908 if (u_sync_once == 2)
2909 {
2910 u_sync_once = 1; // notify that u_sync() was called
2911 u_sync(TRUE);
2912 }
2913
2914 if (u_save(first - 1, last + 1) == FAIL)
2915 {
2916 rettv->vval.v_number = 1; /* FAIL */
2917 return;
2918 }
2919
2920 for (lnum = first; lnum <= last; ++lnum)
2921 ml_delete(first, TRUE);
2922
2923 FOR_ALL_TAB_WINDOWS(tp, wp)
2924 if (wp->w_buffer == buf)
2925 {
2926 if (wp->w_cursor.lnum > last)
2927 wp->w_cursor.lnum -= count;
2928 else if (wp->w_cursor.lnum> first)
2929 wp->w_cursor.lnum = first;
2930 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2931 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2932 }
2933 check_cursor_col();
2934 deleted_lines_mark(first, count);
2935
2936 if (!is_curbuf)
2937 {
2938 curbuf = curbuf_save;
2939 curwin = curwin_save;
2940 }
2941}
2942
2943/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002944 * "did_filetype()" function
2945 */
2946 static void
2947f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2948{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002949 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002950}
2951
2952/*
2953 * "diff_filler()" function
2954 */
2955 static void
2956f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2957{
2958#ifdef FEAT_DIFF
2959 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2960#endif
2961}
2962
2963/*
2964 * "diff_hlID()" function
2965 */
2966 static void
2967f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2968{
2969#ifdef FEAT_DIFF
2970 linenr_T lnum = get_tv_lnum(argvars);
2971 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002972 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002973 static int fnum = 0;
2974 static int change_start = 0;
2975 static int change_end = 0;
2976 static hlf_T hlID = (hlf_T)0;
2977 int filler_lines;
2978 int col;
2979
2980 if (lnum < 0) /* ignore type error in {lnum} arg */
2981 lnum = 0;
2982 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002983 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002984 || fnum != curbuf->b_fnum)
2985 {
2986 /* New line, buffer, change: need to get the values. */
2987 filler_lines = diff_check(curwin, lnum);
2988 if (filler_lines < 0)
2989 {
2990 if (filler_lines == -1)
2991 {
2992 change_start = MAXCOL;
2993 change_end = -1;
2994 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2995 hlID = HLF_ADD; /* added line */
2996 else
2997 hlID = HLF_CHD; /* changed line */
2998 }
2999 else
3000 hlID = HLF_ADD; /* added line */
3001 }
3002 else
3003 hlID = (hlf_T)0;
3004 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003005 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006 fnum = curbuf->b_fnum;
3007 }
3008
3009 if (hlID == HLF_CHD || hlID == HLF_TXD)
3010 {
3011 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
3012 if (col >= change_start && col <= change_end)
3013 hlID = HLF_TXD; /* changed text */
3014 else
3015 hlID = HLF_CHD; /* changed line */
3016 }
3017 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3018#endif
3019}
3020
3021/*
3022 * "empty({expr})" function
3023 */
3024 static void
3025f_empty(typval_T *argvars, typval_T *rettv)
3026{
3027 int n = FALSE;
3028
3029 switch (argvars[0].v_type)
3030 {
3031 case VAR_STRING:
3032 case VAR_FUNC:
3033 n = argvars[0].vval.v_string == NULL
3034 || *argvars[0].vval.v_string == NUL;
3035 break;
3036 case VAR_PARTIAL:
3037 n = FALSE;
3038 break;
3039 case VAR_NUMBER:
3040 n = argvars[0].vval.v_number == 0;
3041 break;
3042 case VAR_FLOAT:
3043#ifdef FEAT_FLOAT
3044 n = argvars[0].vval.v_float == 0.0;
3045 break;
3046#endif
3047 case VAR_LIST:
3048 n = argvars[0].vval.v_list == NULL
3049 || argvars[0].vval.v_list->lv_first == NULL;
3050 break;
3051 case VAR_DICT:
3052 n = argvars[0].vval.v_dict == NULL
3053 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3054 break;
3055 case VAR_SPECIAL:
3056 n = argvars[0].vval.v_number != VVAL_TRUE;
3057 break;
3058
3059 case VAR_JOB:
3060#ifdef FEAT_JOB_CHANNEL
3061 n = argvars[0].vval.v_job == NULL
3062 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3063 break;
3064#endif
3065 case VAR_CHANNEL:
3066#ifdef FEAT_JOB_CHANNEL
3067 n = argvars[0].vval.v_channel == NULL
3068 || !channel_is_open(argvars[0].vval.v_channel);
3069 break;
3070#endif
3071 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003072 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 n = TRUE;
3074 break;
3075 }
3076
3077 rettv->vval.v_number = n;
3078}
3079
3080/*
3081 * "escape({string}, {chars})" function
3082 */
3083 static void
3084f_escape(typval_T *argvars, typval_T *rettv)
3085{
3086 char_u buf[NUMBUFLEN];
3087
3088 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
3089 get_tv_string_buf(&argvars[1], buf));
3090 rettv->v_type = VAR_STRING;
3091}
3092
3093/*
3094 * "eval()" function
3095 */
3096 static void
3097f_eval(typval_T *argvars, typval_T *rettv)
3098{
3099 char_u *s, *p;
3100
3101 s = get_tv_string_chk(&argvars[0]);
3102 if (s != NULL)
3103 s = skipwhite(s);
3104
3105 p = s;
3106 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3107 {
3108 if (p != NULL && !aborting())
3109 EMSG2(_(e_invexpr2), p);
3110 need_clr_eos = FALSE;
3111 rettv->v_type = VAR_NUMBER;
3112 rettv->vval.v_number = 0;
3113 }
3114 else if (*s != NUL)
3115 EMSG(_(e_trailing));
3116}
3117
3118/*
3119 * "eventhandler()" function
3120 */
3121 static void
3122f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3123{
3124 rettv->vval.v_number = vgetc_busy;
3125}
3126
3127/*
3128 * "executable()" function
3129 */
3130 static void
3131f_executable(typval_T *argvars, typval_T *rettv)
3132{
3133 char_u *name = get_tv_string(&argvars[0]);
3134
3135 /* Check in $PATH and also check directly if there is a directory name. */
3136 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3137 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3138}
3139
3140static garray_T redir_execute_ga;
3141
3142/*
3143 * Append "value[value_len]" to the execute() output.
3144 */
3145 void
3146execute_redir_str(char_u *value, int value_len)
3147{
3148 int len;
3149
3150 if (value_len == -1)
3151 len = (int)STRLEN(value); /* Append the entire string */
3152 else
3153 len = value_len; /* Append only "value_len" characters */
3154 if (ga_grow(&redir_execute_ga, len) == OK)
3155 {
3156 mch_memmove((char *)redir_execute_ga.ga_data
3157 + redir_execute_ga.ga_len, value, len);
3158 redir_execute_ga.ga_len += len;
3159 }
3160}
3161
3162/*
3163 * Get next line from a list.
3164 * Called by do_cmdline() to get the next line.
3165 * Returns allocated string, or NULL for end of function.
3166 */
3167
3168 static char_u *
3169get_list_line(
3170 int c UNUSED,
3171 void *cookie,
3172 int indent UNUSED)
3173{
3174 listitem_T **p = (listitem_T **)cookie;
3175 listitem_T *item = *p;
3176 char_u buf[NUMBUFLEN];
3177 char_u *s;
3178
3179 if (item == NULL)
3180 return NULL;
3181 s = get_tv_string_buf_chk(&item->li_tv, buf);
3182 *p = item->li_next;
3183 return s == NULL ? NULL : vim_strsave(s);
3184}
3185
3186/*
3187 * "execute()" function
3188 */
3189 static void
3190f_execute(typval_T *argvars, typval_T *rettv)
3191{
3192 char_u *cmd = NULL;
3193 list_T *list = NULL;
3194 int save_msg_silent = msg_silent;
3195 int save_emsg_silent = emsg_silent;
3196 int save_emsg_noredir = emsg_noredir;
3197 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003198 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003199 garray_T save_ga;
3200
3201 rettv->vval.v_string = NULL;
3202 rettv->v_type = VAR_STRING;
3203
3204 if (argvars[0].v_type == VAR_LIST)
3205 {
3206 list = argvars[0].vval.v_list;
3207 if (list == NULL || list->lv_first == NULL)
3208 /* empty list, no commands, empty output */
3209 return;
3210 ++list->lv_refcount;
3211 }
3212 else
3213 {
3214 cmd = get_tv_string_chk(&argvars[0]);
3215 if (cmd == NULL)
3216 return;
3217 }
3218
3219 if (argvars[1].v_type != VAR_UNKNOWN)
3220 {
3221 char_u buf[NUMBUFLEN];
3222 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
3223
3224 if (s == NULL)
3225 return;
3226 if (STRNCMP(s, "silent", 6) == 0)
3227 ++msg_silent;
3228 if (STRCMP(s, "silent!") == 0)
3229 {
3230 emsg_silent = TRUE;
3231 emsg_noredir = TRUE;
3232 }
3233 }
3234 else
3235 ++msg_silent;
3236
3237 if (redir_execute)
3238 save_ga = redir_execute_ga;
3239 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3240 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003241 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003242
3243 if (cmd != NULL)
3244 do_cmdline_cmd(cmd);
3245 else
3246 {
3247 listitem_T *item = list->lv_first;
3248
3249 do_cmdline(NULL, get_list_line, (void *)&item,
3250 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3251 --list->lv_refcount;
3252 }
3253
Bram Moolenaard297f352017-01-29 20:31:21 +01003254 /* Need to append a NUL to the result. */
3255 if (ga_grow(&redir_execute_ga, 1) == OK)
3256 {
3257 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3258 rettv->vval.v_string = redir_execute_ga.ga_data;
3259 }
3260 else
3261 {
3262 ga_clear(&redir_execute_ga);
3263 rettv->vval.v_string = NULL;
3264 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003265 msg_silent = save_msg_silent;
3266 emsg_silent = save_emsg_silent;
3267 emsg_noredir = save_emsg_noredir;
3268
3269 redir_execute = save_redir_execute;
3270 if (redir_execute)
3271 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003272 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003273
3274 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3275 * line. Put it back in the first column. */
3276 msg_col = 0;
3277}
3278
3279/*
3280 * "exepath()" function
3281 */
3282 static void
3283f_exepath(typval_T *argvars, typval_T *rettv)
3284{
3285 char_u *p = NULL;
3286
3287 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3288 rettv->v_type = VAR_STRING;
3289 rettv->vval.v_string = p;
3290}
3291
3292/*
3293 * "exists()" function
3294 */
3295 static void
3296f_exists(typval_T *argvars, typval_T *rettv)
3297{
3298 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003300
3301 p = get_tv_string(&argvars[0]);
3302 if (*p == '$') /* environment variable */
3303 {
3304 /* first try "normal" environment variables (fast) */
3305 if (mch_getenv(p + 1) != NULL)
3306 n = TRUE;
3307 else
3308 {
3309 /* try expanding things like $VIM and ${HOME} */
3310 p = expand_env_save(p);
3311 if (p != NULL && *p != '$')
3312 n = TRUE;
3313 vim_free(p);
3314 }
3315 }
3316 else if (*p == '&' || *p == '+') /* option */
3317 {
3318 n = (get_option_tv(&p, NULL, TRUE) == OK);
3319 if (*skipwhite(p) != NUL)
3320 n = FALSE; /* trailing garbage */
3321 }
3322 else if (*p == '*') /* internal or user defined function */
3323 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003324 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003325 }
3326 else if (*p == ':')
3327 {
3328 n = cmd_exists(p + 1);
3329 }
3330 else if (*p == '#')
3331 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003332 if (p[1] == '#')
3333 n = autocmd_supported(p + 2);
3334 else
3335 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003336 }
3337 else /* internal variable */
3338 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003339 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003340 }
3341
3342 rettv->vval.v_number = n;
3343}
3344
3345#ifdef FEAT_FLOAT
3346/*
3347 * "exp()" function
3348 */
3349 static void
3350f_exp(typval_T *argvars, typval_T *rettv)
3351{
3352 float_T f = 0.0;
3353
3354 rettv->v_type = VAR_FLOAT;
3355 if (get_float_arg(argvars, &f) == OK)
3356 rettv->vval.v_float = exp(f);
3357 else
3358 rettv->vval.v_float = 0.0;
3359}
3360#endif
3361
3362/*
3363 * "expand()" function
3364 */
3365 static void
3366f_expand(typval_T *argvars, typval_T *rettv)
3367{
3368 char_u *s;
3369 int len;
3370 char_u *errormsg;
3371 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3372 expand_T xpc;
3373 int error = FALSE;
3374 char_u *result;
3375
3376 rettv->v_type = VAR_STRING;
3377 if (argvars[1].v_type != VAR_UNKNOWN
3378 && argvars[2].v_type != VAR_UNKNOWN
3379 && get_tv_number_chk(&argvars[2], &error)
3380 && !error)
3381 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003382 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003383 }
3384
3385 s = get_tv_string(&argvars[0]);
3386 if (*s == '%' || *s == '#' || *s == '<')
3387 {
3388 ++emsg_off;
3389 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3390 --emsg_off;
3391 if (rettv->v_type == VAR_LIST)
3392 {
3393 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3394 list_append_string(rettv->vval.v_list, result, -1);
3395 else
3396 vim_free(result);
3397 }
3398 else
3399 rettv->vval.v_string = result;
3400 }
3401 else
3402 {
3403 /* When the optional second argument is non-zero, don't remove matches
3404 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3405 if (argvars[1].v_type != VAR_UNKNOWN
3406 && get_tv_number_chk(&argvars[1], &error))
3407 options |= WILD_KEEP_ALL;
3408 if (!error)
3409 {
3410 ExpandInit(&xpc);
3411 xpc.xp_context = EXPAND_FILES;
3412 if (p_wic)
3413 options += WILD_ICASE;
3414 if (rettv->v_type == VAR_STRING)
3415 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3416 options, WILD_ALL);
3417 else if (rettv_list_alloc(rettv) != FAIL)
3418 {
3419 int i;
3420
3421 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3422 for (i = 0; i < xpc.xp_numfiles; i++)
3423 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3424 ExpandCleanup(&xpc);
3425 }
3426 }
3427 else
3428 rettv->vval.v_string = NULL;
3429 }
3430}
3431
3432/*
3433 * "extend(list, list [, idx])" function
3434 * "extend(dict, dict [, action])" function
3435 */
3436 static void
3437f_extend(typval_T *argvars, typval_T *rettv)
3438{
3439 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3440
3441 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3442 {
3443 list_T *l1, *l2;
3444 listitem_T *item;
3445 long before;
3446 int error = FALSE;
3447
3448 l1 = argvars[0].vval.v_list;
3449 l2 = argvars[1].vval.v_list;
3450 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3451 && l2 != NULL)
3452 {
3453 if (argvars[2].v_type != VAR_UNKNOWN)
3454 {
3455 before = (long)get_tv_number_chk(&argvars[2], &error);
3456 if (error)
3457 return; /* type error; errmsg already given */
3458
3459 if (before == l1->lv_len)
3460 item = NULL;
3461 else
3462 {
3463 item = list_find(l1, before);
3464 if (item == NULL)
3465 {
3466 EMSGN(_(e_listidx), before);
3467 return;
3468 }
3469 }
3470 }
3471 else
3472 item = NULL;
3473 list_extend(l1, l2, item);
3474
3475 copy_tv(&argvars[0], rettv);
3476 }
3477 }
3478 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3479 {
3480 dict_T *d1, *d2;
3481 char_u *action;
3482 int i;
3483
3484 d1 = argvars[0].vval.v_dict;
3485 d2 = argvars[1].vval.v_dict;
3486 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3487 && d2 != NULL)
3488 {
3489 /* Check the third argument. */
3490 if (argvars[2].v_type != VAR_UNKNOWN)
3491 {
3492 static char *(av[]) = {"keep", "force", "error"};
3493
3494 action = get_tv_string_chk(&argvars[2]);
3495 if (action == NULL)
3496 return; /* type error; errmsg already given */
3497 for (i = 0; i < 3; ++i)
3498 if (STRCMP(action, av[i]) == 0)
3499 break;
3500 if (i == 3)
3501 {
3502 EMSG2(_(e_invarg2), action);
3503 return;
3504 }
3505 }
3506 else
3507 action = (char_u *)"force";
3508
3509 dict_extend(d1, d2, action);
3510
3511 copy_tv(&argvars[0], rettv);
3512 }
3513 }
3514 else
3515 EMSG2(_(e_listdictarg), "extend()");
3516}
3517
3518/*
3519 * "feedkeys()" function
3520 */
3521 static void
3522f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3523{
3524 int remap = TRUE;
3525 int insert = FALSE;
3526 char_u *keys, *flags;
3527 char_u nbuf[NUMBUFLEN];
3528 int typed = FALSE;
3529 int execute = FALSE;
3530 int dangerous = FALSE;
3531 char_u *keys_esc;
3532
3533 /* This is not allowed in the sandbox. If the commands would still be
3534 * executed in the sandbox it would be OK, but it probably happens later,
3535 * when "sandbox" is no longer set. */
3536 if (check_secure())
3537 return;
3538
3539 keys = get_tv_string(&argvars[0]);
3540
3541 if (argvars[1].v_type != VAR_UNKNOWN)
3542 {
3543 flags = get_tv_string_buf(&argvars[1], nbuf);
3544 for ( ; *flags != NUL; ++flags)
3545 {
3546 switch (*flags)
3547 {
3548 case 'n': remap = FALSE; break;
3549 case 'm': remap = TRUE; break;
3550 case 't': typed = TRUE; break;
3551 case 'i': insert = TRUE; break;
3552 case 'x': execute = TRUE; break;
3553 case '!': dangerous = TRUE; break;
3554 }
3555 }
3556 }
3557
3558 if (*keys != NUL || execute)
3559 {
3560 /* Need to escape K_SPECIAL and CSI before putting the string in the
3561 * typeahead buffer. */
3562 keys_esc = vim_strsave_escape_csi(keys);
3563 if (keys_esc != NULL)
3564 {
3565 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3566 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3567 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003568 if (vgetc_busy
3569#ifdef FEAT_TIMERS
3570 || timer_busy
3571#endif
3572 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003573 typebuf_was_filled = TRUE;
3574 if (execute)
3575 {
3576 int save_msg_scroll = msg_scroll;
3577
3578 /* Avoid a 1 second delay when the keys start Insert mode. */
3579 msg_scroll = FALSE;
3580
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003581 if (!dangerous)
3582 ++ex_normal_busy;
Bram Moolenaar655a82a2018-05-08 22:01:07 +02003583 exec_normal(TRUE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003584 if (!dangerous)
3585 --ex_normal_busy;
3586
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003587 msg_scroll |= save_msg_scroll;
3588 }
3589 }
3590 }
3591}
3592
3593/*
3594 * "filereadable()" function
3595 */
3596 static void
3597f_filereadable(typval_T *argvars, typval_T *rettv)
3598{
3599 int fd;
3600 char_u *p;
3601 int n;
3602
3603#ifndef O_NONBLOCK
3604# define O_NONBLOCK 0
3605#endif
3606 p = get_tv_string(&argvars[0]);
3607 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3608 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3609 {
3610 n = TRUE;
3611 close(fd);
3612 }
3613 else
3614 n = FALSE;
3615
3616 rettv->vval.v_number = n;
3617}
3618
3619/*
3620 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3621 * rights to write into.
3622 */
3623 static void
3624f_filewritable(typval_T *argvars, typval_T *rettv)
3625{
3626 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3627}
3628
3629 static void
3630findfilendir(
3631 typval_T *argvars UNUSED,
3632 typval_T *rettv,
3633 int find_what UNUSED)
3634{
3635#ifdef FEAT_SEARCHPATH
3636 char_u *fname;
3637 char_u *fresult = NULL;
3638 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3639 char_u *p;
3640 char_u pathbuf[NUMBUFLEN];
3641 int count = 1;
3642 int first = TRUE;
3643 int error = FALSE;
3644#endif
3645
3646 rettv->vval.v_string = NULL;
3647 rettv->v_type = VAR_STRING;
3648
3649#ifdef FEAT_SEARCHPATH
3650 fname = get_tv_string(&argvars[0]);
3651
3652 if (argvars[1].v_type != VAR_UNKNOWN)
3653 {
3654 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3655 if (p == NULL)
3656 error = TRUE;
3657 else
3658 {
3659 if (*p != NUL)
3660 path = p;
3661
3662 if (argvars[2].v_type != VAR_UNKNOWN)
3663 count = (int)get_tv_number_chk(&argvars[2], &error);
3664 }
3665 }
3666
3667 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3668 error = TRUE;
3669
3670 if (*fname != NUL && !error)
3671 {
3672 do
3673 {
3674 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3675 vim_free(fresult);
3676 fresult = find_file_in_path_option(first ? fname : NULL,
3677 first ? (int)STRLEN(fname) : 0,
3678 0, first, path,
3679 find_what,
3680 curbuf->b_ffname,
3681 find_what == FINDFILE_DIR
3682 ? (char_u *)"" : curbuf->b_p_sua);
3683 first = FALSE;
3684
3685 if (fresult != NULL && rettv->v_type == VAR_LIST)
3686 list_append_string(rettv->vval.v_list, fresult, -1);
3687
3688 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3689 }
3690
3691 if (rettv->v_type == VAR_STRING)
3692 rettv->vval.v_string = fresult;
3693#endif
3694}
3695
3696/*
3697 * "filter()" function
3698 */
3699 static void
3700f_filter(typval_T *argvars, typval_T *rettv)
3701{
3702 filter_map(argvars, rettv, FALSE);
3703}
3704
3705/*
3706 * "finddir({fname}[, {path}[, {count}]])" function
3707 */
3708 static void
3709f_finddir(typval_T *argvars, typval_T *rettv)
3710{
3711 findfilendir(argvars, rettv, FINDFILE_DIR);
3712}
3713
3714/*
3715 * "findfile({fname}[, {path}[, {count}]])" function
3716 */
3717 static void
3718f_findfile(typval_T *argvars, typval_T *rettv)
3719{
3720 findfilendir(argvars, rettv, FINDFILE_FILE);
3721}
3722
3723#ifdef FEAT_FLOAT
3724/*
3725 * "float2nr({float})" function
3726 */
3727 static void
3728f_float2nr(typval_T *argvars, typval_T *rettv)
3729{
3730 float_T f = 0.0;
3731
3732 if (get_float_arg(argvars, &f) == OK)
3733 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003734 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003735 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003736 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003737 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003738 else
3739 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740 }
3741}
3742
3743/*
3744 * "floor({float})" function
3745 */
3746 static void
3747f_floor(typval_T *argvars, typval_T *rettv)
3748{
3749 float_T f = 0.0;
3750
3751 rettv->v_type = VAR_FLOAT;
3752 if (get_float_arg(argvars, &f) == OK)
3753 rettv->vval.v_float = floor(f);
3754 else
3755 rettv->vval.v_float = 0.0;
3756}
3757
3758/*
3759 * "fmod()" function
3760 */
3761 static void
3762f_fmod(typval_T *argvars, typval_T *rettv)
3763{
3764 float_T fx = 0.0, fy = 0.0;
3765
3766 rettv->v_type = VAR_FLOAT;
3767 if (get_float_arg(argvars, &fx) == OK
3768 && get_float_arg(&argvars[1], &fy) == OK)
3769 rettv->vval.v_float = fmod(fx, fy);
3770 else
3771 rettv->vval.v_float = 0.0;
3772}
3773#endif
3774
3775/*
3776 * "fnameescape({string})" function
3777 */
3778 static void
3779f_fnameescape(typval_T *argvars, typval_T *rettv)
3780{
3781 rettv->vval.v_string = vim_strsave_fnameescape(
3782 get_tv_string(&argvars[0]), FALSE);
3783 rettv->v_type = VAR_STRING;
3784}
3785
3786/*
3787 * "fnamemodify({fname}, {mods})" function
3788 */
3789 static void
3790f_fnamemodify(typval_T *argvars, typval_T *rettv)
3791{
3792 char_u *fname;
3793 char_u *mods;
3794 int usedlen = 0;
3795 int len;
3796 char_u *fbuf = NULL;
3797 char_u buf[NUMBUFLEN];
3798
3799 fname = get_tv_string_chk(&argvars[0]);
3800 mods = get_tv_string_buf_chk(&argvars[1], buf);
3801 if (fname == NULL || mods == NULL)
3802 fname = NULL;
3803 else
3804 {
3805 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003806 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003807 }
3808
3809 rettv->v_type = VAR_STRING;
3810 if (fname == NULL)
3811 rettv->vval.v_string = NULL;
3812 else
3813 rettv->vval.v_string = vim_strnsave(fname, len);
3814 vim_free(fbuf);
3815}
3816
3817static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3818
3819/*
3820 * "foldclosed()" function
3821 */
3822 static void
3823foldclosed_both(
3824 typval_T *argvars UNUSED,
3825 typval_T *rettv,
3826 int end UNUSED)
3827{
3828#ifdef FEAT_FOLDING
3829 linenr_T lnum;
3830 linenr_T first, last;
3831
3832 lnum = get_tv_lnum(argvars);
3833 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3834 {
3835 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3836 {
3837 if (end)
3838 rettv->vval.v_number = (varnumber_T)last;
3839 else
3840 rettv->vval.v_number = (varnumber_T)first;
3841 return;
3842 }
3843 }
3844#endif
3845 rettv->vval.v_number = -1;
3846}
3847
3848/*
3849 * "foldclosed()" function
3850 */
3851 static void
3852f_foldclosed(typval_T *argvars, typval_T *rettv)
3853{
3854 foldclosed_both(argvars, rettv, FALSE);
3855}
3856
3857/*
3858 * "foldclosedend()" function
3859 */
3860 static void
3861f_foldclosedend(typval_T *argvars, typval_T *rettv)
3862{
3863 foldclosed_both(argvars, rettv, TRUE);
3864}
3865
3866/*
3867 * "foldlevel()" function
3868 */
3869 static void
3870f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3871{
3872#ifdef FEAT_FOLDING
3873 linenr_T lnum;
3874
3875 lnum = get_tv_lnum(argvars);
3876 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3877 rettv->vval.v_number = foldLevel(lnum);
3878#endif
3879}
3880
3881/*
3882 * "foldtext()" function
3883 */
3884 static void
3885f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3886{
3887#ifdef FEAT_FOLDING
3888 linenr_T foldstart;
3889 linenr_T foldend;
3890 char_u *dashes;
3891 linenr_T lnum;
3892 char_u *s;
3893 char_u *r;
3894 int len;
3895 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003896 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003897#endif
3898
3899 rettv->v_type = VAR_STRING;
3900 rettv->vval.v_string = NULL;
3901#ifdef FEAT_FOLDING
3902 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3903 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3904 dashes = get_vim_var_str(VV_FOLDDASHES);
3905 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3906 && dashes != NULL)
3907 {
3908 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003909 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003910 if (!linewhite(lnum))
3911 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912
3913 /* Find interesting text in this line. */
3914 s = skipwhite(ml_get(lnum));
3915 /* skip C comment-start */
3916 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3917 {
3918 s = skipwhite(s + 2);
3919 if (*skipwhite(s) == NUL
3920 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3921 {
3922 s = skipwhite(ml_get(lnum + 1));
3923 if (*s == '*')
3924 s = skipwhite(s + 1);
3925 }
3926 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003927 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003928 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003929 r = alloc((unsigned)(STRLEN(txt)
3930 + STRLEN(dashes) /* for %s */
3931 + 20 /* for %3ld */
3932 + STRLEN(s))); /* concatenated */
3933 if (r != NULL)
3934 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003935 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003936 len = (int)STRLEN(r);
3937 STRCAT(r, s);
3938 /* remove 'foldmarker' and 'commentstring' */
3939 foldtext_cleanup(r + len);
3940 rettv->vval.v_string = r;
3941 }
3942 }
3943#endif
3944}
3945
3946/*
3947 * "foldtextresult(lnum)" function
3948 */
3949 static void
3950f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3951{
3952#ifdef FEAT_FOLDING
3953 linenr_T lnum;
3954 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003955 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956 foldinfo_T foldinfo;
3957 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003958 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003959#endif
3960
3961 rettv->v_type = VAR_STRING;
3962 rettv->vval.v_string = NULL;
3963#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003964 if (entered)
3965 return; /* reject recursive use */
3966 entered = TRUE;
3967
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003968 lnum = get_tv_lnum(argvars);
3969 /* treat illegal types and illegal string values for {lnum} the same */
3970 if (lnum < 0)
3971 lnum = 0;
3972 fold_count = foldedCount(curwin, lnum, &foldinfo);
3973 if (fold_count > 0)
3974 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003975 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3976 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003977 if (text == buf)
3978 text = vim_strsave(text);
3979 rettv->vval.v_string = text;
3980 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003981
3982 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003983#endif
3984}
3985
3986/*
3987 * "foreground()" function
3988 */
3989 static void
3990f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3991{
3992#ifdef FEAT_GUI
3993 if (gui.in_use)
3994 gui_mch_set_foreground();
3995#else
3996# ifdef WIN32
3997 win32_set_foreground();
3998# endif
3999#endif
4000}
4001
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004002 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004003common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004004{
4005 char_u *s;
4006 char_u *name;
4007 int use_string = FALSE;
4008 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004009 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004010
4011 if (argvars[0].v_type == VAR_FUNC)
4012 {
4013 /* function(MyFunc, [arg], dict) */
4014 s = argvars[0].vval.v_string;
4015 }
4016 else if (argvars[0].v_type == VAR_PARTIAL
4017 && argvars[0].vval.v_partial != NULL)
4018 {
4019 /* function(dict.MyFunc, [arg]) */
4020 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004021 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004022 }
4023 else
4024 {
4025 /* function('MyFunc', [arg], dict) */
4026 s = get_tv_string(&argvars[0]);
4027 use_string = TRUE;
4028 }
4029
Bram Moolenaar843b8842016-08-21 14:36:15 +02004030 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004031 {
4032 name = s;
4033 trans_name = trans_function_name(&name, FALSE,
4034 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4035 if (*name != NUL)
4036 s = NULL;
4037 }
4038
Bram Moolenaar843b8842016-08-21 14:36:15 +02004039 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4040 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02004041 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004042 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004043 else if (trans_name != NULL && (is_funcref
4044 ? find_func(trans_name) == NULL
4045 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004046 EMSG2(_("E700: Unknown function: %s"), s);
4047 else
4048 {
4049 int dict_idx = 0;
4050 int arg_idx = 0;
4051 list_T *list = NULL;
4052
4053 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4054 {
4055 char sid_buf[25];
4056 int off = *s == 's' ? 2 : 5;
4057
4058 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4059 * also be called from another script. Using trans_function_name()
4060 * would also work, but some plugins depend on the name being
4061 * printable text. */
4062 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
4063 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4064 if (name != NULL)
4065 {
4066 STRCPY(name, sid_buf);
4067 STRCAT(name, s + off);
4068 }
4069 }
4070 else
4071 name = vim_strsave(s);
4072
4073 if (argvars[1].v_type != VAR_UNKNOWN)
4074 {
4075 if (argvars[2].v_type != VAR_UNKNOWN)
4076 {
4077 /* function(name, [args], dict) */
4078 arg_idx = 1;
4079 dict_idx = 2;
4080 }
4081 else if (argvars[1].v_type == VAR_DICT)
4082 /* function(name, dict) */
4083 dict_idx = 1;
4084 else
4085 /* function(name, [args]) */
4086 arg_idx = 1;
4087 if (dict_idx > 0)
4088 {
4089 if (argvars[dict_idx].v_type != VAR_DICT)
4090 {
4091 EMSG(_("E922: expected a dict"));
4092 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004093 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004094 }
4095 if (argvars[dict_idx].vval.v_dict == NULL)
4096 dict_idx = 0;
4097 }
4098 if (arg_idx > 0)
4099 {
4100 if (argvars[arg_idx].v_type != VAR_LIST)
4101 {
4102 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4103 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004104 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004105 }
4106 list = argvars[arg_idx].vval.v_list;
4107 if (list == NULL || list->lv_len == 0)
4108 arg_idx = 0;
4109 }
4110 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004111 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004112 {
4113 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4114
4115 /* result is a VAR_PARTIAL */
4116 if (pt == NULL)
4117 vim_free(name);
4118 else
4119 {
4120 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4121 {
4122 listitem_T *li;
4123 int i = 0;
4124 int arg_len = 0;
4125 int lv_len = 0;
4126
4127 if (arg_pt != NULL)
4128 arg_len = arg_pt->pt_argc;
4129 if (list != NULL)
4130 lv_len = list->lv_len;
4131 pt->pt_argc = arg_len + lv_len;
4132 pt->pt_argv = (typval_T *)alloc(
4133 sizeof(typval_T) * pt->pt_argc);
4134 if (pt->pt_argv == NULL)
4135 {
4136 vim_free(pt);
4137 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004138 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004139 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004140 for (i = 0; i < arg_len; i++)
4141 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4142 if (lv_len > 0)
4143 for (li = list->lv_first; li != NULL;
4144 li = li->li_next)
4145 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004146 }
4147
4148 /* For "function(dict.func, [], dict)" and "func" is a partial
4149 * use "dict". That is backwards compatible. */
4150 if (dict_idx > 0)
4151 {
4152 /* The dict is bound explicitly, pt_auto is FALSE. */
4153 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4154 ++pt->pt_dict->dv_refcount;
4155 }
4156 else if (arg_pt != NULL)
4157 {
4158 /* If the dict was bound automatically the result is also
4159 * bound automatically. */
4160 pt->pt_dict = arg_pt->pt_dict;
4161 pt->pt_auto = arg_pt->pt_auto;
4162 if (pt->pt_dict != NULL)
4163 ++pt->pt_dict->dv_refcount;
4164 }
4165
4166 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004167 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4168 {
4169 pt->pt_func = arg_pt->pt_func;
4170 func_ptr_ref(pt->pt_func);
4171 vim_free(name);
4172 }
4173 else if (is_funcref)
4174 {
4175 pt->pt_func = find_func(trans_name);
4176 func_ptr_ref(pt->pt_func);
4177 vim_free(name);
4178 }
4179 else
4180 {
4181 pt->pt_name = name;
4182 func_ref(name);
4183 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004184 }
4185 rettv->v_type = VAR_PARTIAL;
4186 rettv->vval.v_partial = pt;
4187 }
4188 else
4189 {
4190 /* result is a VAR_FUNC */
4191 rettv->v_type = VAR_FUNC;
4192 rettv->vval.v_string = name;
4193 func_ref(name);
4194 }
4195 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004196theend:
4197 vim_free(trans_name);
4198}
4199
4200/*
4201 * "funcref()" function
4202 */
4203 static void
4204f_funcref(typval_T *argvars, typval_T *rettv)
4205{
4206 common_function(argvars, rettv, TRUE);
4207}
4208
4209/*
4210 * "function()" function
4211 */
4212 static void
4213f_function(typval_T *argvars, typval_T *rettv)
4214{
4215 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004216}
4217
4218/*
4219 * "garbagecollect()" function
4220 */
4221 static void
4222f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4223{
4224 /* This is postponed until we are back at the toplevel, because we may be
4225 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4226 want_garbage_collect = TRUE;
4227
4228 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
4229 garbage_collect_at_exit = TRUE;
4230}
4231
4232/*
4233 * "get()" function
4234 */
4235 static void
4236f_get(typval_T *argvars, typval_T *rettv)
4237{
4238 listitem_T *li;
4239 list_T *l;
4240 dictitem_T *di;
4241 dict_T *d;
4242 typval_T *tv = NULL;
4243
4244 if (argvars[0].v_type == VAR_LIST)
4245 {
4246 if ((l = argvars[0].vval.v_list) != NULL)
4247 {
4248 int error = FALSE;
4249
4250 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
4251 if (!error && li != NULL)
4252 tv = &li->li_tv;
4253 }
4254 }
4255 else if (argvars[0].v_type == VAR_DICT)
4256 {
4257 if ((d = argvars[0].vval.v_dict) != NULL)
4258 {
4259 di = dict_find(d, get_tv_string(&argvars[1]), -1);
4260 if (di != NULL)
4261 tv = &di->di_tv;
4262 }
4263 }
4264 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4265 {
4266 partial_T *pt;
4267 partial_T fref_pt;
4268
4269 if (argvars[0].v_type == VAR_PARTIAL)
4270 pt = argvars[0].vval.v_partial;
4271 else
4272 {
4273 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4274 fref_pt.pt_name = argvars[0].vval.v_string;
4275 pt = &fref_pt;
4276 }
4277
4278 if (pt != NULL)
4279 {
4280 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004281 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004282
4283 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4284 {
4285 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004286 n = partial_name(pt);
4287 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004288 rettv->vval.v_string = NULL;
4289 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004290 {
4291 rettv->vval.v_string = vim_strsave(n);
4292 if (rettv->v_type == VAR_FUNC)
4293 func_ref(rettv->vval.v_string);
4294 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004295 }
4296 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004297 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298 else if (STRCMP(what, "args") == 0)
4299 {
4300 rettv->v_type = VAR_LIST;
4301 if (rettv_list_alloc(rettv) == OK)
4302 {
4303 int i;
4304
4305 for (i = 0; i < pt->pt_argc; ++i)
4306 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4307 }
4308 }
4309 else
4310 EMSG2(_(e_invarg2), what);
4311 return;
4312 }
4313 }
4314 else
4315 EMSG2(_(e_listdictarg), "get()");
4316
4317 if (tv == NULL)
4318 {
4319 if (argvars[2].v_type != VAR_UNKNOWN)
4320 copy_tv(&argvars[2], rettv);
4321 }
4322 else
4323 copy_tv(tv, rettv);
4324}
4325
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004326#ifdef FEAT_SIGNS
4327/*
4328 * Returns information about signs placed in a buffer as list of dicts.
4329 */
4330 static void
4331get_buffer_signs(buf_T *buf, list_T *l)
4332{
4333 signlist_T *sign;
4334
4335 for (sign = buf->b_signlist; sign; sign = sign->next)
4336 {
4337 dict_T *d = dict_alloc();
4338
4339 if (d != NULL)
4340 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02004341 dict_add_number(d, "id", sign->id);
4342 dict_add_number(d, "lnum", sign->lnum);
4343 dict_add_string(d, "name", sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004344
4345 list_append_dict(l, d);
4346 }
4347 }
4348}
4349#endif
4350
4351/*
4352 * Returns buffer options, variables and other attributes in a dictionary.
4353 */
4354 static dict_T *
4355get_buffer_info(buf_T *buf)
4356{
4357 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004358 tabpage_T *tp;
4359 win_T *wp;
4360 list_T *windows;
4361
4362 dict = dict_alloc();
4363 if (dict == NULL)
4364 return NULL;
4365
Bram Moolenaare0be1672018-07-08 16:50:37 +02004366 dict_add_number(dict, "bufnr", buf->b_fnum);
4367 dict_add_string(dict, "name", buf->b_ffname);
4368 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4369 : buflist_findlnum(buf));
4370 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4371 dict_add_number(dict, "listed", buf->b_p_bl);
4372 dict_add_number(dict, "changed", bufIsChanged(buf));
4373 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4374 dict_add_number(dict, "hidden",
4375 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004376
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004377 /* Get a reference to buffer variables */
4378 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004379
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004380 /* List of windows displaying this buffer */
4381 windows = list_alloc();
4382 if (windows != NULL)
4383 {
4384 FOR_ALL_TAB_WINDOWS(tp, wp)
4385 if (wp->w_buffer == buf)
4386 list_append_number(windows, (varnumber_T)wp->w_id);
4387 dict_add_list(dict, "windows", windows);
4388 }
4389
4390#ifdef FEAT_SIGNS
4391 if (buf->b_signlist != NULL)
4392 {
4393 /* List of signs placed in this buffer */
4394 list_T *signs = list_alloc();
4395 if (signs != NULL)
4396 {
4397 get_buffer_signs(buf, signs);
4398 dict_add_list(dict, "signs", signs);
4399 }
4400 }
4401#endif
4402
4403 return dict;
4404}
4405
4406/*
4407 * "getbufinfo()" function
4408 */
4409 static void
4410f_getbufinfo(typval_T *argvars, typval_T *rettv)
4411{
4412 buf_T *buf = NULL;
4413 buf_T *argbuf = NULL;
4414 dict_T *d;
4415 int filtered = FALSE;
4416 int sel_buflisted = FALSE;
4417 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004418 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004419
4420 if (rettv_list_alloc(rettv) != OK)
4421 return;
4422
4423 /* List of all the buffers or selected buffers */
4424 if (argvars[0].v_type == VAR_DICT)
4425 {
4426 dict_T *sel_d = argvars[0].vval.v_dict;
4427
4428 if (sel_d != NULL)
4429 {
4430 dictitem_T *di;
4431
4432 filtered = TRUE;
4433
4434 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4435 if (di != NULL && get_tv_number(&di->di_tv))
4436 sel_buflisted = TRUE;
4437
4438 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4439 if (di != NULL && get_tv_number(&di->di_tv))
4440 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004441
4442 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4443 if (di != NULL && get_tv_number(&di->di_tv))
4444 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004445 }
4446 }
4447 else if (argvars[0].v_type != VAR_UNKNOWN)
4448 {
4449 /* Information about one buffer. Argument specifies the buffer */
4450 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4451 ++emsg_off;
4452 argbuf = get_buf_tv(&argvars[0], FALSE);
4453 --emsg_off;
4454 if (argbuf == NULL)
4455 return;
4456 }
4457
4458 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004459 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004460 {
4461 if (argbuf != NULL && argbuf != buf)
4462 continue;
4463 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004464 || (sel_buflisted && !buf->b_p_bl)
4465 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004466 continue;
4467
4468 d = get_buffer_info(buf);
4469 if (d != NULL)
4470 list_append_dict(rettv->vval.v_list, d);
4471 if (argbuf != NULL)
4472 return;
4473 }
4474}
4475
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4477
4478/*
4479 * Get line or list of lines from buffer "buf" into "rettv".
4480 * Return a range (from start to end) of lines in rettv from the specified
4481 * buffer.
4482 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4483 */
4484 static void
4485get_buffer_lines(
4486 buf_T *buf,
4487 linenr_T start,
4488 linenr_T end,
4489 int retlist,
4490 typval_T *rettv)
4491{
4492 char_u *p;
4493
4494 rettv->v_type = VAR_STRING;
4495 rettv->vval.v_string = NULL;
4496 if (retlist && rettv_list_alloc(rettv) == FAIL)
4497 return;
4498
4499 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4500 return;
4501
4502 if (!retlist)
4503 {
4504 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4505 p = ml_get_buf(buf, start, FALSE);
4506 else
4507 p = (char_u *)"";
4508 rettv->vval.v_string = vim_strsave(p);
4509 }
4510 else
4511 {
4512 if (end < start)
4513 return;
4514
4515 if (start < 1)
4516 start = 1;
4517 if (end > buf->b_ml.ml_line_count)
4518 end = buf->b_ml.ml_line_count;
4519 while (start <= end)
4520 if (list_append_string(rettv->vval.v_list,
4521 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4522 break;
4523 }
4524}
4525
4526/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004527 * "getbufline()" function
4528 */
4529 static void
4530f_getbufline(typval_T *argvars, typval_T *rettv)
4531{
4532 linenr_T lnum;
4533 linenr_T end;
4534 buf_T *buf;
4535
4536 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4537 ++emsg_off;
4538 buf = get_buf_tv(&argvars[0], FALSE);
4539 --emsg_off;
4540
4541 lnum = get_tv_lnum_buf(&argvars[1], buf);
4542 if (argvars[2].v_type == VAR_UNKNOWN)
4543 end = lnum;
4544 else
4545 end = get_tv_lnum_buf(&argvars[2], buf);
4546
4547 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4548}
4549
4550/*
4551 * "getbufvar()" function
4552 */
4553 static void
4554f_getbufvar(typval_T *argvars, typval_T *rettv)
4555{
4556 buf_T *buf;
4557 buf_T *save_curbuf;
4558 char_u *varname;
4559 dictitem_T *v;
4560 int done = FALSE;
4561
4562 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4563 varname = get_tv_string_chk(&argvars[1]);
4564 ++emsg_off;
4565 buf = get_buf_tv(&argvars[0], FALSE);
4566
4567 rettv->v_type = VAR_STRING;
4568 rettv->vval.v_string = NULL;
4569
4570 if (buf != NULL && varname != NULL)
4571 {
4572 /* set curbuf to be our buf, temporarily */
4573 save_curbuf = curbuf;
4574 curbuf = buf;
4575
Bram Moolenaar30567352016-08-27 21:25:44 +02004576 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004577 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004578 if (varname[1] == NUL)
4579 {
4580 /* get all buffer-local options in a dict */
4581 dict_T *opts = get_winbuf_options(TRUE);
4582
4583 if (opts != NULL)
4584 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004585 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004586 done = TRUE;
4587 }
4588 }
4589 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4590 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004591 done = TRUE;
4592 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004593 else
4594 {
4595 /* Look up the variable. */
4596 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4597 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4598 'b', varname, FALSE);
4599 if (v != NULL)
4600 {
4601 copy_tv(&v->di_tv, rettv);
4602 done = TRUE;
4603 }
4604 }
4605
4606 /* restore previous notion of curbuf */
4607 curbuf = save_curbuf;
4608 }
4609
4610 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4611 /* use the default value */
4612 copy_tv(&argvars[2], rettv);
4613
4614 --emsg_off;
4615}
4616
4617/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004618 * "getchangelist()" function
4619 */
4620 static void
4621f_getchangelist(typval_T *argvars, typval_T *rettv)
4622{
4623#ifdef FEAT_JUMPLIST
4624 buf_T *buf;
4625 int i;
4626 list_T *l;
4627 dict_T *d;
4628#endif
4629
4630 if (rettv_list_alloc(rettv) != OK)
4631 return;
4632
4633#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004634 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4635 ++emsg_off;
4636 buf = get_buf_tv(&argvars[0], FALSE);
4637 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004638 if (buf == NULL)
4639 return;
4640
4641 l = list_alloc();
4642 if (l == NULL)
4643 return;
4644
4645 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4646 return;
4647 /*
4648 * The current window change list index tracks only the position in the
4649 * current buffer change list. For other buffers, use the change list
4650 * length as the current index.
4651 */
4652 list_append_number(rettv->vval.v_list,
4653 (varnumber_T)((buf == curwin->w_buffer)
4654 ? curwin->w_changelistidx : buf->b_changelistlen));
4655
4656 for (i = 0; i < buf->b_changelistlen; ++i)
4657 {
4658 if (buf->b_changelist[i].lnum == 0)
4659 continue;
4660 if ((d = dict_alloc()) == NULL)
4661 return;
4662 if (list_append_dict(l, d) == FAIL)
4663 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004664 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4665 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004666# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004667 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004668# endif
4669 }
4670#endif
4671}
4672/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004673 * "getchar()" function
4674 */
4675 static void
4676f_getchar(typval_T *argvars, typval_T *rettv)
4677{
4678 varnumber_T n;
4679 int error = FALSE;
4680
4681 /* Position the cursor. Needed after a message that ends in a space. */
4682 windgoto(msg_row, msg_col);
4683
4684 ++no_mapping;
4685 ++allow_keys;
4686 for (;;)
4687 {
4688 if (argvars[0].v_type == VAR_UNKNOWN)
4689 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004690 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004691 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4692 /* getchar(1): only check if char avail */
4693 n = vpeekc_any();
4694 else if (error || vpeekc_any() == NUL)
4695 /* illegal argument or getchar(0) and no char avail: return zero */
4696 n = 0;
4697 else
4698 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004699 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700
4701 if (n == K_IGNORE)
4702 continue;
4703 break;
4704 }
4705 --no_mapping;
4706 --allow_keys;
4707
4708 set_vim_var_nr(VV_MOUSE_WIN, 0);
4709 set_vim_var_nr(VV_MOUSE_WINID, 0);
4710 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4711 set_vim_var_nr(VV_MOUSE_COL, 0);
4712
4713 rettv->vval.v_number = n;
4714 if (IS_SPECIAL(n) || mod_mask != 0)
4715 {
4716 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4717 int i = 0;
4718
4719 /* Turn a special key into three bytes, plus modifier. */
4720 if (mod_mask != 0)
4721 {
4722 temp[i++] = K_SPECIAL;
4723 temp[i++] = KS_MODIFIER;
4724 temp[i++] = mod_mask;
4725 }
4726 if (IS_SPECIAL(n))
4727 {
4728 temp[i++] = K_SPECIAL;
4729 temp[i++] = K_SECOND(n);
4730 temp[i++] = K_THIRD(n);
4731 }
4732#ifdef FEAT_MBYTE
4733 else if (has_mbyte)
4734 i += (*mb_char2bytes)(n, temp + i);
4735#endif
4736 else
4737 temp[i++] = n;
4738 temp[i++] = NUL;
4739 rettv->v_type = VAR_STRING;
4740 rettv->vval.v_string = vim_strsave(temp);
4741
4742#ifdef FEAT_MOUSE
4743 if (is_mouse_key(n))
4744 {
4745 int row = mouse_row;
4746 int col = mouse_col;
4747 win_T *win;
4748 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004749 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004750 int winnr = 1;
4751
4752 if (row >= 0 && col >= 0)
4753 {
4754 /* Find the window at the mouse coordinates and compute the
4755 * text position. */
4756 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004757 if (win == NULL)
4758 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004759 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004760 for (wp = firstwin; wp != win; wp = wp->w_next)
4761 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004762 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4763 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4764 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4765 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4766 }
4767 }
4768#endif
4769 }
4770}
4771
4772/*
4773 * "getcharmod()" function
4774 */
4775 static void
4776f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4777{
4778 rettv->vval.v_number = mod_mask;
4779}
4780
4781/*
4782 * "getcharsearch()" function
4783 */
4784 static void
4785f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4786{
4787 if (rettv_dict_alloc(rettv) != FAIL)
4788 {
4789 dict_T *dict = rettv->vval.v_dict;
4790
Bram Moolenaare0be1672018-07-08 16:50:37 +02004791 dict_add_string(dict, "char", last_csearch());
4792 dict_add_number(dict, "forward", last_csearch_forward());
4793 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004794 }
4795}
4796
4797/*
4798 * "getcmdline()" function
4799 */
4800 static void
4801f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4802{
4803 rettv->v_type = VAR_STRING;
4804 rettv->vval.v_string = get_cmdline_str();
4805}
4806
4807/*
4808 * "getcmdpos()" function
4809 */
4810 static void
4811f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4812{
4813 rettv->vval.v_number = get_cmdline_pos() + 1;
4814}
4815
4816/*
4817 * "getcmdtype()" function
4818 */
4819 static void
4820f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4821{
4822 rettv->v_type = VAR_STRING;
4823 rettv->vval.v_string = alloc(2);
4824 if (rettv->vval.v_string != NULL)
4825 {
4826 rettv->vval.v_string[0] = get_cmdline_type();
4827 rettv->vval.v_string[1] = NUL;
4828 }
4829}
4830
4831/*
4832 * "getcmdwintype()" function
4833 */
4834 static void
4835f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4836{
4837 rettv->v_type = VAR_STRING;
4838 rettv->vval.v_string = NULL;
4839#ifdef FEAT_CMDWIN
4840 rettv->vval.v_string = alloc(2);
4841 if (rettv->vval.v_string != NULL)
4842 {
4843 rettv->vval.v_string[0] = cmdwin_type;
4844 rettv->vval.v_string[1] = NUL;
4845 }
4846#endif
4847}
4848
4849#if defined(FEAT_CMDL_COMPL)
4850/*
4851 * "getcompletion()" function
4852 */
4853 static void
4854f_getcompletion(typval_T *argvars, typval_T *rettv)
4855{
4856 char_u *pat;
4857 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004858 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004859 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4860 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004862 if (argvars[2].v_type != VAR_UNKNOWN)
4863 filtered = get_tv_number_chk(&argvars[2], NULL);
4864
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004865 if (p_wic)
4866 options |= WILD_ICASE;
4867
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004868 /* For filtered results, 'wildignore' is used */
4869 if (!filtered)
4870 options |= WILD_KEEP_ALL;
4871
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004872 ExpandInit(&xpc);
4873 xpc.xp_pattern = get_tv_string(&argvars[0]);
4874 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4875 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4876 if (xpc.xp_context == EXPAND_NOTHING)
4877 {
4878 if (argvars[1].v_type == VAR_STRING)
4879 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4880 else
4881 EMSG(_(e_invarg));
4882 return;
4883 }
4884
4885# if defined(FEAT_MENU)
4886 if (xpc.xp_context == EXPAND_MENUS)
4887 {
4888 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4889 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4890 }
4891# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004892#ifdef FEAT_CSCOPE
4893 if (xpc.xp_context == EXPAND_CSCOPE)
4894 {
4895 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4896 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4897 }
4898#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004899#ifdef FEAT_SIGNS
4900 if (xpc.xp_context == EXPAND_SIGN)
4901 {
4902 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4903 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4904 }
4905#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906
4907 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4908 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4909 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004910 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911
4912 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4913
4914 for (i = 0; i < xpc.xp_numfiles; i++)
4915 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4916 }
4917 vim_free(pat);
4918 ExpandCleanup(&xpc);
4919}
4920#endif
4921
4922/*
4923 * "getcwd()" function
4924 */
4925 static void
4926f_getcwd(typval_T *argvars, typval_T *rettv)
4927{
4928 win_T *wp = NULL;
4929 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004930 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931
4932 rettv->v_type = VAR_STRING;
4933 rettv->vval.v_string = NULL;
4934
Bram Moolenaar54591292018-02-09 20:53:59 +01004935 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4936 global = TRUE;
4937 else
4938 wp = find_tabwin(&argvars[0], &argvars[1]);
4939
4940 if (wp != NULL && wp->w_localdir != NULL)
4941 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4942 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004943 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004944 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945 rettv->vval.v_string = vim_strsave(globaldir);
4946 else
4947 {
4948 cwd = alloc(MAXPATHL);
4949 if (cwd != NULL)
4950 {
4951 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4952 rettv->vval.v_string = vim_strsave(cwd);
4953 vim_free(cwd);
4954 }
4955 }
4956#ifdef BACKSLASH_IN_FILENAME
4957 if (rettv->vval.v_string != NULL)
4958 slash_adjust(rettv->vval.v_string);
4959#endif
4960 }
4961}
4962
4963/*
4964 * "getfontname()" function
4965 */
4966 static void
4967f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4968{
4969 rettv->v_type = VAR_STRING;
4970 rettv->vval.v_string = NULL;
4971#ifdef FEAT_GUI
4972 if (gui.in_use)
4973 {
4974 GuiFont font;
4975 char_u *name = NULL;
4976
4977 if (argvars[0].v_type == VAR_UNKNOWN)
4978 {
4979 /* Get the "Normal" font. Either the name saved by
4980 * hl_set_font_name() or from the font ID. */
4981 font = gui.norm_font;
4982 name = hl_get_font_name();
4983 }
4984 else
4985 {
4986 name = get_tv_string(&argvars[0]);
4987 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4988 return;
4989 font = gui_mch_get_font(name, FALSE);
4990 if (font == NOFONT)
4991 return; /* Invalid font name, return empty string. */
4992 }
4993 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4994 if (argvars[0].v_type != VAR_UNKNOWN)
4995 gui_mch_free_font(font);
4996 }
4997#endif
4998}
4999
5000/*
5001 * "getfperm({fname})" function
5002 */
5003 static void
5004f_getfperm(typval_T *argvars, typval_T *rettv)
5005{
5006 char_u *fname;
5007 stat_T st;
5008 char_u *perm = NULL;
5009 char_u flags[] = "rwx";
5010 int i;
5011
5012 fname = get_tv_string(&argvars[0]);
5013
5014 rettv->v_type = VAR_STRING;
5015 if (mch_stat((char *)fname, &st) >= 0)
5016 {
5017 perm = vim_strsave((char_u *)"---------");
5018 if (perm != NULL)
5019 {
5020 for (i = 0; i < 9; i++)
5021 {
5022 if (st.st_mode & (1 << (8 - i)))
5023 perm[i] = flags[i % 3];
5024 }
5025 }
5026 }
5027 rettv->vval.v_string = perm;
5028}
5029
5030/*
5031 * "getfsize({fname})" function
5032 */
5033 static void
5034f_getfsize(typval_T *argvars, typval_T *rettv)
5035{
5036 char_u *fname;
5037 stat_T st;
5038
5039 fname = get_tv_string(&argvars[0]);
5040
5041 rettv->v_type = VAR_NUMBER;
5042
5043 if (mch_stat((char *)fname, &st) >= 0)
5044 {
5045 if (mch_isdir(fname))
5046 rettv->vval.v_number = 0;
5047 else
5048 {
5049 rettv->vval.v_number = (varnumber_T)st.st_size;
5050
5051 /* non-perfect check for overflow */
5052 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5053 rettv->vval.v_number = -2;
5054 }
5055 }
5056 else
5057 rettv->vval.v_number = -1;
5058}
5059
5060/*
5061 * "getftime({fname})" function
5062 */
5063 static void
5064f_getftime(typval_T *argvars, typval_T *rettv)
5065{
5066 char_u *fname;
5067 stat_T st;
5068
5069 fname = get_tv_string(&argvars[0]);
5070
5071 if (mch_stat((char *)fname, &st) >= 0)
5072 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5073 else
5074 rettv->vval.v_number = -1;
5075}
5076
5077/*
5078 * "getftype({fname})" function
5079 */
5080 static void
5081f_getftype(typval_T *argvars, typval_T *rettv)
5082{
5083 char_u *fname;
5084 stat_T st;
5085 char_u *type = NULL;
5086 char *t;
5087
5088 fname = get_tv_string(&argvars[0]);
5089
5090 rettv->v_type = VAR_STRING;
5091 if (mch_lstat((char *)fname, &st) >= 0)
5092 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005093 if (S_ISREG(st.st_mode))
5094 t = "file";
5095 else if (S_ISDIR(st.st_mode))
5096 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097 else if (S_ISLNK(st.st_mode))
5098 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 else if (S_ISBLK(st.st_mode))
5100 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005101 else if (S_ISCHR(st.st_mode))
5102 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103 else if (S_ISFIFO(st.st_mode))
5104 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005106 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 else
5108 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 type = vim_strsave((char_u *)t);
5110 }
5111 rettv->vval.v_string = type;
5112}
5113
5114/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005115 * "getjumplist()" function
5116 */
5117 static void
5118f_getjumplist(typval_T *argvars, typval_T *rettv)
5119{
5120#ifdef FEAT_JUMPLIST
5121 win_T *wp;
5122 int i;
5123 list_T *l;
5124 dict_T *d;
5125#endif
5126
5127 if (rettv_list_alloc(rettv) != OK)
5128 return;
5129
5130#ifdef FEAT_JUMPLIST
5131 wp = find_tabwin(&argvars[0], &argvars[1]);
5132 if (wp == NULL)
5133 return;
5134
5135 l = list_alloc();
5136 if (l == NULL)
5137 return;
5138
5139 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5140 return;
5141 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5142
Bram Moolenaar48679742018-02-13 13:33:29 +01005143 cleanup_jumplist(wp, TRUE);
5144
Bram Moolenaar4f505882018-02-10 21:06:32 +01005145 for (i = 0; i < wp->w_jumplistlen; ++i)
5146 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005147 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5148 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005149 if ((d = dict_alloc()) == NULL)
5150 return;
5151 if (list_append_dict(l, d) == FAIL)
5152 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005153 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5154 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005155# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005156 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005157# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005158 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005159 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005160 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005161 }
5162#endif
5163}
5164
5165/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005166 * "getline(lnum, [end])" function
5167 */
5168 static void
5169f_getline(typval_T *argvars, typval_T *rettv)
5170{
5171 linenr_T lnum;
5172 linenr_T end;
5173 int retlist;
5174
5175 lnum = get_tv_lnum(argvars);
5176 if (argvars[1].v_type == VAR_UNKNOWN)
5177 {
5178 end = 0;
5179 retlist = FALSE;
5180 }
5181 else
5182 {
5183 end = get_tv_lnum(&argvars[1]);
5184 retlist = TRUE;
5185 }
5186
5187 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5188}
5189
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005190#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005191 static void
5192get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5193{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005194 if (what_arg->v_type == VAR_UNKNOWN)
5195 {
5196 if (rettv_list_alloc(rettv) == OK)
5197 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005198 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005199 }
5200 else
5201 {
5202 if (rettv_dict_alloc(rettv) == OK)
5203 if (is_qf || (wp != NULL))
5204 {
5205 if (what_arg->v_type == VAR_DICT)
5206 {
5207 dict_T *d = what_arg->vval.v_dict;
5208
5209 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005210 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005211 }
5212 else
5213 EMSG(_(e_dictreq));
5214 }
5215 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005216}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005217#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005218
5219/*
5220 * "getloclist()" function
5221 */
5222 static void
5223f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5224{
5225#ifdef FEAT_QUICKFIX
5226 win_T *wp;
5227
5228 wp = find_win_by_nr(&argvars[0], NULL);
5229 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5230#endif
5231}
5232
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005233/*
5234 * "getmatches()" function
5235 */
5236 static void
5237f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5238{
5239#ifdef FEAT_SEARCH_EXTRA
5240 dict_T *dict;
5241 matchitem_T *cur = curwin->w_match_head;
5242 int i;
5243
5244 if (rettv_list_alloc(rettv) == OK)
5245 {
5246 while (cur != NULL)
5247 {
5248 dict = dict_alloc();
5249 if (dict == NULL)
5250 return;
5251 if (cur->match.regprog == NULL)
5252 {
5253 /* match added with matchaddpos() */
5254 for (i = 0; i < MAXPOSMATCH; ++i)
5255 {
5256 llpos_T *llpos;
5257 char buf[6];
5258 list_T *l;
5259
5260 llpos = &cur->pos.pos[i];
5261 if (llpos->lnum == 0)
5262 break;
5263 l = list_alloc();
5264 if (l == NULL)
5265 break;
5266 list_append_number(l, (varnumber_T)llpos->lnum);
5267 if (llpos->col > 0)
5268 {
5269 list_append_number(l, (varnumber_T)llpos->col);
5270 list_append_number(l, (varnumber_T)llpos->len);
5271 }
5272 sprintf(buf, "pos%d", i + 1);
5273 dict_add_list(dict, buf, l);
5274 }
5275 }
5276 else
5277 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005278 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005279 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005280 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5281 dict_add_number(dict, "priority", (long)cur->priority);
5282 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005283# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5284 if (cur->conceal_char)
5285 {
5286 char_u buf[MB_MAXBYTES + 1];
5287
5288 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005289 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005290 }
5291# endif
5292 list_append_dict(rettv->vval.v_list, dict);
5293 cur = cur->next;
5294 }
5295 }
5296#endif
5297}
5298
5299/*
5300 * "getpid()" function
5301 */
5302 static void
5303f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5304{
5305 rettv->vval.v_number = mch_get_pid();
5306}
5307
5308 static void
5309getpos_both(
5310 typval_T *argvars,
5311 typval_T *rettv,
5312 int getcurpos)
5313{
5314 pos_T *fp;
5315 list_T *l;
5316 int fnum = -1;
5317
5318 if (rettv_list_alloc(rettv) == OK)
5319 {
5320 l = rettv->vval.v_list;
5321 if (getcurpos)
5322 fp = &curwin->w_cursor;
5323 else
5324 fp = var2fpos(&argvars[0], TRUE, &fnum);
5325 if (fnum != -1)
5326 list_append_number(l, (varnumber_T)fnum);
5327 else
5328 list_append_number(l, (varnumber_T)0);
5329 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5330 : (varnumber_T)0);
5331 list_append_number(l, (fp != NULL)
5332 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5333 : (varnumber_T)0);
5334 list_append_number(l,
5335#ifdef FEAT_VIRTUALEDIT
5336 (fp != NULL) ? (varnumber_T)fp->coladd :
5337#endif
5338 (varnumber_T)0);
5339 if (getcurpos)
5340 {
5341 update_curswant();
5342 list_append_number(l, curwin->w_curswant == MAXCOL ?
5343 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5344 }
5345 }
5346 else
5347 rettv->vval.v_number = FALSE;
5348}
5349
5350
5351/*
5352 * "getcurpos()" function
5353 */
5354 static void
5355f_getcurpos(typval_T *argvars, typval_T *rettv)
5356{
5357 getpos_both(argvars, rettv, TRUE);
5358}
5359
5360/*
5361 * "getpos(string)" function
5362 */
5363 static void
5364f_getpos(typval_T *argvars, typval_T *rettv)
5365{
5366 getpos_both(argvars, rettv, FALSE);
5367}
5368
5369/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005370 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005371 */
5372 static void
5373f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5374{
5375#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005376 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005377#endif
5378}
5379
5380/*
5381 * "getreg()" function
5382 */
5383 static void
5384f_getreg(typval_T *argvars, typval_T *rettv)
5385{
5386 char_u *strregname;
5387 int regname;
5388 int arg2 = FALSE;
5389 int return_list = FALSE;
5390 int error = FALSE;
5391
5392 if (argvars[0].v_type != VAR_UNKNOWN)
5393 {
5394 strregname = get_tv_string_chk(&argvars[0]);
5395 error = strregname == NULL;
5396 if (argvars[1].v_type != VAR_UNKNOWN)
5397 {
5398 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5399 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5400 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5401 }
5402 }
5403 else
5404 strregname = get_vim_var_str(VV_REG);
5405
5406 if (error)
5407 return;
5408
5409 regname = (strregname == NULL ? '"' : *strregname);
5410 if (regname == 0)
5411 regname = '"';
5412
5413 if (return_list)
5414 {
5415 rettv->v_type = VAR_LIST;
5416 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5417 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5418 if (rettv->vval.v_list == NULL)
5419 (void)rettv_list_alloc(rettv);
5420 else
5421 ++rettv->vval.v_list->lv_refcount;
5422 }
5423 else
5424 {
5425 rettv->v_type = VAR_STRING;
5426 rettv->vval.v_string = get_reg_contents(regname,
5427 arg2 ? GREG_EXPR_SRC : 0);
5428 }
5429}
5430
5431/*
5432 * "getregtype()" function
5433 */
5434 static void
5435f_getregtype(typval_T *argvars, typval_T *rettv)
5436{
5437 char_u *strregname;
5438 int regname;
5439 char_u buf[NUMBUFLEN + 2];
5440 long reglen = 0;
5441
5442 if (argvars[0].v_type != VAR_UNKNOWN)
5443 {
5444 strregname = get_tv_string_chk(&argvars[0]);
5445 if (strregname == NULL) /* type error; errmsg already given */
5446 {
5447 rettv->v_type = VAR_STRING;
5448 rettv->vval.v_string = NULL;
5449 return;
5450 }
5451 }
5452 else
5453 /* Default to v:register */
5454 strregname = get_vim_var_str(VV_REG);
5455
5456 regname = (strregname == NULL ? '"' : *strregname);
5457 if (regname == 0)
5458 regname = '"';
5459
5460 buf[0] = NUL;
5461 buf[1] = NUL;
5462 switch (get_reg_type(regname, &reglen))
5463 {
5464 case MLINE: buf[0] = 'V'; break;
5465 case MCHAR: buf[0] = 'v'; break;
5466 case MBLOCK:
5467 buf[0] = Ctrl_V;
5468 sprintf((char *)buf + 1, "%ld", reglen + 1);
5469 break;
5470 }
5471 rettv->v_type = VAR_STRING;
5472 rettv->vval.v_string = vim_strsave(buf);
5473}
5474
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005475/*
5476 * Returns information (variables, options, etc.) about a tab page
5477 * as a dictionary.
5478 */
5479 static dict_T *
5480get_tabpage_info(tabpage_T *tp, int tp_idx)
5481{
5482 win_T *wp;
5483 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005484 list_T *l;
5485
5486 dict = dict_alloc();
5487 if (dict == NULL)
5488 return NULL;
5489
Bram Moolenaare0be1672018-07-08 16:50:37 +02005490 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005491
5492 l = list_alloc();
5493 if (l != NULL)
5494 {
5495 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5496 wp; wp = wp->w_next)
5497 list_append_number(l, (varnumber_T)wp->w_id);
5498 dict_add_list(dict, "windows", l);
5499 }
5500
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005501 /* Make a reference to tabpage variables */
5502 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005503
5504 return dict;
5505}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005506
5507/*
5508 * "gettabinfo()" function
5509 */
5510 static void
5511f_gettabinfo(typval_T *argvars, typval_T *rettv)
5512{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005513 tabpage_T *tp, *tparg = NULL;
5514 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005515 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005516
5517 if (rettv_list_alloc(rettv) != OK)
5518 return;
5519
5520 if (argvars[0].v_type != VAR_UNKNOWN)
5521 {
5522 /* Information about one tab page */
5523 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5524 if (tparg == NULL)
5525 return;
5526 }
5527
5528 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005529 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005530 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005531 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005532 if (tparg != NULL && tp != tparg)
5533 continue;
5534 d = get_tabpage_info(tp, tpnr);
5535 if (d != NULL)
5536 list_append_dict(rettv->vval.v_list, d);
5537 if (tparg != NULL)
5538 return;
5539 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005540}
5541
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005542/*
5543 * "gettabvar()" function
5544 */
5545 static void
5546f_gettabvar(typval_T *argvars, typval_T *rettv)
5547{
5548 win_T *oldcurwin;
5549 tabpage_T *tp, *oldtabpage;
5550 dictitem_T *v;
5551 char_u *varname;
5552 int done = FALSE;
5553
5554 rettv->v_type = VAR_STRING;
5555 rettv->vval.v_string = NULL;
5556
5557 varname = get_tv_string_chk(&argvars[1]);
5558 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5559 if (tp != NULL && varname != NULL)
5560 {
5561 /* Set tp to be our tabpage, temporarily. Also set the window to the
5562 * first window in the tabpage, otherwise the window is not valid. */
5563 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005564 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5565 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005566 {
5567 /* look up the variable */
5568 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5569 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5570 if (v != NULL)
5571 {
5572 copy_tv(&v->di_tv, rettv);
5573 done = TRUE;
5574 }
5575 }
5576
5577 /* restore previous notion of curwin */
5578 restore_win(oldcurwin, oldtabpage, TRUE);
5579 }
5580
5581 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5582 copy_tv(&argvars[2], rettv);
5583}
5584
5585/*
5586 * "gettabwinvar()" function
5587 */
5588 static void
5589f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5590{
5591 getwinvar(argvars, rettv, 1);
5592}
5593
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005594/*
5595 * Returns information about a window as a dictionary.
5596 */
5597 static dict_T *
5598get_win_info(win_T *wp, short tpnr, short winnr)
5599{
5600 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005601
5602 dict = dict_alloc();
5603 if (dict == NULL)
5604 return NULL;
5605
Bram Moolenaare0be1672018-07-08 16:50:37 +02005606 dict_add_number(dict, "tabnr", tpnr);
5607 dict_add_number(dict, "winnr", winnr);
5608 dict_add_number(dict, "winid", wp->w_id);
5609 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005610 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005611#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005612 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005613#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005614 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005615 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005616 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005617
Bram Moolenaar69905d12017-08-13 18:14:47 +02005618#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005619 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005620#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005621#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005622 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5623 dict_add_number(dict, "loclist",
5624 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005625#endif
5626
Bram Moolenaar30567352016-08-27 21:25:44 +02005627 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005628 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005629
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005630 return dict;
5631}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632
5633/*
5634 * "getwininfo()" function
5635 */
5636 static void
5637f_getwininfo(typval_T *argvars, typval_T *rettv)
5638{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005639 tabpage_T *tp;
5640 win_T *wp = NULL, *wparg = NULL;
5641 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005642 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005643
5644 if (rettv_list_alloc(rettv) != OK)
5645 return;
5646
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005647 if (argvars[0].v_type != VAR_UNKNOWN)
5648 {
5649 wparg = win_id2wp(argvars);
5650 if (wparg == NULL)
5651 return;
5652 }
5653
5654 /* Collect information about either all the windows across all the tab
5655 * pages or one particular window.
5656 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005657 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005658 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005659 tabnr++;
5660 winnr = 0;
5661 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005662 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005663 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005664 if (wparg != NULL && wp != wparg)
5665 continue;
5666 d = get_win_info(wp, tabnr, winnr);
5667 if (d != NULL)
5668 list_append_dict(rettv->vval.v_list, d);
5669 if (wparg != NULL)
5670 /* found information about a specific window */
5671 return;
5672 }
5673 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005674}
5675
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005676/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005677 * "win_findbuf()" function
5678 */
5679 static void
5680f_win_findbuf(typval_T *argvars, typval_T *rettv)
5681{
5682 if (rettv_list_alloc(rettv) != FAIL)
5683 win_findbuf(argvars, rettv->vval.v_list);
5684}
5685
5686/*
5687 * "win_getid()" function
5688 */
5689 static void
5690f_win_getid(typval_T *argvars, typval_T *rettv)
5691{
5692 rettv->vval.v_number = win_getid(argvars);
5693}
5694
5695/*
5696 * "win_gotoid()" function
5697 */
5698 static void
5699f_win_gotoid(typval_T *argvars, typval_T *rettv)
5700{
5701 rettv->vval.v_number = win_gotoid(argvars);
5702}
5703
5704/*
5705 * "win_id2tabwin()" function
5706 */
5707 static void
5708f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5709{
5710 if (rettv_list_alloc(rettv) != FAIL)
5711 win_id2tabwin(argvars, rettv->vval.v_list);
5712}
5713
5714/*
5715 * "win_id2win()" function
5716 */
5717 static void
5718f_win_id2win(typval_T *argvars, typval_T *rettv)
5719{
5720 rettv->vval.v_number = win_id2win(argvars);
5721}
5722
5723/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005724 * "win_screenpos()" function
5725 */
5726 static void
5727f_win_screenpos(typval_T *argvars, typval_T *rettv)
5728{
5729 win_T *wp;
5730
5731 if (rettv_list_alloc(rettv) == FAIL)
5732 return;
5733
5734 wp = find_win_by_nr(&argvars[0], NULL);
5735 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5736 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5737}
5738
5739/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005740 * "getwinpos({timeout})" function
5741 */
5742 static void
5743f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5744{
5745 int x = -1;
5746 int y = -1;
5747
5748 if (rettv_list_alloc(rettv) == FAIL)
5749 return;
5750#ifdef FEAT_GUI
5751 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005752 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005753# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5754 else
5755# endif
5756#endif
5757#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5758 {
5759 varnumber_T timeout = 100;
5760
5761 if (argvars[0].v_type != VAR_UNKNOWN)
5762 timeout = get_tv_number(&argvars[0]);
5763 term_get_winpos(&x, &y, timeout);
5764 }
5765#endif
5766 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5767 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5768}
5769
5770
5771/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005772 * "getwinposx()" function
5773 */
5774 static void
5775f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5776{
5777 rettv->vval.v_number = -1;
5778#ifdef FEAT_GUI
5779 if (gui.in_use)
5780 {
5781 int x, y;
5782
5783 if (gui_mch_get_winpos(&x, &y) == OK)
5784 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005785 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005786 }
5787#endif
5788#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5789 {
5790 int x, y;
5791
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005792 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005793 rettv->vval.v_number = x;
5794 }
5795#endif
5796}
5797
5798/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 * "getwinposy()" function
5800 */
5801 static void
5802f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5803{
5804 rettv->vval.v_number = -1;
5805#ifdef FEAT_GUI
5806 if (gui.in_use)
5807 {
5808 int x, y;
5809
5810 if (gui_mch_get_winpos(&x, &y) == OK)
5811 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005812 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005813 }
5814#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005815#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5816 {
5817 int x, y;
5818
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005819 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005820 rettv->vval.v_number = y;
5821 }
5822#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005823}
5824
5825/*
5826 * "getwinvar()" function
5827 */
5828 static void
5829f_getwinvar(typval_T *argvars, typval_T *rettv)
5830{
5831 getwinvar(argvars, rettv, 0);
5832}
5833
5834/*
5835 * "glob()" function
5836 */
5837 static void
5838f_glob(typval_T *argvars, typval_T *rettv)
5839{
5840 int options = WILD_SILENT|WILD_USE_NL;
5841 expand_T xpc;
5842 int error = FALSE;
5843
5844 /* When the optional second argument is non-zero, don't remove matches
5845 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5846 rettv->v_type = VAR_STRING;
5847 if (argvars[1].v_type != VAR_UNKNOWN)
5848 {
5849 if (get_tv_number_chk(&argvars[1], &error))
5850 options |= WILD_KEEP_ALL;
5851 if (argvars[2].v_type != VAR_UNKNOWN)
5852 {
5853 if (get_tv_number_chk(&argvars[2], &error))
5854 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005855 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005856 }
5857 if (argvars[3].v_type != VAR_UNKNOWN
5858 && get_tv_number_chk(&argvars[3], &error))
5859 options |= WILD_ALLLINKS;
5860 }
5861 }
5862 if (!error)
5863 {
5864 ExpandInit(&xpc);
5865 xpc.xp_context = EXPAND_FILES;
5866 if (p_wic)
5867 options += WILD_ICASE;
5868 if (rettv->v_type == VAR_STRING)
5869 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5870 NULL, options, WILD_ALL);
5871 else if (rettv_list_alloc(rettv) != FAIL)
5872 {
5873 int i;
5874
5875 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5876 NULL, options, WILD_ALL_KEEP);
5877 for (i = 0; i < xpc.xp_numfiles; i++)
5878 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5879
5880 ExpandCleanup(&xpc);
5881 }
5882 }
5883 else
5884 rettv->vval.v_string = NULL;
5885}
5886
5887/*
5888 * "globpath()" function
5889 */
5890 static void
5891f_globpath(typval_T *argvars, typval_T *rettv)
5892{
5893 int flags = 0;
5894 char_u buf1[NUMBUFLEN];
5895 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5896 int error = FALSE;
5897 garray_T ga;
5898 int i;
5899
5900 /* When the optional second argument is non-zero, don't remove matches
5901 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5902 rettv->v_type = VAR_STRING;
5903 if (argvars[2].v_type != VAR_UNKNOWN)
5904 {
5905 if (get_tv_number_chk(&argvars[2], &error))
5906 flags |= WILD_KEEP_ALL;
5907 if (argvars[3].v_type != VAR_UNKNOWN)
5908 {
5909 if (get_tv_number_chk(&argvars[3], &error))
5910 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005911 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912 }
5913 if (argvars[4].v_type != VAR_UNKNOWN
5914 && get_tv_number_chk(&argvars[4], &error))
5915 flags |= WILD_ALLLINKS;
5916 }
5917 }
5918 if (file != NULL && !error)
5919 {
5920 ga_init2(&ga, (int)sizeof(char_u *), 10);
5921 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5922 if (rettv->v_type == VAR_STRING)
5923 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5924 else if (rettv_list_alloc(rettv) != FAIL)
5925 for (i = 0; i < ga.ga_len; ++i)
5926 list_append_string(rettv->vval.v_list,
5927 ((char_u **)(ga.ga_data))[i], -1);
5928 ga_clear_strings(&ga);
5929 }
5930 else
5931 rettv->vval.v_string = NULL;
5932}
5933
5934/*
5935 * "glob2regpat()" function
5936 */
5937 static void
5938f_glob2regpat(typval_T *argvars, typval_T *rettv)
5939{
5940 char_u *pat = get_tv_string_chk(&argvars[0]);
5941
5942 rettv->v_type = VAR_STRING;
5943 rettv->vval.v_string = (pat == NULL)
5944 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5945}
5946
5947/* for VIM_VERSION_ defines */
5948#include "version.h"
5949
5950/*
5951 * "has()" function
5952 */
5953 static void
5954f_has(typval_T *argvars, typval_T *rettv)
5955{
5956 int i;
5957 char_u *name;
5958 int n = FALSE;
5959 static char *(has_list[]) =
5960 {
5961#ifdef AMIGA
5962 "amiga",
5963# ifdef FEAT_ARP
5964 "arp",
5965# endif
5966#endif
5967#ifdef __BEOS__
5968 "beos",
5969#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005970#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005971 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5972 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005973# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005974 "macunix", /* Mac OS X, with the darwin feature */
5975 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005976# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005977#endif
5978#ifdef __QNX__
5979 "qnx",
5980#endif
5981#ifdef UNIX
5982 "unix",
5983#endif
5984#ifdef VMS
5985 "vms",
5986#endif
5987#ifdef WIN32
5988 "win32",
5989#endif
5990#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5991 "win32unix",
5992#endif
5993#if defined(WIN64) || defined(_WIN64)
5994 "win64",
5995#endif
5996#ifdef EBCDIC
5997 "ebcdic",
5998#endif
5999#ifndef CASE_INSENSITIVE_FILENAME
6000 "fname_case",
6001#endif
6002#ifdef HAVE_ACL
6003 "acl",
6004#endif
6005#ifdef FEAT_ARABIC
6006 "arabic",
6007#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006008 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006009#ifdef FEAT_AUTOCHDIR
6010 "autochdir",
6011#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006012#ifdef FEAT_AUTOSERVERNAME
6013 "autoservername",
6014#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006015#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006016 "balloon_eval",
6017# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6018 "balloon_multiline",
6019# endif
6020#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006021#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006022 "balloon_eval_term",
6023#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6025 "builtin_terms",
6026# ifdef ALL_BUILTIN_TCAPS
6027 "all_builtin_terms",
6028# endif
6029#endif
6030#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6031 || defined(FEAT_GUI_W32) \
6032 || defined(FEAT_GUI_MOTIF))
6033 "browsefilter",
6034#endif
6035#ifdef FEAT_BYTEOFF
6036 "byte_offset",
6037#endif
6038#ifdef FEAT_JOB_CHANNEL
6039 "channel",
6040#endif
6041#ifdef FEAT_CINDENT
6042 "cindent",
6043#endif
6044#ifdef FEAT_CLIENTSERVER
6045 "clientserver",
6046#endif
6047#ifdef FEAT_CLIPBOARD
6048 "clipboard",
6049#endif
6050#ifdef FEAT_CMDL_COMPL
6051 "cmdline_compl",
6052#endif
6053#ifdef FEAT_CMDHIST
6054 "cmdline_hist",
6055#endif
6056#ifdef FEAT_COMMENTS
6057 "comments",
6058#endif
6059#ifdef FEAT_CONCEAL
6060 "conceal",
6061#endif
6062#ifdef FEAT_CRYPT
6063 "cryptv",
6064 "crypt-blowfish",
6065 "crypt-blowfish2",
6066#endif
6067#ifdef FEAT_CSCOPE
6068 "cscope",
6069#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006070 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006071#ifdef CURSOR_SHAPE
6072 "cursorshape",
6073#endif
6074#ifdef DEBUG
6075 "debug",
6076#endif
6077#ifdef FEAT_CON_DIALOG
6078 "dialog_con",
6079#endif
6080#ifdef FEAT_GUI_DIALOG
6081 "dialog_gui",
6082#endif
6083#ifdef FEAT_DIFF
6084 "diff",
6085#endif
6086#ifdef FEAT_DIGRAPHS
6087 "digraphs",
6088#endif
6089#ifdef FEAT_DIRECTX
6090 "directx",
6091#endif
6092#ifdef FEAT_DND
6093 "dnd",
6094#endif
6095#ifdef FEAT_EMACS_TAGS
6096 "emacs_tags",
6097#endif
6098 "eval", /* always present, of course! */
6099 "ex_extra", /* graduated feature */
6100#ifdef FEAT_SEARCH_EXTRA
6101 "extra_search",
6102#endif
6103#ifdef FEAT_FKMAP
6104 "farsi",
6105#endif
6106#ifdef FEAT_SEARCHPATH
6107 "file_in_path",
6108#endif
6109#ifdef FEAT_FILTERPIPE
6110 "filterpipe",
6111#endif
6112#ifdef FEAT_FIND_ID
6113 "find_in_path",
6114#endif
6115#ifdef FEAT_FLOAT
6116 "float",
6117#endif
6118#ifdef FEAT_FOLDING
6119 "folding",
6120#endif
6121#ifdef FEAT_FOOTER
6122 "footer",
6123#endif
6124#if !defined(USE_SYSTEM) && defined(UNIX)
6125 "fork",
6126#endif
6127#ifdef FEAT_GETTEXT
6128 "gettext",
6129#endif
6130#ifdef FEAT_GUI
6131 "gui",
6132#endif
6133#ifdef FEAT_GUI_ATHENA
6134# ifdef FEAT_GUI_NEXTAW
6135 "gui_neXtaw",
6136# else
6137 "gui_athena",
6138# endif
6139#endif
6140#ifdef FEAT_GUI_GTK
6141 "gui_gtk",
6142# ifdef USE_GTK3
6143 "gui_gtk3",
6144# else
6145 "gui_gtk2",
6146# endif
6147#endif
6148#ifdef FEAT_GUI_GNOME
6149 "gui_gnome",
6150#endif
6151#ifdef FEAT_GUI_MAC
6152 "gui_mac",
6153#endif
6154#ifdef FEAT_GUI_MOTIF
6155 "gui_motif",
6156#endif
6157#ifdef FEAT_GUI_PHOTON
6158 "gui_photon",
6159#endif
6160#ifdef FEAT_GUI_W32
6161 "gui_win32",
6162#endif
6163#ifdef FEAT_HANGULIN
6164 "hangul_input",
6165#endif
6166#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6167 "iconv",
6168#endif
6169#ifdef FEAT_INS_EXPAND
6170 "insert_expand",
6171#endif
6172#ifdef FEAT_JOB_CHANNEL
6173 "job",
6174#endif
6175#ifdef FEAT_JUMPLIST
6176 "jumplist",
6177#endif
6178#ifdef FEAT_KEYMAP
6179 "keymap",
6180#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006181 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182#ifdef FEAT_LANGMAP
6183 "langmap",
6184#endif
6185#ifdef FEAT_LIBCALL
6186 "libcall",
6187#endif
6188#ifdef FEAT_LINEBREAK
6189 "linebreak",
6190#endif
6191#ifdef FEAT_LISP
6192 "lispindent",
6193#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195#ifdef FEAT_LOCALMAP
6196 "localmap",
6197#endif
6198#ifdef FEAT_LUA
6199# ifndef DYNAMIC_LUA
6200 "lua",
6201# endif
6202#endif
6203#ifdef FEAT_MENU
6204 "menu",
6205#endif
6206#ifdef FEAT_SESSION
6207 "mksession",
6208#endif
6209#ifdef FEAT_MODIFY_FNAME
6210 "modify_fname",
6211#endif
6212#ifdef FEAT_MOUSE
6213 "mouse",
6214#endif
6215#ifdef FEAT_MOUSESHAPE
6216 "mouseshape",
6217#endif
6218#if defined(UNIX) || defined(VMS)
6219# ifdef FEAT_MOUSE_DEC
6220 "mouse_dec",
6221# endif
6222# ifdef FEAT_MOUSE_GPM
6223 "mouse_gpm",
6224# endif
6225# ifdef FEAT_MOUSE_JSB
6226 "mouse_jsbterm",
6227# endif
6228# ifdef FEAT_MOUSE_NET
6229 "mouse_netterm",
6230# endif
6231# ifdef FEAT_MOUSE_PTERM
6232 "mouse_pterm",
6233# endif
6234# ifdef FEAT_MOUSE_SGR
6235 "mouse_sgr",
6236# endif
6237# ifdef FEAT_SYSMOUSE
6238 "mouse_sysmouse",
6239# endif
6240# ifdef FEAT_MOUSE_URXVT
6241 "mouse_urxvt",
6242# endif
6243# ifdef FEAT_MOUSE_XTERM
6244 "mouse_xterm",
6245# endif
6246#endif
6247#ifdef FEAT_MBYTE
6248 "multi_byte",
6249#endif
6250#ifdef FEAT_MBYTE_IME
6251 "multi_byte_ime",
6252#endif
6253#ifdef FEAT_MULTI_LANG
6254 "multi_lang",
6255#endif
6256#ifdef FEAT_MZSCHEME
6257#ifndef DYNAMIC_MZSCHEME
6258 "mzscheme",
6259#endif
6260#endif
6261#ifdef FEAT_NUM64
6262 "num64",
6263#endif
6264#ifdef FEAT_OLE
6265 "ole",
6266#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006267#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006269#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270#ifdef FEAT_PATH_EXTRA
6271 "path_extra",
6272#endif
6273#ifdef FEAT_PERL
6274#ifndef DYNAMIC_PERL
6275 "perl",
6276#endif
6277#endif
6278#ifdef FEAT_PERSISTENT_UNDO
6279 "persistent_undo",
6280#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006281#if defined(FEAT_PYTHON)
6282 "python_compiled",
6283# if defined(DYNAMIC_PYTHON)
6284 "python_dynamic",
6285# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006286 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006287 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006288# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006289#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006290#if defined(FEAT_PYTHON3)
6291 "python3_compiled",
6292# if defined(DYNAMIC_PYTHON3)
6293 "python3_dynamic",
6294# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006295 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006296 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006297# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006298#endif
6299#ifdef FEAT_POSTSCRIPT
6300 "postscript",
6301#endif
6302#ifdef FEAT_PRINTER
6303 "printer",
6304#endif
6305#ifdef FEAT_PROFILE
6306 "profile",
6307#endif
6308#ifdef FEAT_RELTIME
6309 "reltime",
6310#endif
6311#ifdef FEAT_QUICKFIX
6312 "quickfix",
6313#endif
6314#ifdef FEAT_RIGHTLEFT
6315 "rightleft",
6316#endif
6317#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6318 "ruby",
6319#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006320 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321#ifdef FEAT_CMDL_INFO
6322 "showcmd",
6323 "cmdline_info",
6324#endif
6325#ifdef FEAT_SIGNS
6326 "signs",
6327#endif
6328#ifdef FEAT_SMARTINDENT
6329 "smartindent",
6330#endif
6331#ifdef STARTUPTIME
6332 "startuptime",
6333#endif
6334#ifdef FEAT_STL_OPT
6335 "statusline",
6336#endif
6337#ifdef FEAT_SUN_WORKSHOP
6338 "sun_workshop",
6339#endif
6340#ifdef FEAT_NETBEANS_INTG
6341 "netbeans_intg",
6342#endif
6343#ifdef FEAT_SPELL
6344 "spell",
6345#endif
6346#ifdef FEAT_SYN_HL
6347 "syntax",
6348#endif
6349#if defined(USE_SYSTEM) || !defined(UNIX)
6350 "system",
6351#endif
6352#ifdef FEAT_TAG_BINS
6353 "tag_binary",
6354#endif
6355#ifdef FEAT_TAG_OLDSTATIC
6356 "tag_old_static",
6357#endif
6358#ifdef FEAT_TAG_ANYWHITE
6359 "tag_any_white",
6360#endif
6361#ifdef FEAT_TCL
6362# ifndef DYNAMIC_TCL
6363 "tcl",
6364# endif
6365#endif
6366#ifdef FEAT_TERMGUICOLORS
6367 "termguicolors",
6368#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006369#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006370 "terminal",
6371#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372#ifdef TERMINFO
6373 "terminfo",
6374#endif
6375#ifdef FEAT_TERMRESPONSE
6376 "termresponse",
6377#endif
6378#ifdef FEAT_TEXTOBJ
6379 "textobjects",
6380#endif
6381#ifdef HAVE_TGETENT
6382 "tgetent",
6383#endif
6384#ifdef FEAT_TIMERS
6385 "timers",
6386#endif
6387#ifdef FEAT_TITLE
6388 "title",
6389#endif
6390#ifdef FEAT_TOOLBAR
6391 "toolbar",
6392#endif
6393#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6394 "unnamedplus",
6395#endif
6396#ifdef FEAT_USR_CMDS
6397 "user-commands", /* was accidentally included in 5.4 */
6398 "user_commands",
6399#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006400#ifdef FEAT_VARTABS
6401 "vartabs",
6402#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006403#ifdef FEAT_VIMINFO
6404 "viminfo",
6405#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006407#ifdef FEAT_VIRTUALEDIT
6408 "virtualedit",
6409#endif
6410 "visual",
6411#ifdef FEAT_VISUALEXTRA
6412 "visualextra",
6413#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006414 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006415#ifdef FEAT_VTP
6416 "vtp",
6417#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006418#ifdef FEAT_WILDIGN
6419 "wildignore",
6420#endif
6421#ifdef FEAT_WILDMENU
6422 "wildmenu",
6423#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006424 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006425#ifdef FEAT_WAK
6426 "winaltkeys",
6427#endif
6428#ifdef FEAT_WRITEBACKUP
6429 "writebackup",
6430#endif
6431#ifdef FEAT_XIM
6432 "xim",
6433#endif
6434#ifdef FEAT_XFONTSET
6435 "xfontset",
6436#endif
6437#ifdef FEAT_XPM_W32
6438 "xpm",
6439 "xpm_w32", /* for backward compatibility */
6440#else
6441# if defined(HAVE_XPM)
6442 "xpm",
6443# endif
6444#endif
6445#ifdef USE_XSMP
6446 "xsmp",
6447#endif
6448#ifdef USE_XSMP_INTERACT
6449 "xsmp_interact",
6450#endif
6451#ifdef FEAT_XCLIPBOARD
6452 "xterm_clipboard",
6453#endif
6454#ifdef FEAT_XTERM_SAVE
6455 "xterm_save",
6456#endif
6457#if defined(UNIX) && defined(FEAT_X11)
6458 "X11",
6459#endif
6460 NULL
6461 };
6462
6463 name = get_tv_string(&argvars[0]);
6464 for (i = 0; has_list[i] != NULL; ++i)
6465 if (STRICMP(name, has_list[i]) == 0)
6466 {
6467 n = TRUE;
6468 break;
6469 }
6470
6471 if (n == FALSE)
6472 {
6473 if (STRNICMP(name, "patch", 5) == 0)
6474 {
6475 if (name[5] == '-'
6476 && STRLEN(name) >= 11
6477 && vim_isdigit(name[6])
6478 && vim_isdigit(name[8])
6479 && vim_isdigit(name[10]))
6480 {
6481 int major = atoi((char *)name + 6);
6482 int minor = atoi((char *)name + 8);
6483
6484 /* Expect "patch-9.9.01234". */
6485 n = (major < VIM_VERSION_MAJOR
6486 || (major == VIM_VERSION_MAJOR
6487 && (minor < VIM_VERSION_MINOR
6488 || (minor == VIM_VERSION_MINOR
6489 && has_patch(atoi((char *)name + 10))))));
6490 }
6491 else
6492 n = has_patch(atoi((char *)name + 5));
6493 }
6494 else if (STRICMP(name, "vim_starting") == 0)
6495 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006496 else if (STRICMP(name, "ttyin") == 0)
6497 n = mch_input_isatty();
6498 else if (STRICMP(name, "ttyout") == 0)
6499 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500#ifdef FEAT_MBYTE
6501 else if (STRICMP(name, "multi_byte_encoding") == 0)
6502 n = has_mbyte;
6503#endif
6504#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6505 else if (STRICMP(name, "balloon_multiline") == 0)
6506 n = multiline_balloon_available();
6507#endif
6508#ifdef DYNAMIC_TCL
6509 else if (STRICMP(name, "tcl") == 0)
6510 n = tcl_enabled(FALSE);
6511#endif
6512#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6513 else if (STRICMP(name, "iconv") == 0)
6514 n = iconv_enabled(FALSE);
6515#endif
6516#ifdef DYNAMIC_LUA
6517 else if (STRICMP(name, "lua") == 0)
6518 n = lua_enabled(FALSE);
6519#endif
6520#ifdef DYNAMIC_MZSCHEME
6521 else if (STRICMP(name, "mzscheme") == 0)
6522 n = mzscheme_enabled(FALSE);
6523#endif
6524#ifdef DYNAMIC_RUBY
6525 else if (STRICMP(name, "ruby") == 0)
6526 n = ruby_enabled(FALSE);
6527#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006528#ifdef DYNAMIC_PYTHON
6529 else if (STRICMP(name, "python") == 0)
6530 n = python_enabled(FALSE);
6531#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006532#ifdef DYNAMIC_PYTHON3
6533 else if (STRICMP(name, "python3") == 0)
6534 n = python3_enabled(FALSE);
6535#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006536#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6537 else if (STRICMP(name, "pythonx") == 0)
6538 {
6539# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6540 if (p_pyx == 0)
6541 n = python3_enabled(FALSE) || python_enabled(FALSE);
6542 else if (p_pyx == 3)
6543 n = python3_enabled(FALSE);
6544 else if (p_pyx == 2)
6545 n = python_enabled(FALSE);
6546# elif defined(DYNAMIC_PYTHON)
6547 n = python_enabled(FALSE);
6548# elif defined(DYNAMIC_PYTHON3)
6549 n = python3_enabled(FALSE);
6550# endif
6551 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006552#endif
6553#ifdef DYNAMIC_PERL
6554 else if (STRICMP(name, "perl") == 0)
6555 n = perl_enabled(FALSE);
6556#endif
6557#ifdef FEAT_GUI
6558 else if (STRICMP(name, "gui_running") == 0)
6559 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560# ifdef FEAT_BROWSE
6561 else if (STRICMP(name, "browse") == 0)
6562 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6563# endif
6564#endif
6565#ifdef FEAT_SYN_HL
6566 else if (STRICMP(name, "syntax_items") == 0)
6567 n = syntax_present(curwin);
6568#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006569#ifdef FEAT_VTP
6570 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006571 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006572#endif
6573#ifdef FEAT_NETBEANS_INTG
6574 else if (STRICMP(name, "netbeans_enabled") == 0)
6575 n = netbeans_active();
6576#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006577#if defined(FEAT_TERMINAL) && defined(WIN3264)
6578 else if (STRICMP(name, "terminal") == 0)
6579 n = terminal_enabled();
6580#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006581 }
6582
6583 rettv->vval.v_number = n;
6584}
6585
6586/*
6587 * "has_key()" function
6588 */
6589 static void
6590f_has_key(typval_T *argvars, typval_T *rettv)
6591{
6592 if (argvars[0].v_type != VAR_DICT)
6593 {
6594 EMSG(_(e_dictreq));
6595 return;
6596 }
6597 if (argvars[0].vval.v_dict == NULL)
6598 return;
6599
6600 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6601 get_tv_string(&argvars[1]), -1) != NULL;
6602}
6603
6604/*
6605 * "haslocaldir()" function
6606 */
6607 static void
6608f_haslocaldir(typval_T *argvars, typval_T *rettv)
6609{
6610 win_T *wp = NULL;
6611
6612 wp = find_tabwin(&argvars[0], &argvars[1]);
6613 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6614}
6615
6616/*
6617 * "hasmapto()" function
6618 */
6619 static void
6620f_hasmapto(typval_T *argvars, typval_T *rettv)
6621{
6622 char_u *name;
6623 char_u *mode;
6624 char_u buf[NUMBUFLEN];
6625 int abbr = FALSE;
6626
6627 name = get_tv_string(&argvars[0]);
6628 if (argvars[1].v_type == VAR_UNKNOWN)
6629 mode = (char_u *)"nvo";
6630 else
6631 {
6632 mode = get_tv_string_buf(&argvars[1], buf);
6633 if (argvars[2].v_type != VAR_UNKNOWN)
6634 abbr = (int)get_tv_number(&argvars[2]);
6635 }
6636
6637 if (map_to_exists(name, mode, abbr))
6638 rettv->vval.v_number = TRUE;
6639 else
6640 rettv->vval.v_number = FALSE;
6641}
6642
6643/*
6644 * "histadd()" function
6645 */
6646 static void
6647f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6648{
6649#ifdef FEAT_CMDHIST
6650 int histype;
6651 char_u *str;
6652 char_u buf[NUMBUFLEN];
6653#endif
6654
6655 rettv->vval.v_number = FALSE;
6656 if (check_restricted() || check_secure())
6657 return;
6658#ifdef FEAT_CMDHIST
6659 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6660 histype = str != NULL ? get_histtype(str) : -1;
6661 if (histype >= 0)
6662 {
6663 str = get_tv_string_buf(&argvars[1], buf);
6664 if (*str != NUL)
6665 {
6666 init_history();
6667 add_to_history(histype, str, FALSE, NUL);
6668 rettv->vval.v_number = TRUE;
6669 return;
6670 }
6671 }
6672#endif
6673}
6674
6675/*
6676 * "histdel()" function
6677 */
6678 static void
6679f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6680{
6681#ifdef FEAT_CMDHIST
6682 int n;
6683 char_u buf[NUMBUFLEN];
6684 char_u *str;
6685
6686 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6687 if (str == NULL)
6688 n = 0;
6689 else if (argvars[1].v_type == VAR_UNKNOWN)
6690 /* only one argument: clear entire history */
6691 n = clr_history(get_histtype(str));
6692 else if (argvars[1].v_type == VAR_NUMBER)
6693 /* index given: remove that entry */
6694 n = del_history_idx(get_histtype(str),
6695 (int)get_tv_number(&argvars[1]));
6696 else
6697 /* string given: remove all matching entries */
6698 n = del_history_entry(get_histtype(str),
6699 get_tv_string_buf(&argvars[1], buf));
6700 rettv->vval.v_number = n;
6701#endif
6702}
6703
6704/*
6705 * "histget()" function
6706 */
6707 static void
6708f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6709{
6710#ifdef FEAT_CMDHIST
6711 int type;
6712 int idx;
6713 char_u *str;
6714
6715 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6716 if (str == NULL)
6717 rettv->vval.v_string = NULL;
6718 else
6719 {
6720 type = get_histtype(str);
6721 if (argvars[1].v_type == VAR_UNKNOWN)
6722 idx = get_history_idx(type);
6723 else
6724 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6725 /* -1 on type error */
6726 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6727 }
6728#else
6729 rettv->vval.v_string = NULL;
6730#endif
6731 rettv->v_type = VAR_STRING;
6732}
6733
6734/*
6735 * "histnr()" function
6736 */
6737 static void
6738f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6739{
6740 int i;
6741
6742#ifdef FEAT_CMDHIST
6743 char_u *history = get_tv_string_chk(&argvars[0]);
6744
6745 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6746 if (i >= HIST_CMD && i < HIST_COUNT)
6747 i = get_history_idx(i);
6748 else
6749#endif
6750 i = -1;
6751 rettv->vval.v_number = i;
6752}
6753
6754/*
6755 * "highlightID(name)" function
6756 */
6757 static void
6758f_hlID(typval_T *argvars, typval_T *rettv)
6759{
6760 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6761}
6762
6763/*
6764 * "highlight_exists()" function
6765 */
6766 static void
6767f_hlexists(typval_T *argvars, typval_T *rettv)
6768{
6769 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6770}
6771
6772/*
6773 * "hostname()" function
6774 */
6775 static void
6776f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6777{
6778 char_u hostname[256];
6779
6780 mch_get_host_name(hostname, 256);
6781 rettv->v_type = VAR_STRING;
6782 rettv->vval.v_string = vim_strsave(hostname);
6783}
6784
6785/*
6786 * iconv() function
6787 */
6788 static void
6789f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6790{
6791#ifdef FEAT_MBYTE
6792 char_u buf1[NUMBUFLEN];
6793 char_u buf2[NUMBUFLEN];
6794 char_u *from, *to, *str;
6795 vimconv_T vimconv;
6796#endif
6797
6798 rettv->v_type = VAR_STRING;
6799 rettv->vval.v_string = NULL;
6800
6801#ifdef FEAT_MBYTE
6802 str = get_tv_string(&argvars[0]);
6803 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6804 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6805 vimconv.vc_type = CONV_NONE;
6806 convert_setup(&vimconv, from, to);
6807
6808 /* If the encodings are equal, no conversion needed. */
6809 if (vimconv.vc_type == CONV_NONE)
6810 rettv->vval.v_string = vim_strsave(str);
6811 else
6812 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6813
6814 convert_setup(&vimconv, NULL, NULL);
6815 vim_free(from);
6816 vim_free(to);
6817#endif
6818}
6819
6820/*
6821 * "indent()" function
6822 */
6823 static void
6824f_indent(typval_T *argvars, typval_T *rettv)
6825{
6826 linenr_T lnum;
6827
6828 lnum = get_tv_lnum(argvars);
6829 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6830 rettv->vval.v_number = get_indent_lnum(lnum);
6831 else
6832 rettv->vval.v_number = -1;
6833}
6834
6835/*
6836 * "index()" function
6837 */
6838 static void
6839f_index(typval_T *argvars, typval_T *rettv)
6840{
6841 list_T *l;
6842 listitem_T *item;
6843 long idx = 0;
6844 int ic = FALSE;
6845
6846 rettv->vval.v_number = -1;
6847 if (argvars[0].v_type != VAR_LIST)
6848 {
6849 EMSG(_(e_listreq));
6850 return;
6851 }
6852 l = argvars[0].vval.v_list;
6853 if (l != NULL)
6854 {
6855 item = l->lv_first;
6856 if (argvars[2].v_type != VAR_UNKNOWN)
6857 {
6858 int error = FALSE;
6859
6860 /* Start at specified item. Use the cached index that list_find()
6861 * sets, so that a negative number also works. */
6862 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6863 idx = l->lv_idx;
6864 if (argvars[3].v_type != VAR_UNKNOWN)
6865 ic = (int)get_tv_number_chk(&argvars[3], &error);
6866 if (error)
6867 item = NULL;
6868 }
6869
6870 for ( ; item != NULL; item = item->li_next, ++idx)
6871 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6872 {
6873 rettv->vval.v_number = idx;
6874 break;
6875 }
6876 }
6877}
6878
6879static int inputsecret_flag = 0;
6880
6881/*
6882 * "input()" function
6883 * Also handles inputsecret() when inputsecret is set.
6884 */
6885 static void
6886f_input(typval_T *argvars, typval_T *rettv)
6887{
6888 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6889}
6890
6891/*
6892 * "inputdialog()" function
6893 */
6894 static void
6895f_inputdialog(typval_T *argvars, typval_T *rettv)
6896{
6897#if defined(FEAT_GUI_TEXTDIALOG)
6898 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6899 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6900 {
6901 char_u *message;
6902 char_u buf[NUMBUFLEN];
6903 char_u *defstr = (char_u *)"";
6904
6905 message = get_tv_string_chk(&argvars[0]);
6906 if (argvars[1].v_type != VAR_UNKNOWN
6907 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6908 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6909 else
6910 IObuff[0] = NUL;
6911 if (message != NULL && defstr != NULL
6912 && do_dialog(VIM_QUESTION, NULL, message,
6913 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6914 rettv->vval.v_string = vim_strsave(IObuff);
6915 else
6916 {
6917 if (message != NULL && defstr != NULL
6918 && argvars[1].v_type != VAR_UNKNOWN
6919 && argvars[2].v_type != VAR_UNKNOWN)
6920 rettv->vval.v_string = vim_strsave(
6921 get_tv_string_buf(&argvars[2], buf));
6922 else
6923 rettv->vval.v_string = NULL;
6924 }
6925 rettv->v_type = VAR_STRING;
6926 }
6927 else
6928#endif
6929 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6930}
6931
6932/*
6933 * "inputlist()" function
6934 */
6935 static void
6936f_inputlist(typval_T *argvars, typval_T *rettv)
6937{
6938 listitem_T *li;
6939 int selected;
6940 int mouse_used;
6941
6942#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006943 /* While starting up, there is no place to enter text. When running tests
6944 * with --not-a-term we assume feedkeys() will be used. */
6945 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006946 return;
6947#endif
6948 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6949 {
6950 EMSG2(_(e_listarg), "inputlist()");
6951 return;
6952 }
6953
6954 msg_start();
6955 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6956 lines_left = Rows; /* avoid more prompt */
6957 msg_scroll = TRUE;
6958 msg_clr_eos();
6959
6960 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6961 {
6962 msg_puts(get_tv_string(&li->li_tv));
6963 msg_putchar('\n');
6964 }
6965
6966 /* Ask for choice. */
6967 selected = prompt_for_number(&mouse_used);
6968 if (mouse_used)
6969 selected -= lines_left;
6970
6971 rettv->vval.v_number = selected;
6972}
6973
6974
6975static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6976
6977/*
6978 * "inputrestore()" function
6979 */
6980 static void
6981f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6982{
6983 if (ga_userinput.ga_len > 0)
6984 {
6985 --ga_userinput.ga_len;
6986 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6987 + ga_userinput.ga_len);
6988 /* default return is zero == OK */
6989 }
6990 else if (p_verbose > 1)
6991 {
6992 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6993 rettv->vval.v_number = 1; /* Failed */
6994 }
6995}
6996
6997/*
6998 * "inputsave()" function
6999 */
7000 static void
7001f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7002{
7003 /* Add an entry to the stack of typeahead storage. */
7004 if (ga_grow(&ga_userinput, 1) == OK)
7005 {
7006 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7007 + ga_userinput.ga_len);
7008 ++ga_userinput.ga_len;
7009 /* default return is zero == OK */
7010 }
7011 else
7012 rettv->vval.v_number = 1; /* Failed */
7013}
7014
7015/*
7016 * "inputsecret()" function
7017 */
7018 static void
7019f_inputsecret(typval_T *argvars, typval_T *rettv)
7020{
7021 ++cmdline_star;
7022 ++inputsecret_flag;
7023 f_input(argvars, rettv);
7024 --cmdline_star;
7025 --inputsecret_flag;
7026}
7027
7028/*
7029 * "insert()" function
7030 */
7031 static void
7032f_insert(typval_T *argvars, typval_T *rettv)
7033{
7034 long before = 0;
7035 listitem_T *item;
7036 list_T *l;
7037 int error = FALSE;
7038
7039 if (argvars[0].v_type != VAR_LIST)
7040 EMSG2(_(e_listarg), "insert()");
7041 else if ((l = argvars[0].vval.v_list) != NULL
7042 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7043 {
7044 if (argvars[2].v_type != VAR_UNKNOWN)
7045 before = (long)get_tv_number_chk(&argvars[2], &error);
7046 if (error)
7047 return; /* type error; errmsg already given */
7048
7049 if (before == l->lv_len)
7050 item = NULL;
7051 else
7052 {
7053 item = list_find(l, before);
7054 if (item == NULL)
7055 {
7056 EMSGN(_(e_listidx), before);
7057 l = NULL;
7058 }
7059 }
7060 if (l != NULL)
7061 {
7062 list_insert_tv(l, &argvars[1], item);
7063 copy_tv(&argvars[0], rettv);
7064 }
7065 }
7066}
7067
7068/*
7069 * "invert(expr)" function
7070 */
7071 static void
7072f_invert(typval_T *argvars, typval_T *rettv)
7073{
7074 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
7075}
7076
7077/*
7078 * "isdirectory()" function
7079 */
7080 static void
7081f_isdirectory(typval_T *argvars, typval_T *rettv)
7082{
7083 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
7084}
7085
7086/*
7087 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7088 * or it refers to a List or Dictionary that is locked.
7089 */
7090 static int
7091tv_islocked(typval_T *tv)
7092{
7093 return (tv->v_lock & VAR_LOCKED)
7094 || (tv->v_type == VAR_LIST
7095 && tv->vval.v_list != NULL
7096 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7097 || (tv->v_type == VAR_DICT
7098 && tv->vval.v_dict != NULL
7099 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7100}
7101
7102/*
7103 * "islocked()" function
7104 */
7105 static void
7106f_islocked(typval_T *argvars, typval_T *rettv)
7107{
7108 lval_T lv;
7109 char_u *end;
7110 dictitem_T *di;
7111
7112 rettv->vval.v_number = -1;
7113 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007114 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007115 if (end != NULL && lv.ll_name != NULL)
7116 {
7117 if (*end != NUL)
7118 EMSG(_(e_trailing));
7119 else
7120 {
7121 if (lv.ll_tv == NULL)
7122 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007123 di = find_var(lv.ll_name, NULL, TRUE);
7124 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007125 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007126 /* Consider a variable locked when:
7127 * 1. the variable itself is locked
7128 * 2. the value of the variable is locked.
7129 * 3. the List or Dict value is locked.
7130 */
7131 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7132 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007133 }
7134 }
7135 else if (lv.ll_range)
7136 EMSG(_("E786: Range not allowed"));
7137 else if (lv.ll_newkey != NULL)
7138 EMSG2(_(e_dictkey), lv.ll_newkey);
7139 else if (lv.ll_list != NULL)
7140 /* List item. */
7141 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7142 else
7143 /* Dictionary item. */
7144 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7145 }
7146 }
7147
7148 clear_lval(&lv);
7149}
7150
7151#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7152/*
7153 * "isnan()" function
7154 */
7155 static void
7156f_isnan(typval_T *argvars, typval_T *rettv)
7157{
7158 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7159 && isnan(argvars[0].vval.v_float);
7160}
7161#endif
7162
7163/*
7164 * "items(dict)" function
7165 */
7166 static void
7167f_items(typval_T *argvars, typval_T *rettv)
7168{
7169 dict_list(argvars, rettv, 2);
7170}
7171
7172#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7173/*
7174 * Get the job from the argument.
7175 * Returns NULL if the job is invalid.
7176 */
7177 static job_T *
7178get_job_arg(typval_T *tv)
7179{
7180 job_T *job;
7181
7182 if (tv->v_type != VAR_JOB)
7183 {
7184 EMSG2(_(e_invarg2), get_tv_string(tv));
7185 return NULL;
7186 }
7187 job = tv->vval.v_job;
7188
7189 if (job == NULL)
7190 EMSG(_("E916: not a valid job"));
7191 return job;
7192}
7193
7194/*
7195 * "job_getchannel()" function
7196 */
7197 static void
7198f_job_getchannel(typval_T *argvars, typval_T *rettv)
7199{
7200 job_T *job = get_job_arg(&argvars[0]);
7201
7202 if (job != NULL)
7203 {
7204 rettv->v_type = VAR_CHANNEL;
7205 rettv->vval.v_channel = job->jv_channel;
7206 if (job->jv_channel != NULL)
7207 ++job->jv_channel->ch_refcount;
7208 }
7209}
7210
7211/*
7212 * "job_info()" function
7213 */
7214 static void
7215f_job_info(typval_T *argvars, typval_T *rettv)
7216{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007217 if (argvars[0].v_type != VAR_UNKNOWN)
7218 {
7219 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007220
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007221 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7222 job_info(job, rettv->vval.v_dict);
7223 }
7224 else if (rettv_list_alloc(rettv) == OK)
7225 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007226}
7227
7228/*
7229 * "job_setoptions()" function
7230 */
7231 static void
7232f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7233{
7234 job_T *job = get_job_arg(&argvars[0]);
7235 jobopt_T opt;
7236
7237 if (job == NULL)
7238 return;
7239 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007240 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007241 job_set_options(job, &opt);
7242 free_job_options(&opt);
7243}
7244
7245/*
7246 * "job_start()" function
7247 */
7248 static void
7249f_job_start(typval_T *argvars, typval_T *rettv)
7250{
7251 rettv->v_type = VAR_JOB;
7252 if (check_restricted() || check_secure())
7253 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007254 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255}
7256
7257/*
7258 * "job_status()" function
7259 */
7260 static void
7261f_job_status(typval_T *argvars, typval_T *rettv)
7262{
7263 job_T *job = get_job_arg(&argvars[0]);
7264
7265 if (job != NULL)
7266 {
7267 rettv->v_type = VAR_STRING;
7268 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7269 }
7270}
7271
7272/*
7273 * "job_stop()" function
7274 */
7275 static void
7276f_job_stop(typval_T *argvars, typval_T *rettv)
7277{
7278 job_T *job = get_job_arg(&argvars[0]);
7279
7280 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007281 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007282}
7283#endif
7284
7285/*
7286 * "join()" function
7287 */
7288 static void
7289f_join(typval_T *argvars, typval_T *rettv)
7290{
7291 garray_T ga;
7292 char_u *sep;
7293
7294 if (argvars[0].v_type != VAR_LIST)
7295 {
7296 EMSG(_(e_listreq));
7297 return;
7298 }
7299 if (argvars[0].vval.v_list == NULL)
7300 return;
7301 if (argvars[1].v_type == VAR_UNKNOWN)
7302 sep = (char_u *)" ";
7303 else
7304 sep = get_tv_string_chk(&argvars[1]);
7305
7306 rettv->v_type = VAR_STRING;
7307
7308 if (sep != NULL)
7309 {
7310 ga_init2(&ga, (int)sizeof(char), 80);
7311 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7312 ga_append(&ga, NUL);
7313 rettv->vval.v_string = (char_u *)ga.ga_data;
7314 }
7315 else
7316 rettv->vval.v_string = NULL;
7317}
7318
7319/*
7320 * "js_decode()" function
7321 */
7322 static void
7323f_js_decode(typval_T *argvars, typval_T *rettv)
7324{
7325 js_read_T reader;
7326
7327 reader.js_buf = get_tv_string(&argvars[0]);
7328 reader.js_fill = NULL;
7329 reader.js_used = 0;
7330 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7331 EMSG(_(e_invarg));
7332}
7333
7334/*
7335 * "js_encode()" function
7336 */
7337 static void
7338f_js_encode(typval_T *argvars, typval_T *rettv)
7339{
7340 rettv->v_type = VAR_STRING;
7341 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7342}
7343
7344/*
7345 * "json_decode()" function
7346 */
7347 static void
7348f_json_decode(typval_T *argvars, typval_T *rettv)
7349{
7350 js_read_T reader;
7351
7352 reader.js_buf = get_tv_string(&argvars[0]);
7353 reader.js_fill = NULL;
7354 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007355 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356}
7357
7358/*
7359 * "json_encode()" function
7360 */
7361 static void
7362f_json_encode(typval_T *argvars, typval_T *rettv)
7363{
7364 rettv->v_type = VAR_STRING;
7365 rettv->vval.v_string = json_encode(&argvars[0], 0);
7366}
7367
7368/*
7369 * "keys()" function
7370 */
7371 static void
7372f_keys(typval_T *argvars, typval_T *rettv)
7373{
7374 dict_list(argvars, rettv, 0);
7375}
7376
7377/*
7378 * "last_buffer_nr()" function.
7379 */
7380 static void
7381f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7382{
7383 int n = 0;
7384 buf_T *buf;
7385
Bram Moolenaar29323592016-07-24 22:04:11 +02007386 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 if (n < buf->b_fnum)
7388 n = buf->b_fnum;
7389
7390 rettv->vval.v_number = n;
7391}
7392
7393/*
7394 * "len()" function
7395 */
7396 static void
7397f_len(typval_T *argvars, typval_T *rettv)
7398{
7399 switch (argvars[0].v_type)
7400 {
7401 case VAR_STRING:
7402 case VAR_NUMBER:
7403 rettv->vval.v_number = (varnumber_T)STRLEN(
7404 get_tv_string(&argvars[0]));
7405 break;
7406 case VAR_LIST:
7407 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7408 break;
7409 case VAR_DICT:
7410 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7411 break;
7412 case VAR_UNKNOWN:
7413 case VAR_SPECIAL:
7414 case VAR_FLOAT:
7415 case VAR_FUNC:
7416 case VAR_PARTIAL:
7417 case VAR_JOB:
7418 case VAR_CHANNEL:
7419 EMSG(_("E701: Invalid type for len()"));
7420 break;
7421 }
7422}
7423
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007425libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426{
7427#ifdef FEAT_LIBCALL
7428 char_u *string_in;
7429 char_u **string_result;
7430 int nr_result;
7431#endif
7432
7433 rettv->v_type = type;
7434 if (type != VAR_NUMBER)
7435 rettv->vval.v_string = NULL;
7436
7437 if (check_restricted() || check_secure())
7438 return;
7439
7440#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007441 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007442 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7443 {
7444 string_in = NULL;
7445 if (argvars[2].v_type == VAR_STRING)
7446 string_in = argvars[2].vval.v_string;
7447 if (type == VAR_NUMBER)
7448 string_result = NULL;
7449 else
7450 string_result = &rettv->vval.v_string;
7451 if (mch_libcall(argvars[0].vval.v_string,
7452 argvars[1].vval.v_string,
7453 string_in,
7454 argvars[2].vval.v_number,
7455 string_result,
7456 &nr_result) == OK
7457 && type == VAR_NUMBER)
7458 rettv->vval.v_number = nr_result;
7459 }
7460#endif
7461}
7462
7463/*
7464 * "libcall()" function
7465 */
7466 static void
7467f_libcall(typval_T *argvars, typval_T *rettv)
7468{
7469 libcall_common(argvars, rettv, VAR_STRING);
7470}
7471
7472/*
7473 * "libcallnr()" function
7474 */
7475 static void
7476f_libcallnr(typval_T *argvars, typval_T *rettv)
7477{
7478 libcall_common(argvars, rettv, VAR_NUMBER);
7479}
7480
7481/*
7482 * "line(string)" function
7483 */
7484 static void
7485f_line(typval_T *argvars, typval_T *rettv)
7486{
7487 linenr_T lnum = 0;
7488 pos_T *fp;
7489 int fnum;
7490
7491 fp = var2fpos(&argvars[0], TRUE, &fnum);
7492 if (fp != NULL)
7493 lnum = fp->lnum;
7494 rettv->vval.v_number = lnum;
7495}
7496
7497/*
7498 * "line2byte(lnum)" function
7499 */
7500 static void
7501f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7502{
7503#ifndef FEAT_BYTEOFF
7504 rettv->vval.v_number = -1;
7505#else
7506 linenr_T lnum;
7507
7508 lnum = get_tv_lnum(argvars);
7509 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7510 rettv->vval.v_number = -1;
7511 else
7512 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7513 if (rettv->vval.v_number >= 0)
7514 ++rettv->vval.v_number;
7515#endif
7516}
7517
7518/*
7519 * "lispindent(lnum)" function
7520 */
7521 static void
7522f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7523{
7524#ifdef FEAT_LISP
7525 pos_T pos;
7526 linenr_T lnum;
7527
7528 pos = curwin->w_cursor;
7529 lnum = get_tv_lnum(argvars);
7530 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7531 {
7532 curwin->w_cursor.lnum = lnum;
7533 rettv->vval.v_number = get_lisp_indent();
7534 curwin->w_cursor = pos;
7535 }
7536 else
7537#endif
7538 rettv->vval.v_number = -1;
7539}
7540
7541/*
7542 * "localtime()" function
7543 */
7544 static void
7545f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7546{
7547 rettv->vval.v_number = (varnumber_T)time(NULL);
7548}
7549
7550static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7551
7552 static void
7553get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7554{
7555 char_u *keys;
7556 char_u *which;
7557 char_u buf[NUMBUFLEN];
7558 char_u *keys_buf = NULL;
7559 char_u *rhs;
7560 int mode;
7561 int abbr = FALSE;
7562 int get_dict = FALSE;
7563 mapblock_T *mp;
7564 int buffer_local;
7565
7566 /* return empty string for failure */
7567 rettv->v_type = VAR_STRING;
7568 rettv->vval.v_string = NULL;
7569
7570 keys = get_tv_string(&argvars[0]);
7571 if (*keys == NUL)
7572 return;
7573
7574 if (argvars[1].v_type != VAR_UNKNOWN)
7575 {
7576 which = get_tv_string_buf_chk(&argvars[1], buf);
7577 if (argvars[2].v_type != VAR_UNKNOWN)
7578 {
7579 abbr = (int)get_tv_number(&argvars[2]);
7580 if (argvars[3].v_type != VAR_UNKNOWN)
7581 get_dict = (int)get_tv_number(&argvars[3]);
7582 }
7583 }
7584 else
7585 which = (char_u *)"";
7586 if (which == NULL)
7587 return;
7588
7589 mode = get_map_mode(&which, 0);
7590
7591 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7592 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7593 vim_free(keys_buf);
7594
7595 if (!get_dict)
7596 {
7597 /* Return a string. */
7598 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007599 {
7600 if (*rhs == NUL)
7601 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7602 else
7603 rettv->vval.v_string = str2special_save(rhs, FALSE);
7604 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007605
7606 }
7607 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7608 {
7609 /* Return a dictionary. */
7610 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7611 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7612 dict_T *dict = rettv->vval.v_dict;
7613
Bram Moolenaare0be1672018-07-08 16:50:37 +02007614 dict_add_string(dict, "lhs", lhs);
7615 dict_add_string(dict, "rhs", mp->m_orig_str);
7616 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7617 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7618 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
7619 dict_add_number(dict, "sid", (long)mp->m_script_ID);
7620 dict_add_number(dict, "buffer", (long)buffer_local);
7621 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7622 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007623
7624 vim_free(lhs);
7625 vim_free(mapmode);
7626 }
7627}
7628
7629#ifdef FEAT_FLOAT
7630/*
7631 * "log()" function
7632 */
7633 static void
7634f_log(typval_T *argvars, typval_T *rettv)
7635{
7636 float_T f = 0.0;
7637
7638 rettv->v_type = VAR_FLOAT;
7639 if (get_float_arg(argvars, &f) == OK)
7640 rettv->vval.v_float = log(f);
7641 else
7642 rettv->vval.v_float = 0.0;
7643}
7644
7645/*
7646 * "log10()" function
7647 */
7648 static void
7649f_log10(typval_T *argvars, typval_T *rettv)
7650{
7651 float_T f = 0.0;
7652
7653 rettv->v_type = VAR_FLOAT;
7654 if (get_float_arg(argvars, &f) == OK)
7655 rettv->vval.v_float = log10(f);
7656 else
7657 rettv->vval.v_float = 0.0;
7658}
7659#endif
7660
7661#ifdef FEAT_LUA
7662/*
7663 * "luaeval()" function
7664 */
7665 static void
7666f_luaeval(typval_T *argvars, typval_T *rettv)
7667{
7668 char_u *str;
7669 char_u buf[NUMBUFLEN];
7670
7671 str = get_tv_string_buf(&argvars[0], buf);
7672 do_luaeval(str, argvars + 1, rettv);
7673}
7674#endif
7675
7676/*
7677 * "map()" function
7678 */
7679 static void
7680f_map(typval_T *argvars, typval_T *rettv)
7681{
7682 filter_map(argvars, rettv, TRUE);
7683}
7684
7685/*
7686 * "maparg()" function
7687 */
7688 static void
7689f_maparg(typval_T *argvars, typval_T *rettv)
7690{
7691 get_maparg(argvars, rettv, TRUE);
7692}
7693
7694/*
7695 * "mapcheck()" function
7696 */
7697 static void
7698f_mapcheck(typval_T *argvars, typval_T *rettv)
7699{
7700 get_maparg(argvars, rettv, FALSE);
7701}
7702
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007703typedef enum
7704{
7705 MATCH_END, /* matchend() */
7706 MATCH_MATCH, /* match() */
7707 MATCH_STR, /* matchstr() */
7708 MATCH_LIST, /* matchlist() */
7709 MATCH_POS /* matchstrpos() */
7710} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007711
7712 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007713find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714{
7715 char_u *str = NULL;
7716 long len = 0;
7717 char_u *expr = NULL;
7718 char_u *pat;
7719 regmatch_T regmatch;
7720 char_u patbuf[NUMBUFLEN];
7721 char_u strbuf[NUMBUFLEN];
7722 char_u *save_cpo;
7723 long start = 0;
7724 long nth = 1;
7725 colnr_T startcol = 0;
7726 int match = 0;
7727 list_T *l = NULL;
7728 listitem_T *li = NULL;
7729 long idx = 0;
7730 char_u *tofree = NULL;
7731
7732 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7733 save_cpo = p_cpo;
7734 p_cpo = (char_u *)"";
7735
7736 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007737 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007739 /* type MATCH_LIST: return empty list when there are no matches.
7740 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007741 if (rettv_list_alloc(rettv) == FAIL)
7742 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007743 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 && (list_append_string(rettv->vval.v_list,
7745 (char_u *)"", 0) == FAIL
7746 || list_append_number(rettv->vval.v_list,
7747 (varnumber_T)-1) == FAIL
7748 || list_append_number(rettv->vval.v_list,
7749 (varnumber_T)-1) == FAIL
7750 || list_append_number(rettv->vval.v_list,
7751 (varnumber_T)-1) == FAIL))
7752 {
7753 list_free(rettv->vval.v_list);
7754 rettv->vval.v_list = NULL;
7755 goto theend;
7756 }
7757 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007758 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759 {
7760 rettv->v_type = VAR_STRING;
7761 rettv->vval.v_string = NULL;
7762 }
7763
7764 if (argvars[0].v_type == VAR_LIST)
7765 {
7766 if ((l = argvars[0].vval.v_list) == NULL)
7767 goto theend;
7768 li = l->lv_first;
7769 }
7770 else
7771 {
7772 expr = str = get_tv_string(&argvars[0]);
7773 len = (long)STRLEN(str);
7774 }
7775
7776 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7777 if (pat == NULL)
7778 goto theend;
7779
7780 if (argvars[2].v_type != VAR_UNKNOWN)
7781 {
7782 int error = FALSE;
7783
7784 start = (long)get_tv_number_chk(&argvars[2], &error);
7785 if (error)
7786 goto theend;
7787 if (l != NULL)
7788 {
7789 li = list_find(l, start);
7790 if (li == NULL)
7791 goto theend;
7792 idx = l->lv_idx; /* use the cached index */
7793 }
7794 else
7795 {
7796 if (start < 0)
7797 start = 0;
7798 if (start > len)
7799 goto theend;
7800 /* When "count" argument is there ignore matches before "start",
7801 * otherwise skip part of the string. Differs when pattern is "^"
7802 * or "\<". */
7803 if (argvars[3].v_type != VAR_UNKNOWN)
7804 startcol = start;
7805 else
7806 {
7807 str += start;
7808 len -= start;
7809 }
7810 }
7811
7812 if (argvars[3].v_type != VAR_UNKNOWN)
7813 nth = (long)get_tv_number_chk(&argvars[3], &error);
7814 if (error)
7815 goto theend;
7816 }
7817
7818 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7819 if (regmatch.regprog != NULL)
7820 {
7821 regmatch.rm_ic = p_ic;
7822
7823 for (;;)
7824 {
7825 if (l != NULL)
7826 {
7827 if (li == NULL)
7828 {
7829 match = FALSE;
7830 break;
7831 }
7832 vim_free(tofree);
7833 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7834 if (str == NULL)
7835 break;
7836 }
7837
7838 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7839
7840 if (match && --nth <= 0)
7841 break;
7842 if (l == NULL && !match)
7843 break;
7844
7845 /* Advance to just after the match. */
7846 if (l != NULL)
7847 {
7848 li = li->li_next;
7849 ++idx;
7850 }
7851 else
7852 {
7853#ifdef FEAT_MBYTE
7854 startcol = (colnr_T)(regmatch.startp[0]
7855 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7856#else
7857 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7858#endif
7859 if (startcol > (colnr_T)len
7860 || str + startcol <= regmatch.startp[0])
7861 {
7862 match = FALSE;
7863 break;
7864 }
7865 }
7866 }
7867
7868 if (match)
7869 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007870 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871 {
7872 listitem_T *li1 = rettv->vval.v_list->lv_first;
7873 listitem_T *li2 = li1->li_next;
7874 listitem_T *li3 = li2->li_next;
7875 listitem_T *li4 = li3->li_next;
7876
7877 vim_free(li1->li_tv.vval.v_string);
7878 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7879 (int)(regmatch.endp[0] - regmatch.startp[0]));
7880 li3->li_tv.vval.v_number =
7881 (varnumber_T)(regmatch.startp[0] - expr);
7882 li4->li_tv.vval.v_number =
7883 (varnumber_T)(regmatch.endp[0] - expr);
7884 if (l != NULL)
7885 li2->li_tv.vval.v_number = (varnumber_T)idx;
7886 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007887 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007888 {
7889 int i;
7890
7891 /* return list with matched string and submatches */
7892 for (i = 0; i < NSUBEXP; ++i)
7893 {
7894 if (regmatch.endp[i] == NULL)
7895 {
7896 if (list_append_string(rettv->vval.v_list,
7897 (char_u *)"", 0) == FAIL)
7898 break;
7899 }
7900 else if (list_append_string(rettv->vval.v_list,
7901 regmatch.startp[i],
7902 (int)(regmatch.endp[i] - regmatch.startp[i]))
7903 == FAIL)
7904 break;
7905 }
7906 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007907 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908 {
7909 /* return matched string */
7910 if (l != NULL)
7911 copy_tv(&li->li_tv, rettv);
7912 else
7913 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7914 (int)(regmatch.endp[0] - regmatch.startp[0]));
7915 }
7916 else if (l != NULL)
7917 rettv->vval.v_number = idx;
7918 else
7919 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007920 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 rettv->vval.v_number =
7922 (varnumber_T)(regmatch.startp[0] - str);
7923 else
7924 rettv->vval.v_number =
7925 (varnumber_T)(regmatch.endp[0] - str);
7926 rettv->vval.v_number += (varnumber_T)(str - expr);
7927 }
7928 }
7929 vim_regfree(regmatch.regprog);
7930 }
7931
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007932theend:
7933 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007934 /* matchstrpos() without a list: drop the second item. */
7935 listitem_remove(rettv->vval.v_list,
7936 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 vim_free(tofree);
7938 p_cpo = save_cpo;
7939}
7940
7941/*
7942 * "match()" function
7943 */
7944 static void
7945f_match(typval_T *argvars, typval_T *rettv)
7946{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007947 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007948}
7949
Bram Moolenaar95e51472018-07-28 16:55:56 +02007950#ifdef FEAT_SEARCH_EXTRA
7951 static int
7952matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
7953{
7954 dictitem_T *di;
7955
7956 if (tv->v_type != VAR_DICT)
7957 {
7958 EMSG(_(e_dictreq));
7959 return FAIL;
7960 }
7961
7962 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
7963 *conceal_char = get_dict_string(tv->vval.v_dict,
7964 (char_u *)"conceal", FALSE);
7965
7966 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
7967 {
7968 *win = find_win_by_nr(&di->di_tv, NULL);
7969 if (*win == NULL)
7970 {
7971 EMSG(_("E957: Invalid window number"));
7972 return FAIL;
7973 }
7974 }
7975
7976 return OK;
7977}
7978#endif
7979
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980/*
7981 * "matchadd()" function
7982 */
7983 static void
7984f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7985{
7986#ifdef FEAT_SEARCH_EXTRA
7987 char_u buf[NUMBUFLEN];
7988 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7989 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7990 int prio = 10; /* default priority */
7991 int id = -1;
7992 int error = FALSE;
7993 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02007994 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995
7996 rettv->vval.v_number = -1;
7997
7998 if (grp == NULL || pat == NULL)
7999 return;
8000 if (argvars[2].v_type != VAR_UNKNOWN)
8001 {
8002 prio = (int)get_tv_number_chk(&argvars[2], &error);
8003 if (argvars[3].v_type != VAR_UNKNOWN)
8004 {
8005 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008006 if (argvars[4].v_type != VAR_UNKNOWN
8007 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8008 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 }
8010 }
8011 if (error == TRUE)
8012 return;
8013 if (id >= 1 && id <= 3)
8014 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008015 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008016 return;
8017 }
8018
Bram Moolenaar95e51472018-07-28 16:55:56 +02008019 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008020 conceal_char);
8021#endif
8022}
8023
8024/*
8025 * "matchaddpos()" function
8026 */
8027 static void
8028f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8029{
8030#ifdef FEAT_SEARCH_EXTRA
8031 char_u buf[NUMBUFLEN];
8032 char_u *group;
8033 int prio = 10;
8034 int id = -1;
8035 int error = FALSE;
8036 list_T *l;
8037 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008038 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039
8040 rettv->vval.v_number = -1;
8041
8042 group = get_tv_string_buf_chk(&argvars[0], buf);
8043 if (group == NULL)
8044 return;
8045
8046 if (argvars[1].v_type != VAR_LIST)
8047 {
8048 EMSG2(_(e_listarg), "matchaddpos()");
8049 return;
8050 }
8051 l = argvars[1].vval.v_list;
8052 if (l == NULL)
8053 return;
8054
8055 if (argvars[2].v_type != VAR_UNKNOWN)
8056 {
8057 prio = (int)get_tv_number_chk(&argvars[2], &error);
8058 if (argvars[3].v_type != VAR_UNKNOWN)
8059 {
8060 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008061
8062 if (argvars[4].v_type != VAR_UNKNOWN
8063 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8064 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008065 }
8066 }
8067 if (error == TRUE)
8068 return;
8069
8070 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8071 if (id == 1 || id == 2)
8072 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008073 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008074 return;
8075 }
8076
Bram Moolenaar95e51472018-07-28 16:55:56 +02008077 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078 conceal_char);
8079#endif
8080}
8081
8082/*
8083 * "matcharg()" function
8084 */
8085 static void
8086f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8087{
8088 if (rettv_list_alloc(rettv) == OK)
8089 {
8090#ifdef FEAT_SEARCH_EXTRA
8091 int id = (int)get_tv_number(&argvars[0]);
8092 matchitem_T *m;
8093
8094 if (id >= 1 && id <= 3)
8095 {
8096 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8097 {
8098 list_append_string(rettv->vval.v_list,
8099 syn_id2name(m->hlg_id), -1);
8100 list_append_string(rettv->vval.v_list, m->pattern, -1);
8101 }
8102 else
8103 {
8104 list_append_string(rettv->vval.v_list, NULL, -1);
8105 list_append_string(rettv->vval.v_list, NULL, -1);
8106 }
8107 }
8108#endif
8109 }
8110}
8111
8112/*
8113 * "matchdelete()" function
8114 */
8115 static void
8116f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8117{
8118#ifdef FEAT_SEARCH_EXTRA
8119 rettv->vval.v_number = match_delete(curwin,
8120 (int)get_tv_number(&argvars[0]), TRUE);
8121#endif
8122}
8123
8124/*
8125 * "matchend()" function
8126 */
8127 static void
8128f_matchend(typval_T *argvars, typval_T *rettv)
8129{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008130 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008131}
8132
8133/*
8134 * "matchlist()" function
8135 */
8136 static void
8137f_matchlist(typval_T *argvars, typval_T *rettv)
8138{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008139 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140}
8141
8142/*
8143 * "matchstr()" function
8144 */
8145 static void
8146f_matchstr(typval_T *argvars, typval_T *rettv)
8147{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008148 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008149}
8150
8151/*
8152 * "matchstrpos()" function
8153 */
8154 static void
8155f_matchstrpos(typval_T *argvars, typval_T *rettv)
8156{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008157 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158}
8159
8160static void max_min(typval_T *argvars, typval_T *rettv, int domax);
8161
8162 static void
8163max_min(typval_T *argvars, typval_T *rettv, int domax)
8164{
8165 varnumber_T n = 0;
8166 varnumber_T i;
8167 int error = FALSE;
8168
8169 if (argvars[0].v_type == VAR_LIST)
8170 {
8171 list_T *l;
8172 listitem_T *li;
8173
8174 l = argvars[0].vval.v_list;
8175 if (l != NULL)
8176 {
8177 li = l->lv_first;
8178 if (li != NULL)
8179 {
8180 n = get_tv_number_chk(&li->li_tv, &error);
8181 for (;;)
8182 {
8183 li = li->li_next;
8184 if (li == NULL)
8185 break;
8186 i = get_tv_number_chk(&li->li_tv, &error);
8187 if (domax ? i > n : i < n)
8188 n = i;
8189 }
8190 }
8191 }
8192 }
8193 else if (argvars[0].v_type == VAR_DICT)
8194 {
8195 dict_T *d;
8196 int first = TRUE;
8197 hashitem_T *hi;
8198 int todo;
8199
8200 d = argvars[0].vval.v_dict;
8201 if (d != NULL)
8202 {
8203 todo = (int)d->dv_hashtab.ht_used;
8204 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8205 {
8206 if (!HASHITEM_EMPTY(hi))
8207 {
8208 --todo;
8209 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8210 if (first)
8211 {
8212 n = i;
8213 first = FALSE;
8214 }
8215 else if (domax ? i > n : i < n)
8216 n = i;
8217 }
8218 }
8219 }
8220 }
8221 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008222 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223 rettv->vval.v_number = error ? 0 : n;
8224}
8225
8226/*
8227 * "max()" function
8228 */
8229 static void
8230f_max(typval_T *argvars, typval_T *rettv)
8231{
8232 max_min(argvars, rettv, TRUE);
8233}
8234
8235/*
8236 * "min()" function
8237 */
8238 static void
8239f_min(typval_T *argvars, typval_T *rettv)
8240{
8241 max_min(argvars, rettv, FALSE);
8242}
8243
8244static int mkdir_recurse(char_u *dir, int prot);
8245
8246/*
8247 * Create the directory in which "dir" is located, and higher levels when
8248 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008249 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008250 */
8251 static int
8252mkdir_recurse(char_u *dir, int prot)
8253{
8254 char_u *p;
8255 char_u *updir;
8256 int r = FAIL;
8257
8258 /* Get end of directory name in "dir".
8259 * We're done when it's "/" or "c:/". */
8260 p = gettail_sep(dir);
8261 if (p <= get_past_head(dir))
8262 return OK;
8263
8264 /* If the directory exists we're done. Otherwise: create it.*/
8265 updir = vim_strnsave(dir, (int)(p - dir));
8266 if (updir == NULL)
8267 return FAIL;
8268 if (mch_isdir(updir))
8269 r = OK;
8270 else if (mkdir_recurse(updir, prot) == OK)
8271 r = vim_mkdir_emsg(updir, prot);
8272 vim_free(updir);
8273 return r;
8274}
8275
8276#ifdef vim_mkdir
8277/*
8278 * "mkdir()" function
8279 */
8280 static void
8281f_mkdir(typval_T *argvars, typval_T *rettv)
8282{
8283 char_u *dir;
8284 char_u buf[NUMBUFLEN];
8285 int prot = 0755;
8286
8287 rettv->vval.v_number = FAIL;
8288 if (check_restricted() || check_secure())
8289 return;
8290
8291 dir = get_tv_string_buf(&argvars[0], buf);
8292 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008293 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008294
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008295 if (*gettail(dir) == NUL)
8296 /* remove trailing slashes */
8297 *gettail_sep(dir) = NUL;
8298
8299 if (argvars[1].v_type != VAR_UNKNOWN)
8300 {
8301 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008303 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8304 if (prot == -1)
8305 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008306 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008307 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8308 {
8309 if (mch_isdir(dir))
8310 {
8311 /* With the "p" flag it's OK if the dir already exists. */
8312 rettv->vval.v_number = OK;
8313 return;
8314 }
8315 mkdir_recurse(dir, prot);
8316 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008317 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008318 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319}
8320#endif
8321
8322/*
8323 * "mode()" function
8324 */
8325 static void
8326f_mode(typval_T *argvars, typval_T *rettv)
8327{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008328 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329
Bram Moolenaar612cc382018-07-29 15:34:26 +02008330 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008331
8332 if (time_for_testing == 93784)
8333 {
8334 /* Testing the two-character code. */
8335 buf[0] = 'x';
8336 buf[1] = '!';
8337 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008338#ifdef FEAT_TERMINAL
8339 else if (term_use_loop())
8340 buf[0] = 't';
8341#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 else if (VIsual_active)
8343 {
8344 if (VIsual_select)
8345 buf[0] = VIsual_mode + 's' - 'v';
8346 else
8347 buf[0] = VIsual_mode;
8348 }
8349 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8350 || State == CONFIRM)
8351 {
8352 buf[0] = 'r';
8353 if (State == ASKMORE)
8354 buf[1] = 'm';
8355 else if (State == CONFIRM)
8356 buf[1] = '?';
8357 }
8358 else if (State == EXTERNCMD)
8359 buf[0] = '!';
8360 else if (State & INSERT)
8361 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008362 if (State & VREPLACE_FLAG)
8363 {
8364 buf[0] = 'R';
8365 buf[1] = 'v';
8366 }
8367 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008368 {
8369 if (State & REPLACE_FLAG)
8370 buf[0] = 'R';
8371 else
8372 buf[0] = 'i';
8373#ifdef FEAT_INS_EXPAND
8374 if (ins_compl_active())
8375 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008376 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008377 buf[1] = 'x';
8378#endif
8379 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008380 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008381 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008382 {
8383 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008384 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008385 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008386 else if (exmode_active == EXMODE_NORMAL)
8387 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 }
8389 else
8390 {
8391 buf[0] = 'n';
8392 if (finish_op)
8393 buf[1] = 'o';
Bram Moolenaar612cc382018-07-29 15:34:26 +02008394 else if (restart_edit == 'I' || restart_edit == 'R'
8395 || restart_edit == 'V')
8396 {
8397 buf[1] = 'i';
8398 buf[2] = restart_edit;
8399 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008400 }
8401
8402 /* Clear out the minor mode when the argument is not a non-zero number or
8403 * non-empty string. */
8404 if (!non_zero_arg(&argvars[0]))
8405 buf[1] = NUL;
8406
8407 rettv->vval.v_string = vim_strsave(buf);
8408 rettv->v_type = VAR_STRING;
8409}
8410
8411#if defined(FEAT_MZSCHEME) || defined(PROTO)
8412/*
8413 * "mzeval()" function
8414 */
8415 static void
8416f_mzeval(typval_T *argvars, typval_T *rettv)
8417{
8418 char_u *str;
8419 char_u buf[NUMBUFLEN];
8420
8421 str = get_tv_string_buf(&argvars[0], buf);
8422 do_mzeval(str, rettv);
8423}
8424
8425 void
8426mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8427{
8428 typval_T argvars[3];
8429
8430 argvars[0].v_type = VAR_STRING;
8431 argvars[0].vval.v_string = name;
8432 copy_tv(args, &argvars[1]);
8433 argvars[2].v_type = VAR_UNKNOWN;
8434 f_call(argvars, rettv);
8435 clear_tv(&argvars[1]);
8436}
8437#endif
8438
8439/*
8440 * "nextnonblank()" function
8441 */
8442 static void
8443f_nextnonblank(typval_T *argvars, typval_T *rettv)
8444{
8445 linenr_T lnum;
8446
8447 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8448 {
8449 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8450 {
8451 lnum = 0;
8452 break;
8453 }
8454 if (*skipwhite(ml_get(lnum)) != NUL)
8455 break;
8456 }
8457 rettv->vval.v_number = lnum;
8458}
8459
8460/*
8461 * "nr2char()" function
8462 */
8463 static void
8464f_nr2char(typval_T *argvars, typval_T *rettv)
8465{
8466 char_u buf[NUMBUFLEN];
8467
8468#ifdef FEAT_MBYTE
8469 if (has_mbyte)
8470 {
8471 int utf8 = 0;
8472
8473 if (argvars[1].v_type != VAR_UNKNOWN)
8474 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8475 if (utf8)
8476 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8477 else
8478 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8479 }
8480 else
8481#endif
8482 {
8483 buf[0] = (char_u)get_tv_number(&argvars[0]);
8484 buf[1] = NUL;
8485 }
8486 rettv->v_type = VAR_STRING;
8487 rettv->vval.v_string = vim_strsave(buf);
8488}
8489
8490/*
8491 * "or(expr, expr)" function
8492 */
8493 static void
8494f_or(typval_T *argvars, typval_T *rettv)
8495{
8496 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8497 | get_tv_number_chk(&argvars[1], NULL);
8498}
8499
8500/*
8501 * "pathshorten()" function
8502 */
8503 static void
8504f_pathshorten(typval_T *argvars, typval_T *rettv)
8505{
8506 char_u *p;
8507
8508 rettv->v_type = VAR_STRING;
8509 p = get_tv_string_chk(&argvars[0]);
8510 if (p == NULL)
8511 rettv->vval.v_string = NULL;
8512 else
8513 {
8514 p = vim_strsave(p);
8515 rettv->vval.v_string = p;
8516 if (p != NULL)
8517 shorten_dir(p);
8518 }
8519}
8520
8521#ifdef FEAT_PERL
8522/*
8523 * "perleval()" function
8524 */
8525 static void
8526f_perleval(typval_T *argvars, typval_T *rettv)
8527{
8528 char_u *str;
8529 char_u buf[NUMBUFLEN];
8530
8531 str = get_tv_string_buf(&argvars[0], buf);
8532 do_perleval(str, rettv);
8533}
8534#endif
8535
8536#ifdef FEAT_FLOAT
8537/*
8538 * "pow()" function
8539 */
8540 static void
8541f_pow(typval_T *argvars, typval_T *rettv)
8542{
8543 float_T fx = 0.0, fy = 0.0;
8544
8545 rettv->v_type = VAR_FLOAT;
8546 if (get_float_arg(argvars, &fx) == OK
8547 && get_float_arg(&argvars[1], &fy) == OK)
8548 rettv->vval.v_float = pow(fx, fy);
8549 else
8550 rettv->vval.v_float = 0.0;
8551}
8552#endif
8553
8554/*
8555 * "prevnonblank()" function
8556 */
8557 static void
8558f_prevnonblank(typval_T *argvars, typval_T *rettv)
8559{
8560 linenr_T lnum;
8561
8562 lnum = get_tv_lnum(argvars);
8563 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8564 lnum = 0;
8565 else
8566 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8567 --lnum;
8568 rettv->vval.v_number = lnum;
8569}
8570
8571/* This dummy va_list is here because:
8572 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8573 * - locally in the function results in a "used before set" warning
8574 * - using va_start() to initialize it gives "function with fixed args" error */
8575static va_list ap;
8576
8577/*
8578 * "printf()" function
8579 */
8580 static void
8581f_printf(typval_T *argvars, typval_T *rettv)
8582{
8583 char_u buf[NUMBUFLEN];
8584 int len;
8585 char_u *s;
8586 int saved_did_emsg = did_emsg;
8587 char *fmt;
8588
8589 rettv->v_type = VAR_STRING;
8590 rettv->vval.v_string = NULL;
8591
8592 /* Get the required length, allocate the buffer and do it for real. */
8593 did_emsg = FALSE;
8594 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008595 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596 if (!did_emsg)
8597 {
8598 s = alloc(len + 1);
8599 if (s != NULL)
8600 {
8601 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008602 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8603 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008604 }
8605 }
8606 did_emsg |= saved_did_emsg;
8607}
8608
Bram Moolenaarf2732452018-06-03 14:47:35 +02008609#ifdef FEAT_JOB_CHANNEL
8610/*
8611 * "prompt_setcallback({buffer}, {callback})" function
8612 */
8613 static void
8614f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8615{
8616 buf_T *buf;
8617 char_u *callback;
8618 partial_T *partial;
8619
8620 if (check_secure())
8621 return;
8622 buf = get_buf_tv(&argvars[0], FALSE);
8623 if (buf == NULL)
8624 return;
8625
8626 callback = get_callback(&argvars[1], &partial);
8627 if (callback == NULL)
8628 return;
8629
8630 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8631 if (partial == NULL)
8632 buf->b_prompt_callback = vim_strsave(callback);
8633 else
8634 /* pointer into the partial */
8635 buf->b_prompt_callback = callback;
8636 buf->b_prompt_partial = partial;
8637}
8638
8639/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008640 * "prompt_setinterrupt({buffer}, {callback})" function
8641 */
8642 static void
8643f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8644{
8645 buf_T *buf;
8646 char_u *callback;
8647 partial_T *partial;
8648
8649 if (check_secure())
8650 return;
8651 buf = get_buf_tv(&argvars[0], FALSE);
8652 if (buf == NULL)
8653 return;
8654
8655 callback = get_callback(&argvars[1], &partial);
8656 if (callback == NULL)
8657 return;
8658
8659 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8660 if (partial == NULL)
8661 buf->b_prompt_interrupt = vim_strsave(callback);
8662 else
8663 /* pointer into the partial */
8664 buf->b_prompt_interrupt = callback;
8665 buf->b_prompt_int_partial = partial;
8666}
8667
8668/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008669 * "prompt_setprompt({buffer}, {text})" function
8670 */
8671 static void
8672f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8673{
8674 buf_T *buf;
8675 char_u *text;
8676
8677 if (check_secure())
8678 return;
8679 buf = get_buf_tv(&argvars[0], FALSE);
8680 if (buf == NULL)
8681 return;
8682
8683 text = get_tv_string(&argvars[1]);
8684 vim_free(buf->b_prompt_text);
8685 buf->b_prompt_text = vim_strsave(text);
8686}
8687#endif
8688
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689/*
8690 * "pumvisible()" function
8691 */
8692 static void
8693f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8694{
8695#ifdef FEAT_INS_EXPAND
8696 if (pum_visible())
8697 rettv->vval.v_number = 1;
8698#endif
8699}
8700
8701#ifdef FEAT_PYTHON3
8702/*
8703 * "py3eval()" function
8704 */
8705 static void
8706f_py3eval(typval_T *argvars, typval_T *rettv)
8707{
8708 char_u *str;
8709 char_u buf[NUMBUFLEN];
8710
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008711 if (p_pyx == 0)
8712 p_pyx = 3;
8713
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008714 str = get_tv_string_buf(&argvars[0], buf);
8715 do_py3eval(str, rettv);
8716}
8717#endif
8718
8719#ifdef FEAT_PYTHON
8720/*
8721 * "pyeval()" function
8722 */
8723 static void
8724f_pyeval(typval_T *argvars, typval_T *rettv)
8725{
8726 char_u *str;
8727 char_u buf[NUMBUFLEN];
8728
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008729 if (p_pyx == 0)
8730 p_pyx = 2;
8731
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008732 str = get_tv_string_buf(&argvars[0], buf);
8733 do_pyeval(str, rettv);
8734}
8735#endif
8736
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008737#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8738/*
8739 * "pyxeval()" function
8740 */
8741 static void
8742f_pyxeval(typval_T *argvars, typval_T *rettv)
8743{
8744# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8745 init_pyxversion();
8746 if (p_pyx == 2)
8747 f_pyeval(argvars, rettv);
8748 else
8749 f_py3eval(argvars, rettv);
8750# elif defined(FEAT_PYTHON)
8751 f_pyeval(argvars, rettv);
8752# elif defined(FEAT_PYTHON3)
8753 f_py3eval(argvars, rettv);
8754# endif
8755}
8756#endif
8757
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008758/*
8759 * "range()" function
8760 */
8761 static void
8762f_range(typval_T *argvars, typval_T *rettv)
8763{
8764 varnumber_T start;
8765 varnumber_T end;
8766 varnumber_T stride = 1;
8767 varnumber_T i;
8768 int error = FALSE;
8769
8770 start = get_tv_number_chk(&argvars[0], &error);
8771 if (argvars[1].v_type == VAR_UNKNOWN)
8772 {
8773 end = start - 1;
8774 start = 0;
8775 }
8776 else
8777 {
8778 end = get_tv_number_chk(&argvars[1], &error);
8779 if (argvars[2].v_type != VAR_UNKNOWN)
8780 stride = get_tv_number_chk(&argvars[2], &error);
8781 }
8782
8783 if (error)
8784 return; /* type error; errmsg already given */
8785 if (stride == 0)
8786 EMSG(_("E726: Stride is zero"));
8787 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8788 EMSG(_("E727: Start past end"));
8789 else
8790 {
8791 if (rettv_list_alloc(rettv) == OK)
8792 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8793 if (list_append_number(rettv->vval.v_list,
8794 (varnumber_T)i) == FAIL)
8795 break;
8796 }
8797}
8798
8799/*
8800 * "readfile()" function
8801 */
8802 static void
8803f_readfile(typval_T *argvars, typval_T *rettv)
8804{
8805 int binary = FALSE;
8806 int failed = FALSE;
8807 char_u *fname;
8808 FILE *fd;
8809 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8810 int io_size = sizeof(buf);
8811 int readlen; /* size of last fread() */
8812 char_u *prev = NULL; /* previously read bytes, if any */
8813 long prevlen = 0; /* length of data in prev */
8814 long prevsize = 0; /* size of prev buffer */
8815 long maxline = MAXLNUM;
8816 long cnt = 0;
8817 char_u *p; /* position in buf */
8818 char_u *start; /* start of current line */
8819
8820 if (argvars[1].v_type != VAR_UNKNOWN)
8821 {
8822 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8823 binary = TRUE;
8824 if (argvars[2].v_type != VAR_UNKNOWN)
8825 maxline = (long)get_tv_number(&argvars[2]);
8826 }
8827
8828 if (rettv_list_alloc(rettv) == FAIL)
8829 return;
8830
8831 /* Always open the file in binary mode, library functions have a mind of
8832 * their own about CR-LF conversion. */
8833 fname = get_tv_string(&argvars[0]);
8834 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8835 {
8836 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8837 return;
8838 }
8839
8840 while (cnt < maxline || maxline < 0)
8841 {
8842 readlen = (int)fread(buf, 1, io_size, fd);
8843
8844 /* This for loop processes what was read, but is also entered at end
8845 * of file so that either:
8846 * - an incomplete line gets written
8847 * - a "binary" file gets an empty line at the end if it ends in a
8848 * newline. */
8849 for (p = buf, start = buf;
8850 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8851 ++p)
8852 {
8853 if (*p == '\n' || readlen <= 0)
8854 {
8855 listitem_T *li;
8856 char_u *s = NULL;
8857 long_u len = p - start;
8858
8859 /* Finished a line. Remove CRs before NL. */
8860 if (readlen > 0 && !binary)
8861 {
8862 while (len > 0 && start[len - 1] == '\r')
8863 --len;
8864 /* removal may cross back to the "prev" string */
8865 if (len == 0)
8866 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8867 --prevlen;
8868 }
8869 if (prevlen == 0)
8870 s = vim_strnsave(start, (int)len);
8871 else
8872 {
8873 /* Change "prev" buffer to be the right size. This way
8874 * the bytes are only copied once, and very long lines are
8875 * allocated only once. */
8876 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8877 {
8878 mch_memmove(s + prevlen, start, len);
8879 s[prevlen + len] = NUL;
8880 prev = NULL; /* the list will own the string */
8881 prevlen = prevsize = 0;
8882 }
8883 }
8884 if (s == NULL)
8885 {
8886 do_outofmem_msg((long_u) prevlen + len + 1);
8887 failed = TRUE;
8888 break;
8889 }
8890
8891 if ((li = listitem_alloc()) == NULL)
8892 {
8893 vim_free(s);
8894 failed = TRUE;
8895 break;
8896 }
8897 li->li_tv.v_type = VAR_STRING;
8898 li->li_tv.v_lock = 0;
8899 li->li_tv.vval.v_string = s;
8900 list_append(rettv->vval.v_list, li);
8901
8902 start = p + 1; /* step over newline */
8903 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8904 break;
8905 }
8906 else if (*p == NUL)
8907 *p = '\n';
8908#ifdef FEAT_MBYTE
8909 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8910 * when finding the BF and check the previous two bytes. */
8911 else if (*p == 0xbf && enc_utf8 && !binary)
8912 {
8913 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8914 * + 1, these may be in the "prev" string. */
8915 char_u back1 = p >= buf + 1 ? p[-1]
8916 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8917 char_u back2 = p >= buf + 2 ? p[-2]
8918 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8919 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8920
8921 if (back2 == 0xef && back1 == 0xbb)
8922 {
8923 char_u *dest = p - 2;
8924
8925 /* Usually a BOM is at the beginning of a file, and so at
8926 * the beginning of a line; then we can just step over it.
8927 */
8928 if (start == dest)
8929 start = p + 1;
8930 else
8931 {
8932 /* have to shuffle buf to close gap */
8933 int adjust_prevlen = 0;
8934
8935 if (dest < buf)
8936 {
8937 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8938 dest = buf;
8939 }
8940 if (readlen > p - buf + 1)
8941 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8942 readlen -= 3 - adjust_prevlen;
8943 prevlen -= adjust_prevlen;
8944 p = dest - 1;
8945 }
8946 }
8947 }
8948#endif
8949 } /* for */
8950
8951 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8952 break;
8953 if (start < p)
8954 {
8955 /* There's part of a line in buf, store it in "prev". */
8956 if (p - start + prevlen >= prevsize)
8957 {
8958 /* need bigger "prev" buffer */
8959 char_u *newprev;
8960
8961 /* A common use case is ordinary text files and "prev" gets a
8962 * fragment of a line, so the first allocation is made
8963 * small, to avoid repeatedly 'allocing' large and
8964 * 'reallocing' small. */
8965 if (prevsize == 0)
8966 prevsize = (long)(p - start);
8967 else
8968 {
8969 long grow50pc = (prevsize * 3) / 2;
8970 long growmin = (long)((p - start) * 2 + prevlen);
8971 prevsize = grow50pc > growmin ? grow50pc : growmin;
8972 }
8973 newprev = prev == NULL ? alloc(prevsize)
8974 : vim_realloc(prev, prevsize);
8975 if (newprev == NULL)
8976 {
8977 do_outofmem_msg((long_u)prevsize);
8978 failed = TRUE;
8979 break;
8980 }
8981 prev = newprev;
8982 }
8983 /* Add the line part to end of "prev". */
8984 mch_memmove(prev + prevlen, start, p - start);
8985 prevlen += (long)(p - start);
8986 }
8987 } /* while */
8988
8989 /*
8990 * For a negative line count use only the lines at the end of the file,
8991 * free the rest.
8992 */
8993 if (!failed && maxline < 0)
8994 while (cnt > -maxline)
8995 {
8996 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8997 --cnt;
8998 }
8999
9000 if (failed)
9001 {
9002 list_free(rettv->vval.v_list);
9003 /* readfile doc says an empty list is returned on error */
9004 rettv->vval.v_list = list_alloc();
9005 }
9006
9007 vim_free(prev);
9008 fclose(fd);
9009}
9010
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009011 static void
9012return_register(int regname, typval_T *rettv)
9013{
9014 char_u buf[2] = {0, 0};
9015
9016 buf[0] = (char_u)regname;
9017 rettv->v_type = VAR_STRING;
9018 rettv->vval.v_string = vim_strsave(buf);
9019}
9020
9021/*
9022 * "reg_executing()" function
9023 */
9024 static void
9025f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9026{
9027 return_register(reg_executing, rettv);
9028}
9029
9030/*
9031 * "reg_recording()" function
9032 */
9033 static void
9034f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9035{
9036 return_register(reg_recording, rettv);
9037}
9038
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009039#if defined(FEAT_RELTIME)
9040static int list2proftime(typval_T *arg, proftime_T *tm);
9041
9042/*
9043 * Convert a List to proftime_T.
9044 * Return FAIL when there is something wrong.
9045 */
9046 static int
9047list2proftime(typval_T *arg, proftime_T *tm)
9048{
9049 long n1, n2;
9050 int error = FALSE;
9051
9052 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9053 || arg->vval.v_list->lv_len != 2)
9054 return FAIL;
9055 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9056 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9057# ifdef WIN3264
9058 tm->HighPart = n1;
9059 tm->LowPart = n2;
9060# else
9061 tm->tv_sec = n1;
9062 tm->tv_usec = n2;
9063# endif
9064 return error ? FAIL : OK;
9065}
9066#endif /* FEAT_RELTIME */
9067
9068/*
9069 * "reltime()" function
9070 */
9071 static void
9072f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9073{
9074#ifdef FEAT_RELTIME
9075 proftime_T res;
9076 proftime_T start;
9077
9078 if (argvars[0].v_type == VAR_UNKNOWN)
9079 {
9080 /* No arguments: get current time. */
9081 profile_start(&res);
9082 }
9083 else if (argvars[1].v_type == VAR_UNKNOWN)
9084 {
9085 if (list2proftime(&argvars[0], &res) == FAIL)
9086 return;
9087 profile_end(&res);
9088 }
9089 else
9090 {
9091 /* Two arguments: compute the difference. */
9092 if (list2proftime(&argvars[0], &start) == FAIL
9093 || list2proftime(&argvars[1], &res) == FAIL)
9094 return;
9095 profile_sub(&res, &start);
9096 }
9097
9098 if (rettv_list_alloc(rettv) == OK)
9099 {
9100 long n1, n2;
9101
9102# ifdef WIN3264
9103 n1 = res.HighPart;
9104 n2 = res.LowPart;
9105# else
9106 n1 = res.tv_sec;
9107 n2 = res.tv_usec;
9108# endif
9109 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9110 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9111 }
9112#endif
9113}
9114
9115#ifdef FEAT_FLOAT
9116/*
9117 * "reltimefloat()" function
9118 */
9119 static void
9120f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9121{
9122# ifdef FEAT_RELTIME
9123 proftime_T tm;
9124# endif
9125
9126 rettv->v_type = VAR_FLOAT;
9127 rettv->vval.v_float = 0;
9128# ifdef FEAT_RELTIME
9129 if (list2proftime(&argvars[0], &tm) == OK)
9130 rettv->vval.v_float = profile_float(&tm);
9131# endif
9132}
9133#endif
9134
9135/*
9136 * "reltimestr()" function
9137 */
9138 static void
9139f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9140{
9141#ifdef FEAT_RELTIME
9142 proftime_T tm;
9143#endif
9144
9145 rettv->v_type = VAR_STRING;
9146 rettv->vval.v_string = NULL;
9147#ifdef FEAT_RELTIME
9148 if (list2proftime(&argvars[0], &tm) == OK)
9149 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9150#endif
9151}
9152
9153#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9154static void make_connection(void);
9155static int check_connection(void);
9156
9157 static void
9158make_connection(void)
9159{
9160 if (X_DISPLAY == NULL
9161# ifdef FEAT_GUI
9162 && !gui.in_use
9163# endif
9164 )
9165 {
9166 x_force_connect = TRUE;
9167 setup_term_clip();
9168 x_force_connect = FALSE;
9169 }
9170}
9171
9172 static int
9173check_connection(void)
9174{
9175 make_connection();
9176 if (X_DISPLAY == NULL)
9177 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009178 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009179 return FAIL;
9180 }
9181 return OK;
9182}
9183#endif
9184
9185#ifdef FEAT_CLIENTSERVER
9186 static void
9187remote_common(typval_T *argvars, typval_T *rettv, int expr)
9188{
9189 char_u *server_name;
9190 char_u *keys;
9191 char_u *r = NULL;
9192 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009193 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009194# ifdef WIN32
9195 HWND w;
9196# else
9197 Window w;
9198# endif
9199
9200 if (check_restricted() || check_secure())
9201 return;
9202
9203# ifdef FEAT_X11
9204 if (check_connection() == FAIL)
9205 return;
9206# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009207 if (argvars[2].v_type != VAR_UNKNOWN
9208 && argvars[3].v_type != VAR_UNKNOWN)
9209 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009210
9211 server_name = get_tv_string_chk(&argvars[0]);
9212 if (server_name == NULL)
9213 return; /* type error; errmsg already given */
9214 keys = get_tv_string_buf(&argvars[1], buf);
9215# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009216 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009217# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009218 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9219 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009220# endif
9221 {
9222 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009223 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009224 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009225 vim_free(r);
9226 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009227 else
9228 EMSG2(_("E241: Unable to send to %s"), server_name);
9229 return;
9230 }
9231
9232 rettv->vval.v_string = r;
9233
9234 if (argvars[2].v_type != VAR_UNKNOWN)
9235 {
9236 dictitem_T v;
9237 char_u str[30];
9238 char_u *idvar;
9239
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009240 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009241 if (idvar != NULL && *idvar != NUL)
9242 {
9243 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9244 v.di_tv.v_type = VAR_STRING;
9245 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009246 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009247 vim_free(v.di_tv.vval.v_string);
9248 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009249 }
9250}
9251#endif
9252
9253/*
9254 * "remote_expr()" function
9255 */
9256 static void
9257f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9258{
9259 rettv->v_type = VAR_STRING;
9260 rettv->vval.v_string = NULL;
9261#ifdef FEAT_CLIENTSERVER
9262 remote_common(argvars, rettv, TRUE);
9263#endif
9264}
9265
9266/*
9267 * "remote_foreground()" function
9268 */
9269 static void
9270f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9271{
9272#ifdef FEAT_CLIENTSERVER
9273# ifdef WIN32
9274 /* On Win32 it's done in this application. */
9275 {
9276 char_u *server_name = get_tv_string_chk(&argvars[0]);
9277
9278 if (server_name != NULL)
9279 serverForeground(server_name);
9280 }
9281# else
9282 /* Send a foreground() expression to the server. */
9283 argvars[1].v_type = VAR_STRING;
9284 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9285 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009286 rettv->v_type = VAR_STRING;
9287 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009288 remote_common(argvars, rettv, TRUE);
9289 vim_free(argvars[1].vval.v_string);
9290# endif
9291#endif
9292}
9293
9294 static void
9295f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9296{
9297#ifdef FEAT_CLIENTSERVER
9298 dictitem_T v;
9299 char_u *s = NULL;
9300# ifdef WIN32
9301 long_u n = 0;
9302# endif
9303 char_u *serverid;
9304
9305 if (check_restricted() || check_secure())
9306 {
9307 rettv->vval.v_number = -1;
9308 return;
9309 }
9310 serverid = get_tv_string_chk(&argvars[0]);
9311 if (serverid == NULL)
9312 {
9313 rettv->vval.v_number = -1;
9314 return; /* type error; errmsg already given */
9315 }
9316# ifdef WIN32
9317 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9318 if (n == 0)
9319 rettv->vval.v_number = -1;
9320 else
9321 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009322 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009323 rettv->vval.v_number = (s != NULL);
9324 }
9325# else
9326 if (check_connection() == FAIL)
9327 return;
9328
9329 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9330 serverStrToWin(serverid), &s);
9331# endif
9332
9333 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9334 {
9335 char_u *retvar;
9336
9337 v.di_tv.v_type = VAR_STRING;
9338 v.di_tv.vval.v_string = vim_strsave(s);
9339 retvar = get_tv_string_chk(&argvars[1]);
9340 if (retvar != NULL)
9341 set_var(retvar, &v.di_tv, FALSE);
9342 vim_free(v.di_tv.vval.v_string);
9343 }
9344#else
9345 rettv->vval.v_number = -1;
9346#endif
9347}
9348
9349 static void
9350f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9351{
9352 char_u *r = NULL;
9353
9354#ifdef FEAT_CLIENTSERVER
9355 char_u *serverid = get_tv_string_chk(&argvars[0]);
9356
9357 if (serverid != NULL && !check_restricted() && !check_secure())
9358 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009359 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009360# ifdef WIN32
9361 /* The server's HWND is encoded in the 'id' parameter */
9362 long_u n = 0;
9363# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009364
9365 if (argvars[1].v_type != VAR_UNKNOWN)
9366 timeout = get_tv_number(&argvars[1]);
9367
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009368# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009369 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9370 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009371 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009372 if (r == NULL)
9373# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009374 if (check_connection() == FAIL
9375 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9376 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009377# endif
9378 EMSG(_("E277: Unable to read a server reply"));
9379 }
9380#endif
9381 rettv->v_type = VAR_STRING;
9382 rettv->vval.v_string = r;
9383}
9384
9385/*
9386 * "remote_send()" function
9387 */
9388 static void
9389f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9390{
9391 rettv->v_type = VAR_STRING;
9392 rettv->vval.v_string = NULL;
9393#ifdef FEAT_CLIENTSERVER
9394 remote_common(argvars, rettv, FALSE);
9395#endif
9396}
9397
9398/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009399 * "remote_startserver()" function
9400 */
9401 static void
9402f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9403{
9404#ifdef FEAT_CLIENTSERVER
9405 char_u *server = get_tv_string_chk(&argvars[0]);
9406
9407 if (server == NULL)
9408 return; /* type error; errmsg already given */
9409 if (serverName != NULL)
9410 EMSG(_("E941: already started a server"));
9411 else
9412 {
9413# ifdef FEAT_X11
9414 if (check_connection() == OK)
9415 serverRegisterName(X_DISPLAY, server);
9416# else
9417 serverSetName(server);
9418# endif
9419 }
9420#else
9421 EMSG(_("E942: +clientserver feature not available"));
9422#endif
9423}
9424
9425/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009426 * "remove()" function
9427 */
9428 static void
9429f_remove(typval_T *argvars, typval_T *rettv)
9430{
9431 list_T *l;
9432 listitem_T *item, *item2;
9433 listitem_T *li;
9434 long idx;
9435 long end;
9436 char_u *key;
9437 dict_T *d;
9438 dictitem_T *di;
9439 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9440
9441 if (argvars[0].v_type == VAR_DICT)
9442 {
9443 if (argvars[2].v_type != VAR_UNKNOWN)
9444 EMSG2(_(e_toomanyarg), "remove()");
9445 else if ((d = argvars[0].vval.v_dict) != NULL
9446 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9447 {
9448 key = get_tv_string_chk(&argvars[1]);
9449 if (key != NULL)
9450 {
9451 di = dict_find(d, key, -1);
9452 if (di == NULL)
9453 EMSG2(_(e_dictkey), key);
9454 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9455 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9456 {
9457 *rettv = di->di_tv;
9458 init_tv(&di->di_tv);
9459 dictitem_remove(d, di);
9460 }
9461 }
9462 }
9463 }
9464 else if (argvars[0].v_type != VAR_LIST)
9465 EMSG2(_(e_listdictarg), "remove()");
9466 else if ((l = argvars[0].vval.v_list) != NULL
9467 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9468 {
9469 int error = FALSE;
9470
9471 idx = (long)get_tv_number_chk(&argvars[1], &error);
9472 if (error)
9473 ; /* type error: do nothing, errmsg already given */
9474 else if ((item = list_find(l, idx)) == NULL)
9475 EMSGN(_(e_listidx), idx);
9476 else
9477 {
9478 if (argvars[2].v_type == VAR_UNKNOWN)
9479 {
9480 /* Remove one item, return its value. */
9481 vimlist_remove(l, item, item);
9482 *rettv = item->li_tv;
9483 vim_free(item);
9484 }
9485 else
9486 {
9487 /* Remove range of items, return list with values. */
9488 end = (long)get_tv_number_chk(&argvars[2], &error);
9489 if (error)
9490 ; /* type error: do nothing */
9491 else if ((item2 = list_find(l, end)) == NULL)
9492 EMSGN(_(e_listidx), end);
9493 else
9494 {
9495 int cnt = 0;
9496
9497 for (li = item; li != NULL; li = li->li_next)
9498 {
9499 ++cnt;
9500 if (li == item2)
9501 break;
9502 }
9503 if (li == NULL) /* didn't find "item2" after "item" */
9504 EMSG(_(e_invrange));
9505 else
9506 {
9507 vimlist_remove(l, item, item2);
9508 if (rettv_list_alloc(rettv) == OK)
9509 {
9510 l = rettv->vval.v_list;
9511 l->lv_first = item;
9512 l->lv_last = item2;
9513 item->li_prev = NULL;
9514 item2->li_next = NULL;
9515 l->lv_len = cnt;
9516 }
9517 }
9518 }
9519 }
9520 }
9521 }
9522}
9523
9524/*
9525 * "rename({from}, {to})" function
9526 */
9527 static void
9528f_rename(typval_T *argvars, typval_T *rettv)
9529{
9530 char_u buf[NUMBUFLEN];
9531
9532 if (check_restricted() || check_secure())
9533 rettv->vval.v_number = -1;
9534 else
9535 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9536 get_tv_string_buf(&argvars[1], buf));
9537}
9538
9539/*
9540 * "repeat()" function
9541 */
9542 static void
9543f_repeat(typval_T *argvars, typval_T *rettv)
9544{
9545 char_u *p;
9546 int n;
9547 int slen;
9548 int len;
9549 char_u *r;
9550 int i;
9551
9552 n = (int)get_tv_number(&argvars[1]);
9553 if (argvars[0].v_type == VAR_LIST)
9554 {
9555 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9556 while (n-- > 0)
9557 if (list_extend(rettv->vval.v_list,
9558 argvars[0].vval.v_list, NULL) == FAIL)
9559 break;
9560 }
9561 else
9562 {
9563 p = get_tv_string(&argvars[0]);
9564 rettv->v_type = VAR_STRING;
9565 rettv->vval.v_string = NULL;
9566
9567 slen = (int)STRLEN(p);
9568 len = slen * n;
9569 if (len <= 0)
9570 return;
9571
9572 r = alloc(len + 1);
9573 if (r != NULL)
9574 {
9575 for (i = 0; i < n; i++)
9576 mch_memmove(r + i * slen, p, (size_t)slen);
9577 r[len] = NUL;
9578 }
9579
9580 rettv->vval.v_string = r;
9581 }
9582}
9583
9584/*
9585 * "resolve()" function
9586 */
9587 static void
9588f_resolve(typval_T *argvars, typval_T *rettv)
9589{
9590 char_u *p;
9591#ifdef HAVE_READLINK
9592 char_u *buf = NULL;
9593#endif
9594
9595 p = get_tv_string(&argvars[0]);
9596#ifdef FEAT_SHORTCUT
9597 {
9598 char_u *v = NULL;
9599
9600 v = mch_resolve_shortcut(p);
9601 if (v != NULL)
9602 rettv->vval.v_string = v;
9603 else
9604 rettv->vval.v_string = vim_strsave(p);
9605 }
9606#else
9607# ifdef HAVE_READLINK
9608 {
9609 char_u *cpy;
9610 int len;
9611 char_u *remain = NULL;
9612 char_u *q;
9613 int is_relative_to_current = FALSE;
9614 int has_trailing_pathsep = FALSE;
9615 int limit = 100;
9616
9617 p = vim_strsave(p);
9618
9619 if (p[0] == '.' && (vim_ispathsep(p[1])
9620 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9621 is_relative_to_current = TRUE;
9622
9623 len = STRLEN(p);
9624 if (len > 0 && after_pathsep(p, p + len))
9625 {
9626 has_trailing_pathsep = TRUE;
9627 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9628 }
9629
9630 q = getnextcomp(p);
9631 if (*q != NUL)
9632 {
9633 /* Separate the first path component in "p", and keep the
9634 * remainder (beginning with the path separator). */
9635 remain = vim_strsave(q - 1);
9636 q[-1] = NUL;
9637 }
9638
9639 buf = alloc(MAXPATHL + 1);
9640 if (buf == NULL)
9641 goto fail;
9642
9643 for (;;)
9644 {
9645 for (;;)
9646 {
9647 len = readlink((char *)p, (char *)buf, MAXPATHL);
9648 if (len <= 0)
9649 break;
9650 buf[len] = NUL;
9651
9652 if (limit-- == 0)
9653 {
9654 vim_free(p);
9655 vim_free(remain);
9656 EMSG(_("E655: Too many symbolic links (cycle?)"));
9657 rettv->vval.v_string = NULL;
9658 goto fail;
9659 }
9660
9661 /* Ensure that the result will have a trailing path separator
9662 * if the argument has one. */
9663 if (remain == NULL && has_trailing_pathsep)
9664 add_pathsep(buf);
9665
9666 /* Separate the first path component in the link value and
9667 * concatenate the remainders. */
9668 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9669 if (*q != NUL)
9670 {
9671 if (remain == NULL)
9672 remain = vim_strsave(q - 1);
9673 else
9674 {
9675 cpy = concat_str(q - 1, remain);
9676 if (cpy != NULL)
9677 {
9678 vim_free(remain);
9679 remain = cpy;
9680 }
9681 }
9682 q[-1] = NUL;
9683 }
9684
9685 q = gettail(p);
9686 if (q > p && *q == NUL)
9687 {
9688 /* Ignore trailing path separator. */
9689 q[-1] = NUL;
9690 q = gettail(p);
9691 }
9692 if (q > p && !mch_isFullName(buf))
9693 {
9694 /* symlink is relative to directory of argument */
9695 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9696 if (cpy != NULL)
9697 {
9698 STRCPY(cpy, p);
9699 STRCPY(gettail(cpy), buf);
9700 vim_free(p);
9701 p = cpy;
9702 }
9703 }
9704 else
9705 {
9706 vim_free(p);
9707 p = vim_strsave(buf);
9708 }
9709 }
9710
9711 if (remain == NULL)
9712 break;
9713
9714 /* Append the first path component of "remain" to "p". */
9715 q = getnextcomp(remain + 1);
9716 len = q - remain - (*q != NUL);
9717 cpy = vim_strnsave(p, STRLEN(p) + len);
9718 if (cpy != NULL)
9719 {
9720 STRNCAT(cpy, remain, len);
9721 vim_free(p);
9722 p = cpy;
9723 }
9724 /* Shorten "remain". */
9725 if (*q != NUL)
9726 STRMOVE(remain, q - 1);
9727 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009728 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009729 }
9730
9731 /* If the result is a relative path name, make it explicitly relative to
9732 * the current directory if and only if the argument had this form. */
9733 if (!vim_ispathsep(*p))
9734 {
9735 if (is_relative_to_current
9736 && *p != NUL
9737 && !(p[0] == '.'
9738 && (p[1] == NUL
9739 || vim_ispathsep(p[1])
9740 || (p[1] == '.'
9741 && (p[2] == NUL
9742 || vim_ispathsep(p[2]))))))
9743 {
9744 /* Prepend "./". */
9745 cpy = concat_str((char_u *)"./", p);
9746 if (cpy != NULL)
9747 {
9748 vim_free(p);
9749 p = cpy;
9750 }
9751 }
9752 else if (!is_relative_to_current)
9753 {
9754 /* Strip leading "./". */
9755 q = p;
9756 while (q[0] == '.' && vim_ispathsep(q[1]))
9757 q += 2;
9758 if (q > p)
9759 STRMOVE(p, p + 2);
9760 }
9761 }
9762
9763 /* Ensure that the result will have no trailing path separator
9764 * if the argument had none. But keep "/" or "//". */
9765 if (!has_trailing_pathsep)
9766 {
9767 q = p + STRLEN(p);
9768 if (after_pathsep(p, q))
9769 *gettail_sep(p) = NUL;
9770 }
9771
9772 rettv->vval.v_string = p;
9773 }
9774# else
9775 rettv->vval.v_string = vim_strsave(p);
9776# endif
9777#endif
9778
9779 simplify_filename(rettv->vval.v_string);
9780
9781#ifdef HAVE_READLINK
9782fail:
9783 vim_free(buf);
9784#endif
9785 rettv->v_type = VAR_STRING;
9786}
9787
9788/*
9789 * "reverse({list})" function
9790 */
9791 static void
9792f_reverse(typval_T *argvars, typval_T *rettv)
9793{
9794 list_T *l;
9795 listitem_T *li, *ni;
9796
9797 if (argvars[0].v_type != VAR_LIST)
9798 EMSG2(_(e_listarg), "reverse()");
9799 else if ((l = argvars[0].vval.v_list) != NULL
9800 && !tv_check_lock(l->lv_lock,
9801 (char_u *)N_("reverse() argument"), TRUE))
9802 {
9803 li = l->lv_last;
9804 l->lv_first = l->lv_last = NULL;
9805 l->lv_len = 0;
9806 while (li != NULL)
9807 {
9808 ni = li->li_prev;
9809 list_append(l, li);
9810 li = ni;
9811 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009812 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009813 l->lv_idx = l->lv_len - l->lv_idx - 1;
9814 }
9815}
9816
9817#define SP_NOMOVE 0x01 /* don't move cursor */
9818#define SP_REPEAT 0x02 /* repeat to find outer pair */
9819#define SP_RETCOUNT 0x04 /* return matchcount */
9820#define SP_SETPCMARK 0x08 /* set previous context mark */
9821#define SP_START 0x10 /* accept match at start position */
9822#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9823#define SP_END 0x40 /* leave cursor at end of match */
9824#define SP_COLUMN 0x80 /* start at cursor column */
9825
9826static int get_search_arg(typval_T *varp, int *flagsp);
9827
9828/*
9829 * Get flags for a search function.
9830 * Possibly sets "p_ws".
9831 * Returns BACKWARD, FORWARD or zero (for an error).
9832 */
9833 static int
9834get_search_arg(typval_T *varp, int *flagsp)
9835{
9836 int dir = FORWARD;
9837 char_u *flags;
9838 char_u nbuf[NUMBUFLEN];
9839 int mask;
9840
9841 if (varp->v_type != VAR_UNKNOWN)
9842 {
9843 flags = get_tv_string_buf_chk(varp, nbuf);
9844 if (flags == NULL)
9845 return 0; /* type error; errmsg already given */
9846 while (*flags != NUL)
9847 {
9848 switch (*flags)
9849 {
9850 case 'b': dir = BACKWARD; break;
9851 case 'w': p_ws = TRUE; break;
9852 case 'W': p_ws = FALSE; break;
9853 default: mask = 0;
9854 if (flagsp != NULL)
9855 switch (*flags)
9856 {
9857 case 'c': mask = SP_START; break;
9858 case 'e': mask = SP_END; break;
9859 case 'm': mask = SP_RETCOUNT; break;
9860 case 'n': mask = SP_NOMOVE; break;
9861 case 'p': mask = SP_SUBPAT; break;
9862 case 'r': mask = SP_REPEAT; break;
9863 case 's': mask = SP_SETPCMARK; break;
9864 case 'z': mask = SP_COLUMN; break;
9865 }
9866 if (mask == 0)
9867 {
9868 EMSG2(_(e_invarg2), flags);
9869 dir = 0;
9870 }
9871 else
9872 *flagsp |= mask;
9873 }
9874 if (dir == 0)
9875 break;
9876 ++flags;
9877 }
9878 }
9879 return dir;
9880}
9881
9882/*
9883 * Shared by search() and searchpos() functions.
9884 */
9885 static int
9886search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9887{
9888 int flags;
9889 char_u *pat;
9890 pos_T pos;
9891 pos_T save_cursor;
9892 int save_p_ws = p_ws;
9893 int dir;
9894 int retval = 0; /* default: FAIL */
9895 long lnum_stop = 0;
9896 proftime_T tm;
9897#ifdef FEAT_RELTIME
9898 long time_limit = 0;
9899#endif
9900 int options = SEARCH_KEEP;
9901 int subpatnum;
9902
9903 pat = get_tv_string(&argvars[0]);
9904 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9905 if (dir == 0)
9906 goto theend;
9907 flags = *flagsp;
9908 if (flags & SP_START)
9909 options |= SEARCH_START;
9910 if (flags & SP_END)
9911 options |= SEARCH_END;
9912 if (flags & SP_COLUMN)
9913 options |= SEARCH_COL;
9914
9915 /* Optional arguments: line number to stop searching and timeout. */
9916 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9917 {
9918 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9919 if (lnum_stop < 0)
9920 goto theend;
9921#ifdef FEAT_RELTIME
9922 if (argvars[3].v_type != VAR_UNKNOWN)
9923 {
9924 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9925 if (time_limit < 0)
9926 goto theend;
9927 }
9928#endif
9929 }
9930
9931#ifdef FEAT_RELTIME
9932 /* Set the time limit, if there is one. */
9933 profile_setlimit(time_limit, &tm);
9934#endif
9935
9936 /*
9937 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9938 * Check to make sure only those flags are set.
9939 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9940 * flags cannot be set. Check for that condition also.
9941 */
9942 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9943 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9944 {
9945 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9946 goto theend;
9947 }
9948
9949 pos = save_cursor = curwin->w_cursor;
9950 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009951 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009952 if (subpatnum != FAIL)
9953 {
9954 if (flags & SP_SUBPAT)
9955 retval = subpatnum;
9956 else
9957 retval = pos.lnum;
9958 if (flags & SP_SETPCMARK)
9959 setpcmark();
9960 curwin->w_cursor = pos;
9961 if (match_pos != NULL)
9962 {
9963 /* Store the match cursor position */
9964 match_pos->lnum = pos.lnum;
9965 match_pos->col = pos.col + 1;
9966 }
9967 /* "/$" will put the cursor after the end of the line, may need to
9968 * correct that here */
9969 check_cursor();
9970 }
9971
9972 /* If 'n' flag is used: restore cursor position. */
9973 if (flags & SP_NOMOVE)
9974 curwin->w_cursor = save_cursor;
9975 else
9976 curwin->w_set_curswant = TRUE;
9977theend:
9978 p_ws = save_p_ws;
9979
9980 return retval;
9981}
9982
9983#ifdef FEAT_FLOAT
9984
9985/*
9986 * round() is not in C90, use ceil() or floor() instead.
9987 */
9988 float_T
9989vim_round(float_T f)
9990{
9991 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9992}
9993
9994/*
9995 * "round({float})" function
9996 */
9997 static void
9998f_round(typval_T *argvars, typval_T *rettv)
9999{
10000 float_T f = 0.0;
10001
10002 rettv->v_type = VAR_FLOAT;
10003 if (get_float_arg(argvars, &f) == OK)
10004 rettv->vval.v_float = vim_round(f);
10005 else
10006 rettv->vval.v_float = 0.0;
10007}
10008#endif
10009
10010/*
10011 * "screenattr()" function
10012 */
10013 static void
10014f_screenattr(typval_T *argvars, typval_T *rettv)
10015{
10016 int row;
10017 int col;
10018 int c;
10019
10020 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10021 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10022 if (row < 0 || row >= screen_Rows
10023 || col < 0 || col >= screen_Columns)
10024 c = -1;
10025 else
10026 c = ScreenAttrs[LineOffset[row] + col];
10027 rettv->vval.v_number = c;
10028}
10029
10030/*
10031 * "screenchar()" function
10032 */
10033 static void
10034f_screenchar(typval_T *argvars, typval_T *rettv)
10035{
10036 int row;
10037 int col;
10038 int off;
10039 int c;
10040
10041 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10042 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10043 if (row < 0 || row >= screen_Rows
10044 || col < 0 || col >= screen_Columns)
10045 c = -1;
10046 else
10047 {
10048 off = LineOffset[row] + col;
10049#ifdef FEAT_MBYTE
10050 if (enc_utf8 && ScreenLinesUC[off] != 0)
10051 c = ScreenLinesUC[off];
10052 else
10053#endif
10054 c = ScreenLines[off];
10055 }
10056 rettv->vval.v_number = c;
10057}
10058
10059/*
10060 * "screencol()" function
10061 *
10062 * First column is 1 to be consistent with virtcol().
10063 */
10064 static void
10065f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10066{
10067 rettv->vval.v_number = screen_screencol() + 1;
10068}
10069
10070/*
10071 * "screenrow()" function
10072 */
10073 static void
10074f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10075{
10076 rettv->vval.v_number = screen_screenrow() + 1;
10077}
10078
10079/*
10080 * "search()" function
10081 */
10082 static void
10083f_search(typval_T *argvars, typval_T *rettv)
10084{
10085 int flags = 0;
10086
10087 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10088}
10089
10090/*
10091 * "searchdecl()" function
10092 */
10093 static void
10094f_searchdecl(typval_T *argvars, typval_T *rettv)
10095{
10096 int locally = 1;
10097 int thisblock = 0;
10098 int error = FALSE;
10099 char_u *name;
10100
10101 rettv->vval.v_number = 1; /* default: FAIL */
10102
10103 name = get_tv_string_chk(&argvars[0]);
10104 if (argvars[1].v_type != VAR_UNKNOWN)
10105 {
10106 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
10107 if (!error && argvars[2].v_type != VAR_UNKNOWN)
10108 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
10109 }
10110 if (!error && name != NULL)
10111 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10112 locally, thisblock, SEARCH_KEEP) == FAIL;
10113}
10114
10115/*
10116 * Used by searchpair() and searchpairpos()
10117 */
10118 static int
10119searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10120{
10121 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010122 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010123 int save_p_ws = p_ws;
10124 int dir;
10125 int flags = 0;
10126 char_u nbuf1[NUMBUFLEN];
10127 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010128 int retval = 0; /* default: FAIL */
10129 long lnum_stop = 0;
10130 long time_limit = 0;
10131
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010132 /* Get the three pattern arguments: start, middle, end. Will result in an
10133 * error if not a valid argument. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010134 spat = get_tv_string_chk(&argvars[0]);
10135 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
10136 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
10137 if (spat == NULL || mpat == NULL || epat == NULL)
10138 goto theend; /* type error */
10139
10140 /* Handle the optional fourth argument: flags */
10141 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10142 if (dir == 0)
10143 goto theend;
10144
10145 /* Don't accept SP_END or SP_SUBPAT.
10146 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10147 */
10148 if ((flags & (SP_END | SP_SUBPAT)) != 0
10149 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10150 {
10151 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10152 goto theend;
10153 }
10154
10155 /* Using 'r' implies 'W', otherwise it doesn't work. */
10156 if (flags & SP_REPEAT)
10157 p_ws = FALSE;
10158
10159 /* Optional fifth argument: skip expression */
10160 if (argvars[3].v_type == VAR_UNKNOWN
10161 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010162 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010163 else
10164 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010165 skip = &argvars[4];
10166 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10167 && skip->v_type != VAR_STRING)
10168 {
10169 /* Type error */
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010170 EMSG2(_(e_invarg2), get_tv_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010171 goto theend;
10172 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010173 if (argvars[5].v_type != VAR_UNKNOWN)
10174 {
10175 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10176 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010177 {
10178 EMSG2(_(e_invarg2), get_tv_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010179 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010180 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010181#ifdef FEAT_RELTIME
10182 if (argvars[6].v_type != VAR_UNKNOWN)
10183 {
10184 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10185 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010186 {
10187 EMSG2(_(e_invarg2), get_tv_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010188 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010189 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010190 }
10191#endif
10192 }
10193 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010194
10195 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10196 match_pos, lnum_stop, time_limit);
10197
10198theend:
10199 p_ws = save_p_ws;
10200
10201 return retval;
10202}
10203
10204/*
10205 * "searchpair()" function
10206 */
10207 static void
10208f_searchpair(typval_T *argvars, typval_T *rettv)
10209{
10210 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10211}
10212
10213/*
10214 * "searchpairpos()" function
10215 */
10216 static void
10217f_searchpairpos(typval_T *argvars, typval_T *rettv)
10218{
10219 pos_T match_pos;
10220 int lnum = 0;
10221 int col = 0;
10222
10223 if (rettv_list_alloc(rettv) == FAIL)
10224 return;
10225
10226 if (searchpair_cmn(argvars, &match_pos) > 0)
10227 {
10228 lnum = match_pos.lnum;
10229 col = match_pos.col;
10230 }
10231
10232 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10233 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10234}
10235
10236/*
10237 * Search for a start/middle/end thing.
10238 * Used by searchpair(), see its documentation for the details.
10239 * Returns 0 or -1 for no match,
10240 */
10241 long
10242do_searchpair(
10243 char_u *spat, /* start pattern */
10244 char_u *mpat, /* middle pattern */
10245 char_u *epat, /* end pattern */
10246 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010247 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010248 int flags, /* SP_SETPCMARK and other SP_ values */
10249 pos_T *match_pos,
10250 linenr_T lnum_stop, /* stop at this line if not zero */
10251 long time_limit UNUSED) /* stop after this many msec */
10252{
10253 char_u *save_cpo;
10254 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10255 long retval = 0;
10256 pos_T pos;
10257 pos_T firstpos;
10258 pos_T foundpos;
10259 pos_T save_cursor;
10260 pos_T save_pos;
10261 int n;
10262 int r;
10263 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010264 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010265 int err;
10266 int options = SEARCH_KEEP;
10267 proftime_T tm;
10268
10269 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10270 save_cpo = p_cpo;
10271 p_cpo = empty_option;
10272
10273#ifdef FEAT_RELTIME
10274 /* Set the time limit, if there is one. */
10275 profile_setlimit(time_limit, &tm);
10276#endif
10277
10278 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10279 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010280 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10281 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010282 if (pat2 == NULL || pat3 == NULL)
10283 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010284 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010285 if (*mpat == NUL)
10286 STRCPY(pat3, pat2);
10287 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010288 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010289 spat, epat, mpat);
10290 if (flags & SP_START)
10291 options |= SEARCH_START;
10292
Bram Moolenaar48570482017-10-30 21:48:41 +010010293 if (skip != NULL)
10294 {
10295 /* Empty string means to not use the skip expression. */
10296 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10297 use_skip = skip->vval.v_string != NULL
10298 && *skip->vval.v_string != NUL;
10299 }
10300
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010301 save_cursor = curwin->w_cursor;
10302 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010303 CLEAR_POS(&firstpos);
10304 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010305 pat = pat3;
10306 for (;;)
10307 {
10308 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010309 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010310 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010311 /* didn't find it or found the first match again: FAIL */
10312 break;
10313
10314 if (firstpos.lnum == 0)
10315 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010316 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010317 {
10318 /* Found the same position again. Can happen with a pattern that
10319 * has "\zs" at the end and searching backwards. Advance one
10320 * character and try again. */
10321 if (dir == BACKWARD)
10322 decl(&pos);
10323 else
10324 incl(&pos);
10325 }
10326 foundpos = pos;
10327
10328 /* clear the start flag to avoid getting stuck here */
10329 options &= ~SEARCH_START;
10330
10331 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010332 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010333 {
10334 save_pos = curwin->w_cursor;
10335 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010336 err = FALSE;
10337 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010338 curwin->w_cursor = save_pos;
10339 if (err)
10340 {
10341 /* Evaluating {skip} caused an error, break here. */
10342 curwin->w_cursor = save_cursor;
10343 retval = -1;
10344 break;
10345 }
10346 if (r)
10347 continue;
10348 }
10349
10350 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10351 {
10352 /* Found end when searching backwards or start when searching
10353 * forward: nested pair. */
10354 ++nest;
10355 pat = pat2; /* nested, don't search for middle */
10356 }
10357 else
10358 {
10359 /* Found end when searching forward or start when searching
10360 * backward: end of (nested) pair; or found middle in outer pair. */
10361 if (--nest == 1)
10362 pat = pat3; /* outer level, search for middle */
10363 }
10364
10365 if (nest == 0)
10366 {
10367 /* Found the match: return matchcount or line number. */
10368 if (flags & SP_RETCOUNT)
10369 ++retval;
10370 else
10371 retval = pos.lnum;
10372 if (flags & SP_SETPCMARK)
10373 setpcmark();
10374 curwin->w_cursor = pos;
10375 if (!(flags & SP_REPEAT))
10376 break;
10377 nest = 1; /* search for next unmatched */
10378 }
10379 }
10380
10381 if (match_pos != NULL)
10382 {
10383 /* Store the match cursor position */
10384 match_pos->lnum = curwin->w_cursor.lnum;
10385 match_pos->col = curwin->w_cursor.col + 1;
10386 }
10387
10388 /* If 'n' flag is used or search failed: restore cursor position. */
10389 if ((flags & SP_NOMOVE) || retval == 0)
10390 curwin->w_cursor = save_cursor;
10391
10392theend:
10393 vim_free(pat2);
10394 vim_free(pat3);
10395 if (p_cpo == empty_option)
10396 p_cpo = save_cpo;
10397 else
10398 /* Darn, evaluating the {skip} expression changed the value. */
10399 free_string_option(save_cpo);
10400
10401 return retval;
10402}
10403
10404/*
10405 * "searchpos()" function
10406 */
10407 static void
10408f_searchpos(typval_T *argvars, typval_T *rettv)
10409{
10410 pos_T match_pos;
10411 int lnum = 0;
10412 int col = 0;
10413 int n;
10414 int flags = 0;
10415
10416 if (rettv_list_alloc(rettv) == FAIL)
10417 return;
10418
10419 n = search_cmn(argvars, &match_pos, &flags);
10420 if (n > 0)
10421 {
10422 lnum = match_pos.lnum;
10423 col = match_pos.col;
10424 }
10425
10426 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10427 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10428 if (flags & SP_SUBPAT)
10429 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10430}
10431
10432 static void
10433f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10434{
10435#ifdef FEAT_CLIENTSERVER
10436 char_u buf[NUMBUFLEN];
10437 char_u *server = get_tv_string_chk(&argvars[0]);
10438 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10439
10440 rettv->vval.v_number = -1;
10441 if (server == NULL || reply == NULL)
10442 return;
10443 if (check_restricted() || check_secure())
10444 return;
10445# ifdef FEAT_X11
10446 if (check_connection() == FAIL)
10447 return;
10448# endif
10449
10450 if (serverSendReply(server, reply) < 0)
10451 {
10452 EMSG(_("E258: Unable to send to client"));
10453 return;
10454 }
10455 rettv->vval.v_number = 0;
10456#else
10457 rettv->vval.v_number = -1;
10458#endif
10459}
10460
10461 static void
10462f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10463{
10464 char_u *r = NULL;
10465
10466#ifdef FEAT_CLIENTSERVER
10467# ifdef WIN32
10468 r = serverGetVimNames();
10469# else
10470 make_connection();
10471 if (X_DISPLAY != NULL)
10472 r = serverGetVimNames(X_DISPLAY);
10473# endif
10474#endif
10475 rettv->v_type = VAR_STRING;
10476 rettv->vval.v_string = r;
10477}
10478
10479/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010480 * "setbufline()" function
10481 */
10482 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010483f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010484{
10485 linenr_T lnum;
10486 buf_T *buf;
10487
10488 buf = get_buf_tv(&argvars[0], FALSE);
10489 if (buf == NULL)
10490 rettv->vval.v_number = 1; /* FAIL */
10491 else
10492 {
10493 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010494 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010495 }
10496}
10497
10498/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010499 * "setbufvar()" function
10500 */
10501 static void
10502f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10503{
10504 buf_T *buf;
10505 char_u *varname, *bufvarname;
10506 typval_T *varp;
10507 char_u nbuf[NUMBUFLEN];
10508
10509 if (check_restricted() || check_secure())
10510 return;
10511 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10512 varname = get_tv_string_chk(&argvars[1]);
10513 buf = get_buf_tv(&argvars[0], FALSE);
10514 varp = &argvars[2];
10515
10516 if (buf != NULL && varname != NULL && varp != NULL)
10517 {
10518 if (*varname == '&')
10519 {
10520 long numval;
10521 char_u *strval;
10522 int error = FALSE;
10523 aco_save_T aco;
10524
10525 /* set curbuf to be our buf, temporarily */
10526 aucmd_prepbuf(&aco, buf);
10527
10528 ++varname;
10529 numval = (long)get_tv_number_chk(varp, &error);
10530 strval = get_tv_string_buf_chk(varp, nbuf);
10531 if (!error && strval != NULL)
10532 set_option_value(varname, numval, strval, OPT_LOCAL);
10533
10534 /* reset notion of buffer */
10535 aucmd_restbuf(&aco);
10536 }
10537 else
10538 {
10539 buf_T *save_curbuf = curbuf;
10540
10541 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10542 if (bufvarname != NULL)
10543 {
10544 curbuf = buf;
10545 STRCPY(bufvarname, "b:");
10546 STRCPY(bufvarname + 2, varname);
10547 set_var(bufvarname, varp, TRUE);
10548 vim_free(bufvarname);
10549 curbuf = save_curbuf;
10550 }
10551 }
10552 }
10553}
10554
10555 static void
10556f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10557{
10558 dict_T *d;
10559 dictitem_T *di;
10560 char_u *csearch;
10561
10562 if (argvars[0].v_type != VAR_DICT)
10563 {
10564 EMSG(_(e_dictreq));
10565 return;
10566 }
10567
10568 if ((d = argvars[0].vval.v_dict) != NULL)
10569 {
10570 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10571 if (csearch != NULL)
10572 {
10573#ifdef FEAT_MBYTE
10574 if (enc_utf8)
10575 {
10576 int pcc[MAX_MCO];
10577 int c = utfc_ptr2char(csearch, pcc);
10578
10579 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10580 }
10581 else
10582#endif
10583 set_last_csearch(PTR2CHAR(csearch),
10584 csearch, MB_PTR2LEN(csearch));
10585 }
10586
10587 di = dict_find(d, (char_u *)"forward", -1);
10588 if (di != NULL)
10589 set_csearch_direction((int)get_tv_number(&di->di_tv)
10590 ? FORWARD : BACKWARD);
10591
10592 di = dict_find(d, (char_u *)"until", -1);
10593 if (di != NULL)
10594 set_csearch_until(!!get_tv_number(&di->di_tv));
10595 }
10596}
10597
10598/*
10599 * "setcmdpos()" function
10600 */
10601 static void
10602f_setcmdpos(typval_T *argvars, typval_T *rettv)
10603{
10604 int pos = (int)get_tv_number(&argvars[0]) - 1;
10605
10606 if (pos >= 0)
10607 rettv->vval.v_number = set_cmdline_pos(pos);
10608}
10609
10610/*
10611 * "setfperm({fname}, {mode})" function
10612 */
10613 static void
10614f_setfperm(typval_T *argvars, typval_T *rettv)
10615{
10616 char_u *fname;
10617 char_u modebuf[NUMBUFLEN];
10618 char_u *mode_str;
10619 int i;
10620 int mask;
10621 int mode = 0;
10622
10623 rettv->vval.v_number = 0;
10624 fname = get_tv_string_chk(&argvars[0]);
10625 if (fname == NULL)
10626 return;
10627 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10628 if (mode_str == NULL)
10629 return;
10630 if (STRLEN(mode_str) != 9)
10631 {
10632 EMSG2(_(e_invarg2), mode_str);
10633 return;
10634 }
10635
10636 mask = 1;
10637 for (i = 8; i >= 0; --i)
10638 {
10639 if (mode_str[i] != '-')
10640 mode |= mask;
10641 mask = mask << 1;
10642 }
10643 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10644}
10645
10646/*
10647 * "setline()" function
10648 */
10649 static void
10650f_setline(typval_T *argvars, typval_T *rettv)
10651{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010652 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010653
Bram Moolenaarca851592018-06-06 21:04:07 +020010654 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010655}
10656
Bram Moolenaard823fa92016-08-12 16:29:27 +020010657static 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 +020010658
10659/*
10660 * Used by "setqflist()" and "setloclist()" functions
10661 */
10662 static void
10663set_qf_ll_list(
10664 win_T *wp UNUSED,
10665 typval_T *list_arg UNUSED,
10666 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010667 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668 typval_T *rettv)
10669{
10670#ifdef FEAT_QUICKFIX
10671 static char *e_invact = N_("E927: Invalid action: '%s'");
10672 char_u *act;
10673 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010674 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010675#endif
10676
10677 rettv->vval.v_number = -1;
10678
10679#ifdef FEAT_QUICKFIX
10680 if (list_arg->v_type != VAR_LIST)
10681 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010682 else if (recursive != 0)
10683 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010684 else
10685 {
10686 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010687 dict_T *d = NULL;
10688 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010689
10690 if (action_arg->v_type == VAR_STRING)
10691 {
10692 act = get_tv_string_chk(action_arg);
10693 if (act == NULL)
10694 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010695 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10696 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010697 action = *act;
10698 else
10699 EMSG2(_(e_invact), act);
10700 }
10701 else if (action_arg->v_type == VAR_UNKNOWN)
10702 action = ' ';
10703 else
10704 EMSG(_(e_stringreq));
10705
Bram Moolenaard823fa92016-08-12 16:29:27 +020010706 if (action_arg->v_type != VAR_UNKNOWN
10707 && what_arg->v_type != VAR_UNKNOWN)
10708 {
10709 if (what_arg->v_type == VAR_DICT)
10710 d = what_arg->vval.v_dict;
10711 else
10712 {
10713 EMSG(_(e_dictreq));
10714 valid_dict = FALSE;
10715 }
10716 }
10717
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010718 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010719 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010720 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10721 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010722 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010723 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010724 }
10725#endif
10726}
10727
10728/*
10729 * "setloclist()" function
10730 */
10731 static void
10732f_setloclist(typval_T *argvars, typval_T *rettv)
10733{
10734 win_T *win;
10735
10736 rettv->vval.v_number = -1;
10737
10738 win = find_win_by_nr(&argvars[0], NULL);
10739 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010740 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010741}
10742
10743/*
10744 * "setmatches()" function
10745 */
10746 static void
10747f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10748{
10749#ifdef FEAT_SEARCH_EXTRA
10750 list_T *l;
10751 listitem_T *li;
10752 dict_T *d;
10753 list_T *s = NULL;
10754
10755 rettv->vval.v_number = -1;
10756 if (argvars[0].v_type != VAR_LIST)
10757 {
10758 EMSG(_(e_listreq));
10759 return;
10760 }
10761 if ((l = argvars[0].vval.v_list) != NULL)
10762 {
10763
10764 /* To some extent make sure that we are dealing with a list from
10765 * "getmatches()". */
10766 li = l->lv_first;
10767 while (li != NULL)
10768 {
10769 if (li->li_tv.v_type != VAR_DICT
10770 || (d = li->li_tv.vval.v_dict) == NULL)
10771 {
10772 EMSG(_(e_invarg));
10773 return;
10774 }
10775 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10776 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10777 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10778 && dict_find(d, (char_u *)"priority", -1) != NULL
10779 && dict_find(d, (char_u *)"id", -1) != NULL))
10780 {
10781 EMSG(_(e_invarg));
10782 return;
10783 }
10784 li = li->li_next;
10785 }
10786
10787 clear_matches(curwin);
10788 li = l->lv_first;
10789 while (li != NULL)
10790 {
10791 int i = 0;
10792 char_u buf[5];
10793 dictitem_T *di;
10794 char_u *group;
10795 int priority;
10796 int id;
10797 char_u *conceal;
10798
10799 d = li->li_tv.vval.v_dict;
10800 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10801 {
10802 if (s == NULL)
10803 {
10804 s = list_alloc();
10805 if (s == NULL)
10806 return;
10807 }
10808
10809 /* match from matchaddpos() */
10810 for (i = 1; i < 9; i++)
10811 {
10812 sprintf((char *)buf, (char *)"pos%d", i);
10813 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10814 {
10815 if (di->di_tv.v_type != VAR_LIST)
10816 return;
10817
10818 list_append_tv(s, &di->di_tv);
10819 s->lv_refcount++;
10820 }
10821 else
10822 break;
10823 }
10824 }
10825
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010826 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010827 priority = (int)get_dict_number(d, (char_u *)"priority");
10828 id = (int)get_dict_number(d, (char_u *)"id");
10829 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010830 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010831 : NULL;
10832 if (i == 0)
10833 {
10834 match_add(curwin, group,
10835 get_dict_string(d, (char_u *)"pattern", FALSE),
10836 priority, id, NULL, conceal);
10837 }
10838 else
10839 {
10840 match_add(curwin, group, NULL, priority, id, s, conceal);
10841 list_unref(s);
10842 s = NULL;
10843 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010844 vim_free(group);
10845 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010846
10847 li = li->li_next;
10848 }
10849 rettv->vval.v_number = 0;
10850 }
10851#endif
10852}
10853
10854/*
10855 * "setpos()" function
10856 */
10857 static void
10858f_setpos(typval_T *argvars, typval_T *rettv)
10859{
10860 pos_T pos;
10861 int fnum;
10862 char_u *name;
10863 colnr_T curswant = -1;
10864
10865 rettv->vval.v_number = -1;
10866 name = get_tv_string_chk(argvars);
10867 if (name != NULL)
10868 {
10869 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10870 {
10871 if (--pos.col < 0)
10872 pos.col = 0;
10873 if (name[0] == '.' && name[1] == NUL)
10874 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010875 /* set cursor; "fnum" is ignored */
10876 curwin->w_cursor = pos;
10877 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010878 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010879 curwin->w_curswant = curswant - 1;
10880 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010881 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010882 check_cursor();
10883 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010884 }
10885 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10886 {
10887 /* set mark */
10888 if (setmark_pos(name[1], &pos, fnum) == OK)
10889 rettv->vval.v_number = 0;
10890 }
10891 else
10892 EMSG(_(e_invarg));
10893 }
10894 }
10895}
10896
10897/*
10898 * "setqflist()" function
10899 */
10900 static void
10901f_setqflist(typval_T *argvars, typval_T *rettv)
10902{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010903 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010904}
10905
10906/*
10907 * "setreg()" function
10908 */
10909 static void
10910f_setreg(typval_T *argvars, typval_T *rettv)
10911{
10912 int regname;
10913 char_u *strregname;
10914 char_u *stropt;
10915 char_u *strval;
10916 int append;
10917 char_u yank_type;
10918 long block_len;
10919
10920 block_len = -1;
10921 yank_type = MAUTO;
10922 append = FALSE;
10923
10924 strregname = get_tv_string_chk(argvars);
10925 rettv->vval.v_number = 1; /* FAIL is default */
10926
10927 if (strregname == NULL)
10928 return; /* type error; errmsg already given */
10929 regname = *strregname;
10930 if (regname == 0 || regname == '@')
10931 regname = '"';
10932
10933 if (argvars[2].v_type != VAR_UNKNOWN)
10934 {
10935 stropt = get_tv_string_chk(&argvars[2]);
10936 if (stropt == NULL)
10937 return; /* type error */
10938 for (; *stropt != NUL; ++stropt)
10939 switch (*stropt)
10940 {
10941 case 'a': case 'A': /* append */
10942 append = TRUE;
10943 break;
10944 case 'v': case 'c': /* character-wise selection */
10945 yank_type = MCHAR;
10946 break;
10947 case 'V': case 'l': /* line-wise selection */
10948 yank_type = MLINE;
10949 break;
10950 case 'b': case Ctrl_V: /* block-wise selection */
10951 yank_type = MBLOCK;
10952 if (VIM_ISDIGIT(stropt[1]))
10953 {
10954 ++stropt;
10955 block_len = getdigits(&stropt) - 1;
10956 --stropt;
10957 }
10958 break;
10959 }
10960 }
10961
10962 if (argvars[1].v_type == VAR_LIST)
10963 {
10964 char_u **lstval;
10965 char_u **allocval;
10966 char_u buf[NUMBUFLEN];
10967 char_u **curval;
10968 char_u **curallocval;
10969 list_T *ll = argvars[1].vval.v_list;
10970 listitem_T *li;
10971 int len;
10972
10973 /* If the list is NULL handle like an empty list. */
10974 len = ll == NULL ? 0 : ll->lv_len;
10975
10976 /* First half: use for pointers to result lines; second half: use for
10977 * pointers to allocated copies. */
10978 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10979 if (lstval == NULL)
10980 return;
10981 curval = lstval;
10982 allocval = lstval + len + 2;
10983 curallocval = allocval;
10984
10985 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10986 li = li->li_next)
10987 {
10988 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10989 if (strval == NULL)
10990 goto free_lstval;
10991 if (strval == buf)
10992 {
10993 /* Need to make a copy, next get_tv_string_buf_chk() will
10994 * overwrite the string. */
10995 strval = vim_strsave(buf);
10996 if (strval == NULL)
10997 goto free_lstval;
10998 *curallocval++ = strval;
10999 }
11000 *curval++ = strval;
11001 }
11002 *curval++ = NULL;
11003
11004 write_reg_contents_lst(regname, lstval, -1,
11005 append, yank_type, block_len);
11006free_lstval:
11007 while (curallocval > allocval)
11008 vim_free(*--curallocval);
11009 vim_free(lstval);
11010 }
11011 else
11012 {
11013 strval = get_tv_string_chk(&argvars[1]);
11014 if (strval == NULL)
11015 return;
11016 write_reg_contents_ex(regname, strval, -1,
11017 append, yank_type, block_len);
11018 }
11019 rettv->vval.v_number = 0;
11020}
11021
11022/*
11023 * "settabvar()" function
11024 */
11025 static void
11026f_settabvar(typval_T *argvars, typval_T *rettv)
11027{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011028 tabpage_T *save_curtab;
11029 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011030 char_u *varname, *tabvarname;
11031 typval_T *varp;
11032
11033 rettv->vval.v_number = 0;
11034
11035 if (check_restricted() || check_secure())
11036 return;
11037
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011039 varname = get_tv_string_chk(&argvars[1]);
11040 varp = &argvars[2];
11041
Bram Moolenaar4033c552017-09-16 20:54:51 +020011042 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011043 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011044 save_curtab = curtab;
11045 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011046
11047 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11048 if (tabvarname != NULL)
11049 {
11050 STRCPY(tabvarname, "t:");
11051 STRCPY(tabvarname + 2, varname);
11052 set_var(tabvarname, varp, TRUE);
11053 vim_free(tabvarname);
11054 }
11055
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011056 /* Restore current tabpage */
11057 if (valid_tabpage(save_curtab))
11058 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059 }
11060}
11061
11062/*
11063 * "settabwinvar()" function
11064 */
11065 static void
11066f_settabwinvar(typval_T *argvars, typval_T *rettv)
11067{
11068 setwinvar(argvars, rettv, 1);
11069}
11070
11071/*
11072 * "setwinvar()" function
11073 */
11074 static void
11075f_setwinvar(typval_T *argvars, typval_T *rettv)
11076{
11077 setwinvar(argvars, rettv, 0);
11078}
11079
11080#ifdef FEAT_CRYPT
11081/*
11082 * "sha256({string})" function
11083 */
11084 static void
11085f_sha256(typval_T *argvars, typval_T *rettv)
11086{
11087 char_u *p;
11088
11089 p = get_tv_string(&argvars[0]);
11090 rettv->vval.v_string = vim_strsave(
11091 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11092 rettv->v_type = VAR_STRING;
11093}
11094#endif /* FEAT_CRYPT */
11095
11096/*
11097 * "shellescape({string})" function
11098 */
11099 static void
11100f_shellescape(typval_T *argvars, typval_T *rettv)
11101{
Bram Moolenaar20615522017-06-05 18:46:26 +020011102 int do_special = non_zero_arg(&argvars[1]);
11103
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011104 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020011105 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011106 rettv->v_type = VAR_STRING;
11107}
11108
11109/*
11110 * shiftwidth() function
11111 */
11112 static void
11113f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11114{
11115 rettv->vval.v_number = get_sw_value(curbuf);
11116}
11117
11118/*
11119 * "simplify()" function
11120 */
11121 static void
11122f_simplify(typval_T *argvars, typval_T *rettv)
11123{
11124 char_u *p;
11125
11126 p = get_tv_string(&argvars[0]);
11127 rettv->vval.v_string = vim_strsave(p);
11128 simplify_filename(rettv->vval.v_string); /* simplify in place */
11129 rettv->v_type = VAR_STRING;
11130}
11131
11132#ifdef FEAT_FLOAT
11133/*
11134 * "sin()" function
11135 */
11136 static void
11137f_sin(typval_T *argvars, typval_T *rettv)
11138{
11139 float_T f = 0.0;
11140
11141 rettv->v_type = VAR_FLOAT;
11142 if (get_float_arg(argvars, &f) == OK)
11143 rettv->vval.v_float = sin(f);
11144 else
11145 rettv->vval.v_float = 0.0;
11146}
11147
11148/*
11149 * "sinh()" function
11150 */
11151 static void
11152f_sinh(typval_T *argvars, typval_T *rettv)
11153{
11154 float_T f = 0.0;
11155
11156 rettv->v_type = VAR_FLOAT;
11157 if (get_float_arg(argvars, &f) == OK)
11158 rettv->vval.v_float = sinh(f);
11159 else
11160 rettv->vval.v_float = 0.0;
11161}
11162#endif
11163
11164static int
11165#ifdef __BORLANDC__
11166 _RTLENTRYF
11167#endif
11168 item_compare(const void *s1, const void *s2);
11169static int
11170#ifdef __BORLANDC__
11171 _RTLENTRYF
11172#endif
11173 item_compare2(const void *s1, const void *s2);
11174
11175/* struct used in the array that's given to qsort() */
11176typedef struct
11177{
11178 listitem_T *item;
11179 int idx;
11180} sortItem_T;
11181
11182/* struct storing information about current sort */
11183typedef struct
11184{
11185 int item_compare_ic;
11186 int item_compare_numeric;
11187 int item_compare_numbers;
11188#ifdef FEAT_FLOAT
11189 int item_compare_float;
11190#endif
11191 char_u *item_compare_func;
11192 partial_T *item_compare_partial;
11193 dict_T *item_compare_selfdict;
11194 int item_compare_func_err;
11195 int item_compare_keep_zero;
11196} sortinfo_T;
11197static sortinfo_T *sortinfo = NULL;
11198static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
11199#define ITEM_COMPARE_FAIL 999
11200
11201/*
11202 * Compare functions for f_sort() and f_uniq() below.
11203 */
11204 static int
11205#ifdef __BORLANDC__
11206_RTLENTRYF
11207#endif
11208item_compare(const void *s1, const void *s2)
11209{
11210 sortItem_T *si1, *si2;
11211 typval_T *tv1, *tv2;
11212 char_u *p1, *p2;
11213 char_u *tofree1 = NULL, *tofree2 = NULL;
11214 int res;
11215 char_u numbuf1[NUMBUFLEN];
11216 char_u numbuf2[NUMBUFLEN];
11217
11218 si1 = (sortItem_T *)s1;
11219 si2 = (sortItem_T *)s2;
11220 tv1 = &si1->item->li_tv;
11221 tv2 = &si2->item->li_tv;
11222
11223 if (sortinfo->item_compare_numbers)
11224 {
11225 varnumber_T v1 = get_tv_number(tv1);
11226 varnumber_T v2 = get_tv_number(tv2);
11227
11228 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11229 }
11230
11231#ifdef FEAT_FLOAT
11232 if (sortinfo->item_compare_float)
11233 {
11234 float_T v1 = get_tv_float(tv1);
11235 float_T v2 = get_tv_float(tv2);
11236
11237 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11238 }
11239#endif
11240
11241 /* tv2string() puts quotes around a string and allocates memory. Don't do
11242 * that for string variables. Use a single quote when comparing with a
11243 * non-string to do what the docs promise. */
11244 if (tv1->v_type == VAR_STRING)
11245 {
11246 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11247 p1 = (char_u *)"'";
11248 else
11249 p1 = tv1->vval.v_string;
11250 }
11251 else
11252 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11253 if (tv2->v_type == VAR_STRING)
11254 {
11255 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11256 p2 = (char_u *)"'";
11257 else
11258 p2 = tv2->vval.v_string;
11259 }
11260 else
11261 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11262 if (p1 == NULL)
11263 p1 = (char_u *)"";
11264 if (p2 == NULL)
11265 p2 = (char_u *)"";
11266 if (!sortinfo->item_compare_numeric)
11267 {
11268 if (sortinfo->item_compare_ic)
11269 res = STRICMP(p1, p2);
11270 else
11271 res = STRCMP(p1, p2);
11272 }
11273 else
11274 {
11275 double n1, n2;
11276 n1 = strtod((char *)p1, (char **)&p1);
11277 n2 = strtod((char *)p2, (char **)&p2);
11278 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11279 }
11280
11281 /* When the result would be zero, compare the item indexes. Makes the
11282 * sort stable. */
11283 if (res == 0 && !sortinfo->item_compare_keep_zero)
11284 res = si1->idx > si2->idx ? 1 : -1;
11285
11286 vim_free(tofree1);
11287 vim_free(tofree2);
11288 return res;
11289}
11290
11291 static int
11292#ifdef __BORLANDC__
11293_RTLENTRYF
11294#endif
11295item_compare2(const void *s1, const void *s2)
11296{
11297 sortItem_T *si1, *si2;
11298 int res;
11299 typval_T rettv;
11300 typval_T argv[3];
11301 int dummy;
11302 char_u *func_name;
11303 partial_T *partial = sortinfo->item_compare_partial;
11304
11305 /* shortcut after failure in previous call; compare all items equal */
11306 if (sortinfo->item_compare_func_err)
11307 return 0;
11308
11309 si1 = (sortItem_T *)s1;
11310 si2 = (sortItem_T *)s2;
11311
11312 if (partial == NULL)
11313 func_name = sortinfo->item_compare_func;
11314 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011315 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011316
11317 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11318 * in the copy without changing the original list items. */
11319 copy_tv(&si1->item->li_tv, &argv[0]);
11320 copy_tv(&si2->item->li_tv, &argv[1]);
11321
11322 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11323 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011324 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011325 partial, sortinfo->item_compare_selfdict);
11326 clear_tv(&argv[0]);
11327 clear_tv(&argv[1]);
11328
11329 if (res == FAIL)
11330 res = ITEM_COMPARE_FAIL;
11331 else
11332 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11333 if (sortinfo->item_compare_func_err)
11334 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11335 clear_tv(&rettv);
11336
11337 /* When the result would be zero, compare the pointers themselves. Makes
11338 * the sort stable. */
11339 if (res == 0 && !sortinfo->item_compare_keep_zero)
11340 res = si1->idx > si2->idx ? 1 : -1;
11341
11342 return res;
11343}
11344
11345/*
11346 * "sort({list})" function
11347 */
11348 static void
11349do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11350{
11351 list_T *l;
11352 listitem_T *li;
11353 sortItem_T *ptrs;
11354 sortinfo_T *old_sortinfo;
11355 sortinfo_T info;
11356 long len;
11357 long i;
11358
11359 /* Pointer to current info struct used in compare function. Save and
11360 * restore the current one for nested calls. */
11361 old_sortinfo = sortinfo;
11362 sortinfo = &info;
11363
11364 if (argvars[0].v_type != VAR_LIST)
11365 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11366 else
11367 {
11368 l = argvars[0].vval.v_list;
11369 if (l == NULL || tv_check_lock(l->lv_lock,
11370 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11371 TRUE))
11372 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011373 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011374
11375 len = list_len(l);
11376 if (len <= 1)
11377 goto theend; /* short list sorts pretty quickly */
11378
11379 info.item_compare_ic = FALSE;
11380 info.item_compare_numeric = FALSE;
11381 info.item_compare_numbers = FALSE;
11382#ifdef FEAT_FLOAT
11383 info.item_compare_float = FALSE;
11384#endif
11385 info.item_compare_func = NULL;
11386 info.item_compare_partial = NULL;
11387 info.item_compare_selfdict = NULL;
11388 if (argvars[1].v_type != VAR_UNKNOWN)
11389 {
11390 /* optional second argument: {func} */
11391 if (argvars[1].v_type == VAR_FUNC)
11392 info.item_compare_func = argvars[1].vval.v_string;
11393 else if (argvars[1].v_type == VAR_PARTIAL)
11394 info.item_compare_partial = argvars[1].vval.v_partial;
11395 else
11396 {
11397 int error = FALSE;
11398
11399 i = (long)get_tv_number_chk(&argvars[1], &error);
11400 if (error)
11401 goto theend; /* type error; errmsg already given */
11402 if (i == 1)
11403 info.item_compare_ic = TRUE;
11404 else if (argvars[1].v_type != VAR_NUMBER)
11405 info.item_compare_func = get_tv_string(&argvars[1]);
11406 else if (i != 0)
11407 {
11408 EMSG(_(e_invarg));
11409 goto theend;
11410 }
11411 if (info.item_compare_func != NULL)
11412 {
11413 if (*info.item_compare_func == NUL)
11414 {
11415 /* empty string means default sort */
11416 info.item_compare_func = NULL;
11417 }
11418 else if (STRCMP(info.item_compare_func, "n") == 0)
11419 {
11420 info.item_compare_func = NULL;
11421 info.item_compare_numeric = TRUE;
11422 }
11423 else if (STRCMP(info.item_compare_func, "N") == 0)
11424 {
11425 info.item_compare_func = NULL;
11426 info.item_compare_numbers = TRUE;
11427 }
11428#ifdef FEAT_FLOAT
11429 else if (STRCMP(info.item_compare_func, "f") == 0)
11430 {
11431 info.item_compare_func = NULL;
11432 info.item_compare_float = TRUE;
11433 }
11434#endif
11435 else if (STRCMP(info.item_compare_func, "i") == 0)
11436 {
11437 info.item_compare_func = NULL;
11438 info.item_compare_ic = TRUE;
11439 }
11440 }
11441 }
11442
11443 if (argvars[2].v_type != VAR_UNKNOWN)
11444 {
11445 /* optional third argument: {dict} */
11446 if (argvars[2].v_type != VAR_DICT)
11447 {
11448 EMSG(_(e_dictreq));
11449 goto theend;
11450 }
11451 info.item_compare_selfdict = argvars[2].vval.v_dict;
11452 }
11453 }
11454
11455 /* Make an array with each entry pointing to an item in the List. */
11456 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11457 if (ptrs == NULL)
11458 goto theend;
11459
11460 i = 0;
11461 if (sort)
11462 {
11463 /* sort(): ptrs will be the list to sort */
11464 for (li = l->lv_first; li != NULL; li = li->li_next)
11465 {
11466 ptrs[i].item = li;
11467 ptrs[i].idx = i;
11468 ++i;
11469 }
11470
11471 info.item_compare_func_err = FALSE;
11472 info.item_compare_keep_zero = FALSE;
11473 /* test the compare function */
11474 if ((info.item_compare_func != NULL
11475 || info.item_compare_partial != NULL)
11476 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11477 == ITEM_COMPARE_FAIL)
11478 EMSG(_("E702: Sort compare function failed"));
11479 else
11480 {
11481 /* Sort the array with item pointers. */
11482 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11483 info.item_compare_func == NULL
11484 && info.item_compare_partial == NULL
11485 ? item_compare : item_compare2);
11486
11487 if (!info.item_compare_func_err)
11488 {
11489 /* Clear the List and append the items in sorted order. */
11490 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11491 l->lv_len = 0;
11492 for (i = 0; i < len; ++i)
11493 list_append(l, ptrs[i].item);
11494 }
11495 }
11496 }
11497 else
11498 {
11499 int (*item_compare_func_ptr)(const void *, const void *);
11500
11501 /* f_uniq(): ptrs will be a stack of items to remove */
11502 info.item_compare_func_err = FALSE;
11503 info.item_compare_keep_zero = TRUE;
11504 item_compare_func_ptr = info.item_compare_func != NULL
11505 || info.item_compare_partial != NULL
11506 ? item_compare2 : item_compare;
11507
11508 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11509 li = li->li_next)
11510 {
11511 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11512 == 0)
11513 ptrs[i++].item = li;
11514 if (info.item_compare_func_err)
11515 {
11516 EMSG(_("E882: Uniq compare function failed"));
11517 break;
11518 }
11519 }
11520
11521 if (!info.item_compare_func_err)
11522 {
11523 while (--i >= 0)
11524 {
11525 li = ptrs[i].item->li_next;
11526 ptrs[i].item->li_next = li->li_next;
11527 if (li->li_next != NULL)
11528 li->li_next->li_prev = ptrs[i].item;
11529 else
11530 l->lv_last = ptrs[i].item;
11531 list_fix_watch(l, li);
11532 listitem_free(li);
11533 l->lv_len--;
11534 }
11535 }
11536 }
11537
11538 vim_free(ptrs);
11539 }
11540theend:
11541 sortinfo = old_sortinfo;
11542}
11543
11544/*
11545 * "sort({list})" function
11546 */
11547 static void
11548f_sort(typval_T *argvars, typval_T *rettv)
11549{
11550 do_sort_uniq(argvars, rettv, TRUE);
11551}
11552
11553/*
11554 * "uniq({list})" function
11555 */
11556 static void
11557f_uniq(typval_T *argvars, typval_T *rettv)
11558{
11559 do_sort_uniq(argvars, rettv, FALSE);
11560}
11561
11562/*
11563 * "soundfold({word})" function
11564 */
11565 static void
11566f_soundfold(typval_T *argvars, typval_T *rettv)
11567{
11568 char_u *s;
11569
11570 rettv->v_type = VAR_STRING;
11571 s = get_tv_string(&argvars[0]);
11572#ifdef FEAT_SPELL
11573 rettv->vval.v_string = eval_soundfold(s);
11574#else
11575 rettv->vval.v_string = vim_strsave(s);
11576#endif
11577}
11578
11579/*
11580 * "spellbadword()" function
11581 */
11582 static void
11583f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11584{
11585 char_u *word = (char_u *)"";
11586 hlf_T attr = HLF_COUNT;
11587 int len = 0;
11588
11589 if (rettv_list_alloc(rettv) == FAIL)
11590 return;
11591
11592#ifdef FEAT_SPELL
11593 if (argvars[0].v_type == VAR_UNKNOWN)
11594 {
11595 /* Find the start and length of the badly spelled word. */
11596 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11597 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011598 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011599 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011600 curwin->w_set_curswant = TRUE;
11601 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011602 }
11603 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11604 {
11605 char_u *str = get_tv_string_chk(&argvars[0]);
11606 int capcol = -1;
11607
11608 if (str != NULL)
11609 {
11610 /* Check the argument for spelling. */
11611 while (*str != NUL)
11612 {
11613 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11614 if (attr != HLF_COUNT)
11615 {
11616 word = str;
11617 break;
11618 }
11619 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020011620 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011621 }
11622 }
11623 }
11624#endif
11625
11626 list_append_string(rettv->vval.v_list, word, len);
11627 list_append_string(rettv->vval.v_list, (char_u *)(
11628 attr == HLF_SPB ? "bad" :
11629 attr == HLF_SPR ? "rare" :
11630 attr == HLF_SPL ? "local" :
11631 attr == HLF_SPC ? "caps" :
11632 ""), -1);
11633}
11634
11635/*
11636 * "spellsuggest()" function
11637 */
11638 static void
11639f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11640{
11641#ifdef FEAT_SPELL
11642 char_u *str;
11643 int typeerr = FALSE;
11644 int maxcount;
11645 garray_T ga;
11646 int i;
11647 listitem_T *li;
11648 int need_capital = FALSE;
11649#endif
11650
11651 if (rettv_list_alloc(rettv) == FAIL)
11652 return;
11653
11654#ifdef FEAT_SPELL
11655 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11656 {
11657 str = get_tv_string(&argvars[0]);
11658 if (argvars[1].v_type != VAR_UNKNOWN)
11659 {
11660 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11661 if (maxcount <= 0)
11662 return;
11663 if (argvars[2].v_type != VAR_UNKNOWN)
11664 {
11665 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11666 if (typeerr)
11667 return;
11668 }
11669 }
11670 else
11671 maxcount = 25;
11672
11673 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11674
11675 for (i = 0; i < ga.ga_len; ++i)
11676 {
11677 str = ((char_u **)ga.ga_data)[i];
11678
11679 li = listitem_alloc();
11680 if (li == NULL)
11681 vim_free(str);
11682 else
11683 {
11684 li->li_tv.v_type = VAR_STRING;
11685 li->li_tv.v_lock = 0;
11686 li->li_tv.vval.v_string = str;
11687 list_append(rettv->vval.v_list, li);
11688 }
11689 }
11690 ga_clear(&ga);
11691 }
11692#endif
11693}
11694
11695 static void
11696f_split(typval_T *argvars, typval_T *rettv)
11697{
11698 char_u *str;
11699 char_u *end;
11700 char_u *pat = NULL;
11701 regmatch_T regmatch;
11702 char_u patbuf[NUMBUFLEN];
11703 char_u *save_cpo;
11704 int match;
11705 colnr_T col = 0;
11706 int keepempty = FALSE;
11707 int typeerr = FALSE;
11708
11709 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11710 save_cpo = p_cpo;
11711 p_cpo = (char_u *)"";
11712
11713 str = get_tv_string(&argvars[0]);
11714 if (argvars[1].v_type != VAR_UNKNOWN)
11715 {
11716 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11717 if (pat == NULL)
11718 typeerr = TRUE;
11719 if (argvars[2].v_type != VAR_UNKNOWN)
11720 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11721 }
11722 if (pat == NULL || *pat == NUL)
11723 pat = (char_u *)"[\\x01- ]\\+";
11724
11725 if (rettv_list_alloc(rettv) == FAIL)
11726 return;
11727 if (typeerr)
11728 return;
11729
11730 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11731 if (regmatch.regprog != NULL)
11732 {
11733 regmatch.rm_ic = FALSE;
11734 while (*str != NUL || keepempty)
11735 {
11736 if (*str == NUL)
11737 match = FALSE; /* empty item at the end */
11738 else
11739 match = vim_regexec_nl(&regmatch, str, col);
11740 if (match)
11741 end = regmatch.startp[0];
11742 else
11743 end = str + STRLEN(str);
11744 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11745 && *str != NUL && match && end < regmatch.endp[0]))
11746 {
11747 if (list_append_string(rettv->vval.v_list, str,
11748 (int)(end - str)) == FAIL)
11749 break;
11750 }
11751 if (!match)
11752 break;
11753 /* Advance to just after the match. */
11754 if (regmatch.endp[0] > str)
11755 col = 0;
11756 else
11757 {
11758 /* Don't get stuck at the same match. */
11759#ifdef FEAT_MBYTE
11760 col = (*mb_ptr2len)(regmatch.endp[0]);
11761#else
11762 col = 1;
11763#endif
11764 }
11765 str = regmatch.endp[0];
11766 }
11767
11768 vim_regfree(regmatch.regprog);
11769 }
11770
11771 p_cpo = save_cpo;
11772}
11773
11774#ifdef FEAT_FLOAT
11775/*
11776 * "sqrt()" function
11777 */
11778 static void
11779f_sqrt(typval_T *argvars, typval_T *rettv)
11780{
11781 float_T f = 0.0;
11782
11783 rettv->v_type = VAR_FLOAT;
11784 if (get_float_arg(argvars, &f) == OK)
11785 rettv->vval.v_float = sqrt(f);
11786 else
11787 rettv->vval.v_float = 0.0;
11788}
11789
11790/*
11791 * "str2float()" function
11792 */
11793 static void
11794f_str2float(typval_T *argvars, typval_T *rettv)
11795{
11796 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011797 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011798
Bram Moolenaar08243d22017-01-10 16:12:29 +010011799 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011800 p = skipwhite(p + 1);
11801 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011802 if (isneg)
11803 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011804 rettv->v_type = VAR_FLOAT;
11805}
11806#endif
11807
11808/*
11809 * "str2nr()" function
11810 */
11811 static void
11812f_str2nr(typval_T *argvars, typval_T *rettv)
11813{
11814 int base = 10;
11815 char_u *p;
11816 varnumber_T n;
11817 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011818 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011819
11820 if (argvars[1].v_type != VAR_UNKNOWN)
11821 {
11822 base = (int)get_tv_number(&argvars[1]);
11823 if (base != 2 && base != 8 && base != 10 && base != 16)
11824 {
11825 EMSG(_(e_invarg));
11826 return;
11827 }
11828 }
11829
11830 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011831 isneg = (*p == '-');
11832 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011833 p = skipwhite(p + 1);
11834 switch (base)
11835 {
11836 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11837 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11838 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11839 default: what = 0;
11840 }
11841 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011842 if (isneg)
11843 rettv->vval.v_number = -n;
11844 else
11845 rettv->vval.v_number = n;
11846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011847}
11848
11849#ifdef HAVE_STRFTIME
11850/*
11851 * "strftime({format}[, {time}])" function
11852 */
11853 static void
11854f_strftime(typval_T *argvars, typval_T *rettv)
11855{
11856 char_u result_buf[256];
11857 struct tm *curtime;
11858 time_t seconds;
11859 char_u *p;
11860
11861 rettv->v_type = VAR_STRING;
11862
11863 p = get_tv_string(&argvars[0]);
11864 if (argvars[1].v_type == VAR_UNKNOWN)
11865 seconds = time(NULL);
11866 else
11867 seconds = (time_t)get_tv_number(&argvars[1]);
11868 curtime = localtime(&seconds);
11869 /* MSVC returns NULL for an invalid value of seconds. */
11870 if (curtime == NULL)
11871 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11872 else
11873 {
11874# ifdef FEAT_MBYTE
11875 vimconv_T conv;
11876 char_u *enc;
11877
11878 conv.vc_type = CONV_NONE;
11879 enc = enc_locale();
11880 convert_setup(&conv, p_enc, enc);
11881 if (conv.vc_type != CONV_NONE)
11882 p = string_convert(&conv, p, NULL);
11883# endif
11884 if (p != NULL)
11885 (void)strftime((char *)result_buf, sizeof(result_buf),
11886 (char *)p, curtime);
11887 else
11888 result_buf[0] = NUL;
11889
11890# ifdef FEAT_MBYTE
11891 if (conv.vc_type != CONV_NONE)
11892 vim_free(p);
11893 convert_setup(&conv, enc, p_enc);
11894 if (conv.vc_type != CONV_NONE)
11895 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11896 else
11897# endif
11898 rettv->vval.v_string = vim_strsave(result_buf);
11899
11900# ifdef FEAT_MBYTE
11901 /* Release conversion descriptors */
11902 convert_setup(&conv, NULL, NULL);
11903 vim_free(enc);
11904# endif
11905 }
11906}
11907#endif
11908
11909/*
11910 * "strgetchar()" function
11911 */
11912 static void
11913f_strgetchar(typval_T *argvars, typval_T *rettv)
11914{
11915 char_u *str;
11916 int len;
11917 int error = FALSE;
11918 int charidx;
11919
11920 rettv->vval.v_number = -1;
11921 str = get_tv_string_chk(&argvars[0]);
11922 if (str == NULL)
11923 return;
11924 len = (int)STRLEN(str);
11925 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11926 if (error)
11927 return;
11928#ifdef FEAT_MBYTE
11929 {
11930 int byteidx = 0;
11931
11932 while (charidx >= 0 && byteidx < len)
11933 {
11934 if (charidx == 0)
11935 {
11936 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11937 break;
11938 }
11939 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011940 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011941 }
11942 }
11943#else
11944 if (charidx < len)
11945 rettv->vval.v_number = str[charidx];
11946#endif
11947}
11948
11949/*
11950 * "stridx()" function
11951 */
11952 static void
11953f_stridx(typval_T *argvars, typval_T *rettv)
11954{
11955 char_u buf[NUMBUFLEN];
11956 char_u *needle;
11957 char_u *haystack;
11958 char_u *save_haystack;
11959 char_u *pos;
11960 int start_idx;
11961
11962 needle = get_tv_string_chk(&argvars[1]);
11963 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11964 rettv->vval.v_number = -1;
11965 if (needle == NULL || haystack == NULL)
11966 return; /* type error; errmsg already given */
11967
11968 if (argvars[2].v_type != VAR_UNKNOWN)
11969 {
11970 int error = FALSE;
11971
11972 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11973 if (error || start_idx >= (int)STRLEN(haystack))
11974 return;
11975 if (start_idx >= 0)
11976 haystack += start_idx;
11977 }
11978
11979 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11980 if (pos != NULL)
11981 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11982}
11983
11984/*
11985 * "string()" function
11986 */
11987 static void
11988f_string(typval_T *argvars, typval_T *rettv)
11989{
11990 char_u *tofree;
11991 char_u numbuf[NUMBUFLEN];
11992
11993 rettv->v_type = VAR_STRING;
11994 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11995 get_copyID());
11996 /* Make a copy if we have a value but it's not in allocated memory. */
11997 if (rettv->vval.v_string != NULL && tofree == NULL)
11998 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11999}
12000
12001/*
12002 * "strlen()" function
12003 */
12004 static void
12005f_strlen(typval_T *argvars, typval_T *rettv)
12006{
12007 rettv->vval.v_number = (varnumber_T)(STRLEN(
12008 get_tv_string(&argvars[0])));
12009}
12010
12011/*
12012 * "strchars()" function
12013 */
12014 static void
12015f_strchars(typval_T *argvars, typval_T *rettv)
12016{
12017 char_u *s = get_tv_string(&argvars[0]);
12018 int skipcc = 0;
12019#ifdef FEAT_MBYTE
12020 varnumber_T len = 0;
12021 int (*func_mb_ptr2char_adv)(char_u **pp);
12022#endif
12023
12024 if (argvars[1].v_type != VAR_UNKNOWN)
12025 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
12026 if (skipcc < 0 || skipcc > 1)
12027 EMSG(_(e_invarg));
12028 else
12029 {
12030#ifdef FEAT_MBYTE
12031 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12032 while (*s != NUL)
12033 {
12034 func_mb_ptr2char_adv(&s);
12035 ++len;
12036 }
12037 rettv->vval.v_number = len;
12038#else
12039 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12040#endif
12041 }
12042}
12043
12044/*
12045 * "strdisplaywidth()" function
12046 */
12047 static void
12048f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12049{
12050 char_u *s = get_tv_string(&argvars[0]);
12051 int col = 0;
12052
12053 if (argvars[1].v_type != VAR_UNKNOWN)
12054 col = (int)get_tv_number(&argvars[1]);
12055
12056 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12057}
12058
12059/*
12060 * "strwidth()" function
12061 */
12062 static void
12063f_strwidth(typval_T *argvars, typval_T *rettv)
12064{
12065 char_u *s = get_tv_string(&argvars[0]);
12066
12067 rettv->vval.v_number = (varnumber_T)(
12068#ifdef FEAT_MBYTE
12069 mb_string2cells(s, -1)
12070#else
12071 STRLEN(s)
12072#endif
12073 );
12074}
12075
12076/*
12077 * "strcharpart()" function
12078 */
12079 static void
12080f_strcharpart(typval_T *argvars, typval_T *rettv)
12081{
12082#ifdef FEAT_MBYTE
12083 char_u *p;
12084 int nchar;
12085 int nbyte = 0;
12086 int charlen;
12087 int len = 0;
12088 int slen;
12089 int error = FALSE;
12090
12091 p = get_tv_string(&argvars[0]);
12092 slen = (int)STRLEN(p);
12093
12094 nchar = (int)get_tv_number_chk(&argvars[1], &error);
12095 if (!error)
12096 {
12097 if (nchar > 0)
12098 while (nchar > 0 && nbyte < slen)
12099 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012100 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012101 --nchar;
12102 }
12103 else
12104 nbyte = nchar;
12105 if (argvars[2].v_type != VAR_UNKNOWN)
12106 {
12107 charlen = (int)get_tv_number(&argvars[2]);
12108 while (charlen > 0 && nbyte + len < slen)
12109 {
12110 int off = nbyte + len;
12111
12112 if (off < 0)
12113 len += 1;
12114 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012115 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012116 --charlen;
12117 }
12118 }
12119 else
12120 len = slen - nbyte; /* default: all bytes that are available. */
12121 }
12122
12123 /*
12124 * Only return the overlap between the specified part and the actual
12125 * string.
12126 */
12127 if (nbyte < 0)
12128 {
12129 len += nbyte;
12130 nbyte = 0;
12131 }
12132 else if (nbyte > slen)
12133 nbyte = slen;
12134 if (len < 0)
12135 len = 0;
12136 else if (nbyte + len > slen)
12137 len = slen - nbyte;
12138
12139 rettv->v_type = VAR_STRING;
12140 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12141#else
12142 f_strpart(argvars, rettv);
12143#endif
12144}
12145
12146/*
12147 * "strpart()" function
12148 */
12149 static void
12150f_strpart(typval_T *argvars, typval_T *rettv)
12151{
12152 char_u *p;
12153 int n;
12154 int len;
12155 int slen;
12156 int error = FALSE;
12157
12158 p = get_tv_string(&argvars[0]);
12159 slen = (int)STRLEN(p);
12160
12161 n = (int)get_tv_number_chk(&argvars[1], &error);
12162 if (error)
12163 len = 0;
12164 else if (argvars[2].v_type != VAR_UNKNOWN)
12165 len = (int)get_tv_number(&argvars[2]);
12166 else
12167 len = slen - n; /* default len: all bytes that are available. */
12168
12169 /*
12170 * Only return the overlap between the specified part and the actual
12171 * string.
12172 */
12173 if (n < 0)
12174 {
12175 len += n;
12176 n = 0;
12177 }
12178 else if (n > slen)
12179 n = slen;
12180 if (len < 0)
12181 len = 0;
12182 else if (n + len > slen)
12183 len = slen - n;
12184
12185 rettv->v_type = VAR_STRING;
12186 rettv->vval.v_string = vim_strnsave(p + n, len);
12187}
12188
12189/*
12190 * "strridx()" function
12191 */
12192 static void
12193f_strridx(typval_T *argvars, typval_T *rettv)
12194{
12195 char_u buf[NUMBUFLEN];
12196 char_u *needle;
12197 char_u *haystack;
12198 char_u *rest;
12199 char_u *lastmatch = NULL;
12200 int haystack_len, end_idx;
12201
12202 needle = get_tv_string_chk(&argvars[1]);
12203 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12204
12205 rettv->vval.v_number = -1;
12206 if (needle == NULL || haystack == NULL)
12207 return; /* type error; errmsg already given */
12208
12209 haystack_len = (int)STRLEN(haystack);
12210 if (argvars[2].v_type != VAR_UNKNOWN)
12211 {
12212 /* Third argument: upper limit for index */
12213 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12214 if (end_idx < 0)
12215 return; /* can never find a match */
12216 }
12217 else
12218 end_idx = haystack_len;
12219
12220 if (*needle == NUL)
12221 {
12222 /* Empty string matches past the end. */
12223 lastmatch = haystack + end_idx;
12224 }
12225 else
12226 {
12227 for (rest = haystack; *rest != '\0'; ++rest)
12228 {
12229 rest = (char_u *)strstr((char *)rest, (char *)needle);
12230 if (rest == NULL || rest > haystack + end_idx)
12231 break;
12232 lastmatch = rest;
12233 }
12234 }
12235
12236 if (lastmatch == NULL)
12237 rettv->vval.v_number = -1;
12238 else
12239 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12240}
12241
12242/*
12243 * "strtrans()" function
12244 */
12245 static void
12246f_strtrans(typval_T *argvars, typval_T *rettv)
12247{
12248 rettv->v_type = VAR_STRING;
12249 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12250}
12251
12252/*
12253 * "submatch()" function
12254 */
12255 static void
12256f_submatch(typval_T *argvars, typval_T *rettv)
12257{
12258 int error = FALSE;
12259 int no;
12260 int retList = 0;
12261
12262 no = (int)get_tv_number_chk(&argvars[0], &error);
12263 if (error)
12264 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012265 if (no < 0 || no >= NSUBEXP)
12266 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012267 EMSGN(_("E935: invalid submatch number: %d"), no);
12268 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012269 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012270 if (argvars[1].v_type != VAR_UNKNOWN)
12271 retList = (int)get_tv_number_chk(&argvars[1], &error);
12272 if (error)
12273 return;
12274
12275 if (retList == 0)
12276 {
12277 rettv->v_type = VAR_STRING;
12278 rettv->vval.v_string = reg_submatch(no);
12279 }
12280 else
12281 {
12282 rettv->v_type = VAR_LIST;
12283 rettv->vval.v_list = reg_submatch_list(no);
12284 }
12285}
12286
12287/*
12288 * "substitute()" function
12289 */
12290 static void
12291f_substitute(typval_T *argvars, typval_T *rettv)
12292{
12293 char_u patbuf[NUMBUFLEN];
12294 char_u subbuf[NUMBUFLEN];
12295 char_u flagsbuf[NUMBUFLEN];
12296
12297 char_u *str = get_tv_string_chk(&argvars[0]);
12298 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012299 char_u *sub = NULL;
12300 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012301 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12302
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012303 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12304 expr = &argvars[2];
12305 else
12306 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12307
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012308 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012309 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12310 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012311 rettv->vval.v_string = NULL;
12312 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012313 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012314}
12315
12316/*
12317 * "synID(lnum, col, trans)" function
12318 */
12319 static void
12320f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12321{
12322 int id = 0;
12323#ifdef FEAT_SYN_HL
12324 linenr_T lnum;
12325 colnr_T col;
12326 int trans;
12327 int transerr = FALSE;
12328
12329 lnum = get_tv_lnum(argvars); /* -1 on type error */
12330 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12331 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12332
12333 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12334 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12335 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12336#endif
12337
12338 rettv->vval.v_number = id;
12339}
12340
12341/*
12342 * "synIDattr(id, what [, mode])" function
12343 */
12344 static void
12345f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12346{
12347 char_u *p = NULL;
12348#ifdef FEAT_SYN_HL
12349 int id;
12350 char_u *what;
12351 char_u *mode;
12352 char_u modebuf[NUMBUFLEN];
12353 int modec;
12354
12355 id = (int)get_tv_number(&argvars[0]);
12356 what = get_tv_string(&argvars[1]);
12357 if (argvars[2].v_type != VAR_UNKNOWN)
12358 {
12359 mode = get_tv_string_buf(&argvars[2], modebuf);
12360 modec = TOLOWER_ASC(mode[0]);
12361 if (modec != 't' && modec != 'c' && modec != 'g')
12362 modec = 0; /* replace invalid with current */
12363 }
12364 else
12365 {
12366#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12367 if (USE_24BIT)
12368 modec = 'g';
12369 else
12370#endif
12371 if (t_colors > 1)
12372 modec = 'c';
12373 else
12374 modec = 't';
12375 }
12376
12377
12378 switch (TOLOWER_ASC(what[0]))
12379 {
12380 case 'b':
12381 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12382 p = highlight_color(id, what, modec);
12383 else /* bold */
12384 p = highlight_has_attr(id, HL_BOLD, modec);
12385 break;
12386
12387 case 'f': /* fg[#] or font */
12388 p = highlight_color(id, what, modec);
12389 break;
12390
12391 case 'i':
12392 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12393 p = highlight_has_attr(id, HL_INVERSE, modec);
12394 else /* italic */
12395 p = highlight_has_attr(id, HL_ITALIC, modec);
12396 break;
12397
12398 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012399 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012400 break;
12401
12402 case 'r': /* reverse */
12403 p = highlight_has_attr(id, HL_INVERSE, modec);
12404 break;
12405
12406 case 's':
12407 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12408 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012409 /* strikeout */
12410 else if (TOLOWER_ASC(what[1]) == 't' &&
12411 TOLOWER_ASC(what[2]) == 'r')
12412 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012413 else /* standout */
12414 p = highlight_has_attr(id, HL_STANDOUT, modec);
12415 break;
12416
12417 case 'u':
12418 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12419 /* underline */
12420 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12421 else
12422 /* undercurl */
12423 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12424 break;
12425 }
12426
12427 if (p != NULL)
12428 p = vim_strsave(p);
12429#endif
12430 rettv->v_type = VAR_STRING;
12431 rettv->vval.v_string = p;
12432}
12433
12434/*
12435 * "synIDtrans(id)" function
12436 */
12437 static void
12438f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12439{
12440 int id;
12441
12442#ifdef FEAT_SYN_HL
12443 id = (int)get_tv_number(&argvars[0]);
12444
12445 if (id > 0)
12446 id = syn_get_final_id(id);
12447 else
12448#endif
12449 id = 0;
12450
12451 rettv->vval.v_number = id;
12452}
12453
12454/*
12455 * "synconcealed(lnum, col)" function
12456 */
12457 static void
12458f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12459{
12460#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12461 linenr_T lnum;
12462 colnr_T col;
12463 int syntax_flags = 0;
12464 int cchar;
12465 int matchid = 0;
12466 char_u str[NUMBUFLEN];
12467#endif
12468
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012469 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012470
12471#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12472 lnum = get_tv_lnum(argvars); /* -1 on type error */
12473 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12474
12475 vim_memset(str, NUL, sizeof(str));
12476
12477 if (rettv_list_alloc(rettv) != FAIL)
12478 {
12479 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12480 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12481 && curwin->w_p_cole > 0)
12482 {
12483 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12484 syntax_flags = get_syntax_info(&matchid);
12485
12486 /* get the conceal character */
12487 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12488 {
12489 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012490 if (cchar == NUL && curwin->w_p_cole == 1)
12491 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012492 if (cchar != NUL)
12493 {
12494# ifdef FEAT_MBYTE
12495 if (has_mbyte)
12496 (*mb_char2bytes)(cchar, str);
12497 else
12498# endif
12499 str[0] = cchar;
12500 }
12501 }
12502 }
12503
12504 list_append_number(rettv->vval.v_list,
12505 (syntax_flags & HL_CONCEAL) != 0);
12506 /* -1 to auto-determine strlen */
12507 list_append_string(rettv->vval.v_list, str, -1);
12508 list_append_number(rettv->vval.v_list, matchid);
12509 }
12510#endif
12511}
12512
12513/*
12514 * "synstack(lnum, col)" function
12515 */
12516 static void
12517f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12518{
12519#ifdef FEAT_SYN_HL
12520 linenr_T lnum;
12521 colnr_T col;
12522 int i;
12523 int id;
12524#endif
12525
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012526 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012527
12528#ifdef FEAT_SYN_HL
12529 lnum = get_tv_lnum(argvars); /* -1 on type error */
12530 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12531
12532 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12533 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12534 && rettv_list_alloc(rettv) != FAIL)
12535 {
12536 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12537 for (i = 0; ; ++i)
12538 {
12539 id = syn_get_stack_item(i);
12540 if (id < 0)
12541 break;
12542 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12543 break;
12544 }
12545 }
12546#endif
12547}
12548
12549 static void
12550get_cmd_output_as_rettv(
12551 typval_T *argvars,
12552 typval_T *rettv,
12553 int retlist)
12554{
12555 char_u *res = NULL;
12556 char_u *p;
12557 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012558 int err = FALSE;
12559 FILE *fd;
12560 list_T *list = NULL;
12561 int flags = SHELL_SILENT;
12562
12563 rettv->v_type = VAR_STRING;
12564 rettv->vval.v_string = NULL;
12565 if (check_restricted() || check_secure())
12566 goto errret;
12567
12568 if (argvars[1].v_type != VAR_UNKNOWN)
12569 {
12570 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012571 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012572 * command.
12573 */
12574 if ((infile = vim_tempname('i', TRUE)) == NULL)
12575 {
12576 EMSG(_(e_notmp));
12577 goto errret;
12578 }
12579
12580 fd = mch_fopen((char *)infile, WRITEBIN);
12581 if (fd == NULL)
12582 {
12583 EMSG2(_(e_notopen), infile);
12584 goto errret;
12585 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012586 if (argvars[1].v_type == VAR_NUMBER)
12587 {
12588 linenr_T lnum;
12589 buf_T *buf;
12590
12591 buf = buflist_findnr(argvars[1].vval.v_number);
12592 if (buf == NULL)
12593 {
12594 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012595 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012596 goto errret;
12597 }
12598
12599 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12600 {
12601 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12602 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12603 {
12604 err = TRUE;
12605 break;
12606 }
12607 if (putc(NL, fd) == EOF)
12608 {
12609 err = TRUE;
12610 break;
12611 }
12612 }
12613 }
12614 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012615 {
12616 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12617 err = TRUE;
12618 }
12619 else
12620 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012621 size_t len;
12622 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012623
12624 p = get_tv_string_buf_chk(&argvars[1], buf);
12625 if (p == NULL)
12626 {
12627 fclose(fd);
12628 goto errret; /* type error; errmsg already given */
12629 }
12630 len = STRLEN(p);
12631 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12632 err = TRUE;
12633 }
12634 if (fclose(fd) != 0)
12635 err = TRUE;
12636 if (err)
12637 {
12638 EMSG(_("E677: Error writing temp file"));
12639 goto errret;
12640 }
12641 }
12642
12643 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12644 * echoes typeahead, that messes up the display. */
12645 if (!msg_silent)
12646 flags += SHELL_COOKED;
12647
12648 if (retlist)
12649 {
12650 int len;
12651 listitem_T *li;
12652 char_u *s = NULL;
12653 char_u *start;
12654 char_u *end;
12655 int i;
12656
12657 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12658 if (res == NULL)
12659 goto errret;
12660
12661 list = list_alloc();
12662 if (list == NULL)
12663 goto errret;
12664
12665 for (i = 0; i < len; ++i)
12666 {
12667 start = res + i;
12668 while (i < len && res[i] != NL)
12669 ++i;
12670 end = res + i;
12671
12672 s = alloc((unsigned)(end - start + 1));
12673 if (s == NULL)
12674 goto errret;
12675
12676 for (p = s; start < end; ++p, ++start)
12677 *p = *start == NUL ? NL : *start;
12678 *p = NUL;
12679
12680 li = listitem_alloc();
12681 if (li == NULL)
12682 {
12683 vim_free(s);
12684 goto errret;
12685 }
12686 li->li_tv.v_type = VAR_STRING;
12687 li->li_tv.v_lock = 0;
12688 li->li_tv.vval.v_string = s;
12689 list_append(list, li);
12690 }
12691
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012692 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012693 list = NULL;
12694 }
12695 else
12696 {
12697 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12698#ifdef USE_CR
12699 /* translate <CR> into <NL> */
12700 if (res != NULL)
12701 {
12702 char_u *s;
12703
12704 for (s = res; *s; ++s)
12705 {
12706 if (*s == CAR)
12707 *s = NL;
12708 }
12709 }
12710#else
12711# ifdef USE_CRNL
12712 /* translate <CR><NL> into <NL> */
12713 if (res != NULL)
12714 {
12715 char_u *s, *d;
12716
12717 d = res;
12718 for (s = res; *s; ++s)
12719 {
12720 if (s[0] == CAR && s[1] == NL)
12721 ++s;
12722 *d++ = *s;
12723 }
12724 *d = NUL;
12725 }
12726# endif
12727#endif
12728 rettv->vval.v_string = res;
12729 res = NULL;
12730 }
12731
12732errret:
12733 if (infile != NULL)
12734 {
12735 mch_remove(infile);
12736 vim_free(infile);
12737 }
12738 if (res != NULL)
12739 vim_free(res);
12740 if (list != NULL)
12741 list_free(list);
12742}
12743
12744/*
12745 * "system()" function
12746 */
12747 static void
12748f_system(typval_T *argvars, typval_T *rettv)
12749{
12750 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12751}
12752
12753/*
12754 * "systemlist()" function
12755 */
12756 static void
12757f_systemlist(typval_T *argvars, typval_T *rettv)
12758{
12759 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12760}
12761
12762/*
12763 * "tabpagebuflist()" function
12764 */
12765 static void
12766f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12767{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012768 tabpage_T *tp;
12769 win_T *wp = NULL;
12770
12771 if (argvars[0].v_type == VAR_UNKNOWN)
12772 wp = firstwin;
12773 else
12774 {
12775 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12776 if (tp != NULL)
12777 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12778 }
12779 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12780 {
12781 for (; wp != NULL; wp = wp->w_next)
12782 if (list_append_number(rettv->vval.v_list,
12783 wp->w_buffer->b_fnum) == FAIL)
12784 break;
12785 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012786}
12787
12788
12789/*
12790 * "tabpagenr()" function
12791 */
12792 static void
12793f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12794{
12795 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012796 char_u *arg;
12797
12798 if (argvars[0].v_type != VAR_UNKNOWN)
12799 {
12800 arg = get_tv_string_chk(&argvars[0]);
12801 nr = 0;
12802 if (arg != NULL)
12803 {
12804 if (STRCMP(arg, "$") == 0)
12805 nr = tabpage_index(NULL) - 1;
12806 else
12807 EMSG2(_(e_invexpr2), arg);
12808 }
12809 }
12810 else
12811 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012812 rettv->vval.v_number = nr;
12813}
12814
12815
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012816static int get_winnr(tabpage_T *tp, typval_T *argvar);
12817
12818/*
12819 * Common code for tabpagewinnr() and winnr().
12820 */
12821 static int
12822get_winnr(tabpage_T *tp, typval_T *argvar)
12823{
12824 win_T *twin;
12825 int nr = 1;
12826 win_T *wp;
12827 char_u *arg;
12828
12829 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12830 if (argvar->v_type != VAR_UNKNOWN)
12831 {
12832 arg = get_tv_string_chk(argvar);
12833 if (arg == NULL)
12834 nr = 0; /* type error; errmsg already given */
12835 else if (STRCMP(arg, "$") == 0)
12836 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12837 else if (STRCMP(arg, "#") == 0)
12838 {
12839 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12840 if (twin == NULL)
12841 nr = 0;
12842 }
12843 else
12844 {
12845 EMSG2(_(e_invexpr2), arg);
12846 nr = 0;
12847 }
12848 }
12849
12850 if (nr > 0)
12851 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12852 wp != twin; wp = wp->w_next)
12853 {
12854 if (wp == NULL)
12855 {
12856 /* didn't find it in this tabpage */
12857 nr = 0;
12858 break;
12859 }
12860 ++nr;
12861 }
12862 return nr;
12863}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012864
12865/*
12866 * "tabpagewinnr()" function
12867 */
12868 static void
12869f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12870{
12871 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012872 tabpage_T *tp;
12873
12874 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12875 if (tp == NULL)
12876 nr = 0;
12877 else
12878 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012879 rettv->vval.v_number = nr;
12880}
12881
12882
12883/*
12884 * "tagfiles()" function
12885 */
12886 static void
12887f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12888{
12889 char_u *fname;
12890 tagname_T tn;
12891 int first;
12892
12893 if (rettv_list_alloc(rettv) == FAIL)
12894 return;
12895 fname = alloc(MAXPATHL);
12896 if (fname == NULL)
12897 return;
12898
12899 for (first = TRUE; ; first = FALSE)
12900 if (get_tagfname(&tn, first, fname) == FAIL
12901 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12902 break;
12903 tagname_free(&tn);
12904 vim_free(fname);
12905}
12906
12907/*
12908 * "taglist()" function
12909 */
12910 static void
12911f_taglist(typval_T *argvars, typval_T *rettv)
12912{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012913 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012914 char_u *tag_pattern;
12915
12916 tag_pattern = get_tv_string(&argvars[0]);
12917
12918 rettv->vval.v_number = FALSE;
12919 if (*tag_pattern == NUL)
12920 return;
12921
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012922 if (argvars[1].v_type != VAR_UNKNOWN)
12923 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012924 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012925 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012926}
12927
12928/*
12929 * "tempname()" function
12930 */
12931 static void
12932f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12933{
12934 static int x = 'A';
12935
12936 rettv->v_type = VAR_STRING;
12937 rettv->vval.v_string = vim_tempname(x, FALSE);
12938
12939 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12940 * names. Skip 'I' and 'O', they are used for shell redirection. */
12941 do
12942 {
12943 if (x == 'Z')
12944 x = '0';
12945 else if (x == '9')
12946 x = 'A';
12947 else
12948 {
12949#ifdef EBCDIC
12950 if (x == 'I')
12951 x = 'J';
12952 else if (x == 'R')
12953 x = 'S';
12954 else
12955#endif
12956 ++x;
12957 }
12958 } while (x == 'I' || x == 'O');
12959}
12960
12961#ifdef FEAT_FLOAT
12962/*
12963 * "tan()" function
12964 */
12965 static void
12966f_tan(typval_T *argvars, typval_T *rettv)
12967{
12968 float_T f = 0.0;
12969
12970 rettv->v_type = VAR_FLOAT;
12971 if (get_float_arg(argvars, &f) == OK)
12972 rettv->vval.v_float = tan(f);
12973 else
12974 rettv->vval.v_float = 0.0;
12975}
12976
12977/*
12978 * "tanh()" function
12979 */
12980 static void
12981f_tanh(typval_T *argvars, typval_T *rettv)
12982{
12983 float_T f = 0.0;
12984
12985 rettv->v_type = VAR_FLOAT;
12986 if (get_float_arg(argvars, &f) == OK)
12987 rettv->vval.v_float = tanh(f);
12988 else
12989 rettv->vval.v_float = 0.0;
12990}
12991#endif
12992
12993/*
12994 * "test_alloc_fail(id, countdown, repeat)" function
12995 */
12996 static void
12997f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12998{
12999 if (argvars[0].v_type != VAR_NUMBER
13000 || argvars[0].vval.v_number <= 0
13001 || argvars[1].v_type != VAR_NUMBER
13002 || argvars[1].vval.v_number < 0
13003 || argvars[2].v_type != VAR_NUMBER)
13004 EMSG(_(e_invarg));
13005 else
13006 {
13007 alloc_fail_id = argvars[0].vval.v_number;
13008 if (alloc_fail_id >= aid_last)
13009 EMSG(_(e_invarg));
13010 alloc_fail_countdown = argvars[1].vval.v_number;
13011 alloc_fail_repeat = argvars[2].vval.v_number;
13012 did_outofmem_msg = FALSE;
13013 }
13014}
13015
13016/*
13017 * "test_autochdir()"
13018 */
13019 static void
13020f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13021{
13022#if defined(FEAT_AUTOCHDIR)
13023 test_autochdir = TRUE;
13024#endif
13025}
13026
13027/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013028 * "test_feedinput()"
13029 */
13030 static void
13031f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13032{
13033#ifdef USE_INPUT_BUF
13034 char_u *val = get_tv_string_chk(&argvars[0]);
13035
13036 if (val != NULL)
13037 {
13038 trash_input_buf();
13039 add_to_input_buf_csi(val, (int)STRLEN(val));
13040 }
13041#endif
13042}
13043
13044/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013045 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013046 */
13047 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013048f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013049{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013050 char_u *name = (char_u *)"";
13051 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013052 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013053
13054 if (argvars[0].v_type != VAR_STRING
13055 || (argvars[1].v_type) != VAR_NUMBER)
13056 EMSG(_(e_invarg));
13057 else
13058 {
13059 name = get_tv_string_chk(&argvars[0]);
13060 val = (int)get_tv_number(&argvars[1]);
13061
13062 if (STRCMP(name, (char_u *)"redraw") == 0)
13063 disable_redraw_for_testing = val;
13064 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13065 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013066 else if (STRCMP(name, (char_u *)"starting") == 0)
13067 {
13068 if (val)
13069 {
13070 if (save_starting < 0)
13071 save_starting = starting;
13072 starting = 0;
13073 }
13074 else
13075 {
13076 starting = save_starting;
13077 save_starting = -1;
13078 }
13079 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013080 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13081 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013082 else if (STRCMP(name, (char_u *)"ALL") == 0)
13083 {
13084 disable_char_avail_for_testing = FALSE;
13085 disable_redraw_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013086 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013087 if (save_starting >= 0)
13088 {
13089 starting = save_starting;
13090 save_starting = -1;
13091 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013092 }
13093 else
13094 EMSG2(_(e_invarg2), name);
13095 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013096}
13097
13098/*
13099 * "test_garbagecollect_now()" function
13100 */
13101 static void
13102f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13103{
13104 /* This is dangerous, any Lists and Dicts used internally may be freed
13105 * while still in use. */
13106 garbage_collect(TRUE);
13107}
13108
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013109/*
13110 * "test_ignore_error()" function
13111 */
13112 static void
13113f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13114{
13115 ignore_error_for_testing(get_tv_string(&argvars[0]));
13116}
13117
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013118#ifdef FEAT_JOB_CHANNEL
13119 static void
13120f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13121{
13122 rettv->v_type = VAR_CHANNEL;
13123 rettv->vval.v_channel = NULL;
13124}
13125#endif
13126
13127 static void
13128f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13129{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013130 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013131}
13132
13133#ifdef FEAT_JOB_CHANNEL
13134 static void
13135f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13136{
13137 rettv->v_type = VAR_JOB;
13138 rettv->vval.v_job = NULL;
13139}
13140#endif
13141
13142 static void
13143f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13144{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013145 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013146}
13147
13148 static void
13149f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13150{
13151 rettv->v_type = VAR_PARTIAL;
13152 rettv->vval.v_partial = NULL;
13153}
13154
13155 static void
13156f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13157{
13158 rettv->v_type = VAR_STRING;
13159 rettv->vval.v_string = NULL;
13160}
13161
13162 static void
13163f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13164{
13165 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13166}
13167
13168#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13169/*
13170 * Get a callback from "arg". It can be a Funcref or a function name.
13171 * When "arg" is zero return an empty string.
13172 * Return NULL for an invalid argument.
13173 */
13174 char_u *
13175get_callback(typval_T *arg, partial_T **pp)
13176{
13177 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13178 {
13179 *pp = arg->vval.v_partial;
13180 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013181 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013182 }
13183 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013184 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013185 {
13186 func_ref(arg->vval.v_string);
13187 return arg->vval.v_string;
13188 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013189 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13190 return (char_u *)"";
13191 EMSG(_("E921: Invalid callback argument"));
13192 return NULL;
13193}
13194
13195/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013196 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013197 */
13198 void
13199free_callback(char_u *callback, partial_T *partial)
13200{
13201 if (partial != NULL)
13202 partial_unref(partial);
13203 else if (callback != NULL)
13204 {
13205 func_unref(callback);
13206 vim_free(callback);
13207 }
13208}
13209#endif
13210
13211#ifdef FEAT_TIMERS
13212/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013213 * "timer_info([timer])" function
13214 */
13215 static void
13216f_timer_info(typval_T *argvars, typval_T *rettv)
13217{
13218 timer_T *timer = NULL;
13219
13220 if (rettv_list_alloc(rettv) != OK)
13221 return;
13222 if (argvars[0].v_type != VAR_UNKNOWN)
13223 {
13224 if (argvars[0].v_type != VAR_NUMBER)
13225 EMSG(_(e_number_exp));
13226 else
13227 {
13228 timer = find_timer((int)get_tv_number(&argvars[0]));
13229 if (timer != NULL)
13230 add_timer_info(rettv, timer);
13231 }
13232 }
13233 else
13234 add_timer_info_all(rettv);
13235}
13236
13237/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013238 * "timer_pause(timer, paused)" function
13239 */
13240 static void
13241f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13242{
13243 timer_T *timer = NULL;
13244 int paused = (int)get_tv_number(&argvars[1]);
13245
13246 if (argvars[0].v_type != VAR_NUMBER)
13247 EMSG(_(e_number_exp));
13248 else
13249 {
13250 timer = find_timer((int)get_tv_number(&argvars[0]));
13251 if (timer != NULL)
13252 timer->tr_paused = paused;
13253 }
13254}
13255
13256/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013257 * "timer_start(time, callback [, options])" function
13258 */
13259 static void
13260f_timer_start(typval_T *argvars, typval_T *rettv)
13261{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013262 long msec = (long)get_tv_number(&argvars[0]);
13263 timer_T *timer;
13264 int repeat = 0;
13265 char_u *callback;
13266 dict_T *dict;
13267 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013268
Bram Moolenaar75537a92016-09-05 22:45:28 +020013269 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013270 if (check_secure())
13271 return;
13272 if (argvars[2].v_type != VAR_UNKNOWN)
13273 {
13274 if (argvars[2].v_type != VAR_DICT
13275 || (dict = argvars[2].vval.v_dict) == NULL)
13276 {
13277 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13278 return;
13279 }
13280 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13281 repeat = get_dict_number(dict, (char_u *)"repeat");
13282 }
13283
Bram Moolenaar75537a92016-09-05 22:45:28 +020013284 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013285 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013286 return;
13287
13288 timer = create_timer(msec, repeat);
13289 if (timer == NULL)
13290 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013291 else
13292 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013293 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013294 timer->tr_callback = vim_strsave(callback);
13295 else
13296 /* pointer into the partial */
13297 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013298 timer->tr_partial = partial;
13299 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013300 }
13301}
13302
13303/*
13304 * "timer_stop(timer)" function
13305 */
13306 static void
13307f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13308{
13309 timer_T *timer;
13310
13311 if (argvars[0].v_type != VAR_NUMBER)
13312 {
13313 EMSG(_(e_number_exp));
13314 return;
13315 }
13316 timer = find_timer((int)get_tv_number(&argvars[0]));
13317 if (timer != NULL)
13318 stop_timer(timer);
13319}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013320
13321/*
13322 * "timer_stopall()" function
13323 */
13324 static void
13325f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13326{
13327 stop_all_timers();
13328}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013329#endif
13330
13331/*
13332 * "tolower(string)" function
13333 */
13334 static void
13335f_tolower(typval_T *argvars, typval_T *rettv)
13336{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013337 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013338 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013339}
13340
13341/*
13342 * "toupper(string)" function
13343 */
13344 static void
13345f_toupper(typval_T *argvars, typval_T *rettv)
13346{
13347 rettv->v_type = VAR_STRING;
13348 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13349}
13350
13351/*
13352 * "tr(string, fromstr, tostr)" function
13353 */
13354 static void
13355f_tr(typval_T *argvars, typval_T *rettv)
13356{
13357 char_u *in_str;
13358 char_u *fromstr;
13359 char_u *tostr;
13360 char_u *p;
13361#ifdef FEAT_MBYTE
13362 int inlen;
13363 int fromlen;
13364 int tolen;
13365 int idx;
13366 char_u *cpstr;
13367 int cplen;
13368 int first = TRUE;
13369#endif
13370 char_u buf[NUMBUFLEN];
13371 char_u buf2[NUMBUFLEN];
13372 garray_T ga;
13373
13374 in_str = get_tv_string(&argvars[0]);
13375 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13376 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13377
13378 /* Default return value: empty string. */
13379 rettv->v_type = VAR_STRING;
13380 rettv->vval.v_string = NULL;
13381 if (fromstr == NULL || tostr == NULL)
13382 return; /* type error; errmsg already given */
13383 ga_init2(&ga, (int)sizeof(char), 80);
13384
13385#ifdef FEAT_MBYTE
13386 if (!has_mbyte)
13387#endif
13388 /* not multi-byte: fromstr and tostr must be the same length */
13389 if (STRLEN(fromstr) != STRLEN(tostr))
13390 {
13391#ifdef FEAT_MBYTE
13392error:
13393#endif
13394 EMSG2(_(e_invarg2), fromstr);
13395 ga_clear(&ga);
13396 return;
13397 }
13398
13399 /* fromstr and tostr have to contain the same number of chars */
13400 while (*in_str != NUL)
13401 {
13402#ifdef FEAT_MBYTE
13403 if (has_mbyte)
13404 {
13405 inlen = (*mb_ptr2len)(in_str);
13406 cpstr = in_str;
13407 cplen = inlen;
13408 idx = 0;
13409 for (p = fromstr; *p != NUL; p += fromlen)
13410 {
13411 fromlen = (*mb_ptr2len)(p);
13412 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13413 {
13414 for (p = tostr; *p != NUL; p += tolen)
13415 {
13416 tolen = (*mb_ptr2len)(p);
13417 if (idx-- == 0)
13418 {
13419 cplen = tolen;
13420 cpstr = p;
13421 break;
13422 }
13423 }
13424 if (*p == NUL) /* tostr is shorter than fromstr */
13425 goto error;
13426 break;
13427 }
13428 ++idx;
13429 }
13430
13431 if (first && cpstr == in_str)
13432 {
13433 /* Check that fromstr and tostr have the same number of
13434 * (multi-byte) characters. Done only once when a character
13435 * of in_str doesn't appear in fromstr. */
13436 first = FALSE;
13437 for (p = tostr; *p != NUL; p += tolen)
13438 {
13439 tolen = (*mb_ptr2len)(p);
13440 --idx;
13441 }
13442 if (idx != 0)
13443 goto error;
13444 }
13445
13446 (void)ga_grow(&ga, cplen);
13447 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13448 ga.ga_len += cplen;
13449
13450 in_str += inlen;
13451 }
13452 else
13453#endif
13454 {
13455 /* When not using multi-byte chars we can do it faster. */
13456 p = vim_strchr(fromstr, *in_str);
13457 if (p != NULL)
13458 ga_append(&ga, tostr[p - fromstr]);
13459 else
13460 ga_append(&ga, *in_str);
13461 ++in_str;
13462 }
13463 }
13464
13465 /* add a terminating NUL */
13466 (void)ga_grow(&ga, 1);
13467 ga_append(&ga, NUL);
13468
13469 rettv->vval.v_string = ga.ga_data;
13470}
13471
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013472/*
13473 * "trim({expr})" function
13474 */
13475 static void
13476f_trim(typval_T *argvars, typval_T *rettv)
13477{
13478 char_u buf1[NUMBUFLEN];
13479 char_u buf2[NUMBUFLEN];
13480 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13481 char_u *mask = NULL;
13482 char_u *tail;
13483 char_u *prev;
13484 char_u *p;
13485 int c1;
13486
13487 rettv->v_type = VAR_STRING;
13488 if (head == NULL)
13489 {
13490 rettv->vval.v_string = NULL;
13491 return;
13492 }
13493
13494 if (argvars[1].v_type == VAR_STRING)
13495 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13496
13497 while (*head != NUL)
13498 {
13499 c1 = PTR2CHAR(head);
13500 if (mask == NULL)
13501 {
13502 if (c1 > ' ' && c1 != 0xa0)
13503 break;
13504 }
13505 else
13506 {
13507 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13508 if (c1 == PTR2CHAR(p))
13509 break;
13510 if (*p == NUL)
13511 break;
13512 }
13513 MB_PTR_ADV(head);
13514 }
13515
13516 for (tail = head + STRLEN(head); tail > head; tail = prev)
13517 {
13518 prev = tail;
13519 MB_PTR_BACK(head, prev);
13520 c1 = PTR2CHAR(prev);
13521 if (mask == NULL)
13522 {
13523 if (c1 > ' ' && c1 != 0xa0)
13524 break;
13525 }
13526 else
13527 {
13528 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13529 if (c1 == PTR2CHAR(p))
13530 break;
13531 if (*p == NUL)
13532 break;
13533 }
13534 }
13535 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13536}
13537
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013538#ifdef FEAT_FLOAT
13539/*
13540 * "trunc({float})" function
13541 */
13542 static void
13543f_trunc(typval_T *argvars, typval_T *rettv)
13544{
13545 float_T f = 0.0;
13546
13547 rettv->v_type = VAR_FLOAT;
13548 if (get_float_arg(argvars, &f) == OK)
13549 /* trunc() is not in C90, use floor() or ceil() instead. */
13550 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13551 else
13552 rettv->vval.v_float = 0.0;
13553}
13554#endif
13555
13556/*
13557 * "type(expr)" function
13558 */
13559 static void
13560f_type(typval_T *argvars, typval_T *rettv)
13561{
13562 int n = -1;
13563
13564 switch (argvars[0].v_type)
13565 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013566 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13567 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013568 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013569 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13570 case VAR_LIST: n = VAR_TYPE_LIST; break;
13571 case VAR_DICT: n = VAR_TYPE_DICT; break;
13572 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013573 case VAR_SPECIAL:
13574 if (argvars[0].vval.v_number == VVAL_FALSE
13575 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013576 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013577 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013578 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013579 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013580 case VAR_JOB: n = VAR_TYPE_JOB; break;
13581 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013582 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013583 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013584 n = -1;
13585 break;
13586 }
13587 rettv->vval.v_number = n;
13588}
13589
13590/*
13591 * "undofile(name)" function
13592 */
13593 static void
13594f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13595{
13596 rettv->v_type = VAR_STRING;
13597#ifdef FEAT_PERSISTENT_UNDO
13598 {
13599 char_u *fname = get_tv_string(&argvars[0]);
13600
13601 if (*fname == NUL)
13602 {
13603 /* If there is no file name there will be no undo file. */
13604 rettv->vval.v_string = NULL;
13605 }
13606 else
13607 {
13608 char_u *ffname = FullName_save(fname, FALSE);
13609
13610 if (ffname != NULL)
13611 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13612 vim_free(ffname);
13613 }
13614 }
13615#else
13616 rettv->vval.v_string = NULL;
13617#endif
13618}
13619
13620/*
13621 * "undotree()" function
13622 */
13623 static void
13624f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13625{
13626 if (rettv_dict_alloc(rettv) == OK)
13627 {
13628 dict_T *dict = rettv->vval.v_dict;
13629 list_T *list;
13630
Bram Moolenaare0be1672018-07-08 16:50:37 +020013631 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
13632 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
13633 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
13634 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
13635 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
13636 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013637
13638 list = list_alloc();
13639 if (list != NULL)
13640 {
13641 u_eval_tree(curbuf->b_u_oldhead, list);
13642 dict_add_list(dict, "entries", list);
13643 }
13644 }
13645}
13646
13647/*
13648 * "values(dict)" function
13649 */
13650 static void
13651f_values(typval_T *argvars, typval_T *rettv)
13652{
13653 dict_list(argvars, rettv, 1);
13654}
13655
13656/*
13657 * "virtcol(string)" function
13658 */
13659 static void
13660f_virtcol(typval_T *argvars, typval_T *rettv)
13661{
13662 colnr_T vcol = 0;
13663 pos_T *fp;
13664 int fnum = curbuf->b_fnum;
13665
13666 fp = var2fpos(&argvars[0], FALSE, &fnum);
13667 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13668 && fnum == curbuf->b_fnum)
13669 {
13670 getvvcol(curwin, fp, NULL, NULL, &vcol);
13671 ++vcol;
13672 }
13673
13674 rettv->vval.v_number = vcol;
13675}
13676
13677/*
13678 * "visualmode()" function
13679 */
13680 static void
13681f_visualmode(typval_T *argvars, typval_T *rettv)
13682{
13683 char_u str[2];
13684
13685 rettv->v_type = VAR_STRING;
13686 str[0] = curbuf->b_visual_mode_eval;
13687 str[1] = NUL;
13688 rettv->vval.v_string = vim_strsave(str);
13689
13690 /* A non-zero number or non-empty string argument: reset mode. */
13691 if (non_zero_arg(&argvars[0]))
13692 curbuf->b_visual_mode_eval = NUL;
13693}
13694
13695/*
13696 * "wildmenumode()" function
13697 */
13698 static void
13699f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13700{
13701#ifdef FEAT_WILDMENU
13702 if (wild_menu_showing)
13703 rettv->vval.v_number = 1;
13704#endif
13705}
13706
13707/*
13708 * "winbufnr(nr)" function
13709 */
13710 static void
13711f_winbufnr(typval_T *argvars, typval_T *rettv)
13712{
13713 win_T *wp;
13714
13715 wp = find_win_by_nr(&argvars[0], NULL);
13716 if (wp == NULL)
13717 rettv->vval.v_number = -1;
13718 else
13719 rettv->vval.v_number = wp->w_buffer->b_fnum;
13720}
13721
13722/*
13723 * "wincol()" function
13724 */
13725 static void
13726f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13727{
13728 validate_cursor();
13729 rettv->vval.v_number = curwin->w_wcol + 1;
13730}
13731
13732/*
13733 * "winheight(nr)" function
13734 */
13735 static void
13736f_winheight(typval_T *argvars, typval_T *rettv)
13737{
13738 win_T *wp;
13739
13740 wp = find_win_by_nr(&argvars[0], NULL);
13741 if (wp == NULL)
13742 rettv->vval.v_number = -1;
13743 else
13744 rettv->vval.v_number = wp->w_height;
13745}
13746
13747/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020013748 * "winlayout()" function
13749 */
13750 static void
13751f_winlayout(typval_T *argvars, typval_T *rettv)
13752{
13753 tabpage_T *tp;
13754
13755 if (rettv_list_alloc(rettv) != OK)
13756 return;
13757
13758 if (argvars[0].v_type == VAR_UNKNOWN)
13759 tp = curtab;
13760 else
13761 {
13762 tp = find_tabpage((int)get_tv_number(&argvars[0]));
13763 if (tp == NULL)
13764 return;
13765 }
13766
13767 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
13768}
13769
13770/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013771 * "winline()" function
13772 */
13773 static void
13774f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13775{
13776 validate_cursor();
13777 rettv->vval.v_number = curwin->w_wrow + 1;
13778}
13779
13780/*
13781 * "winnr()" function
13782 */
13783 static void
13784f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13785{
13786 int nr = 1;
13787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013788 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013789 rettv->vval.v_number = nr;
13790}
13791
13792/*
13793 * "winrestcmd()" function
13794 */
13795 static void
13796f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13797{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013798 win_T *wp;
13799 int winnr = 1;
13800 garray_T ga;
13801 char_u buf[50];
13802
13803 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013804 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013805 {
13806 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13807 ga_concat(&ga, buf);
13808 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13809 ga_concat(&ga, buf);
13810 ++winnr;
13811 }
13812 ga_append(&ga, NUL);
13813
13814 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013815 rettv->v_type = VAR_STRING;
13816}
13817
13818/*
13819 * "winrestview()" function
13820 */
13821 static void
13822f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13823{
13824 dict_T *dict;
13825
13826 if (argvars[0].v_type != VAR_DICT
13827 || (dict = argvars[0].vval.v_dict) == NULL)
13828 EMSG(_(e_invarg));
13829 else
13830 {
13831 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13832 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13833 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13834 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13835#ifdef FEAT_VIRTUALEDIT
13836 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13837 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13838#endif
13839 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13840 {
13841 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13842 curwin->w_set_curswant = FALSE;
13843 }
13844
13845 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13846 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13847#ifdef FEAT_DIFF
13848 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13849 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13850#endif
13851 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13852 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13853 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13854 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13855
13856 check_cursor();
13857 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013858 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013859 changed_window_setting();
13860
13861 if (curwin->w_topline <= 0)
13862 curwin->w_topline = 1;
13863 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13864 curwin->w_topline = curbuf->b_ml.ml_line_count;
13865#ifdef FEAT_DIFF
13866 check_topfill(curwin, TRUE);
13867#endif
13868 }
13869}
13870
13871/*
13872 * "winsaveview()" function
13873 */
13874 static void
13875f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13876{
13877 dict_T *dict;
13878
13879 if (rettv_dict_alloc(rettv) == FAIL)
13880 return;
13881 dict = rettv->vval.v_dict;
13882
Bram Moolenaare0be1672018-07-08 16:50:37 +020013883 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13884 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013885#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020013886 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013887#endif
13888 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013889 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013890
Bram Moolenaare0be1672018-07-08 16:50:37 +020013891 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013892#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013893 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013894#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013895 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13896 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013897}
13898
13899/*
13900 * "winwidth(nr)" function
13901 */
13902 static void
13903f_winwidth(typval_T *argvars, typval_T *rettv)
13904{
13905 win_T *wp;
13906
13907 wp = find_win_by_nr(&argvars[0], NULL);
13908 if (wp == NULL)
13909 rettv->vval.v_number = -1;
13910 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013911 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013912}
13913
13914/*
13915 * "wordcount()" function
13916 */
13917 static void
13918f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13919{
13920 if (rettv_dict_alloc(rettv) == FAIL)
13921 return;
13922 cursor_pos_info(rettv->vval.v_dict);
13923}
13924
13925/*
13926 * "writefile()" function
13927 */
13928 static void
13929f_writefile(typval_T *argvars, typval_T *rettv)
13930{
13931 int binary = FALSE;
13932 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013933#ifdef HAVE_FSYNC
13934 int do_fsync = p_fs;
13935#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013936 char_u *fname;
13937 FILE *fd;
13938 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013939 listitem_T *li;
13940 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013941
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013942 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013943 if (check_restricted() || check_secure())
13944 return;
13945
13946 if (argvars[0].v_type != VAR_LIST)
13947 {
13948 EMSG2(_(e_listarg), "writefile()");
13949 return;
13950 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013951 list = argvars[0].vval.v_list;
13952 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013953 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013954 for (li = list->lv_first; li != NULL; li = li->li_next)
13955 if (get_tv_string_chk(&li->li_tv) == NULL)
13956 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013957
13958 if (argvars[2].v_type != VAR_UNKNOWN)
13959 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013960 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13961
13962 if (arg2 == NULL)
13963 return;
13964 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013965 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013966 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013967 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013968#ifdef HAVE_FSYNC
13969 if (vim_strchr(arg2, 's') != NULL)
13970 do_fsync = TRUE;
13971 else if (vim_strchr(arg2, 'S') != NULL)
13972 do_fsync = FALSE;
13973#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013974 }
13975
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013976 fname = get_tv_string_chk(&argvars[1]);
13977 if (fname == NULL)
13978 return;
13979
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013980 /* Always open the file in binary mode, library functions have a mind of
13981 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013982 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13983 append ? APPENDBIN : WRITEBIN)) == NULL)
13984 {
13985 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13986 ret = -1;
13987 }
13988 else
13989 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013990 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013991 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013992#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013993 else if (do_fsync)
13994 /* Ignore the error, the user wouldn't know what to do about it.
13995 * May happen for a device. */
13996 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013997#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013998 fclose(fd);
13999 }
14000
14001 rettv->vval.v_number = ret;
14002}
14003
14004/*
14005 * "xor(expr, expr)" function
14006 */
14007 static void
14008f_xor(typval_T *argvars, typval_T *rettv)
14009{
14010 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
14011 ^ get_tv_number_chk(&argvars[1], NULL);
14012}
14013
14014
14015#endif /* FEAT_EVAL */