blob: 82ea05af3354e63411cccaffd4c865ba571f00f4 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
19#ifdef AMIGA
20# include <time.h> /* for strftime() */
21#endif
22
23#ifdef VMS
24# include <float.h>
25#endif
26
Bram Moolenaard0573012017-10-28 21:11:06 +020027#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028# include <time.h> /* for time_t */
29#endif
30
31static char *e_listarg = N_("E686: Argument of %s must be a List");
32#ifdef FEAT_QUICKFIX
33static char *e_stringreq = N_("E928: String required");
34#endif
35
36#ifdef FEAT_FLOAT
37static void f_abs(typval_T *argvars, typval_T *rettv);
38static void f_acos(typval_T *argvars, typval_T *rettv);
39#endif
40static void f_add(typval_T *argvars, typval_T *rettv);
41static void f_and(typval_T *argvars, typval_T *rettv);
42static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020043static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_argc(typval_T *argvars, typval_T *rettv);
45static void f_argidx(typval_T *argvars, typval_T *rettv);
46static void f_arglistid(typval_T *argvars, typval_T *rettv);
47static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010048static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010050static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_assert_exception(typval_T *argvars, typval_T *rettv);
52static void f_assert_fails(typval_T *argvars, typval_T *rettv);
53static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020054static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_assert_match(typval_T *argvars, typval_T *rettv);
56static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
57static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010058static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020059static void f_assert_true(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_asin(typval_T *argvars, typval_T *rettv);
62static void f_atan(typval_T *argvars, typval_T *rettv);
63static void f_atan2(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010065#ifdef FEAT_BEVAL
66static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010067# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010068static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010069# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010070#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020071static void f_browse(typval_T *argvars, typval_T *rettv);
72static void f_browsedir(typval_T *argvars, typval_T *rettv);
73static void f_bufexists(typval_T *argvars, typval_T *rettv);
74static void f_buflisted(typval_T *argvars, typval_T *rettv);
75static void f_bufloaded(typval_T *argvars, typval_T *rettv);
76static void f_bufname(typval_T *argvars, typval_T *rettv);
77static void f_bufnr(typval_T *argvars, typval_T *rettv);
78static void f_bufwinid(typval_T *argvars, typval_T *rettv);
79static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
80static void f_byte2line(typval_T *argvars, typval_T *rettv);
81static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
82static void f_byteidx(typval_T *argvars, typval_T *rettv);
83static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
84static void f_call(typval_T *argvars, typval_T *rettv);
85#ifdef FEAT_FLOAT
86static void f_ceil(typval_T *argvars, typval_T *rettv);
87#endif
88#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010089static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020090static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020091static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
93static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
94static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
95static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
96static void f_ch_info(typval_T *argvars, typval_T *rettv);
97static void f_ch_log(typval_T *argvars, typval_T *rettv);
98static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
99static void f_ch_open(typval_T *argvars, typval_T *rettv);
100static void f_ch_read(typval_T *argvars, typval_T *rettv);
101static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
102static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
103static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
104static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
105static void f_ch_status(typval_T *argvars, typval_T *rettv);
106#endif
107static void f_changenr(typval_T *argvars, typval_T *rettv);
108static void f_char2nr(typval_T *argvars, typval_T *rettv);
109static void f_cindent(typval_T *argvars, typval_T *rettv);
110static void f_clearmatches(typval_T *argvars, typval_T *rettv);
111static void f_col(typval_T *argvars, typval_T *rettv);
112#if defined(FEAT_INS_EXPAND)
113static void f_complete(typval_T *argvars, typval_T *rettv);
114static void f_complete_add(typval_T *argvars, typval_T *rettv);
115static void f_complete_check(typval_T *argvars, typval_T *rettv);
116#endif
117static void f_confirm(typval_T *argvars, typval_T *rettv);
118static void f_copy(typval_T *argvars, typval_T *rettv);
119#ifdef FEAT_FLOAT
120static void f_cos(typval_T *argvars, typval_T *rettv);
121static void f_cosh(typval_T *argvars, typval_T *rettv);
122#endif
123static void f_count(typval_T *argvars, typval_T *rettv);
124static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
125static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200126#ifdef WIN3264
127static void f_debugbreak(typval_T *argvars, typval_T *rettv);
128#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_deepcopy(typval_T *argvars, typval_T *rettv);
130static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200131static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_did_filetype(typval_T *argvars, typval_T *rettv);
133static void f_diff_filler(typval_T *argvars, typval_T *rettv);
134static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
135static void f_empty(typval_T *argvars, typval_T *rettv);
136static void f_escape(typval_T *argvars, typval_T *rettv);
137static void f_eval(typval_T *argvars, typval_T *rettv);
138static void f_eventhandler(typval_T *argvars, typval_T *rettv);
139static void f_executable(typval_T *argvars, typval_T *rettv);
140static void f_execute(typval_T *argvars, typval_T *rettv);
141static void f_exepath(typval_T *argvars, typval_T *rettv);
142static void f_exists(typval_T *argvars, typval_T *rettv);
143#ifdef FEAT_FLOAT
144static void f_exp(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_expand(typval_T *argvars, typval_T *rettv);
147static void f_extend(typval_T *argvars, typval_T *rettv);
148static void f_feedkeys(typval_T *argvars, typval_T *rettv);
149static void f_filereadable(typval_T *argvars, typval_T *rettv);
150static void f_filewritable(typval_T *argvars, typval_T *rettv);
151static void f_filter(typval_T *argvars, typval_T *rettv);
152static void f_finddir(typval_T *argvars, typval_T *rettv);
153static void f_findfile(typval_T *argvars, typval_T *rettv);
154#ifdef FEAT_FLOAT
155static void f_float2nr(typval_T *argvars, typval_T *rettv);
156static void f_floor(typval_T *argvars, typval_T *rettv);
157static void f_fmod(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_fnameescape(typval_T *argvars, typval_T *rettv);
160static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
161static void f_foldclosed(typval_T *argvars, typval_T *rettv);
162static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
163static void f_foldlevel(typval_T *argvars, typval_T *rettv);
164static void f_foldtext(typval_T *argvars, typval_T *rettv);
165static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
166static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200167static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_function(typval_T *argvars, typval_T *rettv);
169static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
170static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200171static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_getbufline(typval_T *argvars, typval_T *rettv);
173static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100174static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_getchar(typval_T *argvars, typval_T *rettv);
176static void f_getcharmod(typval_T *argvars, typval_T *rettv);
177static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
178static void f_getcmdline(typval_T *argvars, typval_T *rettv);
179#if defined(FEAT_CMDL_COMPL)
180static void f_getcompletion(typval_T *argvars, typval_T *rettv);
181#endif
182static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
183static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
184static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
185static void f_getcwd(typval_T *argvars, typval_T *rettv);
186static void f_getfontname(typval_T *argvars, typval_T *rettv);
187static void f_getfperm(typval_T *argvars, typval_T *rettv);
188static void f_getfsize(typval_T *argvars, typval_T *rettv);
189static void f_getftime(typval_T *argvars, typval_T *rettv);
190static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100191static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200193static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getmatches(typval_T *argvars, typval_T *rettv);
195static void f_getpid(typval_T *argvars, typval_T *rettv);
196static void f_getcurpos(typval_T *argvars, typval_T *rettv);
197static void f_getpos(typval_T *argvars, typval_T *rettv);
198static void f_getqflist(typval_T *argvars, typval_T *rettv);
199static void f_getreg(typval_T *argvars, typval_T *rettv);
200static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200201static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_gettabvar(typval_T *argvars, typval_T *rettv);
203static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200204static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100205static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200206static void f_getwinposx(typval_T *argvars, typval_T *rettv);
207static void f_getwinposy(typval_T *argvars, typval_T *rettv);
208static void f_getwinvar(typval_T *argvars, typval_T *rettv);
209static void f_glob(typval_T *argvars, typval_T *rettv);
210static void f_globpath(typval_T *argvars, typval_T *rettv);
211static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
212static void f_has(typval_T *argvars, typval_T *rettv);
213static void f_has_key(typval_T *argvars, typval_T *rettv);
214static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
215static void f_hasmapto(typval_T *argvars, typval_T *rettv);
216static void f_histadd(typval_T *argvars, typval_T *rettv);
217static void f_histdel(typval_T *argvars, typval_T *rettv);
218static void f_histget(typval_T *argvars, typval_T *rettv);
219static void f_histnr(typval_T *argvars, typval_T *rettv);
220static void f_hlID(typval_T *argvars, typval_T *rettv);
221static void f_hlexists(typval_T *argvars, typval_T *rettv);
222static void f_hostname(typval_T *argvars, typval_T *rettv);
223static void f_iconv(typval_T *argvars, typval_T *rettv);
224static void f_indent(typval_T *argvars, typval_T *rettv);
225static void f_index(typval_T *argvars, typval_T *rettv);
226static void f_input(typval_T *argvars, typval_T *rettv);
227static void f_inputdialog(typval_T *argvars, typval_T *rettv);
228static void f_inputlist(typval_T *argvars, typval_T *rettv);
229static void f_inputrestore(typval_T *argvars, typval_T *rettv);
230static void f_inputsave(typval_T *argvars, typval_T *rettv);
231static void f_inputsecret(typval_T *argvars, typval_T *rettv);
232static void f_insert(typval_T *argvars, typval_T *rettv);
233static void f_invert(typval_T *argvars, typval_T *rettv);
234static void f_isdirectory(typval_T *argvars, typval_T *rettv);
235static void f_islocked(typval_T *argvars, typval_T *rettv);
236#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
237static void f_isnan(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_items(typval_T *argvars, typval_T *rettv);
240#ifdef FEAT_JOB_CHANNEL
241static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
242static void f_job_info(typval_T *argvars, typval_T *rettv);
243static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
244static void f_job_start(typval_T *argvars, typval_T *rettv);
245static void f_job_stop(typval_T *argvars, typval_T *rettv);
246static void f_job_status(typval_T *argvars, typval_T *rettv);
247#endif
248static void f_join(typval_T *argvars, typval_T *rettv);
249static void f_js_decode(typval_T *argvars, typval_T *rettv);
250static void f_js_encode(typval_T *argvars, typval_T *rettv);
251static void f_json_decode(typval_T *argvars, typval_T *rettv);
252static void f_json_encode(typval_T *argvars, typval_T *rettv);
253static void f_keys(typval_T *argvars, typval_T *rettv);
254static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
255static void f_len(typval_T *argvars, typval_T *rettv);
256static void f_libcall(typval_T *argvars, typval_T *rettv);
257static void f_libcallnr(typval_T *argvars, typval_T *rettv);
258static void f_line(typval_T *argvars, typval_T *rettv);
259static void f_line2byte(typval_T *argvars, typval_T *rettv);
260static void f_lispindent(typval_T *argvars, typval_T *rettv);
261static void f_localtime(typval_T *argvars, typval_T *rettv);
262#ifdef FEAT_FLOAT
263static void f_log(typval_T *argvars, typval_T *rettv);
264static void f_log10(typval_T *argvars, typval_T *rettv);
265#endif
266#ifdef FEAT_LUA
267static void f_luaeval(typval_T *argvars, typval_T *rettv);
268#endif
269static void f_map(typval_T *argvars, typval_T *rettv);
270static void f_maparg(typval_T *argvars, typval_T *rettv);
271static void f_mapcheck(typval_T *argvars, typval_T *rettv);
272static void f_match(typval_T *argvars, typval_T *rettv);
273static void f_matchadd(typval_T *argvars, typval_T *rettv);
274static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
275static void f_matcharg(typval_T *argvars, typval_T *rettv);
276static void f_matchdelete(typval_T *argvars, typval_T *rettv);
277static void f_matchend(typval_T *argvars, typval_T *rettv);
278static void f_matchlist(typval_T *argvars, typval_T *rettv);
279static void f_matchstr(typval_T *argvars, typval_T *rettv);
280static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
281static void f_max(typval_T *argvars, typval_T *rettv);
282static void f_min(typval_T *argvars, typval_T *rettv);
283#ifdef vim_mkdir
284static void f_mkdir(typval_T *argvars, typval_T *rettv);
285#endif
286static void f_mode(typval_T *argvars, typval_T *rettv);
287#ifdef FEAT_MZSCHEME
288static void f_mzeval(typval_T *argvars, typval_T *rettv);
289#endif
290static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
291static void f_nr2char(typval_T *argvars, typval_T *rettv);
292static void f_or(typval_T *argvars, typval_T *rettv);
293static void f_pathshorten(typval_T *argvars, typval_T *rettv);
294#ifdef FEAT_PERL
295static void f_perleval(typval_T *argvars, typval_T *rettv);
296#endif
297#ifdef FEAT_FLOAT
298static void f_pow(typval_T *argvars, typval_T *rettv);
299#endif
300static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
301static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200302#ifdef FEAT_JOB_CHANNEL
303static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200304static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200305static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
306#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200307static void f_pumvisible(typval_T *argvars, typval_T *rettv);
308#ifdef FEAT_PYTHON3
309static void f_py3eval(typval_T *argvars, typval_T *rettv);
310#endif
311#ifdef FEAT_PYTHON
312static void f_pyeval(typval_T *argvars, typval_T *rettv);
313#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100314#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
315static void f_pyxeval(typval_T *argvars, typval_T *rettv);
316#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317static void f_range(typval_T *argvars, typval_T *rettv);
318static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200319static void f_reg_executing(typval_T *argvars, typval_T *rettv);
320static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200321static void f_reltime(typval_T *argvars, typval_T *rettv);
322#ifdef FEAT_FLOAT
323static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
324#endif
325static void f_reltimestr(typval_T *argvars, typval_T *rettv);
326static void f_remote_expr(typval_T *argvars, typval_T *rettv);
327static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
328static void f_remote_peek(typval_T *argvars, typval_T *rettv);
329static void f_remote_read(typval_T *argvars, typval_T *rettv);
330static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100331static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200332static void f_remove(typval_T *argvars, typval_T *rettv);
333static void f_rename(typval_T *argvars, typval_T *rettv);
334static void f_repeat(typval_T *argvars, typval_T *rettv);
335static void f_resolve(typval_T *argvars, typval_T *rettv);
336static void f_reverse(typval_T *argvars, typval_T *rettv);
337#ifdef FEAT_FLOAT
338static void f_round(typval_T *argvars, typval_T *rettv);
339#endif
340static void f_screenattr(typval_T *argvars, typval_T *rettv);
341static void f_screenchar(typval_T *argvars, typval_T *rettv);
342static void f_screencol(typval_T *argvars, typval_T *rettv);
343static void f_screenrow(typval_T *argvars, typval_T *rettv);
344static void f_search(typval_T *argvars, typval_T *rettv);
345static void f_searchdecl(typval_T *argvars, typval_T *rettv);
346static void f_searchpair(typval_T *argvars, typval_T *rettv);
347static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
348static void f_searchpos(typval_T *argvars, typval_T *rettv);
349static void f_server2client(typval_T *argvars, typval_T *rettv);
350static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200351static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352static void f_setbufvar(typval_T *argvars, typval_T *rettv);
353static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
354static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
355static void f_setfperm(typval_T *argvars, typval_T *rettv);
356static void f_setline(typval_T *argvars, typval_T *rettv);
357static void f_setloclist(typval_T *argvars, typval_T *rettv);
358static void f_setmatches(typval_T *argvars, typval_T *rettv);
359static void f_setpos(typval_T *argvars, typval_T *rettv);
360static void f_setqflist(typval_T *argvars, typval_T *rettv);
361static void f_setreg(typval_T *argvars, typval_T *rettv);
362static void f_settabvar(typval_T *argvars, typval_T *rettv);
363static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
364static void f_setwinvar(typval_T *argvars, typval_T *rettv);
365#ifdef FEAT_CRYPT
366static void f_sha256(typval_T *argvars, typval_T *rettv);
367#endif /* FEAT_CRYPT */
368static void f_shellescape(typval_T *argvars, typval_T *rettv);
369static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
370static void f_simplify(typval_T *argvars, typval_T *rettv);
371#ifdef FEAT_FLOAT
372static void f_sin(typval_T *argvars, typval_T *rettv);
373static void f_sinh(typval_T *argvars, typval_T *rettv);
374#endif
375static void f_sort(typval_T *argvars, typval_T *rettv);
376static void f_soundfold(typval_T *argvars, typval_T *rettv);
377static void f_spellbadword(typval_T *argvars, typval_T *rettv);
378static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
379static void f_split(typval_T *argvars, typval_T *rettv);
380#ifdef FEAT_FLOAT
381static void f_sqrt(typval_T *argvars, typval_T *rettv);
382static void f_str2float(typval_T *argvars, typval_T *rettv);
383#endif
384static void f_str2nr(typval_T *argvars, typval_T *rettv);
385static void f_strchars(typval_T *argvars, typval_T *rettv);
386#ifdef HAVE_STRFTIME
387static void f_strftime(typval_T *argvars, typval_T *rettv);
388#endif
389static void f_strgetchar(typval_T *argvars, typval_T *rettv);
390static void f_stridx(typval_T *argvars, typval_T *rettv);
391static void f_string(typval_T *argvars, typval_T *rettv);
392static void f_strlen(typval_T *argvars, typval_T *rettv);
393static void f_strcharpart(typval_T *argvars, typval_T *rettv);
394static void f_strpart(typval_T *argvars, typval_T *rettv);
395static void f_strridx(typval_T *argvars, typval_T *rettv);
396static void f_strtrans(typval_T *argvars, typval_T *rettv);
397static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
398static void f_strwidth(typval_T *argvars, typval_T *rettv);
399static void f_submatch(typval_T *argvars, typval_T *rettv);
400static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200401static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200402static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200403static void f_synID(typval_T *argvars, typval_T *rettv);
404static void f_synIDattr(typval_T *argvars, typval_T *rettv);
405static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
406static void f_synstack(typval_T *argvars, typval_T *rettv);
407static void f_synconcealed(typval_T *argvars, typval_T *rettv);
408static void f_system(typval_T *argvars, typval_T *rettv);
409static void f_systemlist(typval_T *argvars, typval_T *rettv);
410static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
411static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
412static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
413static void f_taglist(typval_T *argvars, typval_T *rettv);
414static void f_tagfiles(typval_T *argvars, typval_T *rettv);
415static void f_tempname(typval_T *argvars, typval_T *rettv);
416static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
417static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200418static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200419static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100420static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100422static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200423#ifdef FEAT_JOB_CHANNEL
424static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
425#endif
426static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
427#ifdef FEAT_JOB_CHANNEL
428static void f_test_null_job(typval_T *argvars, typval_T *rettv);
429#endif
430static void f_test_null_list(typval_T *argvars, typval_T *rettv);
431static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
432static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200433#ifdef FEAT_GUI
434static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
435#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436static void f_test_settime(typval_T *argvars, typval_T *rettv);
437#ifdef FEAT_FLOAT
438static void f_tan(typval_T *argvars, typval_T *rettv);
439static void f_tanh(typval_T *argvars, typval_T *rettv);
440#endif
441#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200442static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200443static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200444static void f_timer_start(typval_T *argvars, typval_T *rettv);
445static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200446static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447#endif
448static void f_tolower(typval_T *argvars, typval_T *rettv);
449static void f_toupper(typval_T *argvars, typval_T *rettv);
450static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100451static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200452#ifdef FEAT_FLOAT
453static void f_trunc(typval_T *argvars, typval_T *rettv);
454#endif
455static void f_type(typval_T *argvars, typval_T *rettv);
456static void f_undofile(typval_T *argvars, typval_T *rettv);
457static void f_undotree(typval_T *argvars, typval_T *rettv);
458static void f_uniq(typval_T *argvars, typval_T *rettv);
459static void f_values(typval_T *argvars, typval_T *rettv);
460static void f_virtcol(typval_T *argvars, typval_T *rettv);
461static void f_visualmode(typval_T *argvars, typval_T *rettv);
462static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
463static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
464static void f_win_getid(typval_T *argvars, typval_T *rettv);
465static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
466static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
467static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100468static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200469static void f_winbufnr(typval_T *argvars, typval_T *rettv);
470static void f_wincol(typval_T *argvars, typval_T *rettv);
471static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200472static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473static void f_winline(typval_T *argvars, typval_T *rettv);
474static void f_winnr(typval_T *argvars, typval_T *rettv);
475static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
476static void f_winrestview(typval_T *argvars, typval_T *rettv);
477static void f_winsaveview(typval_T *argvars, typval_T *rettv);
478static void f_winwidth(typval_T *argvars, typval_T *rettv);
479static void f_writefile(typval_T *argvars, typval_T *rettv);
480static void f_wordcount(typval_T *argvars, typval_T *rettv);
481static void f_xor(typval_T *argvars, typval_T *rettv);
482
483/*
484 * Array with names and number of arguments of all internal functions
485 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
486 */
487static struct fst
488{
489 char *f_name; /* function name */
490 char f_min_argc; /* minimal number of arguments */
491 char f_max_argc; /* maximal number of arguments */
492 void (*f_func)(typval_T *args, typval_T *rvar);
493 /* implementation of function */
494} functions[] =
495{
496#ifdef FEAT_FLOAT
497 {"abs", 1, 1, f_abs},
498 {"acos", 1, 1, f_acos}, /* WJMc */
499#endif
500 {"add", 2, 2, f_add},
501 {"and", 2, 2, f_and},
502 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200503 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200504 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200505 {"argidx", 0, 0, f_argidx},
506 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200507 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508#ifdef FEAT_FLOAT
509 {"asin", 1, 1, f_asin}, /* WJMc */
510#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100511 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200512 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100513 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200514 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200515 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100517 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200518 {"assert_match", 2, 3, f_assert_match},
519 {"assert_notequal", 2, 3, f_assert_notequal},
520 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100521 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200522 {"assert_true", 1, 2, f_assert_true},
523#ifdef FEAT_FLOAT
524 {"atan", 1, 1, f_atan},
525 {"atan2", 2, 2, f_atan2},
526#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100527#ifdef FEAT_BEVAL
528 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100529# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100530 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100531# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100532#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533 {"browse", 4, 4, f_browse},
534 {"browsedir", 2, 2, f_browsedir},
535 {"bufexists", 1, 1, f_bufexists},
536 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
537 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
538 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
539 {"buflisted", 1, 1, f_buflisted},
540 {"bufloaded", 1, 1, f_bufloaded},
541 {"bufname", 1, 1, f_bufname},
542 {"bufnr", 1, 2, f_bufnr},
543 {"bufwinid", 1, 1, f_bufwinid},
544 {"bufwinnr", 1, 1, f_bufwinnr},
545 {"byte2line", 1, 1, f_byte2line},
546 {"byteidx", 2, 2, f_byteidx},
547 {"byteidxcomp", 2, 2, f_byteidxcomp},
548 {"call", 2, 3, f_call},
549#ifdef FEAT_FLOAT
550 {"ceil", 1, 1, f_ceil},
551#endif
552#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100553 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200554 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200555 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200556 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
557 {"ch_evalraw", 2, 3, f_ch_evalraw},
558 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
559 {"ch_getjob", 1, 1, f_ch_getjob},
560 {"ch_info", 1, 1, f_ch_info},
561 {"ch_log", 1, 2, f_ch_log},
562 {"ch_logfile", 1, 2, f_ch_logfile},
563 {"ch_open", 1, 2, f_ch_open},
564 {"ch_read", 1, 2, f_ch_read},
565 {"ch_readraw", 1, 2, f_ch_readraw},
566 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
567 {"ch_sendraw", 2, 3, f_ch_sendraw},
568 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200569 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200570#endif
571 {"changenr", 0, 0, f_changenr},
572 {"char2nr", 1, 2, f_char2nr},
573 {"cindent", 1, 1, f_cindent},
574 {"clearmatches", 0, 0, f_clearmatches},
575 {"col", 1, 1, f_col},
576#if defined(FEAT_INS_EXPAND)
577 {"complete", 2, 2, f_complete},
578 {"complete_add", 1, 1, f_complete_add},
579 {"complete_check", 0, 0, f_complete_check},
580#endif
581 {"confirm", 1, 4, f_confirm},
582 {"copy", 1, 1, f_copy},
583#ifdef FEAT_FLOAT
584 {"cos", 1, 1, f_cos},
585 {"cosh", 1, 1, f_cosh},
586#endif
587 {"count", 2, 4, f_count},
588 {"cscope_connection",0,3, f_cscope_connection},
589 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200590#ifdef WIN3264
591 {"debugbreak", 1, 1, f_debugbreak},
592#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200593 {"deepcopy", 1, 2, f_deepcopy},
594 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200595 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200596 {"did_filetype", 0, 0, f_did_filetype},
597 {"diff_filler", 1, 1, f_diff_filler},
598 {"diff_hlID", 2, 2, f_diff_hlID},
599 {"empty", 1, 1, f_empty},
600 {"escape", 2, 2, f_escape},
601 {"eval", 1, 1, f_eval},
602 {"eventhandler", 0, 0, f_eventhandler},
603 {"executable", 1, 1, f_executable},
604 {"execute", 1, 2, f_execute},
605 {"exepath", 1, 1, f_exepath},
606 {"exists", 1, 1, f_exists},
607#ifdef FEAT_FLOAT
608 {"exp", 1, 1, f_exp},
609#endif
610 {"expand", 1, 3, f_expand},
611 {"extend", 2, 3, f_extend},
612 {"feedkeys", 1, 2, f_feedkeys},
613 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
614 {"filereadable", 1, 1, f_filereadable},
615 {"filewritable", 1, 1, f_filewritable},
616 {"filter", 2, 2, f_filter},
617 {"finddir", 1, 3, f_finddir},
618 {"findfile", 1, 3, f_findfile},
619#ifdef FEAT_FLOAT
620 {"float2nr", 1, 1, f_float2nr},
621 {"floor", 1, 1, f_floor},
622 {"fmod", 2, 2, f_fmod},
623#endif
624 {"fnameescape", 1, 1, f_fnameescape},
625 {"fnamemodify", 2, 2, f_fnamemodify},
626 {"foldclosed", 1, 1, f_foldclosed},
627 {"foldclosedend", 1, 1, f_foldclosedend},
628 {"foldlevel", 1, 1, f_foldlevel},
629 {"foldtext", 0, 0, f_foldtext},
630 {"foldtextresult", 1, 1, f_foldtextresult},
631 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200632 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633 {"function", 1, 3, f_function},
634 {"garbagecollect", 0, 1, f_garbagecollect},
635 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200636 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637 {"getbufline", 2, 3, f_getbufline},
638 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100639 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640 {"getchar", 0, 1, f_getchar},
641 {"getcharmod", 0, 0, f_getcharmod},
642 {"getcharsearch", 0, 0, f_getcharsearch},
643 {"getcmdline", 0, 0, f_getcmdline},
644 {"getcmdpos", 0, 0, f_getcmdpos},
645 {"getcmdtype", 0, 0, f_getcmdtype},
646 {"getcmdwintype", 0, 0, f_getcmdwintype},
647#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200648 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649#endif
650 {"getcurpos", 0, 0, f_getcurpos},
651 {"getcwd", 0, 2, f_getcwd},
652 {"getfontname", 0, 1, f_getfontname},
653 {"getfperm", 1, 1, f_getfperm},
654 {"getfsize", 1, 1, f_getfsize},
655 {"getftime", 1, 1, f_getftime},
656 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100657 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200659 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200660 {"getmatches", 0, 0, f_getmatches},
661 {"getpid", 0, 0, f_getpid},
662 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200663 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200664 {"getreg", 0, 3, f_getreg},
665 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200666 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200667 {"gettabvar", 2, 3, f_gettabvar},
668 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200669 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100670 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200671 {"getwinposx", 0, 0, f_getwinposx},
672 {"getwinposy", 0, 0, f_getwinposy},
673 {"getwinvar", 2, 3, f_getwinvar},
674 {"glob", 1, 4, f_glob},
675 {"glob2regpat", 1, 1, f_glob2regpat},
676 {"globpath", 2, 5, f_globpath},
677 {"has", 1, 1, f_has},
678 {"has_key", 2, 2, f_has_key},
679 {"haslocaldir", 0, 2, f_haslocaldir},
680 {"hasmapto", 1, 3, f_hasmapto},
681 {"highlightID", 1, 1, f_hlID}, /* obsolete */
682 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
683 {"histadd", 2, 2, f_histadd},
684 {"histdel", 1, 2, f_histdel},
685 {"histget", 1, 2, f_histget},
686 {"histnr", 1, 1, f_histnr},
687 {"hlID", 1, 1, f_hlID},
688 {"hlexists", 1, 1, f_hlexists},
689 {"hostname", 0, 0, f_hostname},
690 {"iconv", 3, 3, f_iconv},
691 {"indent", 1, 1, f_indent},
692 {"index", 2, 4, f_index},
693 {"input", 1, 3, f_input},
694 {"inputdialog", 1, 3, f_inputdialog},
695 {"inputlist", 1, 1, f_inputlist},
696 {"inputrestore", 0, 0, f_inputrestore},
697 {"inputsave", 0, 0, f_inputsave},
698 {"inputsecret", 1, 2, f_inputsecret},
699 {"insert", 2, 3, f_insert},
700 {"invert", 1, 1, f_invert},
701 {"isdirectory", 1, 1, f_isdirectory},
702 {"islocked", 1, 1, f_islocked},
703#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
704 {"isnan", 1, 1, f_isnan},
705#endif
706 {"items", 1, 1, f_items},
707#ifdef FEAT_JOB_CHANNEL
708 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200709 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200710 {"job_setoptions", 2, 2, f_job_setoptions},
711 {"job_start", 1, 2, f_job_start},
712 {"job_status", 1, 1, f_job_status},
713 {"job_stop", 1, 2, f_job_stop},
714#endif
715 {"join", 1, 2, f_join},
716 {"js_decode", 1, 1, f_js_decode},
717 {"js_encode", 1, 1, f_js_encode},
718 {"json_decode", 1, 1, f_json_decode},
719 {"json_encode", 1, 1, f_json_encode},
720 {"keys", 1, 1, f_keys},
721 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
722 {"len", 1, 1, f_len},
723 {"libcall", 3, 3, f_libcall},
724 {"libcallnr", 3, 3, f_libcallnr},
725 {"line", 1, 1, f_line},
726 {"line2byte", 1, 1, f_line2byte},
727 {"lispindent", 1, 1, f_lispindent},
728 {"localtime", 0, 0, f_localtime},
729#ifdef FEAT_FLOAT
730 {"log", 1, 1, f_log},
731 {"log10", 1, 1, f_log10},
732#endif
733#ifdef FEAT_LUA
734 {"luaeval", 1, 2, f_luaeval},
735#endif
736 {"map", 2, 2, f_map},
737 {"maparg", 1, 4, f_maparg},
738 {"mapcheck", 1, 3, f_mapcheck},
739 {"match", 2, 4, f_match},
740 {"matchadd", 2, 5, f_matchadd},
741 {"matchaddpos", 2, 5, f_matchaddpos},
742 {"matcharg", 1, 1, f_matcharg},
743 {"matchdelete", 1, 1, f_matchdelete},
744 {"matchend", 2, 4, f_matchend},
745 {"matchlist", 2, 4, f_matchlist},
746 {"matchstr", 2, 4, f_matchstr},
747 {"matchstrpos", 2, 4, f_matchstrpos},
748 {"max", 1, 1, f_max},
749 {"min", 1, 1, f_min},
750#ifdef vim_mkdir
751 {"mkdir", 1, 3, f_mkdir},
752#endif
753 {"mode", 0, 1, f_mode},
754#ifdef FEAT_MZSCHEME
755 {"mzeval", 1, 1, f_mzeval},
756#endif
757 {"nextnonblank", 1, 1, f_nextnonblank},
758 {"nr2char", 1, 2, f_nr2char},
759 {"or", 2, 2, f_or},
760 {"pathshorten", 1, 1, f_pathshorten},
761#ifdef FEAT_PERL
762 {"perleval", 1, 1, f_perleval},
763#endif
764#ifdef FEAT_FLOAT
765 {"pow", 2, 2, f_pow},
766#endif
767 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100768 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200769#ifdef FEAT_JOB_CHANNEL
770 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200771 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200772 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
773#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200774 {"pumvisible", 0, 0, f_pumvisible},
775#ifdef FEAT_PYTHON3
776 {"py3eval", 1, 1, f_py3eval},
777#endif
778#ifdef FEAT_PYTHON
779 {"pyeval", 1, 1, f_pyeval},
780#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100781#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
782 {"pyxeval", 1, 1, f_pyxeval},
783#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200784 {"range", 1, 3, f_range},
785 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200786 {"reg_executing", 0, 0, f_reg_executing},
787 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"reltime", 0, 2, f_reltime},
789#ifdef FEAT_FLOAT
790 {"reltimefloat", 1, 1, f_reltimefloat},
791#endif
792 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100793 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794 {"remote_foreground", 1, 1, f_remote_foreground},
795 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100796 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200797 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100798 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200799 {"remove", 2, 3, f_remove},
800 {"rename", 2, 2, f_rename},
801 {"repeat", 2, 2, f_repeat},
802 {"resolve", 1, 1, f_resolve},
803 {"reverse", 1, 1, f_reverse},
804#ifdef FEAT_FLOAT
805 {"round", 1, 1, f_round},
806#endif
807 {"screenattr", 2, 2, f_screenattr},
808 {"screenchar", 2, 2, f_screenchar},
809 {"screencol", 0, 0, f_screencol},
810 {"screenrow", 0, 0, f_screenrow},
811 {"search", 1, 4, f_search},
812 {"searchdecl", 1, 3, f_searchdecl},
813 {"searchpair", 3, 7, f_searchpair},
814 {"searchpairpos", 3, 7, f_searchpairpos},
815 {"searchpos", 1, 4, f_searchpos},
816 {"server2client", 2, 2, f_server2client},
817 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200818 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819 {"setbufvar", 3, 3, f_setbufvar},
820 {"setcharsearch", 1, 1, f_setcharsearch},
821 {"setcmdpos", 1, 1, f_setcmdpos},
822 {"setfperm", 2, 2, f_setfperm},
823 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200824 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825 {"setmatches", 1, 1, f_setmatches},
826 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200827 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200828 {"setreg", 2, 3, f_setreg},
829 {"settabvar", 3, 3, f_settabvar},
830 {"settabwinvar", 4, 4, f_settabwinvar},
831 {"setwinvar", 3, 3, f_setwinvar},
832#ifdef FEAT_CRYPT
833 {"sha256", 1, 1, f_sha256},
834#endif
835 {"shellescape", 1, 2, f_shellescape},
836 {"shiftwidth", 0, 0, f_shiftwidth},
837 {"simplify", 1, 1, f_simplify},
838#ifdef FEAT_FLOAT
839 {"sin", 1, 1, f_sin},
840 {"sinh", 1, 1, f_sinh},
841#endif
842 {"sort", 1, 3, f_sort},
843 {"soundfold", 1, 1, f_soundfold},
844 {"spellbadword", 0, 1, f_spellbadword},
845 {"spellsuggest", 1, 3, f_spellsuggest},
846 {"split", 1, 3, f_split},
847#ifdef FEAT_FLOAT
848 {"sqrt", 1, 1, f_sqrt},
849 {"str2float", 1, 1, f_str2float},
850#endif
851 {"str2nr", 1, 2, f_str2nr},
852 {"strcharpart", 2, 3, f_strcharpart},
853 {"strchars", 1, 2, f_strchars},
854 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
855#ifdef HAVE_STRFTIME
856 {"strftime", 1, 2, f_strftime},
857#endif
858 {"strgetchar", 2, 2, f_strgetchar},
859 {"stridx", 2, 3, f_stridx},
860 {"string", 1, 1, f_string},
861 {"strlen", 1, 1, f_strlen},
862 {"strpart", 2, 3, f_strpart},
863 {"strridx", 2, 3, f_strridx},
864 {"strtrans", 1, 1, f_strtrans},
865 {"strwidth", 1, 1, f_strwidth},
866 {"submatch", 1, 2, f_submatch},
867 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200868 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200869 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870 {"synID", 3, 3, f_synID},
871 {"synIDattr", 2, 3, f_synIDattr},
872 {"synIDtrans", 1, 1, f_synIDtrans},
873 {"synconcealed", 2, 2, f_synconcealed},
874 {"synstack", 2, 2, f_synstack},
875 {"system", 1, 2, f_system},
876 {"systemlist", 1, 2, f_systemlist},
877 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
878 {"tabpagenr", 0, 1, f_tabpagenr},
879 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
880 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100881 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200882#ifdef FEAT_FLOAT
883 {"tan", 1, 1, f_tan},
884 {"tanh", 1, 1, f_tanh},
885#endif
886 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200887#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100888 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
889 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100890 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200891 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200892# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
893 {"term_getansicolors", 1, 1, f_term_getansicolors},
894# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200895 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200896 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200897 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200898 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200899 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200900 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200901 {"term_getstatus", 1, 1, f_term_getstatus},
902 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200903 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200904 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200905 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200906 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200907# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
908 {"term_setansicolors", 2, 2, f_term_setansicolors},
909# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100910 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100911 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200912 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200913 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200914 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200915#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200916 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
917 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200918 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200919 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100920 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200921#ifdef FEAT_JOB_CHANNEL
922 {"test_null_channel", 0, 0, f_test_null_channel},
923#endif
924 {"test_null_dict", 0, 0, f_test_null_dict},
925#ifdef FEAT_JOB_CHANNEL
926 {"test_null_job", 0, 0, f_test_null_job},
927#endif
928 {"test_null_list", 0, 0, f_test_null_list},
929 {"test_null_partial", 0, 0, f_test_null_partial},
930 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200931 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100932 {"test_override", 2, 2, f_test_override},
Bram Moolenaarab186732018-09-14 21:27:06 +0200933#ifdef FEAT_GUI
934 {"test_scrollbar", 3, 3, f_test_scrollbar},
935#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200936 {"test_settime", 1, 1, f_test_settime},
937#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200938 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200939 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200940 {"timer_start", 2, 3, f_timer_start},
941 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200942 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943#endif
944 {"tolower", 1, 1, f_tolower},
945 {"toupper", 1, 1, f_toupper},
946 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100947 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948#ifdef FEAT_FLOAT
949 {"trunc", 1, 1, f_trunc},
950#endif
951 {"type", 1, 1, f_type},
952 {"undofile", 1, 1, f_undofile},
953 {"undotree", 0, 0, f_undotree},
954 {"uniq", 1, 3, f_uniq},
955 {"values", 1, 1, f_values},
956 {"virtcol", 1, 1, f_virtcol},
957 {"visualmode", 0, 1, f_visualmode},
958 {"wildmenumode", 0, 0, f_wildmenumode},
959 {"win_findbuf", 1, 1, f_win_findbuf},
960 {"win_getid", 0, 2, f_win_getid},
961 {"win_gotoid", 1, 1, f_win_gotoid},
962 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
963 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100964 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965 {"winbufnr", 1, 1, f_winbufnr},
966 {"wincol", 0, 0, f_wincol},
967 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200968 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200969 {"winline", 0, 0, f_winline},
970 {"winnr", 0, 1, f_winnr},
971 {"winrestcmd", 0, 0, f_winrestcmd},
972 {"winrestview", 1, 1, f_winrestview},
973 {"winsaveview", 0, 0, f_winsaveview},
974 {"winwidth", 1, 1, f_winwidth},
975 {"wordcount", 0, 0, f_wordcount},
976 {"writefile", 2, 3, f_writefile},
977 {"xor", 2, 2, f_xor},
978};
979
980#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
981
982/*
983 * Function given to ExpandGeneric() to obtain the list of internal
984 * or user defined function names.
985 */
986 char_u *
987get_function_name(expand_T *xp, int idx)
988{
989 static int intidx = -1;
990 char_u *name;
991
992 if (idx == 0)
993 intidx = -1;
994 if (intidx < 0)
995 {
996 name = get_user_func_name(xp, idx);
997 if (name != NULL)
998 return name;
999 }
1000 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1001 {
1002 STRCPY(IObuff, functions[intidx].f_name);
1003 STRCAT(IObuff, "(");
1004 if (functions[intidx].f_max_argc == 0)
1005 STRCAT(IObuff, ")");
1006 return IObuff;
1007 }
1008
1009 return NULL;
1010}
1011
1012/*
1013 * Function given to ExpandGeneric() to obtain the list of internal or
1014 * user defined variable or function names.
1015 */
1016 char_u *
1017get_expr_name(expand_T *xp, int idx)
1018{
1019 static int intidx = -1;
1020 char_u *name;
1021
1022 if (idx == 0)
1023 intidx = -1;
1024 if (intidx < 0)
1025 {
1026 name = get_function_name(xp, idx);
1027 if (name != NULL)
1028 return name;
1029 }
1030 return get_user_var_name(xp, ++intidx);
1031}
1032
1033#endif /* FEAT_CMDL_COMPL */
1034
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001035/*
1036 * Find internal function in table above.
1037 * Return index, or -1 if not found
1038 */
1039 int
1040find_internal_func(
1041 char_u *name) /* name of the function */
1042{
1043 int first = 0;
1044 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1045 int cmp;
1046 int x;
1047
1048 /*
1049 * Find the function name in the table. Binary search.
1050 */
1051 while (first <= last)
1052 {
1053 x = first + ((unsigned)(last - first) >> 1);
1054 cmp = STRCMP(name, functions[x].f_name);
1055 if (cmp < 0)
1056 last = x - 1;
1057 else if (cmp > 0)
1058 first = x + 1;
1059 else
1060 return x;
1061 }
1062 return -1;
1063}
1064
1065 int
1066call_internal_func(
1067 char_u *name,
1068 int argcount,
1069 typval_T *argvars,
1070 typval_T *rettv)
1071{
1072 int i;
1073
1074 i = find_internal_func(name);
1075 if (i < 0)
1076 return ERROR_UNKNOWN;
1077 if (argcount < functions[i].f_min_argc)
1078 return ERROR_TOOFEW;
1079 if (argcount > functions[i].f_max_argc)
1080 return ERROR_TOOMANY;
1081 argvars[argcount].v_type = VAR_UNKNOWN;
1082 functions[i].f_func(argvars, rettv);
1083 return ERROR_NONE;
1084}
1085
1086/*
1087 * Return TRUE for a non-zero Number and a non-empty String.
1088 */
1089 static int
1090non_zero_arg(typval_T *argvars)
1091{
1092 return ((argvars[0].v_type == VAR_NUMBER
1093 && argvars[0].vval.v_number != 0)
1094 || (argvars[0].v_type == VAR_SPECIAL
1095 && argvars[0].vval.v_number == VVAL_TRUE)
1096 || (argvars[0].v_type == VAR_STRING
1097 && argvars[0].vval.v_string != NULL
1098 && *argvars[0].vval.v_string != NUL));
1099}
1100
1101/*
1102 * Get the lnum from the first argument.
1103 * Also accepts ".", "$", etc., but that only works for the current buffer.
1104 * Returns -1 on error.
1105 */
1106 static linenr_T
1107get_tv_lnum(typval_T *argvars)
1108{
1109 typval_T rettv;
1110 linenr_T lnum;
1111
1112 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1113 if (lnum == 0) /* no valid number, try using line() */
1114 {
1115 rettv.v_type = VAR_NUMBER;
1116 f_line(argvars, &rettv);
1117 lnum = (linenr_T)rettv.vval.v_number;
1118 clear_tv(&rettv);
1119 }
1120 return lnum;
1121}
1122
1123#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001124/*
1125 * Get the float value of "argvars[0]" into "f".
1126 * Returns FAIL when the argument is not a Number or Float.
1127 */
1128 static int
1129get_float_arg(typval_T *argvars, float_T *f)
1130{
1131 if (argvars[0].v_type == VAR_FLOAT)
1132 {
1133 *f = argvars[0].vval.v_float;
1134 return OK;
1135 }
1136 if (argvars[0].v_type == VAR_NUMBER)
1137 {
1138 *f = (float_T)argvars[0].vval.v_number;
1139 return OK;
1140 }
1141 EMSG(_("E808: Number or Float required"));
1142 return FAIL;
1143}
1144
1145/*
1146 * "abs(expr)" function
1147 */
1148 static void
1149f_abs(typval_T *argvars, typval_T *rettv)
1150{
1151 if (argvars[0].v_type == VAR_FLOAT)
1152 {
1153 rettv->v_type = VAR_FLOAT;
1154 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1155 }
1156 else
1157 {
1158 varnumber_T n;
1159 int error = FALSE;
1160
1161 n = get_tv_number_chk(&argvars[0], &error);
1162 if (error)
1163 rettv->vval.v_number = -1;
1164 else if (n > 0)
1165 rettv->vval.v_number = n;
1166 else
1167 rettv->vval.v_number = -n;
1168 }
1169}
1170
1171/*
1172 * "acos()" function
1173 */
1174 static void
1175f_acos(typval_T *argvars, typval_T *rettv)
1176{
1177 float_T f = 0.0;
1178
1179 rettv->v_type = VAR_FLOAT;
1180 if (get_float_arg(argvars, &f) == OK)
1181 rettv->vval.v_float = acos(f);
1182 else
1183 rettv->vval.v_float = 0.0;
1184}
1185#endif
1186
1187/*
1188 * "add(list, item)" function
1189 */
1190 static void
1191f_add(typval_T *argvars, typval_T *rettv)
1192{
1193 list_T *l;
1194
1195 rettv->vval.v_number = 1; /* Default: Failed */
1196 if (argvars[0].v_type == VAR_LIST)
1197 {
1198 if ((l = argvars[0].vval.v_list) != NULL
1199 && !tv_check_lock(l->lv_lock,
1200 (char_u *)N_("add() argument"), TRUE)
1201 && list_append_tv(l, &argvars[1]) == OK)
1202 copy_tv(&argvars[0], rettv);
1203 }
1204 else
1205 EMSG(_(e_listreq));
1206}
1207
1208/*
1209 * "and(expr, expr)" function
1210 */
1211 static void
1212f_and(typval_T *argvars, typval_T *rettv)
1213{
1214 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1215 & get_tv_number_chk(&argvars[1], NULL);
1216}
1217
1218/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001219 * Get the lnum from the first argument.
1220 * Also accepts "$", then "buf" is used.
1221 * Returns 0 on error.
1222 */
1223 static linenr_T
1224get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
1225{
1226 if (argvars[0].v_type == VAR_STRING
1227 && argvars[0].vval.v_string != NULL
1228 && argvars[0].vval.v_string[0] == '$'
1229 && buf != NULL)
1230 return buf->b_ml.ml_line_count;
1231 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1232}
1233
1234/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001235 * If there is a window for "curbuf", make it the current window.
1236 */
1237 static void
1238find_win_for_curbuf(void)
1239{
1240 wininfo_T *wip;
1241
1242 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1243 {
1244 if (wip->wi_win != NULL)
1245 {
1246 curwin = wip->wi_win;
1247 break;
1248 }
1249 }
1250}
1251
1252/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001253 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254 */
1255 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001256set_buffer_lines(
1257 buf_T *buf,
1258 linenr_T lnum_arg,
1259 int append,
1260 typval_T *lines,
1261 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001262{
Bram Moolenaarca851592018-06-06 21:04:07 +02001263 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1264 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001265 list_T *l = NULL;
1266 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001267 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001268 linenr_T append_lnum;
1269 buf_T *curbuf_save = NULL;
1270 win_T *curwin_save = NULL;
1271 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001272
Bram Moolenaarca851592018-06-06 21:04:07 +02001273 /* When using the current buffer ml_mfp will be set if needed. Useful when
1274 * setline() is used on startup. For other buffers the buffer must be
1275 * loaded. */
1276 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001277 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001278 rettv->vval.v_number = 1; /* FAIL */
1279 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001280 }
1281
Bram Moolenaarca851592018-06-06 21:04:07 +02001282 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001283 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001284 curbuf_save = curbuf;
1285 curwin_save = curwin;
1286 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001287 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001288 }
1289
1290 if (append)
1291 // appendbufline() uses the line number below which we insert
1292 append_lnum = lnum - 1;
1293 else
1294 // setbufline() uses the line number above which we insert, we only
1295 // append if it's below the last line
1296 append_lnum = curbuf->b_ml.ml_line_count;
1297
1298 if (lines->v_type == VAR_LIST)
1299 {
1300 l = lines->vval.v_list;
1301 li = l->lv_first;
1302 }
1303 else
1304 line = get_tv_string_chk(lines);
1305
1306 /* default result is zero == OK */
1307 for (;;)
1308 {
1309 if (l != NULL)
1310 {
1311 /* list argument, get next string */
1312 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313 break;
Bram Moolenaarca851592018-06-06 21:04:07 +02001314 line = get_tv_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001315 li = li->li_next;
1316 }
1317
Bram Moolenaarca851592018-06-06 21:04:07 +02001318 rettv->vval.v_number = 1; /* FAIL */
1319 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1320 break;
1321
1322 /* When coming here from Insert mode, sync undo, so that this can be
1323 * undone separately from what was previously inserted. */
1324 if (u_sync_once == 2)
1325 {
1326 u_sync_once = 1; /* notify that u_sync() was called */
1327 u_sync(TRUE);
1328 }
1329
1330 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1331 {
1332 /* existing line, replace it */
1333 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1334 {
1335 changed_bytes(lnum, 0);
1336 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1337 check_cursor_col();
1338 rettv->vval.v_number = 0; /* OK */
1339 }
1340 }
1341 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1342 {
1343 /* append the line */
1344 ++added;
1345 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1346 rettv->vval.v_number = 0; /* OK */
1347 }
1348
1349 if (l == NULL) /* only one string argument */
1350 break;
1351 ++lnum;
1352 }
1353
1354 if (added > 0)
1355 {
1356 win_T *wp;
1357 tabpage_T *tp;
1358
1359 appended_lines_mark(append_lnum, added);
1360 FOR_ALL_TAB_WINDOWS(tp, wp)
1361 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1362 wp->w_cursor.lnum += added;
1363 check_cursor_col();
1364
Bram Moolenaarf2732452018-06-03 14:47:35 +02001365#ifdef FEAT_JOB_CHANNEL
1366 if (bt_prompt(curbuf) && (State & INSERT))
1367 // show the line with the prompt
1368 update_topline();
1369#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001370 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001371
1372 if (!is_curbuf)
1373 {
1374 curbuf = curbuf_save;
1375 curwin = curwin_save;
1376 }
1377}
1378
1379/*
1380 * "append(lnum, string/list)" function
1381 */
1382 static void
1383f_append(typval_T *argvars, typval_T *rettv)
1384{
1385 linenr_T lnum = get_tv_lnum(&argvars[0]);
1386
1387 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1388}
1389
1390/*
1391 * "appendbufline(buf, lnum, string/list)" function
1392 */
1393 static void
1394f_appendbufline(typval_T *argvars, typval_T *rettv)
1395{
1396 linenr_T lnum;
1397 buf_T *buf;
1398
1399 buf = get_buf_tv(&argvars[0], FALSE);
1400 if (buf == NULL)
1401 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001402 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001403 {
1404 lnum = get_tv_lnum_buf(&argvars[1], buf);
1405 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1406 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001407}
1408
1409/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001410 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001411 */
1412 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001413f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001414{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001415 win_T *wp;
1416
1417 if (argvars[0].v_type == VAR_UNKNOWN)
1418 // use the current window
1419 rettv->vval.v_number = ARGCOUNT;
1420 else if (argvars[0].v_type == VAR_NUMBER
1421 && get_tv_number(&argvars[0]) == -1)
1422 // use the global argument list
1423 rettv->vval.v_number = GARGCOUNT;
1424 else
1425 {
1426 // use the argument list of the specified window
1427 wp = find_win_by_nr_or_id(&argvars[0]);
1428 if (wp != NULL)
1429 rettv->vval.v_number = WARGCOUNT(wp);
1430 else
1431 rettv->vval.v_number = -1;
1432 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001433}
1434
1435/*
1436 * "argidx()" function
1437 */
1438 static void
1439f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1440{
1441 rettv->vval.v_number = curwin->w_arg_idx;
1442}
1443
1444/*
1445 * "arglistid()" function
1446 */
1447 static void
1448f_arglistid(typval_T *argvars, typval_T *rettv)
1449{
1450 win_T *wp;
1451
1452 rettv->vval.v_number = -1;
1453 wp = find_tabwin(&argvars[0], &argvars[1]);
1454 if (wp != NULL)
1455 rettv->vval.v_number = wp->w_alist->id;
1456}
1457
1458/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001459 * Get the argument list for a given window
1460 */
1461 static void
1462get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1463{
1464 int idx;
1465
1466 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1467 for (idx = 0; idx < argcount; ++idx)
1468 list_append_string(rettv->vval.v_list,
1469 alist_name(&arglist[idx]), -1);
1470}
1471
1472/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001473 * "argv(nr)" function
1474 */
1475 static void
1476f_argv(typval_T *argvars, typval_T *rettv)
1477{
1478 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001479 aentry_T *arglist = NULL;
1480 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001481
1482 if (argvars[0].v_type != VAR_UNKNOWN)
1483 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001484 if (argvars[1].v_type == VAR_UNKNOWN)
1485 {
1486 arglist = ARGLIST;
1487 argcount = ARGCOUNT;
1488 }
1489 else if (argvars[1].v_type == VAR_NUMBER
1490 && get_tv_number(&argvars[1]) == -1)
1491 {
1492 arglist = GARGLIST;
1493 argcount = GARGCOUNT;
1494 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001496 {
1497 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1498
1499 if (wp != NULL)
1500 {
1501 /* Use the argument list of the specified window */
1502 arglist = WARGLIST(wp);
1503 argcount = WARGCOUNT(wp);
1504 }
1505 }
1506
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001507 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001508 rettv->vval.v_string = NULL;
1509 idx = get_tv_number_chk(&argvars[0], NULL);
1510 if (arglist != NULL && idx >= 0 && idx < argcount)
1511 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1512 else if (idx == -1)
1513 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001514 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001515 else
1516 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001517}
1518
1519/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001520 * "assert_beeps(cmd [, error])" function
1521 */
1522 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001523f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001524{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001525 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001526}
1527
1528/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529 * "assert_equal(expected, actual[, msg])" function
1530 */
1531 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001532f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001534 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535}
1536
1537/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001538 * "assert_equalfile(fname-one, fname-two)" function
1539 */
1540 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001541f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001542{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001543 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001544}
1545
1546/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001547 * "assert_notequal(expected, actual[, msg])" function
1548 */
1549 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001550f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001551{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001552 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001553}
1554
1555/*
1556 * "assert_exception(string[, msg])" function
1557 */
1558 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001559f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001560{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001561 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001562}
1563
1564/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001565 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001566 */
1567 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001568f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001569{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001570 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001571}
1572
1573/*
1574 * "assert_false(actual[, msg])" function
1575 */
1576 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001577f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001579 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580}
1581
1582/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001583 * "assert_inrange(lower, upper[, msg])" function
1584 */
1585 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001586f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001587{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001588 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001589}
1590
1591/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001592 * "assert_match(pattern, actual[, msg])" function
1593 */
1594 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001595f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001596{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001597 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598}
1599
1600/*
1601 * "assert_notmatch(pattern, actual[, msg])" function
1602 */
1603 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001604f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001605{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001606 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607}
1608
1609/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001610 * "assert_report(msg)" function
1611 */
1612 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001613f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001614{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001615 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001616}
1617
1618/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001619 * "assert_true(actual[, msg])" function
1620 */
1621 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001622f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001623{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001624 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625}
1626
1627#ifdef FEAT_FLOAT
1628/*
1629 * "asin()" function
1630 */
1631 static void
1632f_asin(typval_T *argvars, typval_T *rettv)
1633{
1634 float_T f = 0.0;
1635
1636 rettv->v_type = VAR_FLOAT;
1637 if (get_float_arg(argvars, &f) == OK)
1638 rettv->vval.v_float = asin(f);
1639 else
1640 rettv->vval.v_float = 0.0;
1641}
1642
1643/*
1644 * "atan()" function
1645 */
1646 static void
1647f_atan(typval_T *argvars, typval_T *rettv)
1648{
1649 float_T f = 0.0;
1650
1651 rettv->v_type = VAR_FLOAT;
1652 if (get_float_arg(argvars, &f) == OK)
1653 rettv->vval.v_float = atan(f);
1654 else
1655 rettv->vval.v_float = 0.0;
1656}
1657
1658/*
1659 * "atan2()" function
1660 */
1661 static void
1662f_atan2(typval_T *argvars, typval_T *rettv)
1663{
1664 float_T fx = 0.0, fy = 0.0;
1665
1666 rettv->v_type = VAR_FLOAT;
1667 if (get_float_arg(argvars, &fx) == OK
1668 && get_float_arg(&argvars[1], &fy) == OK)
1669 rettv->vval.v_float = atan2(fx, fy);
1670 else
1671 rettv->vval.v_float = 0.0;
1672}
1673#endif
1674
1675/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001676 * "balloon_show()" function
1677 */
1678#ifdef FEAT_BEVAL
1679 static void
1680f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1681{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001682 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001683 {
1684 if (argvars[0].v_type == VAR_LIST
1685# ifdef FEAT_GUI
1686 && !gui.in_use
1687# endif
1688 )
1689 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1690 else
1691 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1692 }
1693}
1694
Bram Moolenaar669a8282017-11-19 20:13:05 +01001695# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001696 static void
1697f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1698{
1699 if (rettv_list_alloc(rettv) == OK)
1700 {
1701 char_u *msg = get_tv_string_chk(&argvars[0]);
1702
1703 if (msg != NULL)
1704 {
1705 pumitem_T *array;
1706 int size = split_message(msg, &array);
1707 int i;
1708
1709 /* Skip the first and last item, they are always empty. */
1710 for (i = 1; i < size - 1; ++i)
1711 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001712 while (size > 0)
1713 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001714 vim_free(array);
1715 }
1716 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001717}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001718# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001719#endif
1720
1721/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722 * "browse(save, title, initdir, default)" function
1723 */
1724 static void
1725f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1726{
1727#ifdef FEAT_BROWSE
1728 int save;
1729 char_u *title;
1730 char_u *initdir;
1731 char_u *defname;
1732 char_u buf[NUMBUFLEN];
1733 char_u buf2[NUMBUFLEN];
1734 int error = FALSE;
1735
1736 save = (int)get_tv_number_chk(&argvars[0], &error);
1737 title = get_tv_string_chk(&argvars[1]);
1738 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1739 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1740
1741 if (error || title == NULL || initdir == NULL || defname == NULL)
1742 rettv->vval.v_string = NULL;
1743 else
1744 rettv->vval.v_string =
1745 do_browse(save ? BROWSE_SAVE : 0,
1746 title, defname, NULL, initdir, NULL, curbuf);
1747#else
1748 rettv->vval.v_string = NULL;
1749#endif
1750 rettv->v_type = VAR_STRING;
1751}
1752
1753/*
1754 * "browsedir(title, initdir)" function
1755 */
1756 static void
1757f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1758{
1759#ifdef FEAT_BROWSE
1760 char_u *title;
1761 char_u *initdir;
1762 char_u buf[NUMBUFLEN];
1763
1764 title = get_tv_string_chk(&argvars[0]);
1765 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1766
1767 if (title == NULL || initdir == NULL)
1768 rettv->vval.v_string = NULL;
1769 else
1770 rettv->vval.v_string = do_browse(BROWSE_DIR,
1771 title, NULL, NULL, initdir, NULL, curbuf);
1772#else
1773 rettv->vval.v_string = NULL;
1774#endif
1775 rettv->v_type = VAR_STRING;
1776}
1777
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001778/*
1779 * Find a buffer by number or exact name.
1780 */
1781 static buf_T *
1782find_buffer(typval_T *avar)
1783{
1784 buf_T *buf = NULL;
1785
1786 if (avar->v_type == VAR_NUMBER)
1787 buf = buflist_findnr((int)avar->vval.v_number);
1788 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1789 {
1790 buf = buflist_findname_exp(avar->vval.v_string);
1791 if (buf == NULL)
1792 {
1793 /* No full path name match, try a match with a URL or a "nofile"
1794 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001795 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001796 if (buf->b_fname != NULL
1797 && (path_with_url(buf->b_fname)
1798#ifdef FEAT_QUICKFIX
1799 || bt_nofile(buf)
1800#endif
1801 )
1802 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1803 break;
1804 }
1805 }
1806 return buf;
1807}
1808
1809/*
1810 * "bufexists(expr)" function
1811 */
1812 static void
1813f_bufexists(typval_T *argvars, typval_T *rettv)
1814{
1815 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1816}
1817
1818/*
1819 * "buflisted(expr)" function
1820 */
1821 static void
1822f_buflisted(typval_T *argvars, typval_T *rettv)
1823{
1824 buf_T *buf;
1825
1826 buf = find_buffer(&argvars[0]);
1827 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1828}
1829
1830/*
1831 * "bufloaded(expr)" function
1832 */
1833 static void
1834f_bufloaded(typval_T *argvars, typval_T *rettv)
1835{
1836 buf_T *buf;
1837
1838 buf = find_buffer(&argvars[0]);
1839 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1840}
1841
1842 buf_T *
1843buflist_find_by_name(char_u *name, int curtab_only)
1844{
1845 int save_magic;
1846 char_u *save_cpo;
1847 buf_T *buf;
1848
1849 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1850 save_magic = p_magic;
1851 p_magic = TRUE;
1852 save_cpo = p_cpo;
1853 p_cpo = (char_u *)"";
1854
1855 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1856 TRUE, FALSE, curtab_only));
1857
1858 p_magic = save_magic;
1859 p_cpo = save_cpo;
1860 return buf;
1861}
1862
1863/*
1864 * Get buffer by number or pattern.
1865 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001866 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001867get_buf_tv(typval_T *tv, int curtab_only)
1868{
1869 char_u *name = tv->vval.v_string;
1870 buf_T *buf;
1871
1872 if (tv->v_type == VAR_NUMBER)
1873 return buflist_findnr((int)tv->vval.v_number);
1874 if (tv->v_type != VAR_STRING)
1875 return NULL;
1876 if (name == NULL || *name == NUL)
1877 return curbuf;
1878 if (name[0] == '$' && name[1] == NUL)
1879 return lastbuf;
1880
1881 buf = buflist_find_by_name(name, curtab_only);
1882
1883 /* If not found, try expanding the name, like done for bufexists(). */
1884 if (buf == NULL)
1885 buf = find_buffer(tv);
1886
1887 return buf;
1888}
1889
1890/*
1891 * "bufname(expr)" function
1892 */
1893 static void
1894f_bufname(typval_T *argvars, typval_T *rettv)
1895{
1896 buf_T *buf;
1897
1898 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1899 ++emsg_off;
1900 buf = get_buf_tv(&argvars[0], FALSE);
1901 rettv->v_type = VAR_STRING;
1902 if (buf != NULL && buf->b_fname != NULL)
1903 rettv->vval.v_string = vim_strsave(buf->b_fname);
1904 else
1905 rettv->vval.v_string = NULL;
1906 --emsg_off;
1907}
1908
1909/*
1910 * "bufnr(expr)" function
1911 */
1912 static void
1913f_bufnr(typval_T *argvars, typval_T *rettv)
1914{
1915 buf_T *buf;
1916 int error = FALSE;
1917 char_u *name;
1918
1919 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1920 ++emsg_off;
1921 buf = get_buf_tv(&argvars[0], FALSE);
1922 --emsg_off;
1923
1924 /* If the buffer isn't found and the second argument is not zero create a
1925 * new buffer. */
1926 if (buf == NULL
1927 && argvars[1].v_type != VAR_UNKNOWN
1928 && get_tv_number_chk(&argvars[1], &error) != 0
1929 && !error
1930 && (name = get_tv_string_chk(&argvars[0])) != NULL
1931 && !error)
1932 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1933
1934 if (buf != NULL)
1935 rettv->vval.v_number = buf->b_fnum;
1936 else
1937 rettv->vval.v_number = -1;
1938}
1939
1940 static void
1941buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1942{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001943 win_T *wp;
1944 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001945 buf_T *buf;
1946
1947 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1948 ++emsg_off;
1949 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001950 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001951 {
1952 ++winnr;
1953 if (wp->w_buffer == buf)
1954 break;
1955 }
1956 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 --emsg_off;
1958}
1959
1960/*
1961 * "bufwinid(nr)" function
1962 */
1963 static void
1964f_bufwinid(typval_T *argvars, typval_T *rettv)
1965{
1966 buf_win_common(argvars, rettv, FALSE);
1967}
1968
1969/*
1970 * "bufwinnr(nr)" function
1971 */
1972 static void
1973f_bufwinnr(typval_T *argvars, typval_T *rettv)
1974{
1975 buf_win_common(argvars, rettv, TRUE);
1976}
1977
1978/*
1979 * "byte2line(byte)" function
1980 */
1981 static void
1982f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1983{
1984#ifndef FEAT_BYTEOFF
1985 rettv->vval.v_number = -1;
1986#else
1987 long boff = 0;
1988
1989 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1990 if (boff < 0)
1991 rettv->vval.v_number = -1;
1992 else
1993 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1994 (linenr_T)0, &boff);
1995#endif
1996}
1997
1998 static void
1999byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2000{
2001#ifdef FEAT_MBYTE
2002 char_u *t;
2003#endif
2004 char_u *str;
2005 varnumber_T idx;
2006
2007 str = get_tv_string_chk(&argvars[0]);
2008 idx = get_tv_number_chk(&argvars[1], NULL);
2009 rettv->vval.v_number = -1;
2010 if (str == NULL || idx < 0)
2011 return;
2012
2013#ifdef FEAT_MBYTE
2014 t = str;
2015 for ( ; idx > 0; idx--)
2016 {
2017 if (*t == NUL) /* EOL reached */
2018 return;
2019 if (enc_utf8 && comp)
2020 t += utf_ptr2len(t);
2021 else
2022 t += (*mb_ptr2len)(t);
2023 }
2024 rettv->vval.v_number = (varnumber_T)(t - str);
2025#else
2026 if ((size_t)idx <= STRLEN(str))
2027 rettv->vval.v_number = idx;
2028#endif
2029}
2030
2031/*
2032 * "byteidx()" function
2033 */
2034 static void
2035f_byteidx(typval_T *argvars, typval_T *rettv)
2036{
2037 byteidx(argvars, rettv, FALSE);
2038}
2039
2040/*
2041 * "byteidxcomp()" function
2042 */
2043 static void
2044f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2045{
2046 byteidx(argvars, rettv, TRUE);
2047}
2048
2049/*
2050 * "call(func, arglist [, dict])" function
2051 */
2052 static void
2053f_call(typval_T *argvars, typval_T *rettv)
2054{
2055 char_u *func;
2056 partial_T *partial = NULL;
2057 dict_T *selfdict = NULL;
2058
2059 if (argvars[1].v_type != VAR_LIST)
2060 {
2061 EMSG(_(e_listreq));
2062 return;
2063 }
2064 if (argvars[1].vval.v_list == NULL)
2065 return;
2066
2067 if (argvars[0].v_type == VAR_FUNC)
2068 func = argvars[0].vval.v_string;
2069 else if (argvars[0].v_type == VAR_PARTIAL)
2070 {
2071 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002072 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002073 }
2074 else
2075 func = get_tv_string(&argvars[0]);
2076 if (*func == NUL)
2077 return; /* type error or empty name */
2078
2079 if (argvars[2].v_type != VAR_UNKNOWN)
2080 {
2081 if (argvars[2].v_type != VAR_DICT)
2082 {
2083 EMSG(_(e_dictreq));
2084 return;
2085 }
2086 selfdict = argvars[2].vval.v_dict;
2087 }
2088
2089 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2090}
2091
2092#ifdef FEAT_FLOAT
2093/*
2094 * "ceil({float})" function
2095 */
2096 static void
2097f_ceil(typval_T *argvars, typval_T *rettv)
2098{
2099 float_T f = 0.0;
2100
2101 rettv->v_type = VAR_FLOAT;
2102 if (get_float_arg(argvars, &f) == OK)
2103 rettv->vval.v_float = ceil(f);
2104 else
2105 rettv->vval.v_float = 0.0;
2106}
2107#endif
2108
2109#ifdef FEAT_JOB_CHANNEL
2110/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002111 * "ch_canread()" function
2112 */
2113 static void
2114f_ch_canread(typval_T *argvars, typval_T *rettv)
2115{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002116 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002117
2118 rettv->vval.v_number = 0;
2119 if (channel != NULL)
2120 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2121 || channel_has_readahead(channel, PART_OUT)
2122 || channel_has_readahead(channel, PART_ERR);
2123}
2124
2125/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002126 * "ch_close()" function
2127 */
2128 static void
2129f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2130{
2131 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2132
2133 if (channel != NULL)
2134 {
2135 channel_close(channel, FALSE);
2136 channel_clear(channel);
2137 }
2138}
2139
2140/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002141 * "ch_close()" function
2142 */
2143 static void
2144f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2145{
2146 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2147
2148 if (channel != NULL)
2149 channel_close_in(channel);
2150}
2151
2152/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 * "ch_getbufnr()" function
2154 */
2155 static void
2156f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2157{
2158 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2159
2160 rettv->vval.v_number = -1;
2161 if (channel != NULL)
2162 {
2163 char_u *what = get_tv_string(&argvars[1]);
2164 int part;
2165
2166 if (STRCMP(what, "err") == 0)
2167 part = PART_ERR;
2168 else if (STRCMP(what, "out") == 0)
2169 part = PART_OUT;
2170 else if (STRCMP(what, "in") == 0)
2171 part = PART_IN;
2172 else
2173 part = PART_SOCK;
2174 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2175 rettv->vval.v_number =
2176 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2177 }
2178}
2179
2180/*
2181 * "ch_getjob()" function
2182 */
2183 static void
2184f_ch_getjob(typval_T *argvars, typval_T *rettv)
2185{
2186 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2187
2188 if (channel != NULL)
2189 {
2190 rettv->v_type = VAR_JOB;
2191 rettv->vval.v_job = channel->ch_job;
2192 if (channel->ch_job != NULL)
2193 ++channel->ch_job->jv_refcount;
2194 }
2195}
2196
2197/*
2198 * "ch_info()" function
2199 */
2200 static void
2201f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2202{
2203 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2204
2205 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2206 channel_info(channel, rettv->vval.v_dict);
2207}
2208
2209/*
2210 * "ch_log()" function
2211 */
2212 static void
2213f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2214{
2215 char_u *msg = get_tv_string(&argvars[0]);
2216 channel_T *channel = NULL;
2217
2218 if (argvars[1].v_type != VAR_UNKNOWN)
2219 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2220
Bram Moolenaard5359b22018-04-05 22:44:39 +02002221 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002222}
2223
2224/*
2225 * "ch_logfile()" function
2226 */
2227 static void
2228f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2229{
2230 char_u *fname;
2231 char_u *opt = (char_u *)"";
2232 char_u buf[NUMBUFLEN];
2233
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002234 /* Don't open a file in restricted mode. */
2235 if (check_restricted() || check_secure())
2236 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002237 fname = get_tv_string(&argvars[0]);
2238 if (argvars[1].v_type == VAR_STRING)
2239 opt = get_tv_string_buf(&argvars[1], buf);
2240 ch_logfile(fname, opt);
2241}
2242
2243/*
2244 * "ch_open()" function
2245 */
2246 static void
2247f_ch_open(typval_T *argvars, typval_T *rettv)
2248{
2249 rettv->v_type = VAR_CHANNEL;
2250 if (check_restricted() || check_secure())
2251 return;
2252 rettv->vval.v_channel = channel_open_func(argvars);
2253}
2254
2255/*
2256 * "ch_read()" function
2257 */
2258 static void
2259f_ch_read(typval_T *argvars, typval_T *rettv)
2260{
2261 common_channel_read(argvars, rettv, FALSE);
2262}
2263
2264/*
2265 * "ch_readraw()" function
2266 */
2267 static void
2268f_ch_readraw(typval_T *argvars, typval_T *rettv)
2269{
2270 common_channel_read(argvars, rettv, TRUE);
2271}
2272
2273/*
2274 * "ch_evalexpr()" function
2275 */
2276 static void
2277f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2278{
2279 ch_expr_common(argvars, rettv, TRUE);
2280}
2281
2282/*
2283 * "ch_sendexpr()" function
2284 */
2285 static void
2286f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2287{
2288 ch_expr_common(argvars, rettv, FALSE);
2289}
2290
2291/*
2292 * "ch_evalraw()" function
2293 */
2294 static void
2295f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2296{
2297 ch_raw_common(argvars, rettv, TRUE);
2298}
2299
2300/*
2301 * "ch_sendraw()" function
2302 */
2303 static void
2304f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2305{
2306 ch_raw_common(argvars, rettv, FALSE);
2307}
2308
2309/*
2310 * "ch_setoptions()" function
2311 */
2312 static void
2313f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2314{
2315 channel_T *channel;
2316 jobopt_T opt;
2317
2318 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2319 if (channel == NULL)
2320 return;
2321 clear_job_options(&opt);
2322 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002323 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002324 channel_set_options(channel, &opt);
2325 free_job_options(&opt);
2326}
2327
2328/*
2329 * "ch_status()" function
2330 */
2331 static void
2332f_ch_status(typval_T *argvars, typval_T *rettv)
2333{
2334 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002335 jobopt_T opt;
2336 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002337
2338 /* return an empty string by default */
2339 rettv->v_type = VAR_STRING;
2340 rettv->vval.v_string = NULL;
2341
2342 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002343
2344 if (argvars[1].v_type != VAR_UNKNOWN)
2345 {
2346 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002347 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002348 && (opt.jo_set & JO_PART))
2349 part = opt.jo_part;
2350 }
2351
2352 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353}
2354#endif
2355
2356/*
2357 * "changenr()" function
2358 */
2359 static void
2360f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2361{
2362 rettv->vval.v_number = curbuf->b_u_seq_cur;
2363}
2364
2365/*
2366 * "char2nr(string)" function
2367 */
2368 static void
2369f_char2nr(typval_T *argvars, typval_T *rettv)
2370{
2371#ifdef FEAT_MBYTE
2372 if (has_mbyte)
2373 {
2374 int utf8 = 0;
2375
2376 if (argvars[1].v_type != VAR_UNKNOWN)
2377 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2378
2379 if (utf8)
2380 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2381 else
2382 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2383 }
2384 else
2385#endif
2386 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2387}
2388
2389/*
2390 * "cindent(lnum)" function
2391 */
2392 static void
2393f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2394{
2395#ifdef FEAT_CINDENT
2396 pos_T pos;
2397 linenr_T lnum;
2398
2399 pos = curwin->w_cursor;
2400 lnum = get_tv_lnum(argvars);
2401 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2402 {
2403 curwin->w_cursor.lnum = lnum;
2404 rettv->vval.v_number = get_c_indent();
2405 curwin->w_cursor = pos;
2406 }
2407 else
2408#endif
2409 rettv->vval.v_number = -1;
2410}
2411
2412/*
2413 * "clearmatches()" function
2414 */
2415 static void
2416f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2417{
2418#ifdef FEAT_SEARCH_EXTRA
2419 clear_matches(curwin);
2420#endif
2421}
2422
2423/*
2424 * "col(string)" function
2425 */
2426 static void
2427f_col(typval_T *argvars, typval_T *rettv)
2428{
2429 colnr_T col = 0;
2430 pos_T *fp;
2431 int fnum = curbuf->b_fnum;
2432
2433 fp = var2fpos(&argvars[0], FALSE, &fnum);
2434 if (fp != NULL && fnum == curbuf->b_fnum)
2435 {
2436 if (fp->col == MAXCOL)
2437 {
2438 /* '> can be MAXCOL, get the length of the line then */
2439 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2440 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2441 else
2442 col = MAXCOL;
2443 }
2444 else
2445 {
2446 col = fp->col + 1;
2447#ifdef FEAT_VIRTUALEDIT
2448 /* col(".") when the cursor is on the NUL at the end of the line
2449 * because of "coladd" can be seen as an extra column. */
2450 if (virtual_active() && fp == &curwin->w_cursor)
2451 {
2452 char_u *p = ml_get_cursor();
2453
2454 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2455 curwin->w_virtcol - curwin->w_cursor.coladd))
2456 {
2457# ifdef FEAT_MBYTE
2458 int l;
2459
2460 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2461 col += l;
2462# else
2463 if (*p != NUL && p[1] == NUL)
2464 ++col;
2465# endif
2466 }
2467 }
2468#endif
2469 }
2470 }
2471 rettv->vval.v_number = col;
2472}
2473
2474#if defined(FEAT_INS_EXPAND)
2475/*
2476 * "complete()" function
2477 */
2478 static void
2479f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2480{
2481 int startcol;
2482
2483 if ((State & INSERT) == 0)
2484 {
2485 EMSG(_("E785: complete() can only be used in Insert mode"));
2486 return;
2487 }
2488
2489 /* Check for undo allowed here, because if something was already inserted
2490 * the line was already saved for undo and this check isn't done. */
2491 if (!undo_allowed())
2492 return;
2493
2494 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2495 {
2496 EMSG(_(e_invarg));
2497 return;
2498 }
2499
2500 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2501 if (startcol <= 0)
2502 return;
2503
2504 set_completion(startcol - 1, argvars[1].vval.v_list);
2505}
2506
2507/*
2508 * "complete_add()" function
2509 */
2510 static void
2511f_complete_add(typval_T *argvars, typval_T *rettv)
2512{
2513 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2514}
2515
2516/*
2517 * "complete_check()" function
2518 */
2519 static void
2520f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2521{
2522 int saved = RedrawingDisabled;
2523
2524 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002525 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 rettv->vval.v_number = compl_interrupted;
2527 RedrawingDisabled = saved;
2528}
2529#endif
2530
2531/*
2532 * "confirm(message, buttons[, default [, type]])" function
2533 */
2534 static void
2535f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2536{
2537#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2538 char_u *message;
2539 char_u *buttons = NULL;
2540 char_u buf[NUMBUFLEN];
2541 char_u buf2[NUMBUFLEN];
2542 int def = 1;
2543 int type = VIM_GENERIC;
2544 char_u *typestr;
2545 int error = FALSE;
2546
2547 message = get_tv_string_chk(&argvars[0]);
2548 if (message == NULL)
2549 error = TRUE;
2550 if (argvars[1].v_type != VAR_UNKNOWN)
2551 {
2552 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2553 if (buttons == NULL)
2554 error = TRUE;
2555 if (argvars[2].v_type != VAR_UNKNOWN)
2556 {
2557 def = (int)get_tv_number_chk(&argvars[2], &error);
2558 if (argvars[3].v_type != VAR_UNKNOWN)
2559 {
2560 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2561 if (typestr == NULL)
2562 error = TRUE;
2563 else
2564 {
2565 switch (TOUPPER_ASC(*typestr))
2566 {
2567 case 'E': type = VIM_ERROR; break;
2568 case 'Q': type = VIM_QUESTION; break;
2569 case 'I': type = VIM_INFO; break;
2570 case 'W': type = VIM_WARNING; break;
2571 case 'G': type = VIM_GENERIC; break;
2572 }
2573 }
2574 }
2575 }
2576 }
2577
2578 if (buttons == NULL || *buttons == NUL)
2579 buttons = (char_u *)_("&Ok");
2580
2581 if (!error)
2582 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2583 def, NULL, FALSE);
2584#endif
2585}
2586
2587/*
2588 * "copy()" function
2589 */
2590 static void
2591f_copy(typval_T *argvars, typval_T *rettv)
2592{
2593 item_copy(&argvars[0], rettv, FALSE, 0);
2594}
2595
2596#ifdef FEAT_FLOAT
2597/*
2598 * "cos()" function
2599 */
2600 static void
2601f_cos(typval_T *argvars, typval_T *rettv)
2602{
2603 float_T f = 0.0;
2604
2605 rettv->v_type = VAR_FLOAT;
2606 if (get_float_arg(argvars, &f) == OK)
2607 rettv->vval.v_float = cos(f);
2608 else
2609 rettv->vval.v_float = 0.0;
2610}
2611
2612/*
2613 * "cosh()" function
2614 */
2615 static void
2616f_cosh(typval_T *argvars, typval_T *rettv)
2617{
2618 float_T f = 0.0;
2619
2620 rettv->v_type = VAR_FLOAT;
2621 if (get_float_arg(argvars, &f) == OK)
2622 rettv->vval.v_float = cosh(f);
2623 else
2624 rettv->vval.v_float = 0.0;
2625}
2626#endif
2627
2628/*
2629 * "count()" function
2630 */
2631 static void
2632f_count(typval_T *argvars, typval_T *rettv)
2633{
2634 long n = 0;
2635 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002636 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002637
Bram Moolenaar9966b212017-07-28 16:46:57 +02002638 if (argvars[2].v_type != VAR_UNKNOWN)
2639 ic = (int)get_tv_number_chk(&argvars[2], &error);
2640
2641 if (argvars[0].v_type == VAR_STRING)
2642 {
2643 char_u *expr = get_tv_string_chk(&argvars[1]);
2644 char_u *p = argvars[0].vval.v_string;
2645 char_u *next;
2646
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002647 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002648 {
2649 if (ic)
2650 {
2651 size_t len = STRLEN(expr);
2652
2653 while (*p != NUL)
2654 {
2655 if (MB_STRNICMP(p, expr, len) == 0)
2656 {
2657 ++n;
2658 p += len;
2659 }
2660 else
2661 MB_PTR_ADV(p);
2662 }
2663 }
2664 else
2665 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2666 != NULL)
2667 {
2668 ++n;
2669 p = next + STRLEN(expr);
2670 }
2671 }
2672
2673 }
2674 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675 {
2676 listitem_T *li;
2677 list_T *l;
2678 long idx;
2679
2680 if ((l = argvars[0].vval.v_list) != NULL)
2681 {
2682 li = l->lv_first;
2683 if (argvars[2].v_type != VAR_UNKNOWN)
2684 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002685 if (argvars[3].v_type != VAR_UNKNOWN)
2686 {
2687 idx = (long)get_tv_number_chk(&argvars[3], &error);
2688 if (!error)
2689 {
2690 li = list_find(l, idx);
2691 if (li == NULL)
2692 EMSGN(_(e_listidx), idx);
2693 }
2694 }
2695 if (error)
2696 li = NULL;
2697 }
2698
2699 for ( ; li != NULL; li = li->li_next)
2700 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2701 ++n;
2702 }
2703 }
2704 else if (argvars[0].v_type == VAR_DICT)
2705 {
2706 int todo;
2707 dict_T *d;
2708 hashitem_T *hi;
2709
2710 if ((d = argvars[0].vval.v_dict) != NULL)
2711 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002712 if (argvars[2].v_type != VAR_UNKNOWN)
2713 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002714 if (argvars[3].v_type != VAR_UNKNOWN)
2715 EMSG(_(e_invarg));
2716 }
2717
2718 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2719 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2720 {
2721 if (!HASHITEM_EMPTY(hi))
2722 {
2723 --todo;
2724 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2725 ++n;
2726 }
2727 }
2728 }
2729 }
2730 else
2731 EMSG2(_(e_listdictarg), "count()");
2732 rettv->vval.v_number = n;
2733}
2734
2735/*
2736 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2737 *
2738 * Checks the existence of a cscope connection.
2739 */
2740 static void
2741f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2742{
2743#ifdef FEAT_CSCOPE
2744 int num = 0;
2745 char_u *dbpath = NULL;
2746 char_u *prepend = NULL;
2747 char_u buf[NUMBUFLEN];
2748
2749 if (argvars[0].v_type != VAR_UNKNOWN
2750 && argvars[1].v_type != VAR_UNKNOWN)
2751 {
2752 num = (int)get_tv_number(&argvars[0]);
2753 dbpath = get_tv_string(&argvars[1]);
2754 if (argvars[2].v_type != VAR_UNKNOWN)
2755 prepend = get_tv_string_buf(&argvars[2], buf);
2756 }
2757
2758 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2759#endif
2760}
2761
2762/*
2763 * "cursor(lnum, col)" function, or
2764 * "cursor(list)"
2765 *
2766 * Moves the cursor to the specified line and column.
2767 * Returns 0 when the position could be set, -1 otherwise.
2768 */
2769 static void
2770f_cursor(typval_T *argvars, typval_T *rettv)
2771{
2772 long line, col;
2773#ifdef FEAT_VIRTUALEDIT
2774 long coladd = 0;
2775#endif
2776 int set_curswant = TRUE;
2777
2778 rettv->vval.v_number = -1;
2779 if (argvars[1].v_type == VAR_UNKNOWN)
2780 {
2781 pos_T pos;
2782 colnr_T curswant = -1;
2783
2784 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2785 {
2786 EMSG(_(e_invarg));
2787 return;
2788 }
2789 line = pos.lnum;
2790 col = pos.col;
2791#ifdef FEAT_VIRTUALEDIT
2792 coladd = pos.coladd;
2793#endif
2794 if (curswant >= 0)
2795 {
2796 curwin->w_curswant = curswant - 1;
2797 set_curswant = FALSE;
2798 }
2799 }
2800 else
2801 {
2802 line = get_tv_lnum(argvars);
2803 col = (long)get_tv_number_chk(&argvars[1], NULL);
2804#ifdef FEAT_VIRTUALEDIT
2805 if (argvars[2].v_type != VAR_UNKNOWN)
2806 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2807#endif
2808 }
2809 if (line < 0 || col < 0
2810#ifdef FEAT_VIRTUALEDIT
2811 || coladd < 0
2812#endif
2813 )
2814 return; /* type error; errmsg already given */
2815 if (line > 0)
2816 curwin->w_cursor.lnum = line;
2817 if (col > 0)
2818 curwin->w_cursor.col = col - 1;
2819#ifdef FEAT_VIRTUALEDIT
2820 curwin->w_cursor.coladd = coladd;
2821#endif
2822
2823 /* Make sure the cursor is in a valid position. */
2824 check_cursor();
2825#ifdef FEAT_MBYTE
2826 /* Correct cursor for multi-byte character. */
2827 if (has_mbyte)
2828 mb_adjust_cursor();
2829#endif
2830
2831 curwin->w_set_curswant = set_curswant;
2832 rettv->vval.v_number = 0;
2833}
2834
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002835#ifdef WIN3264
2836/*
2837 * "debugbreak()" function
2838 */
2839 static void
2840f_debugbreak(typval_T *argvars, typval_T *rettv)
2841{
2842 int pid;
2843
2844 rettv->vval.v_number = FAIL;
2845 pid = (int)get_tv_number(&argvars[0]);
2846 if (pid == 0)
2847 EMSG(_(e_invarg));
2848 else
2849 {
2850 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2851
2852 if (hProcess != NULL)
2853 {
2854 DebugBreakProcess(hProcess);
2855 CloseHandle(hProcess);
2856 rettv->vval.v_number = OK;
2857 }
2858 }
2859}
2860#endif
2861
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002862/*
2863 * "deepcopy()" function
2864 */
2865 static void
2866f_deepcopy(typval_T *argvars, typval_T *rettv)
2867{
2868 int noref = 0;
2869 int copyID;
2870
2871 if (argvars[1].v_type != VAR_UNKNOWN)
2872 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2873 if (noref < 0 || noref > 1)
2874 EMSG(_(e_invarg));
2875 else
2876 {
2877 copyID = get_copyID();
2878 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2879 }
2880}
2881
2882/*
2883 * "delete()" function
2884 */
2885 static void
2886f_delete(typval_T *argvars, typval_T *rettv)
2887{
2888 char_u nbuf[NUMBUFLEN];
2889 char_u *name;
2890 char_u *flags;
2891
2892 rettv->vval.v_number = -1;
2893 if (check_restricted() || check_secure())
2894 return;
2895
2896 name = get_tv_string(&argvars[0]);
2897 if (name == NULL || *name == NUL)
2898 {
2899 EMSG(_(e_invarg));
2900 return;
2901 }
2902
2903 if (argvars[1].v_type != VAR_UNKNOWN)
2904 flags = get_tv_string_buf(&argvars[1], nbuf);
2905 else
2906 flags = (char_u *)"";
2907
2908 if (*flags == NUL)
2909 /* delete a file */
2910 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2911 else if (STRCMP(flags, "d") == 0)
2912 /* delete an empty directory */
2913 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2914 else if (STRCMP(flags, "rf") == 0)
2915 /* delete a directory recursively */
2916 rettv->vval.v_number = delete_recursive(name);
2917 else
2918 EMSG2(_(e_invexpr2), flags);
2919}
2920
2921/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002922 * "deletebufline()" function
2923 */
2924 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002925f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002926{
2927 buf_T *buf;
2928 linenr_T first, last;
2929 linenr_T lnum;
2930 long count;
2931 int is_curbuf;
2932 buf_T *curbuf_save = NULL;
2933 win_T *curwin_save = NULL;
2934 tabpage_T *tp;
2935 win_T *wp;
2936
2937 buf = get_buf_tv(&argvars[0], FALSE);
2938 if (buf == NULL)
2939 {
2940 rettv->vval.v_number = 1; /* FAIL */
2941 return;
2942 }
2943 is_curbuf = buf == curbuf;
2944
2945 first = get_tv_lnum_buf(&argvars[1], buf);
2946 if (argvars[2].v_type != VAR_UNKNOWN)
2947 last = get_tv_lnum_buf(&argvars[2], buf);
2948 else
2949 last = first;
2950
2951 if (buf->b_ml.ml_mfp == NULL || first < 1
2952 || first > buf->b_ml.ml_line_count || last < first)
2953 {
2954 rettv->vval.v_number = 1; /* FAIL */
2955 return;
2956 }
2957
2958 if (!is_curbuf)
2959 {
2960 curbuf_save = curbuf;
2961 curwin_save = curwin;
2962 curbuf = buf;
2963 find_win_for_curbuf();
2964 }
2965 if (last > curbuf->b_ml.ml_line_count)
2966 last = curbuf->b_ml.ml_line_count;
2967 count = last - first + 1;
2968
2969 // When coming here from Insert mode, sync undo, so that this can be
2970 // undone separately from what was previously inserted.
2971 if (u_sync_once == 2)
2972 {
2973 u_sync_once = 1; // notify that u_sync() was called
2974 u_sync(TRUE);
2975 }
2976
2977 if (u_save(first - 1, last + 1) == FAIL)
2978 {
2979 rettv->vval.v_number = 1; /* FAIL */
2980 return;
2981 }
2982
2983 for (lnum = first; lnum <= last; ++lnum)
2984 ml_delete(first, TRUE);
2985
2986 FOR_ALL_TAB_WINDOWS(tp, wp)
2987 if (wp->w_buffer == buf)
2988 {
2989 if (wp->w_cursor.lnum > last)
2990 wp->w_cursor.lnum -= count;
2991 else if (wp->w_cursor.lnum> first)
2992 wp->w_cursor.lnum = first;
2993 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2994 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2995 }
2996 check_cursor_col();
2997 deleted_lines_mark(first, count);
2998
2999 if (!is_curbuf)
3000 {
3001 curbuf = curbuf_save;
3002 curwin = curwin_save;
3003 }
3004}
3005
3006/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003007 * "did_filetype()" function
3008 */
3009 static void
3010f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3011{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003012 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003013}
3014
3015/*
3016 * "diff_filler()" function
3017 */
3018 static void
3019f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3020{
3021#ifdef FEAT_DIFF
3022 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
3023#endif
3024}
3025
3026/*
3027 * "diff_hlID()" function
3028 */
3029 static void
3030f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3031{
3032#ifdef FEAT_DIFF
3033 linenr_T lnum = get_tv_lnum(argvars);
3034 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003035 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 static int fnum = 0;
3037 static int change_start = 0;
3038 static int change_end = 0;
3039 static hlf_T hlID = (hlf_T)0;
3040 int filler_lines;
3041 int col;
3042
3043 if (lnum < 0) /* ignore type error in {lnum} arg */
3044 lnum = 0;
3045 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003046 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003047 || fnum != curbuf->b_fnum)
3048 {
3049 /* New line, buffer, change: need to get the values. */
3050 filler_lines = diff_check(curwin, lnum);
3051 if (filler_lines < 0)
3052 {
3053 if (filler_lines == -1)
3054 {
3055 change_start = MAXCOL;
3056 change_end = -1;
3057 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3058 hlID = HLF_ADD; /* added line */
3059 else
3060 hlID = HLF_CHD; /* changed line */
3061 }
3062 else
3063 hlID = HLF_ADD; /* added line */
3064 }
3065 else
3066 hlID = (hlf_T)0;
3067 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003068 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003069 fnum = curbuf->b_fnum;
3070 }
3071
3072 if (hlID == HLF_CHD || hlID == HLF_TXD)
3073 {
3074 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
3075 if (col >= change_start && col <= change_end)
3076 hlID = HLF_TXD; /* changed text */
3077 else
3078 hlID = HLF_CHD; /* changed line */
3079 }
3080 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3081#endif
3082}
3083
3084/*
3085 * "empty({expr})" function
3086 */
3087 static void
3088f_empty(typval_T *argvars, typval_T *rettv)
3089{
3090 int n = FALSE;
3091
3092 switch (argvars[0].v_type)
3093 {
3094 case VAR_STRING:
3095 case VAR_FUNC:
3096 n = argvars[0].vval.v_string == NULL
3097 || *argvars[0].vval.v_string == NUL;
3098 break;
3099 case VAR_PARTIAL:
3100 n = FALSE;
3101 break;
3102 case VAR_NUMBER:
3103 n = argvars[0].vval.v_number == 0;
3104 break;
3105 case VAR_FLOAT:
3106#ifdef FEAT_FLOAT
3107 n = argvars[0].vval.v_float == 0.0;
3108 break;
3109#endif
3110 case VAR_LIST:
3111 n = argvars[0].vval.v_list == NULL
3112 || argvars[0].vval.v_list->lv_first == NULL;
3113 break;
3114 case VAR_DICT:
3115 n = argvars[0].vval.v_dict == NULL
3116 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3117 break;
3118 case VAR_SPECIAL:
3119 n = argvars[0].vval.v_number != VVAL_TRUE;
3120 break;
3121
3122 case VAR_JOB:
3123#ifdef FEAT_JOB_CHANNEL
3124 n = argvars[0].vval.v_job == NULL
3125 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3126 break;
3127#endif
3128 case VAR_CHANNEL:
3129#ifdef FEAT_JOB_CHANNEL
3130 n = argvars[0].vval.v_channel == NULL
3131 || !channel_is_open(argvars[0].vval.v_channel);
3132 break;
3133#endif
3134 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003135 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003136 n = TRUE;
3137 break;
3138 }
3139
3140 rettv->vval.v_number = n;
3141}
3142
3143/*
3144 * "escape({string}, {chars})" function
3145 */
3146 static void
3147f_escape(typval_T *argvars, typval_T *rettv)
3148{
3149 char_u buf[NUMBUFLEN];
3150
3151 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
3152 get_tv_string_buf(&argvars[1], buf));
3153 rettv->v_type = VAR_STRING;
3154}
3155
3156/*
3157 * "eval()" function
3158 */
3159 static void
3160f_eval(typval_T *argvars, typval_T *rettv)
3161{
3162 char_u *s, *p;
3163
3164 s = get_tv_string_chk(&argvars[0]);
3165 if (s != NULL)
3166 s = skipwhite(s);
3167
3168 p = s;
3169 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3170 {
3171 if (p != NULL && !aborting())
3172 EMSG2(_(e_invexpr2), p);
3173 need_clr_eos = FALSE;
3174 rettv->v_type = VAR_NUMBER;
3175 rettv->vval.v_number = 0;
3176 }
3177 else if (*s != NUL)
3178 EMSG(_(e_trailing));
3179}
3180
3181/*
3182 * "eventhandler()" function
3183 */
3184 static void
3185f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3186{
3187 rettv->vval.v_number = vgetc_busy;
3188}
3189
3190/*
3191 * "executable()" function
3192 */
3193 static void
3194f_executable(typval_T *argvars, typval_T *rettv)
3195{
3196 char_u *name = get_tv_string(&argvars[0]);
3197
3198 /* Check in $PATH and also check directly if there is a directory name. */
3199 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3200 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3201}
3202
3203static garray_T redir_execute_ga;
3204
3205/*
3206 * Append "value[value_len]" to the execute() output.
3207 */
3208 void
3209execute_redir_str(char_u *value, int value_len)
3210{
3211 int len;
3212
3213 if (value_len == -1)
3214 len = (int)STRLEN(value); /* Append the entire string */
3215 else
3216 len = value_len; /* Append only "value_len" characters */
3217 if (ga_grow(&redir_execute_ga, len) == OK)
3218 {
3219 mch_memmove((char *)redir_execute_ga.ga_data
3220 + redir_execute_ga.ga_len, value, len);
3221 redir_execute_ga.ga_len += len;
3222 }
3223}
3224
3225/*
3226 * Get next line from a list.
3227 * Called by do_cmdline() to get the next line.
3228 * Returns allocated string, or NULL for end of function.
3229 */
3230
3231 static char_u *
3232get_list_line(
3233 int c UNUSED,
3234 void *cookie,
3235 int indent UNUSED)
3236{
3237 listitem_T **p = (listitem_T **)cookie;
3238 listitem_T *item = *p;
3239 char_u buf[NUMBUFLEN];
3240 char_u *s;
3241
3242 if (item == NULL)
3243 return NULL;
3244 s = get_tv_string_buf_chk(&item->li_tv, buf);
3245 *p = item->li_next;
3246 return s == NULL ? NULL : vim_strsave(s);
3247}
3248
3249/*
3250 * "execute()" function
3251 */
3252 static void
3253f_execute(typval_T *argvars, typval_T *rettv)
3254{
3255 char_u *cmd = NULL;
3256 list_T *list = NULL;
3257 int save_msg_silent = msg_silent;
3258 int save_emsg_silent = emsg_silent;
3259 int save_emsg_noredir = emsg_noredir;
3260 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003261 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003262 garray_T save_ga;
3263
3264 rettv->vval.v_string = NULL;
3265 rettv->v_type = VAR_STRING;
3266
3267 if (argvars[0].v_type == VAR_LIST)
3268 {
3269 list = argvars[0].vval.v_list;
3270 if (list == NULL || list->lv_first == NULL)
3271 /* empty list, no commands, empty output */
3272 return;
3273 ++list->lv_refcount;
3274 }
3275 else
3276 {
3277 cmd = get_tv_string_chk(&argvars[0]);
3278 if (cmd == NULL)
3279 return;
3280 }
3281
3282 if (argvars[1].v_type != VAR_UNKNOWN)
3283 {
3284 char_u buf[NUMBUFLEN];
3285 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
3286
3287 if (s == NULL)
3288 return;
3289 if (STRNCMP(s, "silent", 6) == 0)
3290 ++msg_silent;
3291 if (STRCMP(s, "silent!") == 0)
3292 {
3293 emsg_silent = TRUE;
3294 emsg_noredir = TRUE;
3295 }
3296 }
3297 else
3298 ++msg_silent;
3299
3300 if (redir_execute)
3301 save_ga = redir_execute_ga;
3302 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3303 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003304 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003305
3306 if (cmd != NULL)
3307 do_cmdline_cmd(cmd);
3308 else
3309 {
3310 listitem_T *item = list->lv_first;
3311
3312 do_cmdline(NULL, get_list_line, (void *)&item,
3313 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3314 --list->lv_refcount;
3315 }
3316
Bram Moolenaard297f352017-01-29 20:31:21 +01003317 /* Need to append a NUL to the result. */
3318 if (ga_grow(&redir_execute_ga, 1) == OK)
3319 {
3320 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3321 rettv->vval.v_string = redir_execute_ga.ga_data;
3322 }
3323 else
3324 {
3325 ga_clear(&redir_execute_ga);
3326 rettv->vval.v_string = NULL;
3327 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003328 msg_silent = save_msg_silent;
3329 emsg_silent = save_emsg_silent;
3330 emsg_noredir = save_emsg_noredir;
3331
3332 redir_execute = save_redir_execute;
3333 if (redir_execute)
3334 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003335 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003336
3337 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3338 * line. Put it back in the first column. */
3339 msg_col = 0;
3340}
3341
3342/*
3343 * "exepath()" function
3344 */
3345 static void
3346f_exepath(typval_T *argvars, typval_T *rettv)
3347{
3348 char_u *p = NULL;
3349
3350 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3351 rettv->v_type = VAR_STRING;
3352 rettv->vval.v_string = p;
3353}
3354
3355/*
3356 * "exists()" function
3357 */
3358 static void
3359f_exists(typval_T *argvars, typval_T *rettv)
3360{
3361 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003362 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003363
3364 p = get_tv_string(&argvars[0]);
3365 if (*p == '$') /* environment variable */
3366 {
3367 /* first try "normal" environment variables (fast) */
3368 if (mch_getenv(p + 1) != NULL)
3369 n = TRUE;
3370 else
3371 {
3372 /* try expanding things like $VIM and ${HOME} */
3373 p = expand_env_save(p);
3374 if (p != NULL && *p != '$')
3375 n = TRUE;
3376 vim_free(p);
3377 }
3378 }
3379 else if (*p == '&' || *p == '+') /* option */
3380 {
3381 n = (get_option_tv(&p, NULL, TRUE) == OK);
3382 if (*skipwhite(p) != NUL)
3383 n = FALSE; /* trailing garbage */
3384 }
3385 else if (*p == '*') /* internal or user defined function */
3386 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003387 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003388 }
3389 else if (*p == ':')
3390 {
3391 n = cmd_exists(p + 1);
3392 }
3393 else if (*p == '#')
3394 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 if (p[1] == '#')
3396 n = autocmd_supported(p + 2);
3397 else
3398 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003399 }
3400 else /* internal variable */
3401 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003402 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403 }
3404
3405 rettv->vval.v_number = n;
3406}
3407
3408#ifdef FEAT_FLOAT
3409/*
3410 * "exp()" function
3411 */
3412 static void
3413f_exp(typval_T *argvars, typval_T *rettv)
3414{
3415 float_T f = 0.0;
3416
3417 rettv->v_type = VAR_FLOAT;
3418 if (get_float_arg(argvars, &f) == OK)
3419 rettv->vval.v_float = exp(f);
3420 else
3421 rettv->vval.v_float = 0.0;
3422}
3423#endif
3424
3425/*
3426 * "expand()" function
3427 */
3428 static void
3429f_expand(typval_T *argvars, typval_T *rettv)
3430{
3431 char_u *s;
3432 int len;
3433 char_u *errormsg;
3434 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3435 expand_T xpc;
3436 int error = FALSE;
3437 char_u *result;
3438
3439 rettv->v_type = VAR_STRING;
3440 if (argvars[1].v_type != VAR_UNKNOWN
3441 && argvars[2].v_type != VAR_UNKNOWN
3442 && get_tv_number_chk(&argvars[2], &error)
3443 && !error)
3444 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003445 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003446 }
3447
3448 s = get_tv_string(&argvars[0]);
3449 if (*s == '%' || *s == '#' || *s == '<')
3450 {
3451 ++emsg_off;
3452 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3453 --emsg_off;
3454 if (rettv->v_type == VAR_LIST)
3455 {
3456 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3457 list_append_string(rettv->vval.v_list, result, -1);
3458 else
3459 vim_free(result);
3460 }
3461 else
3462 rettv->vval.v_string = result;
3463 }
3464 else
3465 {
3466 /* When the optional second argument is non-zero, don't remove matches
3467 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3468 if (argvars[1].v_type != VAR_UNKNOWN
3469 && get_tv_number_chk(&argvars[1], &error))
3470 options |= WILD_KEEP_ALL;
3471 if (!error)
3472 {
3473 ExpandInit(&xpc);
3474 xpc.xp_context = EXPAND_FILES;
3475 if (p_wic)
3476 options += WILD_ICASE;
3477 if (rettv->v_type == VAR_STRING)
3478 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3479 options, WILD_ALL);
3480 else if (rettv_list_alloc(rettv) != FAIL)
3481 {
3482 int i;
3483
3484 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3485 for (i = 0; i < xpc.xp_numfiles; i++)
3486 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3487 ExpandCleanup(&xpc);
3488 }
3489 }
3490 else
3491 rettv->vval.v_string = NULL;
3492 }
3493}
3494
3495/*
3496 * "extend(list, list [, idx])" function
3497 * "extend(dict, dict [, action])" function
3498 */
3499 static void
3500f_extend(typval_T *argvars, typval_T *rettv)
3501{
3502 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3503
3504 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3505 {
3506 list_T *l1, *l2;
3507 listitem_T *item;
3508 long before;
3509 int error = FALSE;
3510
3511 l1 = argvars[0].vval.v_list;
3512 l2 = argvars[1].vval.v_list;
3513 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3514 && l2 != NULL)
3515 {
3516 if (argvars[2].v_type != VAR_UNKNOWN)
3517 {
3518 before = (long)get_tv_number_chk(&argvars[2], &error);
3519 if (error)
3520 return; /* type error; errmsg already given */
3521
3522 if (before == l1->lv_len)
3523 item = NULL;
3524 else
3525 {
3526 item = list_find(l1, before);
3527 if (item == NULL)
3528 {
3529 EMSGN(_(e_listidx), before);
3530 return;
3531 }
3532 }
3533 }
3534 else
3535 item = NULL;
3536 list_extend(l1, l2, item);
3537
3538 copy_tv(&argvars[0], rettv);
3539 }
3540 }
3541 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3542 {
3543 dict_T *d1, *d2;
3544 char_u *action;
3545 int i;
3546
3547 d1 = argvars[0].vval.v_dict;
3548 d2 = argvars[1].vval.v_dict;
3549 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3550 && d2 != NULL)
3551 {
3552 /* Check the third argument. */
3553 if (argvars[2].v_type != VAR_UNKNOWN)
3554 {
3555 static char *(av[]) = {"keep", "force", "error"};
3556
3557 action = get_tv_string_chk(&argvars[2]);
3558 if (action == NULL)
3559 return; /* type error; errmsg already given */
3560 for (i = 0; i < 3; ++i)
3561 if (STRCMP(action, av[i]) == 0)
3562 break;
3563 if (i == 3)
3564 {
3565 EMSG2(_(e_invarg2), action);
3566 return;
3567 }
3568 }
3569 else
3570 action = (char_u *)"force";
3571
3572 dict_extend(d1, d2, action);
3573
3574 copy_tv(&argvars[0], rettv);
3575 }
3576 }
3577 else
3578 EMSG2(_(e_listdictarg), "extend()");
3579}
3580
3581/*
3582 * "feedkeys()" function
3583 */
3584 static void
3585f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3586{
3587 int remap = TRUE;
3588 int insert = FALSE;
3589 char_u *keys, *flags;
3590 char_u nbuf[NUMBUFLEN];
3591 int typed = FALSE;
3592 int execute = FALSE;
3593 int dangerous = FALSE;
3594 char_u *keys_esc;
3595
3596 /* This is not allowed in the sandbox. If the commands would still be
3597 * executed in the sandbox it would be OK, but it probably happens later,
3598 * when "sandbox" is no longer set. */
3599 if (check_secure())
3600 return;
3601
3602 keys = get_tv_string(&argvars[0]);
3603
3604 if (argvars[1].v_type != VAR_UNKNOWN)
3605 {
3606 flags = get_tv_string_buf(&argvars[1], nbuf);
3607 for ( ; *flags != NUL; ++flags)
3608 {
3609 switch (*flags)
3610 {
3611 case 'n': remap = FALSE; break;
3612 case 'm': remap = TRUE; break;
3613 case 't': typed = TRUE; break;
3614 case 'i': insert = TRUE; break;
3615 case 'x': execute = TRUE; break;
3616 case '!': dangerous = TRUE; break;
3617 }
3618 }
3619 }
3620
3621 if (*keys != NUL || execute)
3622 {
3623 /* Need to escape K_SPECIAL and CSI before putting the string in the
3624 * typeahead buffer. */
3625 keys_esc = vim_strsave_escape_csi(keys);
3626 if (keys_esc != NULL)
3627 {
3628 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3629 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3630 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003631 if (vgetc_busy
3632#ifdef FEAT_TIMERS
3633 || timer_busy
3634#endif
3635 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636 typebuf_was_filled = TRUE;
3637 if (execute)
3638 {
3639 int save_msg_scroll = msg_scroll;
3640
3641 /* Avoid a 1 second delay when the keys start Insert mode. */
3642 msg_scroll = FALSE;
3643
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003644 if (!dangerous)
3645 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003646 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003647 if (!dangerous)
3648 --ex_normal_busy;
3649
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003650 msg_scroll |= save_msg_scroll;
3651 }
3652 }
3653 }
3654}
3655
3656/*
3657 * "filereadable()" function
3658 */
3659 static void
3660f_filereadable(typval_T *argvars, typval_T *rettv)
3661{
3662 int fd;
3663 char_u *p;
3664 int n;
3665
3666#ifndef O_NONBLOCK
3667# define O_NONBLOCK 0
3668#endif
3669 p = get_tv_string(&argvars[0]);
3670 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3671 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3672 {
3673 n = TRUE;
3674 close(fd);
3675 }
3676 else
3677 n = FALSE;
3678
3679 rettv->vval.v_number = n;
3680}
3681
3682/*
3683 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3684 * rights to write into.
3685 */
3686 static void
3687f_filewritable(typval_T *argvars, typval_T *rettv)
3688{
3689 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3690}
3691
3692 static void
3693findfilendir(
3694 typval_T *argvars UNUSED,
3695 typval_T *rettv,
3696 int find_what UNUSED)
3697{
3698#ifdef FEAT_SEARCHPATH
3699 char_u *fname;
3700 char_u *fresult = NULL;
3701 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3702 char_u *p;
3703 char_u pathbuf[NUMBUFLEN];
3704 int count = 1;
3705 int first = TRUE;
3706 int error = FALSE;
3707#endif
3708
3709 rettv->vval.v_string = NULL;
3710 rettv->v_type = VAR_STRING;
3711
3712#ifdef FEAT_SEARCHPATH
3713 fname = get_tv_string(&argvars[0]);
3714
3715 if (argvars[1].v_type != VAR_UNKNOWN)
3716 {
3717 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3718 if (p == NULL)
3719 error = TRUE;
3720 else
3721 {
3722 if (*p != NUL)
3723 path = p;
3724
3725 if (argvars[2].v_type != VAR_UNKNOWN)
3726 count = (int)get_tv_number_chk(&argvars[2], &error);
3727 }
3728 }
3729
3730 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3731 error = TRUE;
3732
3733 if (*fname != NUL && !error)
3734 {
3735 do
3736 {
3737 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3738 vim_free(fresult);
3739 fresult = find_file_in_path_option(first ? fname : NULL,
3740 first ? (int)STRLEN(fname) : 0,
3741 0, first, path,
3742 find_what,
3743 curbuf->b_ffname,
3744 find_what == FINDFILE_DIR
3745 ? (char_u *)"" : curbuf->b_p_sua);
3746 first = FALSE;
3747
3748 if (fresult != NULL && rettv->v_type == VAR_LIST)
3749 list_append_string(rettv->vval.v_list, fresult, -1);
3750
3751 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3752 }
3753
3754 if (rettv->v_type == VAR_STRING)
3755 rettv->vval.v_string = fresult;
3756#endif
3757}
3758
3759/*
3760 * "filter()" function
3761 */
3762 static void
3763f_filter(typval_T *argvars, typval_T *rettv)
3764{
3765 filter_map(argvars, rettv, FALSE);
3766}
3767
3768/*
3769 * "finddir({fname}[, {path}[, {count}]])" function
3770 */
3771 static void
3772f_finddir(typval_T *argvars, typval_T *rettv)
3773{
3774 findfilendir(argvars, rettv, FINDFILE_DIR);
3775}
3776
3777/*
3778 * "findfile({fname}[, {path}[, {count}]])" function
3779 */
3780 static void
3781f_findfile(typval_T *argvars, typval_T *rettv)
3782{
3783 findfilendir(argvars, rettv, FINDFILE_FILE);
3784}
3785
3786#ifdef FEAT_FLOAT
3787/*
3788 * "float2nr({float})" function
3789 */
3790 static void
3791f_float2nr(typval_T *argvars, typval_T *rettv)
3792{
3793 float_T f = 0.0;
3794
3795 if (get_float_arg(argvars, &f) == OK)
3796 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003797 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003798 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003799 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003800 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003801 else
3802 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003803 }
3804}
3805
3806/*
3807 * "floor({float})" function
3808 */
3809 static void
3810f_floor(typval_T *argvars, typval_T *rettv)
3811{
3812 float_T f = 0.0;
3813
3814 rettv->v_type = VAR_FLOAT;
3815 if (get_float_arg(argvars, &f) == OK)
3816 rettv->vval.v_float = floor(f);
3817 else
3818 rettv->vval.v_float = 0.0;
3819}
3820
3821/*
3822 * "fmod()" function
3823 */
3824 static void
3825f_fmod(typval_T *argvars, typval_T *rettv)
3826{
3827 float_T fx = 0.0, fy = 0.0;
3828
3829 rettv->v_type = VAR_FLOAT;
3830 if (get_float_arg(argvars, &fx) == OK
3831 && get_float_arg(&argvars[1], &fy) == OK)
3832 rettv->vval.v_float = fmod(fx, fy);
3833 else
3834 rettv->vval.v_float = 0.0;
3835}
3836#endif
3837
3838/*
3839 * "fnameescape({string})" function
3840 */
3841 static void
3842f_fnameescape(typval_T *argvars, typval_T *rettv)
3843{
3844 rettv->vval.v_string = vim_strsave_fnameescape(
3845 get_tv_string(&argvars[0]), FALSE);
3846 rettv->v_type = VAR_STRING;
3847}
3848
3849/*
3850 * "fnamemodify({fname}, {mods})" function
3851 */
3852 static void
3853f_fnamemodify(typval_T *argvars, typval_T *rettv)
3854{
3855 char_u *fname;
3856 char_u *mods;
3857 int usedlen = 0;
3858 int len;
3859 char_u *fbuf = NULL;
3860 char_u buf[NUMBUFLEN];
3861
3862 fname = get_tv_string_chk(&argvars[0]);
3863 mods = get_tv_string_buf_chk(&argvars[1], buf);
3864 if (fname == NULL || mods == NULL)
3865 fname = NULL;
3866 else
3867 {
3868 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003869 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003870 }
3871
3872 rettv->v_type = VAR_STRING;
3873 if (fname == NULL)
3874 rettv->vval.v_string = NULL;
3875 else
3876 rettv->vval.v_string = vim_strnsave(fname, len);
3877 vim_free(fbuf);
3878}
3879
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003880/*
3881 * "foldclosed()" function
3882 */
3883 static void
3884foldclosed_both(
3885 typval_T *argvars UNUSED,
3886 typval_T *rettv,
3887 int end UNUSED)
3888{
3889#ifdef FEAT_FOLDING
3890 linenr_T lnum;
3891 linenr_T first, last;
3892
3893 lnum = get_tv_lnum(argvars);
3894 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3895 {
3896 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3897 {
3898 if (end)
3899 rettv->vval.v_number = (varnumber_T)last;
3900 else
3901 rettv->vval.v_number = (varnumber_T)first;
3902 return;
3903 }
3904 }
3905#endif
3906 rettv->vval.v_number = -1;
3907}
3908
3909/*
3910 * "foldclosed()" function
3911 */
3912 static void
3913f_foldclosed(typval_T *argvars, typval_T *rettv)
3914{
3915 foldclosed_both(argvars, rettv, FALSE);
3916}
3917
3918/*
3919 * "foldclosedend()" function
3920 */
3921 static void
3922f_foldclosedend(typval_T *argvars, typval_T *rettv)
3923{
3924 foldclosed_both(argvars, rettv, TRUE);
3925}
3926
3927/*
3928 * "foldlevel()" function
3929 */
3930 static void
3931f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3932{
3933#ifdef FEAT_FOLDING
3934 linenr_T lnum;
3935
3936 lnum = get_tv_lnum(argvars);
3937 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3938 rettv->vval.v_number = foldLevel(lnum);
3939#endif
3940}
3941
3942/*
3943 * "foldtext()" function
3944 */
3945 static void
3946f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3947{
3948#ifdef FEAT_FOLDING
3949 linenr_T foldstart;
3950 linenr_T foldend;
3951 char_u *dashes;
3952 linenr_T lnum;
3953 char_u *s;
3954 char_u *r;
3955 int len;
3956 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003957 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003958#endif
3959
3960 rettv->v_type = VAR_STRING;
3961 rettv->vval.v_string = NULL;
3962#ifdef FEAT_FOLDING
3963 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3964 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3965 dashes = get_vim_var_str(VV_FOLDDASHES);
3966 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3967 && dashes != NULL)
3968 {
3969 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003970 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003971 if (!linewhite(lnum))
3972 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003973
3974 /* Find interesting text in this line. */
3975 s = skipwhite(ml_get(lnum));
3976 /* skip C comment-start */
3977 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3978 {
3979 s = skipwhite(s + 2);
3980 if (*skipwhite(s) == NUL
3981 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3982 {
3983 s = skipwhite(ml_get(lnum + 1));
3984 if (*s == '*')
3985 s = skipwhite(s + 1);
3986 }
3987 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003988 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003989 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003990 r = alloc((unsigned)(STRLEN(txt)
3991 + STRLEN(dashes) /* for %s */
3992 + 20 /* for %3ld */
3993 + STRLEN(s))); /* concatenated */
3994 if (r != NULL)
3995 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003996 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003997 len = (int)STRLEN(r);
3998 STRCAT(r, s);
3999 /* remove 'foldmarker' and 'commentstring' */
4000 foldtext_cleanup(r + len);
4001 rettv->vval.v_string = r;
4002 }
4003 }
4004#endif
4005}
4006
4007/*
4008 * "foldtextresult(lnum)" function
4009 */
4010 static void
4011f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4012{
4013#ifdef FEAT_FOLDING
4014 linenr_T lnum;
4015 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004016 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004017 foldinfo_T foldinfo;
4018 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004019 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020#endif
4021
4022 rettv->v_type = VAR_STRING;
4023 rettv->vval.v_string = NULL;
4024#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004025 if (entered)
4026 return; /* reject recursive use */
4027 entered = TRUE;
4028
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004029 lnum = get_tv_lnum(argvars);
4030 /* treat illegal types and illegal string values for {lnum} the same */
4031 if (lnum < 0)
4032 lnum = 0;
4033 fold_count = foldedCount(curwin, lnum, &foldinfo);
4034 if (fold_count > 0)
4035 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004036 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4037 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004038 if (text == buf)
4039 text = vim_strsave(text);
4040 rettv->vval.v_string = text;
4041 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004042
4043 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044#endif
4045}
4046
4047/*
4048 * "foreground()" function
4049 */
4050 static void
4051f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4052{
4053#ifdef FEAT_GUI
4054 if (gui.in_use)
4055 gui_mch_set_foreground();
4056#else
4057# ifdef WIN32
4058 win32_set_foreground();
4059# endif
4060#endif
4061}
4062
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004063 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004064common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004065{
4066 char_u *s;
4067 char_u *name;
4068 int use_string = FALSE;
4069 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004070 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004071
4072 if (argvars[0].v_type == VAR_FUNC)
4073 {
4074 /* function(MyFunc, [arg], dict) */
4075 s = argvars[0].vval.v_string;
4076 }
4077 else if (argvars[0].v_type == VAR_PARTIAL
4078 && argvars[0].vval.v_partial != NULL)
4079 {
4080 /* function(dict.MyFunc, [arg]) */
4081 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004082 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004083 }
4084 else
4085 {
4086 /* function('MyFunc', [arg], dict) */
4087 s = get_tv_string(&argvars[0]);
4088 use_string = TRUE;
4089 }
4090
Bram Moolenaar843b8842016-08-21 14:36:15 +02004091 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004092 {
4093 name = s;
4094 trans_name = trans_function_name(&name, FALSE,
4095 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4096 if (*name != NUL)
4097 s = NULL;
4098 }
4099
Bram Moolenaar843b8842016-08-21 14:36:15 +02004100 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4101 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02004102 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004103 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004104 else if (trans_name != NULL && (is_funcref
4105 ? find_func(trans_name) == NULL
4106 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107 EMSG2(_("E700: Unknown function: %s"), s);
4108 else
4109 {
4110 int dict_idx = 0;
4111 int arg_idx = 0;
4112 list_T *list = NULL;
4113
4114 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4115 {
4116 char sid_buf[25];
4117 int off = *s == 's' ? 2 : 5;
4118
4119 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4120 * also be called from another script. Using trans_function_name()
4121 * would also work, but some plugins depend on the name being
4122 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004123 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004124 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4125 if (name != NULL)
4126 {
4127 STRCPY(name, sid_buf);
4128 STRCAT(name, s + off);
4129 }
4130 }
4131 else
4132 name = vim_strsave(s);
4133
4134 if (argvars[1].v_type != VAR_UNKNOWN)
4135 {
4136 if (argvars[2].v_type != VAR_UNKNOWN)
4137 {
4138 /* function(name, [args], dict) */
4139 arg_idx = 1;
4140 dict_idx = 2;
4141 }
4142 else if (argvars[1].v_type == VAR_DICT)
4143 /* function(name, dict) */
4144 dict_idx = 1;
4145 else
4146 /* function(name, [args]) */
4147 arg_idx = 1;
4148 if (dict_idx > 0)
4149 {
4150 if (argvars[dict_idx].v_type != VAR_DICT)
4151 {
4152 EMSG(_("E922: expected a dict"));
4153 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004154 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004155 }
4156 if (argvars[dict_idx].vval.v_dict == NULL)
4157 dict_idx = 0;
4158 }
4159 if (arg_idx > 0)
4160 {
4161 if (argvars[arg_idx].v_type != VAR_LIST)
4162 {
4163 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4164 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004165 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004166 }
4167 list = argvars[arg_idx].vval.v_list;
4168 if (list == NULL || list->lv_len == 0)
4169 arg_idx = 0;
4170 }
4171 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004172 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004173 {
4174 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4175
4176 /* result is a VAR_PARTIAL */
4177 if (pt == NULL)
4178 vim_free(name);
4179 else
4180 {
4181 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4182 {
4183 listitem_T *li;
4184 int i = 0;
4185 int arg_len = 0;
4186 int lv_len = 0;
4187
4188 if (arg_pt != NULL)
4189 arg_len = arg_pt->pt_argc;
4190 if (list != NULL)
4191 lv_len = list->lv_len;
4192 pt->pt_argc = arg_len + lv_len;
4193 pt->pt_argv = (typval_T *)alloc(
4194 sizeof(typval_T) * pt->pt_argc);
4195 if (pt->pt_argv == NULL)
4196 {
4197 vim_free(pt);
4198 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004199 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004200 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004201 for (i = 0; i < arg_len; i++)
4202 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4203 if (lv_len > 0)
4204 for (li = list->lv_first; li != NULL;
4205 li = li->li_next)
4206 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004207 }
4208
4209 /* For "function(dict.func, [], dict)" and "func" is a partial
4210 * use "dict". That is backwards compatible. */
4211 if (dict_idx > 0)
4212 {
4213 /* The dict is bound explicitly, pt_auto is FALSE. */
4214 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4215 ++pt->pt_dict->dv_refcount;
4216 }
4217 else if (arg_pt != NULL)
4218 {
4219 /* If the dict was bound automatically the result is also
4220 * bound automatically. */
4221 pt->pt_dict = arg_pt->pt_dict;
4222 pt->pt_auto = arg_pt->pt_auto;
4223 if (pt->pt_dict != NULL)
4224 ++pt->pt_dict->dv_refcount;
4225 }
4226
4227 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004228 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4229 {
4230 pt->pt_func = arg_pt->pt_func;
4231 func_ptr_ref(pt->pt_func);
4232 vim_free(name);
4233 }
4234 else if (is_funcref)
4235 {
4236 pt->pt_func = find_func(trans_name);
4237 func_ptr_ref(pt->pt_func);
4238 vim_free(name);
4239 }
4240 else
4241 {
4242 pt->pt_name = name;
4243 func_ref(name);
4244 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004245 }
4246 rettv->v_type = VAR_PARTIAL;
4247 rettv->vval.v_partial = pt;
4248 }
4249 else
4250 {
4251 /* result is a VAR_FUNC */
4252 rettv->v_type = VAR_FUNC;
4253 rettv->vval.v_string = name;
4254 func_ref(name);
4255 }
4256 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004257theend:
4258 vim_free(trans_name);
4259}
4260
4261/*
4262 * "funcref()" function
4263 */
4264 static void
4265f_funcref(typval_T *argvars, typval_T *rettv)
4266{
4267 common_function(argvars, rettv, TRUE);
4268}
4269
4270/*
4271 * "function()" function
4272 */
4273 static void
4274f_function(typval_T *argvars, typval_T *rettv)
4275{
4276 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004277}
4278
4279/*
4280 * "garbagecollect()" function
4281 */
4282 static void
4283f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4284{
4285 /* This is postponed until we are back at the toplevel, because we may be
4286 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4287 want_garbage_collect = TRUE;
4288
4289 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
4290 garbage_collect_at_exit = TRUE;
4291}
4292
4293/*
4294 * "get()" function
4295 */
4296 static void
4297f_get(typval_T *argvars, typval_T *rettv)
4298{
4299 listitem_T *li;
4300 list_T *l;
4301 dictitem_T *di;
4302 dict_T *d;
4303 typval_T *tv = NULL;
4304
4305 if (argvars[0].v_type == VAR_LIST)
4306 {
4307 if ((l = argvars[0].vval.v_list) != NULL)
4308 {
4309 int error = FALSE;
4310
4311 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
4312 if (!error && li != NULL)
4313 tv = &li->li_tv;
4314 }
4315 }
4316 else if (argvars[0].v_type == VAR_DICT)
4317 {
4318 if ((d = argvars[0].vval.v_dict) != NULL)
4319 {
4320 di = dict_find(d, get_tv_string(&argvars[1]), -1);
4321 if (di != NULL)
4322 tv = &di->di_tv;
4323 }
4324 }
4325 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4326 {
4327 partial_T *pt;
4328 partial_T fref_pt;
4329
4330 if (argvars[0].v_type == VAR_PARTIAL)
4331 pt = argvars[0].vval.v_partial;
4332 else
4333 {
4334 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4335 fref_pt.pt_name = argvars[0].vval.v_string;
4336 pt = &fref_pt;
4337 }
4338
4339 if (pt != NULL)
4340 {
4341 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004342 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004343
4344 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4345 {
4346 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004347 n = partial_name(pt);
4348 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004349 rettv->vval.v_string = NULL;
4350 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004351 {
4352 rettv->vval.v_string = vim_strsave(n);
4353 if (rettv->v_type == VAR_FUNC)
4354 func_ref(rettv->vval.v_string);
4355 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004356 }
4357 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004358 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004359 else if (STRCMP(what, "args") == 0)
4360 {
4361 rettv->v_type = VAR_LIST;
4362 if (rettv_list_alloc(rettv) == OK)
4363 {
4364 int i;
4365
4366 for (i = 0; i < pt->pt_argc; ++i)
4367 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4368 }
4369 }
4370 else
4371 EMSG2(_(e_invarg2), what);
4372 return;
4373 }
4374 }
4375 else
4376 EMSG2(_(e_listdictarg), "get()");
4377
4378 if (tv == NULL)
4379 {
4380 if (argvars[2].v_type != VAR_UNKNOWN)
4381 copy_tv(&argvars[2], rettv);
4382 }
4383 else
4384 copy_tv(tv, rettv);
4385}
4386
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004387#ifdef FEAT_SIGNS
4388/*
4389 * Returns information about signs placed in a buffer as list of dicts.
4390 */
4391 static void
4392get_buffer_signs(buf_T *buf, list_T *l)
4393{
4394 signlist_T *sign;
4395
4396 for (sign = buf->b_signlist; sign; sign = sign->next)
4397 {
4398 dict_T *d = dict_alloc();
4399
4400 if (d != NULL)
4401 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02004402 dict_add_number(d, "id", sign->id);
4403 dict_add_number(d, "lnum", sign->lnum);
4404 dict_add_string(d, "name", sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004405
4406 list_append_dict(l, d);
4407 }
4408 }
4409}
4410#endif
4411
4412/*
4413 * Returns buffer options, variables and other attributes in a dictionary.
4414 */
4415 static dict_T *
4416get_buffer_info(buf_T *buf)
4417{
4418 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004419 tabpage_T *tp;
4420 win_T *wp;
4421 list_T *windows;
4422
4423 dict = dict_alloc();
4424 if (dict == NULL)
4425 return NULL;
4426
Bram Moolenaare0be1672018-07-08 16:50:37 +02004427 dict_add_number(dict, "bufnr", buf->b_fnum);
4428 dict_add_string(dict, "name", buf->b_ffname);
4429 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4430 : buflist_findlnum(buf));
4431 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4432 dict_add_number(dict, "listed", buf->b_p_bl);
4433 dict_add_number(dict, "changed", bufIsChanged(buf));
4434 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4435 dict_add_number(dict, "hidden",
4436 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004437
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004438 /* Get a reference to buffer variables */
4439 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004440
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004441 /* List of windows displaying this buffer */
4442 windows = list_alloc();
4443 if (windows != NULL)
4444 {
4445 FOR_ALL_TAB_WINDOWS(tp, wp)
4446 if (wp->w_buffer == buf)
4447 list_append_number(windows, (varnumber_T)wp->w_id);
4448 dict_add_list(dict, "windows", windows);
4449 }
4450
4451#ifdef FEAT_SIGNS
4452 if (buf->b_signlist != NULL)
4453 {
4454 /* List of signs placed in this buffer */
4455 list_T *signs = list_alloc();
4456 if (signs != NULL)
4457 {
4458 get_buffer_signs(buf, signs);
4459 dict_add_list(dict, "signs", signs);
4460 }
4461 }
4462#endif
4463
4464 return dict;
4465}
4466
4467/*
4468 * "getbufinfo()" function
4469 */
4470 static void
4471f_getbufinfo(typval_T *argvars, typval_T *rettv)
4472{
4473 buf_T *buf = NULL;
4474 buf_T *argbuf = NULL;
4475 dict_T *d;
4476 int filtered = FALSE;
4477 int sel_buflisted = FALSE;
4478 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004479 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004480
4481 if (rettv_list_alloc(rettv) != OK)
4482 return;
4483
4484 /* List of all the buffers or selected buffers */
4485 if (argvars[0].v_type == VAR_DICT)
4486 {
4487 dict_T *sel_d = argvars[0].vval.v_dict;
4488
4489 if (sel_d != NULL)
4490 {
4491 dictitem_T *di;
4492
4493 filtered = TRUE;
4494
4495 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4496 if (di != NULL && get_tv_number(&di->di_tv))
4497 sel_buflisted = TRUE;
4498
4499 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4500 if (di != NULL && get_tv_number(&di->di_tv))
4501 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004502
4503 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4504 if (di != NULL && get_tv_number(&di->di_tv))
4505 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004506 }
4507 }
4508 else if (argvars[0].v_type != VAR_UNKNOWN)
4509 {
4510 /* Information about one buffer. Argument specifies the buffer */
4511 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4512 ++emsg_off;
4513 argbuf = get_buf_tv(&argvars[0], FALSE);
4514 --emsg_off;
4515 if (argbuf == NULL)
4516 return;
4517 }
4518
4519 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004520 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004521 {
4522 if (argbuf != NULL && argbuf != buf)
4523 continue;
4524 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004525 || (sel_buflisted && !buf->b_p_bl)
4526 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004527 continue;
4528
4529 d = get_buffer_info(buf);
4530 if (d != NULL)
4531 list_append_dict(rettv->vval.v_list, d);
4532 if (argbuf != NULL)
4533 return;
4534 }
4535}
4536
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004537/*
4538 * Get line or list of lines from buffer "buf" into "rettv".
4539 * Return a range (from start to end) of lines in rettv from the specified
4540 * buffer.
4541 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4542 */
4543 static void
4544get_buffer_lines(
4545 buf_T *buf,
4546 linenr_T start,
4547 linenr_T end,
4548 int retlist,
4549 typval_T *rettv)
4550{
4551 char_u *p;
4552
4553 rettv->v_type = VAR_STRING;
4554 rettv->vval.v_string = NULL;
4555 if (retlist && rettv_list_alloc(rettv) == FAIL)
4556 return;
4557
4558 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4559 return;
4560
4561 if (!retlist)
4562 {
4563 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4564 p = ml_get_buf(buf, start, FALSE);
4565 else
4566 p = (char_u *)"";
4567 rettv->vval.v_string = vim_strsave(p);
4568 }
4569 else
4570 {
4571 if (end < start)
4572 return;
4573
4574 if (start < 1)
4575 start = 1;
4576 if (end > buf->b_ml.ml_line_count)
4577 end = buf->b_ml.ml_line_count;
4578 while (start <= end)
4579 if (list_append_string(rettv->vval.v_list,
4580 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4581 break;
4582 }
4583}
4584
4585/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004586 * "getbufline()" function
4587 */
4588 static void
4589f_getbufline(typval_T *argvars, typval_T *rettv)
4590{
4591 linenr_T lnum;
4592 linenr_T end;
4593 buf_T *buf;
4594
4595 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4596 ++emsg_off;
4597 buf = get_buf_tv(&argvars[0], FALSE);
4598 --emsg_off;
4599
4600 lnum = get_tv_lnum_buf(&argvars[1], buf);
4601 if (argvars[2].v_type == VAR_UNKNOWN)
4602 end = lnum;
4603 else
4604 end = get_tv_lnum_buf(&argvars[2], buf);
4605
4606 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4607}
4608
4609/*
4610 * "getbufvar()" function
4611 */
4612 static void
4613f_getbufvar(typval_T *argvars, typval_T *rettv)
4614{
4615 buf_T *buf;
4616 buf_T *save_curbuf;
4617 char_u *varname;
4618 dictitem_T *v;
4619 int done = FALSE;
4620
4621 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4622 varname = get_tv_string_chk(&argvars[1]);
4623 ++emsg_off;
4624 buf = get_buf_tv(&argvars[0], FALSE);
4625
4626 rettv->v_type = VAR_STRING;
4627 rettv->vval.v_string = NULL;
4628
4629 if (buf != NULL && varname != NULL)
4630 {
4631 /* set curbuf to be our buf, temporarily */
4632 save_curbuf = curbuf;
4633 curbuf = buf;
4634
Bram Moolenaar30567352016-08-27 21:25:44 +02004635 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004636 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004637 if (varname[1] == NUL)
4638 {
4639 /* get all buffer-local options in a dict */
4640 dict_T *opts = get_winbuf_options(TRUE);
4641
4642 if (opts != NULL)
4643 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004644 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004645 done = TRUE;
4646 }
4647 }
4648 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4649 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004650 done = TRUE;
4651 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004652 else
4653 {
4654 /* Look up the variable. */
4655 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4656 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4657 'b', varname, FALSE);
4658 if (v != NULL)
4659 {
4660 copy_tv(&v->di_tv, rettv);
4661 done = TRUE;
4662 }
4663 }
4664
4665 /* restore previous notion of curbuf */
4666 curbuf = save_curbuf;
4667 }
4668
4669 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4670 /* use the default value */
4671 copy_tv(&argvars[2], rettv);
4672
4673 --emsg_off;
4674}
4675
4676/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004677 * "getchangelist()" function
4678 */
4679 static void
4680f_getchangelist(typval_T *argvars, typval_T *rettv)
4681{
4682#ifdef FEAT_JUMPLIST
4683 buf_T *buf;
4684 int i;
4685 list_T *l;
4686 dict_T *d;
4687#endif
4688
4689 if (rettv_list_alloc(rettv) != OK)
4690 return;
4691
4692#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004693 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4694 ++emsg_off;
4695 buf = get_buf_tv(&argvars[0], FALSE);
4696 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004697 if (buf == NULL)
4698 return;
4699
4700 l = list_alloc();
4701 if (l == NULL)
4702 return;
4703
4704 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4705 return;
4706 /*
4707 * The current window change list index tracks only the position in the
4708 * current buffer change list. For other buffers, use the change list
4709 * length as the current index.
4710 */
4711 list_append_number(rettv->vval.v_list,
4712 (varnumber_T)((buf == curwin->w_buffer)
4713 ? curwin->w_changelistidx : buf->b_changelistlen));
4714
4715 for (i = 0; i < buf->b_changelistlen; ++i)
4716 {
4717 if (buf->b_changelist[i].lnum == 0)
4718 continue;
4719 if ((d = dict_alloc()) == NULL)
4720 return;
4721 if (list_append_dict(l, d) == FAIL)
4722 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004723 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4724 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004725# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02004726 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004727# endif
4728 }
4729#endif
4730}
4731/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732 * "getchar()" function
4733 */
4734 static void
4735f_getchar(typval_T *argvars, typval_T *rettv)
4736{
4737 varnumber_T n;
4738 int error = FALSE;
4739
Bram Moolenaar84d93902018-09-11 20:10:20 +02004740#ifdef MESSAGE_QUEUE
4741 // vpeekc() used to check for messages, but that caused problems, invoking
4742 // a callback where it was not expected. Some plugins use getchar(1) in a
4743 // loop to await a message, therefore make sure we check for messages here.
4744 parse_queued_messages();
4745#endif
4746
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004747 /* Position the cursor. Needed after a message that ends in a space. */
4748 windgoto(msg_row, msg_col);
4749
4750 ++no_mapping;
4751 ++allow_keys;
4752 for (;;)
4753 {
4754 if (argvars[0].v_type == VAR_UNKNOWN)
4755 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004756 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004757 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4758 /* getchar(1): only check if char avail */
4759 n = vpeekc_any();
4760 else if (error || vpeekc_any() == NUL)
4761 /* illegal argument or getchar(0) and no char avail: return zero */
4762 n = 0;
4763 else
4764 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004765 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766
4767 if (n == K_IGNORE)
4768 continue;
4769 break;
4770 }
4771 --no_mapping;
4772 --allow_keys;
4773
4774 set_vim_var_nr(VV_MOUSE_WIN, 0);
4775 set_vim_var_nr(VV_MOUSE_WINID, 0);
4776 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4777 set_vim_var_nr(VV_MOUSE_COL, 0);
4778
4779 rettv->vval.v_number = n;
4780 if (IS_SPECIAL(n) || mod_mask != 0)
4781 {
4782 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4783 int i = 0;
4784
4785 /* Turn a special key into three bytes, plus modifier. */
4786 if (mod_mask != 0)
4787 {
4788 temp[i++] = K_SPECIAL;
4789 temp[i++] = KS_MODIFIER;
4790 temp[i++] = mod_mask;
4791 }
4792 if (IS_SPECIAL(n))
4793 {
4794 temp[i++] = K_SPECIAL;
4795 temp[i++] = K_SECOND(n);
4796 temp[i++] = K_THIRD(n);
4797 }
4798#ifdef FEAT_MBYTE
4799 else if (has_mbyte)
4800 i += (*mb_char2bytes)(n, temp + i);
4801#endif
4802 else
4803 temp[i++] = n;
4804 temp[i++] = NUL;
4805 rettv->v_type = VAR_STRING;
4806 rettv->vval.v_string = vim_strsave(temp);
4807
4808#ifdef FEAT_MOUSE
4809 if (is_mouse_key(n))
4810 {
4811 int row = mouse_row;
4812 int col = mouse_col;
4813 win_T *win;
4814 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004816 int winnr = 1;
4817
4818 if (row >= 0 && col >= 0)
4819 {
4820 /* Find the window at the mouse coordinates and compute the
4821 * text position. */
4822 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004823 if (win == NULL)
4824 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004825 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004826 for (wp = firstwin; wp != win; wp = wp->w_next)
4827 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4829 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4830 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4831 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4832 }
4833 }
4834#endif
4835 }
4836}
4837
4838/*
4839 * "getcharmod()" function
4840 */
4841 static void
4842f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4843{
4844 rettv->vval.v_number = mod_mask;
4845}
4846
4847/*
4848 * "getcharsearch()" function
4849 */
4850 static void
4851f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4852{
4853 if (rettv_dict_alloc(rettv) != FAIL)
4854 {
4855 dict_T *dict = rettv->vval.v_dict;
4856
Bram Moolenaare0be1672018-07-08 16:50:37 +02004857 dict_add_string(dict, "char", last_csearch());
4858 dict_add_number(dict, "forward", last_csearch_forward());
4859 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004860 }
4861}
4862
4863/*
4864 * "getcmdline()" function
4865 */
4866 static void
4867f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4868{
4869 rettv->v_type = VAR_STRING;
4870 rettv->vval.v_string = get_cmdline_str();
4871}
4872
4873/*
4874 * "getcmdpos()" function
4875 */
4876 static void
4877f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4878{
4879 rettv->vval.v_number = get_cmdline_pos() + 1;
4880}
4881
4882/*
4883 * "getcmdtype()" function
4884 */
4885 static void
4886f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4887{
4888 rettv->v_type = VAR_STRING;
4889 rettv->vval.v_string = alloc(2);
4890 if (rettv->vval.v_string != NULL)
4891 {
4892 rettv->vval.v_string[0] = get_cmdline_type();
4893 rettv->vval.v_string[1] = NUL;
4894 }
4895}
4896
4897/*
4898 * "getcmdwintype()" function
4899 */
4900 static void
4901f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4902{
4903 rettv->v_type = VAR_STRING;
4904 rettv->vval.v_string = NULL;
4905#ifdef FEAT_CMDWIN
4906 rettv->vval.v_string = alloc(2);
4907 if (rettv->vval.v_string != NULL)
4908 {
4909 rettv->vval.v_string[0] = cmdwin_type;
4910 rettv->vval.v_string[1] = NUL;
4911 }
4912#endif
4913}
4914
4915#if defined(FEAT_CMDL_COMPL)
4916/*
4917 * "getcompletion()" function
4918 */
4919 static void
4920f_getcompletion(typval_T *argvars, typval_T *rettv)
4921{
4922 char_u *pat;
4923 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004924 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004925 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4926 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004927
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004928 if (argvars[2].v_type != VAR_UNKNOWN)
4929 filtered = get_tv_number_chk(&argvars[2], NULL);
4930
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931 if (p_wic)
4932 options |= WILD_ICASE;
4933
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004934 /* For filtered results, 'wildignore' is used */
4935 if (!filtered)
4936 options |= WILD_KEEP_ALL;
4937
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004938 ExpandInit(&xpc);
4939 xpc.xp_pattern = get_tv_string(&argvars[0]);
4940 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4941 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4942 if (xpc.xp_context == EXPAND_NOTHING)
4943 {
4944 if (argvars[1].v_type == VAR_STRING)
4945 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4946 else
4947 EMSG(_(e_invarg));
4948 return;
4949 }
4950
4951# if defined(FEAT_MENU)
4952 if (xpc.xp_context == EXPAND_MENUS)
4953 {
4954 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4955 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4956 }
4957# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004958#ifdef FEAT_CSCOPE
4959 if (xpc.xp_context == EXPAND_CSCOPE)
4960 {
4961 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4962 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4963 }
4964#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004965#ifdef FEAT_SIGNS
4966 if (xpc.xp_context == EXPAND_SIGN)
4967 {
4968 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4969 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4970 }
4971#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972
4973 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4974 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4975 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004976 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004977
4978 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4979
4980 for (i = 0; i < xpc.xp_numfiles; i++)
4981 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4982 }
4983 vim_free(pat);
4984 ExpandCleanup(&xpc);
4985}
4986#endif
4987
4988/*
4989 * "getcwd()" function
4990 */
4991 static void
4992f_getcwd(typval_T *argvars, typval_T *rettv)
4993{
4994 win_T *wp = NULL;
4995 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004996 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004997
4998 rettv->v_type = VAR_STRING;
4999 rettv->vval.v_string = NULL;
5000
Bram Moolenaar54591292018-02-09 20:53:59 +01005001 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5002 global = TRUE;
5003 else
5004 wp = find_tabwin(&argvars[0], &argvars[1]);
5005
5006 if (wp != NULL && wp->w_localdir != NULL)
5007 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5008 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005009 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005010 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005011 rettv->vval.v_string = vim_strsave(globaldir);
5012 else
5013 {
5014 cwd = alloc(MAXPATHL);
5015 if (cwd != NULL)
5016 {
5017 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5018 rettv->vval.v_string = vim_strsave(cwd);
5019 vim_free(cwd);
5020 }
5021 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005022 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005023#ifdef BACKSLASH_IN_FILENAME
5024 if (rettv->vval.v_string != NULL)
5025 slash_adjust(rettv->vval.v_string);
5026#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005027}
5028
5029/*
5030 * "getfontname()" function
5031 */
5032 static void
5033f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5034{
5035 rettv->v_type = VAR_STRING;
5036 rettv->vval.v_string = NULL;
5037#ifdef FEAT_GUI
5038 if (gui.in_use)
5039 {
5040 GuiFont font;
5041 char_u *name = NULL;
5042
5043 if (argvars[0].v_type == VAR_UNKNOWN)
5044 {
5045 /* Get the "Normal" font. Either the name saved by
5046 * hl_set_font_name() or from the font ID. */
5047 font = gui.norm_font;
5048 name = hl_get_font_name();
5049 }
5050 else
5051 {
5052 name = get_tv_string(&argvars[0]);
5053 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5054 return;
5055 font = gui_mch_get_font(name, FALSE);
5056 if (font == NOFONT)
5057 return; /* Invalid font name, return empty string. */
5058 }
5059 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5060 if (argvars[0].v_type != VAR_UNKNOWN)
5061 gui_mch_free_font(font);
5062 }
5063#endif
5064}
5065
5066/*
5067 * "getfperm({fname})" function
5068 */
5069 static void
5070f_getfperm(typval_T *argvars, typval_T *rettv)
5071{
5072 char_u *fname;
5073 stat_T st;
5074 char_u *perm = NULL;
5075 char_u flags[] = "rwx";
5076 int i;
5077
5078 fname = get_tv_string(&argvars[0]);
5079
5080 rettv->v_type = VAR_STRING;
5081 if (mch_stat((char *)fname, &st) >= 0)
5082 {
5083 perm = vim_strsave((char_u *)"---------");
5084 if (perm != NULL)
5085 {
5086 for (i = 0; i < 9; i++)
5087 {
5088 if (st.st_mode & (1 << (8 - i)))
5089 perm[i] = flags[i % 3];
5090 }
5091 }
5092 }
5093 rettv->vval.v_string = perm;
5094}
5095
5096/*
5097 * "getfsize({fname})" function
5098 */
5099 static void
5100f_getfsize(typval_T *argvars, typval_T *rettv)
5101{
5102 char_u *fname;
5103 stat_T st;
5104
5105 fname = get_tv_string(&argvars[0]);
5106
5107 rettv->v_type = VAR_NUMBER;
5108
5109 if (mch_stat((char *)fname, &st) >= 0)
5110 {
5111 if (mch_isdir(fname))
5112 rettv->vval.v_number = 0;
5113 else
5114 {
5115 rettv->vval.v_number = (varnumber_T)st.st_size;
5116
5117 /* non-perfect check for overflow */
5118 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5119 rettv->vval.v_number = -2;
5120 }
5121 }
5122 else
5123 rettv->vval.v_number = -1;
5124}
5125
5126/*
5127 * "getftime({fname})" function
5128 */
5129 static void
5130f_getftime(typval_T *argvars, typval_T *rettv)
5131{
5132 char_u *fname;
5133 stat_T st;
5134
5135 fname = get_tv_string(&argvars[0]);
5136
5137 if (mch_stat((char *)fname, &st) >= 0)
5138 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5139 else
5140 rettv->vval.v_number = -1;
5141}
5142
5143/*
5144 * "getftype({fname})" function
5145 */
5146 static void
5147f_getftype(typval_T *argvars, typval_T *rettv)
5148{
5149 char_u *fname;
5150 stat_T st;
5151 char_u *type = NULL;
5152 char *t;
5153
5154 fname = get_tv_string(&argvars[0]);
5155
5156 rettv->v_type = VAR_STRING;
5157 if (mch_lstat((char *)fname, &st) >= 0)
5158 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005159 if (S_ISREG(st.st_mode))
5160 t = "file";
5161 else if (S_ISDIR(st.st_mode))
5162 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005163 else if (S_ISLNK(st.st_mode))
5164 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005165 else if (S_ISBLK(st.st_mode))
5166 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005167 else if (S_ISCHR(st.st_mode))
5168 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005169 else if (S_ISFIFO(st.st_mode))
5170 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005172 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005173 else
5174 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005175 type = vim_strsave((char_u *)t);
5176 }
5177 rettv->vval.v_string = type;
5178}
5179
5180/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005181 * "getjumplist()" function
5182 */
5183 static void
5184f_getjumplist(typval_T *argvars, typval_T *rettv)
5185{
5186#ifdef FEAT_JUMPLIST
5187 win_T *wp;
5188 int i;
5189 list_T *l;
5190 dict_T *d;
5191#endif
5192
5193 if (rettv_list_alloc(rettv) != OK)
5194 return;
5195
5196#ifdef FEAT_JUMPLIST
5197 wp = find_tabwin(&argvars[0], &argvars[1]);
5198 if (wp == NULL)
5199 return;
5200
5201 l = list_alloc();
5202 if (l == NULL)
5203 return;
5204
5205 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5206 return;
5207 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5208
Bram Moolenaar48679742018-02-13 13:33:29 +01005209 cleanup_jumplist(wp, TRUE);
5210
Bram Moolenaar4f505882018-02-10 21:06:32 +01005211 for (i = 0; i < wp->w_jumplistlen; ++i)
5212 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005213 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5214 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005215 if ((d = dict_alloc()) == NULL)
5216 return;
5217 if (list_append_dict(l, d) == FAIL)
5218 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005219 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5220 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005221# ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +02005222 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005223# endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005224 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005225 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005226 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005227 }
5228#endif
5229}
5230
5231/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005232 * "getline(lnum, [end])" function
5233 */
5234 static void
5235f_getline(typval_T *argvars, typval_T *rettv)
5236{
5237 linenr_T lnum;
5238 linenr_T end;
5239 int retlist;
5240
5241 lnum = get_tv_lnum(argvars);
5242 if (argvars[1].v_type == VAR_UNKNOWN)
5243 {
5244 end = 0;
5245 retlist = FALSE;
5246 }
5247 else
5248 {
5249 end = get_tv_lnum(&argvars[1]);
5250 retlist = TRUE;
5251 }
5252
5253 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5254}
5255
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005256#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005257 static void
5258get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5259{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005260 if (what_arg->v_type == VAR_UNKNOWN)
5261 {
5262 if (rettv_list_alloc(rettv) == OK)
5263 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005264 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005265 }
5266 else
5267 {
5268 if (rettv_dict_alloc(rettv) == OK)
5269 if (is_qf || (wp != NULL))
5270 {
5271 if (what_arg->v_type == VAR_DICT)
5272 {
5273 dict_T *d = what_arg->vval.v_dict;
5274
5275 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005276 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005277 }
5278 else
5279 EMSG(_(e_dictreq));
5280 }
5281 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005282}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005283#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005284
5285/*
5286 * "getloclist()" function
5287 */
5288 static void
5289f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5290{
5291#ifdef FEAT_QUICKFIX
5292 win_T *wp;
5293
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005294 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005295 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5296#endif
5297}
5298
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005299/*
5300 * "getmatches()" function
5301 */
5302 static void
5303f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5304{
5305#ifdef FEAT_SEARCH_EXTRA
5306 dict_T *dict;
5307 matchitem_T *cur = curwin->w_match_head;
5308 int i;
5309
5310 if (rettv_list_alloc(rettv) == OK)
5311 {
5312 while (cur != NULL)
5313 {
5314 dict = dict_alloc();
5315 if (dict == NULL)
5316 return;
5317 if (cur->match.regprog == NULL)
5318 {
5319 /* match added with matchaddpos() */
5320 for (i = 0; i < MAXPOSMATCH; ++i)
5321 {
5322 llpos_T *llpos;
5323 char buf[6];
5324 list_T *l;
5325
5326 llpos = &cur->pos.pos[i];
5327 if (llpos->lnum == 0)
5328 break;
5329 l = list_alloc();
5330 if (l == NULL)
5331 break;
5332 list_append_number(l, (varnumber_T)llpos->lnum);
5333 if (llpos->col > 0)
5334 {
5335 list_append_number(l, (varnumber_T)llpos->col);
5336 list_append_number(l, (varnumber_T)llpos->len);
5337 }
5338 sprintf(buf, "pos%d", i + 1);
5339 dict_add_list(dict, buf, l);
5340 }
5341 }
5342 else
5343 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005344 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005345 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005346 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5347 dict_add_number(dict, "priority", (long)cur->priority);
5348 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005349# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5350 if (cur->conceal_char)
5351 {
5352 char_u buf[MB_MAXBYTES + 1];
5353
5354 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005355 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005356 }
5357# endif
5358 list_append_dict(rettv->vval.v_list, dict);
5359 cur = cur->next;
5360 }
5361 }
5362#endif
5363}
5364
5365/*
5366 * "getpid()" function
5367 */
5368 static void
5369f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5370{
5371 rettv->vval.v_number = mch_get_pid();
5372}
5373
5374 static void
5375getpos_both(
5376 typval_T *argvars,
5377 typval_T *rettv,
5378 int getcurpos)
5379{
5380 pos_T *fp;
5381 list_T *l;
5382 int fnum = -1;
5383
5384 if (rettv_list_alloc(rettv) == OK)
5385 {
5386 l = rettv->vval.v_list;
5387 if (getcurpos)
5388 fp = &curwin->w_cursor;
5389 else
5390 fp = var2fpos(&argvars[0], TRUE, &fnum);
5391 if (fnum != -1)
5392 list_append_number(l, (varnumber_T)fnum);
5393 else
5394 list_append_number(l, (varnumber_T)0);
5395 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5396 : (varnumber_T)0);
5397 list_append_number(l, (fp != NULL)
5398 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5399 : (varnumber_T)0);
5400 list_append_number(l,
5401#ifdef FEAT_VIRTUALEDIT
5402 (fp != NULL) ? (varnumber_T)fp->coladd :
5403#endif
5404 (varnumber_T)0);
5405 if (getcurpos)
5406 {
5407 update_curswant();
5408 list_append_number(l, curwin->w_curswant == MAXCOL ?
5409 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5410 }
5411 }
5412 else
5413 rettv->vval.v_number = FALSE;
5414}
5415
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005416/*
5417 * "getcurpos()" function
5418 */
5419 static void
5420f_getcurpos(typval_T *argvars, typval_T *rettv)
5421{
5422 getpos_both(argvars, rettv, TRUE);
5423}
5424
5425/*
5426 * "getpos(string)" function
5427 */
5428 static void
5429f_getpos(typval_T *argvars, typval_T *rettv)
5430{
5431 getpos_both(argvars, rettv, FALSE);
5432}
5433
5434/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005435 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005436 */
5437 static void
5438f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5439{
5440#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005441 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005442#endif
5443}
5444
5445/*
5446 * "getreg()" function
5447 */
5448 static void
5449f_getreg(typval_T *argvars, typval_T *rettv)
5450{
5451 char_u *strregname;
5452 int regname;
5453 int arg2 = FALSE;
5454 int return_list = FALSE;
5455 int error = FALSE;
5456
5457 if (argvars[0].v_type != VAR_UNKNOWN)
5458 {
5459 strregname = get_tv_string_chk(&argvars[0]);
5460 error = strregname == NULL;
5461 if (argvars[1].v_type != VAR_UNKNOWN)
5462 {
5463 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5464 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5465 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5466 }
5467 }
5468 else
5469 strregname = get_vim_var_str(VV_REG);
5470
5471 if (error)
5472 return;
5473
5474 regname = (strregname == NULL ? '"' : *strregname);
5475 if (regname == 0)
5476 regname = '"';
5477
5478 if (return_list)
5479 {
5480 rettv->v_type = VAR_LIST;
5481 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5482 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5483 if (rettv->vval.v_list == NULL)
5484 (void)rettv_list_alloc(rettv);
5485 else
5486 ++rettv->vval.v_list->lv_refcount;
5487 }
5488 else
5489 {
5490 rettv->v_type = VAR_STRING;
5491 rettv->vval.v_string = get_reg_contents(regname,
5492 arg2 ? GREG_EXPR_SRC : 0);
5493 }
5494}
5495
5496/*
5497 * "getregtype()" function
5498 */
5499 static void
5500f_getregtype(typval_T *argvars, typval_T *rettv)
5501{
5502 char_u *strregname;
5503 int regname;
5504 char_u buf[NUMBUFLEN + 2];
5505 long reglen = 0;
5506
5507 if (argvars[0].v_type != VAR_UNKNOWN)
5508 {
5509 strregname = get_tv_string_chk(&argvars[0]);
5510 if (strregname == NULL) /* type error; errmsg already given */
5511 {
5512 rettv->v_type = VAR_STRING;
5513 rettv->vval.v_string = NULL;
5514 return;
5515 }
5516 }
5517 else
5518 /* Default to v:register */
5519 strregname = get_vim_var_str(VV_REG);
5520
5521 regname = (strregname == NULL ? '"' : *strregname);
5522 if (regname == 0)
5523 regname = '"';
5524
5525 buf[0] = NUL;
5526 buf[1] = NUL;
5527 switch (get_reg_type(regname, &reglen))
5528 {
5529 case MLINE: buf[0] = 'V'; break;
5530 case MCHAR: buf[0] = 'v'; break;
5531 case MBLOCK:
5532 buf[0] = Ctrl_V;
5533 sprintf((char *)buf + 1, "%ld", reglen + 1);
5534 break;
5535 }
5536 rettv->v_type = VAR_STRING;
5537 rettv->vval.v_string = vim_strsave(buf);
5538}
5539
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005540/*
5541 * Returns information (variables, options, etc.) about a tab page
5542 * as a dictionary.
5543 */
5544 static dict_T *
5545get_tabpage_info(tabpage_T *tp, int tp_idx)
5546{
5547 win_T *wp;
5548 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005549 list_T *l;
5550
5551 dict = dict_alloc();
5552 if (dict == NULL)
5553 return NULL;
5554
Bram Moolenaare0be1672018-07-08 16:50:37 +02005555 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005556
5557 l = list_alloc();
5558 if (l != NULL)
5559 {
5560 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5561 wp; wp = wp->w_next)
5562 list_append_number(l, (varnumber_T)wp->w_id);
5563 dict_add_list(dict, "windows", l);
5564 }
5565
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005566 /* Make a reference to tabpage variables */
5567 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005568
5569 return dict;
5570}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005571
5572/*
5573 * "gettabinfo()" function
5574 */
5575 static void
5576f_gettabinfo(typval_T *argvars, typval_T *rettv)
5577{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005578 tabpage_T *tp, *tparg = NULL;
5579 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005580 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005581
5582 if (rettv_list_alloc(rettv) != OK)
5583 return;
5584
5585 if (argvars[0].v_type != VAR_UNKNOWN)
5586 {
5587 /* Information about one tab page */
5588 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5589 if (tparg == NULL)
5590 return;
5591 }
5592
5593 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005594 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005595 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005596 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005597 if (tparg != NULL && tp != tparg)
5598 continue;
5599 d = get_tabpage_info(tp, tpnr);
5600 if (d != NULL)
5601 list_append_dict(rettv->vval.v_list, d);
5602 if (tparg != NULL)
5603 return;
5604 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005605}
5606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005607/*
5608 * "gettabvar()" function
5609 */
5610 static void
5611f_gettabvar(typval_T *argvars, typval_T *rettv)
5612{
5613 win_T *oldcurwin;
5614 tabpage_T *tp, *oldtabpage;
5615 dictitem_T *v;
5616 char_u *varname;
5617 int done = FALSE;
5618
5619 rettv->v_type = VAR_STRING;
5620 rettv->vval.v_string = NULL;
5621
5622 varname = get_tv_string_chk(&argvars[1]);
5623 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5624 if (tp != NULL && varname != NULL)
5625 {
5626 /* Set tp to be our tabpage, temporarily. Also set the window to the
5627 * first window in the tabpage, otherwise the window is not valid. */
5628 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005629 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5630 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631 {
5632 /* look up the variable */
5633 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5634 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5635 if (v != NULL)
5636 {
5637 copy_tv(&v->di_tv, rettv);
5638 done = TRUE;
5639 }
5640 }
5641
5642 /* restore previous notion of curwin */
5643 restore_win(oldcurwin, oldtabpage, TRUE);
5644 }
5645
5646 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5647 copy_tv(&argvars[2], rettv);
5648}
5649
5650/*
5651 * "gettabwinvar()" function
5652 */
5653 static void
5654f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5655{
5656 getwinvar(argvars, rettv, 1);
5657}
5658
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005659/*
5660 * Returns information about a window as a dictionary.
5661 */
5662 static dict_T *
5663get_win_info(win_T *wp, short tpnr, short winnr)
5664{
5665 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005666
5667 dict = dict_alloc();
5668 if (dict == NULL)
5669 return NULL;
5670
Bram Moolenaare0be1672018-07-08 16:50:37 +02005671 dict_add_number(dict, "tabnr", tpnr);
5672 dict_add_number(dict, "winnr", winnr);
5673 dict_add_number(dict, "winid", wp->w_id);
5674 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005675 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005676#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005677 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005678#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005679 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005680 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005681 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005682
Bram Moolenaar69905d12017-08-13 18:14:47 +02005683#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005684 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005685#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005686#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005687 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5688 dict_add_number(dict, "loclist",
5689 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005690#endif
5691
Bram Moolenaar30567352016-08-27 21:25:44 +02005692 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005693 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005694
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005695 return dict;
5696}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005697
5698/*
5699 * "getwininfo()" function
5700 */
5701 static void
5702f_getwininfo(typval_T *argvars, typval_T *rettv)
5703{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005704 tabpage_T *tp;
5705 win_T *wp = NULL, *wparg = NULL;
5706 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005707 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005708
5709 if (rettv_list_alloc(rettv) != OK)
5710 return;
5711
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005712 if (argvars[0].v_type != VAR_UNKNOWN)
5713 {
5714 wparg = win_id2wp(argvars);
5715 if (wparg == NULL)
5716 return;
5717 }
5718
5719 /* Collect information about either all the windows across all the tab
5720 * pages or one particular window.
5721 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005722 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005723 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005724 tabnr++;
5725 winnr = 0;
5726 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005727 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005728 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005729 if (wparg != NULL && wp != wparg)
5730 continue;
5731 d = get_win_info(wp, tabnr, winnr);
5732 if (d != NULL)
5733 list_append_dict(rettv->vval.v_list, d);
5734 if (wparg != NULL)
5735 /* found information about a specific window */
5736 return;
5737 }
5738 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005739}
5740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005741/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005742 * "win_findbuf()" function
5743 */
5744 static void
5745f_win_findbuf(typval_T *argvars, typval_T *rettv)
5746{
5747 if (rettv_list_alloc(rettv) != FAIL)
5748 win_findbuf(argvars, rettv->vval.v_list);
5749}
5750
5751/*
5752 * "win_getid()" function
5753 */
5754 static void
5755f_win_getid(typval_T *argvars, typval_T *rettv)
5756{
5757 rettv->vval.v_number = win_getid(argvars);
5758}
5759
5760/*
5761 * "win_gotoid()" function
5762 */
5763 static void
5764f_win_gotoid(typval_T *argvars, typval_T *rettv)
5765{
5766 rettv->vval.v_number = win_gotoid(argvars);
5767}
5768
5769/*
5770 * "win_id2tabwin()" function
5771 */
5772 static void
5773f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5774{
5775 if (rettv_list_alloc(rettv) != FAIL)
5776 win_id2tabwin(argvars, rettv->vval.v_list);
5777}
5778
5779/*
5780 * "win_id2win()" function
5781 */
5782 static void
5783f_win_id2win(typval_T *argvars, typval_T *rettv)
5784{
5785 rettv->vval.v_number = win_id2win(argvars);
5786}
5787
5788/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005789 * "win_screenpos()" function
5790 */
5791 static void
5792f_win_screenpos(typval_T *argvars, typval_T *rettv)
5793{
5794 win_T *wp;
5795
5796 if (rettv_list_alloc(rettv) == FAIL)
5797 return;
5798
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005799 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005800 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5801 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5802}
5803
5804/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005805 * "getwinpos({timeout})" function
5806 */
5807 static void
5808f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5809{
5810 int x = -1;
5811 int y = -1;
5812
5813 if (rettv_list_alloc(rettv) == FAIL)
5814 return;
5815#ifdef FEAT_GUI
5816 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005817 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005818# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5819 else
5820# endif
5821#endif
5822#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5823 {
5824 varnumber_T timeout = 100;
5825
5826 if (argvars[0].v_type != VAR_UNKNOWN)
5827 timeout = get_tv_number(&argvars[0]);
5828 term_get_winpos(&x, &y, timeout);
5829 }
5830#endif
5831 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5832 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5833}
5834
5835
5836/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005837 * "getwinposx()" function
5838 */
5839 static void
5840f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5841{
5842 rettv->vval.v_number = -1;
5843#ifdef FEAT_GUI
5844 if (gui.in_use)
5845 {
5846 int x, y;
5847
5848 if (gui_mch_get_winpos(&x, &y) == OK)
5849 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005850 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005851 }
5852#endif
5853#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5854 {
5855 int x, y;
5856
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005857 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005858 rettv->vval.v_number = x;
5859 }
5860#endif
5861}
5862
5863/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005864 * "getwinposy()" function
5865 */
5866 static void
5867f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5868{
5869 rettv->vval.v_number = -1;
5870#ifdef FEAT_GUI
5871 if (gui.in_use)
5872 {
5873 int x, y;
5874
5875 if (gui_mch_get_winpos(&x, &y) == OK)
5876 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005877 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005878 }
5879#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005880#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5881 {
5882 int x, y;
5883
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005884 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005885 rettv->vval.v_number = y;
5886 }
5887#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005888}
5889
5890/*
5891 * "getwinvar()" function
5892 */
5893 static void
5894f_getwinvar(typval_T *argvars, typval_T *rettv)
5895{
5896 getwinvar(argvars, rettv, 0);
5897}
5898
5899/*
5900 * "glob()" function
5901 */
5902 static void
5903f_glob(typval_T *argvars, typval_T *rettv)
5904{
5905 int options = WILD_SILENT|WILD_USE_NL;
5906 expand_T xpc;
5907 int error = FALSE;
5908
5909 /* When the optional second argument is non-zero, don't remove matches
5910 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5911 rettv->v_type = VAR_STRING;
5912 if (argvars[1].v_type != VAR_UNKNOWN)
5913 {
5914 if (get_tv_number_chk(&argvars[1], &error))
5915 options |= WILD_KEEP_ALL;
5916 if (argvars[2].v_type != VAR_UNKNOWN)
5917 {
5918 if (get_tv_number_chk(&argvars[2], &error))
5919 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005920 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005921 }
5922 if (argvars[3].v_type != VAR_UNKNOWN
5923 && get_tv_number_chk(&argvars[3], &error))
5924 options |= WILD_ALLLINKS;
5925 }
5926 }
5927 if (!error)
5928 {
5929 ExpandInit(&xpc);
5930 xpc.xp_context = EXPAND_FILES;
5931 if (p_wic)
5932 options += WILD_ICASE;
5933 if (rettv->v_type == VAR_STRING)
5934 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5935 NULL, options, WILD_ALL);
5936 else if (rettv_list_alloc(rettv) != FAIL)
5937 {
5938 int i;
5939
5940 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5941 NULL, options, WILD_ALL_KEEP);
5942 for (i = 0; i < xpc.xp_numfiles; i++)
5943 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5944
5945 ExpandCleanup(&xpc);
5946 }
5947 }
5948 else
5949 rettv->vval.v_string = NULL;
5950}
5951
5952/*
5953 * "globpath()" function
5954 */
5955 static void
5956f_globpath(typval_T *argvars, typval_T *rettv)
5957{
5958 int flags = 0;
5959 char_u buf1[NUMBUFLEN];
5960 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5961 int error = FALSE;
5962 garray_T ga;
5963 int i;
5964
5965 /* When the optional second argument is non-zero, don't remove matches
5966 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5967 rettv->v_type = VAR_STRING;
5968 if (argvars[2].v_type != VAR_UNKNOWN)
5969 {
5970 if (get_tv_number_chk(&argvars[2], &error))
5971 flags |= WILD_KEEP_ALL;
5972 if (argvars[3].v_type != VAR_UNKNOWN)
5973 {
5974 if (get_tv_number_chk(&argvars[3], &error))
5975 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005976 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005977 }
5978 if (argvars[4].v_type != VAR_UNKNOWN
5979 && get_tv_number_chk(&argvars[4], &error))
5980 flags |= WILD_ALLLINKS;
5981 }
5982 }
5983 if (file != NULL && !error)
5984 {
5985 ga_init2(&ga, (int)sizeof(char_u *), 10);
5986 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5987 if (rettv->v_type == VAR_STRING)
5988 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5989 else if (rettv_list_alloc(rettv) != FAIL)
5990 for (i = 0; i < ga.ga_len; ++i)
5991 list_append_string(rettv->vval.v_list,
5992 ((char_u **)(ga.ga_data))[i], -1);
5993 ga_clear_strings(&ga);
5994 }
5995 else
5996 rettv->vval.v_string = NULL;
5997}
5998
5999/*
6000 * "glob2regpat()" function
6001 */
6002 static void
6003f_glob2regpat(typval_T *argvars, typval_T *rettv)
6004{
6005 char_u *pat = get_tv_string_chk(&argvars[0]);
6006
6007 rettv->v_type = VAR_STRING;
6008 rettv->vval.v_string = (pat == NULL)
6009 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6010}
6011
6012/* for VIM_VERSION_ defines */
6013#include "version.h"
6014
6015/*
6016 * "has()" function
6017 */
6018 static void
6019f_has(typval_T *argvars, typval_T *rettv)
6020{
6021 int i;
6022 char_u *name;
6023 int n = FALSE;
6024 static char *(has_list[]) =
6025 {
6026#ifdef AMIGA
6027 "amiga",
6028# ifdef FEAT_ARP
6029 "arp",
6030# endif
6031#endif
6032#ifdef __BEOS__
6033 "beos",
6034#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006035#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006036 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6037 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006038# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006039 "macunix", /* Mac OS X, with the darwin feature */
6040 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006041# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006042#endif
6043#ifdef __QNX__
6044 "qnx",
6045#endif
6046#ifdef UNIX
6047 "unix",
6048#endif
6049#ifdef VMS
6050 "vms",
6051#endif
6052#ifdef WIN32
6053 "win32",
6054#endif
6055#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6056 "win32unix",
6057#endif
6058#if defined(WIN64) || defined(_WIN64)
6059 "win64",
6060#endif
6061#ifdef EBCDIC
6062 "ebcdic",
6063#endif
6064#ifndef CASE_INSENSITIVE_FILENAME
6065 "fname_case",
6066#endif
6067#ifdef HAVE_ACL
6068 "acl",
6069#endif
6070#ifdef FEAT_ARABIC
6071 "arabic",
6072#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006073 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006074#ifdef FEAT_AUTOCHDIR
6075 "autochdir",
6076#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006077#ifdef FEAT_AUTOSERVERNAME
6078 "autoservername",
6079#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006080#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081 "balloon_eval",
6082# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6083 "balloon_multiline",
6084# endif
6085#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006086#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006087 "balloon_eval_term",
6088#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006089#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6090 "builtin_terms",
6091# ifdef ALL_BUILTIN_TCAPS
6092 "all_builtin_terms",
6093# endif
6094#endif
6095#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6096 || defined(FEAT_GUI_W32) \
6097 || defined(FEAT_GUI_MOTIF))
6098 "browsefilter",
6099#endif
6100#ifdef FEAT_BYTEOFF
6101 "byte_offset",
6102#endif
6103#ifdef FEAT_JOB_CHANNEL
6104 "channel",
6105#endif
6106#ifdef FEAT_CINDENT
6107 "cindent",
6108#endif
6109#ifdef FEAT_CLIENTSERVER
6110 "clientserver",
6111#endif
6112#ifdef FEAT_CLIPBOARD
6113 "clipboard",
6114#endif
6115#ifdef FEAT_CMDL_COMPL
6116 "cmdline_compl",
6117#endif
6118#ifdef FEAT_CMDHIST
6119 "cmdline_hist",
6120#endif
6121#ifdef FEAT_COMMENTS
6122 "comments",
6123#endif
6124#ifdef FEAT_CONCEAL
6125 "conceal",
6126#endif
6127#ifdef FEAT_CRYPT
6128 "cryptv",
6129 "crypt-blowfish",
6130 "crypt-blowfish2",
6131#endif
6132#ifdef FEAT_CSCOPE
6133 "cscope",
6134#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006135 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006136#ifdef CURSOR_SHAPE
6137 "cursorshape",
6138#endif
6139#ifdef DEBUG
6140 "debug",
6141#endif
6142#ifdef FEAT_CON_DIALOG
6143 "dialog_con",
6144#endif
6145#ifdef FEAT_GUI_DIALOG
6146 "dialog_gui",
6147#endif
6148#ifdef FEAT_DIFF
6149 "diff",
6150#endif
6151#ifdef FEAT_DIGRAPHS
6152 "digraphs",
6153#endif
6154#ifdef FEAT_DIRECTX
6155 "directx",
6156#endif
6157#ifdef FEAT_DND
6158 "dnd",
6159#endif
6160#ifdef FEAT_EMACS_TAGS
6161 "emacs_tags",
6162#endif
6163 "eval", /* always present, of course! */
6164 "ex_extra", /* graduated feature */
6165#ifdef FEAT_SEARCH_EXTRA
6166 "extra_search",
6167#endif
6168#ifdef FEAT_FKMAP
6169 "farsi",
6170#endif
6171#ifdef FEAT_SEARCHPATH
6172 "file_in_path",
6173#endif
6174#ifdef FEAT_FILTERPIPE
6175 "filterpipe",
6176#endif
6177#ifdef FEAT_FIND_ID
6178 "find_in_path",
6179#endif
6180#ifdef FEAT_FLOAT
6181 "float",
6182#endif
6183#ifdef FEAT_FOLDING
6184 "folding",
6185#endif
6186#ifdef FEAT_FOOTER
6187 "footer",
6188#endif
6189#if !defined(USE_SYSTEM) && defined(UNIX)
6190 "fork",
6191#endif
6192#ifdef FEAT_GETTEXT
6193 "gettext",
6194#endif
6195#ifdef FEAT_GUI
6196 "gui",
6197#endif
6198#ifdef FEAT_GUI_ATHENA
6199# ifdef FEAT_GUI_NEXTAW
6200 "gui_neXtaw",
6201# else
6202 "gui_athena",
6203# endif
6204#endif
6205#ifdef FEAT_GUI_GTK
6206 "gui_gtk",
6207# ifdef USE_GTK3
6208 "gui_gtk3",
6209# else
6210 "gui_gtk2",
6211# endif
6212#endif
6213#ifdef FEAT_GUI_GNOME
6214 "gui_gnome",
6215#endif
6216#ifdef FEAT_GUI_MAC
6217 "gui_mac",
6218#endif
6219#ifdef FEAT_GUI_MOTIF
6220 "gui_motif",
6221#endif
6222#ifdef FEAT_GUI_PHOTON
6223 "gui_photon",
6224#endif
6225#ifdef FEAT_GUI_W32
6226 "gui_win32",
6227#endif
6228#ifdef FEAT_HANGULIN
6229 "hangul_input",
6230#endif
6231#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6232 "iconv",
6233#endif
6234#ifdef FEAT_INS_EXPAND
6235 "insert_expand",
6236#endif
6237#ifdef FEAT_JOB_CHANNEL
6238 "job",
6239#endif
6240#ifdef FEAT_JUMPLIST
6241 "jumplist",
6242#endif
6243#ifdef FEAT_KEYMAP
6244 "keymap",
6245#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006246 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006247#ifdef FEAT_LANGMAP
6248 "langmap",
6249#endif
6250#ifdef FEAT_LIBCALL
6251 "libcall",
6252#endif
6253#ifdef FEAT_LINEBREAK
6254 "linebreak",
6255#endif
6256#ifdef FEAT_LISP
6257 "lispindent",
6258#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006259 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006260#ifdef FEAT_LOCALMAP
6261 "localmap",
6262#endif
6263#ifdef FEAT_LUA
6264# ifndef DYNAMIC_LUA
6265 "lua",
6266# endif
6267#endif
6268#ifdef FEAT_MENU
6269 "menu",
6270#endif
6271#ifdef FEAT_SESSION
6272 "mksession",
6273#endif
6274#ifdef FEAT_MODIFY_FNAME
6275 "modify_fname",
6276#endif
6277#ifdef FEAT_MOUSE
6278 "mouse",
6279#endif
6280#ifdef FEAT_MOUSESHAPE
6281 "mouseshape",
6282#endif
6283#if defined(UNIX) || defined(VMS)
6284# ifdef FEAT_MOUSE_DEC
6285 "mouse_dec",
6286# endif
6287# ifdef FEAT_MOUSE_GPM
6288 "mouse_gpm",
6289# endif
6290# ifdef FEAT_MOUSE_JSB
6291 "mouse_jsbterm",
6292# endif
6293# ifdef FEAT_MOUSE_NET
6294 "mouse_netterm",
6295# endif
6296# ifdef FEAT_MOUSE_PTERM
6297 "mouse_pterm",
6298# endif
6299# ifdef FEAT_MOUSE_SGR
6300 "mouse_sgr",
6301# endif
6302# ifdef FEAT_SYSMOUSE
6303 "mouse_sysmouse",
6304# endif
6305# ifdef FEAT_MOUSE_URXVT
6306 "mouse_urxvt",
6307# endif
6308# ifdef FEAT_MOUSE_XTERM
6309 "mouse_xterm",
6310# endif
6311#endif
6312#ifdef FEAT_MBYTE
6313 "multi_byte",
6314#endif
6315#ifdef FEAT_MBYTE_IME
6316 "multi_byte_ime",
6317#endif
6318#ifdef FEAT_MULTI_LANG
6319 "multi_lang",
6320#endif
6321#ifdef FEAT_MZSCHEME
6322#ifndef DYNAMIC_MZSCHEME
6323 "mzscheme",
6324#endif
6325#endif
6326#ifdef FEAT_NUM64
6327 "num64",
6328#endif
6329#ifdef FEAT_OLE
6330 "ole",
6331#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006332#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006334#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335#ifdef FEAT_PATH_EXTRA
6336 "path_extra",
6337#endif
6338#ifdef FEAT_PERL
6339#ifndef DYNAMIC_PERL
6340 "perl",
6341#endif
6342#endif
6343#ifdef FEAT_PERSISTENT_UNDO
6344 "persistent_undo",
6345#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006346#if defined(FEAT_PYTHON)
6347 "python_compiled",
6348# if defined(DYNAMIC_PYTHON)
6349 "python_dynamic",
6350# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006352 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006353# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006354#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006355#if defined(FEAT_PYTHON3)
6356 "python3_compiled",
6357# if defined(DYNAMIC_PYTHON3)
6358 "python3_dynamic",
6359# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006360 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006361 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006362# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363#endif
6364#ifdef FEAT_POSTSCRIPT
6365 "postscript",
6366#endif
6367#ifdef FEAT_PRINTER
6368 "printer",
6369#endif
6370#ifdef FEAT_PROFILE
6371 "profile",
6372#endif
6373#ifdef FEAT_RELTIME
6374 "reltime",
6375#endif
6376#ifdef FEAT_QUICKFIX
6377 "quickfix",
6378#endif
6379#ifdef FEAT_RIGHTLEFT
6380 "rightleft",
6381#endif
6382#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6383 "ruby",
6384#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006386#ifdef FEAT_CMDL_INFO
6387 "showcmd",
6388 "cmdline_info",
6389#endif
6390#ifdef FEAT_SIGNS
6391 "signs",
6392#endif
6393#ifdef FEAT_SMARTINDENT
6394 "smartindent",
6395#endif
6396#ifdef STARTUPTIME
6397 "startuptime",
6398#endif
6399#ifdef FEAT_STL_OPT
6400 "statusline",
6401#endif
6402#ifdef FEAT_SUN_WORKSHOP
6403 "sun_workshop",
6404#endif
6405#ifdef FEAT_NETBEANS_INTG
6406 "netbeans_intg",
6407#endif
6408#ifdef FEAT_SPELL
6409 "spell",
6410#endif
6411#ifdef FEAT_SYN_HL
6412 "syntax",
6413#endif
6414#if defined(USE_SYSTEM) || !defined(UNIX)
6415 "system",
6416#endif
6417#ifdef FEAT_TAG_BINS
6418 "tag_binary",
6419#endif
6420#ifdef FEAT_TAG_OLDSTATIC
6421 "tag_old_static",
6422#endif
6423#ifdef FEAT_TAG_ANYWHITE
6424 "tag_any_white",
6425#endif
6426#ifdef FEAT_TCL
6427# ifndef DYNAMIC_TCL
6428 "tcl",
6429# endif
6430#endif
6431#ifdef FEAT_TERMGUICOLORS
6432 "termguicolors",
6433#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006434#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006435 "terminal",
6436#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006437#ifdef TERMINFO
6438 "terminfo",
6439#endif
6440#ifdef FEAT_TERMRESPONSE
6441 "termresponse",
6442#endif
6443#ifdef FEAT_TEXTOBJ
6444 "textobjects",
6445#endif
6446#ifdef HAVE_TGETENT
6447 "tgetent",
6448#endif
6449#ifdef FEAT_TIMERS
6450 "timers",
6451#endif
6452#ifdef FEAT_TITLE
6453 "title",
6454#endif
6455#ifdef FEAT_TOOLBAR
6456 "toolbar",
6457#endif
6458#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6459 "unnamedplus",
6460#endif
6461#ifdef FEAT_USR_CMDS
6462 "user-commands", /* was accidentally included in 5.4 */
6463 "user_commands",
6464#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006465#ifdef FEAT_VARTABS
6466 "vartabs",
6467#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006468#ifdef FEAT_VIMINFO
6469 "viminfo",
6470#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006471 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472#ifdef FEAT_VIRTUALEDIT
6473 "virtualedit",
6474#endif
6475 "visual",
6476#ifdef FEAT_VISUALEXTRA
6477 "visualextra",
6478#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006479 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006480#ifdef FEAT_VTP
6481 "vtp",
6482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006483#ifdef FEAT_WILDIGN
6484 "wildignore",
6485#endif
6486#ifdef FEAT_WILDMENU
6487 "wildmenu",
6488#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006490#ifdef FEAT_WAK
6491 "winaltkeys",
6492#endif
6493#ifdef FEAT_WRITEBACKUP
6494 "writebackup",
6495#endif
6496#ifdef FEAT_XIM
6497 "xim",
6498#endif
6499#ifdef FEAT_XFONTSET
6500 "xfontset",
6501#endif
6502#ifdef FEAT_XPM_W32
6503 "xpm",
6504 "xpm_w32", /* for backward compatibility */
6505#else
6506# if defined(HAVE_XPM)
6507 "xpm",
6508# endif
6509#endif
6510#ifdef USE_XSMP
6511 "xsmp",
6512#endif
6513#ifdef USE_XSMP_INTERACT
6514 "xsmp_interact",
6515#endif
6516#ifdef FEAT_XCLIPBOARD
6517 "xterm_clipboard",
6518#endif
6519#ifdef FEAT_XTERM_SAVE
6520 "xterm_save",
6521#endif
6522#if defined(UNIX) && defined(FEAT_X11)
6523 "X11",
6524#endif
6525 NULL
6526 };
6527
6528 name = get_tv_string(&argvars[0]);
6529 for (i = 0; has_list[i] != NULL; ++i)
6530 if (STRICMP(name, has_list[i]) == 0)
6531 {
6532 n = TRUE;
6533 break;
6534 }
6535
6536 if (n == FALSE)
6537 {
6538 if (STRNICMP(name, "patch", 5) == 0)
6539 {
6540 if (name[5] == '-'
6541 && STRLEN(name) >= 11
6542 && vim_isdigit(name[6])
6543 && vim_isdigit(name[8])
6544 && vim_isdigit(name[10]))
6545 {
6546 int major = atoi((char *)name + 6);
6547 int minor = atoi((char *)name + 8);
6548
6549 /* Expect "patch-9.9.01234". */
6550 n = (major < VIM_VERSION_MAJOR
6551 || (major == VIM_VERSION_MAJOR
6552 && (minor < VIM_VERSION_MINOR
6553 || (minor == VIM_VERSION_MINOR
6554 && has_patch(atoi((char *)name + 10))))));
6555 }
6556 else
6557 n = has_patch(atoi((char *)name + 5));
6558 }
6559 else if (STRICMP(name, "vim_starting") == 0)
6560 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006561 else if (STRICMP(name, "ttyin") == 0)
6562 n = mch_input_isatty();
6563 else if (STRICMP(name, "ttyout") == 0)
6564 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006565#ifdef FEAT_MBYTE
6566 else if (STRICMP(name, "multi_byte_encoding") == 0)
6567 n = has_mbyte;
6568#endif
6569#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6570 else if (STRICMP(name, "balloon_multiline") == 0)
6571 n = multiline_balloon_available();
6572#endif
6573#ifdef DYNAMIC_TCL
6574 else if (STRICMP(name, "tcl") == 0)
6575 n = tcl_enabled(FALSE);
6576#endif
6577#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6578 else if (STRICMP(name, "iconv") == 0)
6579 n = iconv_enabled(FALSE);
6580#endif
6581#ifdef DYNAMIC_LUA
6582 else if (STRICMP(name, "lua") == 0)
6583 n = lua_enabled(FALSE);
6584#endif
6585#ifdef DYNAMIC_MZSCHEME
6586 else if (STRICMP(name, "mzscheme") == 0)
6587 n = mzscheme_enabled(FALSE);
6588#endif
6589#ifdef DYNAMIC_RUBY
6590 else if (STRICMP(name, "ruby") == 0)
6591 n = ruby_enabled(FALSE);
6592#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006593#ifdef DYNAMIC_PYTHON
6594 else if (STRICMP(name, "python") == 0)
6595 n = python_enabled(FALSE);
6596#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006597#ifdef DYNAMIC_PYTHON3
6598 else if (STRICMP(name, "python3") == 0)
6599 n = python3_enabled(FALSE);
6600#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006601#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6602 else if (STRICMP(name, "pythonx") == 0)
6603 {
6604# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6605 if (p_pyx == 0)
6606 n = python3_enabled(FALSE) || python_enabled(FALSE);
6607 else if (p_pyx == 3)
6608 n = python3_enabled(FALSE);
6609 else if (p_pyx == 2)
6610 n = python_enabled(FALSE);
6611# elif defined(DYNAMIC_PYTHON)
6612 n = python_enabled(FALSE);
6613# elif defined(DYNAMIC_PYTHON3)
6614 n = python3_enabled(FALSE);
6615# endif
6616 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006617#endif
6618#ifdef DYNAMIC_PERL
6619 else if (STRICMP(name, "perl") == 0)
6620 n = perl_enabled(FALSE);
6621#endif
6622#ifdef FEAT_GUI
6623 else if (STRICMP(name, "gui_running") == 0)
6624 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006625# ifdef FEAT_BROWSE
6626 else if (STRICMP(name, "browse") == 0)
6627 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6628# endif
6629#endif
6630#ifdef FEAT_SYN_HL
6631 else if (STRICMP(name, "syntax_items") == 0)
6632 n = syntax_present(curwin);
6633#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006634#ifdef FEAT_VTP
6635 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006636 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006637#endif
6638#ifdef FEAT_NETBEANS_INTG
6639 else if (STRICMP(name, "netbeans_enabled") == 0)
6640 n = netbeans_active();
6641#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006642#if defined(FEAT_TERMINAL) && defined(WIN3264)
6643 else if (STRICMP(name, "terminal") == 0)
6644 n = terminal_enabled();
6645#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006646 }
6647
6648 rettv->vval.v_number = n;
6649}
6650
6651/*
6652 * "has_key()" function
6653 */
6654 static void
6655f_has_key(typval_T *argvars, typval_T *rettv)
6656{
6657 if (argvars[0].v_type != VAR_DICT)
6658 {
6659 EMSG(_(e_dictreq));
6660 return;
6661 }
6662 if (argvars[0].vval.v_dict == NULL)
6663 return;
6664
6665 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6666 get_tv_string(&argvars[1]), -1) != NULL;
6667}
6668
6669/*
6670 * "haslocaldir()" function
6671 */
6672 static void
6673f_haslocaldir(typval_T *argvars, typval_T *rettv)
6674{
6675 win_T *wp = NULL;
6676
6677 wp = find_tabwin(&argvars[0], &argvars[1]);
6678 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6679}
6680
6681/*
6682 * "hasmapto()" function
6683 */
6684 static void
6685f_hasmapto(typval_T *argvars, typval_T *rettv)
6686{
6687 char_u *name;
6688 char_u *mode;
6689 char_u buf[NUMBUFLEN];
6690 int abbr = FALSE;
6691
6692 name = get_tv_string(&argvars[0]);
6693 if (argvars[1].v_type == VAR_UNKNOWN)
6694 mode = (char_u *)"nvo";
6695 else
6696 {
6697 mode = get_tv_string_buf(&argvars[1], buf);
6698 if (argvars[2].v_type != VAR_UNKNOWN)
6699 abbr = (int)get_tv_number(&argvars[2]);
6700 }
6701
6702 if (map_to_exists(name, mode, abbr))
6703 rettv->vval.v_number = TRUE;
6704 else
6705 rettv->vval.v_number = FALSE;
6706}
6707
6708/*
6709 * "histadd()" function
6710 */
6711 static void
6712f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6713{
6714#ifdef FEAT_CMDHIST
6715 int histype;
6716 char_u *str;
6717 char_u buf[NUMBUFLEN];
6718#endif
6719
6720 rettv->vval.v_number = FALSE;
6721 if (check_restricted() || check_secure())
6722 return;
6723#ifdef FEAT_CMDHIST
6724 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6725 histype = str != NULL ? get_histtype(str) : -1;
6726 if (histype >= 0)
6727 {
6728 str = get_tv_string_buf(&argvars[1], buf);
6729 if (*str != NUL)
6730 {
6731 init_history();
6732 add_to_history(histype, str, FALSE, NUL);
6733 rettv->vval.v_number = TRUE;
6734 return;
6735 }
6736 }
6737#endif
6738}
6739
6740/*
6741 * "histdel()" function
6742 */
6743 static void
6744f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6745{
6746#ifdef FEAT_CMDHIST
6747 int n;
6748 char_u buf[NUMBUFLEN];
6749 char_u *str;
6750
6751 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6752 if (str == NULL)
6753 n = 0;
6754 else if (argvars[1].v_type == VAR_UNKNOWN)
6755 /* only one argument: clear entire history */
6756 n = clr_history(get_histtype(str));
6757 else if (argvars[1].v_type == VAR_NUMBER)
6758 /* index given: remove that entry */
6759 n = del_history_idx(get_histtype(str),
6760 (int)get_tv_number(&argvars[1]));
6761 else
6762 /* string given: remove all matching entries */
6763 n = del_history_entry(get_histtype(str),
6764 get_tv_string_buf(&argvars[1], buf));
6765 rettv->vval.v_number = n;
6766#endif
6767}
6768
6769/*
6770 * "histget()" function
6771 */
6772 static void
6773f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6774{
6775#ifdef FEAT_CMDHIST
6776 int type;
6777 int idx;
6778 char_u *str;
6779
6780 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6781 if (str == NULL)
6782 rettv->vval.v_string = NULL;
6783 else
6784 {
6785 type = get_histtype(str);
6786 if (argvars[1].v_type == VAR_UNKNOWN)
6787 idx = get_history_idx(type);
6788 else
6789 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6790 /* -1 on type error */
6791 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6792 }
6793#else
6794 rettv->vval.v_string = NULL;
6795#endif
6796 rettv->v_type = VAR_STRING;
6797}
6798
6799/*
6800 * "histnr()" function
6801 */
6802 static void
6803f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6804{
6805 int i;
6806
6807#ifdef FEAT_CMDHIST
6808 char_u *history = get_tv_string_chk(&argvars[0]);
6809
6810 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6811 if (i >= HIST_CMD && i < HIST_COUNT)
6812 i = get_history_idx(i);
6813 else
6814#endif
6815 i = -1;
6816 rettv->vval.v_number = i;
6817}
6818
6819/*
6820 * "highlightID(name)" function
6821 */
6822 static void
6823f_hlID(typval_T *argvars, typval_T *rettv)
6824{
6825 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6826}
6827
6828/*
6829 * "highlight_exists()" function
6830 */
6831 static void
6832f_hlexists(typval_T *argvars, typval_T *rettv)
6833{
6834 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6835}
6836
6837/*
6838 * "hostname()" function
6839 */
6840 static void
6841f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6842{
6843 char_u hostname[256];
6844
6845 mch_get_host_name(hostname, 256);
6846 rettv->v_type = VAR_STRING;
6847 rettv->vval.v_string = vim_strsave(hostname);
6848}
6849
6850/*
6851 * iconv() function
6852 */
6853 static void
6854f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6855{
6856#ifdef FEAT_MBYTE
6857 char_u buf1[NUMBUFLEN];
6858 char_u buf2[NUMBUFLEN];
6859 char_u *from, *to, *str;
6860 vimconv_T vimconv;
6861#endif
6862
6863 rettv->v_type = VAR_STRING;
6864 rettv->vval.v_string = NULL;
6865
6866#ifdef FEAT_MBYTE
6867 str = get_tv_string(&argvars[0]);
6868 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6869 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6870 vimconv.vc_type = CONV_NONE;
6871 convert_setup(&vimconv, from, to);
6872
6873 /* If the encodings are equal, no conversion needed. */
6874 if (vimconv.vc_type == CONV_NONE)
6875 rettv->vval.v_string = vim_strsave(str);
6876 else
6877 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6878
6879 convert_setup(&vimconv, NULL, NULL);
6880 vim_free(from);
6881 vim_free(to);
6882#endif
6883}
6884
6885/*
6886 * "indent()" function
6887 */
6888 static void
6889f_indent(typval_T *argvars, typval_T *rettv)
6890{
6891 linenr_T lnum;
6892
6893 lnum = get_tv_lnum(argvars);
6894 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6895 rettv->vval.v_number = get_indent_lnum(lnum);
6896 else
6897 rettv->vval.v_number = -1;
6898}
6899
6900/*
6901 * "index()" function
6902 */
6903 static void
6904f_index(typval_T *argvars, typval_T *rettv)
6905{
6906 list_T *l;
6907 listitem_T *item;
6908 long idx = 0;
6909 int ic = FALSE;
6910
6911 rettv->vval.v_number = -1;
6912 if (argvars[0].v_type != VAR_LIST)
6913 {
6914 EMSG(_(e_listreq));
6915 return;
6916 }
6917 l = argvars[0].vval.v_list;
6918 if (l != NULL)
6919 {
6920 item = l->lv_first;
6921 if (argvars[2].v_type != VAR_UNKNOWN)
6922 {
6923 int error = FALSE;
6924
6925 /* Start at specified item. Use the cached index that list_find()
6926 * sets, so that a negative number also works. */
6927 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6928 idx = l->lv_idx;
6929 if (argvars[3].v_type != VAR_UNKNOWN)
6930 ic = (int)get_tv_number_chk(&argvars[3], &error);
6931 if (error)
6932 item = NULL;
6933 }
6934
6935 for ( ; item != NULL; item = item->li_next, ++idx)
6936 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6937 {
6938 rettv->vval.v_number = idx;
6939 break;
6940 }
6941 }
6942}
6943
6944static int inputsecret_flag = 0;
6945
6946/*
6947 * "input()" function
6948 * Also handles inputsecret() when inputsecret is set.
6949 */
6950 static void
6951f_input(typval_T *argvars, typval_T *rettv)
6952{
6953 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6954}
6955
6956/*
6957 * "inputdialog()" function
6958 */
6959 static void
6960f_inputdialog(typval_T *argvars, typval_T *rettv)
6961{
6962#if defined(FEAT_GUI_TEXTDIALOG)
6963 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6964 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6965 {
6966 char_u *message;
6967 char_u buf[NUMBUFLEN];
6968 char_u *defstr = (char_u *)"";
6969
6970 message = get_tv_string_chk(&argvars[0]);
6971 if (argvars[1].v_type != VAR_UNKNOWN
6972 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6973 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6974 else
6975 IObuff[0] = NUL;
6976 if (message != NULL && defstr != NULL
6977 && do_dialog(VIM_QUESTION, NULL, message,
6978 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6979 rettv->vval.v_string = vim_strsave(IObuff);
6980 else
6981 {
6982 if (message != NULL && defstr != NULL
6983 && argvars[1].v_type != VAR_UNKNOWN
6984 && argvars[2].v_type != VAR_UNKNOWN)
6985 rettv->vval.v_string = vim_strsave(
6986 get_tv_string_buf(&argvars[2], buf));
6987 else
6988 rettv->vval.v_string = NULL;
6989 }
6990 rettv->v_type = VAR_STRING;
6991 }
6992 else
6993#endif
6994 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6995}
6996
6997/*
6998 * "inputlist()" function
6999 */
7000 static void
7001f_inputlist(typval_T *argvars, typval_T *rettv)
7002{
7003 listitem_T *li;
7004 int selected;
7005 int mouse_used;
7006
7007#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007008 /* While starting up, there is no place to enter text. When running tests
7009 * with --not-a-term we assume feedkeys() will be used. */
7010 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007011 return;
7012#endif
7013 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7014 {
7015 EMSG2(_(e_listarg), "inputlist()");
7016 return;
7017 }
7018
7019 msg_start();
7020 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7021 lines_left = Rows; /* avoid more prompt */
7022 msg_scroll = TRUE;
7023 msg_clr_eos();
7024
7025 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7026 {
7027 msg_puts(get_tv_string(&li->li_tv));
7028 msg_putchar('\n');
7029 }
7030
7031 /* Ask for choice. */
7032 selected = prompt_for_number(&mouse_used);
7033 if (mouse_used)
7034 selected -= lines_left;
7035
7036 rettv->vval.v_number = selected;
7037}
7038
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7040
7041/*
7042 * "inputrestore()" function
7043 */
7044 static void
7045f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7046{
7047 if (ga_userinput.ga_len > 0)
7048 {
7049 --ga_userinput.ga_len;
7050 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7051 + ga_userinput.ga_len);
7052 /* default return is zero == OK */
7053 }
7054 else if (p_verbose > 1)
7055 {
7056 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
7057 rettv->vval.v_number = 1; /* Failed */
7058 }
7059}
7060
7061/*
7062 * "inputsave()" function
7063 */
7064 static void
7065f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7066{
7067 /* Add an entry to the stack of typeahead storage. */
7068 if (ga_grow(&ga_userinput, 1) == OK)
7069 {
7070 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7071 + ga_userinput.ga_len);
7072 ++ga_userinput.ga_len;
7073 /* default return is zero == OK */
7074 }
7075 else
7076 rettv->vval.v_number = 1; /* Failed */
7077}
7078
7079/*
7080 * "inputsecret()" function
7081 */
7082 static void
7083f_inputsecret(typval_T *argvars, typval_T *rettv)
7084{
7085 ++cmdline_star;
7086 ++inputsecret_flag;
7087 f_input(argvars, rettv);
7088 --cmdline_star;
7089 --inputsecret_flag;
7090}
7091
7092/*
7093 * "insert()" function
7094 */
7095 static void
7096f_insert(typval_T *argvars, typval_T *rettv)
7097{
7098 long before = 0;
7099 listitem_T *item;
7100 list_T *l;
7101 int error = FALSE;
7102
7103 if (argvars[0].v_type != VAR_LIST)
7104 EMSG2(_(e_listarg), "insert()");
7105 else if ((l = argvars[0].vval.v_list) != NULL
7106 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7107 {
7108 if (argvars[2].v_type != VAR_UNKNOWN)
7109 before = (long)get_tv_number_chk(&argvars[2], &error);
7110 if (error)
7111 return; /* type error; errmsg already given */
7112
7113 if (before == l->lv_len)
7114 item = NULL;
7115 else
7116 {
7117 item = list_find(l, before);
7118 if (item == NULL)
7119 {
7120 EMSGN(_(e_listidx), before);
7121 l = NULL;
7122 }
7123 }
7124 if (l != NULL)
7125 {
7126 list_insert_tv(l, &argvars[1], item);
7127 copy_tv(&argvars[0], rettv);
7128 }
7129 }
7130}
7131
7132/*
7133 * "invert(expr)" function
7134 */
7135 static void
7136f_invert(typval_T *argvars, typval_T *rettv)
7137{
7138 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
7139}
7140
7141/*
7142 * "isdirectory()" function
7143 */
7144 static void
7145f_isdirectory(typval_T *argvars, typval_T *rettv)
7146{
7147 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
7148}
7149
7150/*
7151 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7152 * or it refers to a List or Dictionary that is locked.
7153 */
7154 static int
7155tv_islocked(typval_T *tv)
7156{
7157 return (tv->v_lock & VAR_LOCKED)
7158 || (tv->v_type == VAR_LIST
7159 && tv->vval.v_list != NULL
7160 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7161 || (tv->v_type == VAR_DICT
7162 && tv->vval.v_dict != NULL
7163 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7164}
7165
7166/*
7167 * "islocked()" function
7168 */
7169 static void
7170f_islocked(typval_T *argvars, typval_T *rettv)
7171{
7172 lval_T lv;
7173 char_u *end;
7174 dictitem_T *di;
7175
7176 rettv->vval.v_number = -1;
7177 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007178 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007179 if (end != NULL && lv.ll_name != NULL)
7180 {
7181 if (*end != NUL)
7182 EMSG(_(e_trailing));
7183 else
7184 {
7185 if (lv.ll_tv == NULL)
7186 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007187 di = find_var(lv.ll_name, NULL, TRUE);
7188 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007189 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007190 /* Consider a variable locked when:
7191 * 1. the variable itself is locked
7192 * 2. the value of the variable is locked.
7193 * 3. the List or Dict value is locked.
7194 */
7195 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7196 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 }
7198 }
7199 else if (lv.ll_range)
7200 EMSG(_("E786: Range not allowed"));
7201 else if (lv.ll_newkey != NULL)
7202 EMSG2(_(e_dictkey), lv.ll_newkey);
7203 else if (lv.ll_list != NULL)
7204 /* List item. */
7205 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7206 else
7207 /* Dictionary item. */
7208 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7209 }
7210 }
7211
7212 clear_lval(&lv);
7213}
7214
7215#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7216/*
7217 * "isnan()" function
7218 */
7219 static void
7220f_isnan(typval_T *argvars, typval_T *rettv)
7221{
7222 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7223 && isnan(argvars[0].vval.v_float);
7224}
7225#endif
7226
7227/*
7228 * "items(dict)" function
7229 */
7230 static void
7231f_items(typval_T *argvars, typval_T *rettv)
7232{
7233 dict_list(argvars, rettv, 2);
7234}
7235
7236#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7237/*
7238 * Get the job from the argument.
7239 * Returns NULL if the job is invalid.
7240 */
7241 static job_T *
7242get_job_arg(typval_T *tv)
7243{
7244 job_T *job;
7245
7246 if (tv->v_type != VAR_JOB)
7247 {
7248 EMSG2(_(e_invarg2), get_tv_string(tv));
7249 return NULL;
7250 }
7251 job = tv->vval.v_job;
7252
7253 if (job == NULL)
7254 EMSG(_("E916: not a valid job"));
7255 return job;
7256}
7257
7258/*
7259 * "job_getchannel()" function
7260 */
7261 static void
7262f_job_getchannel(typval_T *argvars, typval_T *rettv)
7263{
7264 job_T *job = get_job_arg(&argvars[0]);
7265
7266 if (job != NULL)
7267 {
7268 rettv->v_type = VAR_CHANNEL;
7269 rettv->vval.v_channel = job->jv_channel;
7270 if (job->jv_channel != NULL)
7271 ++job->jv_channel->ch_refcount;
7272 }
7273}
7274
7275/*
7276 * "job_info()" function
7277 */
7278 static void
7279f_job_info(typval_T *argvars, typval_T *rettv)
7280{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007281 if (argvars[0].v_type != VAR_UNKNOWN)
7282 {
7283 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007284
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007285 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7286 job_info(job, rettv->vval.v_dict);
7287 }
7288 else if (rettv_list_alloc(rettv) == OK)
7289 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007290}
7291
7292/*
7293 * "job_setoptions()" function
7294 */
7295 static void
7296f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7297{
7298 job_T *job = get_job_arg(&argvars[0]);
7299 jobopt_T opt;
7300
7301 if (job == NULL)
7302 return;
7303 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007304 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007305 job_set_options(job, &opt);
7306 free_job_options(&opt);
7307}
7308
7309/*
7310 * "job_start()" function
7311 */
7312 static void
7313f_job_start(typval_T *argvars, typval_T *rettv)
7314{
7315 rettv->v_type = VAR_JOB;
7316 if (check_restricted() || check_secure())
7317 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007318 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319}
7320
7321/*
7322 * "job_status()" function
7323 */
7324 static void
7325f_job_status(typval_T *argvars, typval_T *rettv)
7326{
7327 job_T *job = get_job_arg(&argvars[0]);
7328
7329 if (job != NULL)
7330 {
7331 rettv->v_type = VAR_STRING;
7332 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7333 }
7334}
7335
7336/*
7337 * "job_stop()" function
7338 */
7339 static void
7340f_job_stop(typval_T *argvars, typval_T *rettv)
7341{
7342 job_T *job = get_job_arg(&argvars[0]);
7343
7344 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007345 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346}
7347#endif
7348
7349/*
7350 * "join()" function
7351 */
7352 static void
7353f_join(typval_T *argvars, typval_T *rettv)
7354{
7355 garray_T ga;
7356 char_u *sep;
7357
7358 if (argvars[0].v_type != VAR_LIST)
7359 {
7360 EMSG(_(e_listreq));
7361 return;
7362 }
7363 if (argvars[0].vval.v_list == NULL)
7364 return;
7365 if (argvars[1].v_type == VAR_UNKNOWN)
7366 sep = (char_u *)" ";
7367 else
7368 sep = get_tv_string_chk(&argvars[1]);
7369
7370 rettv->v_type = VAR_STRING;
7371
7372 if (sep != NULL)
7373 {
7374 ga_init2(&ga, (int)sizeof(char), 80);
7375 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7376 ga_append(&ga, NUL);
7377 rettv->vval.v_string = (char_u *)ga.ga_data;
7378 }
7379 else
7380 rettv->vval.v_string = NULL;
7381}
7382
7383/*
7384 * "js_decode()" function
7385 */
7386 static void
7387f_js_decode(typval_T *argvars, typval_T *rettv)
7388{
7389 js_read_T reader;
7390
7391 reader.js_buf = get_tv_string(&argvars[0]);
7392 reader.js_fill = NULL;
7393 reader.js_used = 0;
7394 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7395 EMSG(_(e_invarg));
7396}
7397
7398/*
7399 * "js_encode()" function
7400 */
7401 static void
7402f_js_encode(typval_T *argvars, typval_T *rettv)
7403{
7404 rettv->v_type = VAR_STRING;
7405 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7406}
7407
7408/*
7409 * "json_decode()" function
7410 */
7411 static void
7412f_json_decode(typval_T *argvars, typval_T *rettv)
7413{
7414 js_read_T reader;
7415
7416 reader.js_buf = get_tv_string(&argvars[0]);
7417 reader.js_fill = NULL;
7418 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007419 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007420}
7421
7422/*
7423 * "json_encode()" function
7424 */
7425 static void
7426f_json_encode(typval_T *argvars, typval_T *rettv)
7427{
7428 rettv->v_type = VAR_STRING;
7429 rettv->vval.v_string = json_encode(&argvars[0], 0);
7430}
7431
7432/*
7433 * "keys()" function
7434 */
7435 static void
7436f_keys(typval_T *argvars, typval_T *rettv)
7437{
7438 dict_list(argvars, rettv, 0);
7439}
7440
7441/*
7442 * "last_buffer_nr()" function.
7443 */
7444 static void
7445f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7446{
7447 int n = 0;
7448 buf_T *buf;
7449
Bram Moolenaar29323592016-07-24 22:04:11 +02007450 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007451 if (n < buf->b_fnum)
7452 n = buf->b_fnum;
7453
7454 rettv->vval.v_number = n;
7455}
7456
7457/*
7458 * "len()" function
7459 */
7460 static void
7461f_len(typval_T *argvars, typval_T *rettv)
7462{
7463 switch (argvars[0].v_type)
7464 {
7465 case VAR_STRING:
7466 case VAR_NUMBER:
7467 rettv->vval.v_number = (varnumber_T)STRLEN(
7468 get_tv_string(&argvars[0]));
7469 break;
7470 case VAR_LIST:
7471 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7472 break;
7473 case VAR_DICT:
7474 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7475 break;
7476 case VAR_UNKNOWN:
7477 case VAR_SPECIAL:
7478 case VAR_FLOAT:
7479 case VAR_FUNC:
7480 case VAR_PARTIAL:
7481 case VAR_JOB:
7482 case VAR_CHANNEL:
7483 EMSG(_("E701: Invalid type for len()"));
7484 break;
7485 }
7486}
7487
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007489libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007490{
7491#ifdef FEAT_LIBCALL
7492 char_u *string_in;
7493 char_u **string_result;
7494 int nr_result;
7495#endif
7496
7497 rettv->v_type = type;
7498 if (type != VAR_NUMBER)
7499 rettv->vval.v_string = NULL;
7500
7501 if (check_restricted() || check_secure())
7502 return;
7503
7504#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007505 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7507 {
7508 string_in = NULL;
7509 if (argvars[2].v_type == VAR_STRING)
7510 string_in = argvars[2].vval.v_string;
7511 if (type == VAR_NUMBER)
7512 string_result = NULL;
7513 else
7514 string_result = &rettv->vval.v_string;
7515 if (mch_libcall(argvars[0].vval.v_string,
7516 argvars[1].vval.v_string,
7517 string_in,
7518 argvars[2].vval.v_number,
7519 string_result,
7520 &nr_result) == OK
7521 && type == VAR_NUMBER)
7522 rettv->vval.v_number = nr_result;
7523 }
7524#endif
7525}
7526
7527/*
7528 * "libcall()" function
7529 */
7530 static void
7531f_libcall(typval_T *argvars, typval_T *rettv)
7532{
7533 libcall_common(argvars, rettv, VAR_STRING);
7534}
7535
7536/*
7537 * "libcallnr()" function
7538 */
7539 static void
7540f_libcallnr(typval_T *argvars, typval_T *rettv)
7541{
7542 libcall_common(argvars, rettv, VAR_NUMBER);
7543}
7544
7545/*
7546 * "line(string)" function
7547 */
7548 static void
7549f_line(typval_T *argvars, typval_T *rettv)
7550{
7551 linenr_T lnum = 0;
7552 pos_T *fp;
7553 int fnum;
7554
7555 fp = var2fpos(&argvars[0], TRUE, &fnum);
7556 if (fp != NULL)
7557 lnum = fp->lnum;
7558 rettv->vval.v_number = lnum;
7559}
7560
7561/*
7562 * "line2byte(lnum)" function
7563 */
7564 static void
7565f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7566{
7567#ifndef FEAT_BYTEOFF
7568 rettv->vval.v_number = -1;
7569#else
7570 linenr_T lnum;
7571
7572 lnum = get_tv_lnum(argvars);
7573 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7574 rettv->vval.v_number = -1;
7575 else
7576 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7577 if (rettv->vval.v_number >= 0)
7578 ++rettv->vval.v_number;
7579#endif
7580}
7581
7582/*
7583 * "lispindent(lnum)" function
7584 */
7585 static void
7586f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7587{
7588#ifdef FEAT_LISP
7589 pos_T pos;
7590 linenr_T lnum;
7591
7592 pos = curwin->w_cursor;
7593 lnum = get_tv_lnum(argvars);
7594 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7595 {
7596 curwin->w_cursor.lnum = lnum;
7597 rettv->vval.v_number = get_lisp_indent();
7598 curwin->w_cursor = pos;
7599 }
7600 else
7601#endif
7602 rettv->vval.v_number = -1;
7603}
7604
7605/*
7606 * "localtime()" function
7607 */
7608 static void
7609f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7610{
7611 rettv->vval.v_number = (varnumber_T)time(NULL);
7612}
7613
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007614 static void
7615get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7616{
7617 char_u *keys;
7618 char_u *which;
7619 char_u buf[NUMBUFLEN];
7620 char_u *keys_buf = NULL;
7621 char_u *rhs;
7622 int mode;
7623 int abbr = FALSE;
7624 int get_dict = FALSE;
7625 mapblock_T *mp;
7626 int buffer_local;
7627
7628 /* return empty string for failure */
7629 rettv->v_type = VAR_STRING;
7630 rettv->vval.v_string = NULL;
7631
7632 keys = get_tv_string(&argvars[0]);
7633 if (*keys == NUL)
7634 return;
7635
7636 if (argvars[1].v_type != VAR_UNKNOWN)
7637 {
7638 which = get_tv_string_buf_chk(&argvars[1], buf);
7639 if (argvars[2].v_type != VAR_UNKNOWN)
7640 {
7641 abbr = (int)get_tv_number(&argvars[2]);
7642 if (argvars[3].v_type != VAR_UNKNOWN)
7643 get_dict = (int)get_tv_number(&argvars[3]);
7644 }
7645 }
7646 else
7647 which = (char_u *)"";
7648 if (which == NULL)
7649 return;
7650
7651 mode = get_map_mode(&which, 0);
7652
7653 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7654 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7655 vim_free(keys_buf);
7656
7657 if (!get_dict)
7658 {
7659 /* Return a string. */
7660 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007661 {
7662 if (*rhs == NUL)
7663 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7664 else
7665 rettv->vval.v_string = str2special_save(rhs, FALSE);
7666 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667
7668 }
7669 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7670 {
7671 /* Return a dictionary. */
7672 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7673 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7674 dict_T *dict = rettv->vval.v_dict;
7675
Bram Moolenaare0be1672018-07-08 16:50:37 +02007676 dict_add_string(dict, "lhs", lhs);
7677 dict_add_string(dict, "rhs", mp->m_orig_str);
7678 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7679 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7680 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007681 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7682 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007683 dict_add_number(dict, "buffer", (long)buffer_local);
7684 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7685 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007686
7687 vim_free(lhs);
7688 vim_free(mapmode);
7689 }
7690}
7691
7692#ifdef FEAT_FLOAT
7693/*
7694 * "log()" function
7695 */
7696 static void
7697f_log(typval_T *argvars, typval_T *rettv)
7698{
7699 float_T f = 0.0;
7700
7701 rettv->v_type = VAR_FLOAT;
7702 if (get_float_arg(argvars, &f) == OK)
7703 rettv->vval.v_float = log(f);
7704 else
7705 rettv->vval.v_float = 0.0;
7706}
7707
7708/*
7709 * "log10()" function
7710 */
7711 static void
7712f_log10(typval_T *argvars, typval_T *rettv)
7713{
7714 float_T f = 0.0;
7715
7716 rettv->v_type = VAR_FLOAT;
7717 if (get_float_arg(argvars, &f) == OK)
7718 rettv->vval.v_float = log10(f);
7719 else
7720 rettv->vval.v_float = 0.0;
7721}
7722#endif
7723
7724#ifdef FEAT_LUA
7725/*
7726 * "luaeval()" function
7727 */
7728 static void
7729f_luaeval(typval_T *argvars, typval_T *rettv)
7730{
7731 char_u *str;
7732 char_u buf[NUMBUFLEN];
7733
7734 str = get_tv_string_buf(&argvars[0], buf);
7735 do_luaeval(str, argvars + 1, rettv);
7736}
7737#endif
7738
7739/*
7740 * "map()" function
7741 */
7742 static void
7743f_map(typval_T *argvars, typval_T *rettv)
7744{
7745 filter_map(argvars, rettv, TRUE);
7746}
7747
7748/*
7749 * "maparg()" function
7750 */
7751 static void
7752f_maparg(typval_T *argvars, typval_T *rettv)
7753{
7754 get_maparg(argvars, rettv, TRUE);
7755}
7756
7757/*
7758 * "mapcheck()" function
7759 */
7760 static void
7761f_mapcheck(typval_T *argvars, typval_T *rettv)
7762{
7763 get_maparg(argvars, rettv, FALSE);
7764}
7765
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007766typedef enum
7767{
7768 MATCH_END, /* matchend() */
7769 MATCH_MATCH, /* match() */
7770 MATCH_STR, /* matchstr() */
7771 MATCH_LIST, /* matchlist() */
7772 MATCH_POS /* matchstrpos() */
7773} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007774
7775 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007776find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777{
7778 char_u *str = NULL;
7779 long len = 0;
7780 char_u *expr = NULL;
7781 char_u *pat;
7782 regmatch_T regmatch;
7783 char_u patbuf[NUMBUFLEN];
7784 char_u strbuf[NUMBUFLEN];
7785 char_u *save_cpo;
7786 long start = 0;
7787 long nth = 1;
7788 colnr_T startcol = 0;
7789 int match = 0;
7790 list_T *l = NULL;
7791 listitem_T *li = NULL;
7792 long idx = 0;
7793 char_u *tofree = NULL;
7794
7795 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7796 save_cpo = p_cpo;
7797 p_cpo = (char_u *)"";
7798
7799 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007800 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007801 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007802 /* type MATCH_LIST: return empty list when there are no matches.
7803 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007804 if (rettv_list_alloc(rettv) == FAIL)
7805 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007806 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807 && (list_append_string(rettv->vval.v_list,
7808 (char_u *)"", 0) == FAIL
7809 || list_append_number(rettv->vval.v_list,
7810 (varnumber_T)-1) == FAIL
7811 || list_append_number(rettv->vval.v_list,
7812 (varnumber_T)-1) == FAIL
7813 || list_append_number(rettv->vval.v_list,
7814 (varnumber_T)-1) == FAIL))
7815 {
7816 list_free(rettv->vval.v_list);
7817 rettv->vval.v_list = NULL;
7818 goto theend;
7819 }
7820 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007821 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007822 {
7823 rettv->v_type = VAR_STRING;
7824 rettv->vval.v_string = NULL;
7825 }
7826
7827 if (argvars[0].v_type == VAR_LIST)
7828 {
7829 if ((l = argvars[0].vval.v_list) == NULL)
7830 goto theend;
7831 li = l->lv_first;
7832 }
7833 else
7834 {
7835 expr = str = get_tv_string(&argvars[0]);
7836 len = (long)STRLEN(str);
7837 }
7838
7839 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7840 if (pat == NULL)
7841 goto theend;
7842
7843 if (argvars[2].v_type != VAR_UNKNOWN)
7844 {
7845 int error = FALSE;
7846
7847 start = (long)get_tv_number_chk(&argvars[2], &error);
7848 if (error)
7849 goto theend;
7850 if (l != NULL)
7851 {
7852 li = list_find(l, start);
7853 if (li == NULL)
7854 goto theend;
7855 idx = l->lv_idx; /* use the cached index */
7856 }
7857 else
7858 {
7859 if (start < 0)
7860 start = 0;
7861 if (start > len)
7862 goto theend;
7863 /* When "count" argument is there ignore matches before "start",
7864 * otherwise skip part of the string. Differs when pattern is "^"
7865 * or "\<". */
7866 if (argvars[3].v_type != VAR_UNKNOWN)
7867 startcol = start;
7868 else
7869 {
7870 str += start;
7871 len -= start;
7872 }
7873 }
7874
7875 if (argvars[3].v_type != VAR_UNKNOWN)
7876 nth = (long)get_tv_number_chk(&argvars[3], &error);
7877 if (error)
7878 goto theend;
7879 }
7880
7881 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7882 if (regmatch.regprog != NULL)
7883 {
7884 regmatch.rm_ic = p_ic;
7885
7886 for (;;)
7887 {
7888 if (l != NULL)
7889 {
7890 if (li == NULL)
7891 {
7892 match = FALSE;
7893 break;
7894 }
7895 vim_free(tofree);
7896 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7897 if (str == NULL)
7898 break;
7899 }
7900
7901 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7902
7903 if (match && --nth <= 0)
7904 break;
7905 if (l == NULL && !match)
7906 break;
7907
7908 /* Advance to just after the match. */
7909 if (l != NULL)
7910 {
7911 li = li->li_next;
7912 ++idx;
7913 }
7914 else
7915 {
7916#ifdef FEAT_MBYTE
7917 startcol = (colnr_T)(regmatch.startp[0]
7918 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7919#else
7920 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7921#endif
7922 if (startcol > (colnr_T)len
7923 || str + startcol <= regmatch.startp[0])
7924 {
7925 match = FALSE;
7926 break;
7927 }
7928 }
7929 }
7930
7931 if (match)
7932 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007933 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007934 {
7935 listitem_T *li1 = rettv->vval.v_list->lv_first;
7936 listitem_T *li2 = li1->li_next;
7937 listitem_T *li3 = li2->li_next;
7938 listitem_T *li4 = li3->li_next;
7939
7940 vim_free(li1->li_tv.vval.v_string);
7941 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7942 (int)(regmatch.endp[0] - regmatch.startp[0]));
7943 li3->li_tv.vval.v_number =
7944 (varnumber_T)(regmatch.startp[0] - expr);
7945 li4->li_tv.vval.v_number =
7946 (varnumber_T)(regmatch.endp[0] - expr);
7947 if (l != NULL)
7948 li2->li_tv.vval.v_number = (varnumber_T)idx;
7949 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007950 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951 {
7952 int i;
7953
7954 /* return list with matched string and submatches */
7955 for (i = 0; i < NSUBEXP; ++i)
7956 {
7957 if (regmatch.endp[i] == NULL)
7958 {
7959 if (list_append_string(rettv->vval.v_list,
7960 (char_u *)"", 0) == FAIL)
7961 break;
7962 }
7963 else if (list_append_string(rettv->vval.v_list,
7964 regmatch.startp[i],
7965 (int)(regmatch.endp[i] - regmatch.startp[i]))
7966 == FAIL)
7967 break;
7968 }
7969 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007970 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007971 {
7972 /* return matched string */
7973 if (l != NULL)
7974 copy_tv(&li->li_tv, rettv);
7975 else
7976 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7977 (int)(regmatch.endp[0] - regmatch.startp[0]));
7978 }
7979 else if (l != NULL)
7980 rettv->vval.v_number = idx;
7981 else
7982 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007983 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984 rettv->vval.v_number =
7985 (varnumber_T)(regmatch.startp[0] - str);
7986 else
7987 rettv->vval.v_number =
7988 (varnumber_T)(regmatch.endp[0] - str);
7989 rettv->vval.v_number += (varnumber_T)(str - expr);
7990 }
7991 }
7992 vim_regfree(regmatch.regprog);
7993 }
7994
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007995theend:
7996 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997 /* matchstrpos() without a list: drop the second item. */
7998 listitem_remove(rettv->vval.v_list,
7999 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008000 vim_free(tofree);
8001 p_cpo = save_cpo;
8002}
8003
8004/*
8005 * "match()" function
8006 */
8007 static void
8008f_match(typval_T *argvars, typval_T *rettv)
8009{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008010 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011}
8012
Bram Moolenaar95e51472018-07-28 16:55:56 +02008013#ifdef FEAT_SEARCH_EXTRA
8014 static int
8015matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8016{
8017 dictitem_T *di;
8018
8019 if (tv->v_type != VAR_DICT)
8020 {
8021 EMSG(_(e_dictreq));
8022 return FAIL;
8023 }
8024
8025 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
8026 *conceal_char = get_dict_string(tv->vval.v_dict,
8027 (char_u *)"conceal", FALSE);
8028
8029 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8030 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008031 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008032 if (*win == NULL)
8033 {
8034 EMSG(_("E957: Invalid window number"));
8035 return FAIL;
8036 }
8037 }
8038
8039 return OK;
8040}
8041#endif
8042
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008043/*
8044 * "matchadd()" function
8045 */
8046 static void
8047f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8048{
8049#ifdef FEAT_SEARCH_EXTRA
8050 char_u buf[NUMBUFLEN];
8051 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
8052 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
8053 int prio = 10; /* default priority */
8054 int id = -1;
8055 int error = FALSE;
8056 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008057 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008058
8059 rettv->vval.v_number = -1;
8060
8061 if (grp == NULL || pat == NULL)
8062 return;
8063 if (argvars[2].v_type != VAR_UNKNOWN)
8064 {
8065 prio = (int)get_tv_number_chk(&argvars[2], &error);
8066 if (argvars[3].v_type != VAR_UNKNOWN)
8067 {
8068 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008069 if (argvars[4].v_type != VAR_UNKNOWN
8070 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8071 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008072 }
8073 }
8074 if (error == TRUE)
8075 return;
8076 if (id >= 1 && id <= 3)
8077 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008078 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 return;
8080 }
8081
Bram Moolenaar95e51472018-07-28 16:55:56 +02008082 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083 conceal_char);
8084#endif
8085}
8086
8087/*
8088 * "matchaddpos()" function
8089 */
8090 static void
8091f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8092{
8093#ifdef FEAT_SEARCH_EXTRA
8094 char_u buf[NUMBUFLEN];
8095 char_u *group;
8096 int prio = 10;
8097 int id = -1;
8098 int error = FALSE;
8099 list_T *l;
8100 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008101 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102
8103 rettv->vval.v_number = -1;
8104
8105 group = get_tv_string_buf_chk(&argvars[0], buf);
8106 if (group == NULL)
8107 return;
8108
8109 if (argvars[1].v_type != VAR_LIST)
8110 {
8111 EMSG2(_(e_listarg), "matchaddpos()");
8112 return;
8113 }
8114 l = argvars[1].vval.v_list;
8115 if (l == NULL)
8116 return;
8117
8118 if (argvars[2].v_type != VAR_UNKNOWN)
8119 {
8120 prio = (int)get_tv_number_chk(&argvars[2], &error);
8121 if (argvars[3].v_type != VAR_UNKNOWN)
8122 {
8123 id = (int)get_tv_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008124
8125 if (argvars[4].v_type != VAR_UNKNOWN
8126 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8127 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 }
8129 }
8130 if (error == TRUE)
8131 return;
8132
8133 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8134 if (id == 1 || id == 2)
8135 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008136 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137 return;
8138 }
8139
Bram Moolenaar95e51472018-07-28 16:55:56 +02008140 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141 conceal_char);
8142#endif
8143}
8144
8145/*
8146 * "matcharg()" function
8147 */
8148 static void
8149f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8150{
8151 if (rettv_list_alloc(rettv) == OK)
8152 {
8153#ifdef FEAT_SEARCH_EXTRA
8154 int id = (int)get_tv_number(&argvars[0]);
8155 matchitem_T *m;
8156
8157 if (id >= 1 && id <= 3)
8158 {
8159 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8160 {
8161 list_append_string(rettv->vval.v_list,
8162 syn_id2name(m->hlg_id), -1);
8163 list_append_string(rettv->vval.v_list, m->pattern, -1);
8164 }
8165 else
8166 {
8167 list_append_string(rettv->vval.v_list, NULL, -1);
8168 list_append_string(rettv->vval.v_list, NULL, -1);
8169 }
8170 }
8171#endif
8172 }
8173}
8174
8175/*
8176 * "matchdelete()" function
8177 */
8178 static void
8179f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8180{
8181#ifdef FEAT_SEARCH_EXTRA
8182 rettv->vval.v_number = match_delete(curwin,
8183 (int)get_tv_number(&argvars[0]), TRUE);
8184#endif
8185}
8186
8187/*
8188 * "matchend()" function
8189 */
8190 static void
8191f_matchend(typval_T *argvars, typval_T *rettv)
8192{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008193 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008194}
8195
8196/*
8197 * "matchlist()" function
8198 */
8199 static void
8200f_matchlist(typval_T *argvars, typval_T *rettv)
8201{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008202 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008203}
8204
8205/*
8206 * "matchstr()" function
8207 */
8208 static void
8209f_matchstr(typval_T *argvars, typval_T *rettv)
8210{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008211 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008212}
8213
8214/*
8215 * "matchstrpos()" function
8216 */
8217 static void
8218f_matchstrpos(typval_T *argvars, typval_T *rettv)
8219{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008220 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008221}
8222
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223 static void
8224max_min(typval_T *argvars, typval_T *rettv, int domax)
8225{
8226 varnumber_T n = 0;
8227 varnumber_T i;
8228 int error = FALSE;
8229
8230 if (argvars[0].v_type == VAR_LIST)
8231 {
8232 list_T *l;
8233 listitem_T *li;
8234
8235 l = argvars[0].vval.v_list;
8236 if (l != NULL)
8237 {
8238 li = l->lv_first;
8239 if (li != NULL)
8240 {
8241 n = get_tv_number_chk(&li->li_tv, &error);
8242 for (;;)
8243 {
8244 li = li->li_next;
8245 if (li == NULL)
8246 break;
8247 i = get_tv_number_chk(&li->li_tv, &error);
8248 if (domax ? i > n : i < n)
8249 n = i;
8250 }
8251 }
8252 }
8253 }
8254 else if (argvars[0].v_type == VAR_DICT)
8255 {
8256 dict_T *d;
8257 int first = TRUE;
8258 hashitem_T *hi;
8259 int todo;
8260
8261 d = argvars[0].vval.v_dict;
8262 if (d != NULL)
8263 {
8264 todo = (int)d->dv_hashtab.ht_used;
8265 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8266 {
8267 if (!HASHITEM_EMPTY(hi))
8268 {
8269 --todo;
8270 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8271 if (first)
8272 {
8273 n = i;
8274 first = FALSE;
8275 }
8276 else if (domax ? i > n : i < n)
8277 n = i;
8278 }
8279 }
8280 }
8281 }
8282 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008283 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008284 rettv->vval.v_number = error ? 0 : n;
8285}
8286
8287/*
8288 * "max()" function
8289 */
8290 static void
8291f_max(typval_T *argvars, typval_T *rettv)
8292{
8293 max_min(argvars, rettv, TRUE);
8294}
8295
8296/*
8297 * "min()" function
8298 */
8299 static void
8300f_min(typval_T *argvars, typval_T *rettv)
8301{
8302 max_min(argvars, rettv, FALSE);
8303}
8304
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305/*
8306 * Create the directory in which "dir" is located, and higher levels when
8307 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008308 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008309 */
8310 static int
8311mkdir_recurse(char_u *dir, int prot)
8312{
8313 char_u *p;
8314 char_u *updir;
8315 int r = FAIL;
8316
8317 /* Get end of directory name in "dir".
8318 * We're done when it's "/" or "c:/". */
8319 p = gettail_sep(dir);
8320 if (p <= get_past_head(dir))
8321 return OK;
8322
8323 /* If the directory exists we're done. Otherwise: create it.*/
8324 updir = vim_strnsave(dir, (int)(p - dir));
8325 if (updir == NULL)
8326 return FAIL;
8327 if (mch_isdir(updir))
8328 r = OK;
8329 else if (mkdir_recurse(updir, prot) == OK)
8330 r = vim_mkdir_emsg(updir, prot);
8331 vim_free(updir);
8332 return r;
8333}
8334
8335#ifdef vim_mkdir
8336/*
8337 * "mkdir()" function
8338 */
8339 static void
8340f_mkdir(typval_T *argvars, typval_T *rettv)
8341{
8342 char_u *dir;
8343 char_u buf[NUMBUFLEN];
8344 int prot = 0755;
8345
8346 rettv->vval.v_number = FAIL;
8347 if (check_restricted() || check_secure())
8348 return;
8349
8350 dir = get_tv_string_buf(&argvars[0], buf);
8351 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008352 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008354 if (*gettail(dir) == NUL)
8355 /* remove trailing slashes */
8356 *gettail_sep(dir) = NUL;
8357
8358 if (argvars[1].v_type != VAR_UNKNOWN)
8359 {
8360 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008361 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008362 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8363 if (prot == -1)
8364 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008365 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008366 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8367 {
8368 if (mch_isdir(dir))
8369 {
8370 /* With the "p" flag it's OK if the dir already exists. */
8371 rettv->vval.v_number = OK;
8372 return;
8373 }
8374 mkdir_recurse(dir, prot);
8375 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008377 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008378}
8379#endif
8380
8381/*
8382 * "mode()" function
8383 */
8384 static void
8385f_mode(typval_T *argvars, typval_T *rettv)
8386{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008387 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388
Bram Moolenaar612cc382018-07-29 15:34:26 +02008389 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390
8391 if (time_for_testing == 93784)
8392 {
8393 /* Testing the two-character code. */
8394 buf[0] = 'x';
8395 buf[1] = '!';
8396 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008397#ifdef FEAT_TERMINAL
8398 else if (term_use_loop())
8399 buf[0] = 't';
8400#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008401 else if (VIsual_active)
8402 {
8403 if (VIsual_select)
8404 buf[0] = VIsual_mode + 's' - 'v';
8405 else
8406 buf[0] = VIsual_mode;
8407 }
8408 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8409 || State == CONFIRM)
8410 {
8411 buf[0] = 'r';
8412 if (State == ASKMORE)
8413 buf[1] = 'm';
8414 else if (State == CONFIRM)
8415 buf[1] = '?';
8416 }
8417 else if (State == EXTERNCMD)
8418 buf[0] = '!';
8419 else if (State & INSERT)
8420 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008421 if (State & VREPLACE_FLAG)
8422 {
8423 buf[0] = 'R';
8424 buf[1] = 'v';
8425 }
8426 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008427 {
8428 if (State & REPLACE_FLAG)
8429 buf[0] = 'R';
8430 else
8431 buf[0] = 'i';
8432#ifdef FEAT_INS_EXPAND
8433 if (ins_compl_active())
8434 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008435 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008436 buf[1] = 'x';
8437#endif
8438 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008439 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008440 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008441 {
8442 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008443 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008444 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008445 else if (exmode_active == EXMODE_NORMAL)
8446 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008447 }
8448 else
8449 {
8450 buf[0] = 'n';
8451 if (finish_op)
8452 buf[1] = 'o';
Bram Moolenaar612cc382018-07-29 15:34:26 +02008453 else if (restart_edit == 'I' || restart_edit == 'R'
8454 || restart_edit == 'V')
8455 {
8456 buf[1] = 'i';
8457 buf[2] = restart_edit;
8458 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459 }
8460
8461 /* Clear out the minor mode when the argument is not a non-zero number or
8462 * non-empty string. */
8463 if (!non_zero_arg(&argvars[0]))
8464 buf[1] = NUL;
8465
8466 rettv->vval.v_string = vim_strsave(buf);
8467 rettv->v_type = VAR_STRING;
8468}
8469
8470#if defined(FEAT_MZSCHEME) || defined(PROTO)
8471/*
8472 * "mzeval()" function
8473 */
8474 static void
8475f_mzeval(typval_T *argvars, typval_T *rettv)
8476{
8477 char_u *str;
8478 char_u buf[NUMBUFLEN];
8479
8480 str = get_tv_string_buf(&argvars[0], buf);
8481 do_mzeval(str, rettv);
8482}
8483
8484 void
8485mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8486{
8487 typval_T argvars[3];
8488
8489 argvars[0].v_type = VAR_STRING;
8490 argvars[0].vval.v_string = name;
8491 copy_tv(args, &argvars[1]);
8492 argvars[2].v_type = VAR_UNKNOWN;
8493 f_call(argvars, rettv);
8494 clear_tv(&argvars[1]);
8495}
8496#endif
8497
8498/*
8499 * "nextnonblank()" function
8500 */
8501 static void
8502f_nextnonblank(typval_T *argvars, typval_T *rettv)
8503{
8504 linenr_T lnum;
8505
8506 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8507 {
8508 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8509 {
8510 lnum = 0;
8511 break;
8512 }
8513 if (*skipwhite(ml_get(lnum)) != NUL)
8514 break;
8515 }
8516 rettv->vval.v_number = lnum;
8517}
8518
8519/*
8520 * "nr2char()" function
8521 */
8522 static void
8523f_nr2char(typval_T *argvars, typval_T *rettv)
8524{
8525 char_u buf[NUMBUFLEN];
8526
8527#ifdef FEAT_MBYTE
8528 if (has_mbyte)
8529 {
8530 int utf8 = 0;
8531
8532 if (argvars[1].v_type != VAR_UNKNOWN)
8533 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8534 if (utf8)
8535 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8536 else
8537 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8538 }
8539 else
8540#endif
8541 {
8542 buf[0] = (char_u)get_tv_number(&argvars[0]);
8543 buf[1] = NUL;
8544 }
8545 rettv->v_type = VAR_STRING;
8546 rettv->vval.v_string = vim_strsave(buf);
8547}
8548
8549/*
8550 * "or(expr, expr)" function
8551 */
8552 static void
8553f_or(typval_T *argvars, typval_T *rettv)
8554{
8555 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8556 | get_tv_number_chk(&argvars[1], NULL);
8557}
8558
8559/*
8560 * "pathshorten()" function
8561 */
8562 static void
8563f_pathshorten(typval_T *argvars, typval_T *rettv)
8564{
8565 char_u *p;
8566
8567 rettv->v_type = VAR_STRING;
8568 p = get_tv_string_chk(&argvars[0]);
8569 if (p == NULL)
8570 rettv->vval.v_string = NULL;
8571 else
8572 {
8573 p = vim_strsave(p);
8574 rettv->vval.v_string = p;
8575 if (p != NULL)
8576 shorten_dir(p);
8577 }
8578}
8579
8580#ifdef FEAT_PERL
8581/*
8582 * "perleval()" function
8583 */
8584 static void
8585f_perleval(typval_T *argvars, typval_T *rettv)
8586{
8587 char_u *str;
8588 char_u buf[NUMBUFLEN];
8589
8590 str = get_tv_string_buf(&argvars[0], buf);
8591 do_perleval(str, rettv);
8592}
8593#endif
8594
8595#ifdef FEAT_FLOAT
8596/*
8597 * "pow()" function
8598 */
8599 static void
8600f_pow(typval_T *argvars, typval_T *rettv)
8601{
8602 float_T fx = 0.0, fy = 0.0;
8603
8604 rettv->v_type = VAR_FLOAT;
8605 if (get_float_arg(argvars, &fx) == OK
8606 && get_float_arg(&argvars[1], &fy) == OK)
8607 rettv->vval.v_float = pow(fx, fy);
8608 else
8609 rettv->vval.v_float = 0.0;
8610}
8611#endif
8612
8613/*
8614 * "prevnonblank()" function
8615 */
8616 static void
8617f_prevnonblank(typval_T *argvars, typval_T *rettv)
8618{
8619 linenr_T lnum;
8620
8621 lnum = get_tv_lnum(argvars);
8622 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8623 lnum = 0;
8624 else
8625 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8626 --lnum;
8627 rettv->vval.v_number = lnum;
8628}
8629
8630/* This dummy va_list is here because:
8631 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8632 * - locally in the function results in a "used before set" warning
8633 * - using va_start() to initialize it gives "function with fixed args" error */
8634static va_list ap;
8635
8636/*
8637 * "printf()" function
8638 */
8639 static void
8640f_printf(typval_T *argvars, typval_T *rettv)
8641{
8642 char_u buf[NUMBUFLEN];
8643 int len;
8644 char_u *s;
8645 int saved_did_emsg = did_emsg;
8646 char *fmt;
8647
8648 rettv->v_type = VAR_STRING;
8649 rettv->vval.v_string = NULL;
8650
8651 /* Get the required length, allocate the buffer and do it for real. */
8652 did_emsg = FALSE;
8653 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008654 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008655 if (!did_emsg)
8656 {
8657 s = alloc(len + 1);
8658 if (s != NULL)
8659 {
8660 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008661 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8662 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008663 }
8664 }
8665 did_emsg |= saved_did_emsg;
8666}
8667
Bram Moolenaarf2732452018-06-03 14:47:35 +02008668#ifdef FEAT_JOB_CHANNEL
8669/*
8670 * "prompt_setcallback({buffer}, {callback})" function
8671 */
8672 static void
8673f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8674{
8675 buf_T *buf;
8676 char_u *callback;
8677 partial_T *partial;
8678
8679 if (check_secure())
8680 return;
8681 buf = get_buf_tv(&argvars[0], FALSE);
8682 if (buf == NULL)
8683 return;
8684
8685 callback = get_callback(&argvars[1], &partial);
8686 if (callback == NULL)
8687 return;
8688
8689 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8690 if (partial == NULL)
8691 buf->b_prompt_callback = vim_strsave(callback);
8692 else
8693 /* pointer into the partial */
8694 buf->b_prompt_callback = callback;
8695 buf->b_prompt_partial = partial;
8696}
8697
8698/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008699 * "prompt_setinterrupt({buffer}, {callback})" function
8700 */
8701 static void
8702f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8703{
8704 buf_T *buf;
8705 char_u *callback;
8706 partial_T *partial;
8707
8708 if (check_secure())
8709 return;
8710 buf = get_buf_tv(&argvars[0], FALSE);
8711 if (buf == NULL)
8712 return;
8713
8714 callback = get_callback(&argvars[1], &partial);
8715 if (callback == NULL)
8716 return;
8717
8718 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8719 if (partial == NULL)
8720 buf->b_prompt_interrupt = vim_strsave(callback);
8721 else
8722 /* pointer into the partial */
8723 buf->b_prompt_interrupt = callback;
8724 buf->b_prompt_int_partial = partial;
8725}
8726
8727/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008728 * "prompt_setprompt({buffer}, {text})" function
8729 */
8730 static void
8731f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8732{
8733 buf_T *buf;
8734 char_u *text;
8735
8736 if (check_secure())
8737 return;
8738 buf = get_buf_tv(&argvars[0], FALSE);
8739 if (buf == NULL)
8740 return;
8741
8742 text = get_tv_string(&argvars[1]);
8743 vim_free(buf->b_prompt_text);
8744 buf->b_prompt_text = vim_strsave(text);
8745}
8746#endif
8747
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008748/*
8749 * "pumvisible()" function
8750 */
8751 static void
8752f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8753{
8754#ifdef FEAT_INS_EXPAND
8755 if (pum_visible())
8756 rettv->vval.v_number = 1;
8757#endif
8758}
8759
8760#ifdef FEAT_PYTHON3
8761/*
8762 * "py3eval()" function
8763 */
8764 static void
8765f_py3eval(typval_T *argvars, typval_T *rettv)
8766{
8767 char_u *str;
8768 char_u buf[NUMBUFLEN];
8769
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008770 if (p_pyx == 0)
8771 p_pyx = 3;
8772
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008773 str = get_tv_string_buf(&argvars[0], buf);
8774 do_py3eval(str, rettv);
8775}
8776#endif
8777
8778#ifdef FEAT_PYTHON
8779/*
8780 * "pyeval()" function
8781 */
8782 static void
8783f_pyeval(typval_T *argvars, typval_T *rettv)
8784{
8785 char_u *str;
8786 char_u buf[NUMBUFLEN];
8787
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008788 if (p_pyx == 0)
8789 p_pyx = 2;
8790
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008791 str = get_tv_string_buf(&argvars[0], buf);
8792 do_pyeval(str, rettv);
8793}
8794#endif
8795
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008796#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8797/*
8798 * "pyxeval()" function
8799 */
8800 static void
8801f_pyxeval(typval_T *argvars, typval_T *rettv)
8802{
8803# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8804 init_pyxversion();
8805 if (p_pyx == 2)
8806 f_pyeval(argvars, rettv);
8807 else
8808 f_py3eval(argvars, rettv);
8809# elif defined(FEAT_PYTHON)
8810 f_pyeval(argvars, rettv);
8811# elif defined(FEAT_PYTHON3)
8812 f_py3eval(argvars, rettv);
8813# endif
8814}
8815#endif
8816
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008817/*
8818 * "range()" function
8819 */
8820 static void
8821f_range(typval_T *argvars, typval_T *rettv)
8822{
8823 varnumber_T start;
8824 varnumber_T end;
8825 varnumber_T stride = 1;
8826 varnumber_T i;
8827 int error = FALSE;
8828
8829 start = get_tv_number_chk(&argvars[0], &error);
8830 if (argvars[1].v_type == VAR_UNKNOWN)
8831 {
8832 end = start - 1;
8833 start = 0;
8834 }
8835 else
8836 {
8837 end = get_tv_number_chk(&argvars[1], &error);
8838 if (argvars[2].v_type != VAR_UNKNOWN)
8839 stride = get_tv_number_chk(&argvars[2], &error);
8840 }
8841
8842 if (error)
8843 return; /* type error; errmsg already given */
8844 if (stride == 0)
8845 EMSG(_("E726: Stride is zero"));
8846 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8847 EMSG(_("E727: Start past end"));
8848 else
8849 {
8850 if (rettv_list_alloc(rettv) == OK)
8851 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8852 if (list_append_number(rettv->vval.v_list,
8853 (varnumber_T)i) == FAIL)
8854 break;
8855 }
8856}
8857
8858/*
8859 * "readfile()" function
8860 */
8861 static void
8862f_readfile(typval_T *argvars, typval_T *rettv)
8863{
8864 int binary = FALSE;
8865 int failed = FALSE;
8866 char_u *fname;
8867 FILE *fd;
8868 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8869 int io_size = sizeof(buf);
8870 int readlen; /* size of last fread() */
8871 char_u *prev = NULL; /* previously read bytes, if any */
8872 long prevlen = 0; /* length of data in prev */
8873 long prevsize = 0; /* size of prev buffer */
8874 long maxline = MAXLNUM;
8875 long cnt = 0;
8876 char_u *p; /* position in buf */
8877 char_u *start; /* start of current line */
8878
8879 if (argvars[1].v_type != VAR_UNKNOWN)
8880 {
8881 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8882 binary = TRUE;
8883 if (argvars[2].v_type != VAR_UNKNOWN)
8884 maxline = (long)get_tv_number(&argvars[2]);
8885 }
8886
8887 if (rettv_list_alloc(rettv) == FAIL)
8888 return;
8889
8890 /* Always open the file in binary mode, library functions have a mind of
8891 * their own about CR-LF conversion. */
8892 fname = get_tv_string(&argvars[0]);
8893 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8894 {
8895 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8896 return;
8897 }
8898
8899 while (cnt < maxline || maxline < 0)
8900 {
8901 readlen = (int)fread(buf, 1, io_size, fd);
8902
8903 /* This for loop processes what was read, but is also entered at end
8904 * of file so that either:
8905 * - an incomplete line gets written
8906 * - a "binary" file gets an empty line at the end if it ends in a
8907 * newline. */
8908 for (p = buf, start = buf;
8909 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8910 ++p)
8911 {
8912 if (*p == '\n' || readlen <= 0)
8913 {
8914 listitem_T *li;
8915 char_u *s = NULL;
8916 long_u len = p - start;
8917
8918 /* Finished a line. Remove CRs before NL. */
8919 if (readlen > 0 && !binary)
8920 {
8921 while (len > 0 && start[len - 1] == '\r')
8922 --len;
8923 /* removal may cross back to the "prev" string */
8924 if (len == 0)
8925 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8926 --prevlen;
8927 }
8928 if (prevlen == 0)
8929 s = vim_strnsave(start, (int)len);
8930 else
8931 {
8932 /* Change "prev" buffer to be the right size. This way
8933 * the bytes are only copied once, and very long lines are
8934 * allocated only once. */
8935 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8936 {
8937 mch_memmove(s + prevlen, start, len);
8938 s[prevlen + len] = NUL;
8939 prev = NULL; /* the list will own the string */
8940 prevlen = prevsize = 0;
8941 }
8942 }
8943 if (s == NULL)
8944 {
8945 do_outofmem_msg((long_u) prevlen + len + 1);
8946 failed = TRUE;
8947 break;
8948 }
8949
8950 if ((li = listitem_alloc()) == NULL)
8951 {
8952 vim_free(s);
8953 failed = TRUE;
8954 break;
8955 }
8956 li->li_tv.v_type = VAR_STRING;
8957 li->li_tv.v_lock = 0;
8958 li->li_tv.vval.v_string = s;
8959 list_append(rettv->vval.v_list, li);
8960
8961 start = p + 1; /* step over newline */
8962 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8963 break;
8964 }
8965 else if (*p == NUL)
8966 *p = '\n';
8967#ifdef FEAT_MBYTE
8968 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8969 * when finding the BF and check the previous two bytes. */
8970 else if (*p == 0xbf && enc_utf8 && !binary)
8971 {
8972 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8973 * + 1, these may be in the "prev" string. */
8974 char_u back1 = p >= buf + 1 ? p[-1]
8975 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8976 char_u back2 = p >= buf + 2 ? p[-2]
8977 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8978 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8979
8980 if (back2 == 0xef && back1 == 0xbb)
8981 {
8982 char_u *dest = p - 2;
8983
8984 /* Usually a BOM is at the beginning of a file, and so at
8985 * the beginning of a line; then we can just step over it.
8986 */
8987 if (start == dest)
8988 start = p + 1;
8989 else
8990 {
8991 /* have to shuffle buf to close gap */
8992 int adjust_prevlen = 0;
8993
8994 if (dest < buf)
8995 {
8996 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8997 dest = buf;
8998 }
8999 if (readlen > p - buf + 1)
9000 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9001 readlen -= 3 - adjust_prevlen;
9002 prevlen -= adjust_prevlen;
9003 p = dest - 1;
9004 }
9005 }
9006 }
9007#endif
9008 } /* for */
9009
9010 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9011 break;
9012 if (start < p)
9013 {
9014 /* There's part of a line in buf, store it in "prev". */
9015 if (p - start + prevlen >= prevsize)
9016 {
9017 /* need bigger "prev" buffer */
9018 char_u *newprev;
9019
9020 /* A common use case is ordinary text files and "prev" gets a
9021 * fragment of a line, so the first allocation is made
9022 * small, to avoid repeatedly 'allocing' large and
9023 * 'reallocing' small. */
9024 if (prevsize == 0)
9025 prevsize = (long)(p - start);
9026 else
9027 {
9028 long grow50pc = (prevsize * 3) / 2;
9029 long growmin = (long)((p - start) * 2 + prevlen);
9030 prevsize = grow50pc > growmin ? grow50pc : growmin;
9031 }
9032 newprev = prev == NULL ? alloc(prevsize)
9033 : vim_realloc(prev, prevsize);
9034 if (newprev == NULL)
9035 {
9036 do_outofmem_msg((long_u)prevsize);
9037 failed = TRUE;
9038 break;
9039 }
9040 prev = newprev;
9041 }
9042 /* Add the line part to end of "prev". */
9043 mch_memmove(prev + prevlen, start, p - start);
9044 prevlen += (long)(p - start);
9045 }
9046 } /* while */
9047
9048 /*
9049 * For a negative line count use only the lines at the end of the file,
9050 * free the rest.
9051 */
9052 if (!failed && maxline < 0)
9053 while (cnt > -maxline)
9054 {
9055 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9056 --cnt;
9057 }
9058
9059 if (failed)
9060 {
9061 list_free(rettv->vval.v_list);
9062 /* readfile doc says an empty list is returned on error */
9063 rettv->vval.v_list = list_alloc();
9064 }
9065
9066 vim_free(prev);
9067 fclose(fd);
9068}
9069
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009070 static void
9071return_register(int regname, typval_T *rettv)
9072{
9073 char_u buf[2] = {0, 0};
9074
9075 buf[0] = (char_u)regname;
9076 rettv->v_type = VAR_STRING;
9077 rettv->vval.v_string = vim_strsave(buf);
9078}
9079
9080/*
9081 * "reg_executing()" function
9082 */
9083 static void
9084f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9085{
9086 return_register(reg_executing, rettv);
9087}
9088
9089/*
9090 * "reg_recording()" function
9091 */
9092 static void
9093f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9094{
9095 return_register(reg_recording, rettv);
9096}
9097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009098#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009099/*
9100 * Convert a List to proftime_T.
9101 * Return FAIL when there is something wrong.
9102 */
9103 static int
9104list2proftime(typval_T *arg, proftime_T *tm)
9105{
9106 long n1, n2;
9107 int error = FALSE;
9108
9109 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9110 || arg->vval.v_list->lv_len != 2)
9111 return FAIL;
9112 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9113 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9114# ifdef WIN3264
9115 tm->HighPart = n1;
9116 tm->LowPart = n2;
9117# else
9118 tm->tv_sec = n1;
9119 tm->tv_usec = n2;
9120# endif
9121 return error ? FAIL : OK;
9122}
9123#endif /* FEAT_RELTIME */
9124
9125/*
9126 * "reltime()" function
9127 */
9128 static void
9129f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9130{
9131#ifdef FEAT_RELTIME
9132 proftime_T res;
9133 proftime_T start;
9134
9135 if (argvars[0].v_type == VAR_UNKNOWN)
9136 {
9137 /* No arguments: get current time. */
9138 profile_start(&res);
9139 }
9140 else if (argvars[1].v_type == VAR_UNKNOWN)
9141 {
9142 if (list2proftime(&argvars[0], &res) == FAIL)
9143 return;
9144 profile_end(&res);
9145 }
9146 else
9147 {
9148 /* Two arguments: compute the difference. */
9149 if (list2proftime(&argvars[0], &start) == FAIL
9150 || list2proftime(&argvars[1], &res) == FAIL)
9151 return;
9152 profile_sub(&res, &start);
9153 }
9154
9155 if (rettv_list_alloc(rettv) == OK)
9156 {
9157 long n1, n2;
9158
9159# ifdef WIN3264
9160 n1 = res.HighPart;
9161 n2 = res.LowPart;
9162# else
9163 n1 = res.tv_sec;
9164 n2 = res.tv_usec;
9165# endif
9166 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9167 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9168 }
9169#endif
9170}
9171
9172#ifdef FEAT_FLOAT
9173/*
9174 * "reltimefloat()" function
9175 */
9176 static void
9177f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9178{
9179# ifdef FEAT_RELTIME
9180 proftime_T tm;
9181# endif
9182
9183 rettv->v_type = VAR_FLOAT;
9184 rettv->vval.v_float = 0;
9185# ifdef FEAT_RELTIME
9186 if (list2proftime(&argvars[0], &tm) == OK)
9187 rettv->vval.v_float = profile_float(&tm);
9188# endif
9189}
9190#endif
9191
9192/*
9193 * "reltimestr()" function
9194 */
9195 static void
9196f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9197{
9198#ifdef FEAT_RELTIME
9199 proftime_T tm;
9200#endif
9201
9202 rettv->v_type = VAR_STRING;
9203 rettv->vval.v_string = NULL;
9204#ifdef FEAT_RELTIME
9205 if (list2proftime(&argvars[0], &tm) == OK)
9206 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9207#endif
9208}
9209
9210#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009211 static void
9212make_connection(void)
9213{
9214 if (X_DISPLAY == NULL
9215# ifdef FEAT_GUI
9216 && !gui.in_use
9217# endif
9218 )
9219 {
9220 x_force_connect = TRUE;
9221 setup_term_clip();
9222 x_force_connect = FALSE;
9223 }
9224}
9225
9226 static int
9227check_connection(void)
9228{
9229 make_connection();
9230 if (X_DISPLAY == NULL)
9231 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009232 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009233 return FAIL;
9234 }
9235 return OK;
9236}
9237#endif
9238
9239#ifdef FEAT_CLIENTSERVER
9240 static void
9241remote_common(typval_T *argvars, typval_T *rettv, int expr)
9242{
9243 char_u *server_name;
9244 char_u *keys;
9245 char_u *r = NULL;
9246 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009247 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009248# ifdef WIN32
9249 HWND w;
9250# else
9251 Window w;
9252# endif
9253
9254 if (check_restricted() || check_secure())
9255 return;
9256
9257# ifdef FEAT_X11
9258 if (check_connection() == FAIL)
9259 return;
9260# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009261 if (argvars[2].v_type != VAR_UNKNOWN
9262 && argvars[3].v_type != VAR_UNKNOWN)
9263 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009264
9265 server_name = get_tv_string_chk(&argvars[0]);
9266 if (server_name == NULL)
9267 return; /* type error; errmsg already given */
9268 keys = get_tv_string_buf(&argvars[1], buf);
9269# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009270 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009271# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009272 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9273 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009274# endif
9275 {
9276 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009277 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009278 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009279 vim_free(r);
9280 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009281 else
9282 EMSG2(_("E241: Unable to send to %s"), server_name);
9283 return;
9284 }
9285
9286 rettv->vval.v_string = r;
9287
9288 if (argvars[2].v_type != VAR_UNKNOWN)
9289 {
9290 dictitem_T v;
9291 char_u str[30];
9292 char_u *idvar;
9293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009294 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009295 if (idvar != NULL && *idvar != NUL)
9296 {
9297 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9298 v.di_tv.v_type = VAR_STRING;
9299 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009300 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009301 vim_free(v.di_tv.vval.v_string);
9302 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009303 }
9304}
9305#endif
9306
9307/*
9308 * "remote_expr()" function
9309 */
9310 static void
9311f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9312{
9313 rettv->v_type = VAR_STRING;
9314 rettv->vval.v_string = NULL;
9315#ifdef FEAT_CLIENTSERVER
9316 remote_common(argvars, rettv, TRUE);
9317#endif
9318}
9319
9320/*
9321 * "remote_foreground()" function
9322 */
9323 static void
9324f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9325{
9326#ifdef FEAT_CLIENTSERVER
9327# ifdef WIN32
9328 /* On Win32 it's done in this application. */
9329 {
9330 char_u *server_name = get_tv_string_chk(&argvars[0]);
9331
9332 if (server_name != NULL)
9333 serverForeground(server_name);
9334 }
9335# else
9336 /* Send a foreground() expression to the server. */
9337 argvars[1].v_type = VAR_STRING;
9338 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9339 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009340 rettv->v_type = VAR_STRING;
9341 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009342 remote_common(argvars, rettv, TRUE);
9343 vim_free(argvars[1].vval.v_string);
9344# endif
9345#endif
9346}
9347
9348 static void
9349f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9350{
9351#ifdef FEAT_CLIENTSERVER
9352 dictitem_T v;
9353 char_u *s = NULL;
9354# ifdef WIN32
9355 long_u n = 0;
9356# endif
9357 char_u *serverid;
9358
9359 if (check_restricted() || check_secure())
9360 {
9361 rettv->vval.v_number = -1;
9362 return;
9363 }
9364 serverid = get_tv_string_chk(&argvars[0]);
9365 if (serverid == NULL)
9366 {
9367 rettv->vval.v_number = -1;
9368 return; /* type error; errmsg already given */
9369 }
9370# ifdef WIN32
9371 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9372 if (n == 0)
9373 rettv->vval.v_number = -1;
9374 else
9375 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009376 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009377 rettv->vval.v_number = (s != NULL);
9378 }
9379# else
9380 if (check_connection() == FAIL)
9381 return;
9382
9383 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9384 serverStrToWin(serverid), &s);
9385# endif
9386
9387 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9388 {
9389 char_u *retvar;
9390
9391 v.di_tv.v_type = VAR_STRING;
9392 v.di_tv.vval.v_string = vim_strsave(s);
9393 retvar = get_tv_string_chk(&argvars[1]);
9394 if (retvar != NULL)
9395 set_var(retvar, &v.di_tv, FALSE);
9396 vim_free(v.di_tv.vval.v_string);
9397 }
9398#else
9399 rettv->vval.v_number = -1;
9400#endif
9401}
9402
9403 static void
9404f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9405{
9406 char_u *r = NULL;
9407
9408#ifdef FEAT_CLIENTSERVER
9409 char_u *serverid = get_tv_string_chk(&argvars[0]);
9410
9411 if (serverid != NULL && !check_restricted() && !check_secure())
9412 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009413 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009414# ifdef WIN32
9415 /* The server's HWND is encoded in the 'id' parameter */
9416 long_u n = 0;
9417# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009418
9419 if (argvars[1].v_type != VAR_UNKNOWN)
9420 timeout = get_tv_number(&argvars[1]);
9421
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009422# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009423 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9424 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009425 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009426 if (r == NULL)
9427# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009428 if (check_connection() == FAIL
9429 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9430 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009431# endif
9432 EMSG(_("E277: Unable to read a server reply"));
9433 }
9434#endif
9435 rettv->v_type = VAR_STRING;
9436 rettv->vval.v_string = r;
9437}
9438
9439/*
9440 * "remote_send()" function
9441 */
9442 static void
9443f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9444{
9445 rettv->v_type = VAR_STRING;
9446 rettv->vval.v_string = NULL;
9447#ifdef FEAT_CLIENTSERVER
9448 remote_common(argvars, rettv, FALSE);
9449#endif
9450}
9451
9452/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009453 * "remote_startserver()" function
9454 */
9455 static void
9456f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9457{
9458#ifdef FEAT_CLIENTSERVER
9459 char_u *server = get_tv_string_chk(&argvars[0]);
9460
9461 if (server == NULL)
9462 return; /* type error; errmsg already given */
9463 if (serverName != NULL)
9464 EMSG(_("E941: already started a server"));
9465 else
9466 {
9467# ifdef FEAT_X11
9468 if (check_connection() == OK)
9469 serverRegisterName(X_DISPLAY, server);
9470# else
9471 serverSetName(server);
9472# endif
9473 }
9474#else
9475 EMSG(_("E942: +clientserver feature not available"));
9476#endif
9477}
9478
9479/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009480 * "remove()" function
9481 */
9482 static void
9483f_remove(typval_T *argvars, typval_T *rettv)
9484{
9485 list_T *l;
9486 listitem_T *item, *item2;
9487 listitem_T *li;
9488 long idx;
9489 long end;
9490 char_u *key;
9491 dict_T *d;
9492 dictitem_T *di;
9493 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9494
9495 if (argvars[0].v_type == VAR_DICT)
9496 {
9497 if (argvars[2].v_type != VAR_UNKNOWN)
9498 EMSG2(_(e_toomanyarg), "remove()");
9499 else if ((d = argvars[0].vval.v_dict) != NULL
9500 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9501 {
9502 key = get_tv_string_chk(&argvars[1]);
9503 if (key != NULL)
9504 {
9505 di = dict_find(d, key, -1);
9506 if (di == NULL)
9507 EMSG2(_(e_dictkey), key);
9508 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9509 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9510 {
9511 *rettv = di->di_tv;
9512 init_tv(&di->di_tv);
9513 dictitem_remove(d, di);
9514 }
9515 }
9516 }
9517 }
9518 else if (argvars[0].v_type != VAR_LIST)
9519 EMSG2(_(e_listdictarg), "remove()");
9520 else if ((l = argvars[0].vval.v_list) != NULL
9521 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9522 {
9523 int error = FALSE;
9524
9525 idx = (long)get_tv_number_chk(&argvars[1], &error);
9526 if (error)
9527 ; /* type error: do nothing, errmsg already given */
9528 else if ((item = list_find(l, idx)) == NULL)
9529 EMSGN(_(e_listidx), idx);
9530 else
9531 {
9532 if (argvars[2].v_type == VAR_UNKNOWN)
9533 {
9534 /* Remove one item, return its value. */
9535 vimlist_remove(l, item, item);
9536 *rettv = item->li_tv;
9537 vim_free(item);
9538 }
9539 else
9540 {
9541 /* Remove range of items, return list with values. */
9542 end = (long)get_tv_number_chk(&argvars[2], &error);
9543 if (error)
9544 ; /* type error: do nothing */
9545 else if ((item2 = list_find(l, end)) == NULL)
9546 EMSGN(_(e_listidx), end);
9547 else
9548 {
9549 int cnt = 0;
9550
9551 for (li = item; li != NULL; li = li->li_next)
9552 {
9553 ++cnt;
9554 if (li == item2)
9555 break;
9556 }
9557 if (li == NULL) /* didn't find "item2" after "item" */
9558 EMSG(_(e_invrange));
9559 else
9560 {
9561 vimlist_remove(l, item, item2);
9562 if (rettv_list_alloc(rettv) == OK)
9563 {
9564 l = rettv->vval.v_list;
9565 l->lv_first = item;
9566 l->lv_last = item2;
9567 item->li_prev = NULL;
9568 item2->li_next = NULL;
9569 l->lv_len = cnt;
9570 }
9571 }
9572 }
9573 }
9574 }
9575 }
9576}
9577
9578/*
9579 * "rename({from}, {to})" function
9580 */
9581 static void
9582f_rename(typval_T *argvars, typval_T *rettv)
9583{
9584 char_u buf[NUMBUFLEN];
9585
9586 if (check_restricted() || check_secure())
9587 rettv->vval.v_number = -1;
9588 else
9589 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9590 get_tv_string_buf(&argvars[1], buf));
9591}
9592
9593/*
9594 * "repeat()" function
9595 */
9596 static void
9597f_repeat(typval_T *argvars, typval_T *rettv)
9598{
9599 char_u *p;
9600 int n;
9601 int slen;
9602 int len;
9603 char_u *r;
9604 int i;
9605
9606 n = (int)get_tv_number(&argvars[1]);
9607 if (argvars[0].v_type == VAR_LIST)
9608 {
9609 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9610 while (n-- > 0)
9611 if (list_extend(rettv->vval.v_list,
9612 argvars[0].vval.v_list, NULL) == FAIL)
9613 break;
9614 }
9615 else
9616 {
9617 p = get_tv_string(&argvars[0]);
9618 rettv->v_type = VAR_STRING;
9619 rettv->vval.v_string = NULL;
9620
9621 slen = (int)STRLEN(p);
9622 len = slen * n;
9623 if (len <= 0)
9624 return;
9625
9626 r = alloc(len + 1);
9627 if (r != NULL)
9628 {
9629 for (i = 0; i < n; i++)
9630 mch_memmove(r + i * slen, p, (size_t)slen);
9631 r[len] = NUL;
9632 }
9633
9634 rettv->vval.v_string = r;
9635 }
9636}
9637
9638/*
9639 * "resolve()" function
9640 */
9641 static void
9642f_resolve(typval_T *argvars, typval_T *rettv)
9643{
9644 char_u *p;
9645#ifdef HAVE_READLINK
9646 char_u *buf = NULL;
9647#endif
9648
9649 p = get_tv_string(&argvars[0]);
9650#ifdef FEAT_SHORTCUT
9651 {
9652 char_u *v = NULL;
9653
9654 v = mch_resolve_shortcut(p);
9655 if (v != NULL)
9656 rettv->vval.v_string = v;
9657 else
9658 rettv->vval.v_string = vim_strsave(p);
9659 }
9660#else
9661# ifdef HAVE_READLINK
9662 {
9663 char_u *cpy;
9664 int len;
9665 char_u *remain = NULL;
9666 char_u *q;
9667 int is_relative_to_current = FALSE;
9668 int has_trailing_pathsep = FALSE;
9669 int limit = 100;
9670
9671 p = vim_strsave(p);
9672
9673 if (p[0] == '.' && (vim_ispathsep(p[1])
9674 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9675 is_relative_to_current = TRUE;
9676
9677 len = STRLEN(p);
9678 if (len > 0 && after_pathsep(p, p + len))
9679 {
9680 has_trailing_pathsep = TRUE;
9681 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9682 }
9683
9684 q = getnextcomp(p);
9685 if (*q != NUL)
9686 {
9687 /* Separate the first path component in "p", and keep the
9688 * remainder (beginning with the path separator). */
9689 remain = vim_strsave(q - 1);
9690 q[-1] = NUL;
9691 }
9692
9693 buf = alloc(MAXPATHL + 1);
9694 if (buf == NULL)
9695 goto fail;
9696
9697 for (;;)
9698 {
9699 for (;;)
9700 {
9701 len = readlink((char *)p, (char *)buf, MAXPATHL);
9702 if (len <= 0)
9703 break;
9704 buf[len] = NUL;
9705
9706 if (limit-- == 0)
9707 {
9708 vim_free(p);
9709 vim_free(remain);
9710 EMSG(_("E655: Too many symbolic links (cycle?)"));
9711 rettv->vval.v_string = NULL;
9712 goto fail;
9713 }
9714
9715 /* Ensure that the result will have a trailing path separator
9716 * if the argument has one. */
9717 if (remain == NULL && has_trailing_pathsep)
9718 add_pathsep(buf);
9719
9720 /* Separate the first path component in the link value and
9721 * concatenate the remainders. */
9722 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9723 if (*q != NUL)
9724 {
9725 if (remain == NULL)
9726 remain = vim_strsave(q - 1);
9727 else
9728 {
9729 cpy = concat_str(q - 1, remain);
9730 if (cpy != NULL)
9731 {
9732 vim_free(remain);
9733 remain = cpy;
9734 }
9735 }
9736 q[-1] = NUL;
9737 }
9738
9739 q = gettail(p);
9740 if (q > p && *q == NUL)
9741 {
9742 /* Ignore trailing path separator. */
9743 q[-1] = NUL;
9744 q = gettail(p);
9745 }
9746 if (q > p && !mch_isFullName(buf))
9747 {
9748 /* symlink is relative to directory of argument */
9749 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9750 if (cpy != NULL)
9751 {
9752 STRCPY(cpy, p);
9753 STRCPY(gettail(cpy), buf);
9754 vim_free(p);
9755 p = cpy;
9756 }
9757 }
9758 else
9759 {
9760 vim_free(p);
9761 p = vim_strsave(buf);
9762 }
9763 }
9764
9765 if (remain == NULL)
9766 break;
9767
9768 /* Append the first path component of "remain" to "p". */
9769 q = getnextcomp(remain + 1);
9770 len = q - remain - (*q != NUL);
9771 cpy = vim_strnsave(p, STRLEN(p) + len);
9772 if (cpy != NULL)
9773 {
9774 STRNCAT(cpy, remain, len);
9775 vim_free(p);
9776 p = cpy;
9777 }
9778 /* Shorten "remain". */
9779 if (*q != NUL)
9780 STRMOVE(remain, q - 1);
9781 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009782 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009783 }
9784
9785 /* If the result is a relative path name, make it explicitly relative to
9786 * the current directory if and only if the argument had this form. */
9787 if (!vim_ispathsep(*p))
9788 {
9789 if (is_relative_to_current
9790 && *p != NUL
9791 && !(p[0] == '.'
9792 && (p[1] == NUL
9793 || vim_ispathsep(p[1])
9794 || (p[1] == '.'
9795 && (p[2] == NUL
9796 || vim_ispathsep(p[2]))))))
9797 {
9798 /* Prepend "./". */
9799 cpy = concat_str((char_u *)"./", p);
9800 if (cpy != NULL)
9801 {
9802 vim_free(p);
9803 p = cpy;
9804 }
9805 }
9806 else if (!is_relative_to_current)
9807 {
9808 /* Strip leading "./". */
9809 q = p;
9810 while (q[0] == '.' && vim_ispathsep(q[1]))
9811 q += 2;
9812 if (q > p)
9813 STRMOVE(p, p + 2);
9814 }
9815 }
9816
9817 /* Ensure that the result will have no trailing path separator
9818 * if the argument had none. But keep "/" or "//". */
9819 if (!has_trailing_pathsep)
9820 {
9821 q = p + STRLEN(p);
9822 if (after_pathsep(p, q))
9823 *gettail_sep(p) = NUL;
9824 }
9825
9826 rettv->vval.v_string = p;
9827 }
9828# else
9829 rettv->vval.v_string = vim_strsave(p);
9830# endif
9831#endif
9832
9833 simplify_filename(rettv->vval.v_string);
9834
9835#ifdef HAVE_READLINK
9836fail:
9837 vim_free(buf);
9838#endif
9839 rettv->v_type = VAR_STRING;
9840}
9841
9842/*
9843 * "reverse({list})" function
9844 */
9845 static void
9846f_reverse(typval_T *argvars, typval_T *rettv)
9847{
9848 list_T *l;
9849 listitem_T *li, *ni;
9850
9851 if (argvars[0].v_type != VAR_LIST)
9852 EMSG2(_(e_listarg), "reverse()");
9853 else if ((l = argvars[0].vval.v_list) != NULL
9854 && !tv_check_lock(l->lv_lock,
9855 (char_u *)N_("reverse() argument"), TRUE))
9856 {
9857 li = l->lv_last;
9858 l->lv_first = l->lv_last = NULL;
9859 l->lv_len = 0;
9860 while (li != NULL)
9861 {
9862 ni = li->li_prev;
9863 list_append(l, li);
9864 li = ni;
9865 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009866 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009867 l->lv_idx = l->lv_len - l->lv_idx - 1;
9868 }
9869}
9870
9871#define SP_NOMOVE 0x01 /* don't move cursor */
9872#define SP_REPEAT 0x02 /* repeat to find outer pair */
9873#define SP_RETCOUNT 0x04 /* return matchcount */
9874#define SP_SETPCMARK 0x08 /* set previous context mark */
9875#define SP_START 0x10 /* accept match at start position */
9876#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9877#define SP_END 0x40 /* leave cursor at end of match */
9878#define SP_COLUMN 0x80 /* start at cursor column */
9879
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009880/*
9881 * Get flags for a search function.
9882 * Possibly sets "p_ws".
9883 * Returns BACKWARD, FORWARD or zero (for an error).
9884 */
9885 static int
9886get_search_arg(typval_T *varp, int *flagsp)
9887{
9888 int dir = FORWARD;
9889 char_u *flags;
9890 char_u nbuf[NUMBUFLEN];
9891 int mask;
9892
9893 if (varp->v_type != VAR_UNKNOWN)
9894 {
9895 flags = get_tv_string_buf_chk(varp, nbuf);
9896 if (flags == NULL)
9897 return 0; /* type error; errmsg already given */
9898 while (*flags != NUL)
9899 {
9900 switch (*flags)
9901 {
9902 case 'b': dir = BACKWARD; break;
9903 case 'w': p_ws = TRUE; break;
9904 case 'W': p_ws = FALSE; break;
9905 default: mask = 0;
9906 if (flagsp != NULL)
9907 switch (*flags)
9908 {
9909 case 'c': mask = SP_START; break;
9910 case 'e': mask = SP_END; break;
9911 case 'm': mask = SP_RETCOUNT; break;
9912 case 'n': mask = SP_NOMOVE; break;
9913 case 'p': mask = SP_SUBPAT; break;
9914 case 'r': mask = SP_REPEAT; break;
9915 case 's': mask = SP_SETPCMARK; break;
9916 case 'z': mask = SP_COLUMN; break;
9917 }
9918 if (mask == 0)
9919 {
9920 EMSG2(_(e_invarg2), flags);
9921 dir = 0;
9922 }
9923 else
9924 *flagsp |= mask;
9925 }
9926 if (dir == 0)
9927 break;
9928 ++flags;
9929 }
9930 }
9931 return dir;
9932}
9933
9934/*
9935 * Shared by search() and searchpos() functions.
9936 */
9937 static int
9938search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9939{
9940 int flags;
9941 char_u *pat;
9942 pos_T pos;
9943 pos_T save_cursor;
9944 int save_p_ws = p_ws;
9945 int dir;
9946 int retval = 0; /* default: FAIL */
9947 long lnum_stop = 0;
9948 proftime_T tm;
9949#ifdef FEAT_RELTIME
9950 long time_limit = 0;
9951#endif
9952 int options = SEARCH_KEEP;
9953 int subpatnum;
9954
9955 pat = get_tv_string(&argvars[0]);
9956 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9957 if (dir == 0)
9958 goto theend;
9959 flags = *flagsp;
9960 if (flags & SP_START)
9961 options |= SEARCH_START;
9962 if (flags & SP_END)
9963 options |= SEARCH_END;
9964 if (flags & SP_COLUMN)
9965 options |= SEARCH_COL;
9966
9967 /* Optional arguments: line number to stop searching and timeout. */
9968 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9969 {
9970 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9971 if (lnum_stop < 0)
9972 goto theend;
9973#ifdef FEAT_RELTIME
9974 if (argvars[3].v_type != VAR_UNKNOWN)
9975 {
9976 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9977 if (time_limit < 0)
9978 goto theend;
9979 }
9980#endif
9981 }
9982
9983#ifdef FEAT_RELTIME
9984 /* Set the time limit, if there is one. */
9985 profile_setlimit(time_limit, &tm);
9986#endif
9987
9988 /*
9989 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9990 * Check to make sure only those flags are set.
9991 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9992 * flags cannot be set. Check for that condition also.
9993 */
9994 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9995 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9996 {
9997 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9998 goto theend;
9999 }
10000
10001 pos = save_cursor = curwin->w_cursor;
10002 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010003 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010004 if (subpatnum != FAIL)
10005 {
10006 if (flags & SP_SUBPAT)
10007 retval = subpatnum;
10008 else
10009 retval = pos.lnum;
10010 if (flags & SP_SETPCMARK)
10011 setpcmark();
10012 curwin->w_cursor = pos;
10013 if (match_pos != NULL)
10014 {
10015 /* Store the match cursor position */
10016 match_pos->lnum = pos.lnum;
10017 match_pos->col = pos.col + 1;
10018 }
10019 /* "/$" will put the cursor after the end of the line, may need to
10020 * correct that here */
10021 check_cursor();
10022 }
10023
10024 /* If 'n' flag is used: restore cursor position. */
10025 if (flags & SP_NOMOVE)
10026 curwin->w_cursor = save_cursor;
10027 else
10028 curwin->w_set_curswant = TRUE;
10029theend:
10030 p_ws = save_p_ws;
10031
10032 return retval;
10033}
10034
10035#ifdef FEAT_FLOAT
10036
10037/*
10038 * round() is not in C90, use ceil() or floor() instead.
10039 */
10040 float_T
10041vim_round(float_T f)
10042{
10043 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10044}
10045
10046/*
10047 * "round({float})" function
10048 */
10049 static void
10050f_round(typval_T *argvars, typval_T *rettv)
10051{
10052 float_T f = 0.0;
10053
10054 rettv->v_type = VAR_FLOAT;
10055 if (get_float_arg(argvars, &f) == OK)
10056 rettv->vval.v_float = vim_round(f);
10057 else
10058 rettv->vval.v_float = 0.0;
10059}
10060#endif
10061
10062/*
10063 * "screenattr()" function
10064 */
10065 static void
10066f_screenattr(typval_T *argvars, typval_T *rettv)
10067{
10068 int row;
10069 int col;
10070 int c;
10071
10072 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10073 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10074 if (row < 0 || row >= screen_Rows
10075 || col < 0 || col >= screen_Columns)
10076 c = -1;
10077 else
10078 c = ScreenAttrs[LineOffset[row] + col];
10079 rettv->vval.v_number = c;
10080}
10081
10082/*
10083 * "screenchar()" function
10084 */
10085 static void
10086f_screenchar(typval_T *argvars, typval_T *rettv)
10087{
10088 int row;
10089 int col;
10090 int off;
10091 int c;
10092
10093 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
10094 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
10095 if (row < 0 || row >= screen_Rows
10096 || col < 0 || col >= screen_Columns)
10097 c = -1;
10098 else
10099 {
10100 off = LineOffset[row] + col;
10101#ifdef FEAT_MBYTE
10102 if (enc_utf8 && ScreenLinesUC[off] != 0)
10103 c = ScreenLinesUC[off];
10104 else
10105#endif
10106 c = ScreenLines[off];
10107 }
10108 rettv->vval.v_number = c;
10109}
10110
10111/*
10112 * "screencol()" function
10113 *
10114 * First column is 1 to be consistent with virtcol().
10115 */
10116 static void
10117f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10118{
10119 rettv->vval.v_number = screen_screencol() + 1;
10120}
10121
10122/*
10123 * "screenrow()" function
10124 */
10125 static void
10126f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10127{
10128 rettv->vval.v_number = screen_screenrow() + 1;
10129}
10130
10131/*
10132 * "search()" function
10133 */
10134 static void
10135f_search(typval_T *argvars, typval_T *rettv)
10136{
10137 int flags = 0;
10138
10139 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10140}
10141
10142/*
10143 * "searchdecl()" function
10144 */
10145 static void
10146f_searchdecl(typval_T *argvars, typval_T *rettv)
10147{
10148 int locally = 1;
10149 int thisblock = 0;
10150 int error = FALSE;
10151 char_u *name;
10152
10153 rettv->vval.v_number = 1; /* default: FAIL */
10154
10155 name = get_tv_string_chk(&argvars[0]);
10156 if (argvars[1].v_type != VAR_UNKNOWN)
10157 {
10158 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
10159 if (!error && argvars[2].v_type != VAR_UNKNOWN)
10160 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
10161 }
10162 if (!error && name != NULL)
10163 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10164 locally, thisblock, SEARCH_KEEP) == FAIL;
10165}
10166
10167/*
10168 * Used by searchpair() and searchpairpos()
10169 */
10170 static int
10171searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10172{
10173 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010174 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010175 int save_p_ws = p_ws;
10176 int dir;
10177 int flags = 0;
10178 char_u nbuf1[NUMBUFLEN];
10179 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010180 int retval = 0; /* default: FAIL */
10181 long lnum_stop = 0;
10182 long time_limit = 0;
10183
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010184 /* Get the three pattern arguments: start, middle, end. Will result in an
10185 * error if not a valid argument. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010186 spat = get_tv_string_chk(&argvars[0]);
10187 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
10188 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
10189 if (spat == NULL || mpat == NULL || epat == NULL)
10190 goto theend; /* type error */
10191
10192 /* Handle the optional fourth argument: flags */
10193 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10194 if (dir == 0)
10195 goto theend;
10196
10197 /* Don't accept SP_END or SP_SUBPAT.
10198 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10199 */
10200 if ((flags & (SP_END | SP_SUBPAT)) != 0
10201 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10202 {
10203 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10204 goto theend;
10205 }
10206
10207 /* Using 'r' implies 'W', otherwise it doesn't work. */
10208 if (flags & SP_REPEAT)
10209 p_ws = FALSE;
10210
10211 /* Optional fifth argument: skip expression */
10212 if (argvars[3].v_type == VAR_UNKNOWN
10213 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010214 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010215 else
10216 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010217 skip = &argvars[4];
10218 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10219 && skip->v_type != VAR_STRING)
10220 {
10221 /* Type error */
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010222 EMSG2(_(e_invarg2), get_tv_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010223 goto theend;
10224 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010225 if (argvars[5].v_type != VAR_UNKNOWN)
10226 {
10227 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10228 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010229 {
10230 EMSG2(_(e_invarg2), get_tv_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010231 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010232 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010233#ifdef FEAT_RELTIME
10234 if (argvars[6].v_type != VAR_UNKNOWN)
10235 {
10236 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10237 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010238 {
10239 EMSG2(_(e_invarg2), get_tv_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010240 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010241 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010242 }
10243#endif
10244 }
10245 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010246
10247 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10248 match_pos, lnum_stop, time_limit);
10249
10250theend:
10251 p_ws = save_p_ws;
10252
10253 return retval;
10254}
10255
10256/*
10257 * "searchpair()" function
10258 */
10259 static void
10260f_searchpair(typval_T *argvars, typval_T *rettv)
10261{
10262 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10263}
10264
10265/*
10266 * "searchpairpos()" function
10267 */
10268 static void
10269f_searchpairpos(typval_T *argvars, typval_T *rettv)
10270{
10271 pos_T match_pos;
10272 int lnum = 0;
10273 int col = 0;
10274
10275 if (rettv_list_alloc(rettv) == FAIL)
10276 return;
10277
10278 if (searchpair_cmn(argvars, &match_pos) > 0)
10279 {
10280 lnum = match_pos.lnum;
10281 col = match_pos.col;
10282 }
10283
10284 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10285 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10286}
10287
10288/*
10289 * Search for a start/middle/end thing.
10290 * Used by searchpair(), see its documentation for the details.
10291 * Returns 0 or -1 for no match,
10292 */
10293 long
10294do_searchpair(
10295 char_u *spat, /* start pattern */
10296 char_u *mpat, /* middle pattern */
10297 char_u *epat, /* end pattern */
10298 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010299 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010300 int flags, /* SP_SETPCMARK and other SP_ values */
10301 pos_T *match_pos,
10302 linenr_T lnum_stop, /* stop at this line if not zero */
10303 long time_limit UNUSED) /* stop after this many msec */
10304{
10305 char_u *save_cpo;
10306 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10307 long retval = 0;
10308 pos_T pos;
10309 pos_T firstpos;
10310 pos_T foundpos;
10311 pos_T save_cursor;
10312 pos_T save_pos;
10313 int n;
10314 int r;
10315 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010316 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010317 int err;
10318 int options = SEARCH_KEEP;
10319 proftime_T tm;
10320
10321 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10322 save_cpo = p_cpo;
10323 p_cpo = empty_option;
10324
10325#ifdef FEAT_RELTIME
10326 /* Set the time limit, if there is one. */
10327 profile_setlimit(time_limit, &tm);
10328#endif
10329
10330 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10331 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010332 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10333 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010334 if (pat2 == NULL || pat3 == NULL)
10335 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010336 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010337 if (*mpat == NUL)
10338 STRCPY(pat3, pat2);
10339 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010340 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010341 spat, epat, mpat);
10342 if (flags & SP_START)
10343 options |= SEARCH_START;
10344
Bram Moolenaar48570482017-10-30 21:48:41 +010010345 if (skip != NULL)
10346 {
10347 /* Empty string means to not use the skip expression. */
10348 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10349 use_skip = skip->vval.v_string != NULL
10350 && *skip->vval.v_string != NUL;
10351 }
10352
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010353 save_cursor = curwin->w_cursor;
10354 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010355 CLEAR_POS(&firstpos);
10356 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010357 pat = pat3;
10358 for (;;)
10359 {
10360 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010361 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010362 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010363 /* didn't find it or found the first match again: FAIL */
10364 break;
10365
10366 if (firstpos.lnum == 0)
10367 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010368 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010369 {
10370 /* Found the same position again. Can happen with a pattern that
10371 * has "\zs" at the end and searching backwards. Advance one
10372 * character and try again. */
10373 if (dir == BACKWARD)
10374 decl(&pos);
10375 else
10376 incl(&pos);
10377 }
10378 foundpos = pos;
10379
10380 /* clear the start flag to avoid getting stuck here */
10381 options &= ~SEARCH_START;
10382
10383 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010384 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010385 {
10386 save_pos = curwin->w_cursor;
10387 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010388 err = FALSE;
10389 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010390 curwin->w_cursor = save_pos;
10391 if (err)
10392 {
10393 /* Evaluating {skip} caused an error, break here. */
10394 curwin->w_cursor = save_cursor;
10395 retval = -1;
10396 break;
10397 }
10398 if (r)
10399 continue;
10400 }
10401
10402 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10403 {
10404 /* Found end when searching backwards or start when searching
10405 * forward: nested pair. */
10406 ++nest;
10407 pat = pat2; /* nested, don't search for middle */
10408 }
10409 else
10410 {
10411 /* Found end when searching forward or start when searching
10412 * backward: end of (nested) pair; or found middle in outer pair. */
10413 if (--nest == 1)
10414 pat = pat3; /* outer level, search for middle */
10415 }
10416
10417 if (nest == 0)
10418 {
10419 /* Found the match: return matchcount or line number. */
10420 if (flags & SP_RETCOUNT)
10421 ++retval;
10422 else
10423 retval = pos.lnum;
10424 if (flags & SP_SETPCMARK)
10425 setpcmark();
10426 curwin->w_cursor = pos;
10427 if (!(flags & SP_REPEAT))
10428 break;
10429 nest = 1; /* search for next unmatched */
10430 }
10431 }
10432
10433 if (match_pos != NULL)
10434 {
10435 /* Store the match cursor position */
10436 match_pos->lnum = curwin->w_cursor.lnum;
10437 match_pos->col = curwin->w_cursor.col + 1;
10438 }
10439
10440 /* If 'n' flag is used or search failed: restore cursor position. */
10441 if ((flags & SP_NOMOVE) || retval == 0)
10442 curwin->w_cursor = save_cursor;
10443
10444theend:
10445 vim_free(pat2);
10446 vim_free(pat3);
10447 if (p_cpo == empty_option)
10448 p_cpo = save_cpo;
10449 else
10450 /* Darn, evaluating the {skip} expression changed the value. */
10451 free_string_option(save_cpo);
10452
10453 return retval;
10454}
10455
10456/*
10457 * "searchpos()" function
10458 */
10459 static void
10460f_searchpos(typval_T *argvars, typval_T *rettv)
10461{
10462 pos_T match_pos;
10463 int lnum = 0;
10464 int col = 0;
10465 int n;
10466 int flags = 0;
10467
10468 if (rettv_list_alloc(rettv) == FAIL)
10469 return;
10470
10471 n = search_cmn(argvars, &match_pos, &flags);
10472 if (n > 0)
10473 {
10474 lnum = match_pos.lnum;
10475 col = match_pos.col;
10476 }
10477
10478 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10479 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10480 if (flags & SP_SUBPAT)
10481 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10482}
10483
10484 static void
10485f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10486{
10487#ifdef FEAT_CLIENTSERVER
10488 char_u buf[NUMBUFLEN];
10489 char_u *server = get_tv_string_chk(&argvars[0]);
10490 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10491
10492 rettv->vval.v_number = -1;
10493 if (server == NULL || reply == NULL)
10494 return;
10495 if (check_restricted() || check_secure())
10496 return;
10497# ifdef FEAT_X11
10498 if (check_connection() == FAIL)
10499 return;
10500# endif
10501
10502 if (serverSendReply(server, reply) < 0)
10503 {
10504 EMSG(_("E258: Unable to send to client"));
10505 return;
10506 }
10507 rettv->vval.v_number = 0;
10508#else
10509 rettv->vval.v_number = -1;
10510#endif
10511}
10512
10513 static void
10514f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10515{
10516 char_u *r = NULL;
10517
10518#ifdef FEAT_CLIENTSERVER
10519# ifdef WIN32
10520 r = serverGetVimNames();
10521# else
10522 make_connection();
10523 if (X_DISPLAY != NULL)
10524 r = serverGetVimNames(X_DISPLAY);
10525# endif
10526#endif
10527 rettv->v_type = VAR_STRING;
10528 rettv->vval.v_string = r;
10529}
10530
10531/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010532 * "setbufline()" function
10533 */
10534 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010535f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010536{
10537 linenr_T lnum;
10538 buf_T *buf;
10539
10540 buf = get_buf_tv(&argvars[0], FALSE);
10541 if (buf == NULL)
10542 rettv->vval.v_number = 1; /* FAIL */
10543 else
10544 {
10545 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010546 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010547 }
10548}
10549
10550/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010551 * "setbufvar()" function
10552 */
10553 static void
10554f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10555{
10556 buf_T *buf;
10557 char_u *varname, *bufvarname;
10558 typval_T *varp;
10559 char_u nbuf[NUMBUFLEN];
10560
10561 if (check_restricted() || check_secure())
10562 return;
10563 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10564 varname = get_tv_string_chk(&argvars[1]);
10565 buf = get_buf_tv(&argvars[0], FALSE);
10566 varp = &argvars[2];
10567
10568 if (buf != NULL && varname != NULL && varp != NULL)
10569 {
10570 if (*varname == '&')
10571 {
10572 long numval;
10573 char_u *strval;
10574 int error = FALSE;
10575 aco_save_T aco;
10576
10577 /* set curbuf to be our buf, temporarily */
10578 aucmd_prepbuf(&aco, buf);
10579
10580 ++varname;
10581 numval = (long)get_tv_number_chk(varp, &error);
10582 strval = get_tv_string_buf_chk(varp, nbuf);
10583 if (!error && strval != NULL)
10584 set_option_value(varname, numval, strval, OPT_LOCAL);
10585
10586 /* reset notion of buffer */
10587 aucmd_restbuf(&aco);
10588 }
10589 else
10590 {
10591 buf_T *save_curbuf = curbuf;
10592
10593 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10594 if (bufvarname != NULL)
10595 {
10596 curbuf = buf;
10597 STRCPY(bufvarname, "b:");
10598 STRCPY(bufvarname + 2, varname);
10599 set_var(bufvarname, varp, TRUE);
10600 vim_free(bufvarname);
10601 curbuf = save_curbuf;
10602 }
10603 }
10604 }
10605}
10606
10607 static void
10608f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10609{
10610 dict_T *d;
10611 dictitem_T *di;
10612 char_u *csearch;
10613
10614 if (argvars[0].v_type != VAR_DICT)
10615 {
10616 EMSG(_(e_dictreq));
10617 return;
10618 }
10619
10620 if ((d = argvars[0].vval.v_dict) != NULL)
10621 {
10622 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10623 if (csearch != NULL)
10624 {
10625#ifdef FEAT_MBYTE
10626 if (enc_utf8)
10627 {
10628 int pcc[MAX_MCO];
10629 int c = utfc_ptr2char(csearch, pcc);
10630
10631 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10632 }
10633 else
10634#endif
10635 set_last_csearch(PTR2CHAR(csearch),
10636 csearch, MB_PTR2LEN(csearch));
10637 }
10638
10639 di = dict_find(d, (char_u *)"forward", -1);
10640 if (di != NULL)
10641 set_csearch_direction((int)get_tv_number(&di->di_tv)
10642 ? FORWARD : BACKWARD);
10643
10644 di = dict_find(d, (char_u *)"until", -1);
10645 if (di != NULL)
10646 set_csearch_until(!!get_tv_number(&di->di_tv));
10647 }
10648}
10649
10650/*
10651 * "setcmdpos()" function
10652 */
10653 static void
10654f_setcmdpos(typval_T *argvars, typval_T *rettv)
10655{
10656 int pos = (int)get_tv_number(&argvars[0]) - 1;
10657
10658 if (pos >= 0)
10659 rettv->vval.v_number = set_cmdline_pos(pos);
10660}
10661
10662/*
10663 * "setfperm({fname}, {mode})" function
10664 */
10665 static void
10666f_setfperm(typval_T *argvars, typval_T *rettv)
10667{
10668 char_u *fname;
10669 char_u modebuf[NUMBUFLEN];
10670 char_u *mode_str;
10671 int i;
10672 int mask;
10673 int mode = 0;
10674
10675 rettv->vval.v_number = 0;
10676 fname = get_tv_string_chk(&argvars[0]);
10677 if (fname == NULL)
10678 return;
10679 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10680 if (mode_str == NULL)
10681 return;
10682 if (STRLEN(mode_str) != 9)
10683 {
10684 EMSG2(_(e_invarg2), mode_str);
10685 return;
10686 }
10687
10688 mask = 1;
10689 for (i = 8; i >= 0; --i)
10690 {
10691 if (mode_str[i] != '-')
10692 mode |= mask;
10693 mask = mask << 1;
10694 }
10695 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10696}
10697
10698/*
10699 * "setline()" function
10700 */
10701 static void
10702f_setline(typval_T *argvars, typval_T *rettv)
10703{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010704 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010705
Bram Moolenaarca851592018-06-06 21:04:07 +020010706 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010707}
10708
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010709/*
10710 * Used by "setqflist()" and "setloclist()" functions
10711 */
10712 static void
10713set_qf_ll_list(
10714 win_T *wp UNUSED,
10715 typval_T *list_arg UNUSED,
10716 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010717 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010718 typval_T *rettv)
10719{
10720#ifdef FEAT_QUICKFIX
10721 static char *e_invact = N_("E927: Invalid action: '%s'");
10722 char_u *act;
10723 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010724 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010725#endif
10726
10727 rettv->vval.v_number = -1;
10728
10729#ifdef FEAT_QUICKFIX
10730 if (list_arg->v_type != VAR_LIST)
10731 EMSG(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010732 else if (recursive != 0)
10733 EMSG(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010734 else
10735 {
10736 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010737 dict_T *d = NULL;
10738 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010739
10740 if (action_arg->v_type == VAR_STRING)
10741 {
10742 act = get_tv_string_chk(action_arg);
10743 if (act == NULL)
10744 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010745 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10746 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010747 action = *act;
10748 else
10749 EMSG2(_(e_invact), act);
10750 }
10751 else if (action_arg->v_type == VAR_UNKNOWN)
10752 action = ' ';
10753 else
10754 EMSG(_(e_stringreq));
10755
Bram Moolenaard823fa92016-08-12 16:29:27 +020010756 if (action_arg->v_type != VAR_UNKNOWN
10757 && what_arg->v_type != VAR_UNKNOWN)
10758 {
10759 if (what_arg->v_type == VAR_DICT)
10760 d = what_arg->vval.v_dict;
10761 else
10762 {
10763 EMSG(_(e_dictreq));
10764 valid_dict = FALSE;
10765 }
10766 }
10767
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010768 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010769 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010770 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10771 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010772 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010773 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010774 }
10775#endif
10776}
10777
10778/*
10779 * "setloclist()" function
10780 */
10781 static void
10782f_setloclist(typval_T *argvars, typval_T *rettv)
10783{
10784 win_T *win;
10785
10786 rettv->vval.v_number = -1;
10787
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010788 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010789 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010790 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010791}
10792
10793/*
10794 * "setmatches()" function
10795 */
10796 static void
10797f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10798{
10799#ifdef FEAT_SEARCH_EXTRA
10800 list_T *l;
10801 listitem_T *li;
10802 dict_T *d;
10803 list_T *s = NULL;
10804
10805 rettv->vval.v_number = -1;
10806 if (argvars[0].v_type != VAR_LIST)
10807 {
10808 EMSG(_(e_listreq));
10809 return;
10810 }
10811 if ((l = argvars[0].vval.v_list) != NULL)
10812 {
10813
10814 /* To some extent make sure that we are dealing with a list from
10815 * "getmatches()". */
10816 li = l->lv_first;
10817 while (li != NULL)
10818 {
10819 if (li->li_tv.v_type != VAR_DICT
10820 || (d = li->li_tv.vval.v_dict) == NULL)
10821 {
10822 EMSG(_(e_invarg));
10823 return;
10824 }
10825 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10826 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10827 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10828 && dict_find(d, (char_u *)"priority", -1) != NULL
10829 && dict_find(d, (char_u *)"id", -1) != NULL))
10830 {
10831 EMSG(_(e_invarg));
10832 return;
10833 }
10834 li = li->li_next;
10835 }
10836
10837 clear_matches(curwin);
10838 li = l->lv_first;
10839 while (li != NULL)
10840 {
10841 int i = 0;
10842 char_u buf[5];
10843 dictitem_T *di;
10844 char_u *group;
10845 int priority;
10846 int id;
10847 char_u *conceal;
10848
10849 d = li->li_tv.vval.v_dict;
10850 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10851 {
10852 if (s == NULL)
10853 {
10854 s = list_alloc();
10855 if (s == NULL)
10856 return;
10857 }
10858
10859 /* match from matchaddpos() */
10860 for (i = 1; i < 9; i++)
10861 {
10862 sprintf((char *)buf, (char *)"pos%d", i);
10863 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10864 {
10865 if (di->di_tv.v_type != VAR_LIST)
10866 return;
10867
10868 list_append_tv(s, &di->di_tv);
10869 s->lv_refcount++;
10870 }
10871 else
10872 break;
10873 }
10874 }
10875
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010876 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010877 priority = (int)get_dict_number(d, (char_u *)"priority");
10878 id = (int)get_dict_number(d, (char_u *)"id");
10879 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010880 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010881 : NULL;
10882 if (i == 0)
10883 {
10884 match_add(curwin, group,
10885 get_dict_string(d, (char_u *)"pattern", FALSE),
10886 priority, id, NULL, conceal);
10887 }
10888 else
10889 {
10890 match_add(curwin, group, NULL, priority, id, s, conceal);
10891 list_unref(s);
10892 s = NULL;
10893 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010894 vim_free(group);
10895 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010896
10897 li = li->li_next;
10898 }
10899 rettv->vval.v_number = 0;
10900 }
10901#endif
10902}
10903
10904/*
10905 * "setpos()" function
10906 */
10907 static void
10908f_setpos(typval_T *argvars, typval_T *rettv)
10909{
10910 pos_T pos;
10911 int fnum;
10912 char_u *name;
10913 colnr_T curswant = -1;
10914
10915 rettv->vval.v_number = -1;
10916 name = get_tv_string_chk(argvars);
10917 if (name != NULL)
10918 {
10919 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10920 {
10921 if (--pos.col < 0)
10922 pos.col = 0;
10923 if (name[0] == '.' && name[1] == NUL)
10924 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010925 /* set cursor; "fnum" is ignored */
10926 curwin->w_cursor = pos;
10927 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010928 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010929 curwin->w_curswant = curswant - 1;
10930 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010931 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010932 check_cursor();
10933 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010934 }
10935 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10936 {
10937 /* set mark */
10938 if (setmark_pos(name[1], &pos, fnum) == OK)
10939 rettv->vval.v_number = 0;
10940 }
10941 else
10942 EMSG(_(e_invarg));
10943 }
10944 }
10945}
10946
10947/*
10948 * "setqflist()" function
10949 */
10950 static void
10951f_setqflist(typval_T *argvars, typval_T *rettv)
10952{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010953 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010954}
10955
10956/*
10957 * "setreg()" function
10958 */
10959 static void
10960f_setreg(typval_T *argvars, typval_T *rettv)
10961{
10962 int regname;
10963 char_u *strregname;
10964 char_u *stropt;
10965 char_u *strval;
10966 int append;
10967 char_u yank_type;
10968 long block_len;
10969
10970 block_len = -1;
10971 yank_type = MAUTO;
10972 append = FALSE;
10973
10974 strregname = get_tv_string_chk(argvars);
10975 rettv->vval.v_number = 1; /* FAIL is default */
10976
10977 if (strregname == NULL)
10978 return; /* type error; errmsg already given */
10979 regname = *strregname;
10980 if (regname == 0 || regname == '@')
10981 regname = '"';
10982
10983 if (argvars[2].v_type != VAR_UNKNOWN)
10984 {
10985 stropt = get_tv_string_chk(&argvars[2]);
10986 if (stropt == NULL)
10987 return; /* type error */
10988 for (; *stropt != NUL; ++stropt)
10989 switch (*stropt)
10990 {
10991 case 'a': case 'A': /* append */
10992 append = TRUE;
10993 break;
10994 case 'v': case 'c': /* character-wise selection */
10995 yank_type = MCHAR;
10996 break;
10997 case 'V': case 'l': /* line-wise selection */
10998 yank_type = MLINE;
10999 break;
11000 case 'b': case Ctrl_V: /* block-wise selection */
11001 yank_type = MBLOCK;
11002 if (VIM_ISDIGIT(stropt[1]))
11003 {
11004 ++stropt;
11005 block_len = getdigits(&stropt) - 1;
11006 --stropt;
11007 }
11008 break;
11009 }
11010 }
11011
11012 if (argvars[1].v_type == VAR_LIST)
11013 {
11014 char_u **lstval;
11015 char_u **allocval;
11016 char_u buf[NUMBUFLEN];
11017 char_u **curval;
11018 char_u **curallocval;
11019 list_T *ll = argvars[1].vval.v_list;
11020 listitem_T *li;
11021 int len;
11022
11023 /* If the list is NULL handle like an empty list. */
11024 len = ll == NULL ? 0 : ll->lv_len;
11025
11026 /* First half: use for pointers to result lines; second half: use for
11027 * pointers to allocated copies. */
11028 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11029 if (lstval == NULL)
11030 return;
11031 curval = lstval;
11032 allocval = lstval + len + 2;
11033 curallocval = allocval;
11034
11035 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11036 li = li->li_next)
11037 {
11038 strval = get_tv_string_buf_chk(&li->li_tv, buf);
11039 if (strval == NULL)
11040 goto free_lstval;
11041 if (strval == buf)
11042 {
11043 /* Need to make a copy, next get_tv_string_buf_chk() will
11044 * overwrite the string. */
11045 strval = vim_strsave(buf);
11046 if (strval == NULL)
11047 goto free_lstval;
11048 *curallocval++ = strval;
11049 }
11050 *curval++ = strval;
11051 }
11052 *curval++ = NULL;
11053
11054 write_reg_contents_lst(regname, lstval, -1,
11055 append, yank_type, block_len);
11056free_lstval:
11057 while (curallocval > allocval)
11058 vim_free(*--curallocval);
11059 vim_free(lstval);
11060 }
11061 else
11062 {
11063 strval = get_tv_string_chk(&argvars[1]);
11064 if (strval == NULL)
11065 return;
11066 write_reg_contents_ex(regname, strval, -1,
11067 append, yank_type, block_len);
11068 }
11069 rettv->vval.v_number = 0;
11070}
11071
11072/*
11073 * "settabvar()" function
11074 */
11075 static void
11076f_settabvar(typval_T *argvars, typval_T *rettv)
11077{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011078 tabpage_T *save_curtab;
11079 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080 char_u *varname, *tabvarname;
11081 typval_T *varp;
11082
11083 rettv->vval.v_number = 0;
11084
11085 if (check_restricted() || check_secure())
11086 return;
11087
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011088 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011089 varname = get_tv_string_chk(&argvars[1]);
11090 varp = &argvars[2];
11091
Bram Moolenaar4033c552017-09-16 20:54:51 +020011092 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011093 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011094 save_curtab = curtab;
11095 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011096
11097 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11098 if (tabvarname != NULL)
11099 {
11100 STRCPY(tabvarname, "t:");
11101 STRCPY(tabvarname + 2, varname);
11102 set_var(tabvarname, varp, TRUE);
11103 vim_free(tabvarname);
11104 }
11105
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011106 /* Restore current tabpage */
11107 if (valid_tabpage(save_curtab))
11108 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011109 }
11110}
11111
11112/*
11113 * "settabwinvar()" function
11114 */
11115 static void
11116f_settabwinvar(typval_T *argvars, typval_T *rettv)
11117{
11118 setwinvar(argvars, rettv, 1);
11119}
11120
11121/*
11122 * "setwinvar()" function
11123 */
11124 static void
11125f_setwinvar(typval_T *argvars, typval_T *rettv)
11126{
11127 setwinvar(argvars, rettv, 0);
11128}
11129
11130#ifdef FEAT_CRYPT
11131/*
11132 * "sha256({string})" function
11133 */
11134 static void
11135f_sha256(typval_T *argvars, typval_T *rettv)
11136{
11137 char_u *p;
11138
11139 p = get_tv_string(&argvars[0]);
11140 rettv->vval.v_string = vim_strsave(
11141 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11142 rettv->v_type = VAR_STRING;
11143}
11144#endif /* FEAT_CRYPT */
11145
11146/*
11147 * "shellescape({string})" function
11148 */
11149 static void
11150f_shellescape(typval_T *argvars, typval_T *rettv)
11151{
Bram Moolenaar20615522017-06-05 18:46:26 +020011152 int do_special = non_zero_arg(&argvars[1]);
11153
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011154 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020011155 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011156 rettv->v_type = VAR_STRING;
11157}
11158
11159/*
11160 * shiftwidth() function
11161 */
11162 static void
11163f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11164{
11165 rettv->vval.v_number = get_sw_value(curbuf);
11166}
11167
11168/*
11169 * "simplify()" function
11170 */
11171 static void
11172f_simplify(typval_T *argvars, typval_T *rettv)
11173{
11174 char_u *p;
11175
11176 p = get_tv_string(&argvars[0]);
11177 rettv->vval.v_string = vim_strsave(p);
11178 simplify_filename(rettv->vval.v_string); /* simplify in place */
11179 rettv->v_type = VAR_STRING;
11180}
11181
11182#ifdef FEAT_FLOAT
11183/*
11184 * "sin()" function
11185 */
11186 static void
11187f_sin(typval_T *argvars, typval_T *rettv)
11188{
11189 float_T f = 0.0;
11190
11191 rettv->v_type = VAR_FLOAT;
11192 if (get_float_arg(argvars, &f) == OK)
11193 rettv->vval.v_float = sin(f);
11194 else
11195 rettv->vval.v_float = 0.0;
11196}
11197
11198/*
11199 * "sinh()" function
11200 */
11201 static void
11202f_sinh(typval_T *argvars, typval_T *rettv)
11203{
11204 float_T f = 0.0;
11205
11206 rettv->v_type = VAR_FLOAT;
11207 if (get_float_arg(argvars, &f) == OK)
11208 rettv->vval.v_float = sinh(f);
11209 else
11210 rettv->vval.v_float = 0.0;
11211}
11212#endif
11213
11214static int
11215#ifdef __BORLANDC__
11216 _RTLENTRYF
11217#endif
11218 item_compare(const void *s1, const void *s2);
11219static int
11220#ifdef __BORLANDC__
11221 _RTLENTRYF
11222#endif
11223 item_compare2(const void *s1, const void *s2);
11224
11225/* struct used in the array that's given to qsort() */
11226typedef struct
11227{
11228 listitem_T *item;
11229 int idx;
11230} sortItem_T;
11231
11232/* struct storing information about current sort */
11233typedef struct
11234{
11235 int item_compare_ic;
11236 int item_compare_numeric;
11237 int item_compare_numbers;
11238#ifdef FEAT_FLOAT
11239 int item_compare_float;
11240#endif
11241 char_u *item_compare_func;
11242 partial_T *item_compare_partial;
11243 dict_T *item_compare_selfdict;
11244 int item_compare_func_err;
11245 int item_compare_keep_zero;
11246} sortinfo_T;
11247static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011248#define ITEM_COMPARE_FAIL 999
11249
11250/*
11251 * Compare functions for f_sort() and f_uniq() below.
11252 */
11253 static int
11254#ifdef __BORLANDC__
11255_RTLENTRYF
11256#endif
11257item_compare(const void *s1, const void *s2)
11258{
11259 sortItem_T *si1, *si2;
11260 typval_T *tv1, *tv2;
11261 char_u *p1, *p2;
11262 char_u *tofree1 = NULL, *tofree2 = NULL;
11263 int res;
11264 char_u numbuf1[NUMBUFLEN];
11265 char_u numbuf2[NUMBUFLEN];
11266
11267 si1 = (sortItem_T *)s1;
11268 si2 = (sortItem_T *)s2;
11269 tv1 = &si1->item->li_tv;
11270 tv2 = &si2->item->li_tv;
11271
11272 if (sortinfo->item_compare_numbers)
11273 {
11274 varnumber_T v1 = get_tv_number(tv1);
11275 varnumber_T v2 = get_tv_number(tv2);
11276
11277 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11278 }
11279
11280#ifdef FEAT_FLOAT
11281 if (sortinfo->item_compare_float)
11282 {
11283 float_T v1 = get_tv_float(tv1);
11284 float_T v2 = get_tv_float(tv2);
11285
11286 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11287 }
11288#endif
11289
11290 /* tv2string() puts quotes around a string and allocates memory. Don't do
11291 * that for string variables. Use a single quote when comparing with a
11292 * non-string to do what the docs promise. */
11293 if (tv1->v_type == VAR_STRING)
11294 {
11295 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11296 p1 = (char_u *)"'";
11297 else
11298 p1 = tv1->vval.v_string;
11299 }
11300 else
11301 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11302 if (tv2->v_type == VAR_STRING)
11303 {
11304 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11305 p2 = (char_u *)"'";
11306 else
11307 p2 = tv2->vval.v_string;
11308 }
11309 else
11310 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11311 if (p1 == NULL)
11312 p1 = (char_u *)"";
11313 if (p2 == NULL)
11314 p2 = (char_u *)"";
11315 if (!sortinfo->item_compare_numeric)
11316 {
11317 if (sortinfo->item_compare_ic)
11318 res = STRICMP(p1, p2);
11319 else
11320 res = STRCMP(p1, p2);
11321 }
11322 else
11323 {
11324 double n1, n2;
11325 n1 = strtod((char *)p1, (char **)&p1);
11326 n2 = strtod((char *)p2, (char **)&p2);
11327 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11328 }
11329
11330 /* When the result would be zero, compare the item indexes. Makes the
11331 * sort stable. */
11332 if (res == 0 && !sortinfo->item_compare_keep_zero)
11333 res = si1->idx > si2->idx ? 1 : -1;
11334
11335 vim_free(tofree1);
11336 vim_free(tofree2);
11337 return res;
11338}
11339
11340 static int
11341#ifdef __BORLANDC__
11342_RTLENTRYF
11343#endif
11344item_compare2(const void *s1, const void *s2)
11345{
11346 sortItem_T *si1, *si2;
11347 int res;
11348 typval_T rettv;
11349 typval_T argv[3];
11350 int dummy;
11351 char_u *func_name;
11352 partial_T *partial = sortinfo->item_compare_partial;
11353
11354 /* shortcut after failure in previous call; compare all items equal */
11355 if (sortinfo->item_compare_func_err)
11356 return 0;
11357
11358 si1 = (sortItem_T *)s1;
11359 si2 = (sortItem_T *)s2;
11360
11361 if (partial == NULL)
11362 func_name = sortinfo->item_compare_func;
11363 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011364 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011365
11366 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11367 * in the copy without changing the original list items. */
11368 copy_tv(&si1->item->li_tv, &argv[0]);
11369 copy_tv(&si2->item->li_tv, &argv[1]);
11370
11371 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11372 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011373 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011374 partial, sortinfo->item_compare_selfdict);
11375 clear_tv(&argv[0]);
11376 clear_tv(&argv[1]);
11377
11378 if (res == FAIL)
11379 res = ITEM_COMPARE_FAIL;
11380 else
11381 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11382 if (sortinfo->item_compare_func_err)
11383 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11384 clear_tv(&rettv);
11385
11386 /* When the result would be zero, compare the pointers themselves. Makes
11387 * the sort stable. */
11388 if (res == 0 && !sortinfo->item_compare_keep_zero)
11389 res = si1->idx > si2->idx ? 1 : -1;
11390
11391 return res;
11392}
11393
11394/*
11395 * "sort({list})" function
11396 */
11397 static void
11398do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11399{
11400 list_T *l;
11401 listitem_T *li;
11402 sortItem_T *ptrs;
11403 sortinfo_T *old_sortinfo;
11404 sortinfo_T info;
11405 long len;
11406 long i;
11407
11408 /* Pointer to current info struct used in compare function. Save and
11409 * restore the current one for nested calls. */
11410 old_sortinfo = sortinfo;
11411 sortinfo = &info;
11412
11413 if (argvars[0].v_type != VAR_LIST)
11414 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11415 else
11416 {
11417 l = argvars[0].vval.v_list;
11418 if (l == NULL || tv_check_lock(l->lv_lock,
11419 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11420 TRUE))
11421 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011422 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011423
11424 len = list_len(l);
11425 if (len <= 1)
11426 goto theend; /* short list sorts pretty quickly */
11427
11428 info.item_compare_ic = FALSE;
11429 info.item_compare_numeric = FALSE;
11430 info.item_compare_numbers = FALSE;
11431#ifdef FEAT_FLOAT
11432 info.item_compare_float = FALSE;
11433#endif
11434 info.item_compare_func = NULL;
11435 info.item_compare_partial = NULL;
11436 info.item_compare_selfdict = NULL;
11437 if (argvars[1].v_type != VAR_UNKNOWN)
11438 {
11439 /* optional second argument: {func} */
11440 if (argvars[1].v_type == VAR_FUNC)
11441 info.item_compare_func = argvars[1].vval.v_string;
11442 else if (argvars[1].v_type == VAR_PARTIAL)
11443 info.item_compare_partial = argvars[1].vval.v_partial;
11444 else
11445 {
11446 int error = FALSE;
11447
11448 i = (long)get_tv_number_chk(&argvars[1], &error);
11449 if (error)
11450 goto theend; /* type error; errmsg already given */
11451 if (i == 1)
11452 info.item_compare_ic = TRUE;
11453 else if (argvars[1].v_type != VAR_NUMBER)
11454 info.item_compare_func = get_tv_string(&argvars[1]);
11455 else if (i != 0)
11456 {
11457 EMSG(_(e_invarg));
11458 goto theend;
11459 }
11460 if (info.item_compare_func != NULL)
11461 {
11462 if (*info.item_compare_func == NUL)
11463 {
11464 /* empty string means default sort */
11465 info.item_compare_func = NULL;
11466 }
11467 else if (STRCMP(info.item_compare_func, "n") == 0)
11468 {
11469 info.item_compare_func = NULL;
11470 info.item_compare_numeric = TRUE;
11471 }
11472 else if (STRCMP(info.item_compare_func, "N") == 0)
11473 {
11474 info.item_compare_func = NULL;
11475 info.item_compare_numbers = TRUE;
11476 }
11477#ifdef FEAT_FLOAT
11478 else if (STRCMP(info.item_compare_func, "f") == 0)
11479 {
11480 info.item_compare_func = NULL;
11481 info.item_compare_float = TRUE;
11482 }
11483#endif
11484 else if (STRCMP(info.item_compare_func, "i") == 0)
11485 {
11486 info.item_compare_func = NULL;
11487 info.item_compare_ic = TRUE;
11488 }
11489 }
11490 }
11491
11492 if (argvars[2].v_type != VAR_UNKNOWN)
11493 {
11494 /* optional third argument: {dict} */
11495 if (argvars[2].v_type != VAR_DICT)
11496 {
11497 EMSG(_(e_dictreq));
11498 goto theend;
11499 }
11500 info.item_compare_selfdict = argvars[2].vval.v_dict;
11501 }
11502 }
11503
11504 /* Make an array with each entry pointing to an item in the List. */
11505 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11506 if (ptrs == NULL)
11507 goto theend;
11508
11509 i = 0;
11510 if (sort)
11511 {
11512 /* sort(): ptrs will be the list to sort */
11513 for (li = l->lv_first; li != NULL; li = li->li_next)
11514 {
11515 ptrs[i].item = li;
11516 ptrs[i].idx = i;
11517 ++i;
11518 }
11519
11520 info.item_compare_func_err = FALSE;
11521 info.item_compare_keep_zero = FALSE;
11522 /* test the compare function */
11523 if ((info.item_compare_func != NULL
11524 || info.item_compare_partial != NULL)
11525 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11526 == ITEM_COMPARE_FAIL)
11527 EMSG(_("E702: Sort compare function failed"));
11528 else
11529 {
11530 /* Sort the array with item pointers. */
11531 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11532 info.item_compare_func == NULL
11533 && info.item_compare_partial == NULL
11534 ? item_compare : item_compare2);
11535
11536 if (!info.item_compare_func_err)
11537 {
11538 /* Clear the List and append the items in sorted order. */
11539 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11540 l->lv_len = 0;
11541 for (i = 0; i < len; ++i)
11542 list_append(l, ptrs[i].item);
11543 }
11544 }
11545 }
11546 else
11547 {
11548 int (*item_compare_func_ptr)(const void *, const void *);
11549
11550 /* f_uniq(): ptrs will be a stack of items to remove */
11551 info.item_compare_func_err = FALSE;
11552 info.item_compare_keep_zero = TRUE;
11553 item_compare_func_ptr = info.item_compare_func != NULL
11554 || info.item_compare_partial != NULL
11555 ? item_compare2 : item_compare;
11556
11557 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11558 li = li->li_next)
11559 {
11560 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11561 == 0)
11562 ptrs[i++].item = li;
11563 if (info.item_compare_func_err)
11564 {
11565 EMSG(_("E882: Uniq compare function failed"));
11566 break;
11567 }
11568 }
11569
11570 if (!info.item_compare_func_err)
11571 {
11572 while (--i >= 0)
11573 {
11574 li = ptrs[i].item->li_next;
11575 ptrs[i].item->li_next = li->li_next;
11576 if (li->li_next != NULL)
11577 li->li_next->li_prev = ptrs[i].item;
11578 else
11579 l->lv_last = ptrs[i].item;
11580 list_fix_watch(l, li);
11581 listitem_free(li);
11582 l->lv_len--;
11583 }
11584 }
11585 }
11586
11587 vim_free(ptrs);
11588 }
11589theend:
11590 sortinfo = old_sortinfo;
11591}
11592
11593/*
11594 * "sort({list})" function
11595 */
11596 static void
11597f_sort(typval_T *argvars, typval_T *rettv)
11598{
11599 do_sort_uniq(argvars, rettv, TRUE);
11600}
11601
11602/*
11603 * "uniq({list})" function
11604 */
11605 static void
11606f_uniq(typval_T *argvars, typval_T *rettv)
11607{
11608 do_sort_uniq(argvars, rettv, FALSE);
11609}
11610
11611/*
11612 * "soundfold({word})" function
11613 */
11614 static void
11615f_soundfold(typval_T *argvars, typval_T *rettv)
11616{
11617 char_u *s;
11618
11619 rettv->v_type = VAR_STRING;
11620 s = get_tv_string(&argvars[0]);
11621#ifdef FEAT_SPELL
11622 rettv->vval.v_string = eval_soundfold(s);
11623#else
11624 rettv->vval.v_string = vim_strsave(s);
11625#endif
11626}
11627
11628/*
11629 * "spellbadword()" function
11630 */
11631 static void
11632f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11633{
11634 char_u *word = (char_u *)"";
11635 hlf_T attr = HLF_COUNT;
11636 int len = 0;
11637
11638 if (rettv_list_alloc(rettv) == FAIL)
11639 return;
11640
11641#ifdef FEAT_SPELL
11642 if (argvars[0].v_type == VAR_UNKNOWN)
11643 {
11644 /* Find the start and length of the badly spelled word. */
11645 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11646 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011647 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011648 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011649 curwin->w_set_curswant = TRUE;
11650 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011651 }
11652 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11653 {
11654 char_u *str = get_tv_string_chk(&argvars[0]);
11655 int capcol = -1;
11656
11657 if (str != NULL)
11658 {
11659 /* Check the argument for spelling. */
11660 while (*str != NUL)
11661 {
11662 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11663 if (attr != HLF_COUNT)
11664 {
11665 word = str;
11666 break;
11667 }
11668 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020011669 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011670 }
11671 }
11672 }
11673#endif
11674
11675 list_append_string(rettv->vval.v_list, word, len);
11676 list_append_string(rettv->vval.v_list, (char_u *)(
11677 attr == HLF_SPB ? "bad" :
11678 attr == HLF_SPR ? "rare" :
11679 attr == HLF_SPL ? "local" :
11680 attr == HLF_SPC ? "caps" :
11681 ""), -1);
11682}
11683
11684/*
11685 * "spellsuggest()" function
11686 */
11687 static void
11688f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11689{
11690#ifdef FEAT_SPELL
11691 char_u *str;
11692 int typeerr = FALSE;
11693 int maxcount;
11694 garray_T ga;
11695 int i;
11696 listitem_T *li;
11697 int need_capital = FALSE;
11698#endif
11699
11700 if (rettv_list_alloc(rettv) == FAIL)
11701 return;
11702
11703#ifdef FEAT_SPELL
11704 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11705 {
11706 str = get_tv_string(&argvars[0]);
11707 if (argvars[1].v_type != VAR_UNKNOWN)
11708 {
11709 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11710 if (maxcount <= 0)
11711 return;
11712 if (argvars[2].v_type != VAR_UNKNOWN)
11713 {
11714 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11715 if (typeerr)
11716 return;
11717 }
11718 }
11719 else
11720 maxcount = 25;
11721
11722 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11723
11724 for (i = 0; i < ga.ga_len; ++i)
11725 {
11726 str = ((char_u **)ga.ga_data)[i];
11727
11728 li = listitem_alloc();
11729 if (li == NULL)
11730 vim_free(str);
11731 else
11732 {
11733 li->li_tv.v_type = VAR_STRING;
11734 li->li_tv.v_lock = 0;
11735 li->li_tv.vval.v_string = str;
11736 list_append(rettv->vval.v_list, li);
11737 }
11738 }
11739 ga_clear(&ga);
11740 }
11741#endif
11742}
11743
11744 static void
11745f_split(typval_T *argvars, typval_T *rettv)
11746{
11747 char_u *str;
11748 char_u *end;
11749 char_u *pat = NULL;
11750 regmatch_T regmatch;
11751 char_u patbuf[NUMBUFLEN];
11752 char_u *save_cpo;
11753 int match;
11754 colnr_T col = 0;
11755 int keepempty = FALSE;
11756 int typeerr = FALSE;
11757
11758 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11759 save_cpo = p_cpo;
11760 p_cpo = (char_u *)"";
11761
11762 str = get_tv_string(&argvars[0]);
11763 if (argvars[1].v_type != VAR_UNKNOWN)
11764 {
11765 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11766 if (pat == NULL)
11767 typeerr = TRUE;
11768 if (argvars[2].v_type != VAR_UNKNOWN)
11769 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11770 }
11771 if (pat == NULL || *pat == NUL)
11772 pat = (char_u *)"[\\x01- ]\\+";
11773
11774 if (rettv_list_alloc(rettv) == FAIL)
11775 return;
11776 if (typeerr)
11777 return;
11778
11779 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11780 if (regmatch.regprog != NULL)
11781 {
11782 regmatch.rm_ic = FALSE;
11783 while (*str != NUL || keepempty)
11784 {
11785 if (*str == NUL)
11786 match = FALSE; /* empty item at the end */
11787 else
11788 match = vim_regexec_nl(&regmatch, str, col);
11789 if (match)
11790 end = regmatch.startp[0];
11791 else
11792 end = str + STRLEN(str);
11793 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11794 && *str != NUL && match && end < regmatch.endp[0]))
11795 {
11796 if (list_append_string(rettv->vval.v_list, str,
11797 (int)(end - str)) == FAIL)
11798 break;
11799 }
11800 if (!match)
11801 break;
11802 /* Advance to just after the match. */
11803 if (regmatch.endp[0] > str)
11804 col = 0;
11805 else
11806 {
11807 /* Don't get stuck at the same match. */
11808#ifdef FEAT_MBYTE
11809 col = (*mb_ptr2len)(regmatch.endp[0]);
11810#else
11811 col = 1;
11812#endif
11813 }
11814 str = regmatch.endp[0];
11815 }
11816
11817 vim_regfree(regmatch.regprog);
11818 }
11819
11820 p_cpo = save_cpo;
11821}
11822
11823#ifdef FEAT_FLOAT
11824/*
11825 * "sqrt()" function
11826 */
11827 static void
11828f_sqrt(typval_T *argvars, typval_T *rettv)
11829{
11830 float_T f = 0.0;
11831
11832 rettv->v_type = VAR_FLOAT;
11833 if (get_float_arg(argvars, &f) == OK)
11834 rettv->vval.v_float = sqrt(f);
11835 else
11836 rettv->vval.v_float = 0.0;
11837}
11838
11839/*
11840 * "str2float()" function
11841 */
11842 static void
11843f_str2float(typval_T *argvars, typval_T *rettv)
11844{
11845 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011846 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011847
Bram Moolenaar08243d22017-01-10 16:12:29 +010011848 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011849 p = skipwhite(p + 1);
11850 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011851 if (isneg)
11852 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011853 rettv->v_type = VAR_FLOAT;
11854}
11855#endif
11856
11857/*
11858 * "str2nr()" function
11859 */
11860 static void
11861f_str2nr(typval_T *argvars, typval_T *rettv)
11862{
11863 int base = 10;
11864 char_u *p;
11865 varnumber_T n;
11866 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011867 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011868
11869 if (argvars[1].v_type != VAR_UNKNOWN)
11870 {
11871 base = (int)get_tv_number(&argvars[1]);
11872 if (base != 2 && base != 8 && base != 10 && base != 16)
11873 {
11874 EMSG(_(e_invarg));
11875 return;
11876 }
11877 }
11878
11879 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011880 isneg = (*p == '-');
11881 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011882 p = skipwhite(p + 1);
11883 switch (base)
11884 {
11885 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11886 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11887 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11888 default: what = 0;
11889 }
11890 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011891 if (isneg)
11892 rettv->vval.v_number = -n;
11893 else
11894 rettv->vval.v_number = n;
11895
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011896}
11897
11898#ifdef HAVE_STRFTIME
11899/*
11900 * "strftime({format}[, {time}])" function
11901 */
11902 static void
11903f_strftime(typval_T *argvars, typval_T *rettv)
11904{
11905 char_u result_buf[256];
11906 struct tm *curtime;
11907 time_t seconds;
11908 char_u *p;
11909
11910 rettv->v_type = VAR_STRING;
11911
11912 p = get_tv_string(&argvars[0]);
11913 if (argvars[1].v_type == VAR_UNKNOWN)
11914 seconds = time(NULL);
11915 else
11916 seconds = (time_t)get_tv_number(&argvars[1]);
11917 curtime = localtime(&seconds);
11918 /* MSVC returns NULL for an invalid value of seconds. */
11919 if (curtime == NULL)
11920 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11921 else
11922 {
11923# ifdef FEAT_MBYTE
11924 vimconv_T conv;
11925 char_u *enc;
11926
11927 conv.vc_type = CONV_NONE;
11928 enc = enc_locale();
11929 convert_setup(&conv, p_enc, enc);
11930 if (conv.vc_type != CONV_NONE)
11931 p = string_convert(&conv, p, NULL);
11932# endif
11933 if (p != NULL)
11934 (void)strftime((char *)result_buf, sizeof(result_buf),
11935 (char *)p, curtime);
11936 else
11937 result_buf[0] = NUL;
11938
11939# ifdef FEAT_MBYTE
11940 if (conv.vc_type != CONV_NONE)
11941 vim_free(p);
11942 convert_setup(&conv, enc, p_enc);
11943 if (conv.vc_type != CONV_NONE)
11944 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11945 else
11946# endif
11947 rettv->vval.v_string = vim_strsave(result_buf);
11948
11949# ifdef FEAT_MBYTE
11950 /* Release conversion descriptors */
11951 convert_setup(&conv, NULL, NULL);
11952 vim_free(enc);
11953# endif
11954 }
11955}
11956#endif
11957
11958/*
11959 * "strgetchar()" function
11960 */
11961 static void
11962f_strgetchar(typval_T *argvars, typval_T *rettv)
11963{
11964 char_u *str;
11965 int len;
11966 int error = FALSE;
11967 int charidx;
11968
11969 rettv->vval.v_number = -1;
11970 str = get_tv_string_chk(&argvars[0]);
11971 if (str == NULL)
11972 return;
11973 len = (int)STRLEN(str);
11974 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11975 if (error)
11976 return;
11977#ifdef FEAT_MBYTE
11978 {
11979 int byteidx = 0;
11980
11981 while (charidx >= 0 && byteidx < len)
11982 {
11983 if (charidx == 0)
11984 {
11985 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11986 break;
11987 }
11988 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011989 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011990 }
11991 }
11992#else
11993 if (charidx < len)
11994 rettv->vval.v_number = str[charidx];
11995#endif
11996}
11997
11998/*
11999 * "stridx()" function
12000 */
12001 static void
12002f_stridx(typval_T *argvars, typval_T *rettv)
12003{
12004 char_u buf[NUMBUFLEN];
12005 char_u *needle;
12006 char_u *haystack;
12007 char_u *save_haystack;
12008 char_u *pos;
12009 int start_idx;
12010
12011 needle = get_tv_string_chk(&argvars[1]);
12012 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
12013 rettv->vval.v_number = -1;
12014 if (needle == NULL || haystack == NULL)
12015 return; /* type error; errmsg already given */
12016
12017 if (argvars[2].v_type != VAR_UNKNOWN)
12018 {
12019 int error = FALSE;
12020
12021 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
12022 if (error || start_idx >= (int)STRLEN(haystack))
12023 return;
12024 if (start_idx >= 0)
12025 haystack += start_idx;
12026 }
12027
12028 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12029 if (pos != NULL)
12030 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12031}
12032
12033/*
12034 * "string()" function
12035 */
12036 static void
12037f_string(typval_T *argvars, typval_T *rettv)
12038{
12039 char_u *tofree;
12040 char_u numbuf[NUMBUFLEN];
12041
12042 rettv->v_type = VAR_STRING;
12043 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12044 get_copyID());
12045 /* Make a copy if we have a value but it's not in allocated memory. */
12046 if (rettv->vval.v_string != NULL && tofree == NULL)
12047 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12048}
12049
12050/*
12051 * "strlen()" function
12052 */
12053 static void
12054f_strlen(typval_T *argvars, typval_T *rettv)
12055{
12056 rettv->vval.v_number = (varnumber_T)(STRLEN(
12057 get_tv_string(&argvars[0])));
12058}
12059
12060/*
12061 * "strchars()" function
12062 */
12063 static void
12064f_strchars(typval_T *argvars, typval_T *rettv)
12065{
12066 char_u *s = get_tv_string(&argvars[0]);
12067 int skipcc = 0;
12068#ifdef FEAT_MBYTE
12069 varnumber_T len = 0;
12070 int (*func_mb_ptr2char_adv)(char_u **pp);
12071#endif
12072
12073 if (argvars[1].v_type != VAR_UNKNOWN)
12074 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
12075 if (skipcc < 0 || skipcc > 1)
12076 EMSG(_(e_invarg));
12077 else
12078 {
12079#ifdef FEAT_MBYTE
12080 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12081 while (*s != NUL)
12082 {
12083 func_mb_ptr2char_adv(&s);
12084 ++len;
12085 }
12086 rettv->vval.v_number = len;
12087#else
12088 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
12089#endif
12090 }
12091}
12092
12093/*
12094 * "strdisplaywidth()" function
12095 */
12096 static void
12097f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12098{
12099 char_u *s = get_tv_string(&argvars[0]);
12100 int col = 0;
12101
12102 if (argvars[1].v_type != VAR_UNKNOWN)
12103 col = (int)get_tv_number(&argvars[1]);
12104
12105 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12106}
12107
12108/*
12109 * "strwidth()" function
12110 */
12111 static void
12112f_strwidth(typval_T *argvars, typval_T *rettv)
12113{
12114 char_u *s = get_tv_string(&argvars[0]);
12115
12116 rettv->vval.v_number = (varnumber_T)(
12117#ifdef FEAT_MBYTE
12118 mb_string2cells(s, -1)
12119#else
12120 STRLEN(s)
12121#endif
12122 );
12123}
12124
12125/*
12126 * "strcharpart()" function
12127 */
12128 static void
12129f_strcharpart(typval_T *argvars, typval_T *rettv)
12130{
12131#ifdef FEAT_MBYTE
12132 char_u *p;
12133 int nchar;
12134 int nbyte = 0;
12135 int charlen;
12136 int len = 0;
12137 int slen;
12138 int error = FALSE;
12139
12140 p = get_tv_string(&argvars[0]);
12141 slen = (int)STRLEN(p);
12142
12143 nchar = (int)get_tv_number_chk(&argvars[1], &error);
12144 if (!error)
12145 {
12146 if (nchar > 0)
12147 while (nchar > 0 && nbyte < slen)
12148 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012149 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012150 --nchar;
12151 }
12152 else
12153 nbyte = nchar;
12154 if (argvars[2].v_type != VAR_UNKNOWN)
12155 {
12156 charlen = (int)get_tv_number(&argvars[2]);
12157 while (charlen > 0 && nbyte + len < slen)
12158 {
12159 int off = nbyte + len;
12160
12161 if (off < 0)
12162 len += 1;
12163 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012164 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012165 --charlen;
12166 }
12167 }
12168 else
12169 len = slen - nbyte; /* default: all bytes that are available. */
12170 }
12171
12172 /*
12173 * Only return the overlap between the specified part and the actual
12174 * string.
12175 */
12176 if (nbyte < 0)
12177 {
12178 len += nbyte;
12179 nbyte = 0;
12180 }
12181 else if (nbyte > slen)
12182 nbyte = slen;
12183 if (len < 0)
12184 len = 0;
12185 else if (nbyte + len > slen)
12186 len = slen - nbyte;
12187
12188 rettv->v_type = VAR_STRING;
12189 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12190#else
12191 f_strpart(argvars, rettv);
12192#endif
12193}
12194
12195/*
12196 * "strpart()" function
12197 */
12198 static void
12199f_strpart(typval_T *argvars, typval_T *rettv)
12200{
12201 char_u *p;
12202 int n;
12203 int len;
12204 int slen;
12205 int error = FALSE;
12206
12207 p = get_tv_string(&argvars[0]);
12208 slen = (int)STRLEN(p);
12209
12210 n = (int)get_tv_number_chk(&argvars[1], &error);
12211 if (error)
12212 len = 0;
12213 else if (argvars[2].v_type != VAR_UNKNOWN)
12214 len = (int)get_tv_number(&argvars[2]);
12215 else
12216 len = slen - n; /* default len: all bytes that are available. */
12217
12218 /*
12219 * Only return the overlap between the specified part and the actual
12220 * string.
12221 */
12222 if (n < 0)
12223 {
12224 len += n;
12225 n = 0;
12226 }
12227 else if (n > slen)
12228 n = slen;
12229 if (len < 0)
12230 len = 0;
12231 else if (n + len > slen)
12232 len = slen - n;
12233
12234 rettv->v_type = VAR_STRING;
12235 rettv->vval.v_string = vim_strnsave(p + n, len);
12236}
12237
12238/*
12239 * "strridx()" function
12240 */
12241 static void
12242f_strridx(typval_T *argvars, typval_T *rettv)
12243{
12244 char_u buf[NUMBUFLEN];
12245 char_u *needle;
12246 char_u *haystack;
12247 char_u *rest;
12248 char_u *lastmatch = NULL;
12249 int haystack_len, end_idx;
12250
12251 needle = get_tv_string_chk(&argvars[1]);
12252 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12253
12254 rettv->vval.v_number = -1;
12255 if (needle == NULL || haystack == NULL)
12256 return; /* type error; errmsg already given */
12257
12258 haystack_len = (int)STRLEN(haystack);
12259 if (argvars[2].v_type != VAR_UNKNOWN)
12260 {
12261 /* Third argument: upper limit for index */
12262 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12263 if (end_idx < 0)
12264 return; /* can never find a match */
12265 }
12266 else
12267 end_idx = haystack_len;
12268
12269 if (*needle == NUL)
12270 {
12271 /* Empty string matches past the end. */
12272 lastmatch = haystack + end_idx;
12273 }
12274 else
12275 {
12276 for (rest = haystack; *rest != '\0'; ++rest)
12277 {
12278 rest = (char_u *)strstr((char *)rest, (char *)needle);
12279 if (rest == NULL || rest > haystack + end_idx)
12280 break;
12281 lastmatch = rest;
12282 }
12283 }
12284
12285 if (lastmatch == NULL)
12286 rettv->vval.v_number = -1;
12287 else
12288 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12289}
12290
12291/*
12292 * "strtrans()" function
12293 */
12294 static void
12295f_strtrans(typval_T *argvars, typval_T *rettv)
12296{
12297 rettv->v_type = VAR_STRING;
12298 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12299}
12300
12301/*
12302 * "submatch()" function
12303 */
12304 static void
12305f_submatch(typval_T *argvars, typval_T *rettv)
12306{
12307 int error = FALSE;
12308 int no;
12309 int retList = 0;
12310
12311 no = (int)get_tv_number_chk(&argvars[0], &error);
12312 if (error)
12313 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012314 if (no < 0 || no >= NSUBEXP)
12315 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012316 EMSGN(_("E935: invalid submatch number: %d"), no);
12317 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012318 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012319 if (argvars[1].v_type != VAR_UNKNOWN)
12320 retList = (int)get_tv_number_chk(&argvars[1], &error);
12321 if (error)
12322 return;
12323
12324 if (retList == 0)
12325 {
12326 rettv->v_type = VAR_STRING;
12327 rettv->vval.v_string = reg_submatch(no);
12328 }
12329 else
12330 {
12331 rettv->v_type = VAR_LIST;
12332 rettv->vval.v_list = reg_submatch_list(no);
12333 }
12334}
12335
12336/*
12337 * "substitute()" function
12338 */
12339 static void
12340f_substitute(typval_T *argvars, typval_T *rettv)
12341{
12342 char_u patbuf[NUMBUFLEN];
12343 char_u subbuf[NUMBUFLEN];
12344 char_u flagsbuf[NUMBUFLEN];
12345
12346 char_u *str = get_tv_string_chk(&argvars[0]);
12347 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012348 char_u *sub = NULL;
12349 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012350 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12351
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012352 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12353 expr = &argvars[2];
12354 else
12355 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12356
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012358 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12359 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012360 rettv->vval.v_string = NULL;
12361 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012362 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012363}
12364
12365/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012366 * "swapinfo(swap_filename)" function
12367 */
12368 static void
12369f_swapinfo(typval_T *argvars, typval_T *rettv)
12370{
12371 if (rettv_dict_alloc(rettv) == OK)
12372 get_b0_dict(get_tv_string(argvars), rettv->vval.v_dict);
12373}
12374
12375/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020012376 * "swapname(expr)" function
12377 */
12378 static void
12379f_swapname(typval_T *argvars, typval_T *rettv)
12380{
12381 buf_T *buf;
12382
12383 rettv->v_type = VAR_STRING;
12384 buf = get_buf_tv(&argvars[0], FALSE);
12385 if (buf == NULL || buf->b_ml.ml_mfp == NULL
12386 || buf->b_ml.ml_mfp->mf_fname == NULL)
12387 rettv->vval.v_string = NULL;
12388 else
12389 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
12390}
12391
12392/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012393 * "synID(lnum, col, trans)" function
12394 */
12395 static void
12396f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12397{
12398 int id = 0;
12399#ifdef FEAT_SYN_HL
12400 linenr_T lnum;
12401 colnr_T col;
12402 int trans;
12403 int transerr = FALSE;
12404
12405 lnum = get_tv_lnum(argvars); /* -1 on type error */
12406 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12407 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12408
12409 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12410 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12411 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12412#endif
12413
12414 rettv->vval.v_number = id;
12415}
12416
12417/*
12418 * "synIDattr(id, what [, mode])" function
12419 */
12420 static void
12421f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12422{
12423 char_u *p = NULL;
12424#ifdef FEAT_SYN_HL
12425 int id;
12426 char_u *what;
12427 char_u *mode;
12428 char_u modebuf[NUMBUFLEN];
12429 int modec;
12430
12431 id = (int)get_tv_number(&argvars[0]);
12432 what = get_tv_string(&argvars[1]);
12433 if (argvars[2].v_type != VAR_UNKNOWN)
12434 {
12435 mode = get_tv_string_buf(&argvars[2], modebuf);
12436 modec = TOLOWER_ASC(mode[0]);
12437 if (modec != 't' && modec != 'c' && modec != 'g')
12438 modec = 0; /* replace invalid with current */
12439 }
12440 else
12441 {
12442#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12443 if (USE_24BIT)
12444 modec = 'g';
12445 else
12446#endif
12447 if (t_colors > 1)
12448 modec = 'c';
12449 else
12450 modec = 't';
12451 }
12452
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012453 switch (TOLOWER_ASC(what[0]))
12454 {
12455 case 'b':
12456 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12457 p = highlight_color(id, what, modec);
12458 else /* bold */
12459 p = highlight_has_attr(id, HL_BOLD, modec);
12460 break;
12461
12462 case 'f': /* fg[#] or font */
12463 p = highlight_color(id, what, modec);
12464 break;
12465
12466 case 'i':
12467 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12468 p = highlight_has_attr(id, HL_INVERSE, modec);
12469 else /* italic */
12470 p = highlight_has_attr(id, HL_ITALIC, modec);
12471 break;
12472
12473 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012474 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012475 break;
12476
12477 case 'r': /* reverse */
12478 p = highlight_has_attr(id, HL_INVERSE, modec);
12479 break;
12480
12481 case 's':
12482 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12483 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012484 /* strikeout */
12485 else if (TOLOWER_ASC(what[1]) == 't' &&
12486 TOLOWER_ASC(what[2]) == 'r')
12487 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012488 else /* standout */
12489 p = highlight_has_attr(id, HL_STANDOUT, modec);
12490 break;
12491
12492 case 'u':
12493 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12494 /* underline */
12495 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12496 else
12497 /* undercurl */
12498 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12499 break;
12500 }
12501
12502 if (p != NULL)
12503 p = vim_strsave(p);
12504#endif
12505 rettv->v_type = VAR_STRING;
12506 rettv->vval.v_string = p;
12507}
12508
12509/*
12510 * "synIDtrans(id)" function
12511 */
12512 static void
12513f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12514{
12515 int id;
12516
12517#ifdef FEAT_SYN_HL
12518 id = (int)get_tv_number(&argvars[0]);
12519
12520 if (id > 0)
12521 id = syn_get_final_id(id);
12522 else
12523#endif
12524 id = 0;
12525
12526 rettv->vval.v_number = id;
12527}
12528
12529/*
12530 * "synconcealed(lnum, col)" function
12531 */
12532 static void
12533f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12534{
12535#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12536 linenr_T lnum;
12537 colnr_T col;
12538 int syntax_flags = 0;
12539 int cchar;
12540 int matchid = 0;
12541 char_u str[NUMBUFLEN];
12542#endif
12543
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012544 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012545
12546#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12547 lnum = get_tv_lnum(argvars); /* -1 on type error */
12548 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12549
12550 vim_memset(str, NUL, sizeof(str));
12551
12552 if (rettv_list_alloc(rettv) != FAIL)
12553 {
12554 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12555 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12556 && curwin->w_p_cole > 0)
12557 {
12558 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12559 syntax_flags = get_syntax_info(&matchid);
12560
12561 /* get the conceal character */
12562 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12563 {
12564 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012565 if (cchar == NUL && curwin->w_p_cole == 1)
12566 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012567 if (cchar != NUL)
12568 {
12569# ifdef FEAT_MBYTE
12570 if (has_mbyte)
12571 (*mb_char2bytes)(cchar, str);
12572 else
12573# endif
12574 str[0] = cchar;
12575 }
12576 }
12577 }
12578
12579 list_append_number(rettv->vval.v_list,
12580 (syntax_flags & HL_CONCEAL) != 0);
12581 /* -1 to auto-determine strlen */
12582 list_append_string(rettv->vval.v_list, str, -1);
12583 list_append_number(rettv->vval.v_list, matchid);
12584 }
12585#endif
12586}
12587
12588/*
12589 * "synstack(lnum, col)" function
12590 */
12591 static void
12592f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12593{
12594#ifdef FEAT_SYN_HL
12595 linenr_T lnum;
12596 colnr_T col;
12597 int i;
12598 int id;
12599#endif
12600
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012601 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012602
12603#ifdef FEAT_SYN_HL
12604 lnum = get_tv_lnum(argvars); /* -1 on type error */
12605 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12606
12607 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12608 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12609 && rettv_list_alloc(rettv) != FAIL)
12610 {
12611 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12612 for (i = 0; ; ++i)
12613 {
12614 id = syn_get_stack_item(i);
12615 if (id < 0)
12616 break;
12617 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12618 break;
12619 }
12620 }
12621#endif
12622}
12623
12624 static void
12625get_cmd_output_as_rettv(
12626 typval_T *argvars,
12627 typval_T *rettv,
12628 int retlist)
12629{
12630 char_u *res = NULL;
12631 char_u *p;
12632 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012633 int err = FALSE;
12634 FILE *fd;
12635 list_T *list = NULL;
12636 int flags = SHELL_SILENT;
12637
12638 rettv->v_type = VAR_STRING;
12639 rettv->vval.v_string = NULL;
12640 if (check_restricted() || check_secure())
12641 goto errret;
12642
12643 if (argvars[1].v_type != VAR_UNKNOWN)
12644 {
12645 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012646 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012647 * command.
12648 */
12649 if ((infile = vim_tempname('i', TRUE)) == NULL)
12650 {
12651 EMSG(_(e_notmp));
12652 goto errret;
12653 }
12654
12655 fd = mch_fopen((char *)infile, WRITEBIN);
12656 if (fd == NULL)
12657 {
12658 EMSG2(_(e_notopen), infile);
12659 goto errret;
12660 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012661 if (argvars[1].v_type == VAR_NUMBER)
12662 {
12663 linenr_T lnum;
12664 buf_T *buf;
12665
12666 buf = buflist_findnr(argvars[1].vval.v_number);
12667 if (buf == NULL)
12668 {
12669 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012670 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012671 goto errret;
12672 }
12673
12674 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12675 {
12676 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12677 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12678 {
12679 err = TRUE;
12680 break;
12681 }
12682 if (putc(NL, fd) == EOF)
12683 {
12684 err = TRUE;
12685 break;
12686 }
12687 }
12688 }
12689 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012690 {
12691 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12692 err = TRUE;
12693 }
12694 else
12695 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012696 size_t len;
12697 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012698
12699 p = get_tv_string_buf_chk(&argvars[1], buf);
12700 if (p == NULL)
12701 {
12702 fclose(fd);
12703 goto errret; /* type error; errmsg already given */
12704 }
12705 len = STRLEN(p);
12706 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12707 err = TRUE;
12708 }
12709 if (fclose(fd) != 0)
12710 err = TRUE;
12711 if (err)
12712 {
12713 EMSG(_("E677: Error writing temp file"));
12714 goto errret;
12715 }
12716 }
12717
12718 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12719 * echoes typeahead, that messes up the display. */
12720 if (!msg_silent)
12721 flags += SHELL_COOKED;
12722
12723 if (retlist)
12724 {
12725 int len;
12726 listitem_T *li;
12727 char_u *s = NULL;
12728 char_u *start;
12729 char_u *end;
12730 int i;
12731
12732 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12733 if (res == NULL)
12734 goto errret;
12735
12736 list = list_alloc();
12737 if (list == NULL)
12738 goto errret;
12739
12740 for (i = 0; i < len; ++i)
12741 {
12742 start = res + i;
12743 while (i < len && res[i] != NL)
12744 ++i;
12745 end = res + i;
12746
12747 s = alloc((unsigned)(end - start + 1));
12748 if (s == NULL)
12749 goto errret;
12750
12751 for (p = s; start < end; ++p, ++start)
12752 *p = *start == NUL ? NL : *start;
12753 *p = NUL;
12754
12755 li = listitem_alloc();
12756 if (li == NULL)
12757 {
12758 vim_free(s);
12759 goto errret;
12760 }
12761 li->li_tv.v_type = VAR_STRING;
12762 li->li_tv.v_lock = 0;
12763 li->li_tv.vval.v_string = s;
12764 list_append(list, li);
12765 }
12766
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012767 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012768 list = NULL;
12769 }
12770 else
12771 {
12772 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12773#ifdef USE_CR
12774 /* translate <CR> into <NL> */
12775 if (res != NULL)
12776 {
12777 char_u *s;
12778
12779 for (s = res; *s; ++s)
12780 {
12781 if (*s == CAR)
12782 *s = NL;
12783 }
12784 }
12785#else
12786# ifdef USE_CRNL
12787 /* translate <CR><NL> into <NL> */
12788 if (res != NULL)
12789 {
12790 char_u *s, *d;
12791
12792 d = res;
12793 for (s = res; *s; ++s)
12794 {
12795 if (s[0] == CAR && s[1] == NL)
12796 ++s;
12797 *d++ = *s;
12798 }
12799 *d = NUL;
12800 }
12801# endif
12802#endif
12803 rettv->vval.v_string = res;
12804 res = NULL;
12805 }
12806
12807errret:
12808 if (infile != NULL)
12809 {
12810 mch_remove(infile);
12811 vim_free(infile);
12812 }
12813 if (res != NULL)
12814 vim_free(res);
12815 if (list != NULL)
12816 list_free(list);
12817}
12818
12819/*
12820 * "system()" function
12821 */
12822 static void
12823f_system(typval_T *argvars, typval_T *rettv)
12824{
12825 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12826}
12827
12828/*
12829 * "systemlist()" function
12830 */
12831 static void
12832f_systemlist(typval_T *argvars, typval_T *rettv)
12833{
12834 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12835}
12836
12837/*
12838 * "tabpagebuflist()" function
12839 */
12840 static void
12841f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12842{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012843 tabpage_T *tp;
12844 win_T *wp = NULL;
12845
12846 if (argvars[0].v_type == VAR_UNKNOWN)
12847 wp = firstwin;
12848 else
12849 {
12850 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12851 if (tp != NULL)
12852 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12853 }
12854 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12855 {
12856 for (; wp != NULL; wp = wp->w_next)
12857 if (list_append_number(rettv->vval.v_list,
12858 wp->w_buffer->b_fnum) == FAIL)
12859 break;
12860 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012861}
12862
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012863/*
12864 * "tabpagenr()" function
12865 */
12866 static void
12867f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12868{
12869 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012870 char_u *arg;
12871
12872 if (argvars[0].v_type != VAR_UNKNOWN)
12873 {
12874 arg = get_tv_string_chk(&argvars[0]);
12875 nr = 0;
12876 if (arg != NULL)
12877 {
12878 if (STRCMP(arg, "$") == 0)
12879 nr = tabpage_index(NULL) - 1;
12880 else
12881 EMSG2(_(e_invexpr2), arg);
12882 }
12883 }
12884 else
12885 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012886 rettv->vval.v_number = nr;
12887}
12888
12889
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012890/*
12891 * Common code for tabpagewinnr() and winnr().
12892 */
12893 static int
12894get_winnr(tabpage_T *tp, typval_T *argvar)
12895{
12896 win_T *twin;
12897 int nr = 1;
12898 win_T *wp;
12899 char_u *arg;
12900
12901 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12902 if (argvar->v_type != VAR_UNKNOWN)
12903 {
12904 arg = get_tv_string_chk(argvar);
12905 if (arg == NULL)
12906 nr = 0; /* type error; errmsg already given */
12907 else if (STRCMP(arg, "$") == 0)
12908 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12909 else if (STRCMP(arg, "#") == 0)
12910 {
12911 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12912 if (twin == NULL)
12913 nr = 0;
12914 }
12915 else
12916 {
12917 EMSG2(_(e_invexpr2), arg);
12918 nr = 0;
12919 }
12920 }
12921
12922 if (nr > 0)
12923 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12924 wp != twin; wp = wp->w_next)
12925 {
12926 if (wp == NULL)
12927 {
12928 /* didn't find it in this tabpage */
12929 nr = 0;
12930 break;
12931 }
12932 ++nr;
12933 }
12934 return nr;
12935}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012936
12937/*
12938 * "tabpagewinnr()" function
12939 */
12940 static void
12941f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12942{
12943 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012944 tabpage_T *tp;
12945
12946 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12947 if (tp == NULL)
12948 nr = 0;
12949 else
12950 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012951 rettv->vval.v_number = nr;
12952}
12953
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012954/*
12955 * "tagfiles()" function
12956 */
12957 static void
12958f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12959{
12960 char_u *fname;
12961 tagname_T tn;
12962 int first;
12963
12964 if (rettv_list_alloc(rettv) == FAIL)
12965 return;
12966 fname = alloc(MAXPATHL);
12967 if (fname == NULL)
12968 return;
12969
12970 for (first = TRUE; ; first = FALSE)
12971 if (get_tagfname(&tn, first, fname) == FAIL
12972 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12973 break;
12974 tagname_free(&tn);
12975 vim_free(fname);
12976}
12977
12978/*
12979 * "taglist()" function
12980 */
12981 static void
12982f_taglist(typval_T *argvars, typval_T *rettv)
12983{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012984 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012985 char_u *tag_pattern;
12986
12987 tag_pattern = get_tv_string(&argvars[0]);
12988
12989 rettv->vval.v_number = FALSE;
12990 if (*tag_pattern == NUL)
12991 return;
12992
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012993 if (argvars[1].v_type != VAR_UNKNOWN)
12994 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012995 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012996 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012997}
12998
12999/*
13000 * "tempname()" function
13001 */
13002 static void
13003f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13004{
13005 static int x = 'A';
13006
13007 rettv->v_type = VAR_STRING;
13008 rettv->vval.v_string = vim_tempname(x, FALSE);
13009
13010 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13011 * names. Skip 'I' and 'O', they are used for shell redirection. */
13012 do
13013 {
13014 if (x == 'Z')
13015 x = '0';
13016 else if (x == '9')
13017 x = 'A';
13018 else
13019 {
13020#ifdef EBCDIC
13021 if (x == 'I')
13022 x = 'J';
13023 else if (x == 'R')
13024 x = 'S';
13025 else
13026#endif
13027 ++x;
13028 }
13029 } while (x == 'I' || x == 'O');
13030}
13031
13032#ifdef FEAT_FLOAT
13033/*
13034 * "tan()" function
13035 */
13036 static void
13037f_tan(typval_T *argvars, typval_T *rettv)
13038{
13039 float_T f = 0.0;
13040
13041 rettv->v_type = VAR_FLOAT;
13042 if (get_float_arg(argvars, &f) == OK)
13043 rettv->vval.v_float = tan(f);
13044 else
13045 rettv->vval.v_float = 0.0;
13046}
13047
13048/*
13049 * "tanh()" function
13050 */
13051 static void
13052f_tanh(typval_T *argvars, typval_T *rettv)
13053{
13054 float_T f = 0.0;
13055
13056 rettv->v_type = VAR_FLOAT;
13057 if (get_float_arg(argvars, &f) == OK)
13058 rettv->vval.v_float = tanh(f);
13059 else
13060 rettv->vval.v_float = 0.0;
13061}
13062#endif
13063
13064/*
13065 * "test_alloc_fail(id, countdown, repeat)" function
13066 */
13067 static void
13068f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13069{
13070 if (argvars[0].v_type != VAR_NUMBER
13071 || argvars[0].vval.v_number <= 0
13072 || argvars[1].v_type != VAR_NUMBER
13073 || argvars[1].vval.v_number < 0
13074 || argvars[2].v_type != VAR_NUMBER)
13075 EMSG(_(e_invarg));
13076 else
13077 {
13078 alloc_fail_id = argvars[0].vval.v_number;
13079 if (alloc_fail_id >= aid_last)
13080 EMSG(_(e_invarg));
13081 alloc_fail_countdown = argvars[1].vval.v_number;
13082 alloc_fail_repeat = argvars[2].vval.v_number;
13083 did_outofmem_msg = FALSE;
13084 }
13085}
13086
13087/*
13088 * "test_autochdir()"
13089 */
13090 static void
13091f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13092{
13093#if defined(FEAT_AUTOCHDIR)
13094 test_autochdir = TRUE;
13095#endif
13096}
13097
13098/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013099 * "test_feedinput()"
13100 */
13101 static void
13102f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13103{
13104#ifdef USE_INPUT_BUF
13105 char_u *val = get_tv_string_chk(&argvars[0]);
13106
13107 if (val != NULL)
13108 {
13109 trash_input_buf();
13110 add_to_input_buf_csi(val, (int)STRLEN(val));
13111 }
13112#endif
13113}
13114
13115/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013116 * "test_option_not_set({name})" function
13117 */
13118 static void
13119f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13120{
13121 char_u *name = (char_u *)"";
13122
13123 if (argvars[0].v_type != VAR_STRING)
13124 EMSG(_(e_invarg));
13125 else
13126 {
Bram Moolenaarbf1c1b82018-09-13 21:30:05 +020013127 name = get_tv_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013128 if (reset_option_was_set(name) == FAIL)
13129 EMSG2(_(e_invarg2), name);
13130 }
13131}
13132
13133/*
13134 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013135 */
13136 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013137f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013138{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013139 char_u *name = (char_u *)"";
13140 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013141 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013142
13143 if (argvars[0].v_type != VAR_STRING
13144 || (argvars[1].v_type) != VAR_NUMBER)
13145 EMSG(_(e_invarg));
13146 else
13147 {
13148 name = get_tv_string_chk(&argvars[0]);
13149 val = (int)get_tv_number(&argvars[1]);
13150
13151 if (STRCMP(name, (char_u *)"redraw") == 0)
13152 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013153 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13154 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013155 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13156 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013157 else if (STRCMP(name, (char_u *)"starting") == 0)
13158 {
13159 if (val)
13160 {
13161 if (save_starting < 0)
13162 save_starting = starting;
13163 starting = 0;
13164 }
13165 else
13166 {
13167 starting = save_starting;
13168 save_starting = -1;
13169 }
13170 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013171 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13172 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013173 else if (STRCMP(name, (char_u *)"ALL") == 0)
13174 {
13175 disable_char_avail_for_testing = FALSE;
13176 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013177 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013178 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013179 if (save_starting >= 0)
13180 {
13181 starting = save_starting;
13182 save_starting = -1;
13183 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013184 }
13185 else
13186 EMSG2(_(e_invarg2), name);
13187 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013188}
13189
13190/*
13191 * "test_garbagecollect_now()" function
13192 */
13193 static void
13194f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13195{
13196 /* This is dangerous, any Lists and Dicts used internally may be freed
13197 * while still in use. */
13198 garbage_collect(TRUE);
13199}
13200
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013201/*
13202 * "test_ignore_error()" function
13203 */
13204 static void
13205f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13206{
13207 ignore_error_for_testing(get_tv_string(&argvars[0]));
13208}
13209
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013210#ifdef FEAT_JOB_CHANNEL
13211 static void
13212f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13213{
13214 rettv->v_type = VAR_CHANNEL;
13215 rettv->vval.v_channel = NULL;
13216}
13217#endif
13218
13219 static void
13220f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13221{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013222 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013223}
13224
13225#ifdef FEAT_JOB_CHANNEL
13226 static void
13227f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13228{
13229 rettv->v_type = VAR_JOB;
13230 rettv->vval.v_job = NULL;
13231}
13232#endif
13233
13234 static void
13235f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13236{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013237 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013238}
13239
13240 static void
13241f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13242{
13243 rettv->v_type = VAR_PARTIAL;
13244 rettv->vval.v_partial = NULL;
13245}
13246
13247 static void
13248f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13249{
13250 rettv->v_type = VAR_STRING;
13251 rettv->vval.v_string = NULL;
13252}
13253
Bram Moolenaarab186732018-09-14 21:27:06 +020013254#ifdef FEAT_GUI
13255 static void
13256f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13257{
13258 char_u *which;
13259 long value;
13260 int dragging;
13261 scrollbar_T *sb = NULL;
13262
13263 if (argvars[0].v_type != VAR_STRING
13264 || (argvars[1].v_type) != VAR_NUMBER
13265 || (argvars[2].v_type) != VAR_NUMBER)
13266 {
13267 EMSG(_(e_invarg));
13268 return;
13269 }
13270 which = get_tv_string(&argvars[0]);
13271 value = get_tv_number(&argvars[1]);
13272 dragging = get_tv_number(&argvars[2]);
13273
13274 if (STRCMP(which, "left") == 0)
13275 sb = &curwin->w_scrollbars[SBAR_LEFT];
13276 else if (STRCMP(which, "right") == 0)
13277 sb = &curwin->w_scrollbars[SBAR_RIGHT];
13278 else if (STRCMP(which, "hor") == 0)
13279 sb = &gui.bottom_sbar;
13280 if (sb == NULL)
13281 {
13282 EMSG2(_(e_invarg2), which);
13283 return;
13284 }
13285 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020013286# ifndef USE_ON_FLY_SCROLL
13287 // need to loop through normal_cmd() to handle the scroll events
13288 exec_normal(FALSE, TRUE, FALSE);
13289# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020013290}
13291#endif
13292
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013293 static void
13294f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13295{
13296 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13297}
13298
13299#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13300/*
13301 * Get a callback from "arg". It can be a Funcref or a function name.
13302 * When "arg" is zero return an empty string.
13303 * Return NULL for an invalid argument.
13304 */
13305 char_u *
13306get_callback(typval_T *arg, partial_T **pp)
13307{
13308 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13309 {
13310 *pp = arg->vval.v_partial;
13311 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013312 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013313 }
13314 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013315 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013316 {
13317 func_ref(arg->vval.v_string);
13318 return arg->vval.v_string;
13319 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013320 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13321 return (char_u *)"";
13322 EMSG(_("E921: Invalid callback argument"));
13323 return NULL;
13324}
13325
13326/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013327 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013328 */
13329 void
13330free_callback(char_u *callback, partial_T *partial)
13331{
13332 if (partial != NULL)
13333 partial_unref(partial);
13334 else if (callback != NULL)
13335 {
13336 func_unref(callback);
13337 vim_free(callback);
13338 }
13339}
13340#endif
13341
13342#ifdef FEAT_TIMERS
13343/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013344 * "timer_info([timer])" function
13345 */
13346 static void
13347f_timer_info(typval_T *argvars, typval_T *rettv)
13348{
13349 timer_T *timer = NULL;
13350
13351 if (rettv_list_alloc(rettv) != OK)
13352 return;
13353 if (argvars[0].v_type != VAR_UNKNOWN)
13354 {
13355 if (argvars[0].v_type != VAR_NUMBER)
13356 EMSG(_(e_number_exp));
13357 else
13358 {
13359 timer = find_timer((int)get_tv_number(&argvars[0]));
13360 if (timer != NULL)
13361 add_timer_info(rettv, timer);
13362 }
13363 }
13364 else
13365 add_timer_info_all(rettv);
13366}
13367
13368/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013369 * "timer_pause(timer, paused)" function
13370 */
13371 static void
13372f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13373{
13374 timer_T *timer = NULL;
13375 int paused = (int)get_tv_number(&argvars[1]);
13376
13377 if (argvars[0].v_type != VAR_NUMBER)
13378 EMSG(_(e_number_exp));
13379 else
13380 {
13381 timer = find_timer((int)get_tv_number(&argvars[0]));
13382 if (timer != NULL)
13383 timer->tr_paused = paused;
13384 }
13385}
13386
13387/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013388 * "timer_start(time, callback [, options])" function
13389 */
13390 static void
13391f_timer_start(typval_T *argvars, typval_T *rettv)
13392{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013393 long msec = (long)get_tv_number(&argvars[0]);
13394 timer_T *timer;
13395 int repeat = 0;
13396 char_u *callback;
13397 dict_T *dict;
13398 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013399
Bram Moolenaar75537a92016-09-05 22:45:28 +020013400 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013401 if (check_secure())
13402 return;
13403 if (argvars[2].v_type != VAR_UNKNOWN)
13404 {
13405 if (argvars[2].v_type != VAR_DICT
13406 || (dict = argvars[2].vval.v_dict) == NULL)
13407 {
13408 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13409 return;
13410 }
13411 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13412 repeat = get_dict_number(dict, (char_u *)"repeat");
13413 }
13414
Bram Moolenaar75537a92016-09-05 22:45:28 +020013415 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013416 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013417 return;
13418
13419 timer = create_timer(msec, repeat);
13420 if (timer == NULL)
13421 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013422 else
13423 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013424 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013425 timer->tr_callback = vim_strsave(callback);
13426 else
13427 /* pointer into the partial */
13428 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013429 timer->tr_partial = partial;
13430 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013431 }
13432}
13433
13434/*
13435 * "timer_stop(timer)" function
13436 */
13437 static void
13438f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13439{
13440 timer_T *timer;
13441
13442 if (argvars[0].v_type != VAR_NUMBER)
13443 {
13444 EMSG(_(e_number_exp));
13445 return;
13446 }
13447 timer = find_timer((int)get_tv_number(&argvars[0]));
13448 if (timer != NULL)
13449 stop_timer(timer);
13450}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013451
13452/*
13453 * "timer_stopall()" function
13454 */
13455 static void
13456f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13457{
13458 stop_all_timers();
13459}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013460#endif
13461
13462/*
13463 * "tolower(string)" function
13464 */
13465 static void
13466f_tolower(typval_T *argvars, typval_T *rettv)
13467{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013468 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013469 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013470}
13471
13472/*
13473 * "toupper(string)" function
13474 */
13475 static void
13476f_toupper(typval_T *argvars, typval_T *rettv)
13477{
13478 rettv->v_type = VAR_STRING;
13479 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13480}
13481
13482/*
13483 * "tr(string, fromstr, tostr)" function
13484 */
13485 static void
13486f_tr(typval_T *argvars, typval_T *rettv)
13487{
13488 char_u *in_str;
13489 char_u *fromstr;
13490 char_u *tostr;
13491 char_u *p;
13492#ifdef FEAT_MBYTE
13493 int inlen;
13494 int fromlen;
13495 int tolen;
13496 int idx;
13497 char_u *cpstr;
13498 int cplen;
13499 int first = TRUE;
13500#endif
13501 char_u buf[NUMBUFLEN];
13502 char_u buf2[NUMBUFLEN];
13503 garray_T ga;
13504
13505 in_str = get_tv_string(&argvars[0]);
13506 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13507 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13508
13509 /* Default return value: empty string. */
13510 rettv->v_type = VAR_STRING;
13511 rettv->vval.v_string = NULL;
13512 if (fromstr == NULL || tostr == NULL)
13513 return; /* type error; errmsg already given */
13514 ga_init2(&ga, (int)sizeof(char), 80);
13515
13516#ifdef FEAT_MBYTE
13517 if (!has_mbyte)
13518#endif
13519 /* not multi-byte: fromstr and tostr must be the same length */
13520 if (STRLEN(fromstr) != STRLEN(tostr))
13521 {
13522#ifdef FEAT_MBYTE
13523error:
13524#endif
13525 EMSG2(_(e_invarg2), fromstr);
13526 ga_clear(&ga);
13527 return;
13528 }
13529
13530 /* fromstr and tostr have to contain the same number of chars */
13531 while (*in_str != NUL)
13532 {
13533#ifdef FEAT_MBYTE
13534 if (has_mbyte)
13535 {
13536 inlen = (*mb_ptr2len)(in_str);
13537 cpstr = in_str;
13538 cplen = inlen;
13539 idx = 0;
13540 for (p = fromstr; *p != NUL; p += fromlen)
13541 {
13542 fromlen = (*mb_ptr2len)(p);
13543 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13544 {
13545 for (p = tostr; *p != NUL; p += tolen)
13546 {
13547 tolen = (*mb_ptr2len)(p);
13548 if (idx-- == 0)
13549 {
13550 cplen = tolen;
13551 cpstr = p;
13552 break;
13553 }
13554 }
13555 if (*p == NUL) /* tostr is shorter than fromstr */
13556 goto error;
13557 break;
13558 }
13559 ++idx;
13560 }
13561
13562 if (first && cpstr == in_str)
13563 {
13564 /* Check that fromstr and tostr have the same number of
13565 * (multi-byte) characters. Done only once when a character
13566 * of in_str doesn't appear in fromstr. */
13567 first = FALSE;
13568 for (p = tostr; *p != NUL; p += tolen)
13569 {
13570 tolen = (*mb_ptr2len)(p);
13571 --idx;
13572 }
13573 if (idx != 0)
13574 goto error;
13575 }
13576
13577 (void)ga_grow(&ga, cplen);
13578 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13579 ga.ga_len += cplen;
13580
13581 in_str += inlen;
13582 }
13583 else
13584#endif
13585 {
13586 /* When not using multi-byte chars we can do it faster. */
13587 p = vim_strchr(fromstr, *in_str);
13588 if (p != NULL)
13589 ga_append(&ga, tostr[p - fromstr]);
13590 else
13591 ga_append(&ga, *in_str);
13592 ++in_str;
13593 }
13594 }
13595
13596 /* add a terminating NUL */
13597 (void)ga_grow(&ga, 1);
13598 ga_append(&ga, NUL);
13599
13600 rettv->vval.v_string = ga.ga_data;
13601}
13602
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013603/*
13604 * "trim({expr})" function
13605 */
13606 static void
13607f_trim(typval_T *argvars, typval_T *rettv)
13608{
13609 char_u buf1[NUMBUFLEN];
13610 char_u buf2[NUMBUFLEN];
13611 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13612 char_u *mask = NULL;
13613 char_u *tail;
13614 char_u *prev;
13615 char_u *p;
13616 int c1;
13617
13618 rettv->v_type = VAR_STRING;
13619 if (head == NULL)
13620 {
13621 rettv->vval.v_string = NULL;
13622 return;
13623 }
13624
13625 if (argvars[1].v_type == VAR_STRING)
13626 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13627
13628 while (*head != NUL)
13629 {
13630 c1 = PTR2CHAR(head);
13631 if (mask == NULL)
13632 {
13633 if (c1 > ' ' && c1 != 0xa0)
13634 break;
13635 }
13636 else
13637 {
13638 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13639 if (c1 == PTR2CHAR(p))
13640 break;
13641 if (*p == NUL)
13642 break;
13643 }
13644 MB_PTR_ADV(head);
13645 }
13646
13647 for (tail = head + STRLEN(head); tail > head; tail = prev)
13648 {
13649 prev = tail;
13650 MB_PTR_BACK(head, prev);
13651 c1 = PTR2CHAR(prev);
13652 if (mask == NULL)
13653 {
13654 if (c1 > ' ' && c1 != 0xa0)
13655 break;
13656 }
13657 else
13658 {
13659 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13660 if (c1 == PTR2CHAR(p))
13661 break;
13662 if (*p == NUL)
13663 break;
13664 }
13665 }
13666 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13667}
13668
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013669#ifdef FEAT_FLOAT
13670/*
13671 * "trunc({float})" function
13672 */
13673 static void
13674f_trunc(typval_T *argvars, typval_T *rettv)
13675{
13676 float_T f = 0.0;
13677
13678 rettv->v_type = VAR_FLOAT;
13679 if (get_float_arg(argvars, &f) == OK)
13680 /* trunc() is not in C90, use floor() or ceil() instead. */
13681 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13682 else
13683 rettv->vval.v_float = 0.0;
13684}
13685#endif
13686
13687/*
13688 * "type(expr)" function
13689 */
13690 static void
13691f_type(typval_T *argvars, typval_T *rettv)
13692{
13693 int n = -1;
13694
13695 switch (argvars[0].v_type)
13696 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013697 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13698 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013699 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013700 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13701 case VAR_LIST: n = VAR_TYPE_LIST; break;
13702 case VAR_DICT: n = VAR_TYPE_DICT; break;
13703 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013704 case VAR_SPECIAL:
13705 if (argvars[0].vval.v_number == VVAL_FALSE
13706 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013707 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013708 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013709 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013710 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013711 case VAR_JOB: n = VAR_TYPE_JOB; break;
13712 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013713 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013714 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013715 n = -1;
13716 break;
13717 }
13718 rettv->vval.v_number = n;
13719}
13720
13721/*
13722 * "undofile(name)" function
13723 */
13724 static void
13725f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13726{
13727 rettv->v_type = VAR_STRING;
13728#ifdef FEAT_PERSISTENT_UNDO
13729 {
13730 char_u *fname = get_tv_string(&argvars[0]);
13731
13732 if (*fname == NUL)
13733 {
13734 /* If there is no file name there will be no undo file. */
13735 rettv->vval.v_string = NULL;
13736 }
13737 else
13738 {
13739 char_u *ffname = FullName_save(fname, FALSE);
13740
13741 if (ffname != NULL)
13742 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13743 vim_free(ffname);
13744 }
13745 }
13746#else
13747 rettv->vval.v_string = NULL;
13748#endif
13749}
13750
13751/*
13752 * "undotree()" function
13753 */
13754 static void
13755f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13756{
13757 if (rettv_dict_alloc(rettv) == OK)
13758 {
13759 dict_T *dict = rettv->vval.v_dict;
13760 list_T *list;
13761
Bram Moolenaare0be1672018-07-08 16:50:37 +020013762 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
13763 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
13764 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
13765 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
13766 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
13767 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013768
13769 list = list_alloc();
13770 if (list != NULL)
13771 {
13772 u_eval_tree(curbuf->b_u_oldhead, list);
13773 dict_add_list(dict, "entries", list);
13774 }
13775 }
13776}
13777
13778/*
13779 * "values(dict)" function
13780 */
13781 static void
13782f_values(typval_T *argvars, typval_T *rettv)
13783{
13784 dict_list(argvars, rettv, 1);
13785}
13786
13787/*
13788 * "virtcol(string)" function
13789 */
13790 static void
13791f_virtcol(typval_T *argvars, typval_T *rettv)
13792{
13793 colnr_T vcol = 0;
13794 pos_T *fp;
13795 int fnum = curbuf->b_fnum;
13796
13797 fp = var2fpos(&argvars[0], FALSE, &fnum);
13798 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13799 && fnum == curbuf->b_fnum)
13800 {
13801 getvvcol(curwin, fp, NULL, NULL, &vcol);
13802 ++vcol;
13803 }
13804
13805 rettv->vval.v_number = vcol;
13806}
13807
13808/*
13809 * "visualmode()" function
13810 */
13811 static void
13812f_visualmode(typval_T *argvars, typval_T *rettv)
13813{
13814 char_u str[2];
13815
13816 rettv->v_type = VAR_STRING;
13817 str[0] = curbuf->b_visual_mode_eval;
13818 str[1] = NUL;
13819 rettv->vval.v_string = vim_strsave(str);
13820
13821 /* A non-zero number or non-empty string argument: reset mode. */
13822 if (non_zero_arg(&argvars[0]))
13823 curbuf->b_visual_mode_eval = NUL;
13824}
13825
13826/*
13827 * "wildmenumode()" function
13828 */
13829 static void
13830f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13831{
13832#ifdef FEAT_WILDMENU
13833 if (wild_menu_showing)
13834 rettv->vval.v_number = 1;
13835#endif
13836}
13837
13838/*
13839 * "winbufnr(nr)" function
13840 */
13841 static void
13842f_winbufnr(typval_T *argvars, typval_T *rettv)
13843{
13844 win_T *wp;
13845
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013846 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013847 if (wp == NULL)
13848 rettv->vval.v_number = -1;
13849 else
13850 rettv->vval.v_number = wp->w_buffer->b_fnum;
13851}
13852
13853/*
13854 * "wincol()" function
13855 */
13856 static void
13857f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13858{
13859 validate_cursor();
13860 rettv->vval.v_number = curwin->w_wcol + 1;
13861}
13862
13863/*
13864 * "winheight(nr)" function
13865 */
13866 static void
13867f_winheight(typval_T *argvars, typval_T *rettv)
13868{
13869 win_T *wp;
13870
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013871 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013872 if (wp == NULL)
13873 rettv->vval.v_number = -1;
13874 else
13875 rettv->vval.v_number = wp->w_height;
13876}
13877
13878/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020013879 * "winlayout()" function
13880 */
13881 static void
13882f_winlayout(typval_T *argvars, typval_T *rettv)
13883{
13884 tabpage_T *tp;
13885
13886 if (rettv_list_alloc(rettv) != OK)
13887 return;
13888
13889 if (argvars[0].v_type == VAR_UNKNOWN)
13890 tp = curtab;
13891 else
13892 {
13893 tp = find_tabpage((int)get_tv_number(&argvars[0]));
13894 if (tp == NULL)
13895 return;
13896 }
13897
13898 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
13899}
13900
13901/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013902 * "winline()" function
13903 */
13904 static void
13905f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13906{
13907 validate_cursor();
13908 rettv->vval.v_number = curwin->w_wrow + 1;
13909}
13910
13911/*
13912 * "winnr()" function
13913 */
13914 static void
13915f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13916{
13917 int nr = 1;
13918
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013919 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013920 rettv->vval.v_number = nr;
13921}
13922
13923/*
13924 * "winrestcmd()" function
13925 */
13926 static void
13927f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13928{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013929 win_T *wp;
13930 int winnr = 1;
13931 garray_T ga;
13932 char_u buf[50];
13933
13934 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013935 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013936 {
13937 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13938 ga_concat(&ga, buf);
13939 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13940 ga_concat(&ga, buf);
13941 ++winnr;
13942 }
13943 ga_append(&ga, NUL);
13944
13945 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013946 rettv->v_type = VAR_STRING;
13947}
13948
13949/*
13950 * "winrestview()" function
13951 */
13952 static void
13953f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13954{
13955 dict_T *dict;
13956
13957 if (argvars[0].v_type != VAR_DICT
13958 || (dict = argvars[0].vval.v_dict) == NULL)
13959 EMSG(_(e_invarg));
13960 else
13961 {
13962 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13963 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13964 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13965 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13966#ifdef FEAT_VIRTUALEDIT
13967 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13968 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13969#endif
13970 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13971 {
13972 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13973 curwin->w_set_curswant = FALSE;
13974 }
13975
13976 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13977 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13978#ifdef FEAT_DIFF
13979 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13980 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13981#endif
13982 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13983 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13984 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13985 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13986
13987 check_cursor();
13988 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013989 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013990 changed_window_setting();
13991
13992 if (curwin->w_topline <= 0)
13993 curwin->w_topline = 1;
13994 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13995 curwin->w_topline = curbuf->b_ml.ml_line_count;
13996#ifdef FEAT_DIFF
13997 check_topfill(curwin, TRUE);
13998#endif
13999 }
14000}
14001
14002/*
14003 * "winsaveview()" function
14004 */
14005 static void
14006f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14007{
14008 dict_T *dict;
14009
14010 if (rettv_dict_alloc(rettv) == FAIL)
14011 return;
14012 dict = rettv->vval.v_dict;
14013
Bram Moolenaare0be1672018-07-08 16:50:37 +020014014 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14015 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014016#ifdef FEAT_VIRTUALEDIT
Bram Moolenaare0be1672018-07-08 16:50:37 +020014017 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014018#endif
14019 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014020 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014021
Bram Moolenaare0be1672018-07-08 16:50:37 +020014022 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014023#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014024 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014025#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014026 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14027 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014028}
14029
14030/*
14031 * "winwidth(nr)" function
14032 */
14033 static void
14034f_winwidth(typval_T *argvars, typval_T *rettv)
14035{
14036 win_T *wp;
14037
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014038 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014039 if (wp == NULL)
14040 rettv->vval.v_number = -1;
14041 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014042 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014043}
14044
14045/*
14046 * "wordcount()" function
14047 */
14048 static void
14049f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14050{
14051 if (rettv_dict_alloc(rettv) == FAIL)
14052 return;
14053 cursor_pos_info(rettv->vval.v_dict);
14054}
14055
14056/*
14057 * "writefile()" function
14058 */
14059 static void
14060f_writefile(typval_T *argvars, typval_T *rettv)
14061{
14062 int binary = FALSE;
14063 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014064#ifdef HAVE_FSYNC
14065 int do_fsync = p_fs;
14066#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014067 char_u *fname;
14068 FILE *fd;
14069 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014070 listitem_T *li;
14071 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014072
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014073 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014074 if (check_restricted() || check_secure())
14075 return;
14076
14077 if (argvars[0].v_type != VAR_LIST)
14078 {
14079 EMSG2(_(e_listarg), "writefile()");
14080 return;
14081 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014082 list = argvars[0].vval.v_list;
14083 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014084 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014085 for (li = list->lv_first; li != NULL; li = li->li_next)
14086 if (get_tv_string_chk(&li->li_tv) == NULL)
14087 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014088
14089 if (argvars[2].v_type != VAR_UNKNOWN)
14090 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014091 char_u *arg2 = get_tv_string_chk(&argvars[2]);
14092
14093 if (arg2 == NULL)
14094 return;
14095 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014096 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014097 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014098 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014099#ifdef HAVE_FSYNC
14100 if (vim_strchr(arg2, 's') != NULL)
14101 do_fsync = TRUE;
14102 else if (vim_strchr(arg2, 'S') != NULL)
14103 do_fsync = FALSE;
14104#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014105 }
14106
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014107 fname = get_tv_string_chk(&argvars[1]);
14108 if (fname == NULL)
14109 return;
14110
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014111 /* Always open the file in binary mode, library functions have a mind of
14112 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014113 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14114 append ? APPENDBIN : WRITEBIN)) == NULL)
14115 {
14116 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14117 ret = -1;
14118 }
14119 else
14120 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014121 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014122 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014123#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014124 else if (do_fsync)
14125 /* Ignore the error, the user wouldn't know what to do about it.
14126 * May happen for a device. */
Bram Moolenaar42335f52018-09-13 15:33:43 +020014127 vim_ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014128#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014129 fclose(fd);
14130 }
14131
14132 rettv->vval.v_number = ret;
14133}
14134
14135/*
14136 * "xor(expr, expr)" function
14137 */
14138 static void
14139f_xor(typval_T *argvars, typval_T *rettv)
14140{
14141 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
14142 ^ get_tv_number_chk(&argvars[1], NULL);
14143}
14144
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014145#endif /* FEAT_EVAL */