blob: 2bbeb2569250b53bf51503e2969fa7a05e3f0a26 [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);
126static void f_deepcopy(typval_T *argvars, typval_T *rettv);
127static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200128static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_did_filetype(typval_T *argvars, typval_T *rettv);
130static void f_diff_filler(typval_T *argvars, typval_T *rettv);
131static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
132static void f_empty(typval_T *argvars, typval_T *rettv);
133static void f_escape(typval_T *argvars, typval_T *rettv);
134static void f_eval(typval_T *argvars, typval_T *rettv);
135static void f_eventhandler(typval_T *argvars, typval_T *rettv);
136static void f_executable(typval_T *argvars, typval_T *rettv);
137static void f_execute(typval_T *argvars, typval_T *rettv);
138static void f_exepath(typval_T *argvars, typval_T *rettv);
139static void f_exists(typval_T *argvars, typval_T *rettv);
140#ifdef FEAT_FLOAT
141static void f_exp(typval_T *argvars, typval_T *rettv);
142#endif
143static void f_expand(typval_T *argvars, typval_T *rettv);
144static void f_extend(typval_T *argvars, typval_T *rettv);
145static void f_feedkeys(typval_T *argvars, typval_T *rettv);
146static void f_filereadable(typval_T *argvars, typval_T *rettv);
147static void f_filewritable(typval_T *argvars, typval_T *rettv);
148static void f_filter(typval_T *argvars, typval_T *rettv);
149static void f_finddir(typval_T *argvars, typval_T *rettv);
150static void f_findfile(typval_T *argvars, typval_T *rettv);
151#ifdef FEAT_FLOAT
152static void f_float2nr(typval_T *argvars, typval_T *rettv);
153static void f_floor(typval_T *argvars, typval_T *rettv);
154static void f_fmod(typval_T *argvars, typval_T *rettv);
155#endif
156static void f_fnameescape(typval_T *argvars, typval_T *rettv);
157static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
158static void f_foldclosed(typval_T *argvars, typval_T *rettv);
159static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
160static void f_foldlevel(typval_T *argvars, typval_T *rettv);
161static void f_foldtext(typval_T *argvars, typval_T *rettv);
162static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
163static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200164static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_function(typval_T *argvars, typval_T *rettv);
166static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
167static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200168static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200169static void f_getbufline(typval_T *argvars, typval_T *rettv);
170static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100171static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_getchar(typval_T *argvars, typval_T *rettv);
173static void f_getcharmod(typval_T *argvars, typval_T *rettv);
174static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
175static void f_getcmdline(typval_T *argvars, typval_T *rettv);
176#if defined(FEAT_CMDL_COMPL)
177static void f_getcompletion(typval_T *argvars, typval_T *rettv);
178#endif
179static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
180static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
181static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
182static void f_getcwd(typval_T *argvars, typval_T *rettv);
183static void f_getfontname(typval_T *argvars, typval_T *rettv);
184static void f_getfperm(typval_T *argvars, typval_T *rettv);
185static void f_getfsize(typval_T *argvars, typval_T *rettv);
186static void f_getftime(typval_T *argvars, typval_T *rettv);
187static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100188static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200189static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200190static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_getmatches(typval_T *argvars, typval_T *rettv);
192static void f_getpid(typval_T *argvars, typval_T *rettv);
193static void f_getcurpos(typval_T *argvars, typval_T *rettv);
194static void f_getpos(typval_T *argvars, typval_T *rettv);
195static void f_getqflist(typval_T *argvars, typval_T *rettv);
196static void f_getreg(typval_T *argvars, typval_T *rettv);
197static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200198static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200199static void f_gettabvar(typval_T *argvars, typval_T *rettv);
200static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200201static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100202static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200203static void f_getwinposx(typval_T *argvars, typval_T *rettv);
204static void f_getwinposy(typval_T *argvars, typval_T *rettv);
205static void f_getwinvar(typval_T *argvars, typval_T *rettv);
206static void f_glob(typval_T *argvars, typval_T *rettv);
207static void f_globpath(typval_T *argvars, typval_T *rettv);
208static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
209static void f_has(typval_T *argvars, typval_T *rettv);
210static void f_has_key(typval_T *argvars, typval_T *rettv);
211static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
212static void f_hasmapto(typval_T *argvars, typval_T *rettv);
213static void f_histadd(typval_T *argvars, typval_T *rettv);
214static void f_histdel(typval_T *argvars, typval_T *rettv);
215static void f_histget(typval_T *argvars, typval_T *rettv);
216static void f_histnr(typval_T *argvars, typval_T *rettv);
217static void f_hlID(typval_T *argvars, typval_T *rettv);
218static void f_hlexists(typval_T *argvars, typval_T *rettv);
219static void f_hostname(typval_T *argvars, typval_T *rettv);
220static void f_iconv(typval_T *argvars, typval_T *rettv);
221static void f_indent(typval_T *argvars, typval_T *rettv);
222static void f_index(typval_T *argvars, typval_T *rettv);
223static void f_input(typval_T *argvars, typval_T *rettv);
224static void f_inputdialog(typval_T *argvars, typval_T *rettv);
225static void f_inputlist(typval_T *argvars, typval_T *rettv);
226static void f_inputrestore(typval_T *argvars, typval_T *rettv);
227static void f_inputsave(typval_T *argvars, typval_T *rettv);
228static void f_inputsecret(typval_T *argvars, typval_T *rettv);
229static void f_insert(typval_T *argvars, typval_T *rettv);
230static void f_invert(typval_T *argvars, typval_T *rettv);
231static void f_isdirectory(typval_T *argvars, typval_T *rettv);
232static void f_islocked(typval_T *argvars, typval_T *rettv);
233#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
234static void f_isnan(typval_T *argvars, typval_T *rettv);
235#endif
236static void f_items(typval_T *argvars, typval_T *rettv);
237#ifdef FEAT_JOB_CHANNEL
238static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
239static void f_job_info(typval_T *argvars, typval_T *rettv);
240static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
241static void f_job_start(typval_T *argvars, typval_T *rettv);
242static void f_job_stop(typval_T *argvars, typval_T *rettv);
243static void f_job_status(typval_T *argvars, typval_T *rettv);
244#endif
245static void f_join(typval_T *argvars, typval_T *rettv);
246static void f_js_decode(typval_T *argvars, typval_T *rettv);
247static void f_js_encode(typval_T *argvars, typval_T *rettv);
248static void f_json_decode(typval_T *argvars, typval_T *rettv);
249static void f_json_encode(typval_T *argvars, typval_T *rettv);
250static void f_keys(typval_T *argvars, typval_T *rettv);
251static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
252static void f_len(typval_T *argvars, typval_T *rettv);
253static void f_libcall(typval_T *argvars, typval_T *rettv);
254static void f_libcallnr(typval_T *argvars, typval_T *rettv);
255static void f_line(typval_T *argvars, typval_T *rettv);
256static void f_line2byte(typval_T *argvars, typval_T *rettv);
257static void f_lispindent(typval_T *argvars, typval_T *rettv);
258static void f_localtime(typval_T *argvars, typval_T *rettv);
259#ifdef FEAT_FLOAT
260static void f_log(typval_T *argvars, typval_T *rettv);
261static void f_log10(typval_T *argvars, typval_T *rettv);
262#endif
263#ifdef FEAT_LUA
264static void f_luaeval(typval_T *argvars, typval_T *rettv);
265#endif
266static void f_map(typval_T *argvars, typval_T *rettv);
267static void f_maparg(typval_T *argvars, typval_T *rettv);
268static void f_mapcheck(typval_T *argvars, typval_T *rettv);
269static void f_match(typval_T *argvars, typval_T *rettv);
270static void f_matchadd(typval_T *argvars, typval_T *rettv);
271static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
272static void f_matcharg(typval_T *argvars, typval_T *rettv);
273static void f_matchdelete(typval_T *argvars, typval_T *rettv);
274static void f_matchend(typval_T *argvars, typval_T *rettv);
275static void f_matchlist(typval_T *argvars, typval_T *rettv);
276static void f_matchstr(typval_T *argvars, typval_T *rettv);
277static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
278static void f_max(typval_T *argvars, typval_T *rettv);
279static void f_min(typval_T *argvars, typval_T *rettv);
280#ifdef vim_mkdir
281static void f_mkdir(typval_T *argvars, typval_T *rettv);
282#endif
283static void f_mode(typval_T *argvars, typval_T *rettv);
284#ifdef FEAT_MZSCHEME
285static void f_mzeval(typval_T *argvars, typval_T *rettv);
286#endif
287static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
288static void f_nr2char(typval_T *argvars, typval_T *rettv);
289static void f_or(typval_T *argvars, typval_T *rettv);
290static void f_pathshorten(typval_T *argvars, typval_T *rettv);
291#ifdef FEAT_PERL
292static void f_perleval(typval_T *argvars, typval_T *rettv);
293#endif
294#ifdef FEAT_FLOAT
295static void f_pow(typval_T *argvars, typval_T *rettv);
296#endif
297static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
298static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200299#ifdef FEAT_JOB_CHANNEL
300static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
301static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
302#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200303static void f_pumvisible(typval_T *argvars, typval_T *rettv);
304#ifdef FEAT_PYTHON3
305static void f_py3eval(typval_T *argvars, typval_T *rettv);
306#endif
307#ifdef FEAT_PYTHON
308static void f_pyeval(typval_T *argvars, typval_T *rettv);
309#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100310#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
311static void f_pyxeval(typval_T *argvars, typval_T *rettv);
312#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200313static void f_range(typval_T *argvars, typval_T *rettv);
314static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200315static void f_reg_executing(typval_T *argvars, typval_T *rettv);
316static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317static void f_reltime(typval_T *argvars, typval_T *rettv);
318#ifdef FEAT_FLOAT
319static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
320#endif
321static void f_reltimestr(typval_T *argvars, typval_T *rettv);
322static void f_remote_expr(typval_T *argvars, typval_T *rettv);
323static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
324static void f_remote_peek(typval_T *argvars, typval_T *rettv);
325static void f_remote_read(typval_T *argvars, typval_T *rettv);
326static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100327static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200328static void f_remove(typval_T *argvars, typval_T *rettv);
329static void f_rename(typval_T *argvars, typval_T *rettv);
330static void f_repeat(typval_T *argvars, typval_T *rettv);
331static void f_resolve(typval_T *argvars, typval_T *rettv);
332static void f_reverse(typval_T *argvars, typval_T *rettv);
333#ifdef FEAT_FLOAT
334static void f_round(typval_T *argvars, typval_T *rettv);
335#endif
336static void f_screenattr(typval_T *argvars, typval_T *rettv);
337static void f_screenchar(typval_T *argvars, typval_T *rettv);
338static void f_screencol(typval_T *argvars, typval_T *rettv);
339static void f_screenrow(typval_T *argvars, typval_T *rettv);
340static void f_search(typval_T *argvars, typval_T *rettv);
341static void f_searchdecl(typval_T *argvars, typval_T *rettv);
342static void f_searchpair(typval_T *argvars, typval_T *rettv);
343static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
344static void f_searchpos(typval_T *argvars, typval_T *rettv);
345static void f_server2client(typval_T *argvars, typval_T *rettv);
346static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200347static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200348static void f_setbufvar(typval_T *argvars, typval_T *rettv);
349static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
350static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
351static void f_setfperm(typval_T *argvars, typval_T *rettv);
352static void f_setline(typval_T *argvars, typval_T *rettv);
353static void f_setloclist(typval_T *argvars, typval_T *rettv);
354static void f_setmatches(typval_T *argvars, typval_T *rettv);
355static void f_setpos(typval_T *argvars, typval_T *rettv);
356static void f_setqflist(typval_T *argvars, typval_T *rettv);
357static void f_setreg(typval_T *argvars, typval_T *rettv);
358static void f_settabvar(typval_T *argvars, typval_T *rettv);
359static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
360static void f_setwinvar(typval_T *argvars, typval_T *rettv);
361#ifdef FEAT_CRYPT
362static void f_sha256(typval_T *argvars, typval_T *rettv);
363#endif /* FEAT_CRYPT */
364static void f_shellescape(typval_T *argvars, typval_T *rettv);
365static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
366static void f_simplify(typval_T *argvars, typval_T *rettv);
367#ifdef FEAT_FLOAT
368static void f_sin(typval_T *argvars, typval_T *rettv);
369static void f_sinh(typval_T *argvars, typval_T *rettv);
370#endif
371static void f_sort(typval_T *argvars, typval_T *rettv);
372static void f_soundfold(typval_T *argvars, typval_T *rettv);
373static void f_spellbadword(typval_T *argvars, typval_T *rettv);
374static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
375static void f_split(typval_T *argvars, typval_T *rettv);
376#ifdef FEAT_FLOAT
377static void f_sqrt(typval_T *argvars, typval_T *rettv);
378static void f_str2float(typval_T *argvars, typval_T *rettv);
379#endif
380static void f_str2nr(typval_T *argvars, typval_T *rettv);
381static void f_strchars(typval_T *argvars, typval_T *rettv);
382#ifdef HAVE_STRFTIME
383static void f_strftime(typval_T *argvars, typval_T *rettv);
384#endif
385static void f_strgetchar(typval_T *argvars, typval_T *rettv);
386static void f_stridx(typval_T *argvars, typval_T *rettv);
387static void f_string(typval_T *argvars, typval_T *rettv);
388static void f_strlen(typval_T *argvars, typval_T *rettv);
389static void f_strcharpart(typval_T *argvars, typval_T *rettv);
390static void f_strpart(typval_T *argvars, typval_T *rettv);
391static void f_strridx(typval_T *argvars, typval_T *rettv);
392static void f_strtrans(typval_T *argvars, typval_T *rettv);
393static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
394static void f_strwidth(typval_T *argvars, typval_T *rettv);
395static void f_submatch(typval_T *argvars, typval_T *rettv);
396static void f_substitute(typval_T *argvars, typval_T *rettv);
397static void f_synID(typval_T *argvars, typval_T *rettv);
398static void f_synIDattr(typval_T *argvars, typval_T *rettv);
399static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
400static void f_synstack(typval_T *argvars, typval_T *rettv);
401static void f_synconcealed(typval_T *argvars, typval_T *rettv);
402static void f_system(typval_T *argvars, typval_T *rettv);
403static void f_systemlist(typval_T *argvars, typval_T *rettv);
404static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
405static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
406static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
407static void f_taglist(typval_T *argvars, typval_T *rettv);
408static void f_tagfiles(typval_T *argvars, typval_T *rettv);
409static void f_tempname(typval_T *argvars, typval_T *rettv);
410static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
411static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200412static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100413static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200414static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100415static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200416#ifdef FEAT_JOB_CHANNEL
417static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
418#endif
419static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
420#ifdef FEAT_JOB_CHANNEL
421static void f_test_null_job(typval_T *argvars, typval_T *rettv);
422#endif
423static void f_test_null_list(typval_T *argvars, typval_T *rettv);
424static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
425static void f_test_null_string(typval_T *argvars, typval_T *rettv);
426static void f_test_settime(typval_T *argvars, typval_T *rettv);
427#ifdef FEAT_FLOAT
428static void f_tan(typval_T *argvars, typval_T *rettv);
429static void f_tanh(typval_T *argvars, typval_T *rettv);
430#endif
431#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200432static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200433static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434static void f_timer_start(typval_T *argvars, typval_T *rettv);
435static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200436static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
438static void f_tolower(typval_T *argvars, typval_T *rettv);
439static void f_toupper(typval_T *argvars, typval_T *rettv);
440static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100441static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442#ifdef FEAT_FLOAT
443static void f_trunc(typval_T *argvars, typval_T *rettv);
444#endif
445static void f_type(typval_T *argvars, typval_T *rettv);
446static void f_undofile(typval_T *argvars, typval_T *rettv);
447static void f_undotree(typval_T *argvars, typval_T *rettv);
448static void f_uniq(typval_T *argvars, typval_T *rettv);
449static void f_values(typval_T *argvars, typval_T *rettv);
450static void f_virtcol(typval_T *argvars, typval_T *rettv);
451static void f_visualmode(typval_T *argvars, typval_T *rettv);
452static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
453static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
454static void f_win_getid(typval_T *argvars, typval_T *rettv);
455static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
456static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
457static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100458static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200459static void f_winbufnr(typval_T *argvars, typval_T *rettv);
460static void f_wincol(typval_T *argvars, typval_T *rettv);
461static void f_winheight(typval_T *argvars, typval_T *rettv);
462static void f_winline(typval_T *argvars, typval_T *rettv);
463static void f_winnr(typval_T *argvars, typval_T *rettv);
464static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
465static void f_winrestview(typval_T *argvars, typval_T *rettv);
466static void f_winsaveview(typval_T *argvars, typval_T *rettv);
467static void f_winwidth(typval_T *argvars, typval_T *rettv);
468static void f_writefile(typval_T *argvars, typval_T *rettv);
469static void f_wordcount(typval_T *argvars, typval_T *rettv);
470static void f_xor(typval_T *argvars, typval_T *rettv);
471
472/*
473 * Array with names and number of arguments of all internal functions
474 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
475 */
476static struct fst
477{
478 char *f_name; /* function name */
479 char f_min_argc; /* minimal number of arguments */
480 char f_max_argc; /* maximal number of arguments */
481 void (*f_func)(typval_T *args, typval_T *rvar);
482 /* implementation of function */
483} functions[] =
484{
485#ifdef FEAT_FLOAT
486 {"abs", 1, 1, f_abs},
487 {"acos", 1, 1, f_acos}, /* WJMc */
488#endif
489 {"add", 2, 2, f_add},
490 {"and", 2, 2, f_and},
491 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200492 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200493 {"argc", 0, 0, f_argc},
494 {"argidx", 0, 0, f_argidx},
495 {"arglistid", 0, 2, f_arglistid},
496 {"argv", 0, 1, f_argv},
497#ifdef FEAT_FLOAT
498 {"asin", 1, 1, f_asin}, /* WJMc */
499#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100500 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200501 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100502 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200503 {"assert_exception", 1, 2, f_assert_exception},
504 {"assert_fails", 1, 2, f_assert_fails},
505 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100506 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200507 {"assert_match", 2, 3, f_assert_match},
508 {"assert_notequal", 2, 3, f_assert_notequal},
509 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100510 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200511 {"assert_true", 1, 2, f_assert_true},
512#ifdef FEAT_FLOAT
513 {"atan", 1, 1, f_atan},
514 {"atan2", 2, 2, f_atan2},
515#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100516#ifdef FEAT_BEVAL
517 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100518# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100519 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100520# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100521#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200522 {"browse", 4, 4, f_browse},
523 {"browsedir", 2, 2, f_browsedir},
524 {"bufexists", 1, 1, f_bufexists},
525 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
526 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
527 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
528 {"buflisted", 1, 1, f_buflisted},
529 {"bufloaded", 1, 1, f_bufloaded},
530 {"bufname", 1, 1, f_bufname},
531 {"bufnr", 1, 2, f_bufnr},
532 {"bufwinid", 1, 1, f_bufwinid},
533 {"bufwinnr", 1, 1, f_bufwinnr},
534 {"byte2line", 1, 1, f_byte2line},
535 {"byteidx", 2, 2, f_byteidx},
536 {"byteidxcomp", 2, 2, f_byteidxcomp},
537 {"call", 2, 3, f_call},
538#ifdef FEAT_FLOAT
539 {"ceil", 1, 1, f_ceil},
540#endif
541#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100542 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200543 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200544 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200545 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
546 {"ch_evalraw", 2, 3, f_ch_evalraw},
547 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
548 {"ch_getjob", 1, 1, f_ch_getjob},
549 {"ch_info", 1, 1, f_ch_info},
550 {"ch_log", 1, 2, f_ch_log},
551 {"ch_logfile", 1, 2, f_ch_logfile},
552 {"ch_open", 1, 2, f_ch_open},
553 {"ch_read", 1, 2, f_ch_read},
554 {"ch_readraw", 1, 2, f_ch_readraw},
555 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
556 {"ch_sendraw", 2, 3, f_ch_sendraw},
557 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200558 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200559#endif
560 {"changenr", 0, 0, f_changenr},
561 {"char2nr", 1, 2, f_char2nr},
562 {"cindent", 1, 1, f_cindent},
563 {"clearmatches", 0, 0, f_clearmatches},
564 {"col", 1, 1, f_col},
565#if defined(FEAT_INS_EXPAND)
566 {"complete", 2, 2, f_complete},
567 {"complete_add", 1, 1, f_complete_add},
568 {"complete_check", 0, 0, f_complete_check},
569#endif
570 {"confirm", 1, 4, f_confirm},
571 {"copy", 1, 1, f_copy},
572#ifdef FEAT_FLOAT
573 {"cos", 1, 1, f_cos},
574 {"cosh", 1, 1, f_cosh},
575#endif
576 {"count", 2, 4, f_count},
577 {"cscope_connection",0,3, f_cscope_connection},
578 {"cursor", 1, 3, f_cursor},
579 {"deepcopy", 1, 2, f_deepcopy},
580 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200581 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200582 {"did_filetype", 0, 0, f_did_filetype},
583 {"diff_filler", 1, 1, f_diff_filler},
584 {"diff_hlID", 2, 2, f_diff_hlID},
585 {"empty", 1, 1, f_empty},
586 {"escape", 2, 2, f_escape},
587 {"eval", 1, 1, f_eval},
588 {"eventhandler", 0, 0, f_eventhandler},
589 {"executable", 1, 1, f_executable},
590 {"execute", 1, 2, f_execute},
591 {"exepath", 1, 1, f_exepath},
592 {"exists", 1, 1, f_exists},
593#ifdef FEAT_FLOAT
594 {"exp", 1, 1, f_exp},
595#endif
596 {"expand", 1, 3, f_expand},
597 {"extend", 2, 3, f_extend},
598 {"feedkeys", 1, 2, f_feedkeys},
599 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
600 {"filereadable", 1, 1, f_filereadable},
601 {"filewritable", 1, 1, f_filewritable},
602 {"filter", 2, 2, f_filter},
603 {"finddir", 1, 3, f_finddir},
604 {"findfile", 1, 3, f_findfile},
605#ifdef FEAT_FLOAT
606 {"float2nr", 1, 1, f_float2nr},
607 {"floor", 1, 1, f_floor},
608 {"fmod", 2, 2, f_fmod},
609#endif
610 {"fnameescape", 1, 1, f_fnameescape},
611 {"fnamemodify", 2, 2, f_fnamemodify},
612 {"foldclosed", 1, 1, f_foldclosed},
613 {"foldclosedend", 1, 1, f_foldclosedend},
614 {"foldlevel", 1, 1, f_foldlevel},
615 {"foldtext", 0, 0, f_foldtext},
616 {"foldtextresult", 1, 1, f_foldtextresult},
617 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200618 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200619 {"function", 1, 3, f_function},
620 {"garbagecollect", 0, 1, f_garbagecollect},
621 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200622 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200623 {"getbufline", 2, 3, f_getbufline},
624 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100625 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200626 {"getchar", 0, 1, f_getchar},
627 {"getcharmod", 0, 0, f_getcharmod},
628 {"getcharsearch", 0, 0, f_getcharsearch},
629 {"getcmdline", 0, 0, f_getcmdline},
630 {"getcmdpos", 0, 0, f_getcmdpos},
631 {"getcmdtype", 0, 0, f_getcmdtype},
632 {"getcmdwintype", 0, 0, f_getcmdwintype},
633#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200634 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
636 {"getcurpos", 0, 0, f_getcurpos},
637 {"getcwd", 0, 2, f_getcwd},
638 {"getfontname", 0, 1, f_getfontname},
639 {"getfperm", 1, 1, f_getfperm},
640 {"getfsize", 1, 1, f_getfsize},
641 {"getftime", 1, 1, f_getftime},
642 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100643 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200645 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200646 {"getmatches", 0, 0, f_getmatches},
647 {"getpid", 0, 0, f_getpid},
648 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200649 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200650 {"getreg", 0, 3, f_getreg},
651 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200652 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"gettabvar", 2, 3, f_gettabvar},
654 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200655 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100656 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657 {"getwinposx", 0, 0, f_getwinposx},
658 {"getwinposy", 0, 0, f_getwinposy},
659 {"getwinvar", 2, 3, f_getwinvar},
660 {"glob", 1, 4, f_glob},
661 {"glob2regpat", 1, 1, f_glob2regpat},
662 {"globpath", 2, 5, f_globpath},
663 {"has", 1, 1, f_has},
664 {"has_key", 2, 2, f_has_key},
665 {"haslocaldir", 0, 2, f_haslocaldir},
666 {"hasmapto", 1, 3, f_hasmapto},
667 {"highlightID", 1, 1, f_hlID}, /* obsolete */
668 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
669 {"histadd", 2, 2, f_histadd},
670 {"histdel", 1, 2, f_histdel},
671 {"histget", 1, 2, f_histget},
672 {"histnr", 1, 1, f_histnr},
673 {"hlID", 1, 1, f_hlID},
674 {"hlexists", 1, 1, f_hlexists},
675 {"hostname", 0, 0, f_hostname},
676 {"iconv", 3, 3, f_iconv},
677 {"indent", 1, 1, f_indent},
678 {"index", 2, 4, f_index},
679 {"input", 1, 3, f_input},
680 {"inputdialog", 1, 3, f_inputdialog},
681 {"inputlist", 1, 1, f_inputlist},
682 {"inputrestore", 0, 0, f_inputrestore},
683 {"inputsave", 0, 0, f_inputsave},
684 {"inputsecret", 1, 2, f_inputsecret},
685 {"insert", 2, 3, f_insert},
686 {"invert", 1, 1, f_invert},
687 {"isdirectory", 1, 1, f_isdirectory},
688 {"islocked", 1, 1, f_islocked},
689#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
690 {"isnan", 1, 1, f_isnan},
691#endif
692 {"items", 1, 1, f_items},
693#ifdef FEAT_JOB_CHANNEL
694 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200695 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200696 {"job_setoptions", 2, 2, f_job_setoptions},
697 {"job_start", 1, 2, f_job_start},
698 {"job_status", 1, 1, f_job_status},
699 {"job_stop", 1, 2, f_job_stop},
700#endif
701 {"join", 1, 2, f_join},
702 {"js_decode", 1, 1, f_js_decode},
703 {"js_encode", 1, 1, f_js_encode},
704 {"json_decode", 1, 1, f_json_decode},
705 {"json_encode", 1, 1, f_json_encode},
706 {"keys", 1, 1, f_keys},
707 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
708 {"len", 1, 1, f_len},
709 {"libcall", 3, 3, f_libcall},
710 {"libcallnr", 3, 3, f_libcallnr},
711 {"line", 1, 1, f_line},
712 {"line2byte", 1, 1, f_line2byte},
713 {"lispindent", 1, 1, f_lispindent},
714 {"localtime", 0, 0, f_localtime},
715#ifdef FEAT_FLOAT
716 {"log", 1, 1, f_log},
717 {"log10", 1, 1, f_log10},
718#endif
719#ifdef FEAT_LUA
720 {"luaeval", 1, 2, f_luaeval},
721#endif
722 {"map", 2, 2, f_map},
723 {"maparg", 1, 4, f_maparg},
724 {"mapcheck", 1, 3, f_mapcheck},
725 {"match", 2, 4, f_match},
726 {"matchadd", 2, 5, f_matchadd},
727 {"matchaddpos", 2, 5, f_matchaddpos},
728 {"matcharg", 1, 1, f_matcharg},
729 {"matchdelete", 1, 1, f_matchdelete},
730 {"matchend", 2, 4, f_matchend},
731 {"matchlist", 2, 4, f_matchlist},
732 {"matchstr", 2, 4, f_matchstr},
733 {"matchstrpos", 2, 4, f_matchstrpos},
734 {"max", 1, 1, f_max},
735 {"min", 1, 1, f_min},
736#ifdef vim_mkdir
737 {"mkdir", 1, 3, f_mkdir},
738#endif
739 {"mode", 0, 1, f_mode},
740#ifdef FEAT_MZSCHEME
741 {"mzeval", 1, 1, f_mzeval},
742#endif
743 {"nextnonblank", 1, 1, f_nextnonblank},
744 {"nr2char", 1, 2, f_nr2char},
745 {"or", 2, 2, f_or},
746 {"pathshorten", 1, 1, f_pathshorten},
747#ifdef FEAT_PERL
748 {"perleval", 1, 1, f_perleval},
749#endif
750#ifdef FEAT_FLOAT
751 {"pow", 2, 2, f_pow},
752#endif
753 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100754 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200755#ifdef FEAT_JOB_CHANNEL
756 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
757 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
758#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200759 {"pumvisible", 0, 0, f_pumvisible},
760#ifdef FEAT_PYTHON3
761 {"py3eval", 1, 1, f_py3eval},
762#endif
763#ifdef FEAT_PYTHON
764 {"pyeval", 1, 1, f_pyeval},
765#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100766#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
767 {"pyxeval", 1, 1, f_pyxeval},
768#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200769 {"range", 1, 3, f_range},
770 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200771 {"reg_executing", 0, 0, f_reg_executing},
772 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200773 {"reltime", 0, 2, f_reltime},
774#ifdef FEAT_FLOAT
775 {"reltimefloat", 1, 1, f_reltimefloat},
776#endif
777 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100778 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779 {"remote_foreground", 1, 1, f_remote_foreground},
780 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100781 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200782 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100783 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200784 {"remove", 2, 3, f_remove},
785 {"rename", 2, 2, f_rename},
786 {"repeat", 2, 2, f_repeat},
787 {"resolve", 1, 1, f_resolve},
788 {"reverse", 1, 1, f_reverse},
789#ifdef FEAT_FLOAT
790 {"round", 1, 1, f_round},
791#endif
792 {"screenattr", 2, 2, f_screenattr},
793 {"screenchar", 2, 2, f_screenchar},
794 {"screencol", 0, 0, f_screencol},
795 {"screenrow", 0, 0, f_screenrow},
796 {"search", 1, 4, f_search},
797 {"searchdecl", 1, 3, f_searchdecl},
798 {"searchpair", 3, 7, f_searchpair},
799 {"searchpairpos", 3, 7, f_searchpairpos},
800 {"searchpos", 1, 4, f_searchpos},
801 {"server2client", 2, 2, f_server2client},
802 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200803 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804 {"setbufvar", 3, 3, f_setbufvar},
805 {"setcharsearch", 1, 1, f_setcharsearch},
806 {"setcmdpos", 1, 1, f_setcmdpos},
807 {"setfperm", 2, 2, f_setfperm},
808 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200809 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200810 {"setmatches", 1, 1, f_setmatches},
811 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200812 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200813 {"setreg", 2, 3, f_setreg},
814 {"settabvar", 3, 3, f_settabvar},
815 {"settabwinvar", 4, 4, f_settabwinvar},
816 {"setwinvar", 3, 3, f_setwinvar},
817#ifdef FEAT_CRYPT
818 {"sha256", 1, 1, f_sha256},
819#endif
820 {"shellescape", 1, 2, f_shellescape},
821 {"shiftwidth", 0, 0, f_shiftwidth},
822 {"simplify", 1, 1, f_simplify},
823#ifdef FEAT_FLOAT
824 {"sin", 1, 1, f_sin},
825 {"sinh", 1, 1, f_sinh},
826#endif
827 {"sort", 1, 3, f_sort},
828 {"soundfold", 1, 1, f_soundfold},
829 {"spellbadword", 0, 1, f_spellbadword},
830 {"spellsuggest", 1, 3, f_spellsuggest},
831 {"split", 1, 3, f_split},
832#ifdef FEAT_FLOAT
833 {"sqrt", 1, 1, f_sqrt},
834 {"str2float", 1, 1, f_str2float},
835#endif
836 {"str2nr", 1, 2, f_str2nr},
837 {"strcharpart", 2, 3, f_strcharpart},
838 {"strchars", 1, 2, f_strchars},
839 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
840#ifdef HAVE_STRFTIME
841 {"strftime", 1, 2, f_strftime},
842#endif
843 {"strgetchar", 2, 2, f_strgetchar},
844 {"stridx", 2, 3, f_stridx},
845 {"string", 1, 1, f_string},
846 {"strlen", 1, 1, f_strlen},
847 {"strpart", 2, 3, f_strpart},
848 {"strridx", 2, 3, f_strridx},
849 {"strtrans", 1, 1, f_strtrans},
850 {"strwidth", 1, 1, f_strwidth},
851 {"submatch", 1, 2, f_submatch},
852 {"substitute", 4, 4, f_substitute},
853 {"synID", 3, 3, f_synID},
854 {"synIDattr", 2, 3, f_synIDattr},
855 {"synIDtrans", 1, 1, f_synIDtrans},
856 {"synconcealed", 2, 2, f_synconcealed},
857 {"synstack", 2, 2, f_synstack},
858 {"system", 1, 2, f_system},
859 {"systemlist", 1, 2, f_systemlist},
860 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
861 {"tabpagenr", 0, 1, f_tabpagenr},
862 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
863 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100864 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200865#ifdef FEAT_FLOAT
866 {"tan", 1, 1, f_tan},
867 {"tanh", 1, 1, f_tanh},
868#endif
869 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200870#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100871 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
872 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100873 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200874 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200875# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
876 {"term_getansicolors", 1, 1, f_term_getansicolors},
877# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200878 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200879 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200880 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200881 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200882 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200883 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200884 {"term_getstatus", 1, 1, f_term_getstatus},
885 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200886 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200887 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200888 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200889 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200890# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
891 {"term_setansicolors", 2, 2, f_term_setansicolors},
892# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100893 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100894 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200895 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200896 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200897 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200898#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200899 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
900 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200901 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200902 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100903 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200904#ifdef FEAT_JOB_CHANNEL
905 {"test_null_channel", 0, 0, f_test_null_channel},
906#endif
907 {"test_null_dict", 0, 0, f_test_null_dict},
908#ifdef FEAT_JOB_CHANNEL
909 {"test_null_job", 0, 0, f_test_null_job},
910#endif
911 {"test_null_list", 0, 0, f_test_null_list},
912 {"test_null_partial", 0, 0, f_test_null_partial},
913 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100914 {"test_override", 2, 2, f_test_override},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200915 {"test_settime", 1, 1, f_test_settime},
916#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200917 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200918 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200919 {"timer_start", 2, 3, f_timer_start},
920 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200921 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922#endif
923 {"tolower", 1, 1, f_tolower},
924 {"toupper", 1, 1, f_toupper},
925 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100926 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200927#ifdef FEAT_FLOAT
928 {"trunc", 1, 1, f_trunc},
929#endif
930 {"type", 1, 1, f_type},
931 {"undofile", 1, 1, f_undofile},
932 {"undotree", 0, 0, f_undotree},
933 {"uniq", 1, 3, f_uniq},
934 {"values", 1, 1, f_values},
935 {"virtcol", 1, 1, f_virtcol},
936 {"visualmode", 0, 1, f_visualmode},
937 {"wildmenumode", 0, 0, f_wildmenumode},
938 {"win_findbuf", 1, 1, f_win_findbuf},
939 {"win_getid", 0, 2, f_win_getid},
940 {"win_gotoid", 1, 1, f_win_gotoid},
941 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
942 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100943 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200944 {"winbufnr", 1, 1, f_winbufnr},
945 {"wincol", 0, 0, f_wincol},
946 {"winheight", 1, 1, f_winheight},
947 {"winline", 0, 0, f_winline},
948 {"winnr", 0, 1, f_winnr},
949 {"winrestcmd", 0, 0, f_winrestcmd},
950 {"winrestview", 1, 1, f_winrestview},
951 {"winsaveview", 0, 0, f_winsaveview},
952 {"winwidth", 1, 1, f_winwidth},
953 {"wordcount", 0, 0, f_wordcount},
954 {"writefile", 2, 3, f_writefile},
955 {"xor", 2, 2, f_xor},
956};
957
958#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
959
960/*
961 * Function given to ExpandGeneric() to obtain the list of internal
962 * or user defined function names.
963 */
964 char_u *
965get_function_name(expand_T *xp, int idx)
966{
967 static int intidx = -1;
968 char_u *name;
969
970 if (idx == 0)
971 intidx = -1;
972 if (intidx < 0)
973 {
974 name = get_user_func_name(xp, idx);
975 if (name != NULL)
976 return name;
977 }
978 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
979 {
980 STRCPY(IObuff, functions[intidx].f_name);
981 STRCAT(IObuff, "(");
982 if (functions[intidx].f_max_argc == 0)
983 STRCAT(IObuff, ")");
984 return IObuff;
985 }
986
987 return NULL;
988}
989
990/*
991 * Function given to ExpandGeneric() to obtain the list of internal or
992 * user defined variable or function names.
993 */
994 char_u *
995get_expr_name(expand_T *xp, int idx)
996{
997 static int intidx = -1;
998 char_u *name;
999
1000 if (idx == 0)
1001 intidx = -1;
1002 if (intidx < 0)
1003 {
1004 name = get_function_name(xp, idx);
1005 if (name != NULL)
1006 return name;
1007 }
1008 return get_user_var_name(xp, ++intidx);
1009}
1010
1011#endif /* FEAT_CMDL_COMPL */
1012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001013/*
1014 * Find internal function in table above.
1015 * Return index, or -1 if not found
1016 */
1017 int
1018find_internal_func(
1019 char_u *name) /* name of the function */
1020{
1021 int first = 0;
1022 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1023 int cmp;
1024 int x;
1025
1026 /*
1027 * Find the function name in the table. Binary search.
1028 */
1029 while (first <= last)
1030 {
1031 x = first + ((unsigned)(last - first) >> 1);
1032 cmp = STRCMP(name, functions[x].f_name);
1033 if (cmp < 0)
1034 last = x - 1;
1035 else if (cmp > 0)
1036 first = x + 1;
1037 else
1038 return x;
1039 }
1040 return -1;
1041}
1042
1043 int
1044call_internal_func(
1045 char_u *name,
1046 int argcount,
1047 typval_T *argvars,
1048 typval_T *rettv)
1049{
1050 int i;
1051
1052 i = find_internal_func(name);
1053 if (i < 0)
1054 return ERROR_UNKNOWN;
1055 if (argcount < functions[i].f_min_argc)
1056 return ERROR_TOOFEW;
1057 if (argcount > functions[i].f_max_argc)
1058 return ERROR_TOOMANY;
1059 argvars[argcount].v_type = VAR_UNKNOWN;
1060 functions[i].f_func(argvars, rettv);
1061 return ERROR_NONE;
1062}
1063
1064/*
1065 * Return TRUE for a non-zero Number and a non-empty String.
1066 */
1067 static int
1068non_zero_arg(typval_T *argvars)
1069{
1070 return ((argvars[0].v_type == VAR_NUMBER
1071 && argvars[0].vval.v_number != 0)
1072 || (argvars[0].v_type == VAR_SPECIAL
1073 && argvars[0].vval.v_number == VVAL_TRUE)
1074 || (argvars[0].v_type == VAR_STRING
1075 && argvars[0].vval.v_string != NULL
1076 && *argvars[0].vval.v_string != NUL));
1077}
1078
1079/*
1080 * Get the lnum from the first argument.
1081 * Also accepts ".", "$", etc., but that only works for the current buffer.
1082 * Returns -1 on error.
1083 */
1084 static linenr_T
1085get_tv_lnum(typval_T *argvars)
1086{
1087 typval_T rettv;
1088 linenr_T lnum;
1089
1090 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1091 if (lnum == 0) /* no valid number, try using line() */
1092 {
1093 rettv.v_type = VAR_NUMBER;
1094 f_line(argvars, &rettv);
1095 lnum = (linenr_T)rettv.vval.v_number;
1096 clear_tv(&rettv);
1097 }
1098 return lnum;
1099}
1100
1101#ifdef FEAT_FLOAT
1102static int get_float_arg(typval_T *argvars, float_T *f);
1103
1104/*
1105 * Get the float value of "argvars[0]" into "f".
1106 * Returns FAIL when the argument is not a Number or Float.
1107 */
1108 static int
1109get_float_arg(typval_T *argvars, float_T *f)
1110{
1111 if (argvars[0].v_type == VAR_FLOAT)
1112 {
1113 *f = argvars[0].vval.v_float;
1114 return OK;
1115 }
1116 if (argvars[0].v_type == VAR_NUMBER)
1117 {
1118 *f = (float_T)argvars[0].vval.v_number;
1119 return OK;
1120 }
1121 EMSG(_("E808: Number or Float required"));
1122 return FAIL;
1123}
1124
1125/*
1126 * "abs(expr)" function
1127 */
1128 static void
1129f_abs(typval_T *argvars, typval_T *rettv)
1130{
1131 if (argvars[0].v_type == VAR_FLOAT)
1132 {
1133 rettv->v_type = VAR_FLOAT;
1134 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1135 }
1136 else
1137 {
1138 varnumber_T n;
1139 int error = FALSE;
1140
1141 n = get_tv_number_chk(&argvars[0], &error);
1142 if (error)
1143 rettv->vval.v_number = -1;
1144 else if (n > 0)
1145 rettv->vval.v_number = n;
1146 else
1147 rettv->vval.v_number = -n;
1148 }
1149}
1150
1151/*
1152 * "acos()" function
1153 */
1154 static void
1155f_acos(typval_T *argvars, typval_T *rettv)
1156{
1157 float_T f = 0.0;
1158
1159 rettv->v_type = VAR_FLOAT;
1160 if (get_float_arg(argvars, &f) == OK)
1161 rettv->vval.v_float = acos(f);
1162 else
1163 rettv->vval.v_float = 0.0;
1164}
1165#endif
1166
1167/*
1168 * "add(list, item)" function
1169 */
1170 static void
1171f_add(typval_T *argvars, typval_T *rettv)
1172{
1173 list_T *l;
1174
1175 rettv->vval.v_number = 1; /* Default: Failed */
1176 if (argvars[0].v_type == VAR_LIST)
1177 {
1178 if ((l = argvars[0].vval.v_list) != NULL
1179 && !tv_check_lock(l->lv_lock,
1180 (char_u *)N_("add() argument"), TRUE)
1181 && list_append_tv(l, &argvars[1]) == OK)
1182 copy_tv(&argvars[0], rettv);
1183 }
1184 else
1185 EMSG(_(e_listreq));
1186}
1187
1188/*
1189 * "and(expr, expr)" function
1190 */
1191 static void
1192f_and(typval_T *argvars, typval_T *rettv)
1193{
1194 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1195 & get_tv_number_chk(&argvars[1], NULL);
1196}
1197
1198/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001199 * Get the lnum from the first argument.
1200 * Also accepts "$", then "buf" is used.
1201 * Returns 0 on error.
1202 */
1203 static linenr_T
1204get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
1205{
1206 if (argvars[0].v_type == VAR_STRING
1207 && argvars[0].vval.v_string != NULL
1208 && argvars[0].vval.v_string[0] == '$'
1209 && buf != NULL)
1210 return buf->b_ml.ml_line_count;
1211 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1212}
1213
1214/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001215 * If there is a window for "curbuf", make it the current window.
1216 */
1217 static void
1218find_win_for_curbuf(void)
1219{
1220 wininfo_T *wip;
1221
1222 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1223 {
1224 if (wip->wi_win != NULL)
1225 {
1226 curwin = wip->wi_win;
1227 break;
1228 }
1229 }
1230}
1231
1232/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001233 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001234 */
1235 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001236set_buffer_lines(
1237 buf_T *buf,
1238 linenr_T lnum_arg,
1239 int append,
1240 typval_T *lines,
1241 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242{
Bram Moolenaarca851592018-06-06 21:04:07 +02001243 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1244 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001245 list_T *l = NULL;
1246 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001247 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001248 linenr_T append_lnum;
1249 buf_T *curbuf_save = NULL;
1250 win_T *curwin_save = NULL;
1251 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252
Bram Moolenaarca851592018-06-06 21:04:07 +02001253 /* When using the current buffer ml_mfp will be set if needed. Useful when
1254 * setline() is used on startup. For other buffers the buffer must be
1255 * loaded. */
1256 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001257 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001258 rettv->vval.v_number = 1; /* FAIL */
1259 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001260 }
1261
Bram Moolenaarca851592018-06-06 21:04:07 +02001262 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001263 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001264 curbuf_save = curbuf;
1265 curwin_save = curwin;
1266 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001267 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001268 }
1269
1270 if (append)
1271 // appendbufline() uses the line number below which we insert
1272 append_lnum = lnum - 1;
1273 else
1274 // setbufline() uses the line number above which we insert, we only
1275 // append if it's below the last line
1276 append_lnum = curbuf->b_ml.ml_line_count;
1277
1278 if (lines->v_type == VAR_LIST)
1279 {
1280 l = lines->vval.v_list;
1281 li = l->lv_first;
1282 }
1283 else
1284 line = get_tv_string_chk(lines);
1285
1286 /* default result is zero == OK */
1287 for (;;)
1288 {
1289 if (l != NULL)
1290 {
1291 /* list argument, get next string */
1292 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 break;
Bram Moolenaarca851592018-06-06 21:04:07 +02001294 line = get_tv_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 li = li->li_next;
1296 }
1297
Bram Moolenaarca851592018-06-06 21:04:07 +02001298 rettv->vval.v_number = 1; /* FAIL */
1299 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1300 break;
1301
1302 /* When coming here from Insert mode, sync undo, so that this can be
1303 * undone separately from what was previously inserted. */
1304 if (u_sync_once == 2)
1305 {
1306 u_sync_once = 1; /* notify that u_sync() was called */
1307 u_sync(TRUE);
1308 }
1309
1310 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1311 {
1312 /* existing line, replace it */
1313 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
1314 {
1315 changed_bytes(lnum, 0);
1316 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1317 check_cursor_col();
1318 rettv->vval.v_number = 0; /* OK */
1319 }
1320 }
1321 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1322 {
1323 /* append the line */
1324 ++added;
1325 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1326 rettv->vval.v_number = 0; /* OK */
1327 }
1328
1329 if (l == NULL) /* only one string argument */
1330 break;
1331 ++lnum;
1332 }
1333
1334 if (added > 0)
1335 {
1336 win_T *wp;
1337 tabpage_T *tp;
1338
1339 appended_lines_mark(append_lnum, added);
1340 FOR_ALL_TAB_WINDOWS(tp, wp)
1341 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1342 wp->w_cursor.lnum += added;
1343 check_cursor_col();
1344
Bram Moolenaarf2732452018-06-03 14:47:35 +02001345#ifdef FEAT_JOB_CHANNEL
1346 if (bt_prompt(curbuf) && (State & INSERT))
1347 // show the line with the prompt
1348 update_topline();
1349#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001351
1352 if (!is_curbuf)
1353 {
1354 curbuf = curbuf_save;
1355 curwin = curwin_save;
1356 }
1357}
1358
1359/*
1360 * "append(lnum, string/list)" function
1361 */
1362 static void
1363f_append(typval_T *argvars, typval_T *rettv)
1364{
1365 linenr_T lnum = get_tv_lnum(&argvars[0]);
1366
1367 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1368}
1369
1370/*
1371 * "appendbufline(buf, lnum, string/list)" function
1372 */
1373 static void
1374f_appendbufline(typval_T *argvars, typval_T *rettv)
1375{
1376 linenr_T lnum;
1377 buf_T *buf;
1378
1379 buf = get_buf_tv(&argvars[0], FALSE);
1380 if (buf == NULL)
1381 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001383 {
1384 lnum = get_tv_lnum_buf(&argvars[1], buf);
1385 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1386 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001387}
1388
1389/*
1390 * "argc()" function
1391 */
1392 static void
1393f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1394{
1395 rettv->vval.v_number = ARGCOUNT;
1396}
1397
1398/*
1399 * "argidx()" function
1400 */
1401 static void
1402f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1403{
1404 rettv->vval.v_number = curwin->w_arg_idx;
1405}
1406
1407/*
1408 * "arglistid()" function
1409 */
1410 static void
1411f_arglistid(typval_T *argvars, typval_T *rettv)
1412{
1413 win_T *wp;
1414
1415 rettv->vval.v_number = -1;
1416 wp = find_tabwin(&argvars[0], &argvars[1]);
1417 if (wp != NULL)
1418 rettv->vval.v_number = wp->w_alist->id;
1419}
1420
1421/*
1422 * "argv(nr)" function
1423 */
1424 static void
1425f_argv(typval_T *argvars, typval_T *rettv)
1426{
1427 int idx;
1428
1429 if (argvars[0].v_type != VAR_UNKNOWN)
1430 {
1431 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1432 if (idx >= 0 && idx < ARGCOUNT)
1433 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1434 else
1435 rettv->vval.v_string = NULL;
1436 rettv->v_type = VAR_STRING;
1437 }
1438 else if (rettv_list_alloc(rettv) == OK)
1439 for (idx = 0; idx < ARGCOUNT; ++idx)
1440 list_append_string(rettv->vval.v_list,
1441 alist_name(&ARGLIST[idx]), -1);
1442}
1443
1444/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001445 * "assert_beeps(cmd [, error])" function
1446 */
1447 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001448f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001449{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001450 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001451}
1452
1453/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001454 * "assert_equal(expected, actual[, msg])" function
1455 */
1456 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001457f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001458{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001459 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001460}
1461
1462/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001463 * "assert_equalfile(fname-one, fname-two)" function
1464 */
1465 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001466f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001467{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001468 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001469}
1470
1471/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001472 * "assert_notequal(expected, actual[, msg])" function
1473 */
1474 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001475f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001476{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001477 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001478}
1479
1480/*
1481 * "assert_exception(string[, msg])" function
1482 */
1483 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001484f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001485{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001486 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001487}
1488
1489/*
1490 * "assert_fails(cmd [, error])" function
1491 */
1492 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001493f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001494{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001495 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001496}
1497
1498/*
1499 * "assert_false(actual[, msg])" function
1500 */
1501 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001502f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001503{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001504 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001505}
1506
1507/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001508 * "assert_inrange(lower, upper[, msg])" function
1509 */
1510 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001511f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001512{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001513 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001514}
1515
1516/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001517 * "assert_match(pattern, actual[, msg])" function
1518 */
1519 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001520f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001521{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001522 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001523}
1524
1525/*
1526 * "assert_notmatch(pattern, actual[, msg])" function
1527 */
1528 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001529f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001530{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001531 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001532}
1533
1534/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001535 * "assert_report(msg)" function
1536 */
1537 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001538f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001539{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001540 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001541}
1542
1543/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001544 * "assert_true(actual[, msg])" function
1545 */
1546 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001547f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001548{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001549 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001550}
1551
1552#ifdef FEAT_FLOAT
1553/*
1554 * "asin()" function
1555 */
1556 static void
1557f_asin(typval_T *argvars, typval_T *rettv)
1558{
1559 float_T f = 0.0;
1560
1561 rettv->v_type = VAR_FLOAT;
1562 if (get_float_arg(argvars, &f) == OK)
1563 rettv->vval.v_float = asin(f);
1564 else
1565 rettv->vval.v_float = 0.0;
1566}
1567
1568/*
1569 * "atan()" function
1570 */
1571 static void
1572f_atan(typval_T *argvars, typval_T *rettv)
1573{
1574 float_T f = 0.0;
1575
1576 rettv->v_type = VAR_FLOAT;
1577 if (get_float_arg(argvars, &f) == OK)
1578 rettv->vval.v_float = atan(f);
1579 else
1580 rettv->vval.v_float = 0.0;
1581}
1582
1583/*
1584 * "atan2()" function
1585 */
1586 static void
1587f_atan2(typval_T *argvars, typval_T *rettv)
1588{
1589 float_T fx = 0.0, fy = 0.0;
1590
1591 rettv->v_type = VAR_FLOAT;
1592 if (get_float_arg(argvars, &fx) == OK
1593 && get_float_arg(&argvars[1], &fy) == OK)
1594 rettv->vval.v_float = atan2(fx, fy);
1595 else
1596 rettv->vval.v_float = 0.0;
1597}
1598#endif
1599
1600/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001601 * "balloon_show()" function
1602 */
1603#ifdef FEAT_BEVAL
1604 static void
1605f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1606{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001607 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001608 {
1609 if (argvars[0].v_type == VAR_LIST
1610# ifdef FEAT_GUI
1611 && !gui.in_use
1612# endif
1613 )
1614 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1615 else
1616 post_balloon(balloonEval, get_tv_string_chk(&argvars[0]), NULL);
1617 }
1618}
1619
Bram Moolenaar669a8282017-11-19 20:13:05 +01001620# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001621 static void
1622f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1623{
1624 if (rettv_list_alloc(rettv) == OK)
1625 {
1626 char_u *msg = get_tv_string_chk(&argvars[0]);
1627
1628 if (msg != NULL)
1629 {
1630 pumitem_T *array;
1631 int size = split_message(msg, &array);
1632 int i;
1633
1634 /* Skip the first and last item, they are always empty. */
1635 for (i = 1; i < size - 1; ++i)
1636 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001637 while (size > 0)
1638 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001639 vim_free(array);
1640 }
1641 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001642}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001643# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001644#endif
1645
1646/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001647 * "browse(save, title, initdir, default)" function
1648 */
1649 static void
1650f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1651{
1652#ifdef FEAT_BROWSE
1653 int save;
1654 char_u *title;
1655 char_u *initdir;
1656 char_u *defname;
1657 char_u buf[NUMBUFLEN];
1658 char_u buf2[NUMBUFLEN];
1659 int error = FALSE;
1660
1661 save = (int)get_tv_number_chk(&argvars[0], &error);
1662 title = get_tv_string_chk(&argvars[1]);
1663 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1664 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1665
1666 if (error || title == NULL || initdir == NULL || defname == NULL)
1667 rettv->vval.v_string = NULL;
1668 else
1669 rettv->vval.v_string =
1670 do_browse(save ? BROWSE_SAVE : 0,
1671 title, defname, NULL, initdir, NULL, curbuf);
1672#else
1673 rettv->vval.v_string = NULL;
1674#endif
1675 rettv->v_type = VAR_STRING;
1676}
1677
1678/*
1679 * "browsedir(title, initdir)" function
1680 */
1681 static void
1682f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1683{
1684#ifdef FEAT_BROWSE
1685 char_u *title;
1686 char_u *initdir;
1687 char_u buf[NUMBUFLEN];
1688
1689 title = get_tv_string_chk(&argvars[0]);
1690 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1691
1692 if (title == NULL || initdir == NULL)
1693 rettv->vval.v_string = NULL;
1694 else
1695 rettv->vval.v_string = do_browse(BROWSE_DIR,
1696 title, NULL, NULL, initdir, NULL, curbuf);
1697#else
1698 rettv->vval.v_string = NULL;
1699#endif
1700 rettv->v_type = VAR_STRING;
1701}
1702
1703static buf_T *find_buffer(typval_T *avar);
1704
1705/*
1706 * Find a buffer by number or exact name.
1707 */
1708 static buf_T *
1709find_buffer(typval_T *avar)
1710{
1711 buf_T *buf = NULL;
1712
1713 if (avar->v_type == VAR_NUMBER)
1714 buf = buflist_findnr((int)avar->vval.v_number);
1715 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1716 {
1717 buf = buflist_findname_exp(avar->vval.v_string);
1718 if (buf == NULL)
1719 {
1720 /* No full path name match, try a match with a URL or a "nofile"
1721 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001722 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001723 if (buf->b_fname != NULL
1724 && (path_with_url(buf->b_fname)
1725#ifdef FEAT_QUICKFIX
1726 || bt_nofile(buf)
1727#endif
1728 )
1729 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1730 break;
1731 }
1732 }
1733 return buf;
1734}
1735
1736/*
1737 * "bufexists(expr)" function
1738 */
1739 static void
1740f_bufexists(typval_T *argvars, typval_T *rettv)
1741{
1742 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1743}
1744
1745/*
1746 * "buflisted(expr)" function
1747 */
1748 static void
1749f_buflisted(typval_T *argvars, typval_T *rettv)
1750{
1751 buf_T *buf;
1752
1753 buf = find_buffer(&argvars[0]);
1754 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1755}
1756
1757/*
1758 * "bufloaded(expr)" function
1759 */
1760 static void
1761f_bufloaded(typval_T *argvars, typval_T *rettv)
1762{
1763 buf_T *buf;
1764
1765 buf = find_buffer(&argvars[0]);
1766 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1767}
1768
1769 buf_T *
1770buflist_find_by_name(char_u *name, int curtab_only)
1771{
1772 int save_magic;
1773 char_u *save_cpo;
1774 buf_T *buf;
1775
1776 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1777 save_magic = p_magic;
1778 p_magic = TRUE;
1779 save_cpo = p_cpo;
1780 p_cpo = (char_u *)"";
1781
1782 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1783 TRUE, FALSE, curtab_only));
1784
1785 p_magic = save_magic;
1786 p_cpo = save_cpo;
1787 return buf;
1788}
1789
1790/*
1791 * Get buffer by number or pattern.
1792 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001793 buf_T *
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001794get_buf_tv(typval_T *tv, int curtab_only)
1795{
1796 char_u *name = tv->vval.v_string;
1797 buf_T *buf;
1798
1799 if (tv->v_type == VAR_NUMBER)
1800 return buflist_findnr((int)tv->vval.v_number);
1801 if (tv->v_type != VAR_STRING)
1802 return NULL;
1803 if (name == NULL || *name == NUL)
1804 return curbuf;
1805 if (name[0] == '$' && name[1] == NUL)
1806 return lastbuf;
1807
1808 buf = buflist_find_by_name(name, curtab_only);
1809
1810 /* If not found, try expanding the name, like done for bufexists(). */
1811 if (buf == NULL)
1812 buf = find_buffer(tv);
1813
1814 return buf;
1815}
1816
1817/*
1818 * "bufname(expr)" function
1819 */
1820 static void
1821f_bufname(typval_T *argvars, typval_T *rettv)
1822{
1823 buf_T *buf;
1824
1825 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1826 ++emsg_off;
1827 buf = get_buf_tv(&argvars[0], FALSE);
1828 rettv->v_type = VAR_STRING;
1829 if (buf != NULL && buf->b_fname != NULL)
1830 rettv->vval.v_string = vim_strsave(buf->b_fname);
1831 else
1832 rettv->vval.v_string = NULL;
1833 --emsg_off;
1834}
1835
1836/*
1837 * "bufnr(expr)" function
1838 */
1839 static void
1840f_bufnr(typval_T *argvars, typval_T *rettv)
1841{
1842 buf_T *buf;
1843 int error = FALSE;
1844 char_u *name;
1845
1846 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1847 ++emsg_off;
1848 buf = get_buf_tv(&argvars[0], FALSE);
1849 --emsg_off;
1850
1851 /* If the buffer isn't found and the second argument is not zero create a
1852 * new buffer. */
1853 if (buf == NULL
1854 && argvars[1].v_type != VAR_UNKNOWN
1855 && get_tv_number_chk(&argvars[1], &error) != 0
1856 && !error
1857 && (name = get_tv_string_chk(&argvars[0])) != NULL
1858 && !error)
1859 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1860
1861 if (buf != NULL)
1862 rettv->vval.v_number = buf->b_fnum;
1863 else
1864 rettv->vval.v_number = -1;
1865}
1866
1867 static void
1868buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1869{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001870 win_T *wp;
1871 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001872 buf_T *buf;
1873
1874 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1875 ++emsg_off;
1876 buf = get_buf_tv(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001877 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001878 {
1879 ++winnr;
1880 if (wp->w_buffer == buf)
1881 break;
1882 }
1883 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001884 --emsg_off;
1885}
1886
1887/*
1888 * "bufwinid(nr)" function
1889 */
1890 static void
1891f_bufwinid(typval_T *argvars, typval_T *rettv)
1892{
1893 buf_win_common(argvars, rettv, FALSE);
1894}
1895
1896/*
1897 * "bufwinnr(nr)" function
1898 */
1899 static void
1900f_bufwinnr(typval_T *argvars, typval_T *rettv)
1901{
1902 buf_win_common(argvars, rettv, TRUE);
1903}
1904
1905/*
1906 * "byte2line(byte)" function
1907 */
1908 static void
1909f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1910{
1911#ifndef FEAT_BYTEOFF
1912 rettv->vval.v_number = -1;
1913#else
1914 long boff = 0;
1915
1916 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1917 if (boff < 0)
1918 rettv->vval.v_number = -1;
1919 else
1920 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1921 (linenr_T)0, &boff);
1922#endif
1923}
1924
1925 static void
1926byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1927{
1928#ifdef FEAT_MBYTE
1929 char_u *t;
1930#endif
1931 char_u *str;
1932 varnumber_T idx;
1933
1934 str = get_tv_string_chk(&argvars[0]);
1935 idx = get_tv_number_chk(&argvars[1], NULL);
1936 rettv->vval.v_number = -1;
1937 if (str == NULL || idx < 0)
1938 return;
1939
1940#ifdef FEAT_MBYTE
1941 t = str;
1942 for ( ; idx > 0; idx--)
1943 {
1944 if (*t == NUL) /* EOL reached */
1945 return;
1946 if (enc_utf8 && comp)
1947 t += utf_ptr2len(t);
1948 else
1949 t += (*mb_ptr2len)(t);
1950 }
1951 rettv->vval.v_number = (varnumber_T)(t - str);
1952#else
1953 if ((size_t)idx <= STRLEN(str))
1954 rettv->vval.v_number = idx;
1955#endif
1956}
1957
1958/*
1959 * "byteidx()" function
1960 */
1961 static void
1962f_byteidx(typval_T *argvars, typval_T *rettv)
1963{
1964 byteidx(argvars, rettv, FALSE);
1965}
1966
1967/*
1968 * "byteidxcomp()" function
1969 */
1970 static void
1971f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1972{
1973 byteidx(argvars, rettv, TRUE);
1974}
1975
1976/*
1977 * "call(func, arglist [, dict])" function
1978 */
1979 static void
1980f_call(typval_T *argvars, typval_T *rettv)
1981{
1982 char_u *func;
1983 partial_T *partial = NULL;
1984 dict_T *selfdict = NULL;
1985
1986 if (argvars[1].v_type != VAR_LIST)
1987 {
1988 EMSG(_(e_listreq));
1989 return;
1990 }
1991 if (argvars[1].vval.v_list == NULL)
1992 return;
1993
1994 if (argvars[0].v_type == VAR_FUNC)
1995 func = argvars[0].vval.v_string;
1996 else if (argvars[0].v_type == VAR_PARTIAL)
1997 {
1998 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001999 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002000 }
2001 else
2002 func = get_tv_string(&argvars[0]);
2003 if (*func == NUL)
2004 return; /* type error or empty name */
2005
2006 if (argvars[2].v_type != VAR_UNKNOWN)
2007 {
2008 if (argvars[2].v_type != VAR_DICT)
2009 {
2010 EMSG(_(e_dictreq));
2011 return;
2012 }
2013 selfdict = argvars[2].vval.v_dict;
2014 }
2015
2016 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2017}
2018
2019#ifdef FEAT_FLOAT
2020/*
2021 * "ceil({float})" function
2022 */
2023 static void
2024f_ceil(typval_T *argvars, typval_T *rettv)
2025{
2026 float_T f = 0.0;
2027
2028 rettv->v_type = VAR_FLOAT;
2029 if (get_float_arg(argvars, &f) == OK)
2030 rettv->vval.v_float = ceil(f);
2031 else
2032 rettv->vval.v_float = 0.0;
2033}
2034#endif
2035
2036#ifdef FEAT_JOB_CHANNEL
2037/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002038 * "ch_canread()" function
2039 */
2040 static void
2041f_ch_canread(typval_T *argvars, typval_T *rettv)
2042{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002043 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002044
2045 rettv->vval.v_number = 0;
2046 if (channel != NULL)
2047 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2048 || channel_has_readahead(channel, PART_OUT)
2049 || channel_has_readahead(channel, PART_ERR);
2050}
2051
2052/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002053 * "ch_close()" function
2054 */
2055 static void
2056f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2057{
2058 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2059
2060 if (channel != NULL)
2061 {
2062 channel_close(channel, FALSE);
2063 channel_clear(channel);
2064 }
2065}
2066
2067/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002068 * "ch_close()" function
2069 */
2070 static void
2071f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2072{
2073 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2074
2075 if (channel != NULL)
2076 channel_close_in(channel);
2077}
2078
2079/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002080 * "ch_getbufnr()" function
2081 */
2082 static void
2083f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2084{
2085 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2086
2087 rettv->vval.v_number = -1;
2088 if (channel != NULL)
2089 {
2090 char_u *what = get_tv_string(&argvars[1]);
2091 int part;
2092
2093 if (STRCMP(what, "err") == 0)
2094 part = PART_ERR;
2095 else if (STRCMP(what, "out") == 0)
2096 part = PART_OUT;
2097 else if (STRCMP(what, "in") == 0)
2098 part = PART_IN;
2099 else
2100 part = PART_SOCK;
2101 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2102 rettv->vval.v_number =
2103 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2104 }
2105}
2106
2107/*
2108 * "ch_getjob()" function
2109 */
2110 static void
2111f_ch_getjob(typval_T *argvars, typval_T *rettv)
2112{
2113 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2114
2115 if (channel != NULL)
2116 {
2117 rettv->v_type = VAR_JOB;
2118 rettv->vval.v_job = channel->ch_job;
2119 if (channel->ch_job != NULL)
2120 ++channel->ch_job->jv_refcount;
2121 }
2122}
2123
2124/*
2125 * "ch_info()" function
2126 */
2127 static void
2128f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2129{
2130 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2131
2132 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2133 channel_info(channel, rettv->vval.v_dict);
2134}
2135
2136/*
2137 * "ch_log()" function
2138 */
2139 static void
2140f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2141{
2142 char_u *msg = get_tv_string(&argvars[0]);
2143 channel_T *channel = NULL;
2144
2145 if (argvars[1].v_type != VAR_UNKNOWN)
2146 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2147
Bram Moolenaard5359b22018-04-05 22:44:39 +02002148 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002149}
2150
2151/*
2152 * "ch_logfile()" function
2153 */
2154 static void
2155f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2156{
2157 char_u *fname;
2158 char_u *opt = (char_u *)"";
2159 char_u buf[NUMBUFLEN];
2160
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002161 /* Don't open a file in restricted mode. */
2162 if (check_restricted() || check_secure())
2163 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 fname = get_tv_string(&argvars[0]);
2165 if (argvars[1].v_type == VAR_STRING)
2166 opt = get_tv_string_buf(&argvars[1], buf);
2167 ch_logfile(fname, opt);
2168}
2169
2170/*
2171 * "ch_open()" function
2172 */
2173 static void
2174f_ch_open(typval_T *argvars, typval_T *rettv)
2175{
2176 rettv->v_type = VAR_CHANNEL;
2177 if (check_restricted() || check_secure())
2178 return;
2179 rettv->vval.v_channel = channel_open_func(argvars);
2180}
2181
2182/*
2183 * "ch_read()" function
2184 */
2185 static void
2186f_ch_read(typval_T *argvars, typval_T *rettv)
2187{
2188 common_channel_read(argvars, rettv, FALSE);
2189}
2190
2191/*
2192 * "ch_readraw()" function
2193 */
2194 static void
2195f_ch_readraw(typval_T *argvars, typval_T *rettv)
2196{
2197 common_channel_read(argvars, rettv, TRUE);
2198}
2199
2200/*
2201 * "ch_evalexpr()" function
2202 */
2203 static void
2204f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2205{
2206 ch_expr_common(argvars, rettv, TRUE);
2207}
2208
2209/*
2210 * "ch_sendexpr()" function
2211 */
2212 static void
2213f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2214{
2215 ch_expr_common(argvars, rettv, FALSE);
2216}
2217
2218/*
2219 * "ch_evalraw()" function
2220 */
2221 static void
2222f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2223{
2224 ch_raw_common(argvars, rettv, TRUE);
2225}
2226
2227/*
2228 * "ch_sendraw()" function
2229 */
2230 static void
2231f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2232{
2233 ch_raw_common(argvars, rettv, FALSE);
2234}
2235
2236/*
2237 * "ch_setoptions()" function
2238 */
2239 static void
2240f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2241{
2242 channel_T *channel;
2243 jobopt_T opt;
2244
2245 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2246 if (channel == NULL)
2247 return;
2248 clear_job_options(&opt);
2249 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002250 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002251 channel_set_options(channel, &opt);
2252 free_job_options(&opt);
2253}
2254
2255/*
2256 * "ch_status()" function
2257 */
2258 static void
2259f_ch_status(typval_T *argvars, typval_T *rettv)
2260{
2261 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002262 jobopt_T opt;
2263 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002264
2265 /* return an empty string by default */
2266 rettv->v_type = VAR_STRING;
2267 rettv->vval.v_string = NULL;
2268
2269 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002270
2271 if (argvars[1].v_type != VAR_UNKNOWN)
2272 {
2273 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002274 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002275 && (opt.jo_set & JO_PART))
2276 part = opt.jo_part;
2277 }
2278
2279 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280}
2281#endif
2282
2283/*
2284 * "changenr()" function
2285 */
2286 static void
2287f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2288{
2289 rettv->vval.v_number = curbuf->b_u_seq_cur;
2290}
2291
2292/*
2293 * "char2nr(string)" function
2294 */
2295 static void
2296f_char2nr(typval_T *argvars, typval_T *rettv)
2297{
2298#ifdef FEAT_MBYTE
2299 if (has_mbyte)
2300 {
2301 int utf8 = 0;
2302
2303 if (argvars[1].v_type != VAR_UNKNOWN)
2304 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2305
2306 if (utf8)
2307 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2308 else
2309 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2310 }
2311 else
2312#endif
2313 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2314}
2315
2316/*
2317 * "cindent(lnum)" function
2318 */
2319 static void
2320f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2321{
2322#ifdef FEAT_CINDENT
2323 pos_T pos;
2324 linenr_T lnum;
2325
2326 pos = curwin->w_cursor;
2327 lnum = get_tv_lnum(argvars);
2328 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2329 {
2330 curwin->w_cursor.lnum = lnum;
2331 rettv->vval.v_number = get_c_indent();
2332 curwin->w_cursor = pos;
2333 }
2334 else
2335#endif
2336 rettv->vval.v_number = -1;
2337}
2338
2339/*
2340 * "clearmatches()" function
2341 */
2342 static void
2343f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2344{
2345#ifdef FEAT_SEARCH_EXTRA
2346 clear_matches(curwin);
2347#endif
2348}
2349
2350/*
2351 * "col(string)" function
2352 */
2353 static void
2354f_col(typval_T *argvars, typval_T *rettv)
2355{
2356 colnr_T col = 0;
2357 pos_T *fp;
2358 int fnum = curbuf->b_fnum;
2359
2360 fp = var2fpos(&argvars[0], FALSE, &fnum);
2361 if (fp != NULL && fnum == curbuf->b_fnum)
2362 {
2363 if (fp->col == MAXCOL)
2364 {
2365 /* '> can be MAXCOL, get the length of the line then */
2366 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2367 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2368 else
2369 col = MAXCOL;
2370 }
2371 else
2372 {
2373 col = fp->col + 1;
2374#ifdef FEAT_VIRTUALEDIT
2375 /* col(".") when the cursor is on the NUL at the end of the line
2376 * because of "coladd" can be seen as an extra column. */
2377 if (virtual_active() && fp == &curwin->w_cursor)
2378 {
2379 char_u *p = ml_get_cursor();
2380
2381 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2382 curwin->w_virtcol - curwin->w_cursor.coladd))
2383 {
2384# ifdef FEAT_MBYTE
2385 int l;
2386
2387 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2388 col += l;
2389# else
2390 if (*p != NUL && p[1] == NUL)
2391 ++col;
2392# endif
2393 }
2394 }
2395#endif
2396 }
2397 }
2398 rettv->vval.v_number = col;
2399}
2400
2401#if defined(FEAT_INS_EXPAND)
2402/*
2403 * "complete()" function
2404 */
2405 static void
2406f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2407{
2408 int startcol;
2409
2410 if ((State & INSERT) == 0)
2411 {
2412 EMSG(_("E785: complete() can only be used in Insert mode"));
2413 return;
2414 }
2415
2416 /* Check for undo allowed here, because if something was already inserted
2417 * the line was already saved for undo and this check isn't done. */
2418 if (!undo_allowed())
2419 return;
2420
2421 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2422 {
2423 EMSG(_(e_invarg));
2424 return;
2425 }
2426
2427 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2428 if (startcol <= 0)
2429 return;
2430
2431 set_completion(startcol - 1, argvars[1].vval.v_list);
2432}
2433
2434/*
2435 * "complete_add()" function
2436 */
2437 static void
2438f_complete_add(typval_T *argvars, typval_T *rettv)
2439{
2440 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2441}
2442
2443/*
2444 * "complete_check()" function
2445 */
2446 static void
2447f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2448{
2449 int saved = RedrawingDisabled;
2450
2451 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002452 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002453 rettv->vval.v_number = compl_interrupted;
2454 RedrawingDisabled = saved;
2455}
2456#endif
2457
2458/*
2459 * "confirm(message, buttons[, default [, type]])" function
2460 */
2461 static void
2462f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2463{
2464#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2465 char_u *message;
2466 char_u *buttons = NULL;
2467 char_u buf[NUMBUFLEN];
2468 char_u buf2[NUMBUFLEN];
2469 int def = 1;
2470 int type = VIM_GENERIC;
2471 char_u *typestr;
2472 int error = FALSE;
2473
2474 message = get_tv_string_chk(&argvars[0]);
2475 if (message == NULL)
2476 error = TRUE;
2477 if (argvars[1].v_type != VAR_UNKNOWN)
2478 {
2479 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2480 if (buttons == NULL)
2481 error = TRUE;
2482 if (argvars[2].v_type != VAR_UNKNOWN)
2483 {
2484 def = (int)get_tv_number_chk(&argvars[2], &error);
2485 if (argvars[3].v_type != VAR_UNKNOWN)
2486 {
2487 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2488 if (typestr == NULL)
2489 error = TRUE;
2490 else
2491 {
2492 switch (TOUPPER_ASC(*typestr))
2493 {
2494 case 'E': type = VIM_ERROR; break;
2495 case 'Q': type = VIM_QUESTION; break;
2496 case 'I': type = VIM_INFO; break;
2497 case 'W': type = VIM_WARNING; break;
2498 case 'G': type = VIM_GENERIC; break;
2499 }
2500 }
2501 }
2502 }
2503 }
2504
2505 if (buttons == NULL || *buttons == NUL)
2506 buttons = (char_u *)_("&Ok");
2507
2508 if (!error)
2509 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2510 def, NULL, FALSE);
2511#endif
2512}
2513
2514/*
2515 * "copy()" function
2516 */
2517 static void
2518f_copy(typval_T *argvars, typval_T *rettv)
2519{
2520 item_copy(&argvars[0], rettv, FALSE, 0);
2521}
2522
2523#ifdef FEAT_FLOAT
2524/*
2525 * "cos()" function
2526 */
2527 static void
2528f_cos(typval_T *argvars, typval_T *rettv)
2529{
2530 float_T f = 0.0;
2531
2532 rettv->v_type = VAR_FLOAT;
2533 if (get_float_arg(argvars, &f) == OK)
2534 rettv->vval.v_float = cos(f);
2535 else
2536 rettv->vval.v_float = 0.0;
2537}
2538
2539/*
2540 * "cosh()" function
2541 */
2542 static void
2543f_cosh(typval_T *argvars, typval_T *rettv)
2544{
2545 float_T f = 0.0;
2546
2547 rettv->v_type = VAR_FLOAT;
2548 if (get_float_arg(argvars, &f) == OK)
2549 rettv->vval.v_float = cosh(f);
2550 else
2551 rettv->vval.v_float = 0.0;
2552}
2553#endif
2554
2555/*
2556 * "count()" function
2557 */
2558 static void
2559f_count(typval_T *argvars, typval_T *rettv)
2560{
2561 long n = 0;
2562 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002563 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002564
Bram Moolenaar9966b212017-07-28 16:46:57 +02002565 if (argvars[2].v_type != VAR_UNKNOWN)
2566 ic = (int)get_tv_number_chk(&argvars[2], &error);
2567
2568 if (argvars[0].v_type == VAR_STRING)
2569 {
2570 char_u *expr = get_tv_string_chk(&argvars[1]);
2571 char_u *p = argvars[0].vval.v_string;
2572 char_u *next;
2573
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002574 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002575 {
2576 if (ic)
2577 {
2578 size_t len = STRLEN(expr);
2579
2580 while (*p != NUL)
2581 {
2582 if (MB_STRNICMP(p, expr, len) == 0)
2583 {
2584 ++n;
2585 p += len;
2586 }
2587 else
2588 MB_PTR_ADV(p);
2589 }
2590 }
2591 else
2592 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2593 != NULL)
2594 {
2595 ++n;
2596 p = next + STRLEN(expr);
2597 }
2598 }
2599
2600 }
2601 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 {
2603 listitem_T *li;
2604 list_T *l;
2605 long idx;
2606
2607 if ((l = argvars[0].vval.v_list) != NULL)
2608 {
2609 li = l->lv_first;
2610 if (argvars[2].v_type != VAR_UNKNOWN)
2611 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002612 if (argvars[3].v_type != VAR_UNKNOWN)
2613 {
2614 idx = (long)get_tv_number_chk(&argvars[3], &error);
2615 if (!error)
2616 {
2617 li = list_find(l, idx);
2618 if (li == NULL)
2619 EMSGN(_(e_listidx), idx);
2620 }
2621 }
2622 if (error)
2623 li = NULL;
2624 }
2625
2626 for ( ; li != NULL; li = li->li_next)
2627 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2628 ++n;
2629 }
2630 }
2631 else if (argvars[0].v_type == VAR_DICT)
2632 {
2633 int todo;
2634 dict_T *d;
2635 hashitem_T *hi;
2636
2637 if ((d = argvars[0].vval.v_dict) != NULL)
2638 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002639 if (argvars[2].v_type != VAR_UNKNOWN)
2640 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002641 if (argvars[3].v_type != VAR_UNKNOWN)
2642 EMSG(_(e_invarg));
2643 }
2644
2645 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2646 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2647 {
2648 if (!HASHITEM_EMPTY(hi))
2649 {
2650 --todo;
2651 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2652 ++n;
2653 }
2654 }
2655 }
2656 }
2657 else
2658 EMSG2(_(e_listdictarg), "count()");
2659 rettv->vval.v_number = n;
2660}
2661
2662/*
2663 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2664 *
2665 * Checks the existence of a cscope connection.
2666 */
2667 static void
2668f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2669{
2670#ifdef FEAT_CSCOPE
2671 int num = 0;
2672 char_u *dbpath = NULL;
2673 char_u *prepend = NULL;
2674 char_u buf[NUMBUFLEN];
2675
2676 if (argvars[0].v_type != VAR_UNKNOWN
2677 && argvars[1].v_type != VAR_UNKNOWN)
2678 {
2679 num = (int)get_tv_number(&argvars[0]);
2680 dbpath = get_tv_string(&argvars[1]);
2681 if (argvars[2].v_type != VAR_UNKNOWN)
2682 prepend = get_tv_string_buf(&argvars[2], buf);
2683 }
2684
2685 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2686#endif
2687}
2688
2689/*
2690 * "cursor(lnum, col)" function, or
2691 * "cursor(list)"
2692 *
2693 * Moves the cursor to the specified line and column.
2694 * Returns 0 when the position could be set, -1 otherwise.
2695 */
2696 static void
2697f_cursor(typval_T *argvars, typval_T *rettv)
2698{
2699 long line, col;
2700#ifdef FEAT_VIRTUALEDIT
2701 long coladd = 0;
2702#endif
2703 int set_curswant = TRUE;
2704
2705 rettv->vval.v_number = -1;
2706 if (argvars[1].v_type == VAR_UNKNOWN)
2707 {
2708 pos_T pos;
2709 colnr_T curswant = -1;
2710
2711 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2712 {
2713 EMSG(_(e_invarg));
2714 return;
2715 }
2716 line = pos.lnum;
2717 col = pos.col;
2718#ifdef FEAT_VIRTUALEDIT
2719 coladd = pos.coladd;
2720#endif
2721 if (curswant >= 0)
2722 {
2723 curwin->w_curswant = curswant - 1;
2724 set_curswant = FALSE;
2725 }
2726 }
2727 else
2728 {
2729 line = get_tv_lnum(argvars);
2730 col = (long)get_tv_number_chk(&argvars[1], NULL);
2731#ifdef FEAT_VIRTUALEDIT
2732 if (argvars[2].v_type != VAR_UNKNOWN)
2733 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2734#endif
2735 }
2736 if (line < 0 || col < 0
2737#ifdef FEAT_VIRTUALEDIT
2738 || coladd < 0
2739#endif
2740 )
2741 return; /* type error; errmsg already given */
2742 if (line > 0)
2743 curwin->w_cursor.lnum = line;
2744 if (col > 0)
2745 curwin->w_cursor.col = col - 1;
2746#ifdef FEAT_VIRTUALEDIT
2747 curwin->w_cursor.coladd = coladd;
2748#endif
2749
2750 /* Make sure the cursor is in a valid position. */
2751 check_cursor();
2752#ifdef FEAT_MBYTE
2753 /* Correct cursor for multi-byte character. */
2754 if (has_mbyte)
2755 mb_adjust_cursor();
2756#endif
2757
2758 curwin->w_set_curswant = set_curswant;
2759 rettv->vval.v_number = 0;
2760}
2761
2762/*
2763 * "deepcopy()" function
2764 */
2765 static void
2766f_deepcopy(typval_T *argvars, typval_T *rettv)
2767{
2768 int noref = 0;
2769 int copyID;
2770
2771 if (argvars[1].v_type != VAR_UNKNOWN)
2772 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2773 if (noref < 0 || noref > 1)
2774 EMSG(_(e_invarg));
2775 else
2776 {
2777 copyID = get_copyID();
2778 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2779 }
2780}
2781
2782/*
2783 * "delete()" function
2784 */
2785 static void
2786f_delete(typval_T *argvars, typval_T *rettv)
2787{
2788 char_u nbuf[NUMBUFLEN];
2789 char_u *name;
2790 char_u *flags;
2791
2792 rettv->vval.v_number = -1;
2793 if (check_restricted() || check_secure())
2794 return;
2795
2796 name = get_tv_string(&argvars[0]);
2797 if (name == NULL || *name == NUL)
2798 {
2799 EMSG(_(e_invarg));
2800 return;
2801 }
2802
2803 if (argvars[1].v_type != VAR_UNKNOWN)
2804 flags = get_tv_string_buf(&argvars[1], nbuf);
2805 else
2806 flags = (char_u *)"";
2807
2808 if (*flags == NUL)
2809 /* delete a file */
2810 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2811 else if (STRCMP(flags, "d") == 0)
2812 /* delete an empty directory */
2813 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2814 else if (STRCMP(flags, "rf") == 0)
2815 /* delete a directory recursively */
2816 rettv->vval.v_number = delete_recursive(name);
2817 else
2818 EMSG2(_(e_invexpr2), flags);
2819}
2820
2821/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002822 * "deletebufline()" function
2823 */
2824 static void
2825f_deletebufline(argvars, rettv)
2826 typval_T *argvars;
2827 typval_T *rettv;
2828{
2829 buf_T *buf;
2830 linenr_T first, last;
2831 linenr_T lnum;
2832 long count;
2833 int is_curbuf;
2834 buf_T *curbuf_save = NULL;
2835 win_T *curwin_save = NULL;
2836 tabpage_T *tp;
2837 win_T *wp;
2838
2839 buf = get_buf_tv(&argvars[0], FALSE);
2840 if (buf == NULL)
2841 {
2842 rettv->vval.v_number = 1; /* FAIL */
2843 return;
2844 }
2845 is_curbuf = buf == curbuf;
2846
2847 first = get_tv_lnum_buf(&argvars[1], buf);
2848 if (argvars[2].v_type != VAR_UNKNOWN)
2849 last = get_tv_lnum_buf(&argvars[2], buf);
2850 else
2851 last = first;
2852
2853 if (buf->b_ml.ml_mfp == NULL || first < 1
2854 || first > buf->b_ml.ml_line_count || last < first)
2855 {
2856 rettv->vval.v_number = 1; /* FAIL */
2857 return;
2858 }
2859
2860 if (!is_curbuf)
2861 {
2862 curbuf_save = curbuf;
2863 curwin_save = curwin;
2864 curbuf = buf;
2865 find_win_for_curbuf();
2866 }
2867 if (last > curbuf->b_ml.ml_line_count)
2868 last = curbuf->b_ml.ml_line_count;
2869 count = last - first + 1;
2870
2871 // When coming here from Insert mode, sync undo, so that this can be
2872 // undone separately from what was previously inserted.
2873 if (u_sync_once == 2)
2874 {
2875 u_sync_once = 1; // notify that u_sync() was called
2876 u_sync(TRUE);
2877 }
2878
2879 if (u_save(first - 1, last + 1) == FAIL)
2880 {
2881 rettv->vval.v_number = 1; /* FAIL */
2882 return;
2883 }
2884
2885 for (lnum = first; lnum <= last; ++lnum)
2886 ml_delete(first, TRUE);
2887
2888 FOR_ALL_TAB_WINDOWS(tp, wp)
2889 if (wp->w_buffer == buf)
2890 {
2891 if (wp->w_cursor.lnum > last)
2892 wp->w_cursor.lnum -= count;
2893 else if (wp->w_cursor.lnum> first)
2894 wp->w_cursor.lnum = first;
2895 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2896 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2897 }
2898 check_cursor_col();
2899 deleted_lines_mark(first, count);
2900
2901 if (!is_curbuf)
2902 {
2903 curbuf = curbuf_save;
2904 curwin = curwin_save;
2905 }
2906}
2907
2908/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002909 * "did_filetype()" function
2910 */
2911 static void
2912f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2913{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002914 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002915}
2916
2917/*
2918 * "diff_filler()" function
2919 */
2920 static void
2921f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2922{
2923#ifdef FEAT_DIFF
2924 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2925#endif
2926}
2927
2928/*
2929 * "diff_hlID()" function
2930 */
2931 static void
2932f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2933{
2934#ifdef FEAT_DIFF
2935 linenr_T lnum = get_tv_lnum(argvars);
2936 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002937 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002938 static int fnum = 0;
2939 static int change_start = 0;
2940 static int change_end = 0;
2941 static hlf_T hlID = (hlf_T)0;
2942 int filler_lines;
2943 int col;
2944
2945 if (lnum < 0) /* ignore type error in {lnum} arg */
2946 lnum = 0;
2947 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002948 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002949 || fnum != curbuf->b_fnum)
2950 {
2951 /* New line, buffer, change: need to get the values. */
2952 filler_lines = diff_check(curwin, lnum);
2953 if (filler_lines < 0)
2954 {
2955 if (filler_lines == -1)
2956 {
2957 change_start = MAXCOL;
2958 change_end = -1;
2959 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2960 hlID = HLF_ADD; /* added line */
2961 else
2962 hlID = HLF_CHD; /* changed line */
2963 }
2964 else
2965 hlID = HLF_ADD; /* added line */
2966 }
2967 else
2968 hlID = (hlf_T)0;
2969 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002970 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002971 fnum = curbuf->b_fnum;
2972 }
2973
2974 if (hlID == HLF_CHD || hlID == HLF_TXD)
2975 {
2976 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2977 if (col >= change_start && col <= change_end)
2978 hlID = HLF_TXD; /* changed text */
2979 else
2980 hlID = HLF_CHD; /* changed line */
2981 }
2982 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2983#endif
2984}
2985
2986/*
2987 * "empty({expr})" function
2988 */
2989 static void
2990f_empty(typval_T *argvars, typval_T *rettv)
2991{
2992 int n = FALSE;
2993
2994 switch (argvars[0].v_type)
2995 {
2996 case VAR_STRING:
2997 case VAR_FUNC:
2998 n = argvars[0].vval.v_string == NULL
2999 || *argvars[0].vval.v_string == NUL;
3000 break;
3001 case VAR_PARTIAL:
3002 n = FALSE;
3003 break;
3004 case VAR_NUMBER:
3005 n = argvars[0].vval.v_number == 0;
3006 break;
3007 case VAR_FLOAT:
3008#ifdef FEAT_FLOAT
3009 n = argvars[0].vval.v_float == 0.0;
3010 break;
3011#endif
3012 case VAR_LIST:
3013 n = argvars[0].vval.v_list == NULL
3014 || argvars[0].vval.v_list->lv_first == NULL;
3015 break;
3016 case VAR_DICT:
3017 n = argvars[0].vval.v_dict == NULL
3018 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3019 break;
3020 case VAR_SPECIAL:
3021 n = argvars[0].vval.v_number != VVAL_TRUE;
3022 break;
3023
3024 case VAR_JOB:
3025#ifdef FEAT_JOB_CHANNEL
3026 n = argvars[0].vval.v_job == NULL
3027 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3028 break;
3029#endif
3030 case VAR_CHANNEL:
3031#ifdef FEAT_JOB_CHANNEL
3032 n = argvars[0].vval.v_channel == NULL
3033 || !channel_is_open(argvars[0].vval.v_channel);
3034 break;
3035#endif
3036 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003037 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038 n = TRUE;
3039 break;
3040 }
3041
3042 rettv->vval.v_number = n;
3043}
3044
3045/*
3046 * "escape({string}, {chars})" function
3047 */
3048 static void
3049f_escape(typval_T *argvars, typval_T *rettv)
3050{
3051 char_u buf[NUMBUFLEN];
3052
3053 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
3054 get_tv_string_buf(&argvars[1], buf));
3055 rettv->v_type = VAR_STRING;
3056}
3057
3058/*
3059 * "eval()" function
3060 */
3061 static void
3062f_eval(typval_T *argvars, typval_T *rettv)
3063{
3064 char_u *s, *p;
3065
3066 s = get_tv_string_chk(&argvars[0]);
3067 if (s != NULL)
3068 s = skipwhite(s);
3069
3070 p = s;
3071 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3072 {
3073 if (p != NULL && !aborting())
3074 EMSG2(_(e_invexpr2), p);
3075 need_clr_eos = FALSE;
3076 rettv->v_type = VAR_NUMBER;
3077 rettv->vval.v_number = 0;
3078 }
3079 else if (*s != NUL)
3080 EMSG(_(e_trailing));
3081}
3082
3083/*
3084 * "eventhandler()" function
3085 */
3086 static void
3087f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3088{
3089 rettv->vval.v_number = vgetc_busy;
3090}
3091
3092/*
3093 * "executable()" function
3094 */
3095 static void
3096f_executable(typval_T *argvars, typval_T *rettv)
3097{
3098 char_u *name = get_tv_string(&argvars[0]);
3099
3100 /* Check in $PATH and also check directly if there is a directory name. */
3101 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3102 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3103}
3104
3105static garray_T redir_execute_ga;
3106
3107/*
3108 * Append "value[value_len]" to the execute() output.
3109 */
3110 void
3111execute_redir_str(char_u *value, int value_len)
3112{
3113 int len;
3114
3115 if (value_len == -1)
3116 len = (int)STRLEN(value); /* Append the entire string */
3117 else
3118 len = value_len; /* Append only "value_len" characters */
3119 if (ga_grow(&redir_execute_ga, len) == OK)
3120 {
3121 mch_memmove((char *)redir_execute_ga.ga_data
3122 + redir_execute_ga.ga_len, value, len);
3123 redir_execute_ga.ga_len += len;
3124 }
3125}
3126
3127/*
3128 * Get next line from a list.
3129 * Called by do_cmdline() to get the next line.
3130 * Returns allocated string, or NULL for end of function.
3131 */
3132
3133 static char_u *
3134get_list_line(
3135 int c UNUSED,
3136 void *cookie,
3137 int indent UNUSED)
3138{
3139 listitem_T **p = (listitem_T **)cookie;
3140 listitem_T *item = *p;
3141 char_u buf[NUMBUFLEN];
3142 char_u *s;
3143
3144 if (item == NULL)
3145 return NULL;
3146 s = get_tv_string_buf_chk(&item->li_tv, buf);
3147 *p = item->li_next;
3148 return s == NULL ? NULL : vim_strsave(s);
3149}
3150
3151/*
3152 * "execute()" function
3153 */
3154 static void
3155f_execute(typval_T *argvars, typval_T *rettv)
3156{
3157 char_u *cmd = NULL;
3158 list_T *list = NULL;
3159 int save_msg_silent = msg_silent;
3160 int save_emsg_silent = emsg_silent;
3161 int save_emsg_noredir = emsg_noredir;
3162 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003163 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003164 garray_T save_ga;
3165
3166 rettv->vval.v_string = NULL;
3167 rettv->v_type = VAR_STRING;
3168
3169 if (argvars[0].v_type == VAR_LIST)
3170 {
3171 list = argvars[0].vval.v_list;
3172 if (list == NULL || list->lv_first == NULL)
3173 /* empty list, no commands, empty output */
3174 return;
3175 ++list->lv_refcount;
3176 }
3177 else
3178 {
3179 cmd = get_tv_string_chk(&argvars[0]);
3180 if (cmd == NULL)
3181 return;
3182 }
3183
3184 if (argvars[1].v_type != VAR_UNKNOWN)
3185 {
3186 char_u buf[NUMBUFLEN];
3187 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
3188
3189 if (s == NULL)
3190 return;
3191 if (STRNCMP(s, "silent", 6) == 0)
3192 ++msg_silent;
3193 if (STRCMP(s, "silent!") == 0)
3194 {
3195 emsg_silent = TRUE;
3196 emsg_noredir = TRUE;
3197 }
3198 }
3199 else
3200 ++msg_silent;
3201
3202 if (redir_execute)
3203 save_ga = redir_execute_ga;
3204 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3205 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003206 redir_off = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003207
3208 if (cmd != NULL)
3209 do_cmdline_cmd(cmd);
3210 else
3211 {
3212 listitem_T *item = list->lv_first;
3213
3214 do_cmdline(NULL, get_list_line, (void *)&item,
3215 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3216 --list->lv_refcount;
3217 }
3218
Bram Moolenaard297f352017-01-29 20:31:21 +01003219 /* Need to append a NUL to the result. */
3220 if (ga_grow(&redir_execute_ga, 1) == OK)
3221 {
3222 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3223 rettv->vval.v_string = redir_execute_ga.ga_data;
3224 }
3225 else
3226 {
3227 ga_clear(&redir_execute_ga);
3228 rettv->vval.v_string = NULL;
3229 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230 msg_silent = save_msg_silent;
3231 emsg_silent = save_emsg_silent;
3232 emsg_noredir = save_emsg_noredir;
3233
3234 redir_execute = save_redir_execute;
3235 if (redir_execute)
3236 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003237 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238
3239 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
3240 * line. Put it back in the first column. */
3241 msg_col = 0;
3242}
3243
3244/*
3245 * "exepath()" function
3246 */
3247 static void
3248f_exepath(typval_T *argvars, typval_T *rettv)
3249{
3250 char_u *p = NULL;
3251
3252 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
3253 rettv->v_type = VAR_STRING;
3254 rettv->vval.v_string = p;
3255}
3256
3257/*
3258 * "exists()" function
3259 */
3260 static void
3261f_exists(typval_T *argvars, typval_T *rettv)
3262{
3263 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003264 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003265
3266 p = get_tv_string(&argvars[0]);
3267 if (*p == '$') /* environment variable */
3268 {
3269 /* first try "normal" environment variables (fast) */
3270 if (mch_getenv(p + 1) != NULL)
3271 n = TRUE;
3272 else
3273 {
3274 /* try expanding things like $VIM and ${HOME} */
3275 p = expand_env_save(p);
3276 if (p != NULL && *p != '$')
3277 n = TRUE;
3278 vim_free(p);
3279 }
3280 }
3281 else if (*p == '&' || *p == '+') /* option */
3282 {
3283 n = (get_option_tv(&p, NULL, TRUE) == OK);
3284 if (*skipwhite(p) != NUL)
3285 n = FALSE; /* trailing garbage */
3286 }
3287 else if (*p == '*') /* internal or user defined function */
3288 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003289 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003290 }
3291 else if (*p == ':')
3292 {
3293 n = cmd_exists(p + 1);
3294 }
3295 else if (*p == '#')
3296 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 if (p[1] == '#')
3298 n = autocmd_supported(p + 2);
3299 else
3300 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301 }
3302 else /* internal variable */
3303 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003304 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003305 }
3306
3307 rettv->vval.v_number = n;
3308}
3309
3310#ifdef FEAT_FLOAT
3311/*
3312 * "exp()" function
3313 */
3314 static void
3315f_exp(typval_T *argvars, typval_T *rettv)
3316{
3317 float_T f = 0.0;
3318
3319 rettv->v_type = VAR_FLOAT;
3320 if (get_float_arg(argvars, &f) == OK)
3321 rettv->vval.v_float = exp(f);
3322 else
3323 rettv->vval.v_float = 0.0;
3324}
3325#endif
3326
3327/*
3328 * "expand()" function
3329 */
3330 static void
3331f_expand(typval_T *argvars, typval_T *rettv)
3332{
3333 char_u *s;
3334 int len;
3335 char_u *errormsg;
3336 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3337 expand_T xpc;
3338 int error = FALSE;
3339 char_u *result;
3340
3341 rettv->v_type = VAR_STRING;
3342 if (argvars[1].v_type != VAR_UNKNOWN
3343 && argvars[2].v_type != VAR_UNKNOWN
3344 && get_tv_number_chk(&argvars[2], &error)
3345 && !error)
3346 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003347 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003348 }
3349
3350 s = get_tv_string(&argvars[0]);
3351 if (*s == '%' || *s == '#' || *s == '<')
3352 {
3353 ++emsg_off;
3354 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3355 --emsg_off;
3356 if (rettv->v_type == VAR_LIST)
3357 {
3358 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3359 list_append_string(rettv->vval.v_list, result, -1);
3360 else
3361 vim_free(result);
3362 }
3363 else
3364 rettv->vval.v_string = result;
3365 }
3366 else
3367 {
3368 /* When the optional second argument is non-zero, don't remove matches
3369 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3370 if (argvars[1].v_type != VAR_UNKNOWN
3371 && get_tv_number_chk(&argvars[1], &error))
3372 options |= WILD_KEEP_ALL;
3373 if (!error)
3374 {
3375 ExpandInit(&xpc);
3376 xpc.xp_context = EXPAND_FILES;
3377 if (p_wic)
3378 options += WILD_ICASE;
3379 if (rettv->v_type == VAR_STRING)
3380 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3381 options, WILD_ALL);
3382 else if (rettv_list_alloc(rettv) != FAIL)
3383 {
3384 int i;
3385
3386 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3387 for (i = 0; i < xpc.xp_numfiles; i++)
3388 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3389 ExpandCleanup(&xpc);
3390 }
3391 }
3392 else
3393 rettv->vval.v_string = NULL;
3394 }
3395}
3396
3397/*
3398 * "extend(list, list [, idx])" function
3399 * "extend(dict, dict [, action])" function
3400 */
3401 static void
3402f_extend(typval_T *argvars, typval_T *rettv)
3403{
3404 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3405
3406 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3407 {
3408 list_T *l1, *l2;
3409 listitem_T *item;
3410 long before;
3411 int error = FALSE;
3412
3413 l1 = argvars[0].vval.v_list;
3414 l2 = argvars[1].vval.v_list;
3415 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3416 && l2 != NULL)
3417 {
3418 if (argvars[2].v_type != VAR_UNKNOWN)
3419 {
3420 before = (long)get_tv_number_chk(&argvars[2], &error);
3421 if (error)
3422 return; /* type error; errmsg already given */
3423
3424 if (before == l1->lv_len)
3425 item = NULL;
3426 else
3427 {
3428 item = list_find(l1, before);
3429 if (item == NULL)
3430 {
3431 EMSGN(_(e_listidx), before);
3432 return;
3433 }
3434 }
3435 }
3436 else
3437 item = NULL;
3438 list_extend(l1, l2, item);
3439
3440 copy_tv(&argvars[0], rettv);
3441 }
3442 }
3443 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3444 {
3445 dict_T *d1, *d2;
3446 char_u *action;
3447 int i;
3448
3449 d1 = argvars[0].vval.v_dict;
3450 d2 = argvars[1].vval.v_dict;
3451 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3452 && d2 != NULL)
3453 {
3454 /* Check the third argument. */
3455 if (argvars[2].v_type != VAR_UNKNOWN)
3456 {
3457 static char *(av[]) = {"keep", "force", "error"};
3458
3459 action = get_tv_string_chk(&argvars[2]);
3460 if (action == NULL)
3461 return; /* type error; errmsg already given */
3462 for (i = 0; i < 3; ++i)
3463 if (STRCMP(action, av[i]) == 0)
3464 break;
3465 if (i == 3)
3466 {
3467 EMSG2(_(e_invarg2), action);
3468 return;
3469 }
3470 }
3471 else
3472 action = (char_u *)"force";
3473
3474 dict_extend(d1, d2, action);
3475
3476 copy_tv(&argvars[0], rettv);
3477 }
3478 }
3479 else
3480 EMSG2(_(e_listdictarg), "extend()");
3481}
3482
3483/*
3484 * "feedkeys()" function
3485 */
3486 static void
3487f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3488{
3489 int remap = TRUE;
3490 int insert = FALSE;
3491 char_u *keys, *flags;
3492 char_u nbuf[NUMBUFLEN];
3493 int typed = FALSE;
3494 int execute = FALSE;
3495 int dangerous = FALSE;
3496 char_u *keys_esc;
3497
3498 /* This is not allowed in the sandbox. If the commands would still be
3499 * executed in the sandbox it would be OK, but it probably happens later,
3500 * when "sandbox" is no longer set. */
3501 if (check_secure())
3502 return;
3503
3504 keys = get_tv_string(&argvars[0]);
3505
3506 if (argvars[1].v_type != VAR_UNKNOWN)
3507 {
3508 flags = get_tv_string_buf(&argvars[1], nbuf);
3509 for ( ; *flags != NUL; ++flags)
3510 {
3511 switch (*flags)
3512 {
3513 case 'n': remap = FALSE; break;
3514 case 'm': remap = TRUE; break;
3515 case 't': typed = TRUE; break;
3516 case 'i': insert = TRUE; break;
3517 case 'x': execute = TRUE; break;
3518 case '!': dangerous = TRUE; break;
3519 }
3520 }
3521 }
3522
3523 if (*keys != NUL || execute)
3524 {
3525 /* Need to escape K_SPECIAL and CSI before putting the string in the
3526 * typeahead buffer. */
3527 keys_esc = vim_strsave_escape_csi(keys);
3528 if (keys_esc != NULL)
3529 {
3530 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3531 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3532 vim_free(keys_esc);
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003533 if (vgetc_busy
3534#ifdef FEAT_TIMERS
3535 || timer_busy
3536#endif
3537 )
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003538 typebuf_was_filled = TRUE;
3539 if (execute)
3540 {
3541 int save_msg_scroll = msg_scroll;
3542
3543 /* Avoid a 1 second delay when the keys start Insert mode. */
3544 msg_scroll = FALSE;
3545
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003546 if (!dangerous)
3547 ++ex_normal_busy;
Bram Moolenaar655a82a2018-05-08 22:01:07 +02003548 exec_normal(TRUE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003549 if (!dangerous)
3550 --ex_normal_busy;
3551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003552 msg_scroll |= save_msg_scroll;
3553 }
3554 }
3555 }
3556}
3557
3558/*
3559 * "filereadable()" function
3560 */
3561 static void
3562f_filereadable(typval_T *argvars, typval_T *rettv)
3563{
3564 int fd;
3565 char_u *p;
3566 int n;
3567
3568#ifndef O_NONBLOCK
3569# define O_NONBLOCK 0
3570#endif
3571 p = get_tv_string(&argvars[0]);
3572 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3573 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3574 {
3575 n = TRUE;
3576 close(fd);
3577 }
3578 else
3579 n = FALSE;
3580
3581 rettv->vval.v_number = n;
3582}
3583
3584/*
3585 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3586 * rights to write into.
3587 */
3588 static void
3589f_filewritable(typval_T *argvars, typval_T *rettv)
3590{
3591 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3592}
3593
3594 static void
3595findfilendir(
3596 typval_T *argvars UNUSED,
3597 typval_T *rettv,
3598 int find_what UNUSED)
3599{
3600#ifdef FEAT_SEARCHPATH
3601 char_u *fname;
3602 char_u *fresult = NULL;
3603 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3604 char_u *p;
3605 char_u pathbuf[NUMBUFLEN];
3606 int count = 1;
3607 int first = TRUE;
3608 int error = FALSE;
3609#endif
3610
3611 rettv->vval.v_string = NULL;
3612 rettv->v_type = VAR_STRING;
3613
3614#ifdef FEAT_SEARCHPATH
3615 fname = get_tv_string(&argvars[0]);
3616
3617 if (argvars[1].v_type != VAR_UNKNOWN)
3618 {
3619 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3620 if (p == NULL)
3621 error = TRUE;
3622 else
3623 {
3624 if (*p != NUL)
3625 path = p;
3626
3627 if (argvars[2].v_type != VAR_UNKNOWN)
3628 count = (int)get_tv_number_chk(&argvars[2], &error);
3629 }
3630 }
3631
3632 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3633 error = TRUE;
3634
3635 if (*fname != NUL && !error)
3636 {
3637 do
3638 {
3639 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3640 vim_free(fresult);
3641 fresult = find_file_in_path_option(first ? fname : NULL,
3642 first ? (int)STRLEN(fname) : 0,
3643 0, first, path,
3644 find_what,
3645 curbuf->b_ffname,
3646 find_what == FINDFILE_DIR
3647 ? (char_u *)"" : curbuf->b_p_sua);
3648 first = FALSE;
3649
3650 if (fresult != NULL && rettv->v_type == VAR_LIST)
3651 list_append_string(rettv->vval.v_list, fresult, -1);
3652
3653 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3654 }
3655
3656 if (rettv->v_type == VAR_STRING)
3657 rettv->vval.v_string = fresult;
3658#endif
3659}
3660
3661/*
3662 * "filter()" function
3663 */
3664 static void
3665f_filter(typval_T *argvars, typval_T *rettv)
3666{
3667 filter_map(argvars, rettv, FALSE);
3668}
3669
3670/*
3671 * "finddir({fname}[, {path}[, {count}]])" function
3672 */
3673 static void
3674f_finddir(typval_T *argvars, typval_T *rettv)
3675{
3676 findfilendir(argvars, rettv, FINDFILE_DIR);
3677}
3678
3679/*
3680 * "findfile({fname}[, {path}[, {count}]])" function
3681 */
3682 static void
3683f_findfile(typval_T *argvars, typval_T *rettv)
3684{
3685 findfilendir(argvars, rettv, FINDFILE_FILE);
3686}
3687
3688#ifdef FEAT_FLOAT
3689/*
3690 * "float2nr({float})" function
3691 */
3692 static void
3693f_float2nr(typval_T *argvars, typval_T *rettv)
3694{
3695 float_T f = 0.0;
3696
3697 if (get_float_arg(argvars, &f) == OK)
3698 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003699 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003700 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003701 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003702 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003703 else
3704 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003705 }
3706}
3707
3708/*
3709 * "floor({float})" function
3710 */
3711 static void
3712f_floor(typval_T *argvars, typval_T *rettv)
3713{
3714 float_T f = 0.0;
3715
3716 rettv->v_type = VAR_FLOAT;
3717 if (get_float_arg(argvars, &f) == OK)
3718 rettv->vval.v_float = floor(f);
3719 else
3720 rettv->vval.v_float = 0.0;
3721}
3722
3723/*
3724 * "fmod()" function
3725 */
3726 static void
3727f_fmod(typval_T *argvars, typval_T *rettv)
3728{
3729 float_T fx = 0.0, fy = 0.0;
3730
3731 rettv->v_type = VAR_FLOAT;
3732 if (get_float_arg(argvars, &fx) == OK
3733 && get_float_arg(&argvars[1], &fy) == OK)
3734 rettv->vval.v_float = fmod(fx, fy);
3735 else
3736 rettv->vval.v_float = 0.0;
3737}
3738#endif
3739
3740/*
3741 * "fnameescape({string})" function
3742 */
3743 static void
3744f_fnameescape(typval_T *argvars, typval_T *rettv)
3745{
3746 rettv->vval.v_string = vim_strsave_fnameescape(
3747 get_tv_string(&argvars[0]), FALSE);
3748 rettv->v_type = VAR_STRING;
3749}
3750
3751/*
3752 * "fnamemodify({fname}, {mods})" function
3753 */
3754 static void
3755f_fnamemodify(typval_T *argvars, typval_T *rettv)
3756{
3757 char_u *fname;
3758 char_u *mods;
3759 int usedlen = 0;
3760 int len;
3761 char_u *fbuf = NULL;
3762 char_u buf[NUMBUFLEN];
3763
3764 fname = get_tv_string_chk(&argvars[0]);
3765 mods = get_tv_string_buf_chk(&argvars[1], buf);
3766 if (fname == NULL || mods == NULL)
3767 fname = NULL;
3768 else
3769 {
3770 len = (int)STRLEN(fname);
3771 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3772 }
3773
3774 rettv->v_type = VAR_STRING;
3775 if (fname == NULL)
3776 rettv->vval.v_string = NULL;
3777 else
3778 rettv->vval.v_string = vim_strnsave(fname, len);
3779 vim_free(fbuf);
3780}
3781
3782static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3783
3784/*
3785 * "foldclosed()" function
3786 */
3787 static void
3788foldclosed_both(
3789 typval_T *argvars UNUSED,
3790 typval_T *rettv,
3791 int end UNUSED)
3792{
3793#ifdef FEAT_FOLDING
3794 linenr_T lnum;
3795 linenr_T first, last;
3796
3797 lnum = get_tv_lnum(argvars);
3798 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3799 {
3800 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3801 {
3802 if (end)
3803 rettv->vval.v_number = (varnumber_T)last;
3804 else
3805 rettv->vval.v_number = (varnumber_T)first;
3806 return;
3807 }
3808 }
3809#endif
3810 rettv->vval.v_number = -1;
3811}
3812
3813/*
3814 * "foldclosed()" function
3815 */
3816 static void
3817f_foldclosed(typval_T *argvars, typval_T *rettv)
3818{
3819 foldclosed_both(argvars, rettv, FALSE);
3820}
3821
3822/*
3823 * "foldclosedend()" function
3824 */
3825 static void
3826f_foldclosedend(typval_T *argvars, typval_T *rettv)
3827{
3828 foldclosed_both(argvars, rettv, TRUE);
3829}
3830
3831/*
3832 * "foldlevel()" function
3833 */
3834 static void
3835f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3836{
3837#ifdef FEAT_FOLDING
3838 linenr_T lnum;
3839
3840 lnum = get_tv_lnum(argvars);
3841 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3842 rettv->vval.v_number = foldLevel(lnum);
3843#endif
3844}
3845
3846/*
3847 * "foldtext()" function
3848 */
3849 static void
3850f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3851{
3852#ifdef FEAT_FOLDING
3853 linenr_T foldstart;
3854 linenr_T foldend;
3855 char_u *dashes;
3856 linenr_T lnum;
3857 char_u *s;
3858 char_u *r;
3859 int len;
3860 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003861 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003862#endif
3863
3864 rettv->v_type = VAR_STRING;
3865 rettv->vval.v_string = NULL;
3866#ifdef FEAT_FOLDING
3867 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3868 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3869 dashes = get_vim_var_str(VV_FOLDDASHES);
3870 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3871 && dashes != NULL)
3872 {
3873 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003874 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003875 if (!linewhite(lnum))
3876 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003877
3878 /* Find interesting text in this line. */
3879 s = skipwhite(ml_get(lnum));
3880 /* skip C comment-start */
3881 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3882 {
3883 s = skipwhite(s + 2);
3884 if (*skipwhite(s) == NUL
3885 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3886 {
3887 s = skipwhite(ml_get(lnum + 1));
3888 if (*s == '*')
3889 s = skipwhite(s + 1);
3890 }
3891 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003892 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003893 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003894 r = alloc((unsigned)(STRLEN(txt)
3895 + STRLEN(dashes) /* for %s */
3896 + 20 /* for %3ld */
3897 + STRLEN(s))); /* concatenated */
3898 if (r != NULL)
3899 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003900 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003901 len = (int)STRLEN(r);
3902 STRCAT(r, s);
3903 /* remove 'foldmarker' and 'commentstring' */
3904 foldtext_cleanup(r + len);
3905 rettv->vval.v_string = r;
3906 }
3907 }
3908#endif
3909}
3910
3911/*
3912 * "foldtextresult(lnum)" function
3913 */
3914 static void
3915f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3916{
3917#ifdef FEAT_FOLDING
3918 linenr_T lnum;
3919 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003920 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 foldinfo_T foldinfo;
3922 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003923 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003924#endif
3925
3926 rettv->v_type = VAR_STRING;
3927 rettv->vval.v_string = NULL;
3928#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003929 if (entered)
3930 return; /* reject recursive use */
3931 entered = TRUE;
3932
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933 lnum = get_tv_lnum(argvars);
3934 /* treat illegal types and illegal string values for {lnum} the same */
3935 if (lnum < 0)
3936 lnum = 0;
3937 fold_count = foldedCount(curwin, lnum, &foldinfo);
3938 if (fold_count > 0)
3939 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003940 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3941 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942 if (text == buf)
3943 text = vim_strsave(text);
3944 rettv->vval.v_string = text;
3945 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003946
3947 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003948#endif
3949}
3950
3951/*
3952 * "foreground()" function
3953 */
3954 static void
3955f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3956{
3957#ifdef FEAT_GUI
3958 if (gui.in_use)
3959 gui_mch_set_foreground();
3960#else
3961# ifdef WIN32
3962 win32_set_foreground();
3963# endif
3964#endif
3965}
3966
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003967 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003968common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003969{
3970 char_u *s;
3971 char_u *name;
3972 int use_string = FALSE;
3973 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003974 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003975
3976 if (argvars[0].v_type == VAR_FUNC)
3977 {
3978 /* function(MyFunc, [arg], dict) */
3979 s = argvars[0].vval.v_string;
3980 }
3981 else if (argvars[0].v_type == VAR_PARTIAL
3982 && argvars[0].vval.v_partial != NULL)
3983 {
3984 /* function(dict.MyFunc, [arg]) */
3985 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003986 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987 }
3988 else
3989 {
3990 /* function('MyFunc', [arg], dict) */
3991 s = get_tv_string(&argvars[0]);
3992 use_string = TRUE;
3993 }
3994
Bram Moolenaar843b8842016-08-21 14:36:15 +02003995 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003996 {
3997 name = s;
3998 trans_name = trans_function_name(&name, FALSE,
3999 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4000 if (*name != NUL)
4001 s = NULL;
4002 }
4003
Bram Moolenaar843b8842016-08-21 14:36:15 +02004004 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4005 || (is_funcref && trans_name == NULL))
Bram Moolenaar5582ef12016-09-14 22:16:13 +02004006 EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004008 else if (trans_name != NULL && (is_funcref
4009 ? find_func(trans_name) == NULL
4010 : !translated_function_exists(trans_name)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004011 EMSG2(_("E700: Unknown function: %s"), s);
4012 else
4013 {
4014 int dict_idx = 0;
4015 int arg_idx = 0;
4016 list_T *list = NULL;
4017
4018 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4019 {
4020 char sid_buf[25];
4021 int off = *s == 's' ? 2 : 5;
4022
4023 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4024 * also be called from another script. Using trans_function_name()
4025 * would also work, but some plugins depend on the name being
4026 * printable text. */
4027 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
4028 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4029 if (name != NULL)
4030 {
4031 STRCPY(name, sid_buf);
4032 STRCAT(name, s + off);
4033 }
4034 }
4035 else
4036 name = vim_strsave(s);
4037
4038 if (argvars[1].v_type != VAR_UNKNOWN)
4039 {
4040 if (argvars[2].v_type != VAR_UNKNOWN)
4041 {
4042 /* function(name, [args], dict) */
4043 arg_idx = 1;
4044 dict_idx = 2;
4045 }
4046 else if (argvars[1].v_type == VAR_DICT)
4047 /* function(name, dict) */
4048 dict_idx = 1;
4049 else
4050 /* function(name, [args]) */
4051 arg_idx = 1;
4052 if (dict_idx > 0)
4053 {
4054 if (argvars[dict_idx].v_type != VAR_DICT)
4055 {
4056 EMSG(_("E922: expected a dict"));
4057 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004058 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004059 }
4060 if (argvars[dict_idx].vval.v_dict == NULL)
4061 dict_idx = 0;
4062 }
4063 if (arg_idx > 0)
4064 {
4065 if (argvars[arg_idx].v_type != VAR_LIST)
4066 {
4067 EMSG(_("E923: Second argument of function() must be a list or a dict"));
4068 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004069 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 }
4071 list = argvars[arg_idx].vval.v_list;
4072 if (list == NULL || list->lv_len == 0)
4073 arg_idx = 0;
4074 }
4075 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004076 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004077 {
4078 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4079
4080 /* result is a VAR_PARTIAL */
4081 if (pt == NULL)
4082 vim_free(name);
4083 else
4084 {
4085 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4086 {
4087 listitem_T *li;
4088 int i = 0;
4089 int arg_len = 0;
4090 int lv_len = 0;
4091
4092 if (arg_pt != NULL)
4093 arg_len = arg_pt->pt_argc;
4094 if (list != NULL)
4095 lv_len = list->lv_len;
4096 pt->pt_argc = arg_len + lv_len;
4097 pt->pt_argv = (typval_T *)alloc(
4098 sizeof(typval_T) * pt->pt_argc);
4099 if (pt->pt_argv == NULL)
4100 {
4101 vim_free(pt);
4102 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004103 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004104 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004105 for (i = 0; i < arg_len; i++)
4106 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4107 if (lv_len > 0)
4108 for (li = list->lv_first; li != NULL;
4109 li = li->li_next)
4110 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004111 }
4112
4113 /* For "function(dict.func, [], dict)" and "func" is a partial
4114 * use "dict". That is backwards compatible. */
4115 if (dict_idx > 0)
4116 {
4117 /* The dict is bound explicitly, pt_auto is FALSE. */
4118 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4119 ++pt->pt_dict->dv_refcount;
4120 }
4121 else if (arg_pt != NULL)
4122 {
4123 /* If the dict was bound automatically the result is also
4124 * bound automatically. */
4125 pt->pt_dict = arg_pt->pt_dict;
4126 pt->pt_auto = arg_pt->pt_auto;
4127 if (pt->pt_dict != NULL)
4128 ++pt->pt_dict->dv_refcount;
4129 }
4130
4131 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004132 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4133 {
4134 pt->pt_func = arg_pt->pt_func;
4135 func_ptr_ref(pt->pt_func);
4136 vim_free(name);
4137 }
4138 else if (is_funcref)
4139 {
4140 pt->pt_func = find_func(trans_name);
4141 func_ptr_ref(pt->pt_func);
4142 vim_free(name);
4143 }
4144 else
4145 {
4146 pt->pt_name = name;
4147 func_ref(name);
4148 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004149 }
4150 rettv->v_type = VAR_PARTIAL;
4151 rettv->vval.v_partial = pt;
4152 }
4153 else
4154 {
4155 /* result is a VAR_FUNC */
4156 rettv->v_type = VAR_FUNC;
4157 rettv->vval.v_string = name;
4158 func_ref(name);
4159 }
4160 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004161theend:
4162 vim_free(trans_name);
4163}
4164
4165/*
4166 * "funcref()" function
4167 */
4168 static void
4169f_funcref(typval_T *argvars, typval_T *rettv)
4170{
4171 common_function(argvars, rettv, TRUE);
4172}
4173
4174/*
4175 * "function()" function
4176 */
4177 static void
4178f_function(typval_T *argvars, typval_T *rettv)
4179{
4180 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004181}
4182
4183/*
4184 * "garbagecollect()" function
4185 */
4186 static void
4187f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4188{
4189 /* This is postponed until we are back at the toplevel, because we may be
4190 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4191 want_garbage_collect = TRUE;
4192
4193 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
4194 garbage_collect_at_exit = TRUE;
4195}
4196
4197/*
4198 * "get()" function
4199 */
4200 static void
4201f_get(typval_T *argvars, typval_T *rettv)
4202{
4203 listitem_T *li;
4204 list_T *l;
4205 dictitem_T *di;
4206 dict_T *d;
4207 typval_T *tv = NULL;
4208
4209 if (argvars[0].v_type == VAR_LIST)
4210 {
4211 if ((l = argvars[0].vval.v_list) != NULL)
4212 {
4213 int error = FALSE;
4214
4215 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
4216 if (!error && li != NULL)
4217 tv = &li->li_tv;
4218 }
4219 }
4220 else if (argvars[0].v_type == VAR_DICT)
4221 {
4222 if ((d = argvars[0].vval.v_dict) != NULL)
4223 {
4224 di = dict_find(d, get_tv_string(&argvars[1]), -1);
4225 if (di != NULL)
4226 tv = &di->di_tv;
4227 }
4228 }
4229 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4230 {
4231 partial_T *pt;
4232 partial_T fref_pt;
4233
4234 if (argvars[0].v_type == VAR_PARTIAL)
4235 pt = argvars[0].vval.v_partial;
4236 else
4237 {
4238 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4239 fref_pt.pt_name = argvars[0].vval.v_string;
4240 pt = &fref_pt;
4241 }
4242
4243 if (pt != NULL)
4244 {
4245 char_u *what = get_tv_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004246 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247
4248 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4249 {
4250 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004251 n = partial_name(pt);
4252 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004253 rettv->vval.v_string = NULL;
4254 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004255 {
4256 rettv->vval.v_string = vim_strsave(n);
4257 if (rettv->v_type == VAR_FUNC)
4258 func_ref(rettv->vval.v_string);
4259 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004260 }
4261 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004262 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004263 else if (STRCMP(what, "args") == 0)
4264 {
4265 rettv->v_type = VAR_LIST;
4266 if (rettv_list_alloc(rettv) == OK)
4267 {
4268 int i;
4269
4270 for (i = 0; i < pt->pt_argc; ++i)
4271 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4272 }
4273 }
4274 else
4275 EMSG2(_(e_invarg2), what);
4276 return;
4277 }
4278 }
4279 else
4280 EMSG2(_(e_listdictarg), "get()");
4281
4282 if (tv == NULL)
4283 {
4284 if (argvars[2].v_type != VAR_UNKNOWN)
4285 copy_tv(&argvars[2], rettv);
4286 }
4287 else
4288 copy_tv(tv, rettv);
4289}
4290
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004291#ifdef FEAT_SIGNS
4292/*
4293 * Returns information about signs placed in a buffer as list of dicts.
4294 */
4295 static void
4296get_buffer_signs(buf_T *buf, list_T *l)
4297{
4298 signlist_T *sign;
4299
4300 for (sign = buf->b_signlist; sign; sign = sign->next)
4301 {
4302 dict_T *d = dict_alloc();
4303
4304 if (d != NULL)
4305 {
4306 dict_add_nr_str(d, "id", sign->id, NULL);
4307 dict_add_nr_str(d, "lnum", sign->lnum, NULL);
Bram Moolenaar6a402ed2016-08-28 14:11:24 +02004308 dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004309
4310 list_append_dict(l, d);
4311 }
4312 }
4313}
4314#endif
4315
4316/*
4317 * Returns buffer options, variables and other attributes in a dictionary.
4318 */
4319 static dict_T *
4320get_buffer_info(buf_T *buf)
4321{
4322 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004323 tabpage_T *tp;
4324 win_T *wp;
4325 list_T *windows;
4326
4327 dict = dict_alloc();
4328 if (dict == NULL)
4329 return NULL;
4330
Bram Moolenaar33928832016-08-18 21:22:04 +02004331 dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004332 dict_add_nr_str(dict, "name", 0L,
4333 buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
Bram Moolenaarf845b872017-01-06 14:04:54 +01004334 dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4335 : buflist_findlnum(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004336 dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4337 dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4338 dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
Bram Moolenaar95c526e2017-02-25 14:59:34 +01004339 dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004340 dict_add_nr_str(dict, "hidden",
4341 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4342 NULL);
4343
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004344 /* Get a reference to buffer variables */
4345 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004346
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004347 /* List of windows displaying this buffer */
4348 windows = list_alloc();
4349 if (windows != NULL)
4350 {
4351 FOR_ALL_TAB_WINDOWS(tp, wp)
4352 if (wp->w_buffer == buf)
4353 list_append_number(windows, (varnumber_T)wp->w_id);
4354 dict_add_list(dict, "windows", windows);
4355 }
4356
4357#ifdef FEAT_SIGNS
4358 if (buf->b_signlist != NULL)
4359 {
4360 /* List of signs placed in this buffer */
4361 list_T *signs = list_alloc();
4362 if (signs != NULL)
4363 {
4364 get_buffer_signs(buf, signs);
4365 dict_add_list(dict, "signs", signs);
4366 }
4367 }
4368#endif
4369
4370 return dict;
4371}
4372
4373/*
4374 * "getbufinfo()" function
4375 */
4376 static void
4377f_getbufinfo(typval_T *argvars, typval_T *rettv)
4378{
4379 buf_T *buf = NULL;
4380 buf_T *argbuf = NULL;
4381 dict_T *d;
4382 int filtered = FALSE;
4383 int sel_buflisted = FALSE;
4384 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004385 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004386
4387 if (rettv_list_alloc(rettv) != OK)
4388 return;
4389
4390 /* List of all the buffers or selected buffers */
4391 if (argvars[0].v_type == VAR_DICT)
4392 {
4393 dict_T *sel_d = argvars[0].vval.v_dict;
4394
4395 if (sel_d != NULL)
4396 {
4397 dictitem_T *di;
4398
4399 filtered = TRUE;
4400
4401 di = dict_find(sel_d, (char_u *)"buflisted", -1);
4402 if (di != NULL && get_tv_number(&di->di_tv))
4403 sel_buflisted = TRUE;
4404
4405 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4406 if (di != NULL && get_tv_number(&di->di_tv))
4407 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004408
4409 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4410 if (di != NULL && get_tv_number(&di->di_tv))
4411 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004412 }
4413 }
4414 else if (argvars[0].v_type != VAR_UNKNOWN)
4415 {
4416 /* Information about one buffer. Argument specifies the buffer */
4417 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4418 ++emsg_off;
4419 argbuf = get_buf_tv(&argvars[0], FALSE);
4420 --emsg_off;
4421 if (argbuf == NULL)
4422 return;
4423 }
4424
4425 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004426 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004427 {
4428 if (argbuf != NULL && argbuf != buf)
4429 continue;
4430 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004431 || (sel_buflisted && !buf->b_p_bl)
4432 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004433 continue;
4434
4435 d = get_buffer_info(buf);
4436 if (d != NULL)
4437 list_append_dict(rettv->vval.v_list, d);
4438 if (argbuf != NULL)
4439 return;
4440 }
4441}
4442
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004443static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4444
4445/*
4446 * Get line or list of lines from buffer "buf" into "rettv".
4447 * Return a range (from start to end) of lines in rettv from the specified
4448 * buffer.
4449 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4450 */
4451 static void
4452get_buffer_lines(
4453 buf_T *buf,
4454 linenr_T start,
4455 linenr_T end,
4456 int retlist,
4457 typval_T *rettv)
4458{
4459 char_u *p;
4460
4461 rettv->v_type = VAR_STRING;
4462 rettv->vval.v_string = NULL;
4463 if (retlist && rettv_list_alloc(rettv) == FAIL)
4464 return;
4465
4466 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4467 return;
4468
4469 if (!retlist)
4470 {
4471 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4472 p = ml_get_buf(buf, start, FALSE);
4473 else
4474 p = (char_u *)"";
4475 rettv->vval.v_string = vim_strsave(p);
4476 }
4477 else
4478 {
4479 if (end < start)
4480 return;
4481
4482 if (start < 1)
4483 start = 1;
4484 if (end > buf->b_ml.ml_line_count)
4485 end = buf->b_ml.ml_line_count;
4486 while (start <= end)
4487 if (list_append_string(rettv->vval.v_list,
4488 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4489 break;
4490 }
4491}
4492
4493/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004494 * "getbufline()" function
4495 */
4496 static void
4497f_getbufline(typval_T *argvars, typval_T *rettv)
4498{
4499 linenr_T lnum;
4500 linenr_T end;
4501 buf_T *buf;
4502
4503 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4504 ++emsg_off;
4505 buf = get_buf_tv(&argvars[0], FALSE);
4506 --emsg_off;
4507
4508 lnum = get_tv_lnum_buf(&argvars[1], buf);
4509 if (argvars[2].v_type == VAR_UNKNOWN)
4510 end = lnum;
4511 else
4512 end = get_tv_lnum_buf(&argvars[2], buf);
4513
4514 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4515}
4516
4517/*
4518 * "getbufvar()" function
4519 */
4520 static void
4521f_getbufvar(typval_T *argvars, typval_T *rettv)
4522{
4523 buf_T *buf;
4524 buf_T *save_curbuf;
4525 char_u *varname;
4526 dictitem_T *v;
4527 int done = FALSE;
4528
4529 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4530 varname = get_tv_string_chk(&argvars[1]);
4531 ++emsg_off;
4532 buf = get_buf_tv(&argvars[0], FALSE);
4533
4534 rettv->v_type = VAR_STRING;
4535 rettv->vval.v_string = NULL;
4536
4537 if (buf != NULL && varname != NULL)
4538 {
4539 /* set curbuf to be our buf, temporarily */
4540 save_curbuf = curbuf;
4541 curbuf = buf;
4542
Bram Moolenaar30567352016-08-27 21:25:44 +02004543 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004544 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004545 if (varname[1] == NUL)
4546 {
4547 /* get all buffer-local options in a dict */
4548 dict_T *opts = get_winbuf_options(TRUE);
4549
4550 if (opts != NULL)
4551 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004552 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004553 done = TRUE;
4554 }
4555 }
4556 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4557 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004558 done = TRUE;
4559 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560 else
4561 {
4562 /* Look up the variable. */
4563 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4564 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4565 'b', varname, FALSE);
4566 if (v != NULL)
4567 {
4568 copy_tv(&v->di_tv, rettv);
4569 done = TRUE;
4570 }
4571 }
4572
4573 /* restore previous notion of curbuf */
4574 curbuf = save_curbuf;
4575 }
4576
4577 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4578 /* use the default value */
4579 copy_tv(&argvars[2], rettv);
4580
4581 --emsg_off;
4582}
4583
4584/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004585 * "getchangelist()" function
4586 */
4587 static void
4588f_getchangelist(typval_T *argvars, typval_T *rettv)
4589{
4590#ifdef FEAT_JUMPLIST
4591 buf_T *buf;
4592 int i;
4593 list_T *l;
4594 dict_T *d;
4595#endif
4596
4597 if (rettv_list_alloc(rettv) != OK)
4598 return;
4599
4600#ifdef FEAT_JUMPLIST
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004601 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
4602 ++emsg_off;
4603 buf = get_buf_tv(&argvars[0], FALSE);
4604 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004605 if (buf == NULL)
4606 return;
4607
4608 l = list_alloc();
4609 if (l == NULL)
4610 return;
4611
4612 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4613 return;
4614 /*
4615 * The current window change list index tracks only the position in the
4616 * current buffer change list. For other buffers, use the change list
4617 * length as the current index.
4618 */
4619 list_append_number(rettv->vval.v_list,
4620 (varnumber_T)((buf == curwin->w_buffer)
4621 ? curwin->w_changelistidx : buf->b_changelistlen));
4622
4623 for (i = 0; i < buf->b_changelistlen; ++i)
4624 {
4625 if (buf->b_changelist[i].lnum == 0)
4626 continue;
4627 if ((d = dict_alloc()) == NULL)
4628 return;
4629 if (list_append_dict(l, d) == FAIL)
4630 return;
4631 dict_add_nr_str(d, "lnum", (long)buf->b_changelist[i].lnum, NULL);
4632 dict_add_nr_str(d, "col", (long)buf->b_changelist[i].col, NULL);
4633# ifdef FEAT_VIRTUALEDIT
4634 dict_add_nr_str(d, "coladd", (long)buf->b_changelist[i].coladd, NULL);
4635# endif
4636 }
4637#endif
4638}
4639/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004640 * "getchar()" function
4641 */
4642 static void
4643f_getchar(typval_T *argvars, typval_T *rettv)
4644{
4645 varnumber_T n;
4646 int error = FALSE;
4647
4648 /* Position the cursor. Needed after a message that ends in a space. */
4649 windgoto(msg_row, msg_col);
4650
4651 ++no_mapping;
4652 ++allow_keys;
4653 for (;;)
4654 {
4655 if (argvars[0].v_type == VAR_UNKNOWN)
4656 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004657 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004658 else if (get_tv_number_chk(&argvars[0], &error) == 1)
4659 /* getchar(1): only check if char avail */
4660 n = vpeekc_any();
4661 else if (error || vpeekc_any() == NUL)
4662 /* illegal argument or getchar(0) and no char avail: return zero */
4663 n = 0;
4664 else
4665 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004666 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004667
4668 if (n == K_IGNORE)
4669 continue;
4670 break;
4671 }
4672 --no_mapping;
4673 --allow_keys;
4674
4675 set_vim_var_nr(VV_MOUSE_WIN, 0);
4676 set_vim_var_nr(VV_MOUSE_WINID, 0);
4677 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4678 set_vim_var_nr(VV_MOUSE_COL, 0);
4679
4680 rettv->vval.v_number = n;
4681 if (IS_SPECIAL(n) || mod_mask != 0)
4682 {
4683 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4684 int i = 0;
4685
4686 /* Turn a special key into three bytes, plus modifier. */
4687 if (mod_mask != 0)
4688 {
4689 temp[i++] = K_SPECIAL;
4690 temp[i++] = KS_MODIFIER;
4691 temp[i++] = mod_mask;
4692 }
4693 if (IS_SPECIAL(n))
4694 {
4695 temp[i++] = K_SPECIAL;
4696 temp[i++] = K_SECOND(n);
4697 temp[i++] = K_THIRD(n);
4698 }
4699#ifdef FEAT_MBYTE
4700 else if (has_mbyte)
4701 i += (*mb_char2bytes)(n, temp + i);
4702#endif
4703 else
4704 temp[i++] = n;
4705 temp[i++] = NUL;
4706 rettv->v_type = VAR_STRING;
4707 rettv->vval.v_string = vim_strsave(temp);
4708
4709#ifdef FEAT_MOUSE
4710 if (is_mouse_key(n))
4711 {
4712 int row = mouse_row;
4713 int col = mouse_col;
4714 win_T *win;
4715 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004716 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717 int winnr = 1;
4718
4719 if (row >= 0 && col >= 0)
4720 {
4721 /* Find the window at the mouse coordinates and compute the
4722 * text position. */
4723 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004724 if (win == NULL)
4725 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004726 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004727 for (wp = firstwin; wp != win; wp = wp->w_next)
4728 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4730 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4731 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4732 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4733 }
4734 }
4735#endif
4736 }
4737}
4738
4739/*
4740 * "getcharmod()" function
4741 */
4742 static void
4743f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4744{
4745 rettv->vval.v_number = mod_mask;
4746}
4747
4748/*
4749 * "getcharsearch()" function
4750 */
4751 static void
4752f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4753{
4754 if (rettv_dict_alloc(rettv) != FAIL)
4755 {
4756 dict_T *dict = rettv->vval.v_dict;
4757
4758 dict_add_nr_str(dict, "char", 0L, last_csearch());
4759 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4760 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4761 }
4762}
4763
4764/*
4765 * "getcmdline()" function
4766 */
4767 static void
4768f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4769{
4770 rettv->v_type = VAR_STRING;
4771 rettv->vval.v_string = get_cmdline_str();
4772}
4773
4774/*
4775 * "getcmdpos()" function
4776 */
4777 static void
4778f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4779{
4780 rettv->vval.v_number = get_cmdline_pos() + 1;
4781}
4782
4783/*
4784 * "getcmdtype()" function
4785 */
4786 static void
4787f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4788{
4789 rettv->v_type = VAR_STRING;
4790 rettv->vval.v_string = alloc(2);
4791 if (rettv->vval.v_string != NULL)
4792 {
4793 rettv->vval.v_string[0] = get_cmdline_type();
4794 rettv->vval.v_string[1] = NUL;
4795 }
4796}
4797
4798/*
4799 * "getcmdwintype()" function
4800 */
4801 static void
4802f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4803{
4804 rettv->v_type = VAR_STRING;
4805 rettv->vval.v_string = NULL;
4806#ifdef FEAT_CMDWIN
4807 rettv->vval.v_string = alloc(2);
4808 if (rettv->vval.v_string != NULL)
4809 {
4810 rettv->vval.v_string[0] = cmdwin_type;
4811 rettv->vval.v_string[1] = NUL;
4812 }
4813#endif
4814}
4815
4816#if defined(FEAT_CMDL_COMPL)
4817/*
4818 * "getcompletion()" function
4819 */
4820 static void
4821f_getcompletion(typval_T *argvars, typval_T *rettv)
4822{
4823 char_u *pat;
4824 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004825 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004826 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4827 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004829 if (argvars[2].v_type != VAR_UNKNOWN)
4830 filtered = get_tv_number_chk(&argvars[2], NULL);
4831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832 if (p_wic)
4833 options |= WILD_ICASE;
4834
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004835 /* For filtered results, 'wildignore' is used */
4836 if (!filtered)
4837 options |= WILD_KEEP_ALL;
4838
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839 ExpandInit(&xpc);
4840 xpc.xp_pattern = get_tv_string(&argvars[0]);
4841 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4842 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4843 if (xpc.xp_context == EXPAND_NOTHING)
4844 {
4845 if (argvars[1].v_type == VAR_STRING)
4846 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4847 else
4848 EMSG(_(e_invarg));
4849 return;
4850 }
4851
4852# if defined(FEAT_MENU)
4853 if (xpc.xp_context == EXPAND_MENUS)
4854 {
4855 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4856 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4857 }
4858# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004859#ifdef FEAT_CSCOPE
4860 if (xpc.xp_context == EXPAND_CSCOPE)
4861 {
4862 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4863 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4864 }
4865#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004866#ifdef FEAT_SIGNS
4867 if (xpc.xp_context == EXPAND_SIGN)
4868 {
4869 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4870 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4871 }
4872#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004873
4874 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4875 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4876 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004877 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878
4879 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4880
4881 for (i = 0; i < xpc.xp_numfiles; i++)
4882 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4883 }
4884 vim_free(pat);
4885 ExpandCleanup(&xpc);
4886}
4887#endif
4888
4889/*
4890 * "getcwd()" function
4891 */
4892 static void
4893f_getcwd(typval_T *argvars, typval_T *rettv)
4894{
4895 win_T *wp = NULL;
4896 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004897 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004898
4899 rettv->v_type = VAR_STRING;
4900 rettv->vval.v_string = NULL;
4901
Bram Moolenaar54591292018-02-09 20:53:59 +01004902 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
4903 global = TRUE;
4904 else
4905 wp = find_tabwin(&argvars[0], &argvars[1]);
4906
4907 if (wp != NULL && wp->w_localdir != NULL)
4908 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4909 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004911 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004912 rettv->vval.v_string = vim_strsave(globaldir);
4913 else
4914 {
4915 cwd = alloc(MAXPATHL);
4916 if (cwd != NULL)
4917 {
4918 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4919 rettv->vval.v_string = vim_strsave(cwd);
4920 vim_free(cwd);
4921 }
4922 }
4923#ifdef BACKSLASH_IN_FILENAME
4924 if (rettv->vval.v_string != NULL)
4925 slash_adjust(rettv->vval.v_string);
4926#endif
4927 }
4928}
4929
4930/*
4931 * "getfontname()" function
4932 */
4933 static void
4934f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4935{
4936 rettv->v_type = VAR_STRING;
4937 rettv->vval.v_string = NULL;
4938#ifdef FEAT_GUI
4939 if (gui.in_use)
4940 {
4941 GuiFont font;
4942 char_u *name = NULL;
4943
4944 if (argvars[0].v_type == VAR_UNKNOWN)
4945 {
4946 /* Get the "Normal" font. Either the name saved by
4947 * hl_set_font_name() or from the font ID. */
4948 font = gui.norm_font;
4949 name = hl_get_font_name();
4950 }
4951 else
4952 {
4953 name = get_tv_string(&argvars[0]);
4954 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4955 return;
4956 font = gui_mch_get_font(name, FALSE);
4957 if (font == NOFONT)
4958 return; /* Invalid font name, return empty string. */
4959 }
4960 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4961 if (argvars[0].v_type != VAR_UNKNOWN)
4962 gui_mch_free_font(font);
4963 }
4964#endif
4965}
4966
4967/*
4968 * "getfperm({fname})" function
4969 */
4970 static void
4971f_getfperm(typval_T *argvars, typval_T *rettv)
4972{
4973 char_u *fname;
4974 stat_T st;
4975 char_u *perm = NULL;
4976 char_u flags[] = "rwx";
4977 int i;
4978
4979 fname = get_tv_string(&argvars[0]);
4980
4981 rettv->v_type = VAR_STRING;
4982 if (mch_stat((char *)fname, &st) >= 0)
4983 {
4984 perm = vim_strsave((char_u *)"---------");
4985 if (perm != NULL)
4986 {
4987 for (i = 0; i < 9; i++)
4988 {
4989 if (st.st_mode & (1 << (8 - i)))
4990 perm[i] = flags[i % 3];
4991 }
4992 }
4993 }
4994 rettv->vval.v_string = perm;
4995}
4996
4997/*
4998 * "getfsize({fname})" function
4999 */
5000 static void
5001f_getfsize(typval_T *argvars, typval_T *rettv)
5002{
5003 char_u *fname;
5004 stat_T st;
5005
5006 fname = get_tv_string(&argvars[0]);
5007
5008 rettv->v_type = VAR_NUMBER;
5009
5010 if (mch_stat((char *)fname, &st) >= 0)
5011 {
5012 if (mch_isdir(fname))
5013 rettv->vval.v_number = 0;
5014 else
5015 {
5016 rettv->vval.v_number = (varnumber_T)st.st_size;
5017
5018 /* non-perfect check for overflow */
5019 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5020 rettv->vval.v_number = -2;
5021 }
5022 }
5023 else
5024 rettv->vval.v_number = -1;
5025}
5026
5027/*
5028 * "getftime({fname})" function
5029 */
5030 static void
5031f_getftime(typval_T *argvars, typval_T *rettv)
5032{
5033 char_u *fname;
5034 stat_T st;
5035
5036 fname = get_tv_string(&argvars[0]);
5037
5038 if (mch_stat((char *)fname, &st) >= 0)
5039 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5040 else
5041 rettv->vval.v_number = -1;
5042}
5043
5044/*
5045 * "getftype({fname})" function
5046 */
5047 static void
5048f_getftype(typval_T *argvars, typval_T *rettv)
5049{
5050 char_u *fname;
5051 stat_T st;
5052 char_u *type = NULL;
5053 char *t;
5054
5055 fname = get_tv_string(&argvars[0]);
5056
5057 rettv->v_type = VAR_STRING;
5058 if (mch_lstat((char *)fname, &st) >= 0)
5059 {
5060#ifdef S_ISREG
5061 if (S_ISREG(st.st_mode))
5062 t = "file";
5063 else if (S_ISDIR(st.st_mode))
5064 t = "dir";
5065# ifdef S_ISLNK
5066 else if (S_ISLNK(st.st_mode))
5067 t = "link";
5068# endif
5069# ifdef S_ISBLK
5070 else if (S_ISBLK(st.st_mode))
5071 t = "bdev";
5072# endif
5073# ifdef S_ISCHR
5074 else if (S_ISCHR(st.st_mode))
5075 t = "cdev";
5076# endif
5077# ifdef S_ISFIFO
5078 else if (S_ISFIFO(st.st_mode))
5079 t = "fifo";
5080# endif
5081# ifdef S_ISSOCK
5082 else if (S_ISSOCK(st.st_mode))
5083 t = "fifo";
5084# endif
5085 else
5086 t = "other";
5087#else
5088# ifdef S_IFMT
5089 switch (st.st_mode & S_IFMT)
5090 {
5091 case S_IFREG: t = "file"; break;
5092 case S_IFDIR: t = "dir"; break;
5093# ifdef S_IFLNK
5094 case S_IFLNK: t = "link"; break;
5095# endif
5096# ifdef S_IFBLK
5097 case S_IFBLK: t = "bdev"; break;
5098# endif
5099# ifdef S_IFCHR
5100 case S_IFCHR: t = "cdev"; break;
5101# endif
5102# ifdef S_IFIFO
5103 case S_IFIFO: t = "fifo"; break;
5104# endif
5105# ifdef S_IFSOCK
5106 case S_IFSOCK: t = "socket"; break;
5107# endif
5108 default: t = "other";
5109 }
5110# else
5111 if (mch_isdir(fname))
5112 t = "dir";
5113 else
5114 t = "file";
5115# endif
5116#endif
5117 type = vim_strsave((char_u *)t);
5118 }
5119 rettv->vval.v_string = type;
5120}
5121
5122/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005123 * "getjumplist()" function
5124 */
5125 static void
5126f_getjumplist(typval_T *argvars, typval_T *rettv)
5127{
5128#ifdef FEAT_JUMPLIST
5129 win_T *wp;
5130 int i;
5131 list_T *l;
5132 dict_T *d;
5133#endif
5134
5135 if (rettv_list_alloc(rettv) != OK)
5136 return;
5137
5138#ifdef FEAT_JUMPLIST
5139 wp = find_tabwin(&argvars[0], &argvars[1]);
5140 if (wp == NULL)
5141 return;
5142
5143 l = list_alloc();
5144 if (l == NULL)
5145 return;
5146
5147 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5148 return;
5149 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5150
Bram Moolenaar48679742018-02-13 13:33:29 +01005151 cleanup_jumplist(wp, TRUE);
5152
Bram Moolenaar4f505882018-02-10 21:06:32 +01005153 for (i = 0; i < wp->w_jumplistlen; ++i)
5154 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005155 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5156 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005157 if ((d = dict_alloc()) == NULL)
5158 return;
5159 if (list_append_dict(l, d) == FAIL)
5160 return;
5161 dict_add_nr_str(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum,
5162 NULL);
5163 dict_add_nr_str(d, "col", (long)wp->w_jumplist[i].fmark.mark.col,
5164 NULL);
5165# ifdef FEAT_VIRTUALEDIT
5166 dict_add_nr_str(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd,
5167 NULL);
5168# endif
5169 dict_add_nr_str(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum, NULL);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005170 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaar4f505882018-02-10 21:06:32 +01005171 dict_add_nr_str(d, "filename", 0L, wp->w_jumplist[i].fname);
5172 }
5173#endif
5174}
5175
5176/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005177 * "getline(lnum, [end])" function
5178 */
5179 static void
5180f_getline(typval_T *argvars, typval_T *rettv)
5181{
5182 linenr_T lnum;
5183 linenr_T end;
5184 int retlist;
5185
5186 lnum = get_tv_lnum(argvars);
5187 if (argvars[1].v_type == VAR_UNKNOWN)
5188 {
5189 end = 0;
5190 retlist = FALSE;
5191 }
5192 else
5193 {
5194 end = get_tv_lnum(&argvars[1]);
5195 retlist = TRUE;
5196 }
5197
5198 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5199}
5200
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005201#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005202 static void
5203get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5204{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005205 if (what_arg->v_type == VAR_UNKNOWN)
5206 {
5207 if (rettv_list_alloc(rettv) == OK)
5208 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005209 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005210 }
5211 else
5212 {
5213 if (rettv_dict_alloc(rettv) == OK)
5214 if (is_qf || (wp != NULL))
5215 {
5216 if (what_arg->v_type == VAR_DICT)
5217 {
5218 dict_T *d = what_arg->vval.v_dict;
5219
5220 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005221 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005222 }
5223 else
5224 EMSG(_(e_dictreq));
5225 }
5226 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005227}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005228#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005229
5230/*
5231 * "getloclist()" function
5232 */
5233 static void
5234f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5235{
5236#ifdef FEAT_QUICKFIX
5237 win_T *wp;
5238
5239 wp = find_win_by_nr(&argvars[0], NULL);
5240 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5241#endif
5242}
5243
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244/*
5245 * "getmatches()" function
5246 */
5247 static void
5248f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5249{
5250#ifdef FEAT_SEARCH_EXTRA
5251 dict_T *dict;
5252 matchitem_T *cur = curwin->w_match_head;
5253 int i;
5254
5255 if (rettv_list_alloc(rettv) == OK)
5256 {
5257 while (cur != NULL)
5258 {
5259 dict = dict_alloc();
5260 if (dict == NULL)
5261 return;
5262 if (cur->match.regprog == NULL)
5263 {
5264 /* match added with matchaddpos() */
5265 for (i = 0; i < MAXPOSMATCH; ++i)
5266 {
5267 llpos_T *llpos;
5268 char buf[6];
5269 list_T *l;
5270
5271 llpos = &cur->pos.pos[i];
5272 if (llpos->lnum == 0)
5273 break;
5274 l = list_alloc();
5275 if (l == NULL)
5276 break;
5277 list_append_number(l, (varnumber_T)llpos->lnum);
5278 if (llpos->col > 0)
5279 {
5280 list_append_number(l, (varnumber_T)llpos->col);
5281 list_append_number(l, (varnumber_T)llpos->len);
5282 }
5283 sprintf(buf, "pos%d", i + 1);
5284 dict_add_list(dict, buf, l);
5285 }
5286 }
5287 else
5288 {
5289 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
5290 }
5291 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
5292 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
5293 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
5294# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
5295 if (cur->conceal_char)
5296 {
5297 char_u buf[MB_MAXBYTES + 1];
5298
5299 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5300 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
5301 }
5302# endif
5303 list_append_dict(rettv->vval.v_list, dict);
5304 cur = cur->next;
5305 }
5306 }
5307#endif
5308}
5309
5310/*
5311 * "getpid()" function
5312 */
5313 static void
5314f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5315{
5316 rettv->vval.v_number = mch_get_pid();
5317}
5318
5319 static void
5320getpos_both(
5321 typval_T *argvars,
5322 typval_T *rettv,
5323 int getcurpos)
5324{
5325 pos_T *fp;
5326 list_T *l;
5327 int fnum = -1;
5328
5329 if (rettv_list_alloc(rettv) == OK)
5330 {
5331 l = rettv->vval.v_list;
5332 if (getcurpos)
5333 fp = &curwin->w_cursor;
5334 else
5335 fp = var2fpos(&argvars[0], TRUE, &fnum);
5336 if (fnum != -1)
5337 list_append_number(l, (varnumber_T)fnum);
5338 else
5339 list_append_number(l, (varnumber_T)0);
5340 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5341 : (varnumber_T)0);
5342 list_append_number(l, (fp != NULL)
5343 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5344 : (varnumber_T)0);
5345 list_append_number(l,
5346#ifdef FEAT_VIRTUALEDIT
5347 (fp != NULL) ? (varnumber_T)fp->coladd :
5348#endif
5349 (varnumber_T)0);
5350 if (getcurpos)
5351 {
5352 update_curswant();
5353 list_append_number(l, curwin->w_curswant == MAXCOL ?
5354 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5355 }
5356 }
5357 else
5358 rettv->vval.v_number = FALSE;
5359}
5360
5361
5362/*
5363 * "getcurpos()" function
5364 */
5365 static void
5366f_getcurpos(typval_T *argvars, typval_T *rettv)
5367{
5368 getpos_both(argvars, rettv, TRUE);
5369}
5370
5371/*
5372 * "getpos(string)" function
5373 */
5374 static void
5375f_getpos(typval_T *argvars, typval_T *rettv)
5376{
5377 getpos_both(argvars, rettv, FALSE);
5378}
5379
5380/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005381 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005382 */
5383 static void
5384f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5385{
5386#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005387 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005388#endif
5389}
5390
5391/*
5392 * "getreg()" function
5393 */
5394 static void
5395f_getreg(typval_T *argvars, typval_T *rettv)
5396{
5397 char_u *strregname;
5398 int regname;
5399 int arg2 = FALSE;
5400 int return_list = FALSE;
5401 int error = FALSE;
5402
5403 if (argvars[0].v_type != VAR_UNKNOWN)
5404 {
5405 strregname = get_tv_string_chk(&argvars[0]);
5406 error = strregname == NULL;
5407 if (argvars[1].v_type != VAR_UNKNOWN)
5408 {
5409 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5410 if (!error && argvars[2].v_type != VAR_UNKNOWN)
5411 return_list = (int)get_tv_number_chk(&argvars[2], &error);
5412 }
5413 }
5414 else
5415 strregname = get_vim_var_str(VV_REG);
5416
5417 if (error)
5418 return;
5419
5420 regname = (strregname == NULL ? '"' : *strregname);
5421 if (regname == 0)
5422 regname = '"';
5423
5424 if (return_list)
5425 {
5426 rettv->v_type = VAR_LIST;
5427 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5428 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5429 if (rettv->vval.v_list == NULL)
5430 (void)rettv_list_alloc(rettv);
5431 else
5432 ++rettv->vval.v_list->lv_refcount;
5433 }
5434 else
5435 {
5436 rettv->v_type = VAR_STRING;
5437 rettv->vval.v_string = get_reg_contents(regname,
5438 arg2 ? GREG_EXPR_SRC : 0);
5439 }
5440}
5441
5442/*
5443 * "getregtype()" function
5444 */
5445 static void
5446f_getregtype(typval_T *argvars, typval_T *rettv)
5447{
5448 char_u *strregname;
5449 int regname;
5450 char_u buf[NUMBUFLEN + 2];
5451 long reglen = 0;
5452
5453 if (argvars[0].v_type != VAR_UNKNOWN)
5454 {
5455 strregname = get_tv_string_chk(&argvars[0]);
5456 if (strregname == NULL) /* type error; errmsg already given */
5457 {
5458 rettv->v_type = VAR_STRING;
5459 rettv->vval.v_string = NULL;
5460 return;
5461 }
5462 }
5463 else
5464 /* Default to v:register */
5465 strregname = get_vim_var_str(VV_REG);
5466
5467 regname = (strregname == NULL ? '"' : *strregname);
5468 if (regname == 0)
5469 regname = '"';
5470
5471 buf[0] = NUL;
5472 buf[1] = NUL;
5473 switch (get_reg_type(regname, &reglen))
5474 {
5475 case MLINE: buf[0] = 'V'; break;
5476 case MCHAR: buf[0] = 'v'; break;
5477 case MBLOCK:
5478 buf[0] = Ctrl_V;
5479 sprintf((char *)buf + 1, "%ld", reglen + 1);
5480 break;
5481 }
5482 rettv->v_type = VAR_STRING;
5483 rettv->vval.v_string = vim_strsave(buf);
5484}
5485
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005486/*
5487 * Returns information (variables, options, etc.) about a tab page
5488 * as a dictionary.
5489 */
5490 static dict_T *
5491get_tabpage_info(tabpage_T *tp, int tp_idx)
5492{
5493 win_T *wp;
5494 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005495 list_T *l;
5496
5497 dict = dict_alloc();
5498 if (dict == NULL)
5499 return NULL;
5500
Bram Moolenaar33928832016-08-18 21:22:04 +02005501 dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005502
5503 l = list_alloc();
5504 if (l != NULL)
5505 {
5506 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5507 wp; wp = wp->w_next)
5508 list_append_number(l, (varnumber_T)wp->w_id);
5509 dict_add_list(dict, "windows", l);
5510 }
5511
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005512 /* Make a reference to tabpage variables */
5513 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005514
5515 return dict;
5516}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005517
5518/*
5519 * "gettabinfo()" function
5520 */
5521 static void
5522f_gettabinfo(typval_T *argvars, typval_T *rettv)
5523{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005524 tabpage_T *tp, *tparg = NULL;
5525 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005526 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005527
5528 if (rettv_list_alloc(rettv) != OK)
5529 return;
5530
5531 if (argvars[0].v_type != VAR_UNKNOWN)
5532 {
5533 /* Information about one tab page */
5534 tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5535 if (tparg == NULL)
5536 return;
5537 }
5538
5539 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005540 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005541 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005542 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005543 if (tparg != NULL && tp != tparg)
5544 continue;
5545 d = get_tabpage_info(tp, tpnr);
5546 if (d != NULL)
5547 list_append_dict(rettv->vval.v_list, d);
5548 if (tparg != NULL)
5549 return;
5550 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005551}
5552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005553/*
5554 * "gettabvar()" function
5555 */
5556 static void
5557f_gettabvar(typval_T *argvars, typval_T *rettv)
5558{
5559 win_T *oldcurwin;
5560 tabpage_T *tp, *oldtabpage;
5561 dictitem_T *v;
5562 char_u *varname;
5563 int done = FALSE;
5564
5565 rettv->v_type = VAR_STRING;
5566 rettv->vval.v_string = NULL;
5567
5568 varname = get_tv_string_chk(&argvars[1]);
5569 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5570 if (tp != NULL && varname != NULL)
5571 {
5572 /* Set tp to be our tabpage, temporarily. Also set the window to the
5573 * first window in the tabpage, otherwise the window is not valid. */
5574 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005575 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5576 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 {
5578 /* look up the variable */
5579 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5580 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5581 if (v != NULL)
5582 {
5583 copy_tv(&v->di_tv, rettv);
5584 done = TRUE;
5585 }
5586 }
5587
5588 /* restore previous notion of curwin */
5589 restore_win(oldcurwin, oldtabpage, TRUE);
5590 }
5591
5592 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5593 copy_tv(&argvars[2], rettv);
5594}
5595
5596/*
5597 * "gettabwinvar()" function
5598 */
5599 static void
5600f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5601{
5602 getwinvar(argvars, rettv, 1);
5603}
5604
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005605/*
5606 * Returns information about a window as a dictionary.
5607 */
5608 static dict_T *
5609get_win_info(win_T *wp, short tpnr, short winnr)
5610{
5611 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005612
5613 dict = dict_alloc();
5614 if (dict == NULL)
5615 return NULL;
5616
Bram Moolenaar33928832016-08-18 21:22:04 +02005617 dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5618 dict_add_nr_str(dict, "winnr", winnr, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005619 dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5620 dict_add_nr_str(dict, "height", wp->w_height, NULL);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005621#ifdef FEAT_MENU
5622 dict_add_nr_str(dict, "winbar", wp->w_winbar_height, NULL);
5623#endif
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005624 dict_add_nr_str(dict, "width", wp->w_width, NULL);
Bram Moolenaar33928832016-08-18 21:22:04 +02005625 dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005626
Bram Moolenaar69905d12017-08-13 18:14:47 +02005627#ifdef FEAT_TERMINAL
5628 dict_add_nr_str(dict, "terminal", bt_terminal(wp->w_buffer), NULL);
5629#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005630#ifdef FEAT_QUICKFIX
5631 dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5632 dict_add_nr_str(dict, "loclist",
5633 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5634#endif
5635
Bram Moolenaar30567352016-08-27 21:25:44 +02005636 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005637 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005638
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005639 return dict;
5640}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005641
5642/*
5643 * "getwininfo()" function
5644 */
5645 static void
5646f_getwininfo(typval_T *argvars, typval_T *rettv)
5647{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005648 tabpage_T *tp;
5649 win_T *wp = NULL, *wparg = NULL;
5650 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005651 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005652
5653 if (rettv_list_alloc(rettv) != OK)
5654 return;
5655
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005656 if (argvars[0].v_type != VAR_UNKNOWN)
5657 {
5658 wparg = win_id2wp(argvars);
5659 if (wparg == NULL)
5660 return;
5661 }
5662
5663 /* Collect information about either all the windows across all the tab
5664 * pages or one particular window.
5665 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005666 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005667 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005668 tabnr++;
5669 winnr = 0;
5670 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005671 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005672 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005673 if (wparg != NULL && wp != wparg)
5674 continue;
5675 d = get_win_info(wp, tabnr, winnr);
5676 if (d != NULL)
5677 list_append_dict(rettv->vval.v_list, d);
5678 if (wparg != NULL)
5679 /* found information about a specific window */
5680 return;
5681 }
5682 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005683}
5684
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005686 * "win_findbuf()" function
5687 */
5688 static void
5689f_win_findbuf(typval_T *argvars, typval_T *rettv)
5690{
5691 if (rettv_list_alloc(rettv) != FAIL)
5692 win_findbuf(argvars, rettv->vval.v_list);
5693}
5694
5695/*
5696 * "win_getid()" function
5697 */
5698 static void
5699f_win_getid(typval_T *argvars, typval_T *rettv)
5700{
5701 rettv->vval.v_number = win_getid(argvars);
5702}
5703
5704/*
5705 * "win_gotoid()" function
5706 */
5707 static void
5708f_win_gotoid(typval_T *argvars, typval_T *rettv)
5709{
5710 rettv->vval.v_number = win_gotoid(argvars);
5711}
5712
5713/*
5714 * "win_id2tabwin()" function
5715 */
5716 static void
5717f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5718{
5719 if (rettv_list_alloc(rettv) != FAIL)
5720 win_id2tabwin(argvars, rettv->vval.v_list);
5721}
5722
5723/*
5724 * "win_id2win()" function
5725 */
5726 static void
5727f_win_id2win(typval_T *argvars, typval_T *rettv)
5728{
5729 rettv->vval.v_number = win_id2win(argvars);
5730}
5731
5732/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005733 * "win_screenpos()" function
5734 */
5735 static void
5736f_win_screenpos(typval_T *argvars, typval_T *rettv)
5737{
5738 win_T *wp;
5739
5740 if (rettv_list_alloc(rettv) == FAIL)
5741 return;
5742
5743 wp = find_win_by_nr(&argvars[0], NULL);
5744 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5745 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5746}
5747
5748/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005749 * "getwinpos({timeout})" function
5750 */
5751 static void
5752f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5753{
5754 int x = -1;
5755 int y = -1;
5756
5757 if (rettv_list_alloc(rettv) == FAIL)
5758 return;
5759#ifdef FEAT_GUI
5760 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005761 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005762# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5763 else
5764# endif
5765#endif
5766#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5767 {
5768 varnumber_T timeout = 100;
5769
5770 if (argvars[0].v_type != VAR_UNKNOWN)
5771 timeout = get_tv_number(&argvars[0]);
5772 term_get_winpos(&x, &y, timeout);
5773 }
5774#endif
5775 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5776 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5777}
5778
5779
5780/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005781 * "getwinposx()" function
5782 */
5783 static void
5784f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5785{
5786 rettv->vval.v_number = -1;
5787#ifdef FEAT_GUI
5788 if (gui.in_use)
5789 {
5790 int x, y;
5791
5792 if (gui_mch_get_winpos(&x, &y) == OK)
5793 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005794 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005795 }
5796#endif
5797#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5798 {
5799 int x, y;
5800
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005801 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005802 rettv->vval.v_number = x;
5803 }
5804#endif
5805}
5806
5807/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808 * "getwinposy()" function
5809 */
5810 static void
5811f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5812{
5813 rettv->vval.v_number = -1;
5814#ifdef FEAT_GUI
5815 if (gui.in_use)
5816 {
5817 int x, y;
5818
5819 if (gui_mch_get_winpos(&x, &y) == OK)
5820 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005821 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005822 }
5823#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005824#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5825 {
5826 int x, y;
5827
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005828 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005829 rettv->vval.v_number = y;
5830 }
5831#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005832}
5833
5834/*
5835 * "getwinvar()" function
5836 */
5837 static void
5838f_getwinvar(typval_T *argvars, typval_T *rettv)
5839{
5840 getwinvar(argvars, rettv, 0);
5841}
5842
5843/*
5844 * "glob()" function
5845 */
5846 static void
5847f_glob(typval_T *argvars, typval_T *rettv)
5848{
5849 int options = WILD_SILENT|WILD_USE_NL;
5850 expand_T xpc;
5851 int error = FALSE;
5852
5853 /* When the optional second argument is non-zero, don't remove matches
5854 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5855 rettv->v_type = VAR_STRING;
5856 if (argvars[1].v_type != VAR_UNKNOWN)
5857 {
5858 if (get_tv_number_chk(&argvars[1], &error))
5859 options |= WILD_KEEP_ALL;
5860 if (argvars[2].v_type != VAR_UNKNOWN)
5861 {
5862 if (get_tv_number_chk(&argvars[2], &error))
5863 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005864 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005865 }
5866 if (argvars[3].v_type != VAR_UNKNOWN
5867 && get_tv_number_chk(&argvars[3], &error))
5868 options |= WILD_ALLLINKS;
5869 }
5870 }
5871 if (!error)
5872 {
5873 ExpandInit(&xpc);
5874 xpc.xp_context = EXPAND_FILES;
5875 if (p_wic)
5876 options += WILD_ICASE;
5877 if (rettv->v_type == VAR_STRING)
5878 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5879 NULL, options, WILD_ALL);
5880 else if (rettv_list_alloc(rettv) != FAIL)
5881 {
5882 int i;
5883
5884 ExpandOne(&xpc, get_tv_string(&argvars[0]),
5885 NULL, options, WILD_ALL_KEEP);
5886 for (i = 0; i < xpc.xp_numfiles; i++)
5887 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5888
5889 ExpandCleanup(&xpc);
5890 }
5891 }
5892 else
5893 rettv->vval.v_string = NULL;
5894}
5895
5896/*
5897 * "globpath()" function
5898 */
5899 static void
5900f_globpath(typval_T *argvars, typval_T *rettv)
5901{
5902 int flags = 0;
5903 char_u buf1[NUMBUFLEN];
5904 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
5905 int error = FALSE;
5906 garray_T ga;
5907 int i;
5908
5909 /* When the optional second argument is non-zero, don't remove matches
5910 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5911 rettv->v_type = VAR_STRING;
5912 if (argvars[2].v_type != VAR_UNKNOWN)
5913 {
5914 if (get_tv_number_chk(&argvars[2], &error))
5915 flags |= WILD_KEEP_ALL;
5916 if (argvars[3].v_type != VAR_UNKNOWN)
5917 {
5918 if (get_tv_number_chk(&argvars[3], &error))
5919 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005920 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005921 }
5922 if (argvars[4].v_type != VAR_UNKNOWN
5923 && get_tv_number_chk(&argvars[4], &error))
5924 flags |= WILD_ALLLINKS;
5925 }
5926 }
5927 if (file != NULL && !error)
5928 {
5929 ga_init2(&ga, (int)sizeof(char_u *), 10);
5930 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5931 if (rettv->v_type == VAR_STRING)
5932 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5933 else if (rettv_list_alloc(rettv) != FAIL)
5934 for (i = 0; i < ga.ga_len; ++i)
5935 list_append_string(rettv->vval.v_list,
5936 ((char_u **)(ga.ga_data))[i], -1);
5937 ga_clear_strings(&ga);
5938 }
5939 else
5940 rettv->vval.v_string = NULL;
5941}
5942
5943/*
5944 * "glob2regpat()" function
5945 */
5946 static void
5947f_glob2regpat(typval_T *argvars, typval_T *rettv)
5948{
5949 char_u *pat = get_tv_string_chk(&argvars[0]);
5950
5951 rettv->v_type = VAR_STRING;
5952 rettv->vval.v_string = (pat == NULL)
5953 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5954}
5955
5956/* for VIM_VERSION_ defines */
5957#include "version.h"
5958
5959/*
5960 * "has()" function
5961 */
5962 static void
5963f_has(typval_T *argvars, typval_T *rettv)
5964{
5965 int i;
5966 char_u *name;
5967 int n = FALSE;
5968 static char *(has_list[]) =
5969 {
5970#ifdef AMIGA
5971 "amiga",
5972# ifdef FEAT_ARP
5973 "arp",
5974# endif
5975#endif
5976#ifdef __BEOS__
5977 "beos",
5978#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005979#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005980 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5981 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005982# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005983 "macunix", /* Mac OS X, with the darwin feature */
5984 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005985# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005986#endif
5987#ifdef __QNX__
5988 "qnx",
5989#endif
5990#ifdef UNIX
5991 "unix",
5992#endif
5993#ifdef VMS
5994 "vms",
5995#endif
5996#ifdef WIN32
5997 "win32",
5998#endif
5999#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6000 "win32unix",
6001#endif
6002#if defined(WIN64) || defined(_WIN64)
6003 "win64",
6004#endif
6005#ifdef EBCDIC
6006 "ebcdic",
6007#endif
6008#ifndef CASE_INSENSITIVE_FILENAME
6009 "fname_case",
6010#endif
6011#ifdef HAVE_ACL
6012 "acl",
6013#endif
6014#ifdef FEAT_ARABIC
6015 "arabic",
6016#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006017 "autocmd",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006018#ifdef FEAT_AUTOSERVERNAME
6019 "autoservername",
6020#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006021#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006022 "balloon_eval",
6023# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6024 "balloon_multiline",
6025# endif
6026#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006027#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006028 "balloon_eval_term",
6029#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6031 "builtin_terms",
6032# ifdef ALL_BUILTIN_TCAPS
6033 "all_builtin_terms",
6034# endif
6035#endif
6036#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6037 || defined(FEAT_GUI_W32) \
6038 || defined(FEAT_GUI_MOTIF))
6039 "browsefilter",
6040#endif
6041#ifdef FEAT_BYTEOFF
6042 "byte_offset",
6043#endif
6044#ifdef FEAT_JOB_CHANNEL
6045 "channel",
6046#endif
6047#ifdef FEAT_CINDENT
6048 "cindent",
6049#endif
6050#ifdef FEAT_CLIENTSERVER
6051 "clientserver",
6052#endif
6053#ifdef FEAT_CLIPBOARD
6054 "clipboard",
6055#endif
6056#ifdef FEAT_CMDL_COMPL
6057 "cmdline_compl",
6058#endif
6059#ifdef FEAT_CMDHIST
6060 "cmdline_hist",
6061#endif
6062#ifdef FEAT_COMMENTS
6063 "comments",
6064#endif
6065#ifdef FEAT_CONCEAL
6066 "conceal",
6067#endif
6068#ifdef FEAT_CRYPT
6069 "cryptv",
6070 "crypt-blowfish",
6071 "crypt-blowfish2",
6072#endif
6073#ifdef FEAT_CSCOPE
6074 "cscope",
6075#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006076 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006077#ifdef CURSOR_SHAPE
6078 "cursorshape",
6079#endif
6080#ifdef DEBUG
6081 "debug",
6082#endif
6083#ifdef FEAT_CON_DIALOG
6084 "dialog_con",
6085#endif
6086#ifdef FEAT_GUI_DIALOG
6087 "dialog_gui",
6088#endif
6089#ifdef FEAT_DIFF
6090 "diff",
6091#endif
6092#ifdef FEAT_DIGRAPHS
6093 "digraphs",
6094#endif
6095#ifdef FEAT_DIRECTX
6096 "directx",
6097#endif
6098#ifdef FEAT_DND
6099 "dnd",
6100#endif
6101#ifdef FEAT_EMACS_TAGS
6102 "emacs_tags",
6103#endif
6104 "eval", /* always present, of course! */
6105 "ex_extra", /* graduated feature */
6106#ifdef FEAT_SEARCH_EXTRA
6107 "extra_search",
6108#endif
6109#ifdef FEAT_FKMAP
6110 "farsi",
6111#endif
6112#ifdef FEAT_SEARCHPATH
6113 "file_in_path",
6114#endif
6115#ifdef FEAT_FILTERPIPE
6116 "filterpipe",
6117#endif
6118#ifdef FEAT_FIND_ID
6119 "find_in_path",
6120#endif
6121#ifdef FEAT_FLOAT
6122 "float",
6123#endif
6124#ifdef FEAT_FOLDING
6125 "folding",
6126#endif
6127#ifdef FEAT_FOOTER
6128 "footer",
6129#endif
6130#if !defined(USE_SYSTEM) && defined(UNIX)
6131 "fork",
6132#endif
6133#ifdef FEAT_GETTEXT
6134 "gettext",
6135#endif
6136#ifdef FEAT_GUI
6137 "gui",
6138#endif
6139#ifdef FEAT_GUI_ATHENA
6140# ifdef FEAT_GUI_NEXTAW
6141 "gui_neXtaw",
6142# else
6143 "gui_athena",
6144# endif
6145#endif
6146#ifdef FEAT_GUI_GTK
6147 "gui_gtk",
6148# ifdef USE_GTK3
6149 "gui_gtk3",
6150# else
6151 "gui_gtk2",
6152# endif
6153#endif
6154#ifdef FEAT_GUI_GNOME
6155 "gui_gnome",
6156#endif
6157#ifdef FEAT_GUI_MAC
6158 "gui_mac",
6159#endif
6160#ifdef FEAT_GUI_MOTIF
6161 "gui_motif",
6162#endif
6163#ifdef FEAT_GUI_PHOTON
6164 "gui_photon",
6165#endif
6166#ifdef FEAT_GUI_W32
6167 "gui_win32",
6168#endif
6169#ifdef FEAT_HANGULIN
6170 "hangul_input",
6171#endif
6172#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6173 "iconv",
6174#endif
6175#ifdef FEAT_INS_EXPAND
6176 "insert_expand",
6177#endif
6178#ifdef FEAT_JOB_CHANNEL
6179 "job",
6180#endif
6181#ifdef FEAT_JUMPLIST
6182 "jumplist",
6183#endif
6184#ifdef FEAT_KEYMAP
6185 "keymap",
6186#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006187 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188#ifdef FEAT_LANGMAP
6189 "langmap",
6190#endif
6191#ifdef FEAT_LIBCALL
6192 "libcall",
6193#endif
6194#ifdef FEAT_LINEBREAK
6195 "linebreak",
6196#endif
6197#ifdef FEAT_LISP
6198 "lispindent",
6199#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006200 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006201#ifdef FEAT_LOCALMAP
6202 "localmap",
6203#endif
6204#ifdef FEAT_LUA
6205# ifndef DYNAMIC_LUA
6206 "lua",
6207# endif
6208#endif
6209#ifdef FEAT_MENU
6210 "menu",
6211#endif
6212#ifdef FEAT_SESSION
6213 "mksession",
6214#endif
6215#ifdef FEAT_MODIFY_FNAME
6216 "modify_fname",
6217#endif
6218#ifdef FEAT_MOUSE
6219 "mouse",
6220#endif
6221#ifdef FEAT_MOUSESHAPE
6222 "mouseshape",
6223#endif
6224#if defined(UNIX) || defined(VMS)
6225# ifdef FEAT_MOUSE_DEC
6226 "mouse_dec",
6227# endif
6228# ifdef FEAT_MOUSE_GPM
6229 "mouse_gpm",
6230# endif
6231# ifdef FEAT_MOUSE_JSB
6232 "mouse_jsbterm",
6233# endif
6234# ifdef FEAT_MOUSE_NET
6235 "mouse_netterm",
6236# endif
6237# ifdef FEAT_MOUSE_PTERM
6238 "mouse_pterm",
6239# endif
6240# ifdef FEAT_MOUSE_SGR
6241 "mouse_sgr",
6242# endif
6243# ifdef FEAT_SYSMOUSE
6244 "mouse_sysmouse",
6245# endif
6246# ifdef FEAT_MOUSE_URXVT
6247 "mouse_urxvt",
6248# endif
6249# ifdef FEAT_MOUSE_XTERM
6250 "mouse_xterm",
6251# endif
6252#endif
6253#ifdef FEAT_MBYTE
6254 "multi_byte",
6255#endif
6256#ifdef FEAT_MBYTE_IME
6257 "multi_byte_ime",
6258#endif
6259#ifdef FEAT_MULTI_LANG
6260 "multi_lang",
6261#endif
6262#ifdef FEAT_MZSCHEME
6263#ifndef DYNAMIC_MZSCHEME
6264 "mzscheme",
6265#endif
6266#endif
6267#ifdef FEAT_NUM64
6268 "num64",
6269#endif
6270#ifdef FEAT_OLE
6271 "ole",
6272#endif
6273 "packages",
6274#ifdef FEAT_PATH_EXTRA
6275 "path_extra",
6276#endif
6277#ifdef FEAT_PERL
6278#ifndef DYNAMIC_PERL
6279 "perl",
6280#endif
6281#endif
6282#ifdef FEAT_PERSISTENT_UNDO
6283 "persistent_undo",
6284#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006285#if defined(FEAT_PYTHON)
6286 "python_compiled",
6287# if defined(DYNAMIC_PYTHON)
6288 "python_dynamic",
6289# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006291 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006292# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006294#if defined(FEAT_PYTHON3)
6295 "python3_compiled",
6296# if defined(DYNAMIC_PYTHON3)
6297 "python3_dynamic",
6298# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006299 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006300 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006301# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006302#endif
6303#ifdef FEAT_POSTSCRIPT
6304 "postscript",
6305#endif
6306#ifdef FEAT_PRINTER
6307 "printer",
6308#endif
6309#ifdef FEAT_PROFILE
6310 "profile",
6311#endif
6312#ifdef FEAT_RELTIME
6313 "reltime",
6314#endif
6315#ifdef FEAT_QUICKFIX
6316 "quickfix",
6317#endif
6318#ifdef FEAT_RIGHTLEFT
6319 "rightleft",
6320#endif
6321#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6322 "ruby",
6323#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006324 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325#ifdef FEAT_CMDL_INFO
6326 "showcmd",
6327 "cmdline_info",
6328#endif
6329#ifdef FEAT_SIGNS
6330 "signs",
6331#endif
6332#ifdef FEAT_SMARTINDENT
6333 "smartindent",
6334#endif
6335#ifdef STARTUPTIME
6336 "startuptime",
6337#endif
6338#ifdef FEAT_STL_OPT
6339 "statusline",
6340#endif
6341#ifdef FEAT_SUN_WORKSHOP
6342 "sun_workshop",
6343#endif
6344#ifdef FEAT_NETBEANS_INTG
6345 "netbeans_intg",
6346#endif
6347#ifdef FEAT_SPELL
6348 "spell",
6349#endif
6350#ifdef FEAT_SYN_HL
6351 "syntax",
6352#endif
6353#if defined(USE_SYSTEM) || !defined(UNIX)
6354 "system",
6355#endif
6356#ifdef FEAT_TAG_BINS
6357 "tag_binary",
6358#endif
6359#ifdef FEAT_TAG_OLDSTATIC
6360 "tag_old_static",
6361#endif
6362#ifdef FEAT_TAG_ANYWHITE
6363 "tag_any_white",
6364#endif
6365#ifdef FEAT_TCL
6366# ifndef DYNAMIC_TCL
6367 "tcl",
6368# endif
6369#endif
6370#ifdef FEAT_TERMGUICOLORS
6371 "termguicolors",
6372#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006373#if defined(FEAT_TERMINAL) && !defined(WIN3264)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006374 "terminal",
6375#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376#ifdef TERMINFO
6377 "terminfo",
6378#endif
6379#ifdef FEAT_TERMRESPONSE
6380 "termresponse",
6381#endif
6382#ifdef FEAT_TEXTOBJ
6383 "textobjects",
6384#endif
6385#ifdef HAVE_TGETENT
6386 "tgetent",
6387#endif
6388#ifdef FEAT_TIMERS
6389 "timers",
6390#endif
6391#ifdef FEAT_TITLE
6392 "title",
6393#endif
6394#ifdef FEAT_TOOLBAR
6395 "toolbar",
6396#endif
6397#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6398 "unnamedplus",
6399#endif
6400#ifdef FEAT_USR_CMDS
6401 "user-commands", /* was accidentally included in 5.4 */
6402 "user_commands",
6403#endif
6404#ifdef FEAT_VIMINFO
6405 "viminfo",
6406#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006407 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006408#ifdef FEAT_VIRTUALEDIT
6409 "virtualedit",
6410#endif
6411 "visual",
6412#ifdef FEAT_VISUALEXTRA
6413 "visualextra",
6414#endif
6415#ifdef FEAT_VREPLACE
6416 "vreplace",
6417#endif
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006418#ifdef FEAT_VTP
6419 "vtp",
6420#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421#ifdef FEAT_WILDIGN
6422 "wildignore",
6423#endif
6424#ifdef FEAT_WILDMENU
6425 "wildmenu",
6426#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006428#ifdef FEAT_WAK
6429 "winaltkeys",
6430#endif
6431#ifdef FEAT_WRITEBACKUP
6432 "writebackup",
6433#endif
6434#ifdef FEAT_XIM
6435 "xim",
6436#endif
6437#ifdef FEAT_XFONTSET
6438 "xfontset",
6439#endif
6440#ifdef FEAT_XPM_W32
6441 "xpm",
6442 "xpm_w32", /* for backward compatibility */
6443#else
6444# if defined(HAVE_XPM)
6445 "xpm",
6446# endif
6447#endif
6448#ifdef USE_XSMP
6449 "xsmp",
6450#endif
6451#ifdef USE_XSMP_INTERACT
6452 "xsmp_interact",
6453#endif
6454#ifdef FEAT_XCLIPBOARD
6455 "xterm_clipboard",
6456#endif
6457#ifdef FEAT_XTERM_SAVE
6458 "xterm_save",
6459#endif
6460#if defined(UNIX) && defined(FEAT_X11)
6461 "X11",
6462#endif
6463 NULL
6464 };
6465
6466 name = get_tv_string(&argvars[0]);
6467 for (i = 0; has_list[i] != NULL; ++i)
6468 if (STRICMP(name, has_list[i]) == 0)
6469 {
6470 n = TRUE;
6471 break;
6472 }
6473
6474 if (n == FALSE)
6475 {
6476 if (STRNICMP(name, "patch", 5) == 0)
6477 {
6478 if (name[5] == '-'
6479 && STRLEN(name) >= 11
6480 && vim_isdigit(name[6])
6481 && vim_isdigit(name[8])
6482 && vim_isdigit(name[10]))
6483 {
6484 int major = atoi((char *)name + 6);
6485 int minor = atoi((char *)name + 8);
6486
6487 /* Expect "patch-9.9.01234". */
6488 n = (major < VIM_VERSION_MAJOR
6489 || (major == VIM_VERSION_MAJOR
6490 && (minor < VIM_VERSION_MINOR
6491 || (minor == VIM_VERSION_MINOR
6492 && has_patch(atoi((char *)name + 10))))));
6493 }
6494 else
6495 n = has_patch(atoi((char *)name + 5));
6496 }
6497 else if (STRICMP(name, "vim_starting") == 0)
6498 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006499 else if (STRICMP(name, "ttyin") == 0)
6500 n = mch_input_isatty();
6501 else if (STRICMP(name, "ttyout") == 0)
6502 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503#ifdef FEAT_MBYTE
6504 else if (STRICMP(name, "multi_byte_encoding") == 0)
6505 n = has_mbyte;
6506#endif
6507#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6508 else if (STRICMP(name, "balloon_multiline") == 0)
6509 n = multiline_balloon_available();
6510#endif
6511#ifdef DYNAMIC_TCL
6512 else if (STRICMP(name, "tcl") == 0)
6513 n = tcl_enabled(FALSE);
6514#endif
6515#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6516 else if (STRICMP(name, "iconv") == 0)
6517 n = iconv_enabled(FALSE);
6518#endif
6519#ifdef DYNAMIC_LUA
6520 else if (STRICMP(name, "lua") == 0)
6521 n = lua_enabled(FALSE);
6522#endif
6523#ifdef DYNAMIC_MZSCHEME
6524 else if (STRICMP(name, "mzscheme") == 0)
6525 n = mzscheme_enabled(FALSE);
6526#endif
6527#ifdef DYNAMIC_RUBY
6528 else if (STRICMP(name, "ruby") == 0)
6529 n = ruby_enabled(FALSE);
6530#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006531#ifdef DYNAMIC_PYTHON
6532 else if (STRICMP(name, "python") == 0)
6533 n = python_enabled(FALSE);
6534#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006535#ifdef DYNAMIC_PYTHON3
6536 else if (STRICMP(name, "python3") == 0)
6537 n = python3_enabled(FALSE);
6538#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006539#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6540 else if (STRICMP(name, "pythonx") == 0)
6541 {
6542# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6543 if (p_pyx == 0)
6544 n = python3_enabled(FALSE) || python_enabled(FALSE);
6545 else if (p_pyx == 3)
6546 n = python3_enabled(FALSE);
6547 else if (p_pyx == 2)
6548 n = python_enabled(FALSE);
6549# elif defined(DYNAMIC_PYTHON)
6550 n = python_enabled(FALSE);
6551# elif defined(DYNAMIC_PYTHON3)
6552 n = python3_enabled(FALSE);
6553# endif
6554 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555#endif
6556#ifdef DYNAMIC_PERL
6557 else if (STRICMP(name, "perl") == 0)
6558 n = perl_enabled(FALSE);
6559#endif
6560#ifdef FEAT_GUI
6561 else if (STRICMP(name, "gui_running") == 0)
6562 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006563# ifdef FEAT_BROWSE
6564 else if (STRICMP(name, "browse") == 0)
6565 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6566# endif
6567#endif
6568#ifdef FEAT_SYN_HL
6569 else if (STRICMP(name, "syntax_items") == 0)
6570 n = syntax_present(curwin);
6571#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006572#ifdef FEAT_VTP
6573 else if (STRICMP(name, "vcon") == 0)
6574 n = has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006575#endif
6576#ifdef FEAT_NETBEANS_INTG
6577 else if (STRICMP(name, "netbeans_enabled") == 0)
6578 n = netbeans_active();
6579#endif
Bram Moolenaara83e3962017-08-17 14:39:07 +02006580#if defined(FEAT_TERMINAL) && defined(WIN3264)
6581 else if (STRICMP(name, "terminal") == 0)
6582 n = terminal_enabled();
6583#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006584 }
6585
6586 rettv->vval.v_number = n;
6587}
6588
6589/*
6590 * "has_key()" function
6591 */
6592 static void
6593f_has_key(typval_T *argvars, typval_T *rettv)
6594{
6595 if (argvars[0].v_type != VAR_DICT)
6596 {
6597 EMSG(_(e_dictreq));
6598 return;
6599 }
6600 if (argvars[0].vval.v_dict == NULL)
6601 return;
6602
6603 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6604 get_tv_string(&argvars[1]), -1) != NULL;
6605}
6606
6607/*
6608 * "haslocaldir()" function
6609 */
6610 static void
6611f_haslocaldir(typval_T *argvars, typval_T *rettv)
6612{
6613 win_T *wp = NULL;
6614
6615 wp = find_tabwin(&argvars[0], &argvars[1]);
6616 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6617}
6618
6619/*
6620 * "hasmapto()" function
6621 */
6622 static void
6623f_hasmapto(typval_T *argvars, typval_T *rettv)
6624{
6625 char_u *name;
6626 char_u *mode;
6627 char_u buf[NUMBUFLEN];
6628 int abbr = FALSE;
6629
6630 name = get_tv_string(&argvars[0]);
6631 if (argvars[1].v_type == VAR_UNKNOWN)
6632 mode = (char_u *)"nvo";
6633 else
6634 {
6635 mode = get_tv_string_buf(&argvars[1], buf);
6636 if (argvars[2].v_type != VAR_UNKNOWN)
6637 abbr = (int)get_tv_number(&argvars[2]);
6638 }
6639
6640 if (map_to_exists(name, mode, abbr))
6641 rettv->vval.v_number = TRUE;
6642 else
6643 rettv->vval.v_number = FALSE;
6644}
6645
6646/*
6647 * "histadd()" function
6648 */
6649 static void
6650f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6651{
6652#ifdef FEAT_CMDHIST
6653 int histype;
6654 char_u *str;
6655 char_u buf[NUMBUFLEN];
6656#endif
6657
6658 rettv->vval.v_number = FALSE;
6659 if (check_restricted() || check_secure())
6660 return;
6661#ifdef FEAT_CMDHIST
6662 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6663 histype = str != NULL ? get_histtype(str) : -1;
6664 if (histype >= 0)
6665 {
6666 str = get_tv_string_buf(&argvars[1], buf);
6667 if (*str != NUL)
6668 {
6669 init_history();
6670 add_to_history(histype, str, FALSE, NUL);
6671 rettv->vval.v_number = TRUE;
6672 return;
6673 }
6674 }
6675#endif
6676}
6677
6678/*
6679 * "histdel()" function
6680 */
6681 static void
6682f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6683{
6684#ifdef FEAT_CMDHIST
6685 int n;
6686 char_u buf[NUMBUFLEN];
6687 char_u *str;
6688
6689 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6690 if (str == NULL)
6691 n = 0;
6692 else if (argvars[1].v_type == VAR_UNKNOWN)
6693 /* only one argument: clear entire history */
6694 n = clr_history(get_histtype(str));
6695 else if (argvars[1].v_type == VAR_NUMBER)
6696 /* index given: remove that entry */
6697 n = del_history_idx(get_histtype(str),
6698 (int)get_tv_number(&argvars[1]));
6699 else
6700 /* string given: remove all matching entries */
6701 n = del_history_entry(get_histtype(str),
6702 get_tv_string_buf(&argvars[1], buf));
6703 rettv->vval.v_number = n;
6704#endif
6705}
6706
6707/*
6708 * "histget()" function
6709 */
6710 static void
6711f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6712{
6713#ifdef FEAT_CMDHIST
6714 int type;
6715 int idx;
6716 char_u *str;
6717
6718 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
6719 if (str == NULL)
6720 rettv->vval.v_string = NULL;
6721 else
6722 {
6723 type = get_histtype(str);
6724 if (argvars[1].v_type == VAR_UNKNOWN)
6725 idx = get_history_idx(type);
6726 else
6727 idx = (int)get_tv_number_chk(&argvars[1], NULL);
6728 /* -1 on type error */
6729 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6730 }
6731#else
6732 rettv->vval.v_string = NULL;
6733#endif
6734 rettv->v_type = VAR_STRING;
6735}
6736
6737/*
6738 * "histnr()" function
6739 */
6740 static void
6741f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6742{
6743 int i;
6744
6745#ifdef FEAT_CMDHIST
6746 char_u *history = get_tv_string_chk(&argvars[0]);
6747
6748 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6749 if (i >= HIST_CMD && i < HIST_COUNT)
6750 i = get_history_idx(i);
6751 else
6752#endif
6753 i = -1;
6754 rettv->vval.v_number = i;
6755}
6756
6757/*
6758 * "highlightID(name)" function
6759 */
6760 static void
6761f_hlID(typval_T *argvars, typval_T *rettv)
6762{
6763 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6764}
6765
6766/*
6767 * "highlight_exists()" function
6768 */
6769 static void
6770f_hlexists(typval_T *argvars, typval_T *rettv)
6771{
6772 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6773}
6774
6775/*
6776 * "hostname()" function
6777 */
6778 static void
6779f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6780{
6781 char_u hostname[256];
6782
6783 mch_get_host_name(hostname, 256);
6784 rettv->v_type = VAR_STRING;
6785 rettv->vval.v_string = vim_strsave(hostname);
6786}
6787
6788/*
6789 * iconv() function
6790 */
6791 static void
6792f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6793{
6794#ifdef FEAT_MBYTE
6795 char_u buf1[NUMBUFLEN];
6796 char_u buf2[NUMBUFLEN];
6797 char_u *from, *to, *str;
6798 vimconv_T vimconv;
6799#endif
6800
6801 rettv->v_type = VAR_STRING;
6802 rettv->vval.v_string = NULL;
6803
6804#ifdef FEAT_MBYTE
6805 str = get_tv_string(&argvars[0]);
6806 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6807 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6808 vimconv.vc_type = CONV_NONE;
6809 convert_setup(&vimconv, from, to);
6810
6811 /* If the encodings are equal, no conversion needed. */
6812 if (vimconv.vc_type == CONV_NONE)
6813 rettv->vval.v_string = vim_strsave(str);
6814 else
6815 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6816
6817 convert_setup(&vimconv, NULL, NULL);
6818 vim_free(from);
6819 vim_free(to);
6820#endif
6821}
6822
6823/*
6824 * "indent()" function
6825 */
6826 static void
6827f_indent(typval_T *argvars, typval_T *rettv)
6828{
6829 linenr_T lnum;
6830
6831 lnum = get_tv_lnum(argvars);
6832 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6833 rettv->vval.v_number = get_indent_lnum(lnum);
6834 else
6835 rettv->vval.v_number = -1;
6836}
6837
6838/*
6839 * "index()" function
6840 */
6841 static void
6842f_index(typval_T *argvars, typval_T *rettv)
6843{
6844 list_T *l;
6845 listitem_T *item;
6846 long idx = 0;
6847 int ic = FALSE;
6848
6849 rettv->vval.v_number = -1;
6850 if (argvars[0].v_type != VAR_LIST)
6851 {
6852 EMSG(_(e_listreq));
6853 return;
6854 }
6855 l = argvars[0].vval.v_list;
6856 if (l != NULL)
6857 {
6858 item = l->lv_first;
6859 if (argvars[2].v_type != VAR_UNKNOWN)
6860 {
6861 int error = FALSE;
6862
6863 /* Start at specified item. Use the cached index that list_find()
6864 * sets, so that a negative number also works. */
6865 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6866 idx = l->lv_idx;
6867 if (argvars[3].v_type != VAR_UNKNOWN)
6868 ic = (int)get_tv_number_chk(&argvars[3], &error);
6869 if (error)
6870 item = NULL;
6871 }
6872
6873 for ( ; item != NULL; item = item->li_next, ++idx)
6874 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6875 {
6876 rettv->vval.v_number = idx;
6877 break;
6878 }
6879 }
6880}
6881
6882static int inputsecret_flag = 0;
6883
6884/*
6885 * "input()" function
6886 * Also handles inputsecret() when inputsecret is set.
6887 */
6888 static void
6889f_input(typval_T *argvars, typval_T *rettv)
6890{
6891 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6892}
6893
6894/*
6895 * "inputdialog()" function
6896 */
6897 static void
6898f_inputdialog(typval_T *argvars, typval_T *rettv)
6899{
6900#if defined(FEAT_GUI_TEXTDIALOG)
6901 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6902 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6903 {
6904 char_u *message;
6905 char_u buf[NUMBUFLEN];
6906 char_u *defstr = (char_u *)"";
6907
6908 message = get_tv_string_chk(&argvars[0]);
6909 if (argvars[1].v_type != VAR_UNKNOWN
6910 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6911 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6912 else
6913 IObuff[0] = NUL;
6914 if (message != NULL && defstr != NULL
6915 && do_dialog(VIM_QUESTION, NULL, message,
6916 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6917 rettv->vval.v_string = vim_strsave(IObuff);
6918 else
6919 {
6920 if (message != NULL && defstr != NULL
6921 && argvars[1].v_type != VAR_UNKNOWN
6922 && argvars[2].v_type != VAR_UNKNOWN)
6923 rettv->vval.v_string = vim_strsave(
6924 get_tv_string_buf(&argvars[2], buf));
6925 else
6926 rettv->vval.v_string = NULL;
6927 }
6928 rettv->v_type = VAR_STRING;
6929 }
6930 else
6931#endif
6932 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6933}
6934
6935/*
6936 * "inputlist()" function
6937 */
6938 static void
6939f_inputlist(typval_T *argvars, typval_T *rettv)
6940{
6941 listitem_T *li;
6942 int selected;
6943 int mouse_used;
6944
6945#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006946 /* While starting up, there is no place to enter text. When running tests
6947 * with --not-a-term we assume feedkeys() will be used. */
6948 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006949 return;
6950#endif
6951 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6952 {
6953 EMSG2(_(e_listarg), "inputlist()");
6954 return;
6955 }
6956
6957 msg_start();
6958 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6959 lines_left = Rows; /* avoid more prompt */
6960 msg_scroll = TRUE;
6961 msg_clr_eos();
6962
6963 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6964 {
6965 msg_puts(get_tv_string(&li->li_tv));
6966 msg_putchar('\n');
6967 }
6968
6969 /* Ask for choice. */
6970 selected = prompt_for_number(&mouse_used);
6971 if (mouse_used)
6972 selected -= lines_left;
6973
6974 rettv->vval.v_number = selected;
6975}
6976
6977
6978static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6979
6980/*
6981 * "inputrestore()" function
6982 */
6983 static void
6984f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6985{
6986 if (ga_userinput.ga_len > 0)
6987 {
6988 --ga_userinput.ga_len;
6989 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6990 + ga_userinput.ga_len);
6991 /* default return is zero == OK */
6992 }
6993 else if (p_verbose > 1)
6994 {
6995 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6996 rettv->vval.v_number = 1; /* Failed */
6997 }
6998}
6999
7000/*
7001 * "inputsave()" function
7002 */
7003 static void
7004f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7005{
7006 /* Add an entry to the stack of typeahead storage. */
7007 if (ga_grow(&ga_userinput, 1) == OK)
7008 {
7009 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7010 + ga_userinput.ga_len);
7011 ++ga_userinput.ga_len;
7012 /* default return is zero == OK */
7013 }
7014 else
7015 rettv->vval.v_number = 1; /* Failed */
7016}
7017
7018/*
7019 * "inputsecret()" function
7020 */
7021 static void
7022f_inputsecret(typval_T *argvars, typval_T *rettv)
7023{
7024 ++cmdline_star;
7025 ++inputsecret_flag;
7026 f_input(argvars, rettv);
7027 --cmdline_star;
7028 --inputsecret_flag;
7029}
7030
7031/*
7032 * "insert()" function
7033 */
7034 static void
7035f_insert(typval_T *argvars, typval_T *rettv)
7036{
7037 long before = 0;
7038 listitem_T *item;
7039 list_T *l;
7040 int error = FALSE;
7041
7042 if (argvars[0].v_type != VAR_LIST)
7043 EMSG2(_(e_listarg), "insert()");
7044 else if ((l = argvars[0].vval.v_list) != NULL
7045 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
7046 {
7047 if (argvars[2].v_type != VAR_UNKNOWN)
7048 before = (long)get_tv_number_chk(&argvars[2], &error);
7049 if (error)
7050 return; /* type error; errmsg already given */
7051
7052 if (before == l->lv_len)
7053 item = NULL;
7054 else
7055 {
7056 item = list_find(l, before);
7057 if (item == NULL)
7058 {
7059 EMSGN(_(e_listidx), before);
7060 l = NULL;
7061 }
7062 }
7063 if (l != NULL)
7064 {
7065 list_insert_tv(l, &argvars[1], item);
7066 copy_tv(&argvars[0], rettv);
7067 }
7068 }
7069}
7070
7071/*
7072 * "invert(expr)" function
7073 */
7074 static void
7075f_invert(typval_T *argvars, typval_T *rettv)
7076{
7077 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
7078}
7079
7080/*
7081 * "isdirectory()" function
7082 */
7083 static void
7084f_isdirectory(typval_T *argvars, typval_T *rettv)
7085{
7086 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
7087}
7088
7089/*
7090 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7091 * or it refers to a List or Dictionary that is locked.
7092 */
7093 static int
7094tv_islocked(typval_T *tv)
7095{
7096 return (tv->v_lock & VAR_LOCKED)
7097 || (tv->v_type == VAR_LIST
7098 && tv->vval.v_list != NULL
7099 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7100 || (tv->v_type == VAR_DICT
7101 && tv->vval.v_dict != NULL
7102 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7103}
7104
7105/*
7106 * "islocked()" function
7107 */
7108 static void
7109f_islocked(typval_T *argvars, typval_T *rettv)
7110{
7111 lval_T lv;
7112 char_u *end;
7113 dictitem_T *di;
7114
7115 rettv->vval.v_number = -1;
7116 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007117 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 if (end != NULL && lv.ll_name != NULL)
7119 {
7120 if (*end != NUL)
7121 EMSG(_(e_trailing));
7122 else
7123 {
7124 if (lv.ll_tv == NULL)
7125 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007126 di = find_var(lv.ll_name, NULL, TRUE);
7127 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007128 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007129 /* Consider a variable locked when:
7130 * 1. the variable itself is locked
7131 * 2. the value of the variable is locked.
7132 * 3. the List or Dict value is locked.
7133 */
7134 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7135 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 }
7137 }
7138 else if (lv.ll_range)
7139 EMSG(_("E786: Range not allowed"));
7140 else if (lv.ll_newkey != NULL)
7141 EMSG2(_(e_dictkey), lv.ll_newkey);
7142 else if (lv.ll_list != NULL)
7143 /* List item. */
7144 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7145 else
7146 /* Dictionary item. */
7147 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7148 }
7149 }
7150
7151 clear_lval(&lv);
7152}
7153
7154#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7155/*
7156 * "isnan()" function
7157 */
7158 static void
7159f_isnan(typval_T *argvars, typval_T *rettv)
7160{
7161 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7162 && isnan(argvars[0].vval.v_float);
7163}
7164#endif
7165
7166/*
7167 * "items(dict)" function
7168 */
7169 static void
7170f_items(typval_T *argvars, typval_T *rettv)
7171{
7172 dict_list(argvars, rettv, 2);
7173}
7174
7175#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7176/*
7177 * Get the job from the argument.
7178 * Returns NULL if the job is invalid.
7179 */
7180 static job_T *
7181get_job_arg(typval_T *tv)
7182{
7183 job_T *job;
7184
7185 if (tv->v_type != VAR_JOB)
7186 {
7187 EMSG2(_(e_invarg2), get_tv_string(tv));
7188 return NULL;
7189 }
7190 job = tv->vval.v_job;
7191
7192 if (job == NULL)
7193 EMSG(_("E916: not a valid job"));
7194 return job;
7195}
7196
7197/*
7198 * "job_getchannel()" function
7199 */
7200 static void
7201f_job_getchannel(typval_T *argvars, typval_T *rettv)
7202{
7203 job_T *job = get_job_arg(&argvars[0]);
7204
7205 if (job != NULL)
7206 {
7207 rettv->v_type = VAR_CHANNEL;
7208 rettv->vval.v_channel = job->jv_channel;
7209 if (job->jv_channel != NULL)
7210 ++job->jv_channel->ch_refcount;
7211 }
7212}
7213
7214/*
7215 * "job_info()" function
7216 */
7217 static void
7218f_job_info(typval_T *argvars, typval_T *rettv)
7219{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007220 if (argvars[0].v_type != VAR_UNKNOWN)
7221 {
7222 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007223
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007224 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7225 job_info(job, rettv->vval.v_dict);
7226 }
7227 else if (rettv_list_alloc(rettv) == OK)
7228 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229}
7230
7231/*
7232 * "job_setoptions()" function
7233 */
7234 static void
7235f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7236{
7237 job_T *job = get_job_arg(&argvars[0]);
7238 jobopt_T opt;
7239
7240 if (job == NULL)
7241 return;
7242 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007243 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007244 job_set_options(job, &opt);
7245 free_job_options(&opt);
7246}
7247
7248/*
7249 * "job_start()" function
7250 */
7251 static void
7252f_job_start(typval_T *argvars, typval_T *rettv)
7253{
7254 rettv->v_type = VAR_JOB;
7255 if (check_restricted() || check_secure())
7256 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007257 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258}
7259
7260/*
7261 * "job_status()" function
7262 */
7263 static void
7264f_job_status(typval_T *argvars, typval_T *rettv)
7265{
7266 job_T *job = get_job_arg(&argvars[0]);
7267
7268 if (job != NULL)
7269 {
7270 rettv->v_type = VAR_STRING;
7271 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7272 }
7273}
7274
7275/*
7276 * "job_stop()" function
7277 */
7278 static void
7279f_job_stop(typval_T *argvars, typval_T *rettv)
7280{
7281 job_T *job = get_job_arg(&argvars[0]);
7282
7283 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007284 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285}
7286#endif
7287
7288/*
7289 * "join()" function
7290 */
7291 static void
7292f_join(typval_T *argvars, typval_T *rettv)
7293{
7294 garray_T ga;
7295 char_u *sep;
7296
7297 if (argvars[0].v_type != VAR_LIST)
7298 {
7299 EMSG(_(e_listreq));
7300 return;
7301 }
7302 if (argvars[0].vval.v_list == NULL)
7303 return;
7304 if (argvars[1].v_type == VAR_UNKNOWN)
7305 sep = (char_u *)" ";
7306 else
7307 sep = get_tv_string_chk(&argvars[1]);
7308
7309 rettv->v_type = VAR_STRING;
7310
7311 if (sep != NULL)
7312 {
7313 ga_init2(&ga, (int)sizeof(char), 80);
7314 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7315 ga_append(&ga, NUL);
7316 rettv->vval.v_string = (char_u *)ga.ga_data;
7317 }
7318 else
7319 rettv->vval.v_string = NULL;
7320}
7321
7322/*
7323 * "js_decode()" function
7324 */
7325 static void
7326f_js_decode(typval_T *argvars, typval_T *rettv)
7327{
7328 js_read_T reader;
7329
7330 reader.js_buf = get_tv_string(&argvars[0]);
7331 reader.js_fill = NULL;
7332 reader.js_used = 0;
7333 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7334 EMSG(_(e_invarg));
7335}
7336
7337/*
7338 * "js_encode()" function
7339 */
7340 static void
7341f_js_encode(typval_T *argvars, typval_T *rettv)
7342{
7343 rettv->v_type = VAR_STRING;
7344 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7345}
7346
7347/*
7348 * "json_decode()" function
7349 */
7350 static void
7351f_json_decode(typval_T *argvars, typval_T *rettv)
7352{
7353 js_read_T reader;
7354
7355 reader.js_buf = get_tv_string(&argvars[0]);
7356 reader.js_fill = NULL;
7357 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007358 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007359}
7360
7361/*
7362 * "json_encode()" function
7363 */
7364 static void
7365f_json_encode(typval_T *argvars, typval_T *rettv)
7366{
7367 rettv->v_type = VAR_STRING;
7368 rettv->vval.v_string = json_encode(&argvars[0], 0);
7369}
7370
7371/*
7372 * "keys()" function
7373 */
7374 static void
7375f_keys(typval_T *argvars, typval_T *rettv)
7376{
7377 dict_list(argvars, rettv, 0);
7378}
7379
7380/*
7381 * "last_buffer_nr()" function.
7382 */
7383 static void
7384f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7385{
7386 int n = 0;
7387 buf_T *buf;
7388
Bram Moolenaar29323592016-07-24 22:04:11 +02007389 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007390 if (n < buf->b_fnum)
7391 n = buf->b_fnum;
7392
7393 rettv->vval.v_number = n;
7394}
7395
7396/*
7397 * "len()" function
7398 */
7399 static void
7400f_len(typval_T *argvars, typval_T *rettv)
7401{
7402 switch (argvars[0].v_type)
7403 {
7404 case VAR_STRING:
7405 case VAR_NUMBER:
7406 rettv->vval.v_number = (varnumber_T)STRLEN(
7407 get_tv_string(&argvars[0]));
7408 break;
7409 case VAR_LIST:
7410 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7411 break;
7412 case VAR_DICT:
7413 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7414 break;
7415 case VAR_UNKNOWN:
7416 case VAR_SPECIAL:
7417 case VAR_FLOAT:
7418 case VAR_FUNC:
7419 case VAR_PARTIAL:
7420 case VAR_JOB:
7421 case VAR_CHANNEL:
7422 EMSG(_("E701: Invalid type for len()"));
7423 break;
7424 }
7425}
7426
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007428libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007429{
7430#ifdef FEAT_LIBCALL
7431 char_u *string_in;
7432 char_u **string_result;
7433 int nr_result;
7434#endif
7435
7436 rettv->v_type = type;
7437 if (type != VAR_NUMBER)
7438 rettv->vval.v_string = NULL;
7439
7440 if (check_restricted() || check_secure())
7441 return;
7442
7443#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007444 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007445 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7446 {
7447 string_in = NULL;
7448 if (argvars[2].v_type == VAR_STRING)
7449 string_in = argvars[2].vval.v_string;
7450 if (type == VAR_NUMBER)
7451 string_result = NULL;
7452 else
7453 string_result = &rettv->vval.v_string;
7454 if (mch_libcall(argvars[0].vval.v_string,
7455 argvars[1].vval.v_string,
7456 string_in,
7457 argvars[2].vval.v_number,
7458 string_result,
7459 &nr_result) == OK
7460 && type == VAR_NUMBER)
7461 rettv->vval.v_number = nr_result;
7462 }
7463#endif
7464}
7465
7466/*
7467 * "libcall()" function
7468 */
7469 static void
7470f_libcall(typval_T *argvars, typval_T *rettv)
7471{
7472 libcall_common(argvars, rettv, VAR_STRING);
7473}
7474
7475/*
7476 * "libcallnr()" function
7477 */
7478 static void
7479f_libcallnr(typval_T *argvars, typval_T *rettv)
7480{
7481 libcall_common(argvars, rettv, VAR_NUMBER);
7482}
7483
7484/*
7485 * "line(string)" function
7486 */
7487 static void
7488f_line(typval_T *argvars, typval_T *rettv)
7489{
7490 linenr_T lnum = 0;
7491 pos_T *fp;
7492 int fnum;
7493
7494 fp = var2fpos(&argvars[0], TRUE, &fnum);
7495 if (fp != NULL)
7496 lnum = fp->lnum;
7497 rettv->vval.v_number = lnum;
7498}
7499
7500/*
7501 * "line2byte(lnum)" function
7502 */
7503 static void
7504f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7505{
7506#ifndef FEAT_BYTEOFF
7507 rettv->vval.v_number = -1;
7508#else
7509 linenr_T lnum;
7510
7511 lnum = get_tv_lnum(argvars);
7512 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7513 rettv->vval.v_number = -1;
7514 else
7515 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7516 if (rettv->vval.v_number >= 0)
7517 ++rettv->vval.v_number;
7518#endif
7519}
7520
7521/*
7522 * "lispindent(lnum)" function
7523 */
7524 static void
7525f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7526{
7527#ifdef FEAT_LISP
7528 pos_T pos;
7529 linenr_T lnum;
7530
7531 pos = curwin->w_cursor;
7532 lnum = get_tv_lnum(argvars);
7533 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7534 {
7535 curwin->w_cursor.lnum = lnum;
7536 rettv->vval.v_number = get_lisp_indent();
7537 curwin->w_cursor = pos;
7538 }
7539 else
7540#endif
7541 rettv->vval.v_number = -1;
7542}
7543
7544/*
7545 * "localtime()" function
7546 */
7547 static void
7548f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7549{
7550 rettv->vval.v_number = (varnumber_T)time(NULL);
7551}
7552
7553static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7554
7555 static void
7556get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7557{
7558 char_u *keys;
7559 char_u *which;
7560 char_u buf[NUMBUFLEN];
7561 char_u *keys_buf = NULL;
7562 char_u *rhs;
7563 int mode;
7564 int abbr = FALSE;
7565 int get_dict = FALSE;
7566 mapblock_T *mp;
7567 int buffer_local;
7568
7569 /* return empty string for failure */
7570 rettv->v_type = VAR_STRING;
7571 rettv->vval.v_string = NULL;
7572
7573 keys = get_tv_string(&argvars[0]);
7574 if (*keys == NUL)
7575 return;
7576
7577 if (argvars[1].v_type != VAR_UNKNOWN)
7578 {
7579 which = get_tv_string_buf_chk(&argvars[1], buf);
7580 if (argvars[2].v_type != VAR_UNKNOWN)
7581 {
7582 abbr = (int)get_tv_number(&argvars[2]);
7583 if (argvars[3].v_type != VAR_UNKNOWN)
7584 get_dict = (int)get_tv_number(&argvars[3]);
7585 }
7586 }
7587 else
7588 which = (char_u *)"";
7589 if (which == NULL)
7590 return;
7591
7592 mode = get_map_mode(&which, 0);
7593
7594 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7595 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7596 vim_free(keys_buf);
7597
7598 if (!get_dict)
7599 {
7600 /* Return a string. */
7601 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007602 {
7603 if (*rhs == NUL)
7604 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7605 else
7606 rettv->vval.v_string = str2special_save(rhs, FALSE);
7607 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007608
7609 }
7610 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7611 {
7612 /* Return a dictionary. */
7613 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7614 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7615 dict_T *dict = rettv->vval.v_dict;
7616
7617 dict_add_nr_str(dict, "lhs", 0L, lhs);
7618 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
7619 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7620 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
7621 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
7622 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
7623 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
7624 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
7625 dict_add_nr_str(dict, "mode", 0L, mapmode);
7626
7627 vim_free(lhs);
7628 vim_free(mapmode);
7629 }
7630}
7631
7632#ifdef FEAT_FLOAT
7633/*
7634 * "log()" function
7635 */
7636 static void
7637f_log(typval_T *argvars, typval_T *rettv)
7638{
7639 float_T f = 0.0;
7640
7641 rettv->v_type = VAR_FLOAT;
7642 if (get_float_arg(argvars, &f) == OK)
7643 rettv->vval.v_float = log(f);
7644 else
7645 rettv->vval.v_float = 0.0;
7646}
7647
7648/*
7649 * "log10()" function
7650 */
7651 static void
7652f_log10(typval_T *argvars, typval_T *rettv)
7653{
7654 float_T f = 0.0;
7655
7656 rettv->v_type = VAR_FLOAT;
7657 if (get_float_arg(argvars, &f) == OK)
7658 rettv->vval.v_float = log10(f);
7659 else
7660 rettv->vval.v_float = 0.0;
7661}
7662#endif
7663
7664#ifdef FEAT_LUA
7665/*
7666 * "luaeval()" function
7667 */
7668 static void
7669f_luaeval(typval_T *argvars, typval_T *rettv)
7670{
7671 char_u *str;
7672 char_u buf[NUMBUFLEN];
7673
7674 str = get_tv_string_buf(&argvars[0], buf);
7675 do_luaeval(str, argvars + 1, rettv);
7676}
7677#endif
7678
7679/*
7680 * "map()" function
7681 */
7682 static void
7683f_map(typval_T *argvars, typval_T *rettv)
7684{
7685 filter_map(argvars, rettv, TRUE);
7686}
7687
7688/*
7689 * "maparg()" function
7690 */
7691 static void
7692f_maparg(typval_T *argvars, typval_T *rettv)
7693{
7694 get_maparg(argvars, rettv, TRUE);
7695}
7696
7697/*
7698 * "mapcheck()" function
7699 */
7700 static void
7701f_mapcheck(typval_T *argvars, typval_T *rettv)
7702{
7703 get_maparg(argvars, rettv, FALSE);
7704}
7705
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007706typedef enum
7707{
7708 MATCH_END, /* matchend() */
7709 MATCH_MATCH, /* match() */
7710 MATCH_STR, /* matchstr() */
7711 MATCH_LIST, /* matchlist() */
7712 MATCH_POS /* matchstrpos() */
7713} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714
7715 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007716find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717{
7718 char_u *str = NULL;
7719 long len = 0;
7720 char_u *expr = NULL;
7721 char_u *pat;
7722 regmatch_T regmatch;
7723 char_u patbuf[NUMBUFLEN];
7724 char_u strbuf[NUMBUFLEN];
7725 char_u *save_cpo;
7726 long start = 0;
7727 long nth = 1;
7728 colnr_T startcol = 0;
7729 int match = 0;
7730 list_T *l = NULL;
7731 listitem_T *li = NULL;
7732 long idx = 0;
7733 char_u *tofree = NULL;
7734
7735 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7736 save_cpo = p_cpo;
7737 p_cpo = (char_u *)"";
7738
7739 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007740 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007741 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007742 /* type MATCH_LIST: return empty list when there are no matches.
7743 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 if (rettv_list_alloc(rettv) == FAIL)
7745 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007746 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747 && (list_append_string(rettv->vval.v_list,
7748 (char_u *)"", 0) == FAIL
7749 || list_append_number(rettv->vval.v_list,
7750 (varnumber_T)-1) == FAIL
7751 || list_append_number(rettv->vval.v_list,
7752 (varnumber_T)-1) == FAIL
7753 || list_append_number(rettv->vval.v_list,
7754 (varnumber_T)-1) == FAIL))
7755 {
7756 list_free(rettv->vval.v_list);
7757 rettv->vval.v_list = NULL;
7758 goto theend;
7759 }
7760 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007761 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007762 {
7763 rettv->v_type = VAR_STRING;
7764 rettv->vval.v_string = NULL;
7765 }
7766
7767 if (argvars[0].v_type == VAR_LIST)
7768 {
7769 if ((l = argvars[0].vval.v_list) == NULL)
7770 goto theend;
7771 li = l->lv_first;
7772 }
7773 else
7774 {
7775 expr = str = get_tv_string(&argvars[0]);
7776 len = (long)STRLEN(str);
7777 }
7778
7779 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7780 if (pat == NULL)
7781 goto theend;
7782
7783 if (argvars[2].v_type != VAR_UNKNOWN)
7784 {
7785 int error = FALSE;
7786
7787 start = (long)get_tv_number_chk(&argvars[2], &error);
7788 if (error)
7789 goto theend;
7790 if (l != NULL)
7791 {
7792 li = list_find(l, start);
7793 if (li == NULL)
7794 goto theend;
7795 idx = l->lv_idx; /* use the cached index */
7796 }
7797 else
7798 {
7799 if (start < 0)
7800 start = 0;
7801 if (start > len)
7802 goto theend;
7803 /* When "count" argument is there ignore matches before "start",
7804 * otherwise skip part of the string. Differs when pattern is "^"
7805 * or "\<". */
7806 if (argvars[3].v_type != VAR_UNKNOWN)
7807 startcol = start;
7808 else
7809 {
7810 str += start;
7811 len -= start;
7812 }
7813 }
7814
7815 if (argvars[3].v_type != VAR_UNKNOWN)
7816 nth = (long)get_tv_number_chk(&argvars[3], &error);
7817 if (error)
7818 goto theend;
7819 }
7820
7821 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7822 if (regmatch.regprog != NULL)
7823 {
7824 regmatch.rm_ic = p_ic;
7825
7826 for (;;)
7827 {
7828 if (l != NULL)
7829 {
7830 if (li == NULL)
7831 {
7832 match = FALSE;
7833 break;
7834 }
7835 vim_free(tofree);
7836 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7837 if (str == NULL)
7838 break;
7839 }
7840
7841 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7842
7843 if (match && --nth <= 0)
7844 break;
7845 if (l == NULL && !match)
7846 break;
7847
7848 /* Advance to just after the match. */
7849 if (l != NULL)
7850 {
7851 li = li->li_next;
7852 ++idx;
7853 }
7854 else
7855 {
7856#ifdef FEAT_MBYTE
7857 startcol = (colnr_T)(regmatch.startp[0]
7858 + (*mb_ptr2len)(regmatch.startp[0]) - str);
7859#else
7860 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7861#endif
7862 if (startcol > (colnr_T)len
7863 || str + startcol <= regmatch.startp[0])
7864 {
7865 match = FALSE;
7866 break;
7867 }
7868 }
7869 }
7870
7871 if (match)
7872 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007873 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 {
7875 listitem_T *li1 = rettv->vval.v_list->lv_first;
7876 listitem_T *li2 = li1->li_next;
7877 listitem_T *li3 = li2->li_next;
7878 listitem_T *li4 = li3->li_next;
7879
7880 vim_free(li1->li_tv.vval.v_string);
7881 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7882 (int)(regmatch.endp[0] - regmatch.startp[0]));
7883 li3->li_tv.vval.v_number =
7884 (varnumber_T)(regmatch.startp[0] - expr);
7885 li4->li_tv.vval.v_number =
7886 (varnumber_T)(regmatch.endp[0] - expr);
7887 if (l != NULL)
7888 li2->li_tv.vval.v_number = (varnumber_T)idx;
7889 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007890 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007891 {
7892 int i;
7893
7894 /* return list with matched string and submatches */
7895 for (i = 0; i < NSUBEXP; ++i)
7896 {
7897 if (regmatch.endp[i] == NULL)
7898 {
7899 if (list_append_string(rettv->vval.v_list,
7900 (char_u *)"", 0) == FAIL)
7901 break;
7902 }
7903 else if (list_append_string(rettv->vval.v_list,
7904 regmatch.startp[i],
7905 (int)(regmatch.endp[i] - regmatch.startp[i]))
7906 == FAIL)
7907 break;
7908 }
7909 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007910 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007911 {
7912 /* return matched string */
7913 if (l != NULL)
7914 copy_tv(&li->li_tv, rettv);
7915 else
7916 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7917 (int)(regmatch.endp[0] - regmatch.startp[0]));
7918 }
7919 else if (l != NULL)
7920 rettv->vval.v_number = idx;
7921 else
7922 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007923 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924 rettv->vval.v_number =
7925 (varnumber_T)(regmatch.startp[0] - str);
7926 else
7927 rettv->vval.v_number =
7928 (varnumber_T)(regmatch.endp[0] - str);
7929 rettv->vval.v_number += (varnumber_T)(str - expr);
7930 }
7931 }
7932 vim_regfree(regmatch.regprog);
7933 }
7934
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007935theend:
7936 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 /* matchstrpos() without a list: drop the second item. */
7938 listitem_remove(rettv->vval.v_list,
7939 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007940 vim_free(tofree);
7941 p_cpo = save_cpo;
7942}
7943
7944/*
7945 * "match()" function
7946 */
7947 static void
7948f_match(typval_T *argvars, typval_T *rettv)
7949{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007950 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951}
7952
7953/*
7954 * "matchadd()" function
7955 */
7956 static void
7957f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7958{
7959#ifdef FEAT_SEARCH_EXTRA
7960 char_u buf[NUMBUFLEN];
7961 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7962 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7963 int prio = 10; /* default priority */
7964 int id = -1;
7965 int error = FALSE;
7966 char_u *conceal_char = NULL;
7967
7968 rettv->vval.v_number = -1;
7969
7970 if (grp == NULL || pat == NULL)
7971 return;
7972 if (argvars[2].v_type != VAR_UNKNOWN)
7973 {
7974 prio = (int)get_tv_number_chk(&argvars[2], &error);
7975 if (argvars[3].v_type != VAR_UNKNOWN)
7976 {
7977 id = (int)get_tv_number_chk(&argvars[3], &error);
7978 if (argvars[4].v_type != VAR_UNKNOWN)
7979 {
7980 if (argvars[4].v_type != VAR_DICT)
7981 {
7982 EMSG(_(e_dictreq));
7983 return;
7984 }
7985 if (dict_find(argvars[4].vval.v_dict,
7986 (char_u *)"conceal", -1) != NULL)
7987 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7988 (char_u *)"conceal", FALSE);
7989 }
7990 }
7991 }
7992 if (error == TRUE)
7993 return;
7994 if (id >= 1 && id <= 3)
7995 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02007996 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997 return;
7998 }
7999
8000 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
8001 conceal_char);
8002#endif
8003}
8004
8005/*
8006 * "matchaddpos()" function
8007 */
8008 static void
8009f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8010{
8011#ifdef FEAT_SEARCH_EXTRA
8012 char_u buf[NUMBUFLEN];
8013 char_u *group;
8014 int prio = 10;
8015 int id = -1;
8016 int error = FALSE;
8017 list_T *l;
8018 char_u *conceal_char = NULL;
8019
8020 rettv->vval.v_number = -1;
8021
8022 group = get_tv_string_buf_chk(&argvars[0], buf);
8023 if (group == NULL)
8024 return;
8025
8026 if (argvars[1].v_type != VAR_LIST)
8027 {
8028 EMSG2(_(e_listarg), "matchaddpos()");
8029 return;
8030 }
8031 l = argvars[1].vval.v_list;
8032 if (l == NULL)
8033 return;
8034
8035 if (argvars[2].v_type != VAR_UNKNOWN)
8036 {
8037 prio = (int)get_tv_number_chk(&argvars[2], &error);
8038 if (argvars[3].v_type != VAR_UNKNOWN)
8039 {
8040 id = (int)get_tv_number_chk(&argvars[3], &error);
8041 if (argvars[4].v_type != VAR_UNKNOWN)
8042 {
8043 if (argvars[4].v_type != VAR_DICT)
8044 {
8045 EMSG(_(e_dictreq));
8046 return;
8047 }
8048 if (dict_find(argvars[4].vval.v_dict,
8049 (char_u *)"conceal", -1) != NULL)
8050 conceal_char = get_dict_string(argvars[4].vval.v_dict,
8051 (char_u *)"conceal", FALSE);
8052 }
8053 }
8054 }
8055 if (error == TRUE)
8056 return;
8057
8058 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8059 if (id == 1 || id == 2)
8060 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02008061 EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008062 return;
8063 }
8064
8065 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
8066 conceal_char);
8067#endif
8068}
8069
8070/*
8071 * "matcharg()" function
8072 */
8073 static void
8074f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8075{
8076 if (rettv_list_alloc(rettv) == OK)
8077 {
8078#ifdef FEAT_SEARCH_EXTRA
8079 int id = (int)get_tv_number(&argvars[0]);
8080 matchitem_T *m;
8081
8082 if (id >= 1 && id <= 3)
8083 {
8084 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8085 {
8086 list_append_string(rettv->vval.v_list,
8087 syn_id2name(m->hlg_id), -1);
8088 list_append_string(rettv->vval.v_list, m->pattern, -1);
8089 }
8090 else
8091 {
8092 list_append_string(rettv->vval.v_list, NULL, -1);
8093 list_append_string(rettv->vval.v_list, NULL, -1);
8094 }
8095 }
8096#endif
8097 }
8098}
8099
8100/*
8101 * "matchdelete()" function
8102 */
8103 static void
8104f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8105{
8106#ifdef FEAT_SEARCH_EXTRA
8107 rettv->vval.v_number = match_delete(curwin,
8108 (int)get_tv_number(&argvars[0]), TRUE);
8109#endif
8110}
8111
8112/*
8113 * "matchend()" function
8114 */
8115 static void
8116f_matchend(typval_T *argvars, typval_T *rettv)
8117{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008118 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119}
8120
8121/*
8122 * "matchlist()" function
8123 */
8124 static void
8125f_matchlist(typval_T *argvars, typval_T *rettv)
8126{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008127 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128}
8129
8130/*
8131 * "matchstr()" function
8132 */
8133 static void
8134f_matchstr(typval_T *argvars, typval_T *rettv)
8135{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008136 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137}
8138
8139/*
8140 * "matchstrpos()" function
8141 */
8142 static void
8143f_matchstrpos(typval_T *argvars, typval_T *rettv)
8144{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008145 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146}
8147
8148static void max_min(typval_T *argvars, typval_T *rettv, int domax);
8149
8150 static void
8151max_min(typval_T *argvars, typval_T *rettv, int domax)
8152{
8153 varnumber_T n = 0;
8154 varnumber_T i;
8155 int error = FALSE;
8156
8157 if (argvars[0].v_type == VAR_LIST)
8158 {
8159 list_T *l;
8160 listitem_T *li;
8161
8162 l = argvars[0].vval.v_list;
8163 if (l != NULL)
8164 {
8165 li = l->lv_first;
8166 if (li != NULL)
8167 {
8168 n = get_tv_number_chk(&li->li_tv, &error);
8169 for (;;)
8170 {
8171 li = li->li_next;
8172 if (li == NULL)
8173 break;
8174 i = get_tv_number_chk(&li->li_tv, &error);
8175 if (domax ? i > n : i < n)
8176 n = i;
8177 }
8178 }
8179 }
8180 }
8181 else if (argvars[0].v_type == VAR_DICT)
8182 {
8183 dict_T *d;
8184 int first = TRUE;
8185 hashitem_T *hi;
8186 int todo;
8187
8188 d = argvars[0].vval.v_dict;
8189 if (d != NULL)
8190 {
8191 todo = (int)d->dv_hashtab.ht_used;
8192 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8193 {
8194 if (!HASHITEM_EMPTY(hi))
8195 {
8196 --todo;
8197 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
8198 if (first)
8199 {
8200 n = i;
8201 first = FALSE;
8202 }
8203 else if (domax ? i > n : i < n)
8204 n = i;
8205 }
8206 }
8207 }
8208 }
8209 else
Bram Moolenaar26b84332016-09-04 21:42:36 +02008210 EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 rettv->vval.v_number = error ? 0 : n;
8212}
8213
8214/*
8215 * "max()" function
8216 */
8217 static void
8218f_max(typval_T *argvars, typval_T *rettv)
8219{
8220 max_min(argvars, rettv, TRUE);
8221}
8222
8223/*
8224 * "min()" function
8225 */
8226 static void
8227f_min(typval_T *argvars, typval_T *rettv)
8228{
8229 max_min(argvars, rettv, FALSE);
8230}
8231
8232static int mkdir_recurse(char_u *dir, int prot);
8233
8234/*
8235 * Create the directory in which "dir" is located, and higher levels when
8236 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008237 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238 */
8239 static int
8240mkdir_recurse(char_u *dir, int prot)
8241{
8242 char_u *p;
8243 char_u *updir;
8244 int r = FAIL;
8245
8246 /* Get end of directory name in "dir".
8247 * We're done when it's "/" or "c:/". */
8248 p = gettail_sep(dir);
8249 if (p <= get_past_head(dir))
8250 return OK;
8251
8252 /* If the directory exists we're done. Otherwise: create it.*/
8253 updir = vim_strnsave(dir, (int)(p - dir));
8254 if (updir == NULL)
8255 return FAIL;
8256 if (mch_isdir(updir))
8257 r = OK;
8258 else if (mkdir_recurse(updir, prot) == OK)
8259 r = vim_mkdir_emsg(updir, prot);
8260 vim_free(updir);
8261 return r;
8262}
8263
8264#ifdef vim_mkdir
8265/*
8266 * "mkdir()" function
8267 */
8268 static void
8269f_mkdir(typval_T *argvars, typval_T *rettv)
8270{
8271 char_u *dir;
8272 char_u buf[NUMBUFLEN];
8273 int prot = 0755;
8274
8275 rettv->vval.v_number = FAIL;
8276 if (check_restricted() || check_secure())
8277 return;
8278
8279 dir = get_tv_string_buf(&argvars[0], buf);
8280 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008281 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008282
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008283 if (*gettail(dir) == NUL)
8284 /* remove trailing slashes */
8285 *gettail_sep(dir) = NUL;
8286
8287 if (argvars[1].v_type != VAR_UNKNOWN)
8288 {
8289 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008290 {
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008291 prot = (int)get_tv_number_chk(&argvars[2], NULL);
8292 if (prot == -1)
8293 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008294 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008295 if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8296 {
8297 if (mch_isdir(dir))
8298 {
8299 /* With the "p" flag it's OK if the dir already exists. */
8300 rettv->vval.v_number = OK;
8301 return;
8302 }
8303 mkdir_recurse(dir, prot);
8304 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008306 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008307}
8308#endif
8309
8310/*
8311 * "mode()" function
8312 */
8313 static void
8314f_mode(typval_T *argvars, typval_T *rettv)
8315{
8316 char_u buf[3];
8317
8318 buf[1] = NUL;
8319 buf[2] = NUL;
8320
8321 if (time_for_testing == 93784)
8322 {
8323 /* Testing the two-character code. */
8324 buf[0] = 'x';
8325 buf[1] = '!';
8326 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008327#ifdef FEAT_TERMINAL
8328 else if (term_use_loop())
8329 buf[0] = 't';
8330#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008331 else if (VIsual_active)
8332 {
8333 if (VIsual_select)
8334 buf[0] = VIsual_mode + 's' - 'v';
8335 else
8336 buf[0] = VIsual_mode;
8337 }
8338 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8339 || State == CONFIRM)
8340 {
8341 buf[0] = 'r';
8342 if (State == ASKMORE)
8343 buf[1] = 'm';
8344 else if (State == CONFIRM)
8345 buf[1] = '?';
8346 }
8347 else if (State == EXTERNCMD)
8348 buf[0] = '!';
8349 else if (State & INSERT)
8350 {
8351#ifdef FEAT_VREPLACE
8352 if (State & VREPLACE_FLAG)
8353 {
8354 buf[0] = 'R';
8355 buf[1] = 'v';
8356 }
8357 else
8358#endif
Bram Moolenaare90858d2017-02-01 17:24:34 +01008359 {
8360 if (State & REPLACE_FLAG)
8361 buf[0] = 'R';
8362 else
8363 buf[0] = 'i';
8364#ifdef FEAT_INS_EXPAND
8365 if (ins_compl_active())
8366 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008367 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008368 buf[1] = 'x';
8369#endif
8370 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008372 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008373 {
8374 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008375 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008377 else if (exmode_active == EXMODE_NORMAL)
8378 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008379 }
8380 else
8381 {
8382 buf[0] = 'n';
8383 if (finish_op)
8384 buf[1] = 'o';
8385 }
8386
8387 /* Clear out the minor mode when the argument is not a non-zero number or
8388 * non-empty string. */
8389 if (!non_zero_arg(&argvars[0]))
8390 buf[1] = NUL;
8391
8392 rettv->vval.v_string = vim_strsave(buf);
8393 rettv->v_type = VAR_STRING;
8394}
8395
8396#if defined(FEAT_MZSCHEME) || defined(PROTO)
8397/*
8398 * "mzeval()" function
8399 */
8400 static void
8401f_mzeval(typval_T *argvars, typval_T *rettv)
8402{
8403 char_u *str;
8404 char_u buf[NUMBUFLEN];
8405
8406 str = get_tv_string_buf(&argvars[0], buf);
8407 do_mzeval(str, rettv);
8408}
8409
8410 void
8411mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8412{
8413 typval_T argvars[3];
8414
8415 argvars[0].v_type = VAR_STRING;
8416 argvars[0].vval.v_string = name;
8417 copy_tv(args, &argvars[1]);
8418 argvars[2].v_type = VAR_UNKNOWN;
8419 f_call(argvars, rettv);
8420 clear_tv(&argvars[1]);
8421}
8422#endif
8423
8424/*
8425 * "nextnonblank()" function
8426 */
8427 static void
8428f_nextnonblank(typval_T *argvars, typval_T *rettv)
8429{
8430 linenr_T lnum;
8431
8432 for (lnum = get_tv_lnum(argvars); ; ++lnum)
8433 {
8434 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8435 {
8436 lnum = 0;
8437 break;
8438 }
8439 if (*skipwhite(ml_get(lnum)) != NUL)
8440 break;
8441 }
8442 rettv->vval.v_number = lnum;
8443}
8444
8445/*
8446 * "nr2char()" function
8447 */
8448 static void
8449f_nr2char(typval_T *argvars, typval_T *rettv)
8450{
8451 char_u buf[NUMBUFLEN];
8452
8453#ifdef FEAT_MBYTE
8454 if (has_mbyte)
8455 {
8456 int utf8 = 0;
8457
8458 if (argvars[1].v_type != VAR_UNKNOWN)
8459 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8460 if (utf8)
8461 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8462 else
8463 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
8464 }
8465 else
8466#endif
8467 {
8468 buf[0] = (char_u)get_tv_number(&argvars[0]);
8469 buf[1] = NUL;
8470 }
8471 rettv->v_type = VAR_STRING;
8472 rettv->vval.v_string = vim_strsave(buf);
8473}
8474
8475/*
8476 * "or(expr, expr)" function
8477 */
8478 static void
8479f_or(typval_T *argvars, typval_T *rettv)
8480{
8481 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
8482 | get_tv_number_chk(&argvars[1], NULL);
8483}
8484
8485/*
8486 * "pathshorten()" function
8487 */
8488 static void
8489f_pathshorten(typval_T *argvars, typval_T *rettv)
8490{
8491 char_u *p;
8492
8493 rettv->v_type = VAR_STRING;
8494 p = get_tv_string_chk(&argvars[0]);
8495 if (p == NULL)
8496 rettv->vval.v_string = NULL;
8497 else
8498 {
8499 p = vim_strsave(p);
8500 rettv->vval.v_string = p;
8501 if (p != NULL)
8502 shorten_dir(p);
8503 }
8504}
8505
8506#ifdef FEAT_PERL
8507/*
8508 * "perleval()" function
8509 */
8510 static void
8511f_perleval(typval_T *argvars, typval_T *rettv)
8512{
8513 char_u *str;
8514 char_u buf[NUMBUFLEN];
8515
8516 str = get_tv_string_buf(&argvars[0], buf);
8517 do_perleval(str, rettv);
8518}
8519#endif
8520
8521#ifdef FEAT_FLOAT
8522/*
8523 * "pow()" function
8524 */
8525 static void
8526f_pow(typval_T *argvars, typval_T *rettv)
8527{
8528 float_T fx = 0.0, fy = 0.0;
8529
8530 rettv->v_type = VAR_FLOAT;
8531 if (get_float_arg(argvars, &fx) == OK
8532 && get_float_arg(&argvars[1], &fy) == OK)
8533 rettv->vval.v_float = pow(fx, fy);
8534 else
8535 rettv->vval.v_float = 0.0;
8536}
8537#endif
8538
8539/*
8540 * "prevnonblank()" function
8541 */
8542 static void
8543f_prevnonblank(typval_T *argvars, typval_T *rettv)
8544{
8545 linenr_T lnum;
8546
8547 lnum = get_tv_lnum(argvars);
8548 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8549 lnum = 0;
8550 else
8551 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8552 --lnum;
8553 rettv->vval.v_number = lnum;
8554}
8555
8556/* This dummy va_list is here because:
8557 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8558 * - locally in the function results in a "used before set" warning
8559 * - using va_start() to initialize it gives "function with fixed args" error */
8560static va_list ap;
8561
8562/*
8563 * "printf()" function
8564 */
8565 static void
8566f_printf(typval_T *argvars, typval_T *rettv)
8567{
8568 char_u buf[NUMBUFLEN];
8569 int len;
8570 char_u *s;
8571 int saved_did_emsg = did_emsg;
8572 char *fmt;
8573
8574 rettv->v_type = VAR_STRING;
8575 rettv->vval.v_string = NULL;
8576
8577 /* Get the required length, allocate the buffer and do it for real. */
8578 did_emsg = FALSE;
8579 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008580 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008581 if (!did_emsg)
8582 {
8583 s = alloc(len + 1);
8584 if (s != NULL)
8585 {
8586 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008587 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8588 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008589 }
8590 }
8591 did_emsg |= saved_did_emsg;
8592}
8593
Bram Moolenaarf2732452018-06-03 14:47:35 +02008594#ifdef FEAT_JOB_CHANNEL
8595/*
8596 * "prompt_setcallback({buffer}, {callback})" function
8597 */
8598 static void
8599f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8600{
8601 buf_T *buf;
8602 char_u *callback;
8603 partial_T *partial;
8604
8605 if (check_secure())
8606 return;
8607 buf = get_buf_tv(&argvars[0], FALSE);
8608 if (buf == NULL)
8609 return;
8610
8611 callback = get_callback(&argvars[1], &partial);
8612 if (callback == NULL)
8613 return;
8614
8615 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8616 if (partial == NULL)
8617 buf->b_prompt_callback = vim_strsave(callback);
8618 else
8619 /* pointer into the partial */
8620 buf->b_prompt_callback = callback;
8621 buf->b_prompt_partial = partial;
8622}
8623
8624/*
8625 * "prompt_setprompt({buffer}, {text})" function
8626 */
8627 static void
8628f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8629{
8630 buf_T *buf;
8631 char_u *text;
8632
8633 if (check_secure())
8634 return;
8635 buf = get_buf_tv(&argvars[0], FALSE);
8636 if (buf == NULL)
8637 return;
8638
8639 text = get_tv_string(&argvars[1]);
8640 vim_free(buf->b_prompt_text);
8641 buf->b_prompt_text = vim_strsave(text);
8642}
8643#endif
8644
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008645/*
8646 * "pumvisible()" function
8647 */
8648 static void
8649f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8650{
8651#ifdef FEAT_INS_EXPAND
8652 if (pum_visible())
8653 rettv->vval.v_number = 1;
8654#endif
8655}
8656
8657#ifdef FEAT_PYTHON3
8658/*
8659 * "py3eval()" function
8660 */
8661 static void
8662f_py3eval(typval_T *argvars, typval_T *rettv)
8663{
8664 char_u *str;
8665 char_u buf[NUMBUFLEN];
8666
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008667 if (p_pyx == 0)
8668 p_pyx = 3;
8669
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008670 str = get_tv_string_buf(&argvars[0], buf);
8671 do_py3eval(str, rettv);
8672}
8673#endif
8674
8675#ifdef FEAT_PYTHON
8676/*
8677 * "pyeval()" function
8678 */
8679 static void
8680f_pyeval(typval_T *argvars, typval_T *rettv)
8681{
8682 char_u *str;
8683 char_u buf[NUMBUFLEN];
8684
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008685 if (p_pyx == 0)
8686 p_pyx = 2;
8687
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008688 str = get_tv_string_buf(&argvars[0], buf);
8689 do_pyeval(str, rettv);
8690}
8691#endif
8692
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008693#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8694/*
8695 * "pyxeval()" function
8696 */
8697 static void
8698f_pyxeval(typval_T *argvars, typval_T *rettv)
8699{
8700# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8701 init_pyxversion();
8702 if (p_pyx == 2)
8703 f_pyeval(argvars, rettv);
8704 else
8705 f_py3eval(argvars, rettv);
8706# elif defined(FEAT_PYTHON)
8707 f_pyeval(argvars, rettv);
8708# elif defined(FEAT_PYTHON3)
8709 f_py3eval(argvars, rettv);
8710# endif
8711}
8712#endif
8713
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008714/*
8715 * "range()" function
8716 */
8717 static void
8718f_range(typval_T *argvars, typval_T *rettv)
8719{
8720 varnumber_T start;
8721 varnumber_T end;
8722 varnumber_T stride = 1;
8723 varnumber_T i;
8724 int error = FALSE;
8725
8726 start = get_tv_number_chk(&argvars[0], &error);
8727 if (argvars[1].v_type == VAR_UNKNOWN)
8728 {
8729 end = start - 1;
8730 start = 0;
8731 }
8732 else
8733 {
8734 end = get_tv_number_chk(&argvars[1], &error);
8735 if (argvars[2].v_type != VAR_UNKNOWN)
8736 stride = get_tv_number_chk(&argvars[2], &error);
8737 }
8738
8739 if (error)
8740 return; /* type error; errmsg already given */
8741 if (stride == 0)
8742 EMSG(_("E726: Stride is zero"));
8743 else if (stride > 0 ? end + 1 < start : end - 1 > start)
8744 EMSG(_("E727: Start past end"));
8745 else
8746 {
8747 if (rettv_list_alloc(rettv) == OK)
8748 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8749 if (list_append_number(rettv->vval.v_list,
8750 (varnumber_T)i) == FAIL)
8751 break;
8752 }
8753}
8754
8755/*
8756 * "readfile()" function
8757 */
8758 static void
8759f_readfile(typval_T *argvars, typval_T *rettv)
8760{
8761 int binary = FALSE;
8762 int failed = FALSE;
8763 char_u *fname;
8764 FILE *fd;
8765 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8766 int io_size = sizeof(buf);
8767 int readlen; /* size of last fread() */
8768 char_u *prev = NULL; /* previously read bytes, if any */
8769 long prevlen = 0; /* length of data in prev */
8770 long prevsize = 0; /* size of prev buffer */
8771 long maxline = MAXLNUM;
8772 long cnt = 0;
8773 char_u *p; /* position in buf */
8774 char_u *start; /* start of current line */
8775
8776 if (argvars[1].v_type != VAR_UNKNOWN)
8777 {
8778 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8779 binary = TRUE;
8780 if (argvars[2].v_type != VAR_UNKNOWN)
8781 maxline = (long)get_tv_number(&argvars[2]);
8782 }
8783
8784 if (rettv_list_alloc(rettv) == FAIL)
8785 return;
8786
8787 /* Always open the file in binary mode, library functions have a mind of
8788 * their own about CR-LF conversion. */
8789 fname = get_tv_string(&argvars[0]);
8790 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8791 {
8792 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8793 return;
8794 }
8795
8796 while (cnt < maxline || maxline < 0)
8797 {
8798 readlen = (int)fread(buf, 1, io_size, fd);
8799
8800 /* This for loop processes what was read, but is also entered at end
8801 * of file so that either:
8802 * - an incomplete line gets written
8803 * - a "binary" file gets an empty line at the end if it ends in a
8804 * newline. */
8805 for (p = buf, start = buf;
8806 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8807 ++p)
8808 {
8809 if (*p == '\n' || readlen <= 0)
8810 {
8811 listitem_T *li;
8812 char_u *s = NULL;
8813 long_u len = p - start;
8814
8815 /* Finished a line. Remove CRs before NL. */
8816 if (readlen > 0 && !binary)
8817 {
8818 while (len > 0 && start[len - 1] == '\r')
8819 --len;
8820 /* removal may cross back to the "prev" string */
8821 if (len == 0)
8822 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8823 --prevlen;
8824 }
8825 if (prevlen == 0)
8826 s = vim_strnsave(start, (int)len);
8827 else
8828 {
8829 /* Change "prev" buffer to be the right size. This way
8830 * the bytes are only copied once, and very long lines are
8831 * allocated only once. */
8832 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8833 {
8834 mch_memmove(s + prevlen, start, len);
8835 s[prevlen + len] = NUL;
8836 prev = NULL; /* the list will own the string */
8837 prevlen = prevsize = 0;
8838 }
8839 }
8840 if (s == NULL)
8841 {
8842 do_outofmem_msg((long_u) prevlen + len + 1);
8843 failed = TRUE;
8844 break;
8845 }
8846
8847 if ((li = listitem_alloc()) == NULL)
8848 {
8849 vim_free(s);
8850 failed = TRUE;
8851 break;
8852 }
8853 li->li_tv.v_type = VAR_STRING;
8854 li->li_tv.v_lock = 0;
8855 li->li_tv.vval.v_string = s;
8856 list_append(rettv->vval.v_list, li);
8857
8858 start = p + 1; /* step over newline */
8859 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8860 break;
8861 }
8862 else if (*p == NUL)
8863 *p = '\n';
8864#ifdef FEAT_MBYTE
8865 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8866 * when finding the BF and check the previous two bytes. */
8867 else if (*p == 0xbf && enc_utf8 && !binary)
8868 {
8869 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8870 * + 1, these may be in the "prev" string. */
8871 char_u back1 = p >= buf + 1 ? p[-1]
8872 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8873 char_u back2 = p >= buf + 2 ? p[-2]
8874 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8875 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8876
8877 if (back2 == 0xef && back1 == 0xbb)
8878 {
8879 char_u *dest = p - 2;
8880
8881 /* Usually a BOM is at the beginning of a file, and so at
8882 * the beginning of a line; then we can just step over it.
8883 */
8884 if (start == dest)
8885 start = p + 1;
8886 else
8887 {
8888 /* have to shuffle buf to close gap */
8889 int adjust_prevlen = 0;
8890
8891 if (dest < buf)
8892 {
8893 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8894 dest = buf;
8895 }
8896 if (readlen > p - buf + 1)
8897 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8898 readlen -= 3 - adjust_prevlen;
8899 prevlen -= adjust_prevlen;
8900 p = dest - 1;
8901 }
8902 }
8903 }
8904#endif
8905 } /* for */
8906
8907 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8908 break;
8909 if (start < p)
8910 {
8911 /* There's part of a line in buf, store it in "prev". */
8912 if (p - start + prevlen >= prevsize)
8913 {
8914 /* need bigger "prev" buffer */
8915 char_u *newprev;
8916
8917 /* A common use case is ordinary text files and "prev" gets a
8918 * fragment of a line, so the first allocation is made
8919 * small, to avoid repeatedly 'allocing' large and
8920 * 'reallocing' small. */
8921 if (prevsize == 0)
8922 prevsize = (long)(p - start);
8923 else
8924 {
8925 long grow50pc = (prevsize * 3) / 2;
8926 long growmin = (long)((p - start) * 2 + prevlen);
8927 prevsize = grow50pc > growmin ? grow50pc : growmin;
8928 }
8929 newprev = prev == NULL ? alloc(prevsize)
8930 : vim_realloc(prev, prevsize);
8931 if (newprev == NULL)
8932 {
8933 do_outofmem_msg((long_u)prevsize);
8934 failed = TRUE;
8935 break;
8936 }
8937 prev = newprev;
8938 }
8939 /* Add the line part to end of "prev". */
8940 mch_memmove(prev + prevlen, start, p - start);
8941 prevlen += (long)(p - start);
8942 }
8943 } /* while */
8944
8945 /*
8946 * For a negative line count use only the lines at the end of the file,
8947 * free the rest.
8948 */
8949 if (!failed && maxline < 0)
8950 while (cnt > -maxline)
8951 {
8952 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8953 --cnt;
8954 }
8955
8956 if (failed)
8957 {
8958 list_free(rettv->vval.v_list);
8959 /* readfile doc says an empty list is returned on error */
8960 rettv->vval.v_list = list_alloc();
8961 }
8962
8963 vim_free(prev);
8964 fclose(fd);
8965}
8966
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008967 static void
8968return_register(int regname, typval_T *rettv)
8969{
8970 char_u buf[2] = {0, 0};
8971
8972 buf[0] = (char_u)regname;
8973 rettv->v_type = VAR_STRING;
8974 rettv->vval.v_string = vim_strsave(buf);
8975}
8976
8977/*
8978 * "reg_executing()" function
8979 */
8980 static void
8981f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8982{
8983 return_register(reg_executing, rettv);
8984}
8985
8986/*
8987 * "reg_recording()" function
8988 */
8989 static void
8990f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8991{
8992 return_register(reg_recording, rettv);
8993}
8994
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008995#if defined(FEAT_RELTIME)
8996static int list2proftime(typval_T *arg, proftime_T *tm);
8997
8998/*
8999 * Convert a List to proftime_T.
9000 * Return FAIL when there is something wrong.
9001 */
9002 static int
9003list2proftime(typval_T *arg, proftime_T *tm)
9004{
9005 long n1, n2;
9006 int error = FALSE;
9007
9008 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9009 || arg->vval.v_list->lv_len != 2)
9010 return FAIL;
9011 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9012 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9013# ifdef WIN3264
9014 tm->HighPart = n1;
9015 tm->LowPart = n2;
9016# else
9017 tm->tv_sec = n1;
9018 tm->tv_usec = n2;
9019# endif
9020 return error ? FAIL : OK;
9021}
9022#endif /* FEAT_RELTIME */
9023
9024/*
9025 * "reltime()" function
9026 */
9027 static void
9028f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9029{
9030#ifdef FEAT_RELTIME
9031 proftime_T res;
9032 proftime_T start;
9033
9034 if (argvars[0].v_type == VAR_UNKNOWN)
9035 {
9036 /* No arguments: get current time. */
9037 profile_start(&res);
9038 }
9039 else if (argvars[1].v_type == VAR_UNKNOWN)
9040 {
9041 if (list2proftime(&argvars[0], &res) == FAIL)
9042 return;
9043 profile_end(&res);
9044 }
9045 else
9046 {
9047 /* Two arguments: compute the difference. */
9048 if (list2proftime(&argvars[0], &start) == FAIL
9049 || list2proftime(&argvars[1], &res) == FAIL)
9050 return;
9051 profile_sub(&res, &start);
9052 }
9053
9054 if (rettv_list_alloc(rettv) == OK)
9055 {
9056 long n1, n2;
9057
9058# ifdef WIN3264
9059 n1 = res.HighPart;
9060 n2 = res.LowPart;
9061# else
9062 n1 = res.tv_sec;
9063 n2 = res.tv_usec;
9064# endif
9065 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9066 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9067 }
9068#endif
9069}
9070
9071#ifdef FEAT_FLOAT
9072/*
9073 * "reltimefloat()" function
9074 */
9075 static void
9076f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9077{
9078# ifdef FEAT_RELTIME
9079 proftime_T tm;
9080# endif
9081
9082 rettv->v_type = VAR_FLOAT;
9083 rettv->vval.v_float = 0;
9084# ifdef FEAT_RELTIME
9085 if (list2proftime(&argvars[0], &tm) == OK)
9086 rettv->vval.v_float = profile_float(&tm);
9087# endif
9088}
9089#endif
9090
9091/*
9092 * "reltimestr()" function
9093 */
9094 static void
9095f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9096{
9097#ifdef FEAT_RELTIME
9098 proftime_T tm;
9099#endif
9100
9101 rettv->v_type = VAR_STRING;
9102 rettv->vval.v_string = NULL;
9103#ifdef FEAT_RELTIME
9104 if (list2proftime(&argvars[0], &tm) == OK)
9105 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9106#endif
9107}
9108
9109#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9110static void make_connection(void);
9111static int check_connection(void);
9112
9113 static void
9114make_connection(void)
9115{
9116 if (X_DISPLAY == NULL
9117# ifdef FEAT_GUI
9118 && !gui.in_use
9119# endif
9120 )
9121 {
9122 x_force_connect = TRUE;
9123 setup_term_clip();
9124 x_force_connect = FALSE;
9125 }
9126}
9127
9128 static int
9129check_connection(void)
9130{
9131 make_connection();
9132 if (X_DISPLAY == NULL)
9133 {
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009134 EMSG(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009135 return FAIL;
9136 }
9137 return OK;
9138}
9139#endif
9140
9141#ifdef FEAT_CLIENTSERVER
9142 static void
9143remote_common(typval_T *argvars, typval_T *rettv, int expr)
9144{
9145 char_u *server_name;
9146 char_u *keys;
9147 char_u *r = NULL;
9148 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009149 int timeout = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009150# ifdef WIN32
9151 HWND w;
9152# else
9153 Window w;
9154# endif
9155
9156 if (check_restricted() || check_secure())
9157 return;
9158
9159# ifdef FEAT_X11
9160 if (check_connection() == FAIL)
9161 return;
9162# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009163 if (argvars[2].v_type != VAR_UNKNOWN
9164 && argvars[3].v_type != VAR_UNKNOWN)
9165 timeout = get_tv_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009166
9167 server_name = get_tv_string_chk(&argvars[0]);
9168 if (server_name == NULL)
9169 return; /* type error; errmsg already given */
9170 keys = get_tv_string_buf(&argvars[1], buf);
9171# ifdef WIN32
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009172 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009173# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009174 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9175 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009176# endif
9177 {
9178 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009179 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009180 EMSG(r); /* sending worked but evaluation failed */
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009181 vim_free(r);
9182 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009183 else
9184 EMSG2(_("E241: Unable to send to %s"), server_name);
9185 return;
9186 }
9187
9188 rettv->vval.v_string = r;
9189
9190 if (argvars[2].v_type != VAR_UNKNOWN)
9191 {
9192 dictitem_T v;
9193 char_u str[30];
9194 char_u *idvar;
9195
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009196 idvar = get_tv_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009197 if (idvar != NULL && *idvar != NUL)
9198 {
9199 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9200 v.di_tv.v_type = VAR_STRING;
9201 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009202 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009203 vim_free(v.di_tv.vval.v_string);
9204 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009205 }
9206}
9207#endif
9208
9209/*
9210 * "remote_expr()" function
9211 */
9212 static void
9213f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9214{
9215 rettv->v_type = VAR_STRING;
9216 rettv->vval.v_string = NULL;
9217#ifdef FEAT_CLIENTSERVER
9218 remote_common(argvars, rettv, TRUE);
9219#endif
9220}
9221
9222/*
9223 * "remote_foreground()" function
9224 */
9225 static void
9226f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9227{
9228#ifdef FEAT_CLIENTSERVER
9229# ifdef WIN32
9230 /* On Win32 it's done in this application. */
9231 {
9232 char_u *server_name = get_tv_string_chk(&argvars[0]);
9233
9234 if (server_name != NULL)
9235 serverForeground(server_name);
9236 }
9237# else
9238 /* Send a foreground() expression to the server. */
9239 argvars[1].v_type = VAR_STRING;
9240 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9241 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009242 rettv->v_type = VAR_STRING;
9243 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009244 remote_common(argvars, rettv, TRUE);
9245 vim_free(argvars[1].vval.v_string);
9246# endif
9247#endif
9248}
9249
9250 static void
9251f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9252{
9253#ifdef FEAT_CLIENTSERVER
9254 dictitem_T v;
9255 char_u *s = NULL;
9256# ifdef WIN32
9257 long_u n = 0;
9258# endif
9259 char_u *serverid;
9260
9261 if (check_restricted() || check_secure())
9262 {
9263 rettv->vval.v_number = -1;
9264 return;
9265 }
9266 serverid = get_tv_string_chk(&argvars[0]);
9267 if (serverid == NULL)
9268 {
9269 rettv->vval.v_number = -1;
9270 return; /* type error; errmsg already given */
9271 }
9272# ifdef WIN32
9273 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9274 if (n == 0)
9275 rettv->vval.v_number = -1;
9276 else
9277 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009278 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009279 rettv->vval.v_number = (s != NULL);
9280 }
9281# else
9282 if (check_connection() == FAIL)
9283 return;
9284
9285 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9286 serverStrToWin(serverid), &s);
9287# endif
9288
9289 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9290 {
9291 char_u *retvar;
9292
9293 v.di_tv.v_type = VAR_STRING;
9294 v.di_tv.vval.v_string = vim_strsave(s);
9295 retvar = get_tv_string_chk(&argvars[1]);
9296 if (retvar != NULL)
9297 set_var(retvar, &v.di_tv, FALSE);
9298 vim_free(v.di_tv.vval.v_string);
9299 }
9300#else
9301 rettv->vval.v_number = -1;
9302#endif
9303}
9304
9305 static void
9306f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9307{
9308 char_u *r = NULL;
9309
9310#ifdef FEAT_CLIENTSERVER
9311 char_u *serverid = get_tv_string_chk(&argvars[0]);
9312
9313 if (serverid != NULL && !check_restricted() && !check_secure())
9314 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009315 int timeout = 0;
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009316# ifdef WIN32
9317 /* The server's HWND is encoded in the 'id' parameter */
9318 long_u n = 0;
9319# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009320
9321 if (argvars[1].v_type != VAR_UNKNOWN)
9322 timeout = get_tv_number(&argvars[1]);
9323
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009324# ifdef WIN32
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009325 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9326 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009327 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009328 if (r == NULL)
9329# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009330 if (check_connection() == FAIL
9331 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9332 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333# endif
9334 EMSG(_("E277: Unable to read a server reply"));
9335 }
9336#endif
9337 rettv->v_type = VAR_STRING;
9338 rettv->vval.v_string = r;
9339}
9340
9341/*
9342 * "remote_send()" function
9343 */
9344 static void
9345f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9346{
9347 rettv->v_type = VAR_STRING;
9348 rettv->vval.v_string = NULL;
9349#ifdef FEAT_CLIENTSERVER
9350 remote_common(argvars, rettv, FALSE);
9351#endif
9352}
9353
9354/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009355 * "remote_startserver()" function
9356 */
9357 static void
9358f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9359{
9360#ifdef FEAT_CLIENTSERVER
9361 char_u *server = get_tv_string_chk(&argvars[0]);
9362
9363 if (server == NULL)
9364 return; /* type error; errmsg already given */
9365 if (serverName != NULL)
9366 EMSG(_("E941: already started a server"));
9367 else
9368 {
9369# ifdef FEAT_X11
9370 if (check_connection() == OK)
9371 serverRegisterName(X_DISPLAY, server);
9372# else
9373 serverSetName(server);
9374# endif
9375 }
9376#else
9377 EMSG(_("E942: +clientserver feature not available"));
9378#endif
9379}
9380
9381/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009382 * "remove()" function
9383 */
9384 static void
9385f_remove(typval_T *argvars, typval_T *rettv)
9386{
9387 list_T *l;
9388 listitem_T *item, *item2;
9389 listitem_T *li;
9390 long idx;
9391 long end;
9392 char_u *key;
9393 dict_T *d;
9394 dictitem_T *di;
9395 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9396
9397 if (argvars[0].v_type == VAR_DICT)
9398 {
9399 if (argvars[2].v_type != VAR_UNKNOWN)
9400 EMSG2(_(e_toomanyarg), "remove()");
9401 else if ((d = argvars[0].vval.v_dict) != NULL
9402 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9403 {
9404 key = get_tv_string_chk(&argvars[1]);
9405 if (key != NULL)
9406 {
9407 di = dict_find(d, key, -1);
9408 if (di == NULL)
9409 EMSG2(_(e_dictkey), key);
9410 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9411 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9412 {
9413 *rettv = di->di_tv;
9414 init_tv(&di->di_tv);
9415 dictitem_remove(d, di);
9416 }
9417 }
9418 }
9419 }
9420 else if (argvars[0].v_type != VAR_LIST)
9421 EMSG2(_(e_listdictarg), "remove()");
9422 else if ((l = argvars[0].vval.v_list) != NULL
9423 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9424 {
9425 int error = FALSE;
9426
9427 idx = (long)get_tv_number_chk(&argvars[1], &error);
9428 if (error)
9429 ; /* type error: do nothing, errmsg already given */
9430 else if ((item = list_find(l, idx)) == NULL)
9431 EMSGN(_(e_listidx), idx);
9432 else
9433 {
9434 if (argvars[2].v_type == VAR_UNKNOWN)
9435 {
9436 /* Remove one item, return its value. */
9437 vimlist_remove(l, item, item);
9438 *rettv = item->li_tv;
9439 vim_free(item);
9440 }
9441 else
9442 {
9443 /* Remove range of items, return list with values. */
9444 end = (long)get_tv_number_chk(&argvars[2], &error);
9445 if (error)
9446 ; /* type error: do nothing */
9447 else if ((item2 = list_find(l, end)) == NULL)
9448 EMSGN(_(e_listidx), end);
9449 else
9450 {
9451 int cnt = 0;
9452
9453 for (li = item; li != NULL; li = li->li_next)
9454 {
9455 ++cnt;
9456 if (li == item2)
9457 break;
9458 }
9459 if (li == NULL) /* didn't find "item2" after "item" */
9460 EMSG(_(e_invrange));
9461 else
9462 {
9463 vimlist_remove(l, item, item2);
9464 if (rettv_list_alloc(rettv) == OK)
9465 {
9466 l = rettv->vval.v_list;
9467 l->lv_first = item;
9468 l->lv_last = item2;
9469 item->li_prev = NULL;
9470 item2->li_next = NULL;
9471 l->lv_len = cnt;
9472 }
9473 }
9474 }
9475 }
9476 }
9477 }
9478}
9479
9480/*
9481 * "rename({from}, {to})" function
9482 */
9483 static void
9484f_rename(typval_T *argvars, typval_T *rettv)
9485{
9486 char_u buf[NUMBUFLEN];
9487
9488 if (check_restricted() || check_secure())
9489 rettv->vval.v_number = -1;
9490 else
9491 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
9492 get_tv_string_buf(&argvars[1], buf));
9493}
9494
9495/*
9496 * "repeat()" function
9497 */
9498 static void
9499f_repeat(typval_T *argvars, typval_T *rettv)
9500{
9501 char_u *p;
9502 int n;
9503 int slen;
9504 int len;
9505 char_u *r;
9506 int i;
9507
9508 n = (int)get_tv_number(&argvars[1]);
9509 if (argvars[0].v_type == VAR_LIST)
9510 {
9511 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9512 while (n-- > 0)
9513 if (list_extend(rettv->vval.v_list,
9514 argvars[0].vval.v_list, NULL) == FAIL)
9515 break;
9516 }
9517 else
9518 {
9519 p = get_tv_string(&argvars[0]);
9520 rettv->v_type = VAR_STRING;
9521 rettv->vval.v_string = NULL;
9522
9523 slen = (int)STRLEN(p);
9524 len = slen * n;
9525 if (len <= 0)
9526 return;
9527
9528 r = alloc(len + 1);
9529 if (r != NULL)
9530 {
9531 for (i = 0; i < n; i++)
9532 mch_memmove(r + i * slen, p, (size_t)slen);
9533 r[len] = NUL;
9534 }
9535
9536 rettv->vval.v_string = r;
9537 }
9538}
9539
9540/*
9541 * "resolve()" function
9542 */
9543 static void
9544f_resolve(typval_T *argvars, typval_T *rettv)
9545{
9546 char_u *p;
9547#ifdef HAVE_READLINK
9548 char_u *buf = NULL;
9549#endif
9550
9551 p = get_tv_string(&argvars[0]);
9552#ifdef FEAT_SHORTCUT
9553 {
9554 char_u *v = NULL;
9555
9556 v = mch_resolve_shortcut(p);
9557 if (v != NULL)
9558 rettv->vval.v_string = v;
9559 else
9560 rettv->vval.v_string = vim_strsave(p);
9561 }
9562#else
9563# ifdef HAVE_READLINK
9564 {
9565 char_u *cpy;
9566 int len;
9567 char_u *remain = NULL;
9568 char_u *q;
9569 int is_relative_to_current = FALSE;
9570 int has_trailing_pathsep = FALSE;
9571 int limit = 100;
9572
9573 p = vim_strsave(p);
9574
9575 if (p[0] == '.' && (vim_ispathsep(p[1])
9576 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9577 is_relative_to_current = TRUE;
9578
9579 len = STRLEN(p);
9580 if (len > 0 && after_pathsep(p, p + len))
9581 {
9582 has_trailing_pathsep = TRUE;
9583 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9584 }
9585
9586 q = getnextcomp(p);
9587 if (*q != NUL)
9588 {
9589 /* Separate the first path component in "p", and keep the
9590 * remainder (beginning with the path separator). */
9591 remain = vim_strsave(q - 1);
9592 q[-1] = NUL;
9593 }
9594
9595 buf = alloc(MAXPATHL + 1);
9596 if (buf == NULL)
9597 goto fail;
9598
9599 for (;;)
9600 {
9601 for (;;)
9602 {
9603 len = readlink((char *)p, (char *)buf, MAXPATHL);
9604 if (len <= 0)
9605 break;
9606 buf[len] = NUL;
9607
9608 if (limit-- == 0)
9609 {
9610 vim_free(p);
9611 vim_free(remain);
9612 EMSG(_("E655: Too many symbolic links (cycle?)"));
9613 rettv->vval.v_string = NULL;
9614 goto fail;
9615 }
9616
9617 /* Ensure that the result will have a trailing path separator
9618 * if the argument has one. */
9619 if (remain == NULL && has_trailing_pathsep)
9620 add_pathsep(buf);
9621
9622 /* Separate the first path component in the link value and
9623 * concatenate the remainders. */
9624 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9625 if (*q != NUL)
9626 {
9627 if (remain == NULL)
9628 remain = vim_strsave(q - 1);
9629 else
9630 {
9631 cpy = concat_str(q - 1, remain);
9632 if (cpy != NULL)
9633 {
9634 vim_free(remain);
9635 remain = cpy;
9636 }
9637 }
9638 q[-1] = NUL;
9639 }
9640
9641 q = gettail(p);
9642 if (q > p && *q == NUL)
9643 {
9644 /* Ignore trailing path separator. */
9645 q[-1] = NUL;
9646 q = gettail(p);
9647 }
9648 if (q > p && !mch_isFullName(buf))
9649 {
9650 /* symlink is relative to directory of argument */
9651 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9652 if (cpy != NULL)
9653 {
9654 STRCPY(cpy, p);
9655 STRCPY(gettail(cpy), buf);
9656 vim_free(p);
9657 p = cpy;
9658 }
9659 }
9660 else
9661 {
9662 vim_free(p);
9663 p = vim_strsave(buf);
9664 }
9665 }
9666
9667 if (remain == NULL)
9668 break;
9669
9670 /* Append the first path component of "remain" to "p". */
9671 q = getnextcomp(remain + 1);
9672 len = q - remain - (*q != NUL);
9673 cpy = vim_strnsave(p, STRLEN(p) + len);
9674 if (cpy != NULL)
9675 {
9676 STRNCAT(cpy, remain, len);
9677 vim_free(p);
9678 p = cpy;
9679 }
9680 /* Shorten "remain". */
9681 if (*q != NUL)
9682 STRMOVE(remain, q - 1);
9683 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009684 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009685 }
9686
9687 /* If the result is a relative path name, make it explicitly relative to
9688 * the current directory if and only if the argument had this form. */
9689 if (!vim_ispathsep(*p))
9690 {
9691 if (is_relative_to_current
9692 && *p != NUL
9693 && !(p[0] == '.'
9694 && (p[1] == NUL
9695 || vim_ispathsep(p[1])
9696 || (p[1] == '.'
9697 && (p[2] == NUL
9698 || vim_ispathsep(p[2]))))))
9699 {
9700 /* Prepend "./". */
9701 cpy = concat_str((char_u *)"./", p);
9702 if (cpy != NULL)
9703 {
9704 vim_free(p);
9705 p = cpy;
9706 }
9707 }
9708 else if (!is_relative_to_current)
9709 {
9710 /* Strip leading "./". */
9711 q = p;
9712 while (q[0] == '.' && vim_ispathsep(q[1]))
9713 q += 2;
9714 if (q > p)
9715 STRMOVE(p, p + 2);
9716 }
9717 }
9718
9719 /* Ensure that the result will have no trailing path separator
9720 * if the argument had none. But keep "/" or "//". */
9721 if (!has_trailing_pathsep)
9722 {
9723 q = p + STRLEN(p);
9724 if (after_pathsep(p, q))
9725 *gettail_sep(p) = NUL;
9726 }
9727
9728 rettv->vval.v_string = p;
9729 }
9730# else
9731 rettv->vval.v_string = vim_strsave(p);
9732# endif
9733#endif
9734
9735 simplify_filename(rettv->vval.v_string);
9736
9737#ifdef HAVE_READLINK
9738fail:
9739 vim_free(buf);
9740#endif
9741 rettv->v_type = VAR_STRING;
9742}
9743
9744/*
9745 * "reverse({list})" function
9746 */
9747 static void
9748f_reverse(typval_T *argvars, typval_T *rettv)
9749{
9750 list_T *l;
9751 listitem_T *li, *ni;
9752
9753 if (argvars[0].v_type != VAR_LIST)
9754 EMSG2(_(e_listarg), "reverse()");
9755 else if ((l = argvars[0].vval.v_list) != NULL
9756 && !tv_check_lock(l->lv_lock,
9757 (char_u *)N_("reverse() argument"), TRUE))
9758 {
9759 li = l->lv_last;
9760 l->lv_first = l->lv_last = NULL;
9761 l->lv_len = 0;
9762 while (li != NULL)
9763 {
9764 ni = li->li_prev;
9765 list_append(l, li);
9766 li = ni;
9767 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009768 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009769 l->lv_idx = l->lv_len - l->lv_idx - 1;
9770 }
9771}
9772
9773#define SP_NOMOVE 0x01 /* don't move cursor */
9774#define SP_REPEAT 0x02 /* repeat to find outer pair */
9775#define SP_RETCOUNT 0x04 /* return matchcount */
9776#define SP_SETPCMARK 0x08 /* set previous context mark */
9777#define SP_START 0x10 /* accept match at start position */
9778#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9779#define SP_END 0x40 /* leave cursor at end of match */
9780#define SP_COLUMN 0x80 /* start at cursor column */
9781
9782static int get_search_arg(typval_T *varp, int *flagsp);
9783
9784/*
9785 * Get flags for a search function.
9786 * Possibly sets "p_ws".
9787 * Returns BACKWARD, FORWARD or zero (for an error).
9788 */
9789 static int
9790get_search_arg(typval_T *varp, int *flagsp)
9791{
9792 int dir = FORWARD;
9793 char_u *flags;
9794 char_u nbuf[NUMBUFLEN];
9795 int mask;
9796
9797 if (varp->v_type != VAR_UNKNOWN)
9798 {
9799 flags = get_tv_string_buf_chk(varp, nbuf);
9800 if (flags == NULL)
9801 return 0; /* type error; errmsg already given */
9802 while (*flags != NUL)
9803 {
9804 switch (*flags)
9805 {
9806 case 'b': dir = BACKWARD; break;
9807 case 'w': p_ws = TRUE; break;
9808 case 'W': p_ws = FALSE; break;
9809 default: mask = 0;
9810 if (flagsp != NULL)
9811 switch (*flags)
9812 {
9813 case 'c': mask = SP_START; break;
9814 case 'e': mask = SP_END; break;
9815 case 'm': mask = SP_RETCOUNT; break;
9816 case 'n': mask = SP_NOMOVE; break;
9817 case 'p': mask = SP_SUBPAT; break;
9818 case 'r': mask = SP_REPEAT; break;
9819 case 's': mask = SP_SETPCMARK; break;
9820 case 'z': mask = SP_COLUMN; break;
9821 }
9822 if (mask == 0)
9823 {
9824 EMSG2(_(e_invarg2), flags);
9825 dir = 0;
9826 }
9827 else
9828 *flagsp |= mask;
9829 }
9830 if (dir == 0)
9831 break;
9832 ++flags;
9833 }
9834 }
9835 return dir;
9836}
9837
9838/*
9839 * Shared by search() and searchpos() functions.
9840 */
9841 static int
9842search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9843{
9844 int flags;
9845 char_u *pat;
9846 pos_T pos;
9847 pos_T save_cursor;
9848 int save_p_ws = p_ws;
9849 int dir;
9850 int retval = 0; /* default: FAIL */
9851 long lnum_stop = 0;
9852 proftime_T tm;
9853#ifdef FEAT_RELTIME
9854 long time_limit = 0;
9855#endif
9856 int options = SEARCH_KEEP;
9857 int subpatnum;
9858
9859 pat = get_tv_string(&argvars[0]);
9860 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9861 if (dir == 0)
9862 goto theend;
9863 flags = *flagsp;
9864 if (flags & SP_START)
9865 options |= SEARCH_START;
9866 if (flags & SP_END)
9867 options |= SEARCH_END;
9868 if (flags & SP_COLUMN)
9869 options |= SEARCH_COL;
9870
9871 /* Optional arguments: line number to stop searching and timeout. */
9872 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9873 {
9874 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9875 if (lnum_stop < 0)
9876 goto theend;
9877#ifdef FEAT_RELTIME
9878 if (argvars[3].v_type != VAR_UNKNOWN)
9879 {
9880 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9881 if (time_limit < 0)
9882 goto theend;
9883 }
9884#endif
9885 }
9886
9887#ifdef FEAT_RELTIME
9888 /* Set the time limit, if there is one. */
9889 profile_setlimit(time_limit, &tm);
9890#endif
9891
9892 /*
9893 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9894 * Check to make sure only those flags are set.
9895 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9896 * flags cannot be set. Check for that condition also.
9897 */
9898 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9899 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9900 {
9901 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9902 goto theend;
9903 }
9904
9905 pos = save_cursor = curwin->w_cursor;
9906 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009907 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009908 if (subpatnum != FAIL)
9909 {
9910 if (flags & SP_SUBPAT)
9911 retval = subpatnum;
9912 else
9913 retval = pos.lnum;
9914 if (flags & SP_SETPCMARK)
9915 setpcmark();
9916 curwin->w_cursor = pos;
9917 if (match_pos != NULL)
9918 {
9919 /* Store the match cursor position */
9920 match_pos->lnum = pos.lnum;
9921 match_pos->col = pos.col + 1;
9922 }
9923 /* "/$" will put the cursor after the end of the line, may need to
9924 * correct that here */
9925 check_cursor();
9926 }
9927
9928 /* If 'n' flag is used: restore cursor position. */
9929 if (flags & SP_NOMOVE)
9930 curwin->w_cursor = save_cursor;
9931 else
9932 curwin->w_set_curswant = TRUE;
9933theend:
9934 p_ws = save_p_ws;
9935
9936 return retval;
9937}
9938
9939#ifdef FEAT_FLOAT
9940
9941/*
9942 * round() is not in C90, use ceil() or floor() instead.
9943 */
9944 float_T
9945vim_round(float_T f)
9946{
9947 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9948}
9949
9950/*
9951 * "round({float})" function
9952 */
9953 static void
9954f_round(typval_T *argvars, typval_T *rettv)
9955{
9956 float_T f = 0.0;
9957
9958 rettv->v_type = VAR_FLOAT;
9959 if (get_float_arg(argvars, &f) == OK)
9960 rettv->vval.v_float = vim_round(f);
9961 else
9962 rettv->vval.v_float = 0.0;
9963}
9964#endif
9965
9966/*
9967 * "screenattr()" function
9968 */
9969 static void
9970f_screenattr(typval_T *argvars, typval_T *rettv)
9971{
9972 int row;
9973 int col;
9974 int c;
9975
9976 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9977 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9978 if (row < 0 || row >= screen_Rows
9979 || col < 0 || col >= screen_Columns)
9980 c = -1;
9981 else
9982 c = ScreenAttrs[LineOffset[row] + col];
9983 rettv->vval.v_number = c;
9984}
9985
9986/*
9987 * "screenchar()" function
9988 */
9989 static void
9990f_screenchar(typval_T *argvars, typval_T *rettv)
9991{
9992 int row;
9993 int col;
9994 int off;
9995 int c;
9996
9997 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9998 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9999 if (row < 0 || row >= screen_Rows
10000 || col < 0 || col >= screen_Columns)
10001 c = -1;
10002 else
10003 {
10004 off = LineOffset[row] + col;
10005#ifdef FEAT_MBYTE
10006 if (enc_utf8 && ScreenLinesUC[off] != 0)
10007 c = ScreenLinesUC[off];
10008 else
10009#endif
10010 c = ScreenLines[off];
10011 }
10012 rettv->vval.v_number = c;
10013}
10014
10015/*
10016 * "screencol()" function
10017 *
10018 * First column is 1 to be consistent with virtcol().
10019 */
10020 static void
10021f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10022{
10023 rettv->vval.v_number = screen_screencol() + 1;
10024}
10025
10026/*
10027 * "screenrow()" function
10028 */
10029 static void
10030f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10031{
10032 rettv->vval.v_number = screen_screenrow() + 1;
10033}
10034
10035/*
10036 * "search()" function
10037 */
10038 static void
10039f_search(typval_T *argvars, typval_T *rettv)
10040{
10041 int flags = 0;
10042
10043 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10044}
10045
10046/*
10047 * "searchdecl()" function
10048 */
10049 static void
10050f_searchdecl(typval_T *argvars, typval_T *rettv)
10051{
10052 int locally = 1;
10053 int thisblock = 0;
10054 int error = FALSE;
10055 char_u *name;
10056
10057 rettv->vval.v_number = 1; /* default: FAIL */
10058
10059 name = get_tv_string_chk(&argvars[0]);
10060 if (argvars[1].v_type != VAR_UNKNOWN)
10061 {
10062 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
10063 if (!error && argvars[2].v_type != VAR_UNKNOWN)
10064 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
10065 }
10066 if (!error && name != NULL)
10067 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10068 locally, thisblock, SEARCH_KEEP) == FAIL;
10069}
10070
10071/*
10072 * Used by searchpair() and searchpairpos()
10073 */
10074 static int
10075searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10076{
10077 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010078 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010079 int save_p_ws = p_ws;
10080 int dir;
10081 int flags = 0;
10082 char_u nbuf1[NUMBUFLEN];
10083 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010084 int retval = 0; /* default: FAIL */
10085 long lnum_stop = 0;
10086 long time_limit = 0;
10087
10088 /* Get the three pattern arguments: start, middle, end. */
10089 spat = get_tv_string_chk(&argvars[0]);
10090 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
10091 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
10092 if (spat == NULL || mpat == NULL || epat == NULL)
10093 goto theend; /* type error */
10094
10095 /* Handle the optional fourth argument: flags */
10096 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10097 if (dir == 0)
10098 goto theend;
10099
10100 /* Don't accept SP_END or SP_SUBPAT.
10101 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10102 */
10103 if ((flags & (SP_END | SP_SUBPAT)) != 0
10104 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10105 {
10106 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
10107 goto theend;
10108 }
10109
10110 /* Using 'r' implies 'W', otherwise it doesn't work. */
10111 if (flags & SP_REPEAT)
10112 p_ws = FALSE;
10113
10114 /* Optional fifth argument: skip expression */
10115 if (argvars[3].v_type == VAR_UNKNOWN
10116 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010117 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010118 else
10119 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010120 skip = &argvars[4];
10121 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10122 && skip->v_type != VAR_STRING)
10123 {
10124 /* Type error */
10125 goto theend;
10126 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010127 if (argvars[5].v_type != VAR_UNKNOWN)
10128 {
10129 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
10130 if (lnum_stop < 0)
10131 goto theend;
10132#ifdef FEAT_RELTIME
10133 if (argvars[6].v_type != VAR_UNKNOWN)
10134 {
10135 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
10136 if (time_limit < 0)
10137 goto theend;
10138 }
10139#endif
10140 }
10141 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010142
10143 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10144 match_pos, lnum_stop, time_limit);
10145
10146theend:
10147 p_ws = save_p_ws;
10148
10149 return retval;
10150}
10151
10152/*
10153 * "searchpair()" function
10154 */
10155 static void
10156f_searchpair(typval_T *argvars, typval_T *rettv)
10157{
10158 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10159}
10160
10161/*
10162 * "searchpairpos()" function
10163 */
10164 static void
10165f_searchpairpos(typval_T *argvars, typval_T *rettv)
10166{
10167 pos_T match_pos;
10168 int lnum = 0;
10169 int col = 0;
10170
10171 if (rettv_list_alloc(rettv) == FAIL)
10172 return;
10173
10174 if (searchpair_cmn(argvars, &match_pos) > 0)
10175 {
10176 lnum = match_pos.lnum;
10177 col = match_pos.col;
10178 }
10179
10180 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10181 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10182}
10183
10184/*
10185 * Search for a start/middle/end thing.
10186 * Used by searchpair(), see its documentation for the details.
10187 * Returns 0 or -1 for no match,
10188 */
10189 long
10190do_searchpair(
10191 char_u *spat, /* start pattern */
10192 char_u *mpat, /* middle pattern */
10193 char_u *epat, /* end pattern */
10194 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010195 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010196 int flags, /* SP_SETPCMARK and other SP_ values */
10197 pos_T *match_pos,
10198 linenr_T lnum_stop, /* stop at this line if not zero */
10199 long time_limit UNUSED) /* stop after this many msec */
10200{
10201 char_u *save_cpo;
10202 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10203 long retval = 0;
10204 pos_T pos;
10205 pos_T firstpos;
10206 pos_T foundpos;
10207 pos_T save_cursor;
10208 pos_T save_pos;
10209 int n;
10210 int r;
10211 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010212 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010213 int err;
10214 int options = SEARCH_KEEP;
10215 proftime_T tm;
10216
10217 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10218 save_cpo = p_cpo;
10219 p_cpo = empty_option;
10220
10221#ifdef FEAT_RELTIME
10222 /* Set the time limit, if there is one. */
10223 profile_setlimit(time_limit, &tm);
10224#endif
10225
10226 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10227 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010228 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10229 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010230 if (pat2 == NULL || pat3 == NULL)
10231 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010232 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010233 if (*mpat == NUL)
10234 STRCPY(pat3, pat2);
10235 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010236 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010237 spat, epat, mpat);
10238 if (flags & SP_START)
10239 options |= SEARCH_START;
10240
Bram Moolenaar48570482017-10-30 21:48:41 +010010241 if (skip != NULL)
10242 {
10243 /* Empty string means to not use the skip expression. */
10244 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10245 use_skip = skip->vval.v_string != NULL
10246 && *skip->vval.v_string != NUL;
10247 }
10248
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010249 save_cursor = curwin->w_cursor;
10250 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010251 CLEAR_POS(&firstpos);
10252 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010253 pat = pat3;
10254 for (;;)
10255 {
10256 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010257 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010258 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010259 /* didn't find it or found the first match again: FAIL */
10260 break;
10261
10262 if (firstpos.lnum == 0)
10263 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010264 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010265 {
10266 /* Found the same position again. Can happen with a pattern that
10267 * has "\zs" at the end and searching backwards. Advance one
10268 * character and try again. */
10269 if (dir == BACKWARD)
10270 decl(&pos);
10271 else
10272 incl(&pos);
10273 }
10274 foundpos = pos;
10275
10276 /* clear the start flag to avoid getting stuck here */
10277 options &= ~SEARCH_START;
10278
10279 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010280 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010281 {
10282 save_pos = curwin->w_cursor;
10283 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010284 err = FALSE;
10285 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010286 curwin->w_cursor = save_pos;
10287 if (err)
10288 {
10289 /* Evaluating {skip} caused an error, break here. */
10290 curwin->w_cursor = save_cursor;
10291 retval = -1;
10292 break;
10293 }
10294 if (r)
10295 continue;
10296 }
10297
10298 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10299 {
10300 /* Found end when searching backwards or start when searching
10301 * forward: nested pair. */
10302 ++nest;
10303 pat = pat2; /* nested, don't search for middle */
10304 }
10305 else
10306 {
10307 /* Found end when searching forward or start when searching
10308 * backward: end of (nested) pair; or found middle in outer pair. */
10309 if (--nest == 1)
10310 pat = pat3; /* outer level, search for middle */
10311 }
10312
10313 if (nest == 0)
10314 {
10315 /* Found the match: return matchcount or line number. */
10316 if (flags & SP_RETCOUNT)
10317 ++retval;
10318 else
10319 retval = pos.lnum;
10320 if (flags & SP_SETPCMARK)
10321 setpcmark();
10322 curwin->w_cursor = pos;
10323 if (!(flags & SP_REPEAT))
10324 break;
10325 nest = 1; /* search for next unmatched */
10326 }
10327 }
10328
10329 if (match_pos != NULL)
10330 {
10331 /* Store the match cursor position */
10332 match_pos->lnum = curwin->w_cursor.lnum;
10333 match_pos->col = curwin->w_cursor.col + 1;
10334 }
10335
10336 /* If 'n' flag is used or search failed: restore cursor position. */
10337 if ((flags & SP_NOMOVE) || retval == 0)
10338 curwin->w_cursor = save_cursor;
10339
10340theend:
10341 vim_free(pat2);
10342 vim_free(pat3);
10343 if (p_cpo == empty_option)
10344 p_cpo = save_cpo;
10345 else
10346 /* Darn, evaluating the {skip} expression changed the value. */
10347 free_string_option(save_cpo);
10348
10349 return retval;
10350}
10351
10352/*
10353 * "searchpos()" function
10354 */
10355 static void
10356f_searchpos(typval_T *argvars, typval_T *rettv)
10357{
10358 pos_T match_pos;
10359 int lnum = 0;
10360 int col = 0;
10361 int n;
10362 int flags = 0;
10363
10364 if (rettv_list_alloc(rettv) == FAIL)
10365 return;
10366
10367 n = search_cmn(argvars, &match_pos, &flags);
10368 if (n > 0)
10369 {
10370 lnum = match_pos.lnum;
10371 col = match_pos.col;
10372 }
10373
10374 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10375 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10376 if (flags & SP_SUBPAT)
10377 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10378}
10379
10380 static void
10381f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10382{
10383#ifdef FEAT_CLIENTSERVER
10384 char_u buf[NUMBUFLEN];
10385 char_u *server = get_tv_string_chk(&argvars[0]);
10386 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
10387
10388 rettv->vval.v_number = -1;
10389 if (server == NULL || reply == NULL)
10390 return;
10391 if (check_restricted() || check_secure())
10392 return;
10393# ifdef FEAT_X11
10394 if (check_connection() == FAIL)
10395 return;
10396# endif
10397
10398 if (serverSendReply(server, reply) < 0)
10399 {
10400 EMSG(_("E258: Unable to send to client"));
10401 return;
10402 }
10403 rettv->vval.v_number = 0;
10404#else
10405 rettv->vval.v_number = -1;
10406#endif
10407}
10408
10409 static void
10410f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10411{
10412 char_u *r = NULL;
10413
10414#ifdef FEAT_CLIENTSERVER
10415# ifdef WIN32
10416 r = serverGetVimNames();
10417# else
10418 make_connection();
10419 if (X_DISPLAY != NULL)
10420 r = serverGetVimNames(X_DISPLAY);
10421# endif
10422#endif
10423 rettv->v_type = VAR_STRING;
10424 rettv->vval.v_string = r;
10425}
10426
10427/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010428 * "setbufline()" function
10429 */
10430 static void
10431f_setbufline(argvars, rettv)
10432 typval_T *argvars;
10433 typval_T *rettv;
10434{
10435 linenr_T lnum;
10436 buf_T *buf;
10437
10438 buf = get_buf_tv(&argvars[0], FALSE);
10439 if (buf == NULL)
10440 rettv->vval.v_number = 1; /* FAIL */
10441 else
10442 {
10443 lnum = get_tv_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010444 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010445 }
10446}
10447
10448/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010449 * "setbufvar()" function
10450 */
10451 static void
10452f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10453{
10454 buf_T *buf;
10455 char_u *varname, *bufvarname;
10456 typval_T *varp;
10457 char_u nbuf[NUMBUFLEN];
10458
10459 if (check_restricted() || check_secure())
10460 return;
10461 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10462 varname = get_tv_string_chk(&argvars[1]);
10463 buf = get_buf_tv(&argvars[0], FALSE);
10464 varp = &argvars[2];
10465
10466 if (buf != NULL && varname != NULL && varp != NULL)
10467 {
10468 if (*varname == '&')
10469 {
10470 long numval;
10471 char_u *strval;
10472 int error = FALSE;
10473 aco_save_T aco;
10474
10475 /* set curbuf to be our buf, temporarily */
10476 aucmd_prepbuf(&aco, buf);
10477
10478 ++varname;
10479 numval = (long)get_tv_number_chk(varp, &error);
10480 strval = get_tv_string_buf_chk(varp, nbuf);
10481 if (!error && strval != NULL)
10482 set_option_value(varname, numval, strval, OPT_LOCAL);
10483
10484 /* reset notion of buffer */
10485 aucmd_restbuf(&aco);
10486 }
10487 else
10488 {
10489 buf_T *save_curbuf = curbuf;
10490
10491 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10492 if (bufvarname != NULL)
10493 {
10494 curbuf = buf;
10495 STRCPY(bufvarname, "b:");
10496 STRCPY(bufvarname + 2, varname);
10497 set_var(bufvarname, varp, TRUE);
10498 vim_free(bufvarname);
10499 curbuf = save_curbuf;
10500 }
10501 }
10502 }
10503}
10504
10505 static void
10506f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10507{
10508 dict_T *d;
10509 dictitem_T *di;
10510 char_u *csearch;
10511
10512 if (argvars[0].v_type != VAR_DICT)
10513 {
10514 EMSG(_(e_dictreq));
10515 return;
10516 }
10517
10518 if ((d = argvars[0].vval.v_dict) != NULL)
10519 {
10520 csearch = get_dict_string(d, (char_u *)"char", FALSE);
10521 if (csearch != NULL)
10522 {
10523#ifdef FEAT_MBYTE
10524 if (enc_utf8)
10525 {
10526 int pcc[MAX_MCO];
10527 int c = utfc_ptr2char(csearch, pcc);
10528
10529 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10530 }
10531 else
10532#endif
10533 set_last_csearch(PTR2CHAR(csearch),
10534 csearch, MB_PTR2LEN(csearch));
10535 }
10536
10537 di = dict_find(d, (char_u *)"forward", -1);
10538 if (di != NULL)
10539 set_csearch_direction((int)get_tv_number(&di->di_tv)
10540 ? FORWARD : BACKWARD);
10541
10542 di = dict_find(d, (char_u *)"until", -1);
10543 if (di != NULL)
10544 set_csearch_until(!!get_tv_number(&di->di_tv));
10545 }
10546}
10547
10548/*
10549 * "setcmdpos()" function
10550 */
10551 static void
10552f_setcmdpos(typval_T *argvars, typval_T *rettv)
10553{
10554 int pos = (int)get_tv_number(&argvars[0]) - 1;
10555
10556 if (pos >= 0)
10557 rettv->vval.v_number = set_cmdline_pos(pos);
10558}
10559
10560/*
10561 * "setfperm({fname}, {mode})" function
10562 */
10563 static void
10564f_setfperm(typval_T *argvars, typval_T *rettv)
10565{
10566 char_u *fname;
10567 char_u modebuf[NUMBUFLEN];
10568 char_u *mode_str;
10569 int i;
10570 int mask;
10571 int mode = 0;
10572
10573 rettv->vval.v_number = 0;
10574 fname = get_tv_string_chk(&argvars[0]);
10575 if (fname == NULL)
10576 return;
10577 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
10578 if (mode_str == NULL)
10579 return;
10580 if (STRLEN(mode_str) != 9)
10581 {
10582 EMSG2(_(e_invarg2), mode_str);
10583 return;
10584 }
10585
10586 mask = 1;
10587 for (i = 8; i >= 0; --i)
10588 {
10589 if (mode_str[i] != '-')
10590 mode |= mask;
10591 mask = mask << 1;
10592 }
10593 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10594}
10595
10596/*
10597 * "setline()" function
10598 */
10599 static void
10600f_setline(typval_T *argvars, typval_T *rettv)
10601{
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010602 linenr_T lnum = get_tv_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010603
Bram Moolenaarca851592018-06-06 21:04:07 +020010604 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010605}
10606
Bram Moolenaard823fa92016-08-12 16:29:27 +020010607static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *what_arg, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010608
10609/*
10610 * Used by "setqflist()" and "setloclist()" functions
10611 */
10612 static void
10613set_qf_ll_list(
10614 win_T *wp UNUSED,
10615 typval_T *list_arg UNUSED,
10616 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010617 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010618 typval_T *rettv)
10619{
10620#ifdef FEAT_QUICKFIX
10621 static char *e_invact = N_("E927: Invalid action: '%s'");
10622 char_u *act;
10623 int action = 0;
10624#endif
10625
10626 rettv->vval.v_number = -1;
10627
10628#ifdef FEAT_QUICKFIX
10629 if (list_arg->v_type != VAR_LIST)
10630 EMSG(_(e_listreq));
10631 else
10632 {
10633 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010634 dict_T *d = NULL;
10635 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010636
10637 if (action_arg->v_type == VAR_STRING)
10638 {
10639 act = get_tv_string_chk(action_arg);
10640 if (act == NULL)
10641 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010642 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10643 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 action = *act;
10645 else
10646 EMSG2(_(e_invact), act);
10647 }
10648 else if (action_arg->v_type == VAR_UNKNOWN)
10649 action = ' ';
10650 else
10651 EMSG(_(e_stringreq));
10652
Bram Moolenaard823fa92016-08-12 16:29:27 +020010653 if (action_arg->v_type != VAR_UNKNOWN
10654 && what_arg->v_type != VAR_UNKNOWN)
10655 {
10656 if (what_arg->v_type == VAR_DICT)
10657 d = what_arg->vval.v_dict;
10658 else
10659 {
10660 EMSG(_(e_dictreq));
10661 valid_dict = FALSE;
10662 }
10663 }
10664
10665 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar8b62e312018-05-13 15:29:04 +020010666 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"), d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010667 rettv->vval.v_number = 0;
10668 }
10669#endif
10670}
10671
10672/*
10673 * "setloclist()" function
10674 */
10675 static void
10676f_setloclist(typval_T *argvars, typval_T *rettv)
10677{
10678 win_T *win;
10679
10680 rettv->vval.v_number = -1;
10681
10682 win = find_win_by_nr(&argvars[0], NULL);
10683 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010684 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010685}
10686
10687/*
10688 * "setmatches()" function
10689 */
10690 static void
10691f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10692{
10693#ifdef FEAT_SEARCH_EXTRA
10694 list_T *l;
10695 listitem_T *li;
10696 dict_T *d;
10697 list_T *s = NULL;
10698
10699 rettv->vval.v_number = -1;
10700 if (argvars[0].v_type != VAR_LIST)
10701 {
10702 EMSG(_(e_listreq));
10703 return;
10704 }
10705 if ((l = argvars[0].vval.v_list) != NULL)
10706 {
10707
10708 /* To some extent make sure that we are dealing with a list from
10709 * "getmatches()". */
10710 li = l->lv_first;
10711 while (li != NULL)
10712 {
10713 if (li->li_tv.v_type != VAR_DICT
10714 || (d = li->li_tv.vval.v_dict) == NULL)
10715 {
10716 EMSG(_(e_invarg));
10717 return;
10718 }
10719 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10720 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10721 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10722 && dict_find(d, (char_u *)"priority", -1) != NULL
10723 && dict_find(d, (char_u *)"id", -1) != NULL))
10724 {
10725 EMSG(_(e_invarg));
10726 return;
10727 }
10728 li = li->li_next;
10729 }
10730
10731 clear_matches(curwin);
10732 li = l->lv_first;
10733 while (li != NULL)
10734 {
10735 int i = 0;
10736 char_u buf[5];
10737 dictitem_T *di;
10738 char_u *group;
10739 int priority;
10740 int id;
10741 char_u *conceal;
10742
10743 d = li->li_tv.vval.v_dict;
10744 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10745 {
10746 if (s == NULL)
10747 {
10748 s = list_alloc();
10749 if (s == NULL)
10750 return;
10751 }
10752
10753 /* match from matchaddpos() */
10754 for (i = 1; i < 9; i++)
10755 {
10756 sprintf((char *)buf, (char *)"pos%d", i);
10757 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10758 {
10759 if (di->di_tv.v_type != VAR_LIST)
10760 return;
10761
10762 list_append_tv(s, &di->di_tv);
10763 s->lv_refcount++;
10764 }
10765 else
10766 break;
10767 }
10768 }
10769
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010770 group = get_dict_string(d, (char_u *)"group", TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010771 priority = (int)get_dict_number(d, (char_u *)"priority");
10772 id = (int)get_dict_number(d, (char_u *)"id");
10773 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010774 ? get_dict_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010775 : NULL;
10776 if (i == 0)
10777 {
10778 match_add(curwin, group,
10779 get_dict_string(d, (char_u *)"pattern", FALSE),
10780 priority, id, NULL, conceal);
10781 }
10782 else
10783 {
10784 match_add(curwin, group, NULL, priority, id, s, conceal);
10785 list_unref(s);
10786 s = NULL;
10787 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010788 vim_free(group);
10789 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010790
10791 li = li->li_next;
10792 }
10793 rettv->vval.v_number = 0;
10794 }
10795#endif
10796}
10797
10798/*
10799 * "setpos()" function
10800 */
10801 static void
10802f_setpos(typval_T *argvars, typval_T *rettv)
10803{
10804 pos_T pos;
10805 int fnum;
10806 char_u *name;
10807 colnr_T curswant = -1;
10808
10809 rettv->vval.v_number = -1;
10810 name = get_tv_string_chk(argvars);
10811 if (name != NULL)
10812 {
10813 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10814 {
10815 if (--pos.col < 0)
10816 pos.col = 0;
10817 if (name[0] == '.' && name[1] == NUL)
10818 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010819 /* set cursor; "fnum" is ignored */
10820 curwin->w_cursor = pos;
10821 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010822 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010823 curwin->w_curswant = curswant - 1;
10824 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010825 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010826 check_cursor();
10827 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010828 }
10829 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10830 {
10831 /* set mark */
10832 if (setmark_pos(name[1], &pos, fnum) == OK)
10833 rettv->vval.v_number = 0;
10834 }
10835 else
10836 EMSG(_(e_invarg));
10837 }
10838 }
10839}
10840
10841/*
10842 * "setqflist()" function
10843 */
10844 static void
10845f_setqflist(typval_T *argvars, typval_T *rettv)
10846{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010847 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010848}
10849
10850/*
10851 * "setreg()" function
10852 */
10853 static void
10854f_setreg(typval_T *argvars, typval_T *rettv)
10855{
10856 int regname;
10857 char_u *strregname;
10858 char_u *stropt;
10859 char_u *strval;
10860 int append;
10861 char_u yank_type;
10862 long block_len;
10863
10864 block_len = -1;
10865 yank_type = MAUTO;
10866 append = FALSE;
10867
10868 strregname = get_tv_string_chk(argvars);
10869 rettv->vval.v_number = 1; /* FAIL is default */
10870
10871 if (strregname == NULL)
10872 return; /* type error; errmsg already given */
10873 regname = *strregname;
10874 if (regname == 0 || regname == '@')
10875 regname = '"';
10876
10877 if (argvars[2].v_type != VAR_UNKNOWN)
10878 {
10879 stropt = get_tv_string_chk(&argvars[2]);
10880 if (stropt == NULL)
10881 return; /* type error */
10882 for (; *stropt != NUL; ++stropt)
10883 switch (*stropt)
10884 {
10885 case 'a': case 'A': /* append */
10886 append = TRUE;
10887 break;
10888 case 'v': case 'c': /* character-wise selection */
10889 yank_type = MCHAR;
10890 break;
10891 case 'V': case 'l': /* line-wise selection */
10892 yank_type = MLINE;
10893 break;
10894 case 'b': case Ctrl_V: /* block-wise selection */
10895 yank_type = MBLOCK;
10896 if (VIM_ISDIGIT(stropt[1]))
10897 {
10898 ++stropt;
10899 block_len = getdigits(&stropt) - 1;
10900 --stropt;
10901 }
10902 break;
10903 }
10904 }
10905
10906 if (argvars[1].v_type == VAR_LIST)
10907 {
10908 char_u **lstval;
10909 char_u **allocval;
10910 char_u buf[NUMBUFLEN];
10911 char_u **curval;
10912 char_u **curallocval;
10913 list_T *ll = argvars[1].vval.v_list;
10914 listitem_T *li;
10915 int len;
10916
10917 /* If the list is NULL handle like an empty list. */
10918 len = ll == NULL ? 0 : ll->lv_len;
10919
10920 /* First half: use for pointers to result lines; second half: use for
10921 * pointers to allocated copies. */
10922 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10923 if (lstval == NULL)
10924 return;
10925 curval = lstval;
10926 allocval = lstval + len + 2;
10927 curallocval = allocval;
10928
10929 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10930 li = li->li_next)
10931 {
10932 strval = get_tv_string_buf_chk(&li->li_tv, buf);
10933 if (strval == NULL)
10934 goto free_lstval;
10935 if (strval == buf)
10936 {
10937 /* Need to make a copy, next get_tv_string_buf_chk() will
10938 * overwrite the string. */
10939 strval = vim_strsave(buf);
10940 if (strval == NULL)
10941 goto free_lstval;
10942 *curallocval++ = strval;
10943 }
10944 *curval++ = strval;
10945 }
10946 *curval++ = NULL;
10947
10948 write_reg_contents_lst(regname, lstval, -1,
10949 append, yank_type, block_len);
10950free_lstval:
10951 while (curallocval > allocval)
10952 vim_free(*--curallocval);
10953 vim_free(lstval);
10954 }
10955 else
10956 {
10957 strval = get_tv_string_chk(&argvars[1]);
10958 if (strval == NULL)
10959 return;
10960 write_reg_contents_ex(regname, strval, -1,
10961 append, yank_type, block_len);
10962 }
10963 rettv->vval.v_number = 0;
10964}
10965
10966/*
10967 * "settabvar()" function
10968 */
10969 static void
10970f_settabvar(typval_T *argvars, typval_T *rettv)
10971{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010972 tabpage_T *save_curtab;
10973 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010974 char_u *varname, *tabvarname;
10975 typval_T *varp;
10976
10977 rettv->vval.v_number = 0;
10978
10979 if (check_restricted() || check_secure())
10980 return;
10981
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010982 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010983 varname = get_tv_string_chk(&argvars[1]);
10984 varp = &argvars[2];
10985
Bram Moolenaar4033c552017-09-16 20:54:51 +020010986 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010987 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010988 save_curtab = curtab;
10989 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010990
10991 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10992 if (tabvarname != NULL)
10993 {
10994 STRCPY(tabvarname, "t:");
10995 STRCPY(tabvarname + 2, varname);
10996 set_var(tabvarname, varp, TRUE);
10997 vim_free(tabvarname);
10998 }
10999
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011000 /* Restore current tabpage */
11001 if (valid_tabpage(save_curtab))
11002 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011003 }
11004}
11005
11006/*
11007 * "settabwinvar()" function
11008 */
11009 static void
11010f_settabwinvar(typval_T *argvars, typval_T *rettv)
11011{
11012 setwinvar(argvars, rettv, 1);
11013}
11014
11015/*
11016 * "setwinvar()" function
11017 */
11018 static void
11019f_setwinvar(typval_T *argvars, typval_T *rettv)
11020{
11021 setwinvar(argvars, rettv, 0);
11022}
11023
11024#ifdef FEAT_CRYPT
11025/*
11026 * "sha256({string})" function
11027 */
11028 static void
11029f_sha256(typval_T *argvars, typval_T *rettv)
11030{
11031 char_u *p;
11032
11033 p = get_tv_string(&argvars[0]);
11034 rettv->vval.v_string = vim_strsave(
11035 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11036 rettv->v_type = VAR_STRING;
11037}
11038#endif /* FEAT_CRYPT */
11039
11040/*
11041 * "shellescape({string})" function
11042 */
11043 static void
11044f_shellescape(typval_T *argvars, typval_T *rettv)
11045{
Bram Moolenaar20615522017-06-05 18:46:26 +020011046 int do_special = non_zero_arg(&argvars[1]);
11047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011048 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaar20615522017-06-05 18:46:26 +020011049 get_tv_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011050 rettv->v_type = VAR_STRING;
11051}
11052
11053/*
11054 * shiftwidth() function
11055 */
11056 static void
11057f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11058{
11059 rettv->vval.v_number = get_sw_value(curbuf);
11060}
11061
11062/*
11063 * "simplify()" function
11064 */
11065 static void
11066f_simplify(typval_T *argvars, typval_T *rettv)
11067{
11068 char_u *p;
11069
11070 p = get_tv_string(&argvars[0]);
11071 rettv->vval.v_string = vim_strsave(p);
11072 simplify_filename(rettv->vval.v_string); /* simplify in place */
11073 rettv->v_type = VAR_STRING;
11074}
11075
11076#ifdef FEAT_FLOAT
11077/*
11078 * "sin()" function
11079 */
11080 static void
11081f_sin(typval_T *argvars, typval_T *rettv)
11082{
11083 float_T f = 0.0;
11084
11085 rettv->v_type = VAR_FLOAT;
11086 if (get_float_arg(argvars, &f) == OK)
11087 rettv->vval.v_float = sin(f);
11088 else
11089 rettv->vval.v_float = 0.0;
11090}
11091
11092/*
11093 * "sinh()" function
11094 */
11095 static void
11096f_sinh(typval_T *argvars, typval_T *rettv)
11097{
11098 float_T f = 0.0;
11099
11100 rettv->v_type = VAR_FLOAT;
11101 if (get_float_arg(argvars, &f) == OK)
11102 rettv->vval.v_float = sinh(f);
11103 else
11104 rettv->vval.v_float = 0.0;
11105}
11106#endif
11107
11108static int
11109#ifdef __BORLANDC__
11110 _RTLENTRYF
11111#endif
11112 item_compare(const void *s1, const void *s2);
11113static int
11114#ifdef __BORLANDC__
11115 _RTLENTRYF
11116#endif
11117 item_compare2(const void *s1, const void *s2);
11118
11119/* struct used in the array that's given to qsort() */
11120typedef struct
11121{
11122 listitem_T *item;
11123 int idx;
11124} sortItem_T;
11125
11126/* struct storing information about current sort */
11127typedef struct
11128{
11129 int item_compare_ic;
11130 int item_compare_numeric;
11131 int item_compare_numbers;
11132#ifdef FEAT_FLOAT
11133 int item_compare_float;
11134#endif
11135 char_u *item_compare_func;
11136 partial_T *item_compare_partial;
11137 dict_T *item_compare_selfdict;
11138 int item_compare_func_err;
11139 int item_compare_keep_zero;
11140} sortinfo_T;
11141static sortinfo_T *sortinfo = NULL;
11142static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
11143#define ITEM_COMPARE_FAIL 999
11144
11145/*
11146 * Compare functions for f_sort() and f_uniq() below.
11147 */
11148 static int
11149#ifdef __BORLANDC__
11150_RTLENTRYF
11151#endif
11152item_compare(const void *s1, const void *s2)
11153{
11154 sortItem_T *si1, *si2;
11155 typval_T *tv1, *tv2;
11156 char_u *p1, *p2;
11157 char_u *tofree1 = NULL, *tofree2 = NULL;
11158 int res;
11159 char_u numbuf1[NUMBUFLEN];
11160 char_u numbuf2[NUMBUFLEN];
11161
11162 si1 = (sortItem_T *)s1;
11163 si2 = (sortItem_T *)s2;
11164 tv1 = &si1->item->li_tv;
11165 tv2 = &si2->item->li_tv;
11166
11167 if (sortinfo->item_compare_numbers)
11168 {
11169 varnumber_T v1 = get_tv_number(tv1);
11170 varnumber_T v2 = get_tv_number(tv2);
11171
11172 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11173 }
11174
11175#ifdef FEAT_FLOAT
11176 if (sortinfo->item_compare_float)
11177 {
11178 float_T v1 = get_tv_float(tv1);
11179 float_T v2 = get_tv_float(tv2);
11180
11181 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11182 }
11183#endif
11184
11185 /* tv2string() puts quotes around a string and allocates memory. Don't do
11186 * that for string variables. Use a single quote when comparing with a
11187 * non-string to do what the docs promise. */
11188 if (tv1->v_type == VAR_STRING)
11189 {
11190 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11191 p1 = (char_u *)"'";
11192 else
11193 p1 = tv1->vval.v_string;
11194 }
11195 else
11196 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11197 if (tv2->v_type == VAR_STRING)
11198 {
11199 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11200 p2 = (char_u *)"'";
11201 else
11202 p2 = tv2->vval.v_string;
11203 }
11204 else
11205 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11206 if (p1 == NULL)
11207 p1 = (char_u *)"";
11208 if (p2 == NULL)
11209 p2 = (char_u *)"";
11210 if (!sortinfo->item_compare_numeric)
11211 {
11212 if (sortinfo->item_compare_ic)
11213 res = STRICMP(p1, p2);
11214 else
11215 res = STRCMP(p1, p2);
11216 }
11217 else
11218 {
11219 double n1, n2;
11220 n1 = strtod((char *)p1, (char **)&p1);
11221 n2 = strtod((char *)p2, (char **)&p2);
11222 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11223 }
11224
11225 /* When the result would be zero, compare the item indexes. Makes the
11226 * sort stable. */
11227 if (res == 0 && !sortinfo->item_compare_keep_zero)
11228 res = si1->idx > si2->idx ? 1 : -1;
11229
11230 vim_free(tofree1);
11231 vim_free(tofree2);
11232 return res;
11233}
11234
11235 static int
11236#ifdef __BORLANDC__
11237_RTLENTRYF
11238#endif
11239item_compare2(const void *s1, const void *s2)
11240{
11241 sortItem_T *si1, *si2;
11242 int res;
11243 typval_T rettv;
11244 typval_T argv[3];
11245 int dummy;
11246 char_u *func_name;
11247 partial_T *partial = sortinfo->item_compare_partial;
11248
11249 /* shortcut after failure in previous call; compare all items equal */
11250 if (sortinfo->item_compare_func_err)
11251 return 0;
11252
11253 si1 = (sortItem_T *)s1;
11254 si2 = (sortItem_T *)s2;
11255
11256 if (partial == NULL)
11257 func_name = sortinfo->item_compare_func;
11258 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011259 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011260
11261 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11262 * in the copy without changing the original list items. */
11263 copy_tv(&si1->item->li_tv, &argv[0]);
11264 copy_tv(&si2->item->li_tv, &argv[1]);
11265
11266 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
11267 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020011268 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011269 partial, sortinfo->item_compare_selfdict);
11270 clear_tv(&argv[0]);
11271 clear_tv(&argv[1]);
11272
11273 if (res == FAIL)
11274 res = ITEM_COMPARE_FAIL;
11275 else
11276 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
11277 if (sortinfo->item_compare_func_err)
11278 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11279 clear_tv(&rettv);
11280
11281 /* When the result would be zero, compare the pointers themselves. Makes
11282 * the sort stable. */
11283 if (res == 0 && !sortinfo->item_compare_keep_zero)
11284 res = si1->idx > si2->idx ? 1 : -1;
11285
11286 return res;
11287}
11288
11289/*
11290 * "sort({list})" function
11291 */
11292 static void
11293do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11294{
11295 list_T *l;
11296 listitem_T *li;
11297 sortItem_T *ptrs;
11298 sortinfo_T *old_sortinfo;
11299 sortinfo_T info;
11300 long len;
11301 long i;
11302
11303 /* Pointer to current info struct used in compare function. Save and
11304 * restore the current one for nested calls. */
11305 old_sortinfo = sortinfo;
11306 sortinfo = &info;
11307
11308 if (argvars[0].v_type != VAR_LIST)
11309 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
11310 else
11311 {
11312 l = argvars[0].vval.v_list;
11313 if (l == NULL || tv_check_lock(l->lv_lock,
11314 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11315 TRUE))
11316 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011317 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011318
11319 len = list_len(l);
11320 if (len <= 1)
11321 goto theend; /* short list sorts pretty quickly */
11322
11323 info.item_compare_ic = FALSE;
11324 info.item_compare_numeric = FALSE;
11325 info.item_compare_numbers = FALSE;
11326#ifdef FEAT_FLOAT
11327 info.item_compare_float = FALSE;
11328#endif
11329 info.item_compare_func = NULL;
11330 info.item_compare_partial = NULL;
11331 info.item_compare_selfdict = NULL;
11332 if (argvars[1].v_type != VAR_UNKNOWN)
11333 {
11334 /* optional second argument: {func} */
11335 if (argvars[1].v_type == VAR_FUNC)
11336 info.item_compare_func = argvars[1].vval.v_string;
11337 else if (argvars[1].v_type == VAR_PARTIAL)
11338 info.item_compare_partial = argvars[1].vval.v_partial;
11339 else
11340 {
11341 int error = FALSE;
11342
11343 i = (long)get_tv_number_chk(&argvars[1], &error);
11344 if (error)
11345 goto theend; /* type error; errmsg already given */
11346 if (i == 1)
11347 info.item_compare_ic = TRUE;
11348 else if (argvars[1].v_type != VAR_NUMBER)
11349 info.item_compare_func = get_tv_string(&argvars[1]);
11350 else if (i != 0)
11351 {
11352 EMSG(_(e_invarg));
11353 goto theend;
11354 }
11355 if (info.item_compare_func != NULL)
11356 {
11357 if (*info.item_compare_func == NUL)
11358 {
11359 /* empty string means default sort */
11360 info.item_compare_func = NULL;
11361 }
11362 else if (STRCMP(info.item_compare_func, "n") == 0)
11363 {
11364 info.item_compare_func = NULL;
11365 info.item_compare_numeric = TRUE;
11366 }
11367 else if (STRCMP(info.item_compare_func, "N") == 0)
11368 {
11369 info.item_compare_func = NULL;
11370 info.item_compare_numbers = TRUE;
11371 }
11372#ifdef FEAT_FLOAT
11373 else if (STRCMP(info.item_compare_func, "f") == 0)
11374 {
11375 info.item_compare_func = NULL;
11376 info.item_compare_float = TRUE;
11377 }
11378#endif
11379 else if (STRCMP(info.item_compare_func, "i") == 0)
11380 {
11381 info.item_compare_func = NULL;
11382 info.item_compare_ic = TRUE;
11383 }
11384 }
11385 }
11386
11387 if (argvars[2].v_type != VAR_UNKNOWN)
11388 {
11389 /* optional third argument: {dict} */
11390 if (argvars[2].v_type != VAR_DICT)
11391 {
11392 EMSG(_(e_dictreq));
11393 goto theend;
11394 }
11395 info.item_compare_selfdict = argvars[2].vval.v_dict;
11396 }
11397 }
11398
11399 /* Make an array with each entry pointing to an item in the List. */
11400 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
11401 if (ptrs == NULL)
11402 goto theend;
11403
11404 i = 0;
11405 if (sort)
11406 {
11407 /* sort(): ptrs will be the list to sort */
11408 for (li = l->lv_first; li != NULL; li = li->li_next)
11409 {
11410 ptrs[i].item = li;
11411 ptrs[i].idx = i;
11412 ++i;
11413 }
11414
11415 info.item_compare_func_err = FALSE;
11416 info.item_compare_keep_zero = FALSE;
11417 /* test the compare function */
11418 if ((info.item_compare_func != NULL
11419 || info.item_compare_partial != NULL)
11420 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11421 == ITEM_COMPARE_FAIL)
11422 EMSG(_("E702: Sort compare function failed"));
11423 else
11424 {
11425 /* Sort the array with item pointers. */
11426 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11427 info.item_compare_func == NULL
11428 && info.item_compare_partial == NULL
11429 ? item_compare : item_compare2);
11430
11431 if (!info.item_compare_func_err)
11432 {
11433 /* Clear the List and append the items in sorted order. */
11434 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11435 l->lv_len = 0;
11436 for (i = 0; i < len; ++i)
11437 list_append(l, ptrs[i].item);
11438 }
11439 }
11440 }
11441 else
11442 {
11443 int (*item_compare_func_ptr)(const void *, const void *);
11444
11445 /* f_uniq(): ptrs will be a stack of items to remove */
11446 info.item_compare_func_err = FALSE;
11447 info.item_compare_keep_zero = TRUE;
11448 item_compare_func_ptr = info.item_compare_func != NULL
11449 || info.item_compare_partial != NULL
11450 ? item_compare2 : item_compare;
11451
11452 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11453 li = li->li_next)
11454 {
11455 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11456 == 0)
11457 ptrs[i++].item = li;
11458 if (info.item_compare_func_err)
11459 {
11460 EMSG(_("E882: Uniq compare function failed"));
11461 break;
11462 }
11463 }
11464
11465 if (!info.item_compare_func_err)
11466 {
11467 while (--i >= 0)
11468 {
11469 li = ptrs[i].item->li_next;
11470 ptrs[i].item->li_next = li->li_next;
11471 if (li->li_next != NULL)
11472 li->li_next->li_prev = ptrs[i].item;
11473 else
11474 l->lv_last = ptrs[i].item;
11475 list_fix_watch(l, li);
11476 listitem_free(li);
11477 l->lv_len--;
11478 }
11479 }
11480 }
11481
11482 vim_free(ptrs);
11483 }
11484theend:
11485 sortinfo = old_sortinfo;
11486}
11487
11488/*
11489 * "sort({list})" function
11490 */
11491 static void
11492f_sort(typval_T *argvars, typval_T *rettv)
11493{
11494 do_sort_uniq(argvars, rettv, TRUE);
11495}
11496
11497/*
11498 * "uniq({list})" function
11499 */
11500 static void
11501f_uniq(typval_T *argvars, typval_T *rettv)
11502{
11503 do_sort_uniq(argvars, rettv, FALSE);
11504}
11505
11506/*
11507 * "soundfold({word})" function
11508 */
11509 static void
11510f_soundfold(typval_T *argvars, typval_T *rettv)
11511{
11512 char_u *s;
11513
11514 rettv->v_type = VAR_STRING;
11515 s = get_tv_string(&argvars[0]);
11516#ifdef FEAT_SPELL
11517 rettv->vval.v_string = eval_soundfold(s);
11518#else
11519 rettv->vval.v_string = vim_strsave(s);
11520#endif
11521}
11522
11523/*
11524 * "spellbadword()" function
11525 */
11526 static void
11527f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11528{
11529 char_u *word = (char_u *)"";
11530 hlf_T attr = HLF_COUNT;
11531 int len = 0;
11532
11533 if (rettv_list_alloc(rettv) == FAIL)
11534 return;
11535
11536#ifdef FEAT_SPELL
11537 if (argvars[0].v_type == VAR_UNKNOWN)
11538 {
11539 /* Find the start and length of the badly spelled word. */
11540 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11541 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011542 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011543 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011544 curwin->w_set_curswant = TRUE;
11545 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011546 }
11547 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11548 {
11549 char_u *str = get_tv_string_chk(&argvars[0]);
11550 int capcol = -1;
11551
11552 if (str != NULL)
11553 {
11554 /* Check the argument for spelling. */
11555 while (*str != NUL)
11556 {
11557 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11558 if (attr != HLF_COUNT)
11559 {
11560 word = str;
11561 break;
11562 }
11563 str += len;
11564 }
11565 }
11566 }
11567#endif
11568
11569 list_append_string(rettv->vval.v_list, word, len);
11570 list_append_string(rettv->vval.v_list, (char_u *)(
11571 attr == HLF_SPB ? "bad" :
11572 attr == HLF_SPR ? "rare" :
11573 attr == HLF_SPL ? "local" :
11574 attr == HLF_SPC ? "caps" :
11575 ""), -1);
11576}
11577
11578/*
11579 * "spellsuggest()" function
11580 */
11581 static void
11582f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11583{
11584#ifdef FEAT_SPELL
11585 char_u *str;
11586 int typeerr = FALSE;
11587 int maxcount;
11588 garray_T ga;
11589 int i;
11590 listitem_T *li;
11591 int need_capital = FALSE;
11592#endif
11593
11594 if (rettv_list_alloc(rettv) == FAIL)
11595 return;
11596
11597#ifdef FEAT_SPELL
11598 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11599 {
11600 str = get_tv_string(&argvars[0]);
11601 if (argvars[1].v_type != VAR_UNKNOWN)
11602 {
11603 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11604 if (maxcount <= 0)
11605 return;
11606 if (argvars[2].v_type != VAR_UNKNOWN)
11607 {
11608 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11609 if (typeerr)
11610 return;
11611 }
11612 }
11613 else
11614 maxcount = 25;
11615
11616 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11617
11618 for (i = 0; i < ga.ga_len; ++i)
11619 {
11620 str = ((char_u **)ga.ga_data)[i];
11621
11622 li = listitem_alloc();
11623 if (li == NULL)
11624 vim_free(str);
11625 else
11626 {
11627 li->li_tv.v_type = VAR_STRING;
11628 li->li_tv.v_lock = 0;
11629 li->li_tv.vval.v_string = str;
11630 list_append(rettv->vval.v_list, li);
11631 }
11632 }
11633 ga_clear(&ga);
11634 }
11635#endif
11636}
11637
11638 static void
11639f_split(typval_T *argvars, typval_T *rettv)
11640{
11641 char_u *str;
11642 char_u *end;
11643 char_u *pat = NULL;
11644 regmatch_T regmatch;
11645 char_u patbuf[NUMBUFLEN];
11646 char_u *save_cpo;
11647 int match;
11648 colnr_T col = 0;
11649 int keepempty = FALSE;
11650 int typeerr = FALSE;
11651
11652 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11653 save_cpo = p_cpo;
11654 p_cpo = (char_u *)"";
11655
11656 str = get_tv_string(&argvars[0]);
11657 if (argvars[1].v_type != VAR_UNKNOWN)
11658 {
11659 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11660 if (pat == NULL)
11661 typeerr = TRUE;
11662 if (argvars[2].v_type != VAR_UNKNOWN)
11663 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11664 }
11665 if (pat == NULL || *pat == NUL)
11666 pat = (char_u *)"[\\x01- ]\\+";
11667
11668 if (rettv_list_alloc(rettv) == FAIL)
11669 return;
11670 if (typeerr)
11671 return;
11672
11673 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11674 if (regmatch.regprog != NULL)
11675 {
11676 regmatch.rm_ic = FALSE;
11677 while (*str != NUL || keepempty)
11678 {
11679 if (*str == NUL)
11680 match = FALSE; /* empty item at the end */
11681 else
11682 match = vim_regexec_nl(&regmatch, str, col);
11683 if (match)
11684 end = regmatch.startp[0];
11685 else
11686 end = str + STRLEN(str);
11687 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11688 && *str != NUL && match && end < regmatch.endp[0]))
11689 {
11690 if (list_append_string(rettv->vval.v_list, str,
11691 (int)(end - str)) == FAIL)
11692 break;
11693 }
11694 if (!match)
11695 break;
11696 /* Advance to just after the match. */
11697 if (regmatch.endp[0] > str)
11698 col = 0;
11699 else
11700 {
11701 /* Don't get stuck at the same match. */
11702#ifdef FEAT_MBYTE
11703 col = (*mb_ptr2len)(regmatch.endp[0]);
11704#else
11705 col = 1;
11706#endif
11707 }
11708 str = regmatch.endp[0];
11709 }
11710
11711 vim_regfree(regmatch.regprog);
11712 }
11713
11714 p_cpo = save_cpo;
11715}
11716
11717#ifdef FEAT_FLOAT
11718/*
11719 * "sqrt()" function
11720 */
11721 static void
11722f_sqrt(typval_T *argvars, typval_T *rettv)
11723{
11724 float_T f = 0.0;
11725
11726 rettv->v_type = VAR_FLOAT;
11727 if (get_float_arg(argvars, &f) == OK)
11728 rettv->vval.v_float = sqrt(f);
11729 else
11730 rettv->vval.v_float = 0.0;
11731}
11732
11733/*
11734 * "str2float()" function
11735 */
11736 static void
11737f_str2float(typval_T *argvars, typval_T *rettv)
11738{
11739 char_u *p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011740 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011741
Bram Moolenaar08243d22017-01-10 16:12:29 +010011742 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011743 p = skipwhite(p + 1);
11744 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011745 if (isneg)
11746 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011747 rettv->v_type = VAR_FLOAT;
11748}
11749#endif
11750
11751/*
11752 * "str2nr()" function
11753 */
11754 static void
11755f_str2nr(typval_T *argvars, typval_T *rettv)
11756{
11757 int base = 10;
11758 char_u *p;
11759 varnumber_T n;
11760 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011761 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011762
11763 if (argvars[1].v_type != VAR_UNKNOWN)
11764 {
11765 base = (int)get_tv_number(&argvars[1]);
11766 if (base != 2 && base != 8 && base != 10 && base != 16)
11767 {
11768 EMSG(_(e_invarg));
11769 return;
11770 }
11771 }
11772
11773 p = skipwhite(get_tv_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011774 isneg = (*p == '-');
11775 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011776 p = skipwhite(p + 1);
11777 switch (base)
11778 {
11779 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11780 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11781 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11782 default: what = 0;
11783 }
11784 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011785 if (isneg)
11786 rettv->vval.v_number = -n;
11787 else
11788 rettv->vval.v_number = n;
11789
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011790}
11791
11792#ifdef HAVE_STRFTIME
11793/*
11794 * "strftime({format}[, {time}])" function
11795 */
11796 static void
11797f_strftime(typval_T *argvars, typval_T *rettv)
11798{
11799 char_u result_buf[256];
11800 struct tm *curtime;
11801 time_t seconds;
11802 char_u *p;
11803
11804 rettv->v_type = VAR_STRING;
11805
11806 p = get_tv_string(&argvars[0]);
11807 if (argvars[1].v_type == VAR_UNKNOWN)
11808 seconds = time(NULL);
11809 else
11810 seconds = (time_t)get_tv_number(&argvars[1]);
11811 curtime = localtime(&seconds);
11812 /* MSVC returns NULL for an invalid value of seconds. */
11813 if (curtime == NULL)
11814 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11815 else
11816 {
11817# ifdef FEAT_MBYTE
11818 vimconv_T conv;
11819 char_u *enc;
11820
11821 conv.vc_type = CONV_NONE;
11822 enc = enc_locale();
11823 convert_setup(&conv, p_enc, enc);
11824 if (conv.vc_type != CONV_NONE)
11825 p = string_convert(&conv, p, NULL);
11826# endif
11827 if (p != NULL)
11828 (void)strftime((char *)result_buf, sizeof(result_buf),
11829 (char *)p, curtime);
11830 else
11831 result_buf[0] = NUL;
11832
11833# ifdef FEAT_MBYTE
11834 if (conv.vc_type != CONV_NONE)
11835 vim_free(p);
11836 convert_setup(&conv, enc, p_enc);
11837 if (conv.vc_type != CONV_NONE)
11838 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11839 else
11840# endif
11841 rettv->vval.v_string = vim_strsave(result_buf);
11842
11843# ifdef FEAT_MBYTE
11844 /* Release conversion descriptors */
11845 convert_setup(&conv, NULL, NULL);
11846 vim_free(enc);
11847# endif
11848 }
11849}
11850#endif
11851
11852/*
11853 * "strgetchar()" function
11854 */
11855 static void
11856f_strgetchar(typval_T *argvars, typval_T *rettv)
11857{
11858 char_u *str;
11859 int len;
11860 int error = FALSE;
11861 int charidx;
11862
11863 rettv->vval.v_number = -1;
11864 str = get_tv_string_chk(&argvars[0]);
11865 if (str == NULL)
11866 return;
11867 len = (int)STRLEN(str);
11868 charidx = (int)get_tv_number_chk(&argvars[1], &error);
11869 if (error)
11870 return;
11871#ifdef FEAT_MBYTE
11872 {
11873 int byteidx = 0;
11874
11875 while (charidx >= 0 && byteidx < len)
11876 {
11877 if (charidx == 0)
11878 {
11879 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11880 break;
11881 }
11882 --charidx;
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011883 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011884 }
11885 }
11886#else
11887 if (charidx < len)
11888 rettv->vval.v_number = str[charidx];
11889#endif
11890}
11891
11892/*
11893 * "stridx()" function
11894 */
11895 static void
11896f_stridx(typval_T *argvars, typval_T *rettv)
11897{
11898 char_u buf[NUMBUFLEN];
11899 char_u *needle;
11900 char_u *haystack;
11901 char_u *save_haystack;
11902 char_u *pos;
11903 int start_idx;
11904
11905 needle = get_tv_string_chk(&argvars[1]);
11906 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11907 rettv->vval.v_number = -1;
11908 if (needle == NULL || haystack == NULL)
11909 return; /* type error; errmsg already given */
11910
11911 if (argvars[2].v_type != VAR_UNKNOWN)
11912 {
11913 int error = FALSE;
11914
11915 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11916 if (error || start_idx >= (int)STRLEN(haystack))
11917 return;
11918 if (start_idx >= 0)
11919 haystack += start_idx;
11920 }
11921
11922 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11923 if (pos != NULL)
11924 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11925}
11926
11927/*
11928 * "string()" function
11929 */
11930 static void
11931f_string(typval_T *argvars, typval_T *rettv)
11932{
11933 char_u *tofree;
11934 char_u numbuf[NUMBUFLEN];
11935
11936 rettv->v_type = VAR_STRING;
11937 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11938 get_copyID());
11939 /* Make a copy if we have a value but it's not in allocated memory. */
11940 if (rettv->vval.v_string != NULL && tofree == NULL)
11941 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11942}
11943
11944/*
11945 * "strlen()" function
11946 */
11947 static void
11948f_strlen(typval_T *argvars, typval_T *rettv)
11949{
11950 rettv->vval.v_number = (varnumber_T)(STRLEN(
11951 get_tv_string(&argvars[0])));
11952}
11953
11954/*
11955 * "strchars()" function
11956 */
11957 static void
11958f_strchars(typval_T *argvars, typval_T *rettv)
11959{
11960 char_u *s = get_tv_string(&argvars[0]);
11961 int skipcc = 0;
11962#ifdef FEAT_MBYTE
11963 varnumber_T len = 0;
11964 int (*func_mb_ptr2char_adv)(char_u **pp);
11965#endif
11966
11967 if (argvars[1].v_type != VAR_UNKNOWN)
11968 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11969 if (skipcc < 0 || skipcc > 1)
11970 EMSG(_(e_invarg));
11971 else
11972 {
11973#ifdef FEAT_MBYTE
11974 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11975 while (*s != NUL)
11976 {
11977 func_mb_ptr2char_adv(&s);
11978 ++len;
11979 }
11980 rettv->vval.v_number = len;
11981#else
11982 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11983#endif
11984 }
11985}
11986
11987/*
11988 * "strdisplaywidth()" function
11989 */
11990 static void
11991f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11992{
11993 char_u *s = get_tv_string(&argvars[0]);
11994 int col = 0;
11995
11996 if (argvars[1].v_type != VAR_UNKNOWN)
11997 col = (int)get_tv_number(&argvars[1]);
11998
11999 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12000}
12001
12002/*
12003 * "strwidth()" function
12004 */
12005 static void
12006f_strwidth(typval_T *argvars, typval_T *rettv)
12007{
12008 char_u *s = get_tv_string(&argvars[0]);
12009
12010 rettv->vval.v_number = (varnumber_T)(
12011#ifdef FEAT_MBYTE
12012 mb_string2cells(s, -1)
12013#else
12014 STRLEN(s)
12015#endif
12016 );
12017}
12018
12019/*
12020 * "strcharpart()" function
12021 */
12022 static void
12023f_strcharpart(typval_T *argvars, typval_T *rettv)
12024{
12025#ifdef FEAT_MBYTE
12026 char_u *p;
12027 int nchar;
12028 int nbyte = 0;
12029 int charlen;
12030 int len = 0;
12031 int slen;
12032 int error = FALSE;
12033
12034 p = get_tv_string(&argvars[0]);
12035 slen = (int)STRLEN(p);
12036
12037 nchar = (int)get_tv_number_chk(&argvars[1], &error);
12038 if (!error)
12039 {
12040 if (nchar > 0)
12041 while (nchar > 0 && nbyte < slen)
12042 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012043 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012044 --nchar;
12045 }
12046 else
12047 nbyte = nchar;
12048 if (argvars[2].v_type != VAR_UNKNOWN)
12049 {
12050 charlen = (int)get_tv_number(&argvars[2]);
12051 while (charlen > 0 && nbyte + len < slen)
12052 {
12053 int off = nbyte + len;
12054
12055 if (off < 0)
12056 len += 1;
12057 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012058 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012059 --charlen;
12060 }
12061 }
12062 else
12063 len = slen - nbyte; /* default: all bytes that are available. */
12064 }
12065
12066 /*
12067 * Only return the overlap between the specified part and the actual
12068 * string.
12069 */
12070 if (nbyte < 0)
12071 {
12072 len += nbyte;
12073 nbyte = 0;
12074 }
12075 else if (nbyte > slen)
12076 nbyte = slen;
12077 if (len < 0)
12078 len = 0;
12079 else if (nbyte + len > slen)
12080 len = slen - nbyte;
12081
12082 rettv->v_type = VAR_STRING;
12083 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12084#else
12085 f_strpart(argvars, rettv);
12086#endif
12087}
12088
12089/*
12090 * "strpart()" function
12091 */
12092 static void
12093f_strpart(typval_T *argvars, typval_T *rettv)
12094{
12095 char_u *p;
12096 int n;
12097 int len;
12098 int slen;
12099 int error = FALSE;
12100
12101 p = get_tv_string(&argvars[0]);
12102 slen = (int)STRLEN(p);
12103
12104 n = (int)get_tv_number_chk(&argvars[1], &error);
12105 if (error)
12106 len = 0;
12107 else if (argvars[2].v_type != VAR_UNKNOWN)
12108 len = (int)get_tv_number(&argvars[2]);
12109 else
12110 len = slen - n; /* default len: all bytes that are available. */
12111
12112 /*
12113 * Only return the overlap between the specified part and the actual
12114 * string.
12115 */
12116 if (n < 0)
12117 {
12118 len += n;
12119 n = 0;
12120 }
12121 else if (n > slen)
12122 n = slen;
12123 if (len < 0)
12124 len = 0;
12125 else if (n + len > slen)
12126 len = slen - n;
12127
12128 rettv->v_type = VAR_STRING;
12129 rettv->vval.v_string = vim_strnsave(p + n, len);
12130}
12131
12132/*
12133 * "strridx()" function
12134 */
12135 static void
12136f_strridx(typval_T *argvars, typval_T *rettv)
12137{
12138 char_u buf[NUMBUFLEN];
12139 char_u *needle;
12140 char_u *haystack;
12141 char_u *rest;
12142 char_u *lastmatch = NULL;
12143 int haystack_len, end_idx;
12144
12145 needle = get_tv_string_chk(&argvars[1]);
12146 haystack = get_tv_string_buf_chk(&argvars[0], buf);
12147
12148 rettv->vval.v_number = -1;
12149 if (needle == NULL || haystack == NULL)
12150 return; /* type error; errmsg already given */
12151
12152 haystack_len = (int)STRLEN(haystack);
12153 if (argvars[2].v_type != VAR_UNKNOWN)
12154 {
12155 /* Third argument: upper limit for index */
12156 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
12157 if (end_idx < 0)
12158 return; /* can never find a match */
12159 }
12160 else
12161 end_idx = haystack_len;
12162
12163 if (*needle == NUL)
12164 {
12165 /* Empty string matches past the end. */
12166 lastmatch = haystack + end_idx;
12167 }
12168 else
12169 {
12170 for (rest = haystack; *rest != '\0'; ++rest)
12171 {
12172 rest = (char_u *)strstr((char *)rest, (char *)needle);
12173 if (rest == NULL || rest > haystack + end_idx)
12174 break;
12175 lastmatch = rest;
12176 }
12177 }
12178
12179 if (lastmatch == NULL)
12180 rettv->vval.v_number = -1;
12181 else
12182 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12183}
12184
12185/*
12186 * "strtrans()" function
12187 */
12188 static void
12189f_strtrans(typval_T *argvars, typval_T *rettv)
12190{
12191 rettv->v_type = VAR_STRING;
12192 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
12193}
12194
12195/*
12196 * "submatch()" function
12197 */
12198 static void
12199f_submatch(typval_T *argvars, typval_T *rettv)
12200{
12201 int error = FALSE;
12202 int no;
12203 int retList = 0;
12204
12205 no = (int)get_tv_number_chk(&argvars[0], &error);
12206 if (error)
12207 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012208 if (no < 0 || no >= NSUBEXP)
12209 {
Bram Moolenaar79518e22017-02-17 16:31:35 +010012210 EMSGN(_("E935: invalid submatch number: %d"), no);
12211 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012212 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012213 if (argvars[1].v_type != VAR_UNKNOWN)
12214 retList = (int)get_tv_number_chk(&argvars[1], &error);
12215 if (error)
12216 return;
12217
12218 if (retList == 0)
12219 {
12220 rettv->v_type = VAR_STRING;
12221 rettv->vval.v_string = reg_submatch(no);
12222 }
12223 else
12224 {
12225 rettv->v_type = VAR_LIST;
12226 rettv->vval.v_list = reg_submatch_list(no);
12227 }
12228}
12229
12230/*
12231 * "substitute()" function
12232 */
12233 static void
12234f_substitute(typval_T *argvars, typval_T *rettv)
12235{
12236 char_u patbuf[NUMBUFLEN];
12237 char_u subbuf[NUMBUFLEN];
12238 char_u flagsbuf[NUMBUFLEN];
12239
12240 char_u *str = get_tv_string_chk(&argvars[0]);
12241 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012242 char_u *sub = NULL;
12243 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012244 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
12245
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012246 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12247 expr = &argvars[2];
12248 else
12249 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
12250
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012251 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012252 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12253 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012254 rettv->vval.v_string = NULL;
12255 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012256 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012257}
12258
12259/*
12260 * "synID(lnum, col, trans)" function
12261 */
12262 static void
12263f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12264{
12265 int id = 0;
12266#ifdef FEAT_SYN_HL
12267 linenr_T lnum;
12268 colnr_T col;
12269 int trans;
12270 int transerr = FALSE;
12271
12272 lnum = get_tv_lnum(argvars); /* -1 on type error */
12273 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12274 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
12275
12276 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12277 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12278 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12279#endif
12280
12281 rettv->vval.v_number = id;
12282}
12283
12284/*
12285 * "synIDattr(id, what [, mode])" function
12286 */
12287 static void
12288f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12289{
12290 char_u *p = NULL;
12291#ifdef FEAT_SYN_HL
12292 int id;
12293 char_u *what;
12294 char_u *mode;
12295 char_u modebuf[NUMBUFLEN];
12296 int modec;
12297
12298 id = (int)get_tv_number(&argvars[0]);
12299 what = get_tv_string(&argvars[1]);
12300 if (argvars[2].v_type != VAR_UNKNOWN)
12301 {
12302 mode = get_tv_string_buf(&argvars[2], modebuf);
12303 modec = TOLOWER_ASC(mode[0]);
12304 if (modec != 't' && modec != 'c' && modec != 'g')
12305 modec = 0; /* replace invalid with current */
12306 }
12307 else
12308 {
12309#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12310 if (USE_24BIT)
12311 modec = 'g';
12312 else
12313#endif
12314 if (t_colors > 1)
12315 modec = 'c';
12316 else
12317 modec = 't';
12318 }
12319
12320
12321 switch (TOLOWER_ASC(what[0]))
12322 {
12323 case 'b':
12324 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12325 p = highlight_color(id, what, modec);
12326 else /* bold */
12327 p = highlight_has_attr(id, HL_BOLD, modec);
12328 break;
12329
12330 case 'f': /* fg[#] or font */
12331 p = highlight_color(id, what, modec);
12332 break;
12333
12334 case 'i':
12335 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12336 p = highlight_has_attr(id, HL_INVERSE, modec);
12337 else /* italic */
12338 p = highlight_has_attr(id, HL_ITALIC, modec);
12339 break;
12340
12341 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012342 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012343 break;
12344
12345 case 'r': /* reverse */
12346 p = highlight_has_attr(id, HL_INVERSE, modec);
12347 break;
12348
12349 case 's':
12350 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12351 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012352 /* strikeout */
12353 else if (TOLOWER_ASC(what[1]) == 't' &&
12354 TOLOWER_ASC(what[2]) == 'r')
12355 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012356 else /* standout */
12357 p = highlight_has_attr(id, HL_STANDOUT, modec);
12358 break;
12359
12360 case 'u':
12361 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12362 /* underline */
12363 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12364 else
12365 /* undercurl */
12366 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12367 break;
12368 }
12369
12370 if (p != NULL)
12371 p = vim_strsave(p);
12372#endif
12373 rettv->v_type = VAR_STRING;
12374 rettv->vval.v_string = p;
12375}
12376
12377/*
12378 * "synIDtrans(id)" function
12379 */
12380 static void
12381f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12382{
12383 int id;
12384
12385#ifdef FEAT_SYN_HL
12386 id = (int)get_tv_number(&argvars[0]);
12387
12388 if (id > 0)
12389 id = syn_get_final_id(id);
12390 else
12391#endif
12392 id = 0;
12393
12394 rettv->vval.v_number = id;
12395}
12396
12397/*
12398 * "synconcealed(lnum, col)" function
12399 */
12400 static void
12401f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12402{
12403#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12404 linenr_T lnum;
12405 colnr_T col;
12406 int syntax_flags = 0;
12407 int cchar;
12408 int matchid = 0;
12409 char_u str[NUMBUFLEN];
12410#endif
12411
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012412 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012413
12414#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12415 lnum = get_tv_lnum(argvars); /* -1 on type error */
12416 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12417
12418 vim_memset(str, NUL, sizeof(str));
12419
12420 if (rettv_list_alloc(rettv) != FAIL)
12421 {
12422 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12423 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12424 && curwin->w_p_cole > 0)
12425 {
12426 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12427 syntax_flags = get_syntax_info(&matchid);
12428
12429 /* get the conceal character */
12430 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12431 {
12432 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012433 if (cchar == NUL && curwin->w_p_cole == 1)
12434 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012435 if (cchar != NUL)
12436 {
12437# ifdef FEAT_MBYTE
12438 if (has_mbyte)
12439 (*mb_char2bytes)(cchar, str);
12440 else
12441# endif
12442 str[0] = cchar;
12443 }
12444 }
12445 }
12446
12447 list_append_number(rettv->vval.v_list,
12448 (syntax_flags & HL_CONCEAL) != 0);
12449 /* -1 to auto-determine strlen */
12450 list_append_string(rettv->vval.v_list, str, -1);
12451 list_append_number(rettv->vval.v_list, matchid);
12452 }
12453#endif
12454}
12455
12456/*
12457 * "synstack(lnum, col)" function
12458 */
12459 static void
12460f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12461{
12462#ifdef FEAT_SYN_HL
12463 linenr_T lnum;
12464 colnr_T col;
12465 int i;
12466 int id;
12467#endif
12468
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012469 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012470
12471#ifdef FEAT_SYN_HL
12472 lnum = get_tv_lnum(argvars); /* -1 on type error */
12473 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
12474
12475 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12476 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12477 && rettv_list_alloc(rettv) != FAIL)
12478 {
12479 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12480 for (i = 0; ; ++i)
12481 {
12482 id = syn_get_stack_item(i);
12483 if (id < 0)
12484 break;
12485 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12486 break;
12487 }
12488 }
12489#endif
12490}
12491
12492 static void
12493get_cmd_output_as_rettv(
12494 typval_T *argvars,
12495 typval_T *rettv,
12496 int retlist)
12497{
12498 char_u *res = NULL;
12499 char_u *p;
12500 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012501 int err = FALSE;
12502 FILE *fd;
12503 list_T *list = NULL;
12504 int flags = SHELL_SILENT;
12505
12506 rettv->v_type = VAR_STRING;
12507 rettv->vval.v_string = NULL;
12508 if (check_restricted() || check_secure())
12509 goto errret;
12510
12511 if (argvars[1].v_type != VAR_UNKNOWN)
12512 {
12513 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012514 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012515 * command.
12516 */
12517 if ((infile = vim_tempname('i', TRUE)) == NULL)
12518 {
12519 EMSG(_(e_notmp));
12520 goto errret;
12521 }
12522
12523 fd = mch_fopen((char *)infile, WRITEBIN);
12524 if (fd == NULL)
12525 {
12526 EMSG2(_(e_notopen), infile);
12527 goto errret;
12528 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012529 if (argvars[1].v_type == VAR_NUMBER)
12530 {
12531 linenr_T lnum;
12532 buf_T *buf;
12533
12534 buf = buflist_findnr(argvars[1].vval.v_number);
12535 if (buf == NULL)
12536 {
12537 EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012538 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012539 goto errret;
12540 }
12541
12542 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12543 {
12544 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12545 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12546 {
12547 err = TRUE;
12548 break;
12549 }
12550 if (putc(NL, fd) == EOF)
12551 {
12552 err = TRUE;
12553 break;
12554 }
12555 }
12556 }
12557 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012558 {
12559 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12560 err = TRUE;
12561 }
12562 else
12563 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012564 size_t len;
12565 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012566
12567 p = get_tv_string_buf_chk(&argvars[1], buf);
12568 if (p == NULL)
12569 {
12570 fclose(fd);
12571 goto errret; /* type error; errmsg already given */
12572 }
12573 len = STRLEN(p);
12574 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12575 err = TRUE;
12576 }
12577 if (fclose(fd) != 0)
12578 err = TRUE;
12579 if (err)
12580 {
12581 EMSG(_("E677: Error writing temp file"));
12582 goto errret;
12583 }
12584 }
12585
12586 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12587 * echoes typeahead, that messes up the display. */
12588 if (!msg_silent)
12589 flags += SHELL_COOKED;
12590
12591 if (retlist)
12592 {
12593 int len;
12594 listitem_T *li;
12595 char_u *s = NULL;
12596 char_u *start;
12597 char_u *end;
12598 int i;
12599
12600 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12601 if (res == NULL)
12602 goto errret;
12603
12604 list = list_alloc();
12605 if (list == NULL)
12606 goto errret;
12607
12608 for (i = 0; i < len; ++i)
12609 {
12610 start = res + i;
12611 while (i < len && res[i] != NL)
12612 ++i;
12613 end = res + i;
12614
12615 s = alloc((unsigned)(end - start + 1));
12616 if (s == NULL)
12617 goto errret;
12618
12619 for (p = s; start < end; ++p, ++start)
12620 *p = *start == NUL ? NL : *start;
12621 *p = NUL;
12622
12623 li = listitem_alloc();
12624 if (li == NULL)
12625 {
12626 vim_free(s);
12627 goto errret;
12628 }
12629 li->li_tv.v_type = VAR_STRING;
12630 li->li_tv.v_lock = 0;
12631 li->li_tv.vval.v_string = s;
12632 list_append(list, li);
12633 }
12634
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012635 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012636 list = NULL;
12637 }
12638 else
12639 {
12640 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12641#ifdef USE_CR
12642 /* translate <CR> into <NL> */
12643 if (res != NULL)
12644 {
12645 char_u *s;
12646
12647 for (s = res; *s; ++s)
12648 {
12649 if (*s == CAR)
12650 *s = NL;
12651 }
12652 }
12653#else
12654# ifdef USE_CRNL
12655 /* translate <CR><NL> into <NL> */
12656 if (res != NULL)
12657 {
12658 char_u *s, *d;
12659
12660 d = res;
12661 for (s = res; *s; ++s)
12662 {
12663 if (s[0] == CAR && s[1] == NL)
12664 ++s;
12665 *d++ = *s;
12666 }
12667 *d = NUL;
12668 }
12669# endif
12670#endif
12671 rettv->vval.v_string = res;
12672 res = NULL;
12673 }
12674
12675errret:
12676 if (infile != NULL)
12677 {
12678 mch_remove(infile);
12679 vim_free(infile);
12680 }
12681 if (res != NULL)
12682 vim_free(res);
12683 if (list != NULL)
12684 list_free(list);
12685}
12686
12687/*
12688 * "system()" function
12689 */
12690 static void
12691f_system(typval_T *argvars, typval_T *rettv)
12692{
12693 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12694}
12695
12696/*
12697 * "systemlist()" function
12698 */
12699 static void
12700f_systemlist(typval_T *argvars, typval_T *rettv)
12701{
12702 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12703}
12704
12705/*
12706 * "tabpagebuflist()" function
12707 */
12708 static void
12709f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12710{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012711 tabpage_T *tp;
12712 win_T *wp = NULL;
12713
12714 if (argvars[0].v_type == VAR_UNKNOWN)
12715 wp = firstwin;
12716 else
12717 {
12718 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12719 if (tp != NULL)
12720 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12721 }
12722 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12723 {
12724 for (; wp != NULL; wp = wp->w_next)
12725 if (list_append_number(rettv->vval.v_list,
12726 wp->w_buffer->b_fnum) == FAIL)
12727 break;
12728 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012729}
12730
12731
12732/*
12733 * "tabpagenr()" function
12734 */
12735 static void
12736f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12737{
12738 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012739 char_u *arg;
12740
12741 if (argvars[0].v_type != VAR_UNKNOWN)
12742 {
12743 arg = get_tv_string_chk(&argvars[0]);
12744 nr = 0;
12745 if (arg != NULL)
12746 {
12747 if (STRCMP(arg, "$") == 0)
12748 nr = tabpage_index(NULL) - 1;
12749 else
12750 EMSG2(_(e_invexpr2), arg);
12751 }
12752 }
12753 else
12754 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012755 rettv->vval.v_number = nr;
12756}
12757
12758
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012759static int get_winnr(tabpage_T *tp, typval_T *argvar);
12760
12761/*
12762 * Common code for tabpagewinnr() and winnr().
12763 */
12764 static int
12765get_winnr(tabpage_T *tp, typval_T *argvar)
12766{
12767 win_T *twin;
12768 int nr = 1;
12769 win_T *wp;
12770 char_u *arg;
12771
12772 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12773 if (argvar->v_type != VAR_UNKNOWN)
12774 {
12775 arg = get_tv_string_chk(argvar);
12776 if (arg == NULL)
12777 nr = 0; /* type error; errmsg already given */
12778 else if (STRCMP(arg, "$") == 0)
12779 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12780 else if (STRCMP(arg, "#") == 0)
12781 {
12782 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12783 if (twin == NULL)
12784 nr = 0;
12785 }
12786 else
12787 {
12788 EMSG2(_(e_invexpr2), arg);
12789 nr = 0;
12790 }
12791 }
12792
12793 if (nr > 0)
12794 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12795 wp != twin; wp = wp->w_next)
12796 {
12797 if (wp == NULL)
12798 {
12799 /* didn't find it in this tabpage */
12800 nr = 0;
12801 break;
12802 }
12803 ++nr;
12804 }
12805 return nr;
12806}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012807
12808/*
12809 * "tabpagewinnr()" function
12810 */
12811 static void
12812f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12813{
12814 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012815 tabpage_T *tp;
12816
12817 tp = find_tabpage((int)get_tv_number(&argvars[0]));
12818 if (tp == NULL)
12819 nr = 0;
12820 else
12821 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012822 rettv->vval.v_number = nr;
12823}
12824
12825
12826/*
12827 * "tagfiles()" function
12828 */
12829 static void
12830f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12831{
12832 char_u *fname;
12833 tagname_T tn;
12834 int first;
12835
12836 if (rettv_list_alloc(rettv) == FAIL)
12837 return;
12838 fname = alloc(MAXPATHL);
12839 if (fname == NULL)
12840 return;
12841
12842 for (first = TRUE; ; first = FALSE)
12843 if (get_tagfname(&tn, first, fname) == FAIL
12844 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12845 break;
12846 tagname_free(&tn);
12847 vim_free(fname);
12848}
12849
12850/*
12851 * "taglist()" function
12852 */
12853 static void
12854f_taglist(typval_T *argvars, typval_T *rettv)
12855{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012856 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012857 char_u *tag_pattern;
12858
12859 tag_pattern = get_tv_string(&argvars[0]);
12860
12861 rettv->vval.v_number = FALSE;
12862 if (*tag_pattern == NUL)
12863 return;
12864
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012865 if (argvars[1].v_type != VAR_UNKNOWN)
12866 fname = get_tv_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012867 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012868 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012869}
12870
12871/*
12872 * "tempname()" function
12873 */
12874 static void
12875f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12876{
12877 static int x = 'A';
12878
12879 rettv->v_type = VAR_STRING;
12880 rettv->vval.v_string = vim_tempname(x, FALSE);
12881
12882 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12883 * names. Skip 'I' and 'O', they are used for shell redirection. */
12884 do
12885 {
12886 if (x == 'Z')
12887 x = '0';
12888 else if (x == '9')
12889 x = 'A';
12890 else
12891 {
12892#ifdef EBCDIC
12893 if (x == 'I')
12894 x = 'J';
12895 else if (x == 'R')
12896 x = 'S';
12897 else
12898#endif
12899 ++x;
12900 }
12901 } while (x == 'I' || x == 'O');
12902}
12903
12904#ifdef FEAT_FLOAT
12905/*
12906 * "tan()" function
12907 */
12908 static void
12909f_tan(typval_T *argvars, typval_T *rettv)
12910{
12911 float_T f = 0.0;
12912
12913 rettv->v_type = VAR_FLOAT;
12914 if (get_float_arg(argvars, &f) == OK)
12915 rettv->vval.v_float = tan(f);
12916 else
12917 rettv->vval.v_float = 0.0;
12918}
12919
12920/*
12921 * "tanh()" function
12922 */
12923 static void
12924f_tanh(typval_T *argvars, typval_T *rettv)
12925{
12926 float_T f = 0.0;
12927
12928 rettv->v_type = VAR_FLOAT;
12929 if (get_float_arg(argvars, &f) == OK)
12930 rettv->vval.v_float = tanh(f);
12931 else
12932 rettv->vval.v_float = 0.0;
12933}
12934#endif
12935
12936/*
12937 * "test_alloc_fail(id, countdown, repeat)" function
12938 */
12939 static void
12940f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12941{
12942 if (argvars[0].v_type != VAR_NUMBER
12943 || argvars[0].vval.v_number <= 0
12944 || argvars[1].v_type != VAR_NUMBER
12945 || argvars[1].vval.v_number < 0
12946 || argvars[2].v_type != VAR_NUMBER)
12947 EMSG(_(e_invarg));
12948 else
12949 {
12950 alloc_fail_id = argvars[0].vval.v_number;
12951 if (alloc_fail_id >= aid_last)
12952 EMSG(_(e_invarg));
12953 alloc_fail_countdown = argvars[1].vval.v_number;
12954 alloc_fail_repeat = argvars[2].vval.v_number;
12955 did_outofmem_msg = FALSE;
12956 }
12957}
12958
12959/*
12960 * "test_autochdir()"
12961 */
12962 static void
12963f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12964{
12965#if defined(FEAT_AUTOCHDIR)
12966 test_autochdir = TRUE;
12967#endif
12968}
12969
12970/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020012971 * "test_feedinput()"
12972 */
12973 static void
12974f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
12975{
12976#ifdef USE_INPUT_BUF
12977 char_u *val = get_tv_string_chk(&argvars[0]);
12978
12979 if (val != NULL)
12980 {
12981 trash_input_buf();
12982 add_to_input_buf_csi(val, (int)STRLEN(val));
12983 }
12984#endif
12985}
12986
12987/*
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012988 * "test_disable({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012989 */
12990 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012991f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012992{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012993 char_u *name = (char_u *)"";
12994 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020012995 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010012996
12997 if (argvars[0].v_type != VAR_STRING
12998 || (argvars[1].v_type) != VAR_NUMBER)
12999 EMSG(_(e_invarg));
13000 else
13001 {
13002 name = get_tv_string_chk(&argvars[0]);
13003 val = (int)get_tv_number(&argvars[1]);
13004
13005 if (STRCMP(name, (char_u *)"redraw") == 0)
13006 disable_redraw_for_testing = val;
13007 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13008 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013009 else if (STRCMP(name, (char_u *)"starting") == 0)
13010 {
13011 if (val)
13012 {
13013 if (save_starting < 0)
13014 save_starting = starting;
13015 starting = 0;
13016 }
13017 else
13018 {
13019 starting = save_starting;
13020 save_starting = -1;
13021 }
13022 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013023 else if (STRCMP(name, (char_u *)"ALL") == 0)
13024 {
13025 disable_char_avail_for_testing = FALSE;
13026 disable_redraw_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013027 if (save_starting >= 0)
13028 {
13029 starting = save_starting;
13030 save_starting = -1;
13031 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013032 }
13033 else
13034 EMSG2(_(e_invarg2), name);
13035 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013036}
13037
13038/*
13039 * "test_garbagecollect_now()" function
13040 */
13041 static void
13042f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13043{
13044 /* This is dangerous, any Lists and Dicts used internally may be freed
13045 * while still in use. */
13046 garbage_collect(TRUE);
13047}
13048
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013049/*
13050 * "test_ignore_error()" function
13051 */
13052 static void
13053f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13054{
13055 ignore_error_for_testing(get_tv_string(&argvars[0]));
13056}
13057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013058#ifdef FEAT_JOB_CHANNEL
13059 static void
13060f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13061{
13062 rettv->v_type = VAR_CHANNEL;
13063 rettv->vval.v_channel = NULL;
13064}
13065#endif
13066
13067 static void
13068f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13069{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013070 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013071}
13072
13073#ifdef FEAT_JOB_CHANNEL
13074 static void
13075f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13076{
13077 rettv->v_type = VAR_JOB;
13078 rettv->vval.v_job = NULL;
13079}
13080#endif
13081
13082 static void
13083f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13084{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013085 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013086}
13087
13088 static void
13089f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13090{
13091 rettv->v_type = VAR_PARTIAL;
13092 rettv->vval.v_partial = NULL;
13093}
13094
13095 static void
13096f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13097{
13098 rettv->v_type = VAR_STRING;
13099 rettv->vval.v_string = NULL;
13100}
13101
13102 static void
13103f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13104{
13105 time_for_testing = (time_t)get_tv_number(&argvars[0]);
13106}
13107
13108#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13109/*
13110 * Get a callback from "arg". It can be a Funcref or a function name.
13111 * When "arg" is zero return an empty string.
13112 * Return NULL for an invalid argument.
13113 */
13114 char_u *
13115get_callback(typval_T *arg, partial_T **pp)
13116{
13117 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13118 {
13119 *pp = arg->vval.v_partial;
13120 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013121 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013122 }
13123 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013124 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013125 {
13126 func_ref(arg->vval.v_string);
13127 return arg->vval.v_string;
13128 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013129 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13130 return (char_u *)"";
13131 EMSG(_("E921: Invalid callback argument"));
13132 return NULL;
13133}
13134
13135/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013136 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013137 */
13138 void
13139free_callback(char_u *callback, partial_T *partial)
13140{
13141 if (partial != NULL)
13142 partial_unref(partial);
13143 else if (callback != NULL)
13144 {
13145 func_unref(callback);
13146 vim_free(callback);
13147 }
13148}
13149#endif
13150
13151#ifdef FEAT_TIMERS
13152/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013153 * "timer_info([timer])" function
13154 */
13155 static void
13156f_timer_info(typval_T *argvars, typval_T *rettv)
13157{
13158 timer_T *timer = NULL;
13159
13160 if (rettv_list_alloc(rettv) != OK)
13161 return;
13162 if (argvars[0].v_type != VAR_UNKNOWN)
13163 {
13164 if (argvars[0].v_type != VAR_NUMBER)
13165 EMSG(_(e_number_exp));
13166 else
13167 {
13168 timer = find_timer((int)get_tv_number(&argvars[0]));
13169 if (timer != NULL)
13170 add_timer_info(rettv, timer);
13171 }
13172 }
13173 else
13174 add_timer_info_all(rettv);
13175}
13176
13177/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013178 * "timer_pause(timer, paused)" function
13179 */
13180 static void
13181f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13182{
13183 timer_T *timer = NULL;
13184 int paused = (int)get_tv_number(&argvars[1]);
13185
13186 if (argvars[0].v_type != VAR_NUMBER)
13187 EMSG(_(e_number_exp));
13188 else
13189 {
13190 timer = find_timer((int)get_tv_number(&argvars[0]));
13191 if (timer != NULL)
13192 timer->tr_paused = paused;
13193 }
13194}
13195
13196/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013197 * "timer_start(time, callback [, options])" function
13198 */
13199 static void
13200f_timer_start(typval_T *argvars, typval_T *rettv)
13201{
Bram Moolenaar75537a92016-09-05 22:45:28 +020013202 long msec = (long)get_tv_number(&argvars[0]);
13203 timer_T *timer;
13204 int repeat = 0;
13205 char_u *callback;
13206 dict_T *dict;
13207 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013208
Bram Moolenaar75537a92016-09-05 22:45:28 +020013209 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013210 if (check_secure())
13211 return;
13212 if (argvars[2].v_type != VAR_UNKNOWN)
13213 {
13214 if (argvars[2].v_type != VAR_DICT
13215 || (dict = argvars[2].vval.v_dict) == NULL)
13216 {
13217 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
13218 return;
13219 }
13220 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
13221 repeat = get_dict_number(dict, (char_u *)"repeat");
13222 }
13223
Bram Moolenaar75537a92016-09-05 22:45:28 +020013224 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013225 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013226 return;
13227
13228 timer = create_timer(msec, repeat);
13229 if (timer == NULL)
13230 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013231 else
13232 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020013233 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020013234 timer->tr_callback = vim_strsave(callback);
13235 else
13236 /* pointer into the partial */
13237 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013238 timer->tr_partial = partial;
13239 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013240 }
13241}
13242
13243/*
13244 * "timer_stop(timer)" function
13245 */
13246 static void
13247f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13248{
13249 timer_T *timer;
13250
13251 if (argvars[0].v_type != VAR_NUMBER)
13252 {
13253 EMSG(_(e_number_exp));
13254 return;
13255 }
13256 timer = find_timer((int)get_tv_number(&argvars[0]));
13257 if (timer != NULL)
13258 stop_timer(timer);
13259}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013260
13261/*
13262 * "timer_stopall()" function
13263 */
13264 static void
13265f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13266{
13267 stop_all_timers();
13268}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013269#endif
13270
13271/*
13272 * "tolower(string)" function
13273 */
13274 static void
13275f_tolower(typval_T *argvars, typval_T *rettv)
13276{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013277 rettv->v_type = VAR_STRING;
Bram Moolenaarcc5b22b2017-01-26 22:51:56 +010013278 rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013279}
13280
13281/*
13282 * "toupper(string)" function
13283 */
13284 static void
13285f_toupper(typval_T *argvars, typval_T *rettv)
13286{
13287 rettv->v_type = VAR_STRING;
13288 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
13289}
13290
13291/*
13292 * "tr(string, fromstr, tostr)" function
13293 */
13294 static void
13295f_tr(typval_T *argvars, typval_T *rettv)
13296{
13297 char_u *in_str;
13298 char_u *fromstr;
13299 char_u *tostr;
13300 char_u *p;
13301#ifdef FEAT_MBYTE
13302 int inlen;
13303 int fromlen;
13304 int tolen;
13305 int idx;
13306 char_u *cpstr;
13307 int cplen;
13308 int first = TRUE;
13309#endif
13310 char_u buf[NUMBUFLEN];
13311 char_u buf2[NUMBUFLEN];
13312 garray_T ga;
13313
13314 in_str = get_tv_string(&argvars[0]);
13315 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
13316 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
13317
13318 /* Default return value: empty string. */
13319 rettv->v_type = VAR_STRING;
13320 rettv->vval.v_string = NULL;
13321 if (fromstr == NULL || tostr == NULL)
13322 return; /* type error; errmsg already given */
13323 ga_init2(&ga, (int)sizeof(char), 80);
13324
13325#ifdef FEAT_MBYTE
13326 if (!has_mbyte)
13327#endif
13328 /* not multi-byte: fromstr and tostr must be the same length */
13329 if (STRLEN(fromstr) != STRLEN(tostr))
13330 {
13331#ifdef FEAT_MBYTE
13332error:
13333#endif
13334 EMSG2(_(e_invarg2), fromstr);
13335 ga_clear(&ga);
13336 return;
13337 }
13338
13339 /* fromstr and tostr have to contain the same number of chars */
13340 while (*in_str != NUL)
13341 {
13342#ifdef FEAT_MBYTE
13343 if (has_mbyte)
13344 {
13345 inlen = (*mb_ptr2len)(in_str);
13346 cpstr = in_str;
13347 cplen = inlen;
13348 idx = 0;
13349 for (p = fromstr; *p != NUL; p += fromlen)
13350 {
13351 fromlen = (*mb_ptr2len)(p);
13352 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13353 {
13354 for (p = tostr; *p != NUL; p += tolen)
13355 {
13356 tolen = (*mb_ptr2len)(p);
13357 if (idx-- == 0)
13358 {
13359 cplen = tolen;
13360 cpstr = p;
13361 break;
13362 }
13363 }
13364 if (*p == NUL) /* tostr is shorter than fromstr */
13365 goto error;
13366 break;
13367 }
13368 ++idx;
13369 }
13370
13371 if (first && cpstr == in_str)
13372 {
13373 /* Check that fromstr and tostr have the same number of
13374 * (multi-byte) characters. Done only once when a character
13375 * of in_str doesn't appear in fromstr. */
13376 first = FALSE;
13377 for (p = tostr; *p != NUL; p += tolen)
13378 {
13379 tolen = (*mb_ptr2len)(p);
13380 --idx;
13381 }
13382 if (idx != 0)
13383 goto error;
13384 }
13385
13386 (void)ga_grow(&ga, cplen);
13387 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13388 ga.ga_len += cplen;
13389
13390 in_str += inlen;
13391 }
13392 else
13393#endif
13394 {
13395 /* When not using multi-byte chars we can do it faster. */
13396 p = vim_strchr(fromstr, *in_str);
13397 if (p != NULL)
13398 ga_append(&ga, tostr[p - fromstr]);
13399 else
13400 ga_append(&ga, *in_str);
13401 ++in_str;
13402 }
13403 }
13404
13405 /* add a terminating NUL */
13406 (void)ga_grow(&ga, 1);
13407 ga_append(&ga, NUL);
13408
13409 rettv->vval.v_string = ga.ga_data;
13410}
13411
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013412/*
13413 * "trim({expr})" function
13414 */
13415 static void
13416f_trim(typval_T *argvars, typval_T *rettv)
13417{
13418 char_u buf1[NUMBUFLEN];
13419 char_u buf2[NUMBUFLEN];
13420 char_u *head = get_tv_string_buf_chk(&argvars[0], buf1);
13421 char_u *mask = NULL;
13422 char_u *tail;
13423 char_u *prev;
13424 char_u *p;
13425 int c1;
13426
13427 rettv->v_type = VAR_STRING;
13428 if (head == NULL)
13429 {
13430 rettv->vval.v_string = NULL;
13431 return;
13432 }
13433
13434 if (argvars[1].v_type == VAR_STRING)
13435 mask = get_tv_string_buf_chk(&argvars[1], buf2);
13436
13437 while (*head != NUL)
13438 {
13439 c1 = PTR2CHAR(head);
13440 if (mask == NULL)
13441 {
13442 if (c1 > ' ' && c1 != 0xa0)
13443 break;
13444 }
13445 else
13446 {
13447 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13448 if (c1 == PTR2CHAR(p))
13449 break;
13450 if (*p == NUL)
13451 break;
13452 }
13453 MB_PTR_ADV(head);
13454 }
13455
13456 for (tail = head + STRLEN(head); tail > head; tail = prev)
13457 {
13458 prev = tail;
13459 MB_PTR_BACK(head, prev);
13460 c1 = PTR2CHAR(prev);
13461 if (mask == NULL)
13462 {
13463 if (c1 > ' ' && c1 != 0xa0)
13464 break;
13465 }
13466 else
13467 {
13468 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13469 if (c1 == PTR2CHAR(p))
13470 break;
13471 if (*p == NUL)
13472 break;
13473 }
13474 }
13475 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13476}
13477
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013478#ifdef FEAT_FLOAT
13479/*
13480 * "trunc({float})" function
13481 */
13482 static void
13483f_trunc(typval_T *argvars, typval_T *rettv)
13484{
13485 float_T f = 0.0;
13486
13487 rettv->v_type = VAR_FLOAT;
13488 if (get_float_arg(argvars, &f) == OK)
13489 /* trunc() is not in C90, use floor() or ceil() instead. */
13490 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13491 else
13492 rettv->vval.v_float = 0.0;
13493}
13494#endif
13495
13496/*
13497 * "type(expr)" function
13498 */
13499 static void
13500f_type(typval_T *argvars, typval_T *rettv)
13501{
13502 int n = -1;
13503
13504 switch (argvars[0].v_type)
13505 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013506 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13507 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013508 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013509 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13510 case VAR_LIST: n = VAR_TYPE_LIST; break;
13511 case VAR_DICT: n = VAR_TYPE_DICT; break;
13512 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013513 case VAR_SPECIAL:
13514 if (argvars[0].vval.v_number == VVAL_FALSE
13515 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013516 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013517 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013518 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013519 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013520 case VAR_JOB: n = VAR_TYPE_JOB; break;
13521 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013522 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013523 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013524 n = -1;
13525 break;
13526 }
13527 rettv->vval.v_number = n;
13528}
13529
13530/*
13531 * "undofile(name)" function
13532 */
13533 static void
13534f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13535{
13536 rettv->v_type = VAR_STRING;
13537#ifdef FEAT_PERSISTENT_UNDO
13538 {
13539 char_u *fname = get_tv_string(&argvars[0]);
13540
13541 if (*fname == NUL)
13542 {
13543 /* If there is no file name there will be no undo file. */
13544 rettv->vval.v_string = NULL;
13545 }
13546 else
13547 {
13548 char_u *ffname = FullName_save(fname, FALSE);
13549
13550 if (ffname != NULL)
13551 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13552 vim_free(ffname);
13553 }
13554 }
13555#else
13556 rettv->vval.v_string = NULL;
13557#endif
13558}
13559
13560/*
13561 * "undotree()" function
13562 */
13563 static void
13564f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13565{
13566 if (rettv_dict_alloc(rettv) == OK)
13567 {
13568 dict_T *dict = rettv->vval.v_dict;
13569 list_T *list;
13570
13571 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
13572 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
13573 dict_add_nr_str(dict, "save_last",
13574 (long)curbuf->b_u_save_nr_last, NULL);
13575 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
13576 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
13577 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
13578
13579 list = list_alloc();
13580 if (list != NULL)
13581 {
13582 u_eval_tree(curbuf->b_u_oldhead, list);
13583 dict_add_list(dict, "entries", list);
13584 }
13585 }
13586}
13587
13588/*
13589 * "values(dict)" function
13590 */
13591 static void
13592f_values(typval_T *argvars, typval_T *rettv)
13593{
13594 dict_list(argvars, rettv, 1);
13595}
13596
13597/*
13598 * "virtcol(string)" function
13599 */
13600 static void
13601f_virtcol(typval_T *argvars, typval_T *rettv)
13602{
13603 colnr_T vcol = 0;
13604 pos_T *fp;
13605 int fnum = curbuf->b_fnum;
13606
13607 fp = var2fpos(&argvars[0], FALSE, &fnum);
13608 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13609 && fnum == curbuf->b_fnum)
13610 {
13611 getvvcol(curwin, fp, NULL, NULL, &vcol);
13612 ++vcol;
13613 }
13614
13615 rettv->vval.v_number = vcol;
13616}
13617
13618/*
13619 * "visualmode()" function
13620 */
13621 static void
13622f_visualmode(typval_T *argvars, typval_T *rettv)
13623{
13624 char_u str[2];
13625
13626 rettv->v_type = VAR_STRING;
13627 str[0] = curbuf->b_visual_mode_eval;
13628 str[1] = NUL;
13629 rettv->vval.v_string = vim_strsave(str);
13630
13631 /* A non-zero number or non-empty string argument: reset mode. */
13632 if (non_zero_arg(&argvars[0]))
13633 curbuf->b_visual_mode_eval = NUL;
13634}
13635
13636/*
13637 * "wildmenumode()" function
13638 */
13639 static void
13640f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13641{
13642#ifdef FEAT_WILDMENU
13643 if (wild_menu_showing)
13644 rettv->vval.v_number = 1;
13645#endif
13646}
13647
13648/*
13649 * "winbufnr(nr)" function
13650 */
13651 static void
13652f_winbufnr(typval_T *argvars, typval_T *rettv)
13653{
13654 win_T *wp;
13655
13656 wp = find_win_by_nr(&argvars[0], NULL);
13657 if (wp == NULL)
13658 rettv->vval.v_number = -1;
13659 else
13660 rettv->vval.v_number = wp->w_buffer->b_fnum;
13661}
13662
13663/*
13664 * "wincol()" function
13665 */
13666 static void
13667f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13668{
13669 validate_cursor();
13670 rettv->vval.v_number = curwin->w_wcol + 1;
13671}
13672
13673/*
13674 * "winheight(nr)" function
13675 */
13676 static void
13677f_winheight(typval_T *argvars, typval_T *rettv)
13678{
13679 win_T *wp;
13680
13681 wp = find_win_by_nr(&argvars[0], NULL);
13682 if (wp == NULL)
13683 rettv->vval.v_number = -1;
13684 else
13685 rettv->vval.v_number = wp->w_height;
13686}
13687
13688/*
13689 * "winline()" function
13690 */
13691 static void
13692f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13693{
13694 validate_cursor();
13695 rettv->vval.v_number = curwin->w_wrow + 1;
13696}
13697
13698/*
13699 * "winnr()" function
13700 */
13701 static void
13702f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13703{
13704 int nr = 1;
13705
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013706 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013707 rettv->vval.v_number = nr;
13708}
13709
13710/*
13711 * "winrestcmd()" function
13712 */
13713 static void
13714f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13715{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013716 win_T *wp;
13717 int winnr = 1;
13718 garray_T ga;
13719 char_u buf[50];
13720
13721 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013722 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013723 {
13724 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13725 ga_concat(&ga, buf);
13726 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13727 ga_concat(&ga, buf);
13728 ++winnr;
13729 }
13730 ga_append(&ga, NUL);
13731
13732 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013733 rettv->v_type = VAR_STRING;
13734}
13735
13736/*
13737 * "winrestview()" function
13738 */
13739 static void
13740f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13741{
13742 dict_T *dict;
13743
13744 if (argvars[0].v_type != VAR_DICT
13745 || (dict = argvars[0].vval.v_dict) == NULL)
13746 EMSG(_(e_invarg));
13747 else
13748 {
13749 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13750 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13751 if (dict_find(dict, (char_u *)"col", -1) != NULL)
13752 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13753#ifdef FEAT_VIRTUALEDIT
13754 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13755 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13756#endif
13757 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13758 {
13759 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13760 curwin->w_set_curswant = FALSE;
13761 }
13762
13763 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13764 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13765#ifdef FEAT_DIFF
13766 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13767 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13768#endif
13769 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13770 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13771 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13772 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13773
13774 check_cursor();
13775 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013776 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013777 changed_window_setting();
13778
13779 if (curwin->w_topline <= 0)
13780 curwin->w_topline = 1;
13781 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13782 curwin->w_topline = curbuf->b_ml.ml_line_count;
13783#ifdef FEAT_DIFF
13784 check_topfill(curwin, TRUE);
13785#endif
13786 }
13787}
13788
13789/*
13790 * "winsaveview()" function
13791 */
13792 static void
13793f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13794{
13795 dict_T *dict;
13796
13797 if (rettv_dict_alloc(rettv) == FAIL)
13798 return;
13799 dict = rettv->vval.v_dict;
13800
13801 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13802 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13803#ifdef FEAT_VIRTUALEDIT
13804 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13805#endif
13806 update_curswant();
13807 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13808
13809 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13810#ifdef FEAT_DIFF
13811 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13812#endif
13813 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13814 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13815}
13816
13817/*
13818 * "winwidth(nr)" function
13819 */
13820 static void
13821f_winwidth(typval_T *argvars, typval_T *rettv)
13822{
13823 win_T *wp;
13824
13825 wp = find_win_by_nr(&argvars[0], NULL);
13826 if (wp == NULL)
13827 rettv->vval.v_number = -1;
13828 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013829 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013830}
13831
13832/*
13833 * "wordcount()" function
13834 */
13835 static void
13836f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13837{
13838 if (rettv_dict_alloc(rettv) == FAIL)
13839 return;
13840 cursor_pos_info(rettv->vval.v_dict);
13841}
13842
13843/*
13844 * "writefile()" function
13845 */
13846 static void
13847f_writefile(typval_T *argvars, typval_T *rettv)
13848{
13849 int binary = FALSE;
13850 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013851#ifdef HAVE_FSYNC
13852 int do_fsync = p_fs;
13853#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013854 char_u *fname;
13855 FILE *fd;
13856 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013857 listitem_T *li;
13858 list_T *list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013859
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013860 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013861 if (check_restricted() || check_secure())
13862 return;
13863
13864 if (argvars[0].v_type != VAR_LIST)
13865 {
13866 EMSG2(_(e_listarg), "writefile()");
13867 return;
13868 }
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013869 list = argvars[0].vval.v_list;
13870 if (list == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013871 return;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013872 for (li = list->lv_first; li != NULL; li = li->li_next)
13873 if (get_tv_string_chk(&li->li_tv) == NULL)
13874 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013875
13876 if (argvars[2].v_type != VAR_UNKNOWN)
13877 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013878 char_u *arg2 = get_tv_string_chk(&argvars[2]);
13879
13880 if (arg2 == NULL)
13881 return;
13882 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013883 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013884 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013885 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013886#ifdef HAVE_FSYNC
13887 if (vim_strchr(arg2, 's') != NULL)
13888 do_fsync = TRUE;
13889 else if (vim_strchr(arg2, 'S') != NULL)
13890 do_fsync = FALSE;
13891#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013892 }
13893
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013894 fname = get_tv_string_chk(&argvars[1]);
13895 if (fname == NULL)
13896 return;
13897
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013898 /* Always open the file in binary mode, library functions have a mind of
13899 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013900 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13901 append ? APPENDBIN : WRITEBIN)) == NULL)
13902 {
13903 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13904 ret = -1;
13905 }
13906 else
13907 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013908 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013909 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013910#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013911 else if (do_fsync)
13912 /* Ignore the error, the user wouldn't know what to do about it.
13913 * May happen for a device. */
13914 ignored = fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013915#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013916 fclose(fd);
13917 }
13918
13919 rettv->vval.v_number = ret;
13920}
13921
13922/*
13923 * "xor(expr, expr)" function
13924 */
13925 static void
13926f_xor(typval_T *argvars, typval_T *rettv)
13927{
13928 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13929 ^ get_tv_number_chk(&argvars[1], NULL);
13930}
13931
13932
13933#endif /* FEAT_EVAL */