blob: f5a0bd8b5db4717886c5507f9f7d43abdbcd5096 [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");
Bram Moolenaarbf821bc2019-01-23 21:15:02 +010032static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020033static char *e_stringreq = N_("E928: String required");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020034
35#ifdef FEAT_FLOAT
36static void f_abs(typval_T *argvars, typval_T *rettv);
37static void f_acos(typval_T *argvars, typval_T *rettv);
38#endif
39static void f_add(typval_T *argvars, typval_T *rettv);
40static void f_and(typval_T *argvars, typval_T *rettv);
41static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020042static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020043static void f_argc(typval_T *argvars, typval_T *rettv);
44static void f_argidx(typval_T *argvars, typval_T *rettv);
45static void f_arglistid(typval_T *argvars, typval_T *rettv);
46static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010047static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010049static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_assert_exception(typval_T *argvars, typval_T *rettv);
51static void f_assert_fails(typval_T *argvars, typval_T *rettv);
52static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020053static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_assert_match(typval_T *argvars, typval_T *rettv);
55static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
56static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010057static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020058static void f_assert_true(typval_T *argvars, typval_T *rettv);
59#ifdef FEAT_FLOAT
60static void f_asin(typval_T *argvars, typval_T *rettv);
61static void f_atan(typval_T *argvars, typval_T *rettv);
62static void f_atan2(typval_T *argvars, typval_T *rettv);
63#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010064#ifdef FEAT_BEVAL
65static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010066# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010067static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010068# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010069#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_browse(typval_T *argvars, typval_T *rettv);
71static void f_browsedir(typval_T *argvars, typval_T *rettv);
72static void f_bufexists(typval_T *argvars, typval_T *rettv);
73static void f_buflisted(typval_T *argvars, typval_T *rettv);
74static void f_bufloaded(typval_T *argvars, typval_T *rettv);
75static void f_bufname(typval_T *argvars, typval_T *rettv);
76static void f_bufnr(typval_T *argvars, typval_T *rettv);
77static void f_bufwinid(typval_T *argvars, typval_T *rettv);
78static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
79static void f_byte2line(typval_T *argvars, typval_T *rettv);
80static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
81static void f_byteidx(typval_T *argvars, typval_T *rettv);
82static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
83static void f_call(typval_T *argvars, typval_T *rettv);
84#ifdef FEAT_FLOAT
85static void f_ceil(typval_T *argvars, typval_T *rettv);
86#endif
87#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010088static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020090static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
92static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
93static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
94static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
95static void f_ch_info(typval_T *argvars, typval_T *rettv);
96static void f_ch_log(typval_T *argvars, typval_T *rettv);
97static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
98static void f_ch_open(typval_T *argvars, typval_T *rettv);
99static void f_ch_read(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100100static void f_ch_readblob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
102static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
103static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
104static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
105static void f_ch_status(typval_T *argvars, typval_T *rettv);
106#endif
107static void f_changenr(typval_T *argvars, typval_T *rettv);
108static void f_char2nr(typval_T *argvars, typval_T *rettv);
109static void f_cindent(typval_T *argvars, typval_T *rettv);
110static void f_clearmatches(typval_T *argvars, typval_T *rettv);
111static void f_col(typval_T *argvars, typval_T *rettv);
112#if defined(FEAT_INS_EXPAND)
113static void f_complete(typval_T *argvars, typval_T *rettv);
114static void f_complete_add(typval_T *argvars, typval_T *rettv);
115static void f_complete_check(typval_T *argvars, typval_T *rettv);
116#endif
117static void f_confirm(typval_T *argvars, typval_T *rettv);
118static void f_copy(typval_T *argvars, typval_T *rettv);
119#ifdef FEAT_FLOAT
120static void f_cos(typval_T *argvars, typval_T *rettv);
121static void f_cosh(typval_T *argvars, typval_T *rettv);
122#endif
123static void f_count(typval_T *argvars, typval_T *rettv);
124static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
125static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100126#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200127static void f_debugbreak(typval_T *argvars, typval_T *rettv);
128#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_deepcopy(typval_T *argvars, typval_T *rettv);
130static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200131static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_did_filetype(typval_T *argvars, typval_T *rettv);
133static void f_diff_filler(typval_T *argvars, typval_T *rettv);
134static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
135static void f_empty(typval_T *argvars, typval_T *rettv);
136static void f_escape(typval_T *argvars, typval_T *rettv);
137static void f_eval(typval_T *argvars, typval_T *rettv);
138static void f_eventhandler(typval_T *argvars, typval_T *rettv);
139static void f_executable(typval_T *argvars, typval_T *rettv);
140static void f_execute(typval_T *argvars, typval_T *rettv);
141static void f_exepath(typval_T *argvars, typval_T *rettv);
142static void f_exists(typval_T *argvars, typval_T *rettv);
143#ifdef FEAT_FLOAT
144static void f_exp(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_expand(typval_T *argvars, typval_T *rettv);
147static void f_extend(typval_T *argvars, typval_T *rettv);
148static void f_feedkeys(typval_T *argvars, typval_T *rettv);
149static void f_filereadable(typval_T *argvars, typval_T *rettv);
150static void f_filewritable(typval_T *argvars, typval_T *rettv);
151static void f_filter(typval_T *argvars, typval_T *rettv);
152static void f_finddir(typval_T *argvars, typval_T *rettv);
153static void f_findfile(typval_T *argvars, typval_T *rettv);
154#ifdef FEAT_FLOAT
155static void f_float2nr(typval_T *argvars, typval_T *rettv);
156static void f_floor(typval_T *argvars, typval_T *rettv);
157static void f_fmod(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_fnameescape(typval_T *argvars, typval_T *rettv);
160static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
161static void f_foldclosed(typval_T *argvars, typval_T *rettv);
162static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
163static void f_foldlevel(typval_T *argvars, typval_T *rettv);
164static void f_foldtext(typval_T *argvars, typval_T *rettv);
165static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
166static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200167static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_function(typval_T *argvars, typval_T *rettv);
169static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
170static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200171static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_getbufline(typval_T *argvars, typval_T *rettv);
173static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100174static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_getchar(typval_T *argvars, typval_T *rettv);
176static void f_getcharmod(typval_T *argvars, typval_T *rettv);
177static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
178static void f_getcmdline(typval_T *argvars, typval_T *rettv);
179#if defined(FEAT_CMDL_COMPL)
180static void f_getcompletion(typval_T *argvars, typval_T *rettv);
181#endif
182static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
183static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
184static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
185static void f_getcwd(typval_T *argvars, typval_T *rettv);
186static void f_getfontname(typval_T *argvars, typval_T *rettv);
187static void f_getfperm(typval_T *argvars, typval_T *rettv);
188static void f_getfsize(typval_T *argvars, typval_T *rettv);
189static void f_getftime(typval_T *argvars, typval_T *rettv);
190static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100191static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200193static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getmatches(typval_T *argvars, typval_T *rettv);
195static void f_getpid(typval_T *argvars, typval_T *rettv);
196static void f_getcurpos(typval_T *argvars, typval_T *rettv);
197static void f_getpos(typval_T *argvars, typval_T *rettv);
198static void f_getqflist(typval_T *argvars, typval_T *rettv);
199static void f_getreg(typval_T *argvars, typval_T *rettv);
200static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200201static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_gettabvar(typval_T *argvars, typval_T *rettv);
203static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100204static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200205static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100206static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_getwinposx(typval_T *argvars, typval_T *rettv);
208static void f_getwinposy(typval_T *argvars, typval_T *rettv);
209static void f_getwinvar(typval_T *argvars, typval_T *rettv);
210static void f_glob(typval_T *argvars, typval_T *rettv);
211static void f_globpath(typval_T *argvars, typval_T *rettv);
212static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
213static void f_has(typval_T *argvars, typval_T *rettv);
214static void f_has_key(typval_T *argvars, typval_T *rettv);
215static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
216static void f_hasmapto(typval_T *argvars, typval_T *rettv);
217static void f_histadd(typval_T *argvars, typval_T *rettv);
218static void f_histdel(typval_T *argvars, typval_T *rettv);
219static void f_histget(typval_T *argvars, typval_T *rettv);
220static void f_histnr(typval_T *argvars, typval_T *rettv);
221static void f_hlID(typval_T *argvars, typval_T *rettv);
222static void f_hlexists(typval_T *argvars, typval_T *rettv);
223static void f_hostname(typval_T *argvars, typval_T *rettv);
224static void f_iconv(typval_T *argvars, typval_T *rettv);
225static void f_indent(typval_T *argvars, typval_T *rettv);
226static void f_index(typval_T *argvars, typval_T *rettv);
227static void f_input(typval_T *argvars, typval_T *rettv);
228static void f_inputdialog(typval_T *argvars, typval_T *rettv);
229static void f_inputlist(typval_T *argvars, typval_T *rettv);
230static void f_inputrestore(typval_T *argvars, typval_T *rettv);
231static void f_inputsave(typval_T *argvars, typval_T *rettv);
232static void f_inputsecret(typval_T *argvars, typval_T *rettv);
233static void f_insert(typval_T *argvars, typval_T *rettv);
234static void f_invert(typval_T *argvars, typval_T *rettv);
235static void f_isdirectory(typval_T *argvars, typval_T *rettv);
236static void f_islocked(typval_T *argvars, typval_T *rettv);
237#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
238static void f_isnan(typval_T *argvars, typval_T *rettv);
239#endif
240static void f_items(typval_T *argvars, typval_T *rettv);
241#ifdef FEAT_JOB_CHANNEL
242static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
243static void f_job_info(typval_T *argvars, typval_T *rettv);
244static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
245static void f_job_start(typval_T *argvars, typval_T *rettv);
246static void f_job_stop(typval_T *argvars, typval_T *rettv);
247static void f_job_status(typval_T *argvars, typval_T *rettv);
248#endif
249static void f_join(typval_T *argvars, typval_T *rettv);
250static void f_js_decode(typval_T *argvars, typval_T *rettv);
251static void f_js_encode(typval_T *argvars, typval_T *rettv);
252static void f_json_decode(typval_T *argvars, typval_T *rettv);
253static void f_json_encode(typval_T *argvars, typval_T *rettv);
254static void f_keys(typval_T *argvars, typval_T *rettv);
255static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
256static void f_len(typval_T *argvars, typval_T *rettv);
257static void f_libcall(typval_T *argvars, typval_T *rettv);
258static void f_libcallnr(typval_T *argvars, typval_T *rettv);
259static void f_line(typval_T *argvars, typval_T *rettv);
260static void f_line2byte(typval_T *argvars, typval_T *rettv);
261static void f_lispindent(typval_T *argvars, typval_T *rettv);
262static void f_localtime(typval_T *argvars, typval_T *rettv);
263#ifdef FEAT_FLOAT
264static void f_log(typval_T *argvars, typval_T *rettv);
265static void f_log10(typval_T *argvars, typval_T *rettv);
266#endif
267#ifdef FEAT_LUA
268static void f_luaeval(typval_T *argvars, typval_T *rettv);
269#endif
270static void f_map(typval_T *argvars, typval_T *rettv);
271static void f_maparg(typval_T *argvars, typval_T *rettv);
272static void f_mapcheck(typval_T *argvars, typval_T *rettv);
273static void f_match(typval_T *argvars, typval_T *rettv);
274static void f_matchadd(typval_T *argvars, typval_T *rettv);
275static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
276static void f_matcharg(typval_T *argvars, typval_T *rettv);
277static void f_matchdelete(typval_T *argvars, typval_T *rettv);
278static void f_matchend(typval_T *argvars, typval_T *rettv);
279static void f_matchlist(typval_T *argvars, typval_T *rettv);
280static void f_matchstr(typval_T *argvars, typval_T *rettv);
281static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
282static void f_max(typval_T *argvars, typval_T *rettv);
283static void f_min(typval_T *argvars, typval_T *rettv);
284#ifdef vim_mkdir
285static void f_mkdir(typval_T *argvars, typval_T *rettv);
286#endif
287static void f_mode(typval_T *argvars, typval_T *rettv);
288#ifdef FEAT_MZSCHEME
289static void f_mzeval(typval_T *argvars, typval_T *rettv);
290#endif
291static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
292static void f_nr2char(typval_T *argvars, typval_T *rettv);
293static void f_or(typval_T *argvars, typval_T *rettv);
294static void f_pathshorten(typval_T *argvars, typval_T *rettv);
295#ifdef FEAT_PERL
296static void f_perleval(typval_T *argvars, typval_T *rettv);
297#endif
298#ifdef FEAT_FLOAT
299static void f_pow(typval_T *argvars, typval_T *rettv);
300#endif
301static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
302static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200303#ifdef FEAT_JOB_CHANNEL
304static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200305static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200306static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
307#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200308static void f_pumvisible(typval_T *argvars, typval_T *rettv);
309#ifdef FEAT_PYTHON3
310static void f_py3eval(typval_T *argvars, typval_T *rettv);
311#endif
312#ifdef FEAT_PYTHON
313static void f_pyeval(typval_T *argvars, typval_T *rettv);
314#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100315#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
316static void f_pyxeval(typval_T *argvars, typval_T *rettv);
317#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200318static void f_range(typval_T *argvars, typval_T *rettv);
319static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200320static void f_reg_executing(typval_T *argvars, typval_T *rettv);
321static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200322static void f_reltime(typval_T *argvars, typval_T *rettv);
323#ifdef FEAT_FLOAT
324static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
325#endif
326static void f_reltimestr(typval_T *argvars, typval_T *rettv);
327static void f_remote_expr(typval_T *argvars, typval_T *rettv);
328static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
329static void f_remote_peek(typval_T *argvars, typval_T *rettv);
330static void f_remote_read(typval_T *argvars, typval_T *rettv);
331static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100332static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200333static void f_remove(typval_T *argvars, typval_T *rettv);
334static void f_rename(typval_T *argvars, typval_T *rettv);
335static void f_repeat(typval_T *argvars, typval_T *rettv);
336static void f_resolve(typval_T *argvars, typval_T *rettv);
337static void f_reverse(typval_T *argvars, typval_T *rettv);
338#ifdef FEAT_FLOAT
339static void f_round(typval_T *argvars, typval_T *rettv);
340#endif
341static void f_screenattr(typval_T *argvars, typval_T *rettv);
342static void f_screenchar(typval_T *argvars, typval_T *rettv);
343static void f_screencol(typval_T *argvars, typval_T *rettv);
344static void f_screenrow(typval_T *argvars, typval_T *rettv);
345static void f_search(typval_T *argvars, typval_T *rettv);
346static void f_searchdecl(typval_T *argvars, typval_T *rettv);
347static void f_searchpair(typval_T *argvars, typval_T *rettv);
348static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
349static void f_searchpos(typval_T *argvars, typval_T *rettv);
350static void f_server2client(typval_T *argvars, typval_T *rettv);
351static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200352static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353static void f_setbufvar(typval_T *argvars, typval_T *rettv);
354static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
355static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
356static void f_setfperm(typval_T *argvars, typval_T *rettv);
357static void f_setline(typval_T *argvars, typval_T *rettv);
358static void f_setloclist(typval_T *argvars, typval_T *rettv);
359static void f_setmatches(typval_T *argvars, typval_T *rettv);
360static void f_setpos(typval_T *argvars, typval_T *rettv);
361static void f_setqflist(typval_T *argvars, typval_T *rettv);
362static void f_setreg(typval_T *argvars, typval_T *rettv);
363static void f_settabvar(typval_T *argvars, typval_T *rettv);
364static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100365static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366static void f_setwinvar(typval_T *argvars, typval_T *rettv);
367#ifdef FEAT_CRYPT
368static void f_sha256(typval_T *argvars, typval_T *rettv);
369#endif /* FEAT_CRYPT */
370static void f_shellescape(typval_T *argvars, typval_T *rettv);
371static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100372#ifdef FEAT_SIGNS
373static void f_sign_define(typval_T *argvars, typval_T *rettv);
374static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
375static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100376static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100377static void f_sign_place(typval_T *argvars, typval_T *rettv);
378static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
379static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
380#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381static void f_simplify(typval_T *argvars, typval_T *rettv);
382#ifdef FEAT_FLOAT
383static void f_sin(typval_T *argvars, typval_T *rettv);
384static void f_sinh(typval_T *argvars, typval_T *rettv);
385#endif
386static void f_sort(typval_T *argvars, typval_T *rettv);
387static void f_soundfold(typval_T *argvars, typval_T *rettv);
388static void f_spellbadword(typval_T *argvars, typval_T *rettv);
389static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
390static void f_split(typval_T *argvars, typval_T *rettv);
391#ifdef FEAT_FLOAT
392static void f_sqrt(typval_T *argvars, typval_T *rettv);
393static void f_str2float(typval_T *argvars, typval_T *rettv);
394#endif
395static void f_str2nr(typval_T *argvars, typval_T *rettv);
396static void f_strchars(typval_T *argvars, typval_T *rettv);
397#ifdef HAVE_STRFTIME
398static void f_strftime(typval_T *argvars, typval_T *rettv);
399#endif
400static void f_strgetchar(typval_T *argvars, typval_T *rettv);
401static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200402static void f_strlen(typval_T *argvars, typval_T *rettv);
403static void f_strcharpart(typval_T *argvars, typval_T *rettv);
404static void f_strpart(typval_T *argvars, typval_T *rettv);
405static void f_strridx(typval_T *argvars, typval_T *rettv);
406static void f_strtrans(typval_T *argvars, typval_T *rettv);
407static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
408static void f_strwidth(typval_T *argvars, typval_T *rettv);
409static void f_submatch(typval_T *argvars, typval_T *rettv);
410static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200411static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200412static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200413static void f_synID(typval_T *argvars, typval_T *rettv);
414static void f_synIDattr(typval_T *argvars, typval_T *rettv);
415static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
416static void f_synstack(typval_T *argvars, typval_T *rettv);
417static void f_synconcealed(typval_T *argvars, typval_T *rettv);
418static void f_system(typval_T *argvars, typval_T *rettv);
419static void f_systemlist(typval_T *argvars, typval_T *rettv);
420static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
421static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
422static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
423static void f_taglist(typval_T *argvars, typval_T *rettv);
424static void f_tagfiles(typval_T *argvars, typval_T *rettv);
425static void f_tempname(typval_T *argvars, typval_T *rettv);
426static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
427static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200428static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200429static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100430static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200431static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100432static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100433static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434#ifdef FEAT_JOB_CHANNEL
435static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
436#endif
437static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
438#ifdef FEAT_JOB_CHANNEL
439static void f_test_null_job(typval_T *argvars, typval_T *rettv);
440#endif
441static void f_test_null_list(typval_T *argvars, typval_T *rettv);
442static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
443static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200444#ifdef FEAT_GUI
445static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
446#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447static void f_test_settime(typval_T *argvars, typval_T *rettv);
448#ifdef FEAT_FLOAT
449static void f_tan(typval_T *argvars, typval_T *rettv);
450static void f_tanh(typval_T *argvars, typval_T *rettv);
451#endif
452#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200453static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200454static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200455static void f_timer_start(typval_T *argvars, typval_T *rettv);
456static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200457static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200458#endif
459static void f_tolower(typval_T *argvars, typval_T *rettv);
460static void f_toupper(typval_T *argvars, typval_T *rettv);
461static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100462static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200463#ifdef FEAT_FLOAT
464static void f_trunc(typval_T *argvars, typval_T *rettv);
465#endif
466static void f_type(typval_T *argvars, typval_T *rettv);
467static void f_undofile(typval_T *argvars, typval_T *rettv);
468static void f_undotree(typval_T *argvars, typval_T *rettv);
469static void f_uniq(typval_T *argvars, typval_T *rettv);
470static void f_values(typval_T *argvars, typval_T *rettv);
471static void f_virtcol(typval_T *argvars, typval_T *rettv);
472static void f_visualmode(typval_T *argvars, typval_T *rettv);
473static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
474static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
475static void f_win_getid(typval_T *argvars, typval_T *rettv);
476static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
477static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
478static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100479static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200480static void f_winbufnr(typval_T *argvars, typval_T *rettv);
481static void f_wincol(typval_T *argvars, typval_T *rettv);
482static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200483static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200484static void f_winline(typval_T *argvars, typval_T *rettv);
485static void f_winnr(typval_T *argvars, typval_T *rettv);
486static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
487static void f_winrestview(typval_T *argvars, typval_T *rettv);
488static void f_winsaveview(typval_T *argvars, typval_T *rettv);
489static void f_winwidth(typval_T *argvars, typval_T *rettv);
490static void f_writefile(typval_T *argvars, typval_T *rettv);
491static void f_wordcount(typval_T *argvars, typval_T *rettv);
492static void f_xor(typval_T *argvars, typval_T *rettv);
493
494/*
495 * Array with names and number of arguments of all internal functions
496 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
497 */
498static struct fst
499{
500 char *f_name; /* function name */
501 char f_min_argc; /* minimal number of arguments */
502 char f_max_argc; /* maximal number of arguments */
503 void (*f_func)(typval_T *args, typval_T *rvar);
504 /* implementation of function */
505} functions[] =
506{
507#ifdef FEAT_FLOAT
508 {"abs", 1, 1, f_abs},
509 {"acos", 1, 1, f_acos}, /* WJMc */
510#endif
511 {"add", 2, 2, f_add},
512 {"and", 2, 2, f_and},
513 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200514 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200515 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516 {"argidx", 0, 0, f_argidx},
517 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200518 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200519#ifdef FEAT_FLOAT
520 {"asin", 1, 1, f_asin}, /* WJMc */
521#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100522 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200523 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100524 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200526 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100528 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529 {"assert_match", 2, 3, f_assert_match},
530 {"assert_notequal", 2, 3, f_assert_notequal},
531 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100532 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533 {"assert_true", 1, 2, f_assert_true},
534#ifdef FEAT_FLOAT
535 {"atan", 1, 1, f_atan},
536 {"atan2", 2, 2, f_atan2},
537#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100538#ifdef FEAT_BEVAL
539 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100540# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100541 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100542# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100543#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200544 {"browse", 4, 4, f_browse},
545 {"browsedir", 2, 2, f_browsedir},
546 {"bufexists", 1, 1, f_bufexists},
547 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
548 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
549 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
550 {"buflisted", 1, 1, f_buflisted},
551 {"bufloaded", 1, 1, f_bufloaded},
552 {"bufname", 1, 1, f_bufname},
553 {"bufnr", 1, 2, f_bufnr},
554 {"bufwinid", 1, 1, f_bufwinid},
555 {"bufwinnr", 1, 1, f_bufwinnr},
556 {"byte2line", 1, 1, f_byte2line},
557 {"byteidx", 2, 2, f_byteidx},
558 {"byteidxcomp", 2, 2, f_byteidxcomp},
559 {"call", 2, 3, f_call},
560#ifdef FEAT_FLOAT
561 {"ceil", 1, 1, f_ceil},
562#endif
563#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100564 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200565 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200566 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200567 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
568 {"ch_evalraw", 2, 3, f_ch_evalraw},
569 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
570 {"ch_getjob", 1, 1, f_ch_getjob},
571 {"ch_info", 1, 1, f_ch_info},
572 {"ch_log", 1, 2, f_ch_log},
573 {"ch_logfile", 1, 2, f_ch_logfile},
574 {"ch_open", 1, 2, f_ch_open},
575 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100576 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200577 {"ch_readraw", 1, 2, f_ch_readraw},
578 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
579 {"ch_sendraw", 2, 3, f_ch_sendraw},
580 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200581 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200582#endif
583 {"changenr", 0, 0, f_changenr},
584 {"char2nr", 1, 2, f_char2nr},
585 {"cindent", 1, 1, f_cindent},
586 {"clearmatches", 0, 0, f_clearmatches},
587 {"col", 1, 1, f_col},
588#if defined(FEAT_INS_EXPAND)
589 {"complete", 2, 2, f_complete},
590 {"complete_add", 1, 1, f_complete_add},
591 {"complete_check", 0, 0, f_complete_check},
592#endif
593 {"confirm", 1, 4, f_confirm},
594 {"copy", 1, 1, f_copy},
595#ifdef FEAT_FLOAT
596 {"cos", 1, 1, f_cos},
597 {"cosh", 1, 1, f_cosh},
598#endif
599 {"count", 2, 4, f_count},
600 {"cscope_connection",0,3, f_cscope_connection},
601 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100602#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200603 {"debugbreak", 1, 1, f_debugbreak},
604#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200605 {"deepcopy", 1, 2, f_deepcopy},
606 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200607 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200608 {"did_filetype", 0, 0, f_did_filetype},
609 {"diff_filler", 1, 1, f_diff_filler},
610 {"diff_hlID", 2, 2, f_diff_hlID},
611 {"empty", 1, 1, f_empty},
612 {"escape", 2, 2, f_escape},
613 {"eval", 1, 1, f_eval},
614 {"eventhandler", 0, 0, f_eventhandler},
615 {"executable", 1, 1, f_executable},
616 {"execute", 1, 2, f_execute},
617 {"exepath", 1, 1, f_exepath},
618 {"exists", 1, 1, f_exists},
619#ifdef FEAT_FLOAT
620 {"exp", 1, 1, f_exp},
621#endif
622 {"expand", 1, 3, f_expand},
623 {"extend", 2, 3, f_extend},
624 {"feedkeys", 1, 2, f_feedkeys},
625 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
626 {"filereadable", 1, 1, f_filereadable},
627 {"filewritable", 1, 1, f_filewritable},
628 {"filter", 2, 2, f_filter},
629 {"finddir", 1, 3, f_finddir},
630 {"findfile", 1, 3, f_findfile},
631#ifdef FEAT_FLOAT
632 {"float2nr", 1, 1, f_float2nr},
633 {"floor", 1, 1, f_floor},
634 {"fmod", 2, 2, f_fmod},
635#endif
636 {"fnameescape", 1, 1, f_fnameescape},
637 {"fnamemodify", 2, 2, f_fnamemodify},
638 {"foldclosed", 1, 1, f_foldclosed},
639 {"foldclosedend", 1, 1, f_foldclosedend},
640 {"foldlevel", 1, 1, f_foldlevel},
641 {"foldtext", 0, 0, f_foldtext},
642 {"foldtextresult", 1, 1, f_foldtextresult},
643 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200644 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200645 {"function", 1, 3, f_function},
646 {"garbagecollect", 0, 1, f_garbagecollect},
647 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200648 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649 {"getbufline", 2, 3, f_getbufline},
650 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100651 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652 {"getchar", 0, 1, f_getchar},
653 {"getcharmod", 0, 0, f_getcharmod},
654 {"getcharsearch", 0, 0, f_getcharsearch},
655 {"getcmdline", 0, 0, f_getcmdline},
656 {"getcmdpos", 0, 0, f_getcmdpos},
657 {"getcmdtype", 0, 0, f_getcmdtype},
658 {"getcmdwintype", 0, 0, f_getcmdwintype},
659#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200660 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661#endif
662 {"getcurpos", 0, 0, f_getcurpos},
663 {"getcwd", 0, 2, f_getcwd},
664 {"getfontname", 0, 1, f_getfontname},
665 {"getfperm", 1, 1, f_getfperm},
666 {"getfsize", 1, 1, f_getfsize},
667 {"getftime", 1, 1, f_getftime},
668 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100669 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200670 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200671 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200672 {"getmatches", 0, 0, f_getmatches},
673 {"getpid", 0, 0, f_getpid},
674 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200675 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200676 {"getreg", 0, 3, f_getreg},
677 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200678 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200679 {"gettabvar", 2, 3, f_gettabvar},
680 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100681 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200682 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100683 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200684 {"getwinposx", 0, 0, f_getwinposx},
685 {"getwinposy", 0, 0, f_getwinposy},
686 {"getwinvar", 2, 3, f_getwinvar},
687 {"glob", 1, 4, f_glob},
688 {"glob2regpat", 1, 1, f_glob2regpat},
689 {"globpath", 2, 5, f_globpath},
690 {"has", 1, 1, f_has},
691 {"has_key", 2, 2, f_has_key},
692 {"haslocaldir", 0, 2, f_haslocaldir},
693 {"hasmapto", 1, 3, f_hasmapto},
694 {"highlightID", 1, 1, f_hlID}, /* obsolete */
695 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
696 {"histadd", 2, 2, f_histadd},
697 {"histdel", 1, 2, f_histdel},
698 {"histget", 1, 2, f_histget},
699 {"histnr", 1, 1, f_histnr},
700 {"hlID", 1, 1, f_hlID},
701 {"hlexists", 1, 1, f_hlexists},
702 {"hostname", 0, 0, f_hostname},
703 {"iconv", 3, 3, f_iconv},
704 {"indent", 1, 1, f_indent},
705 {"index", 2, 4, f_index},
706 {"input", 1, 3, f_input},
707 {"inputdialog", 1, 3, f_inputdialog},
708 {"inputlist", 1, 1, f_inputlist},
709 {"inputrestore", 0, 0, f_inputrestore},
710 {"inputsave", 0, 0, f_inputsave},
711 {"inputsecret", 1, 2, f_inputsecret},
712 {"insert", 2, 3, f_insert},
713 {"invert", 1, 1, f_invert},
714 {"isdirectory", 1, 1, f_isdirectory},
715 {"islocked", 1, 1, f_islocked},
716#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
717 {"isnan", 1, 1, f_isnan},
718#endif
719 {"items", 1, 1, f_items},
720#ifdef FEAT_JOB_CHANNEL
721 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200722 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200723 {"job_setoptions", 2, 2, f_job_setoptions},
724 {"job_start", 1, 2, f_job_start},
725 {"job_status", 1, 1, f_job_status},
726 {"job_stop", 1, 2, f_job_stop},
727#endif
728 {"join", 1, 2, f_join},
729 {"js_decode", 1, 1, f_js_decode},
730 {"js_encode", 1, 1, f_js_encode},
731 {"json_decode", 1, 1, f_json_decode},
732 {"json_encode", 1, 1, f_json_encode},
733 {"keys", 1, 1, f_keys},
734 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
735 {"len", 1, 1, f_len},
736 {"libcall", 3, 3, f_libcall},
737 {"libcallnr", 3, 3, f_libcallnr},
738 {"line", 1, 1, f_line},
739 {"line2byte", 1, 1, f_line2byte},
740 {"lispindent", 1, 1, f_lispindent},
741 {"localtime", 0, 0, f_localtime},
742#ifdef FEAT_FLOAT
743 {"log", 1, 1, f_log},
744 {"log10", 1, 1, f_log10},
745#endif
746#ifdef FEAT_LUA
747 {"luaeval", 1, 2, f_luaeval},
748#endif
749 {"map", 2, 2, f_map},
750 {"maparg", 1, 4, f_maparg},
751 {"mapcheck", 1, 3, f_mapcheck},
752 {"match", 2, 4, f_match},
753 {"matchadd", 2, 5, f_matchadd},
754 {"matchaddpos", 2, 5, f_matchaddpos},
755 {"matcharg", 1, 1, f_matcharg},
756 {"matchdelete", 1, 1, f_matchdelete},
757 {"matchend", 2, 4, f_matchend},
758 {"matchlist", 2, 4, f_matchlist},
759 {"matchstr", 2, 4, f_matchstr},
760 {"matchstrpos", 2, 4, f_matchstrpos},
761 {"max", 1, 1, f_max},
762 {"min", 1, 1, f_min},
763#ifdef vim_mkdir
764 {"mkdir", 1, 3, f_mkdir},
765#endif
766 {"mode", 0, 1, f_mode},
767#ifdef FEAT_MZSCHEME
768 {"mzeval", 1, 1, f_mzeval},
769#endif
770 {"nextnonblank", 1, 1, f_nextnonblank},
771 {"nr2char", 1, 2, f_nr2char},
772 {"or", 2, 2, f_or},
773 {"pathshorten", 1, 1, f_pathshorten},
774#ifdef FEAT_PERL
775 {"perleval", 1, 1, f_perleval},
776#endif
777#ifdef FEAT_FLOAT
778 {"pow", 2, 2, f_pow},
779#endif
780 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100781 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200782#ifdef FEAT_JOB_CHANNEL
783 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200784 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200785 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
786#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100787#ifdef FEAT_TEXT_PROP
788 {"prop_add", 3, 3, f_prop_add},
789 {"prop_clear", 1, 3, f_prop_clear},
790 {"prop_list", 1, 2, f_prop_list},
791 {"prop_remove", 2, 3, f_prop_remove},
792 {"prop_type_add", 2, 2, f_prop_type_add},
793 {"prop_type_change", 2, 2, f_prop_type_change},
794 {"prop_type_delete", 1, 2, f_prop_type_delete},
795 {"prop_type_get", 1, 2, f_prop_type_get},
796 {"prop_type_list", 0, 1, f_prop_type_list},
797#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200798 {"pumvisible", 0, 0, f_pumvisible},
799#ifdef FEAT_PYTHON3
800 {"py3eval", 1, 1, f_py3eval},
801#endif
802#ifdef FEAT_PYTHON
803 {"pyeval", 1, 1, f_pyeval},
804#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100805#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
806 {"pyxeval", 1, 1, f_pyxeval},
807#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808 {"range", 1, 3, f_range},
809 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200810 {"reg_executing", 0, 0, f_reg_executing},
811 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200812 {"reltime", 0, 2, f_reltime},
813#ifdef FEAT_FLOAT
814 {"reltimefloat", 1, 1, f_reltimefloat},
815#endif
816 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100817 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200818 {"remote_foreground", 1, 1, f_remote_foreground},
819 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100820 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100822 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823 {"remove", 2, 3, f_remove},
824 {"rename", 2, 2, f_rename},
825 {"repeat", 2, 2, f_repeat},
826 {"resolve", 1, 1, f_resolve},
827 {"reverse", 1, 1, f_reverse},
828#ifdef FEAT_FLOAT
829 {"round", 1, 1, f_round},
830#endif
831 {"screenattr", 2, 2, f_screenattr},
832 {"screenchar", 2, 2, f_screenchar},
833 {"screencol", 0, 0, f_screencol},
834 {"screenrow", 0, 0, f_screenrow},
835 {"search", 1, 4, f_search},
836 {"searchdecl", 1, 3, f_searchdecl},
837 {"searchpair", 3, 7, f_searchpair},
838 {"searchpairpos", 3, 7, f_searchpairpos},
839 {"searchpos", 1, 4, f_searchpos},
840 {"server2client", 2, 2, f_server2client},
841 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200842 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843 {"setbufvar", 3, 3, f_setbufvar},
844 {"setcharsearch", 1, 1, f_setcharsearch},
845 {"setcmdpos", 1, 1, f_setcmdpos},
846 {"setfperm", 2, 2, f_setfperm},
847 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200848 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849 {"setmatches", 1, 1, f_setmatches},
850 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200851 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200852 {"setreg", 2, 3, f_setreg},
853 {"settabvar", 3, 3, f_settabvar},
854 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100855 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856 {"setwinvar", 3, 3, f_setwinvar},
857#ifdef FEAT_CRYPT
858 {"sha256", 1, 1, f_sha256},
859#endif
860 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100861 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100862#ifdef FEAT_SIGNS
863 {"sign_define", 1, 2, f_sign_define},
864 {"sign_getdefined", 0, 1, f_sign_getdefined},
865 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100866 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100867 {"sign_place", 4, 5, f_sign_place},
868 {"sign_undefine", 0, 1, f_sign_undefine},
869 {"sign_unplace", 1, 2, f_sign_unplace},
870#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200871 {"simplify", 1, 1, f_simplify},
872#ifdef FEAT_FLOAT
873 {"sin", 1, 1, f_sin},
874 {"sinh", 1, 1, f_sinh},
875#endif
876 {"sort", 1, 3, f_sort},
877 {"soundfold", 1, 1, f_soundfold},
878 {"spellbadword", 0, 1, f_spellbadword},
879 {"spellsuggest", 1, 3, f_spellsuggest},
880 {"split", 1, 3, f_split},
881#ifdef FEAT_FLOAT
882 {"sqrt", 1, 1, f_sqrt},
883 {"str2float", 1, 1, f_str2float},
884#endif
885 {"str2nr", 1, 2, f_str2nr},
886 {"strcharpart", 2, 3, f_strcharpart},
887 {"strchars", 1, 2, f_strchars},
888 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
889#ifdef HAVE_STRFTIME
890 {"strftime", 1, 2, f_strftime},
891#endif
892 {"strgetchar", 2, 2, f_strgetchar},
893 {"stridx", 2, 3, f_stridx},
894 {"string", 1, 1, f_string},
895 {"strlen", 1, 1, f_strlen},
896 {"strpart", 2, 3, f_strpart},
897 {"strridx", 2, 3, f_strridx},
898 {"strtrans", 1, 1, f_strtrans},
899 {"strwidth", 1, 1, f_strwidth},
900 {"submatch", 1, 2, f_submatch},
901 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200902 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200903 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200904 {"synID", 3, 3, f_synID},
905 {"synIDattr", 2, 3, f_synIDattr},
906 {"synIDtrans", 1, 1, f_synIDtrans},
907 {"synconcealed", 2, 2, f_synconcealed},
908 {"synstack", 2, 2, f_synstack},
909 {"system", 1, 2, f_system},
910 {"systemlist", 1, 2, f_systemlist},
911 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
912 {"tabpagenr", 0, 1, f_tabpagenr},
913 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
914 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100915 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200916#ifdef FEAT_FLOAT
917 {"tan", 1, 1, f_tan},
918 {"tanh", 1, 1, f_tanh},
919#endif
920 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200921#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100922 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
923 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100924 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200925 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200926# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
927 {"term_getansicolors", 1, 1, f_term_getansicolors},
928# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200929 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200930 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200931 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200932 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200933 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200934 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200935 {"term_getstatus", 1, 1, f_term_getstatus},
936 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200937 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200938 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200939 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200940 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200941# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
942 {"term_setansicolors", 2, 2, f_term_setansicolors},
943# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100944 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100945 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200946 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200947 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200948 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200949#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200950 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
951 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200952 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200953 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100954 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100955 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956#ifdef FEAT_JOB_CHANNEL
957 {"test_null_channel", 0, 0, f_test_null_channel},
958#endif
959 {"test_null_dict", 0, 0, f_test_null_dict},
960#ifdef FEAT_JOB_CHANNEL
961 {"test_null_job", 0, 0, f_test_null_job},
962#endif
963 {"test_null_list", 0, 0, f_test_null_list},
964 {"test_null_partial", 0, 0, f_test_null_partial},
965 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200966 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100967 {"test_override", 2, 2, f_test_override},
Bram Moolenaarab186732018-09-14 21:27:06 +0200968#ifdef FEAT_GUI
969 {"test_scrollbar", 3, 3, f_test_scrollbar},
970#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200971 {"test_settime", 1, 1, f_test_settime},
972#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200973 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200974 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200975 {"timer_start", 2, 3, f_timer_start},
976 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200977 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200978#endif
979 {"tolower", 1, 1, f_tolower},
980 {"toupper", 1, 1, f_toupper},
981 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100982 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200983#ifdef FEAT_FLOAT
984 {"trunc", 1, 1, f_trunc},
985#endif
986 {"type", 1, 1, f_type},
987 {"undofile", 1, 1, f_undofile},
988 {"undotree", 0, 0, f_undotree},
989 {"uniq", 1, 3, f_uniq},
990 {"values", 1, 1, f_values},
991 {"virtcol", 1, 1, f_virtcol},
992 {"visualmode", 0, 1, f_visualmode},
993 {"wildmenumode", 0, 0, f_wildmenumode},
994 {"win_findbuf", 1, 1, f_win_findbuf},
995 {"win_getid", 0, 2, f_win_getid},
996 {"win_gotoid", 1, 1, f_win_gotoid},
997 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
998 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100999 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001000 {"winbufnr", 1, 1, f_winbufnr},
1001 {"wincol", 0, 0, f_wincol},
1002 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001003 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001004 {"winline", 0, 0, f_winline},
1005 {"winnr", 0, 1, f_winnr},
1006 {"winrestcmd", 0, 0, f_winrestcmd},
1007 {"winrestview", 1, 1, f_winrestview},
1008 {"winsaveview", 0, 0, f_winsaveview},
1009 {"winwidth", 1, 1, f_winwidth},
1010 {"wordcount", 0, 0, f_wordcount},
1011 {"writefile", 2, 3, f_writefile},
1012 {"xor", 2, 2, f_xor},
1013};
1014
1015#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1016
1017/*
1018 * Function given to ExpandGeneric() to obtain the list of internal
1019 * or user defined function names.
1020 */
1021 char_u *
1022get_function_name(expand_T *xp, int idx)
1023{
1024 static int intidx = -1;
1025 char_u *name;
1026
1027 if (idx == 0)
1028 intidx = -1;
1029 if (intidx < 0)
1030 {
1031 name = get_user_func_name(xp, idx);
1032 if (name != NULL)
1033 return name;
1034 }
1035 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1036 {
1037 STRCPY(IObuff, functions[intidx].f_name);
1038 STRCAT(IObuff, "(");
1039 if (functions[intidx].f_max_argc == 0)
1040 STRCAT(IObuff, ")");
1041 return IObuff;
1042 }
1043
1044 return NULL;
1045}
1046
1047/*
1048 * Function given to ExpandGeneric() to obtain the list of internal or
1049 * user defined variable or function names.
1050 */
1051 char_u *
1052get_expr_name(expand_T *xp, int idx)
1053{
1054 static int intidx = -1;
1055 char_u *name;
1056
1057 if (idx == 0)
1058 intidx = -1;
1059 if (intidx < 0)
1060 {
1061 name = get_function_name(xp, idx);
1062 if (name != NULL)
1063 return name;
1064 }
1065 return get_user_var_name(xp, ++intidx);
1066}
1067
1068#endif /* FEAT_CMDL_COMPL */
1069
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001070/*
1071 * Find internal function in table above.
1072 * Return index, or -1 if not found
1073 */
1074 int
1075find_internal_func(
1076 char_u *name) /* name of the function */
1077{
1078 int first = 0;
1079 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1080 int cmp;
1081 int x;
1082
1083 /*
1084 * Find the function name in the table. Binary search.
1085 */
1086 while (first <= last)
1087 {
1088 x = first + ((unsigned)(last - first) >> 1);
1089 cmp = STRCMP(name, functions[x].f_name);
1090 if (cmp < 0)
1091 last = x - 1;
1092 else if (cmp > 0)
1093 first = x + 1;
1094 else
1095 return x;
1096 }
1097 return -1;
1098}
1099
1100 int
1101call_internal_func(
1102 char_u *name,
1103 int argcount,
1104 typval_T *argvars,
1105 typval_T *rettv)
1106{
1107 int i;
1108
1109 i = find_internal_func(name);
1110 if (i < 0)
1111 return ERROR_UNKNOWN;
1112 if (argcount < functions[i].f_min_argc)
1113 return ERROR_TOOFEW;
1114 if (argcount > functions[i].f_max_argc)
1115 return ERROR_TOOMANY;
1116 argvars[argcount].v_type = VAR_UNKNOWN;
1117 functions[i].f_func(argvars, rettv);
1118 return ERROR_NONE;
1119}
1120
1121/*
1122 * Return TRUE for a non-zero Number and a non-empty String.
1123 */
1124 static int
1125non_zero_arg(typval_T *argvars)
1126{
1127 return ((argvars[0].v_type == VAR_NUMBER
1128 && argvars[0].vval.v_number != 0)
1129 || (argvars[0].v_type == VAR_SPECIAL
1130 && argvars[0].vval.v_number == VVAL_TRUE)
1131 || (argvars[0].v_type == VAR_STRING
1132 && argvars[0].vval.v_string != NULL
1133 && *argvars[0].vval.v_string != NUL));
1134}
1135
1136/*
1137 * Get the lnum from the first argument.
1138 * Also accepts ".", "$", etc., but that only works for the current buffer.
1139 * Returns -1 on error.
1140 */
1141 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001142tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001143{
1144 typval_T rettv;
1145 linenr_T lnum;
1146
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001147 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001148 if (lnum == 0) /* no valid number, try using line() */
1149 {
1150 rettv.v_type = VAR_NUMBER;
1151 f_line(argvars, &rettv);
1152 lnum = (linenr_T)rettv.vval.v_number;
1153 clear_tv(&rettv);
1154 }
1155 return lnum;
1156}
1157
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001158/*
1159 * Get the lnum from the first argument.
1160 * Also accepts "$", then "buf" is used.
1161 * Returns 0 on error.
1162 */
1163 static linenr_T
1164tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1165{
1166 if (argvars[0].v_type == VAR_STRING
1167 && argvars[0].vval.v_string != NULL
1168 && argvars[0].vval.v_string[0] == '$'
1169 && buf != NULL)
1170 return buf->b_ml.ml_line_count;
1171 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1172}
1173
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001174#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001175/*
1176 * Get the float value of "argvars[0]" into "f".
1177 * Returns FAIL when the argument is not a Number or Float.
1178 */
1179 static int
1180get_float_arg(typval_T *argvars, float_T *f)
1181{
1182 if (argvars[0].v_type == VAR_FLOAT)
1183 {
1184 *f = argvars[0].vval.v_float;
1185 return OK;
1186 }
1187 if (argvars[0].v_type == VAR_NUMBER)
1188 {
1189 *f = (float_T)argvars[0].vval.v_number;
1190 return OK;
1191 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001192 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001193 return FAIL;
1194}
1195
1196/*
1197 * "abs(expr)" function
1198 */
1199 static void
1200f_abs(typval_T *argvars, typval_T *rettv)
1201{
1202 if (argvars[0].v_type == VAR_FLOAT)
1203 {
1204 rettv->v_type = VAR_FLOAT;
1205 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1206 }
1207 else
1208 {
1209 varnumber_T n;
1210 int error = FALSE;
1211
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001212 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001213 if (error)
1214 rettv->vval.v_number = -1;
1215 else if (n > 0)
1216 rettv->vval.v_number = n;
1217 else
1218 rettv->vval.v_number = -n;
1219 }
1220}
1221
1222/*
1223 * "acos()" function
1224 */
1225 static void
1226f_acos(typval_T *argvars, typval_T *rettv)
1227{
1228 float_T f = 0.0;
1229
1230 rettv->v_type = VAR_FLOAT;
1231 if (get_float_arg(argvars, &f) == OK)
1232 rettv->vval.v_float = acos(f);
1233 else
1234 rettv->vval.v_float = 0.0;
1235}
1236#endif
1237
1238/*
1239 * "add(list, item)" function
1240 */
1241 static void
1242f_add(typval_T *argvars, typval_T *rettv)
1243{
1244 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001245 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001246
1247 rettv->vval.v_number = 1; /* Default: Failed */
1248 if (argvars[0].v_type == VAR_LIST)
1249 {
1250 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001251 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252 (char_u *)N_("add() argument"), TRUE)
1253 && list_append_tv(l, &argvars[1]) == OK)
1254 copy_tv(&argvars[0], rettv);
1255 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001256 else if (argvars[0].v_type == VAR_BLOB)
1257 {
1258 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001259 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001260 (char_u *)N_("add() argument"), TRUE))
1261 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001262 int error = FALSE;
1263 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1264
1265 if (!error)
1266 {
1267 ga_append(&b->bv_ga, (int)n);
1268 copy_tv(&argvars[0], rettv);
1269 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001270 }
1271 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001272 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001273 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001274}
1275
1276/*
1277 * "and(expr, expr)" function
1278 */
1279 static void
1280f_and(typval_T *argvars, typval_T *rettv)
1281{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001282 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1283 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001284}
1285
1286/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001287 * If there is a window for "curbuf", make it the current window.
1288 */
1289 static void
1290find_win_for_curbuf(void)
1291{
1292 wininfo_T *wip;
1293
1294 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1295 {
1296 if (wip->wi_win != NULL)
1297 {
1298 curwin = wip->wi_win;
1299 break;
1300 }
1301 }
1302}
1303
1304/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001305 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001306 */
1307 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001308set_buffer_lines(
1309 buf_T *buf,
1310 linenr_T lnum_arg,
1311 int append,
1312 typval_T *lines,
1313 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001314{
Bram Moolenaarca851592018-06-06 21:04:07 +02001315 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1316 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001317 list_T *l = NULL;
1318 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001319 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001320 linenr_T append_lnum;
1321 buf_T *curbuf_save = NULL;
1322 win_T *curwin_save = NULL;
1323 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001324
Bram Moolenaarca851592018-06-06 21:04:07 +02001325 /* When using the current buffer ml_mfp will be set if needed. Useful when
1326 * setline() is used on startup. For other buffers the buffer must be
1327 * loaded. */
1328 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001329 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001330 rettv->vval.v_number = 1; /* FAIL */
1331 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001332 }
1333
Bram Moolenaarca851592018-06-06 21:04:07 +02001334 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001335 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001336 curbuf_save = curbuf;
1337 curwin_save = curwin;
1338 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001339 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001340 }
1341
1342 if (append)
1343 // appendbufline() uses the line number below which we insert
1344 append_lnum = lnum - 1;
1345 else
1346 // setbufline() uses the line number above which we insert, we only
1347 // append if it's below the last line
1348 append_lnum = curbuf->b_ml.ml_line_count;
1349
1350 if (lines->v_type == VAR_LIST)
1351 {
1352 l = lines->vval.v_list;
1353 li = l->lv_first;
1354 }
1355 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001356 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001357
1358 /* default result is zero == OK */
1359 for (;;)
1360 {
1361 if (l != NULL)
1362 {
1363 /* list argument, get next string */
1364 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001365 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001366 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 li = li->li_next;
1368 }
1369
Bram Moolenaarca851592018-06-06 21:04:07 +02001370 rettv->vval.v_number = 1; /* FAIL */
1371 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1372 break;
1373
1374 /* When coming here from Insert mode, sync undo, so that this can be
1375 * undone separately from what was previously inserted. */
1376 if (u_sync_once == 2)
1377 {
1378 u_sync_once = 1; /* notify that u_sync() was called */
1379 u_sync(TRUE);
1380 }
1381
1382 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1383 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001384 // Existing line, replace it.
1385 // Removes any existing text properties.
1386 if (u_savesub(lnum) == OK && ml_replace_len(
1387 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001388 {
1389 changed_bytes(lnum, 0);
1390 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1391 check_cursor_col();
1392 rettv->vval.v_number = 0; /* OK */
1393 }
1394 }
1395 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1396 {
1397 /* append the line */
1398 ++added;
1399 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1400 rettv->vval.v_number = 0; /* OK */
1401 }
1402
1403 if (l == NULL) /* only one string argument */
1404 break;
1405 ++lnum;
1406 }
1407
1408 if (added > 0)
1409 {
1410 win_T *wp;
1411 tabpage_T *tp;
1412
1413 appended_lines_mark(append_lnum, added);
1414 FOR_ALL_TAB_WINDOWS(tp, wp)
1415 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1416 wp->w_cursor.lnum += added;
1417 check_cursor_col();
1418
Bram Moolenaarf2732452018-06-03 14:47:35 +02001419#ifdef FEAT_JOB_CHANNEL
1420 if (bt_prompt(curbuf) && (State & INSERT))
1421 // show the line with the prompt
1422 update_topline();
1423#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001424 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001425
1426 if (!is_curbuf)
1427 {
1428 curbuf = curbuf_save;
1429 curwin = curwin_save;
1430 }
1431}
1432
1433/*
1434 * "append(lnum, string/list)" function
1435 */
1436 static void
1437f_append(typval_T *argvars, typval_T *rettv)
1438{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001439 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001440
1441 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1442}
1443
1444/*
1445 * "appendbufline(buf, lnum, string/list)" function
1446 */
1447 static void
1448f_appendbufline(typval_T *argvars, typval_T *rettv)
1449{
1450 linenr_T lnum;
1451 buf_T *buf;
1452
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001453 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001454 if (buf == NULL)
1455 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001456 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001457 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001458 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001459 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1460 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001461}
1462
1463/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001464 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001465 */
1466 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001467f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001468{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001469 win_T *wp;
1470
1471 if (argvars[0].v_type == VAR_UNKNOWN)
1472 // use the current window
1473 rettv->vval.v_number = ARGCOUNT;
1474 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001475 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001476 // use the global argument list
1477 rettv->vval.v_number = GARGCOUNT;
1478 else
1479 {
1480 // use the argument list of the specified window
1481 wp = find_win_by_nr_or_id(&argvars[0]);
1482 if (wp != NULL)
1483 rettv->vval.v_number = WARGCOUNT(wp);
1484 else
1485 rettv->vval.v_number = -1;
1486 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001487}
1488
1489/*
1490 * "argidx()" function
1491 */
1492 static void
1493f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1494{
1495 rettv->vval.v_number = curwin->w_arg_idx;
1496}
1497
1498/*
1499 * "arglistid()" function
1500 */
1501 static void
1502f_arglistid(typval_T *argvars, typval_T *rettv)
1503{
1504 win_T *wp;
1505
1506 rettv->vval.v_number = -1;
1507 wp = find_tabwin(&argvars[0], &argvars[1]);
1508 if (wp != NULL)
1509 rettv->vval.v_number = wp->w_alist->id;
1510}
1511
1512/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001513 * Get the argument list for a given window
1514 */
1515 static void
1516get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1517{
1518 int idx;
1519
1520 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1521 for (idx = 0; idx < argcount; ++idx)
1522 list_append_string(rettv->vval.v_list,
1523 alist_name(&arglist[idx]), -1);
1524}
1525
1526/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001527 * "argv(nr)" function
1528 */
1529 static void
1530f_argv(typval_T *argvars, typval_T *rettv)
1531{
1532 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001533 aentry_T *arglist = NULL;
1534 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535
1536 if (argvars[0].v_type != VAR_UNKNOWN)
1537 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001538 if (argvars[1].v_type == VAR_UNKNOWN)
1539 {
1540 arglist = ARGLIST;
1541 argcount = ARGCOUNT;
1542 }
1543 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001544 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001545 {
1546 arglist = GARGLIST;
1547 argcount = GARGCOUNT;
1548 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001549 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001550 {
1551 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1552
1553 if (wp != NULL)
1554 {
1555 /* Use the argument list of the specified window */
1556 arglist = WARGLIST(wp);
1557 argcount = WARGCOUNT(wp);
1558 }
1559 }
1560
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001561 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001562 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001563 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001564 if (arglist != NULL && idx >= 0 && idx < argcount)
1565 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1566 else if (idx == -1)
1567 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001568 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001569 else
1570 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001571}
1572
1573/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001574 * "assert_beeps(cmd [, error])" function
1575 */
1576 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001577f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001578{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001579 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001580}
1581
1582/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001583 * "assert_equal(expected, actual[, msg])" function
1584 */
1585 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001586f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001587{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001588 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001589}
1590
1591/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001592 * "assert_equalfile(fname-one, fname-two)" function
1593 */
1594 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001595f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001596{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001597 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001598}
1599
1600/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601 * "assert_notequal(expected, actual[, msg])" function
1602 */
1603 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001604f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001605{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001606 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607}
1608
1609/*
1610 * "assert_exception(string[, msg])" function
1611 */
1612 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001613f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001614{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001615 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616}
1617
1618/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001619 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001620 */
1621 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001622f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001623{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001624 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625}
1626
1627/*
1628 * "assert_false(actual[, msg])" function
1629 */
1630 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001631f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001632{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001633 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001634}
1635
1636/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001637 * "assert_inrange(lower, upper[, msg])" function
1638 */
1639 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001640f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001641{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001642 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001643}
1644
1645/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646 * "assert_match(pattern, actual[, msg])" function
1647 */
1648 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001649f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001650{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001651 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001652}
1653
1654/*
1655 * "assert_notmatch(pattern, actual[, msg])" function
1656 */
1657 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001658f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001659{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001660 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661}
1662
1663/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001664 * "assert_report(msg)" function
1665 */
1666 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001667f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001668{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001669 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001670}
1671
1672/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673 * "assert_true(actual[, msg])" function
1674 */
1675 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001676f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001677{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001678 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001679}
1680
1681#ifdef FEAT_FLOAT
1682/*
1683 * "asin()" function
1684 */
1685 static void
1686f_asin(typval_T *argvars, typval_T *rettv)
1687{
1688 float_T f = 0.0;
1689
1690 rettv->v_type = VAR_FLOAT;
1691 if (get_float_arg(argvars, &f) == OK)
1692 rettv->vval.v_float = asin(f);
1693 else
1694 rettv->vval.v_float = 0.0;
1695}
1696
1697/*
1698 * "atan()" function
1699 */
1700 static void
1701f_atan(typval_T *argvars, typval_T *rettv)
1702{
1703 float_T f = 0.0;
1704
1705 rettv->v_type = VAR_FLOAT;
1706 if (get_float_arg(argvars, &f) == OK)
1707 rettv->vval.v_float = atan(f);
1708 else
1709 rettv->vval.v_float = 0.0;
1710}
1711
1712/*
1713 * "atan2()" function
1714 */
1715 static void
1716f_atan2(typval_T *argvars, typval_T *rettv)
1717{
1718 float_T fx = 0.0, fy = 0.0;
1719
1720 rettv->v_type = VAR_FLOAT;
1721 if (get_float_arg(argvars, &fx) == OK
1722 && get_float_arg(&argvars[1], &fy) == OK)
1723 rettv->vval.v_float = atan2(fx, fy);
1724 else
1725 rettv->vval.v_float = 0.0;
1726}
1727#endif
1728
1729/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001730 * "balloon_show()" function
1731 */
1732#ifdef FEAT_BEVAL
1733 static void
1734f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1735{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001736 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001737 {
1738 if (argvars[0].v_type == VAR_LIST
1739# ifdef FEAT_GUI
1740 && !gui.in_use
1741# endif
1742 )
1743 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1744 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001745 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001746 }
1747}
1748
Bram Moolenaar669a8282017-11-19 20:13:05 +01001749# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001750 static void
1751f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1752{
1753 if (rettv_list_alloc(rettv) == OK)
1754 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001755 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001756
1757 if (msg != NULL)
1758 {
1759 pumitem_T *array;
1760 int size = split_message(msg, &array);
1761 int i;
1762
1763 /* Skip the first and last item, they are always empty. */
1764 for (i = 1; i < size - 1; ++i)
1765 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001766 while (size > 0)
1767 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001768 vim_free(array);
1769 }
1770 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001771}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001772# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001773#endif
1774
1775/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001776 * "browse(save, title, initdir, default)" function
1777 */
1778 static void
1779f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1780{
1781#ifdef FEAT_BROWSE
1782 int save;
1783 char_u *title;
1784 char_u *initdir;
1785 char_u *defname;
1786 char_u buf[NUMBUFLEN];
1787 char_u buf2[NUMBUFLEN];
1788 int error = FALSE;
1789
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001790 save = (int)tv_get_number_chk(&argvars[0], &error);
1791 title = tv_get_string_chk(&argvars[1]);
1792 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1793 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001794
1795 if (error || title == NULL || initdir == NULL || defname == NULL)
1796 rettv->vval.v_string = NULL;
1797 else
1798 rettv->vval.v_string =
1799 do_browse(save ? BROWSE_SAVE : 0,
1800 title, defname, NULL, initdir, NULL, curbuf);
1801#else
1802 rettv->vval.v_string = NULL;
1803#endif
1804 rettv->v_type = VAR_STRING;
1805}
1806
1807/*
1808 * "browsedir(title, initdir)" function
1809 */
1810 static void
1811f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1812{
1813#ifdef FEAT_BROWSE
1814 char_u *title;
1815 char_u *initdir;
1816 char_u buf[NUMBUFLEN];
1817
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001818 title = tv_get_string_chk(&argvars[0]);
1819 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001820
1821 if (title == NULL || initdir == NULL)
1822 rettv->vval.v_string = NULL;
1823 else
1824 rettv->vval.v_string = do_browse(BROWSE_DIR,
1825 title, NULL, NULL, initdir, NULL, curbuf);
1826#else
1827 rettv->vval.v_string = NULL;
1828#endif
1829 rettv->v_type = VAR_STRING;
1830}
1831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832/*
1833 * Find a buffer by number or exact name.
1834 */
1835 static buf_T *
1836find_buffer(typval_T *avar)
1837{
1838 buf_T *buf = NULL;
1839
1840 if (avar->v_type == VAR_NUMBER)
1841 buf = buflist_findnr((int)avar->vval.v_number);
1842 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1843 {
1844 buf = buflist_findname_exp(avar->vval.v_string);
1845 if (buf == NULL)
1846 {
1847 /* No full path name match, try a match with a URL or a "nofile"
1848 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001849 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001850 if (buf->b_fname != NULL
1851 && (path_with_url(buf->b_fname)
1852#ifdef FEAT_QUICKFIX
1853 || bt_nofile(buf)
1854#endif
1855 )
1856 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1857 break;
1858 }
1859 }
1860 return buf;
1861}
1862
1863/*
1864 * "bufexists(expr)" function
1865 */
1866 static void
1867f_bufexists(typval_T *argvars, typval_T *rettv)
1868{
1869 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1870}
1871
1872/*
1873 * "buflisted(expr)" function
1874 */
1875 static void
1876f_buflisted(typval_T *argvars, typval_T *rettv)
1877{
1878 buf_T *buf;
1879
1880 buf = find_buffer(&argvars[0]);
1881 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1882}
1883
1884/*
1885 * "bufloaded(expr)" function
1886 */
1887 static void
1888f_bufloaded(typval_T *argvars, typval_T *rettv)
1889{
1890 buf_T *buf;
1891
1892 buf = find_buffer(&argvars[0]);
1893 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1894}
1895
1896 buf_T *
1897buflist_find_by_name(char_u *name, int curtab_only)
1898{
1899 int save_magic;
1900 char_u *save_cpo;
1901 buf_T *buf;
1902
1903 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1904 save_magic = p_magic;
1905 p_magic = TRUE;
1906 save_cpo = p_cpo;
1907 p_cpo = (char_u *)"";
1908
1909 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1910 TRUE, FALSE, curtab_only));
1911
1912 p_magic = save_magic;
1913 p_cpo = save_cpo;
1914 return buf;
1915}
1916
1917/*
1918 * Get buffer by number or pattern.
1919 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001920 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001921tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001922{
1923 char_u *name = tv->vval.v_string;
1924 buf_T *buf;
1925
1926 if (tv->v_type == VAR_NUMBER)
1927 return buflist_findnr((int)tv->vval.v_number);
1928 if (tv->v_type != VAR_STRING)
1929 return NULL;
1930 if (name == NULL || *name == NUL)
1931 return curbuf;
1932 if (name[0] == '$' && name[1] == NUL)
1933 return lastbuf;
1934
1935 buf = buflist_find_by_name(name, curtab_only);
1936
1937 /* If not found, try expanding the name, like done for bufexists(). */
1938 if (buf == NULL)
1939 buf = find_buffer(tv);
1940
1941 return buf;
1942}
1943
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001944#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001945/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001946 * Get the buffer from "arg" and give an error and return NULL if it is not
1947 * valid.
1948 */
1949 static buf_T *
1950get_buf_arg(typval_T *arg)
1951{
1952 buf_T *buf;
1953
1954 ++emsg_off;
1955 buf = tv_get_buf(arg, FALSE);
1956 --emsg_off;
1957 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001958 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001959 return buf;
1960}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001961#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001962
1963/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001964 * "bufname(expr)" function
1965 */
1966 static void
1967f_bufname(typval_T *argvars, typval_T *rettv)
1968{
1969 buf_T *buf;
1970
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001971 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001972 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001973 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001974 rettv->v_type = VAR_STRING;
1975 if (buf != NULL && buf->b_fname != NULL)
1976 rettv->vval.v_string = vim_strsave(buf->b_fname);
1977 else
1978 rettv->vval.v_string = NULL;
1979 --emsg_off;
1980}
1981
1982/*
1983 * "bufnr(expr)" function
1984 */
1985 static void
1986f_bufnr(typval_T *argvars, typval_T *rettv)
1987{
1988 buf_T *buf;
1989 int error = FALSE;
1990 char_u *name;
1991
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001992 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001993 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001994 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 --emsg_off;
1996
1997 /* If the buffer isn't found and the second argument is not zero create a
1998 * new buffer. */
1999 if (buf == NULL
2000 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002001 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002003 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004 && !error)
2005 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2006
2007 if (buf != NULL)
2008 rettv->vval.v_number = buf->b_fnum;
2009 else
2010 rettv->vval.v_number = -1;
2011}
2012
2013 static void
2014buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2015{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002016 win_T *wp;
2017 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002018 buf_T *buf;
2019
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002020 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002022 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002023 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002024 {
2025 ++winnr;
2026 if (wp->w_buffer == buf)
2027 break;
2028 }
2029 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002030 --emsg_off;
2031}
2032
2033/*
2034 * "bufwinid(nr)" function
2035 */
2036 static void
2037f_bufwinid(typval_T *argvars, typval_T *rettv)
2038{
2039 buf_win_common(argvars, rettv, FALSE);
2040}
2041
2042/*
2043 * "bufwinnr(nr)" function
2044 */
2045 static void
2046f_bufwinnr(typval_T *argvars, typval_T *rettv)
2047{
2048 buf_win_common(argvars, rettv, TRUE);
2049}
2050
2051/*
2052 * "byte2line(byte)" function
2053 */
2054 static void
2055f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2056{
2057#ifndef FEAT_BYTEOFF
2058 rettv->vval.v_number = -1;
2059#else
2060 long boff = 0;
2061
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002062 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 if (boff < 0)
2064 rettv->vval.v_number = -1;
2065 else
2066 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2067 (linenr_T)0, &boff);
2068#endif
2069}
2070
2071 static void
2072byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2073{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002074 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002075 char_u *str;
2076 varnumber_T idx;
2077
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002078 str = tv_get_string_chk(&argvars[0]);
2079 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002080 rettv->vval.v_number = -1;
2081 if (str == NULL || idx < 0)
2082 return;
2083
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002084 t = str;
2085 for ( ; idx > 0; idx--)
2086 {
2087 if (*t == NUL) /* EOL reached */
2088 return;
2089 if (enc_utf8 && comp)
2090 t += utf_ptr2len(t);
2091 else
2092 t += (*mb_ptr2len)(t);
2093 }
2094 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095}
2096
2097/*
2098 * "byteidx()" function
2099 */
2100 static void
2101f_byteidx(typval_T *argvars, typval_T *rettv)
2102{
2103 byteidx(argvars, rettv, FALSE);
2104}
2105
2106/*
2107 * "byteidxcomp()" function
2108 */
2109 static void
2110f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2111{
2112 byteidx(argvars, rettv, TRUE);
2113}
2114
2115/*
2116 * "call(func, arglist [, dict])" function
2117 */
2118 static void
2119f_call(typval_T *argvars, typval_T *rettv)
2120{
2121 char_u *func;
2122 partial_T *partial = NULL;
2123 dict_T *selfdict = NULL;
2124
2125 if (argvars[1].v_type != VAR_LIST)
2126 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002127 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002128 return;
2129 }
2130 if (argvars[1].vval.v_list == NULL)
2131 return;
2132
2133 if (argvars[0].v_type == VAR_FUNC)
2134 func = argvars[0].vval.v_string;
2135 else if (argvars[0].v_type == VAR_PARTIAL)
2136 {
2137 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002138 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002139 }
2140 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002141 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002142 if (*func == NUL)
2143 return; /* type error or empty name */
2144
2145 if (argvars[2].v_type != VAR_UNKNOWN)
2146 {
2147 if (argvars[2].v_type != VAR_DICT)
2148 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002149 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002150 return;
2151 }
2152 selfdict = argvars[2].vval.v_dict;
2153 }
2154
2155 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2156}
2157
2158#ifdef FEAT_FLOAT
2159/*
2160 * "ceil({float})" function
2161 */
2162 static void
2163f_ceil(typval_T *argvars, typval_T *rettv)
2164{
2165 float_T f = 0.0;
2166
2167 rettv->v_type = VAR_FLOAT;
2168 if (get_float_arg(argvars, &f) == OK)
2169 rettv->vval.v_float = ceil(f);
2170 else
2171 rettv->vval.v_float = 0.0;
2172}
2173#endif
2174
2175#ifdef FEAT_JOB_CHANNEL
2176/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002177 * "ch_canread()" function
2178 */
2179 static void
2180f_ch_canread(typval_T *argvars, typval_T *rettv)
2181{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002182 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002183
2184 rettv->vval.v_number = 0;
2185 if (channel != NULL)
2186 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2187 || channel_has_readahead(channel, PART_OUT)
2188 || channel_has_readahead(channel, PART_ERR);
2189}
2190
2191/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 * "ch_close()" function
2193 */
2194 static void
2195f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2196{
2197 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2198
2199 if (channel != NULL)
2200 {
2201 channel_close(channel, FALSE);
2202 channel_clear(channel);
2203 }
2204}
2205
2206/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002207 * "ch_close()" function
2208 */
2209 static void
2210f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2211{
2212 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2213
2214 if (channel != NULL)
2215 channel_close_in(channel);
2216}
2217
2218/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002219 * "ch_getbufnr()" function
2220 */
2221 static void
2222f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2223{
2224 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2225
2226 rettv->vval.v_number = -1;
2227 if (channel != NULL)
2228 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002229 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002230 int part;
2231
2232 if (STRCMP(what, "err") == 0)
2233 part = PART_ERR;
2234 else if (STRCMP(what, "out") == 0)
2235 part = PART_OUT;
2236 else if (STRCMP(what, "in") == 0)
2237 part = PART_IN;
2238 else
2239 part = PART_SOCK;
2240 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2241 rettv->vval.v_number =
2242 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2243 }
2244}
2245
2246/*
2247 * "ch_getjob()" function
2248 */
2249 static void
2250f_ch_getjob(typval_T *argvars, typval_T *rettv)
2251{
2252 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2253
2254 if (channel != NULL)
2255 {
2256 rettv->v_type = VAR_JOB;
2257 rettv->vval.v_job = channel->ch_job;
2258 if (channel->ch_job != NULL)
2259 ++channel->ch_job->jv_refcount;
2260 }
2261}
2262
2263/*
2264 * "ch_info()" function
2265 */
2266 static void
2267f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2268{
2269 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2270
2271 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2272 channel_info(channel, rettv->vval.v_dict);
2273}
2274
2275/*
2276 * "ch_log()" function
2277 */
2278 static void
2279f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2280{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002281 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 channel_T *channel = NULL;
2283
2284 if (argvars[1].v_type != VAR_UNKNOWN)
2285 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2286
Bram Moolenaard5359b22018-04-05 22:44:39 +02002287 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002288}
2289
2290/*
2291 * "ch_logfile()" function
2292 */
2293 static void
2294f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2295{
2296 char_u *fname;
2297 char_u *opt = (char_u *)"";
2298 char_u buf[NUMBUFLEN];
2299
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002300 /* Don't open a file in restricted mode. */
2301 if (check_restricted() || check_secure())
2302 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002303 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002304 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002305 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002306 ch_logfile(fname, opt);
2307}
2308
2309/*
2310 * "ch_open()" function
2311 */
2312 static void
2313f_ch_open(typval_T *argvars, typval_T *rettv)
2314{
2315 rettv->v_type = VAR_CHANNEL;
2316 if (check_restricted() || check_secure())
2317 return;
2318 rettv->vval.v_channel = channel_open_func(argvars);
2319}
2320
2321/*
2322 * "ch_read()" function
2323 */
2324 static void
2325f_ch_read(typval_T *argvars, typval_T *rettv)
2326{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002327 common_channel_read(argvars, rettv, FALSE, FALSE);
2328}
2329
2330/*
2331 * "ch_readblob()" function
2332 */
2333 static void
2334f_ch_readblob(typval_T *argvars, typval_T *rettv)
2335{
2336 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002337}
2338
2339/*
2340 * "ch_readraw()" function
2341 */
2342 static void
2343f_ch_readraw(typval_T *argvars, typval_T *rettv)
2344{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002345 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002346}
2347
2348/*
2349 * "ch_evalexpr()" function
2350 */
2351 static void
2352f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2353{
2354 ch_expr_common(argvars, rettv, TRUE);
2355}
2356
2357/*
2358 * "ch_sendexpr()" function
2359 */
2360 static void
2361f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2362{
2363 ch_expr_common(argvars, rettv, FALSE);
2364}
2365
2366/*
2367 * "ch_evalraw()" function
2368 */
2369 static void
2370f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2371{
2372 ch_raw_common(argvars, rettv, TRUE);
2373}
2374
2375/*
2376 * "ch_sendraw()" function
2377 */
2378 static void
2379f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2380{
2381 ch_raw_common(argvars, rettv, FALSE);
2382}
2383
2384/*
2385 * "ch_setoptions()" function
2386 */
2387 static void
2388f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2389{
2390 channel_T *channel;
2391 jobopt_T opt;
2392
2393 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2394 if (channel == NULL)
2395 return;
2396 clear_job_options(&opt);
2397 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002398 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002399 channel_set_options(channel, &opt);
2400 free_job_options(&opt);
2401}
2402
2403/*
2404 * "ch_status()" function
2405 */
2406 static void
2407f_ch_status(typval_T *argvars, typval_T *rettv)
2408{
2409 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002410 jobopt_T opt;
2411 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002412
2413 /* return an empty string by default */
2414 rettv->v_type = VAR_STRING;
2415 rettv->vval.v_string = NULL;
2416
2417 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002418
2419 if (argvars[1].v_type != VAR_UNKNOWN)
2420 {
2421 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002422 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002423 && (opt.jo_set & JO_PART))
2424 part = opt.jo_part;
2425 }
2426
2427 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002428}
2429#endif
2430
2431/*
2432 * "changenr()" function
2433 */
2434 static void
2435f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2436{
2437 rettv->vval.v_number = curbuf->b_u_seq_cur;
2438}
2439
2440/*
2441 * "char2nr(string)" function
2442 */
2443 static void
2444f_char2nr(typval_T *argvars, typval_T *rettv)
2445{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446 if (has_mbyte)
2447 {
2448 int utf8 = 0;
2449
2450 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002451 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452
2453 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002454 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002455 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002456 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457 }
2458 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002459 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460}
2461
2462/*
2463 * "cindent(lnum)" function
2464 */
2465 static void
2466f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2467{
2468#ifdef FEAT_CINDENT
2469 pos_T pos;
2470 linenr_T lnum;
2471
2472 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002473 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002474 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2475 {
2476 curwin->w_cursor.lnum = lnum;
2477 rettv->vval.v_number = get_c_indent();
2478 curwin->w_cursor = pos;
2479 }
2480 else
2481#endif
2482 rettv->vval.v_number = -1;
2483}
2484
2485/*
2486 * "clearmatches()" function
2487 */
2488 static void
2489f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2490{
2491#ifdef FEAT_SEARCH_EXTRA
2492 clear_matches(curwin);
2493#endif
2494}
2495
2496/*
2497 * "col(string)" function
2498 */
2499 static void
2500f_col(typval_T *argvars, typval_T *rettv)
2501{
2502 colnr_T col = 0;
2503 pos_T *fp;
2504 int fnum = curbuf->b_fnum;
2505
2506 fp = var2fpos(&argvars[0], FALSE, &fnum);
2507 if (fp != NULL && fnum == curbuf->b_fnum)
2508 {
2509 if (fp->col == MAXCOL)
2510 {
2511 /* '> can be MAXCOL, get the length of the line then */
2512 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2513 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2514 else
2515 col = MAXCOL;
2516 }
2517 else
2518 {
2519 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002520 /* col(".") when the cursor is on the NUL at the end of the line
2521 * because of "coladd" can be seen as an extra column. */
2522 if (virtual_active() && fp == &curwin->w_cursor)
2523 {
2524 char_u *p = ml_get_cursor();
2525
2526 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2527 curwin->w_virtcol - curwin->w_cursor.coladd))
2528 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002529 int l;
2530
2531 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2532 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002533 }
2534 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002535 }
2536 }
2537 rettv->vval.v_number = col;
2538}
2539
2540#if defined(FEAT_INS_EXPAND)
2541/*
2542 * "complete()" function
2543 */
2544 static void
2545f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2546{
2547 int startcol;
2548
2549 if ((State & INSERT) == 0)
2550 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002551 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 return;
2553 }
2554
2555 /* Check for undo allowed here, because if something was already inserted
2556 * the line was already saved for undo and this check isn't done. */
2557 if (!undo_allowed())
2558 return;
2559
2560 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2561 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002562 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563 return;
2564 }
2565
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002566 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002567 if (startcol <= 0)
2568 return;
2569
2570 set_completion(startcol - 1, argvars[1].vval.v_list);
2571}
2572
2573/*
2574 * "complete_add()" function
2575 */
2576 static void
2577f_complete_add(typval_T *argvars, typval_T *rettv)
2578{
2579 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2580}
2581
2582/*
2583 * "complete_check()" function
2584 */
2585 static void
2586f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2587{
2588 int saved = RedrawingDisabled;
2589
2590 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002591 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592 rettv->vval.v_number = compl_interrupted;
2593 RedrawingDisabled = saved;
2594}
2595#endif
2596
2597/*
2598 * "confirm(message, buttons[, default [, type]])" function
2599 */
2600 static void
2601f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2602{
2603#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2604 char_u *message;
2605 char_u *buttons = NULL;
2606 char_u buf[NUMBUFLEN];
2607 char_u buf2[NUMBUFLEN];
2608 int def = 1;
2609 int type = VIM_GENERIC;
2610 char_u *typestr;
2611 int error = FALSE;
2612
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002613 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614 if (message == NULL)
2615 error = TRUE;
2616 if (argvars[1].v_type != VAR_UNKNOWN)
2617 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002618 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002619 if (buttons == NULL)
2620 error = TRUE;
2621 if (argvars[2].v_type != VAR_UNKNOWN)
2622 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002623 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002624 if (argvars[3].v_type != VAR_UNKNOWN)
2625 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002626 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 if (typestr == NULL)
2628 error = TRUE;
2629 else
2630 {
2631 switch (TOUPPER_ASC(*typestr))
2632 {
2633 case 'E': type = VIM_ERROR; break;
2634 case 'Q': type = VIM_QUESTION; break;
2635 case 'I': type = VIM_INFO; break;
2636 case 'W': type = VIM_WARNING; break;
2637 case 'G': type = VIM_GENERIC; break;
2638 }
2639 }
2640 }
2641 }
2642 }
2643
2644 if (buttons == NULL || *buttons == NUL)
2645 buttons = (char_u *)_("&Ok");
2646
2647 if (!error)
2648 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2649 def, NULL, FALSE);
2650#endif
2651}
2652
2653/*
2654 * "copy()" function
2655 */
2656 static void
2657f_copy(typval_T *argvars, typval_T *rettv)
2658{
2659 item_copy(&argvars[0], rettv, FALSE, 0);
2660}
2661
2662#ifdef FEAT_FLOAT
2663/*
2664 * "cos()" function
2665 */
2666 static void
2667f_cos(typval_T *argvars, typval_T *rettv)
2668{
2669 float_T f = 0.0;
2670
2671 rettv->v_type = VAR_FLOAT;
2672 if (get_float_arg(argvars, &f) == OK)
2673 rettv->vval.v_float = cos(f);
2674 else
2675 rettv->vval.v_float = 0.0;
2676}
2677
2678/*
2679 * "cosh()" function
2680 */
2681 static void
2682f_cosh(typval_T *argvars, typval_T *rettv)
2683{
2684 float_T f = 0.0;
2685
2686 rettv->v_type = VAR_FLOAT;
2687 if (get_float_arg(argvars, &f) == OK)
2688 rettv->vval.v_float = cosh(f);
2689 else
2690 rettv->vval.v_float = 0.0;
2691}
2692#endif
2693
2694/*
2695 * "count()" function
2696 */
2697 static void
2698f_count(typval_T *argvars, typval_T *rettv)
2699{
2700 long n = 0;
2701 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002702 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703
Bram Moolenaar9966b212017-07-28 16:46:57 +02002704 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002705 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002706
2707 if (argvars[0].v_type == VAR_STRING)
2708 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002709 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002710 char_u *p = argvars[0].vval.v_string;
2711 char_u *next;
2712
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002713 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002714 {
2715 if (ic)
2716 {
2717 size_t len = STRLEN(expr);
2718
2719 while (*p != NUL)
2720 {
2721 if (MB_STRNICMP(p, expr, len) == 0)
2722 {
2723 ++n;
2724 p += len;
2725 }
2726 else
2727 MB_PTR_ADV(p);
2728 }
2729 }
2730 else
2731 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2732 != NULL)
2733 {
2734 ++n;
2735 p = next + STRLEN(expr);
2736 }
2737 }
2738
2739 }
2740 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002741 {
2742 listitem_T *li;
2743 list_T *l;
2744 long idx;
2745
2746 if ((l = argvars[0].vval.v_list) != NULL)
2747 {
2748 li = l->lv_first;
2749 if (argvars[2].v_type != VAR_UNKNOWN)
2750 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002751 if (argvars[3].v_type != VAR_UNKNOWN)
2752 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002753 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002754 if (!error)
2755 {
2756 li = list_find(l, idx);
2757 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002758 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002759 }
2760 }
2761 if (error)
2762 li = NULL;
2763 }
2764
2765 for ( ; li != NULL; li = li->li_next)
2766 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2767 ++n;
2768 }
2769 }
2770 else if (argvars[0].v_type == VAR_DICT)
2771 {
2772 int todo;
2773 dict_T *d;
2774 hashitem_T *hi;
2775
2776 if ((d = argvars[0].vval.v_dict) != NULL)
2777 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 if (argvars[2].v_type != VAR_UNKNOWN)
2779 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002780 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002781 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002782 }
2783
2784 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2785 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2786 {
2787 if (!HASHITEM_EMPTY(hi))
2788 {
2789 --todo;
2790 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2791 ++n;
2792 }
2793 }
2794 }
2795 }
2796 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002797 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002798 rettv->vval.v_number = n;
2799}
2800
2801/*
2802 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2803 *
2804 * Checks the existence of a cscope connection.
2805 */
2806 static void
2807f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2808{
2809#ifdef FEAT_CSCOPE
2810 int num = 0;
2811 char_u *dbpath = NULL;
2812 char_u *prepend = NULL;
2813 char_u buf[NUMBUFLEN];
2814
2815 if (argvars[0].v_type != VAR_UNKNOWN
2816 && argvars[1].v_type != VAR_UNKNOWN)
2817 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002818 num = (int)tv_get_number(&argvars[0]);
2819 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002820 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002821 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002822 }
2823
2824 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2825#endif
2826}
2827
2828/*
2829 * "cursor(lnum, col)" function, or
2830 * "cursor(list)"
2831 *
2832 * Moves the cursor to the specified line and column.
2833 * Returns 0 when the position could be set, -1 otherwise.
2834 */
2835 static void
2836f_cursor(typval_T *argvars, typval_T *rettv)
2837{
2838 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002839 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 int set_curswant = TRUE;
2841
2842 rettv->vval.v_number = -1;
2843 if (argvars[1].v_type == VAR_UNKNOWN)
2844 {
2845 pos_T pos;
2846 colnr_T curswant = -1;
2847
2848 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2849 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002850 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851 return;
2852 }
2853 line = pos.lnum;
2854 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002856 if (curswant >= 0)
2857 {
2858 curwin->w_curswant = curswant - 1;
2859 set_curswant = FALSE;
2860 }
2861 }
2862 else
2863 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002864 line = tv_get_lnum(argvars);
2865 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002866 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002867 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002868 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002869 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002870 return; /* type error; errmsg already given */
2871 if (line > 0)
2872 curwin->w_cursor.lnum = line;
2873 if (col > 0)
2874 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002875 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876
2877 /* Make sure the cursor is in a valid position. */
2878 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002879 /* Correct cursor for multi-byte character. */
2880 if (has_mbyte)
2881 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002882
2883 curwin->w_set_curswant = set_curswant;
2884 rettv->vval.v_number = 0;
2885}
2886
Bram Moolenaar4f974752019-02-17 17:44:42 +01002887#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002888/*
2889 * "debugbreak()" function
2890 */
2891 static void
2892f_debugbreak(typval_T *argvars, typval_T *rettv)
2893{
2894 int pid;
2895
2896 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002897 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002898 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002899 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002900 else
2901 {
2902 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2903
2904 if (hProcess != NULL)
2905 {
2906 DebugBreakProcess(hProcess);
2907 CloseHandle(hProcess);
2908 rettv->vval.v_number = OK;
2909 }
2910 }
2911}
2912#endif
2913
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002914/*
2915 * "deepcopy()" function
2916 */
2917 static void
2918f_deepcopy(typval_T *argvars, typval_T *rettv)
2919{
2920 int noref = 0;
2921 int copyID;
2922
2923 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002924 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002925 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002926 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002927 else
2928 {
2929 copyID = get_copyID();
2930 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2931 }
2932}
2933
2934/*
2935 * "delete()" function
2936 */
2937 static void
2938f_delete(typval_T *argvars, typval_T *rettv)
2939{
2940 char_u nbuf[NUMBUFLEN];
2941 char_u *name;
2942 char_u *flags;
2943
2944 rettv->vval.v_number = -1;
2945 if (check_restricted() || check_secure())
2946 return;
2947
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002948 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002949 if (name == NULL || *name == NUL)
2950 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002951 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002952 return;
2953 }
2954
2955 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002956 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002957 else
2958 flags = (char_u *)"";
2959
2960 if (*flags == NUL)
2961 /* delete a file */
2962 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2963 else if (STRCMP(flags, "d") == 0)
2964 /* delete an empty directory */
2965 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2966 else if (STRCMP(flags, "rf") == 0)
2967 /* delete a directory recursively */
2968 rettv->vval.v_number = delete_recursive(name);
2969 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002970 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002971}
2972
2973/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002974 * "deletebufline()" function
2975 */
2976 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002977f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002978{
2979 buf_T *buf;
2980 linenr_T first, last;
2981 linenr_T lnum;
2982 long count;
2983 int is_curbuf;
2984 buf_T *curbuf_save = NULL;
2985 win_T *curwin_save = NULL;
2986 tabpage_T *tp;
2987 win_T *wp;
2988
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002989 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002990 if (buf == NULL)
2991 {
2992 rettv->vval.v_number = 1; /* FAIL */
2993 return;
2994 }
2995 is_curbuf = buf == curbuf;
2996
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002997 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002998 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002999 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003000 else
3001 last = first;
3002
3003 if (buf->b_ml.ml_mfp == NULL || first < 1
3004 || first > buf->b_ml.ml_line_count || last < first)
3005 {
3006 rettv->vval.v_number = 1; /* FAIL */
3007 return;
3008 }
3009
3010 if (!is_curbuf)
3011 {
3012 curbuf_save = curbuf;
3013 curwin_save = curwin;
3014 curbuf = buf;
3015 find_win_for_curbuf();
3016 }
3017 if (last > curbuf->b_ml.ml_line_count)
3018 last = curbuf->b_ml.ml_line_count;
3019 count = last - first + 1;
3020
3021 // When coming here from Insert mode, sync undo, so that this can be
3022 // undone separately from what was previously inserted.
3023 if (u_sync_once == 2)
3024 {
3025 u_sync_once = 1; // notify that u_sync() was called
3026 u_sync(TRUE);
3027 }
3028
3029 if (u_save(first - 1, last + 1) == FAIL)
3030 {
3031 rettv->vval.v_number = 1; /* FAIL */
3032 return;
3033 }
3034
3035 for (lnum = first; lnum <= last; ++lnum)
3036 ml_delete(first, TRUE);
3037
3038 FOR_ALL_TAB_WINDOWS(tp, wp)
3039 if (wp->w_buffer == buf)
3040 {
3041 if (wp->w_cursor.lnum > last)
3042 wp->w_cursor.lnum -= count;
3043 else if (wp->w_cursor.lnum> first)
3044 wp->w_cursor.lnum = first;
3045 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3046 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3047 }
3048 check_cursor_col();
3049 deleted_lines_mark(first, count);
3050
3051 if (!is_curbuf)
3052 {
3053 curbuf = curbuf_save;
3054 curwin = curwin_save;
3055 }
3056}
3057
3058/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059 * "did_filetype()" function
3060 */
3061 static void
3062f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3063{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003064 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065}
3066
3067/*
3068 * "diff_filler()" function
3069 */
3070 static void
3071f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3072{
3073#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003074 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075#endif
3076}
3077
3078/*
3079 * "diff_hlID()" function
3080 */
3081 static void
3082f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3083{
3084#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003085 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003086 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003087 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003088 static int fnum = 0;
3089 static int change_start = 0;
3090 static int change_end = 0;
3091 static hlf_T hlID = (hlf_T)0;
3092 int filler_lines;
3093 int col;
3094
3095 if (lnum < 0) /* ignore type error in {lnum} arg */
3096 lnum = 0;
3097 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003098 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 || fnum != curbuf->b_fnum)
3100 {
3101 /* New line, buffer, change: need to get the values. */
3102 filler_lines = diff_check(curwin, lnum);
3103 if (filler_lines < 0)
3104 {
3105 if (filler_lines == -1)
3106 {
3107 change_start = MAXCOL;
3108 change_end = -1;
3109 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3110 hlID = HLF_ADD; /* added line */
3111 else
3112 hlID = HLF_CHD; /* changed line */
3113 }
3114 else
3115 hlID = HLF_ADD; /* added line */
3116 }
3117 else
3118 hlID = (hlf_T)0;
3119 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003120 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003121 fnum = curbuf->b_fnum;
3122 }
3123
3124 if (hlID == HLF_CHD || hlID == HLF_TXD)
3125 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003126 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003127 if (col >= change_start && col <= change_end)
3128 hlID = HLF_TXD; /* changed text */
3129 else
3130 hlID = HLF_CHD; /* changed line */
3131 }
3132 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3133#endif
3134}
3135
3136/*
3137 * "empty({expr})" function
3138 */
3139 static void
3140f_empty(typval_T *argvars, typval_T *rettv)
3141{
3142 int n = FALSE;
3143
3144 switch (argvars[0].v_type)
3145 {
3146 case VAR_STRING:
3147 case VAR_FUNC:
3148 n = argvars[0].vval.v_string == NULL
3149 || *argvars[0].vval.v_string == NUL;
3150 break;
3151 case VAR_PARTIAL:
3152 n = FALSE;
3153 break;
3154 case VAR_NUMBER:
3155 n = argvars[0].vval.v_number == 0;
3156 break;
3157 case VAR_FLOAT:
3158#ifdef FEAT_FLOAT
3159 n = argvars[0].vval.v_float == 0.0;
3160 break;
3161#endif
3162 case VAR_LIST:
3163 n = argvars[0].vval.v_list == NULL
3164 || argvars[0].vval.v_list->lv_first == NULL;
3165 break;
3166 case VAR_DICT:
3167 n = argvars[0].vval.v_dict == NULL
3168 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3169 break;
3170 case VAR_SPECIAL:
3171 n = argvars[0].vval.v_number != VVAL_TRUE;
3172 break;
3173
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003174 case VAR_BLOB:
3175 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003176 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3177 break;
3178
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003179 case VAR_JOB:
3180#ifdef FEAT_JOB_CHANNEL
3181 n = argvars[0].vval.v_job == NULL
3182 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3183 break;
3184#endif
3185 case VAR_CHANNEL:
3186#ifdef FEAT_JOB_CHANNEL
3187 n = argvars[0].vval.v_channel == NULL
3188 || !channel_is_open(argvars[0].vval.v_channel);
3189 break;
3190#endif
3191 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003192 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003193 n = TRUE;
3194 break;
3195 }
3196
3197 rettv->vval.v_number = n;
3198}
3199
3200/*
3201 * "escape({string}, {chars})" function
3202 */
3203 static void
3204f_escape(typval_T *argvars, typval_T *rettv)
3205{
3206 char_u buf[NUMBUFLEN];
3207
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003208 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3209 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003210 rettv->v_type = VAR_STRING;
3211}
3212
3213/*
3214 * "eval()" function
3215 */
3216 static void
3217f_eval(typval_T *argvars, typval_T *rettv)
3218{
3219 char_u *s, *p;
3220
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003221 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003222 if (s != NULL)
3223 s = skipwhite(s);
3224
3225 p = s;
3226 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3227 {
3228 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003229 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230 need_clr_eos = FALSE;
3231 rettv->v_type = VAR_NUMBER;
3232 rettv->vval.v_number = 0;
3233 }
3234 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003235 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003236}
3237
3238/*
3239 * "eventhandler()" function
3240 */
3241 static void
3242f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3243{
3244 rettv->vval.v_number = vgetc_busy;
3245}
3246
3247/*
3248 * "executable()" function
3249 */
3250 static void
3251f_executable(typval_T *argvars, typval_T *rettv)
3252{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003253 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003254
3255 /* Check in $PATH and also check directly if there is a directory name. */
3256 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3257 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3258}
3259
3260static garray_T redir_execute_ga;
3261
3262/*
3263 * Append "value[value_len]" to the execute() output.
3264 */
3265 void
3266execute_redir_str(char_u *value, int value_len)
3267{
3268 int len;
3269
3270 if (value_len == -1)
3271 len = (int)STRLEN(value); /* Append the entire string */
3272 else
3273 len = value_len; /* Append only "value_len" characters */
3274 if (ga_grow(&redir_execute_ga, len) == OK)
3275 {
3276 mch_memmove((char *)redir_execute_ga.ga_data
3277 + redir_execute_ga.ga_len, value, len);
3278 redir_execute_ga.ga_len += len;
3279 }
3280}
3281
3282/*
3283 * Get next line from a list.
3284 * Called by do_cmdline() to get the next line.
3285 * Returns allocated string, or NULL for end of function.
3286 */
3287
3288 static char_u *
3289get_list_line(
3290 int c UNUSED,
3291 void *cookie,
3292 int indent UNUSED)
3293{
3294 listitem_T **p = (listitem_T **)cookie;
3295 listitem_T *item = *p;
3296 char_u buf[NUMBUFLEN];
3297 char_u *s;
3298
3299 if (item == NULL)
3300 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003301 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003302 *p = item->li_next;
3303 return s == NULL ? NULL : vim_strsave(s);
3304}
3305
3306/*
3307 * "execute()" function
3308 */
3309 static void
3310f_execute(typval_T *argvars, typval_T *rettv)
3311{
3312 char_u *cmd = NULL;
3313 list_T *list = NULL;
3314 int save_msg_silent = msg_silent;
3315 int save_emsg_silent = emsg_silent;
3316 int save_emsg_noredir = emsg_noredir;
3317 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003318 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003319 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003320 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003321 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003322
3323 rettv->vval.v_string = NULL;
3324 rettv->v_type = VAR_STRING;
3325
3326 if (argvars[0].v_type == VAR_LIST)
3327 {
3328 list = argvars[0].vval.v_list;
3329 if (list == NULL || list->lv_first == NULL)
3330 /* empty list, no commands, empty output */
3331 return;
3332 ++list->lv_refcount;
3333 }
3334 else
3335 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003336 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003337 if (cmd == NULL)
3338 return;
3339 }
3340
3341 if (argvars[1].v_type != VAR_UNKNOWN)
3342 {
3343 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003344 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003345
3346 if (s == NULL)
3347 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003348 if (*s == NUL)
3349 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003350 if (STRNCMP(s, "silent", 6) == 0)
3351 ++msg_silent;
3352 if (STRCMP(s, "silent!") == 0)
3353 {
3354 emsg_silent = TRUE;
3355 emsg_noredir = TRUE;
3356 }
3357 }
3358 else
3359 ++msg_silent;
3360
3361 if (redir_execute)
3362 save_ga = redir_execute_ga;
3363 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3364 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003365 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003366 if (!echo_output)
3367 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003368
3369 if (cmd != NULL)
3370 do_cmdline_cmd(cmd);
3371 else
3372 {
3373 listitem_T *item = list->lv_first;
3374
3375 do_cmdline(NULL, get_list_line, (void *)&item,
3376 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3377 --list->lv_refcount;
3378 }
3379
Bram Moolenaard297f352017-01-29 20:31:21 +01003380 /* Need to append a NUL to the result. */
3381 if (ga_grow(&redir_execute_ga, 1) == OK)
3382 {
3383 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3384 rettv->vval.v_string = redir_execute_ga.ga_data;
3385 }
3386 else
3387 {
3388 ga_clear(&redir_execute_ga);
3389 rettv->vval.v_string = NULL;
3390 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 msg_silent = save_msg_silent;
3392 emsg_silent = save_emsg_silent;
3393 emsg_noredir = save_emsg_noredir;
3394
3395 redir_execute = save_redir_execute;
3396 if (redir_execute)
3397 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003398 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003399
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003400 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003401 if (echo_output)
3402 // When not working silently: put it in column zero. A following
3403 // "echon" will overwrite the message, unavoidably.
3404 msg_col = 0;
3405 else
3406 // When working silently: Put it back where it was, since nothing
3407 // should have been written.
3408 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003409}
3410
3411/*
3412 * "exepath()" function
3413 */
3414 static void
3415f_exepath(typval_T *argvars, typval_T *rettv)
3416{
3417 char_u *p = NULL;
3418
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003419 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003420 rettv->v_type = VAR_STRING;
3421 rettv->vval.v_string = p;
3422}
3423
3424/*
3425 * "exists()" function
3426 */
3427 static void
3428f_exists(typval_T *argvars, typval_T *rettv)
3429{
3430 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003431 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003432
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003433 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434 if (*p == '$') /* environment variable */
3435 {
3436 /* first try "normal" environment variables (fast) */
3437 if (mch_getenv(p + 1) != NULL)
3438 n = TRUE;
3439 else
3440 {
3441 /* try expanding things like $VIM and ${HOME} */
3442 p = expand_env_save(p);
3443 if (p != NULL && *p != '$')
3444 n = TRUE;
3445 vim_free(p);
3446 }
3447 }
3448 else if (*p == '&' || *p == '+') /* option */
3449 {
3450 n = (get_option_tv(&p, NULL, TRUE) == OK);
3451 if (*skipwhite(p) != NUL)
3452 n = FALSE; /* trailing garbage */
3453 }
3454 else if (*p == '*') /* internal or user defined function */
3455 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003456 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457 }
3458 else if (*p == ':')
3459 {
3460 n = cmd_exists(p + 1);
3461 }
3462 else if (*p == '#')
3463 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003464 if (p[1] == '#')
3465 n = autocmd_supported(p + 2);
3466 else
3467 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468 }
3469 else /* internal variable */
3470 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003471 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472 }
3473
3474 rettv->vval.v_number = n;
3475}
3476
3477#ifdef FEAT_FLOAT
3478/*
3479 * "exp()" function
3480 */
3481 static void
3482f_exp(typval_T *argvars, typval_T *rettv)
3483{
3484 float_T f = 0.0;
3485
3486 rettv->v_type = VAR_FLOAT;
3487 if (get_float_arg(argvars, &f) == OK)
3488 rettv->vval.v_float = exp(f);
3489 else
3490 rettv->vval.v_float = 0.0;
3491}
3492#endif
3493
3494/*
3495 * "expand()" function
3496 */
3497 static void
3498f_expand(typval_T *argvars, typval_T *rettv)
3499{
3500 char_u *s;
3501 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003502 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3504 expand_T xpc;
3505 int error = FALSE;
3506 char_u *result;
3507
3508 rettv->v_type = VAR_STRING;
3509 if (argvars[1].v_type != VAR_UNKNOWN
3510 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003511 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003512 && !error)
3513 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003514 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003515 }
3516
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003517 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518 if (*s == '%' || *s == '#' || *s == '<')
3519 {
3520 ++emsg_off;
3521 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3522 --emsg_off;
3523 if (rettv->v_type == VAR_LIST)
3524 {
3525 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3526 list_append_string(rettv->vval.v_list, result, -1);
3527 else
3528 vim_free(result);
3529 }
3530 else
3531 rettv->vval.v_string = result;
3532 }
3533 else
3534 {
3535 /* When the optional second argument is non-zero, don't remove matches
3536 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3537 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003538 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003539 options |= WILD_KEEP_ALL;
3540 if (!error)
3541 {
3542 ExpandInit(&xpc);
3543 xpc.xp_context = EXPAND_FILES;
3544 if (p_wic)
3545 options += WILD_ICASE;
3546 if (rettv->v_type == VAR_STRING)
3547 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3548 options, WILD_ALL);
3549 else if (rettv_list_alloc(rettv) != FAIL)
3550 {
3551 int i;
3552
3553 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3554 for (i = 0; i < xpc.xp_numfiles; i++)
3555 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3556 ExpandCleanup(&xpc);
3557 }
3558 }
3559 else
3560 rettv->vval.v_string = NULL;
3561 }
3562}
3563
3564/*
3565 * "extend(list, list [, idx])" function
3566 * "extend(dict, dict [, action])" function
3567 */
3568 static void
3569f_extend(typval_T *argvars, typval_T *rettv)
3570{
3571 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3572
3573 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3574 {
3575 list_T *l1, *l2;
3576 listitem_T *item;
3577 long before;
3578 int error = FALSE;
3579
3580 l1 = argvars[0].vval.v_list;
3581 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003582 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003583 && l2 != NULL)
3584 {
3585 if (argvars[2].v_type != VAR_UNKNOWN)
3586 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003587 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003588 if (error)
3589 return; /* type error; errmsg already given */
3590
3591 if (before == l1->lv_len)
3592 item = NULL;
3593 else
3594 {
3595 item = list_find(l1, before);
3596 if (item == NULL)
3597 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003598 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003599 return;
3600 }
3601 }
3602 }
3603 else
3604 item = NULL;
3605 list_extend(l1, l2, item);
3606
3607 copy_tv(&argvars[0], rettv);
3608 }
3609 }
3610 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3611 {
3612 dict_T *d1, *d2;
3613 char_u *action;
3614 int i;
3615
3616 d1 = argvars[0].vval.v_dict;
3617 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003618 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003619 && d2 != NULL)
3620 {
3621 /* Check the third argument. */
3622 if (argvars[2].v_type != VAR_UNKNOWN)
3623 {
3624 static char *(av[]) = {"keep", "force", "error"};
3625
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003626 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003627 if (action == NULL)
3628 return; /* type error; errmsg already given */
3629 for (i = 0; i < 3; ++i)
3630 if (STRCMP(action, av[i]) == 0)
3631 break;
3632 if (i == 3)
3633 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003634 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635 return;
3636 }
3637 }
3638 else
3639 action = (char_u *)"force";
3640
3641 dict_extend(d1, d2, action);
3642
3643 copy_tv(&argvars[0], rettv);
3644 }
3645 }
3646 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003647 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003648}
3649
3650/*
3651 * "feedkeys()" function
3652 */
3653 static void
3654f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3655{
3656 int remap = TRUE;
3657 int insert = FALSE;
3658 char_u *keys, *flags;
3659 char_u nbuf[NUMBUFLEN];
3660 int typed = FALSE;
3661 int execute = FALSE;
3662 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003663 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003664 char_u *keys_esc;
3665
3666 /* This is not allowed in the sandbox. If the commands would still be
3667 * executed in the sandbox it would be OK, but it probably happens later,
3668 * when "sandbox" is no longer set. */
3669 if (check_secure())
3670 return;
3671
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003672 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003673
3674 if (argvars[1].v_type != VAR_UNKNOWN)
3675 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003676 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677 for ( ; *flags != NUL; ++flags)
3678 {
3679 switch (*flags)
3680 {
3681 case 'n': remap = FALSE; break;
3682 case 'm': remap = TRUE; break;
3683 case 't': typed = TRUE; break;
3684 case 'i': insert = TRUE; break;
3685 case 'x': execute = TRUE; break;
3686 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003687 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003688 }
3689 }
3690 }
3691
3692 if (*keys != NUL || execute)
3693 {
3694 /* Need to escape K_SPECIAL and CSI before putting the string in the
3695 * typeahead buffer. */
3696 keys_esc = vim_strsave_escape_csi(keys);
3697 if (keys_esc != NULL)
3698 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003699 if (lowlevel)
3700 {
3701#ifdef USE_INPUT_BUF
3702 add_to_input_buf(keys, (int)STRLEN(keys));
3703#else
3704 emsg(_("E980: lowlevel input not supported"));
3705#endif
3706 }
3707 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003708 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003709 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003710 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003711 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003712#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003713 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003714#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003715 )
3716 typebuf_was_filled = TRUE;
3717 }
3718 vim_free(keys_esc);
3719
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720 if (execute)
3721 {
3722 int save_msg_scroll = msg_scroll;
3723
3724 /* Avoid a 1 second delay when the keys start Insert mode. */
3725 msg_scroll = FALSE;
3726
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003727 if (!dangerous)
3728 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003729 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003730 if (!dangerous)
3731 --ex_normal_busy;
3732
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003733 msg_scroll |= save_msg_scroll;
3734 }
3735 }
3736 }
3737}
3738
3739/*
3740 * "filereadable()" function
3741 */
3742 static void
3743f_filereadable(typval_T *argvars, typval_T *rettv)
3744{
3745 int fd;
3746 char_u *p;
3747 int n;
3748
3749#ifndef O_NONBLOCK
3750# define O_NONBLOCK 0
3751#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003752 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003753 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3754 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3755 {
3756 n = TRUE;
3757 close(fd);
3758 }
3759 else
3760 n = FALSE;
3761
3762 rettv->vval.v_number = n;
3763}
3764
3765/*
3766 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3767 * rights to write into.
3768 */
3769 static void
3770f_filewritable(typval_T *argvars, typval_T *rettv)
3771{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003772 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003773}
3774
3775 static void
3776findfilendir(
3777 typval_T *argvars UNUSED,
3778 typval_T *rettv,
3779 int find_what UNUSED)
3780{
3781#ifdef FEAT_SEARCHPATH
3782 char_u *fname;
3783 char_u *fresult = NULL;
3784 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3785 char_u *p;
3786 char_u pathbuf[NUMBUFLEN];
3787 int count = 1;
3788 int first = TRUE;
3789 int error = FALSE;
3790#endif
3791
3792 rettv->vval.v_string = NULL;
3793 rettv->v_type = VAR_STRING;
3794
3795#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003796 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003797
3798 if (argvars[1].v_type != VAR_UNKNOWN)
3799 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003800 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003801 if (p == NULL)
3802 error = TRUE;
3803 else
3804 {
3805 if (*p != NUL)
3806 path = p;
3807
3808 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003809 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003810 }
3811 }
3812
3813 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3814 error = TRUE;
3815
3816 if (*fname != NUL && !error)
3817 {
3818 do
3819 {
3820 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3821 vim_free(fresult);
3822 fresult = find_file_in_path_option(first ? fname : NULL,
3823 first ? (int)STRLEN(fname) : 0,
3824 0, first, path,
3825 find_what,
3826 curbuf->b_ffname,
3827 find_what == FINDFILE_DIR
3828 ? (char_u *)"" : curbuf->b_p_sua);
3829 first = FALSE;
3830
3831 if (fresult != NULL && rettv->v_type == VAR_LIST)
3832 list_append_string(rettv->vval.v_list, fresult, -1);
3833
3834 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3835 }
3836
3837 if (rettv->v_type == VAR_STRING)
3838 rettv->vval.v_string = fresult;
3839#endif
3840}
3841
3842/*
3843 * "filter()" function
3844 */
3845 static void
3846f_filter(typval_T *argvars, typval_T *rettv)
3847{
3848 filter_map(argvars, rettv, FALSE);
3849}
3850
3851/*
3852 * "finddir({fname}[, {path}[, {count}]])" function
3853 */
3854 static void
3855f_finddir(typval_T *argvars, typval_T *rettv)
3856{
3857 findfilendir(argvars, rettv, FINDFILE_DIR);
3858}
3859
3860/*
3861 * "findfile({fname}[, {path}[, {count}]])" function
3862 */
3863 static void
3864f_findfile(typval_T *argvars, typval_T *rettv)
3865{
3866 findfilendir(argvars, rettv, FINDFILE_FILE);
3867}
3868
3869#ifdef FEAT_FLOAT
3870/*
3871 * "float2nr({float})" function
3872 */
3873 static void
3874f_float2nr(typval_T *argvars, typval_T *rettv)
3875{
3876 float_T f = 0.0;
3877
3878 if (get_float_arg(argvars, &f) == OK)
3879 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003880 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003881 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003882 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003883 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003884 else
3885 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003886 }
3887}
3888
3889/*
3890 * "floor({float})" function
3891 */
3892 static void
3893f_floor(typval_T *argvars, typval_T *rettv)
3894{
3895 float_T f = 0.0;
3896
3897 rettv->v_type = VAR_FLOAT;
3898 if (get_float_arg(argvars, &f) == OK)
3899 rettv->vval.v_float = floor(f);
3900 else
3901 rettv->vval.v_float = 0.0;
3902}
3903
3904/*
3905 * "fmod()" function
3906 */
3907 static void
3908f_fmod(typval_T *argvars, typval_T *rettv)
3909{
3910 float_T fx = 0.0, fy = 0.0;
3911
3912 rettv->v_type = VAR_FLOAT;
3913 if (get_float_arg(argvars, &fx) == OK
3914 && get_float_arg(&argvars[1], &fy) == OK)
3915 rettv->vval.v_float = fmod(fx, fy);
3916 else
3917 rettv->vval.v_float = 0.0;
3918}
3919#endif
3920
3921/*
3922 * "fnameescape({string})" function
3923 */
3924 static void
3925f_fnameescape(typval_T *argvars, typval_T *rettv)
3926{
3927 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003928 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003929 rettv->v_type = VAR_STRING;
3930}
3931
3932/*
3933 * "fnamemodify({fname}, {mods})" function
3934 */
3935 static void
3936f_fnamemodify(typval_T *argvars, typval_T *rettv)
3937{
3938 char_u *fname;
3939 char_u *mods;
3940 int usedlen = 0;
3941 int len;
3942 char_u *fbuf = NULL;
3943 char_u buf[NUMBUFLEN];
3944
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003945 fname = tv_get_string_chk(&argvars[0]);
3946 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003947 if (fname == NULL || mods == NULL)
3948 fname = NULL;
3949 else
3950 {
3951 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003952 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953 }
3954
3955 rettv->v_type = VAR_STRING;
3956 if (fname == NULL)
3957 rettv->vval.v_string = NULL;
3958 else
3959 rettv->vval.v_string = vim_strnsave(fname, len);
3960 vim_free(fbuf);
3961}
3962
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003963/*
3964 * "foldclosed()" function
3965 */
3966 static void
3967foldclosed_both(
3968 typval_T *argvars UNUSED,
3969 typval_T *rettv,
3970 int end UNUSED)
3971{
3972#ifdef FEAT_FOLDING
3973 linenr_T lnum;
3974 linenr_T first, last;
3975
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003976 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003977 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3978 {
3979 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3980 {
3981 if (end)
3982 rettv->vval.v_number = (varnumber_T)last;
3983 else
3984 rettv->vval.v_number = (varnumber_T)first;
3985 return;
3986 }
3987 }
3988#endif
3989 rettv->vval.v_number = -1;
3990}
3991
3992/*
3993 * "foldclosed()" function
3994 */
3995 static void
3996f_foldclosed(typval_T *argvars, typval_T *rettv)
3997{
3998 foldclosed_both(argvars, rettv, FALSE);
3999}
4000
4001/*
4002 * "foldclosedend()" function
4003 */
4004 static void
4005f_foldclosedend(typval_T *argvars, typval_T *rettv)
4006{
4007 foldclosed_both(argvars, rettv, TRUE);
4008}
4009
4010/*
4011 * "foldlevel()" function
4012 */
4013 static void
4014f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4015{
4016#ifdef FEAT_FOLDING
4017 linenr_T lnum;
4018
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004019 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4021 rettv->vval.v_number = foldLevel(lnum);
4022#endif
4023}
4024
4025/*
4026 * "foldtext()" function
4027 */
4028 static void
4029f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4030{
4031#ifdef FEAT_FOLDING
4032 linenr_T foldstart;
4033 linenr_T foldend;
4034 char_u *dashes;
4035 linenr_T lnum;
4036 char_u *s;
4037 char_u *r;
4038 int len;
4039 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004040 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004041#endif
4042
4043 rettv->v_type = VAR_STRING;
4044 rettv->vval.v_string = NULL;
4045#ifdef FEAT_FOLDING
4046 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4047 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4048 dashes = get_vim_var_str(VV_FOLDDASHES);
4049 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4050 && dashes != NULL)
4051 {
4052 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004053 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004054 if (!linewhite(lnum))
4055 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004056
4057 /* Find interesting text in this line. */
4058 s = skipwhite(ml_get(lnum));
4059 /* skip C comment-start */
4060 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4061 {
4062 s = skipwhite(s + 2);
4063 if (*skipwhite(s) == NUL
4064 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4065 {
4066 s = skipwhite(ml_get(lnum + 1));
4067 if (*s == '*')
4068 s = skipwhite(s + 1);
4069 }
4070 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004071 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004072 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004073 r = alloc((unsigned)(STRLEN(txt)
4074 + STRLEN(dashes) /* for %s */
4075 + 20 /* for %3ld */
4076 + STRLEN(s))); /* concatenated */
4077 if (r != NULL)
4078 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004079 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004080 len = (int)STRLEN(r);
4081 STRCAT(r, s);
4082 /* remove 'foldmarker' and 'commentstring' */
4083 foldtext_cleanup(r + len);
4084 rettv->vval.v_string = r;
4085 }
4086 }
4087#endif
4088}
4089
4090/*
4091 * "foldtextresult(lnum)" function
4092 */
4093 static void
4094f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4095{
4096#ifdef FEAT_FOLDING
4097 linenr_T lnum;
4098 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004099 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004100 foldinfo_T foldinfo;
4101 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004102 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004103#endif
4104
4105 rettv->v_type = VAR_STRING;
4106 rettv->vval.v_string = NULL;
4107#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004108 if (entered)
4109 return; /* reject recursive use */
4110 entered = TRUE;
4111
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004112 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004113 /* treat illegal types and illegal string values for {lnum} the same */
4114 if (lnum < 0)
4115 lnum = 0;
4116 fold_count = foldedCount(curwin, lnum, &foldinfo);
4117 if (fold_count > 0)
4118 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004119 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4120 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004121 if (text == buf)
4122 text = vim_strsave(text);
4123 rettv->vval.v_string = text;
4124 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004125
4126 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004127#endif
4128}
4129
4130/*
4131 * "foreground()" function
4132 */
4133 static void
4134f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4135{
4136#ifdef FEAT_GUI
4137 if (gui.in_use)
4138 gui_mch_set_foreground();
4139#else
Bram Moolenaar4f974752019-02-17 17:44:42 +01004140# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 win32_set_foreground();
4142# endif
4143#endif
4144}
4145
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004146 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004147common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148{
4149 char_u *s;
4150 char_u *name;
4151 int use_string = FALSE;
4152 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004153 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004154
4155 if (argvars[0].v_type == VAR_FUNC)
4156 {
4157 /* function(MyFunc, [arg], dict) */
4158 s = argvars[0].vval.v_string;
4159 }
4160 else if (argvars[0].v_type == VAR_PARTIAL
4161 && argvars[0].vval.v_partial != NULL)
4162 {
4163 /* function(dict.MyFunc, [arg]) */
4164 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004165 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004166 }
4167 else
4168 {
4169 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004170 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004171 use_string = TRUE;
4172 }
4173
Bram Moolenaar843b8842016-08-21 14:36:15 +02004174 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004175 {
4176 name = s;
4177 trans_name = trans_function_name(&name, FALSE,
4178 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4179 if (*name != NUL)
4180 s = NULL;
4181 }
4182
Bram Moolenaar843b8842016-08-21 14:36:15 +02004183 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4184 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004185 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004186 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004187 else if (trans_name != NULL && (is_funcref
4188 ? find_func(trans_name) == NULL
4189 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004190 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004191 else
4192 {
4193 int dict_idx = 0;
4194 int arg_idx = 0;
4195 list_T *list = NULL;
4196
4197 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4198 {
4199 char sid_buf[25];
4200 int off = *s == 's' ? 2 : 5;
4201
4202 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4203 * also be called from another script. Using trans_function_name()
4204 * would also work, but some plugins depend on the name being
4205 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004206 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004207 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4208 if (name != NULL)
4209 {
4210 STRCPY(name, sid_buf);
4211 STRCAT(name, s + off);
4212 }
4213 }
4214 else
4215 name = vim_strsave(s);
4216
4217 if (argvars[1].v_type != VAR_UNKNOWN)
4218 {
4219 if (argvars[2].v_type != VAR_UNKNOWN)
4220 {
4221 /* function(name, [args], dict) */
4222 arg_idx = 1;
4223 dict_idx = 2;
4224 }
4225 else if (argvars[1].v_type == VAR_DICT)
4226 /* function(name, dict) */
4227 dict_idx = 1;
4228 else
4229 /* function(name, [args]) */
4230 arg_idx = 1;
4231 if (dict_idx > 0)
4232 {
4233 if (argvars[dict_idx].v_type != VAR_DICT)
4234 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004235 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004236 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004237 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004238 }
4239 if (argvars[dict_idx].vval.v_dict == NULL)
4240 dict_idx = 0;
4241 }
4242 if (arg_idx > 0)
4243 {
4244 if (argvars[arg_idx].v_type != VAR_LIST)
4245 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004246 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004248 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004249 }
4250 list = argvars[arg_idx].vval.v_list;
4251 if (list == NULL || list->lv_len == 0)
4252 arg_idx = 0;
4253 }
4254 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004255 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004256 {
4257 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4258
4259 /* result is a VAR_PARTIAL */
4260 if (pt == NULL)
4261 vim_free(name);
4262 else
4263 {
4264 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4265 {
4266 listitem_T *li;
4267 int i = 0;
4268 int arg_len = 0;
4269 int lv_len = 0;
4270
4271 if (arg_pt != NULL)
4272 arg_len = arg_pt->pt_argc;
4273 if (list != NULL)
4274 lv_len = list->lv_len;
4275 pt->pt_argc = arg_len + lv_len;
4276 pt->pt_argv = (typval_T *)alloc(
4277 sizeof(typval_T) * pt->pt_argc);
4278 if (pt->pt_argv == NULL)
4279 {
4280 vim_free(pt);
4281 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004282 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004283 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004284 for (i = 0; i < arg_len; i++)
4285 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4286 if (lv_len > 0)
4287 for (li = list->lv_first; li != NULL;
4288 li = li->li_next)
4289 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004290 }
4291
4292 /* For "function(dict.func, [], dict)" and "func" is a partial
4293 * use "dict". That is backwards compatible. */
4294 if (dict_idx > 0)
4295 {
4296 /* The dict is bound explicitly, pt_auto is FALSE. */
4297 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4298 ++pt->pt_dict->dv_refcount;
4299 }
4300 else if (arg_pt != NULL)
4301 {
4302 /* If the dict was bound automatically the result is also
4303 * bound automatically. */
4304 pt->pt_dict = arg_pt->pt_dict;
4305 pt->pt_auto = arg_pt->pt_auto;
4306 if (pt->pt_dict != NULL)
4307 ++pt->pt_dict->dv_refcount;
4308 }
4309
4310 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004311 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4312 {
4313 pt->pt_func = arg_pt->pt_func;
4314 func_ptr_ref(pt->pt_func);
4315 vim_free(name);
4316 }
4317 else if (is_funcref)
4318 {
4319 pt->pt_func = find_func(trans_name);
4320 func_ptr_ref(pt->pt_func);
4321 vim_free(name);
4322 }
4323 else
4324 {
4325 pt->pt_name = name;
4326 func_ref(name);
4327 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004328 }
4329 rettv->v_type = VAR_PARTIAL;
4330 rettv->vval.v_partial = pt;
4331 }
4332 else
4333 {
4334 /* result is a VAR_FUNC */
4335 rettv->v_type = VAR_FUNC;
4336 rettv->vval.v_string = name;
4337 func_ref(name);
4338 }
4339 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004340theend:
4341 vim_free(trans_name);
4342}
4343
4344/*
4345 * "funcref()" function
4346 */
4347 static void
4348f_funcref(typval_T *argvars, typval_T *rettv)
4349{
4350 common_function(argvars, rettv, TRUE);
4351}
4352
4353/*
4354 * "function()" function
4355 */
4356 static void
4357f_function(typval_T *argvars, typval_T *rettv)
4358{
4359 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004360}
4361
4362/*
4363 * "garbagecollect()" function
4364 */
4365 static void
4366f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4367{
4368 /* This is postponed until we are back at the toplevel, because we may be
4369 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4370 want_garbage_collect = TRUE;
4371
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004372 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004373 garbage_collect_at_exit = TRUE;
4374}
4375
4376/*
4377 * "get()" function
4378 */
4379 static void
4380f_get(typval_T *argvars, typval_T *rettv)
4381{
4382 listitem_T *li;
4383 list_T *l;
4384 dictitem_T *di;
4385 dict_T *d;
4386 typval_T *tv = NULL;
4387
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004388 if (argvars[0].v_type == VAR_BLOB)
4389 {
4390 int error = FALSE;
4391 int idx = tv_get_number_chk(&argvars[1], &error);
4392
4393 if (!error)
4394 {
4395 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004396 if (idx < 0)
4397 idx = blob_len(argvars[0].vval.v_blob) + idx;
4398 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4399 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004400 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004401 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004402 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004403 tv = rettv;
4404 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004405 }
4406 }
4407 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004408 {
4409 if ((l = argvars[0].vval.v_list) != NULL)
4410 {
4411 int error = FALSE;
4412
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004413 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004414 if (!error && li != NULL)
4415 tv = &li->li_tv;
4416 }
4417 }
4418 else if (argvars[0].v_type == VAR_DICT)
4419 {
4420 if ((d = argvars[0].vval.v_dict) != NULL)
4421 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004422 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004423 if (di != NULL)
4424 tv = &di->di_tv;
4425 }
4426 }
4427 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4428 {
4429 partial_T *pt;
4430 partial_T fref_pt;
4431
4432 if (argvars[0].v_type == VAR_PARTIAL)
4433 pt = argvars[0].vval.v_partial;
4434 else
4435 {
4436 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4437 fref_pt.pt_name = argvars[0].vval.v_string;
4438 pt = &fref_pt;
4439 }
4440
4441 if (pt != NULL)
4442 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004443 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004444 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004445
4446 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4447 {
4448 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004449 n = partial_name(pt);
4450 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004451 rettv->vval.v_string = NULL;
4452 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004453 {
4454 rettv->vval.v_string = vim_strsave(n);
4455 if (rettv->v_type == VAR_FUNC)
4456 func_ref(rettv->vval.v_string);
4457 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004458 }
4459 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004460 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004461 else if (STRCMP(what, "args") == 0)
4462 {
4463 rettv->v_type = VAR_LIST;
4464 if (rettv_list_alloc(rettv) == OK)
4465 {
4466 int i;
4467
4468 for (i = 0; i < pt->pt_argc; ++i)
4469 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4470 }
4471 }
4472 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004473 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474 return;
4475 }
4476 }
4477 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004478 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479
4480 if (tv == NULL)
4481 {
4482 if (argvars[2].v_type != VAR_UNKNOWN)
4483 copy_tv(&argvars[2], rettv);
4484 }
4485 else
4486 copy_tv(tv, rettv);
4487}
4488
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004489/*
4490 * Returns buffer options, variables and other attributes in a dictionary.
4491 */
4492 static dict_T *
4493get_buffer_info(buf_T *buf)
4494{
4495 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004496 tabpage_T *tp;
4497 win_T *wp;
4498 list_T *windows;
4499
4500 dict = dict_alloc();
4501 if (dict == NULL)
4502 return NULL;
4503
Bram Moolenaare0be1672018-07-08 16:50:37 +02004504 dict_add_number(dict, "bufnr", buf->b_fnum);
4505 dict_add_string(dict, "name", buf->b_ffname);
4506 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4507 : buflist_findlnum(buf));
4508 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4509 dict_add_number(dict, "listed", buf->b_p_bl);
4510 dict_add_number(dict, "changed", bufIsChanged(buf));
4511 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4512 dict_add_number(dict, "hidden",
4513 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004514
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004515 /* Get a reference to buffer variables */
4516 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004517
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004518 /* List of windows displaying this buffer */
4519 windows = list_alloc();
4520 if (windows != NULL)
4521 {
4522 FOR_ALL_TAB_WINDOWS(tp, wp)
4523 if (wp->w_buffer == buf)
4524 list_append_number(windows, (varnumber_T)wp->w_id);
4525 dict_add_list(dict, "windows", windows);
4526 }
4527
4528#ifdef FEAT_SIGNS
4529 if (buf->b_signlist != NULL)
4530 {
4531 /* List of signs placed in this buffer */
4532 list_T *signs = list_alloc();
4533 if (signs != NULL)
4534 {
4535 get_buffer_signs(buf, signs);
4536 dict_add_list(dict, "signs", signs);
4537 }
4538 }
4539#endif
4540
4541 return dict;
4542}
4543
4544/*
4545 * "getbufinfo()" function
4546 */
4547 static void
4548f_getbufinfo(typval_T *argvars, typval_T *rettv)
4549{
4550 buf_T *buf = NULL;
4551 buf_T *argbuf = NULL;
4552 dict_T *d;
4553 int filtered = FALSE;
4554 int sel_buflisted = FALSE;
4555 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004556 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004557
4558 if (rettv_list_alloc(rettv) != OK)
4559 return;
4560
4561 /* List of all the buffers or selected buffers */
4562 if (argvars[0].v_type == VAR_DICT)
4563 {
4564 dict_T *sel_d = argvars[0].vval.v_dict;
4565
4566 if (sel_d != NULL)
4567 {
4568 dictitem_T *di;
4569
4570 filtered = TRUE;
4571
4572 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004573 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004574 sel_buflisted = TRUE;
4575
4576 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004577 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004578 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004579
4580 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004581 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004582 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004583 }
4584 }
4585 else if (argvars[0].v_type != VAR_UNKNOWN)
4586 {
4587 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004588 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004589 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004590 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004591 --emsg_off;
4592 if (argbuf == NULL)
4593 return;
4594 }
4595
4596 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004597 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004598 {
4599 if (argbuf != NULL && argbuf != buf)
4600 continue;
4601 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004602 || (sel_buflisted && !buf->b_p_bl)
4603 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004604 continue;
4605
4606 d = get_buffer_info(buf);
4607 if (d != NULL)
4608 list_append_dict(rettv->vval.v_list, d);
4609 if (argbuf != NULL)
4610 return;
4611 }
4612}
4613
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004614/*
4615 * Get line or list of lines from buffer "buf" into "rettv".
4616 * Return a range (from start to end) of lines in rettv from the specified
4617 * buffer.
4618 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4619 */
4620 static void
4621get_buffer_lines(
4622 buf_T *buf,
4623 linenr_T start,
4624 linenr_T end,
4625 int retlist,
4626 typval_T *rettv)
4627{
4628 char_u *p;
4629
4630 rettv->v_type = VAR_STRING;
4631 rettv->vval.v_string = NULL;
4632 if (retlist && rettv_list_alloc(rettv) == FAIL)
4633 return;
4634
4635 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4636 return;
4637
4638 if (!retlist)
4639 {
4640 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4641 p = ml_get_buf(buf, start, FALSE);
4642 else
4643 p = (char_u *)"";
4644 rettv->vval.v_string = vim_strsave(p);
4645 }
4646 else
4647 {
4648 if (end < start)
4649 return;
4650
4651 if (start < 1)
4652 start = 1;
4653 if (end > buf->b_ml.ml_line_count)
4654 end = buf->b_ml.ml_line_count;
4655 while (start <= end)
4656 if (list_append_string(rettv->vval.v_list,
4657 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4658 break;
4659 }
4660}
4661
4662/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663 * "getbufline()" function
4664 */
4665 static void
4666f_getbufline(typval_T *argvars, typval_T *rettv)
4667{
4668 linenr_T lnum;
4669 linenr_T end;
4670 buf_T *buf;
4671
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004672 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004673 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004674 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675 --emsg_off;
4676
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004677 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004678 if (argvars[2].v_type == VAR_UNKNOWN)
4679 end = lnum;
4680 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004681 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004682
4683 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4684}
4685
4686/*
4687 * "getbufvar()" function
4688 */
4689 static void
4690f_getbufvar(typval_T *argvars, typval_T *rettv)
4691{
4692 buf_T *buf;
4693 buf_T *save_curbuf;
4694 char_u *varname;
4695 dictitem_T *v;
4696 int done = FALSE;
4697
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004698 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4699 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004701 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702
4703 rettv->v_type = VAR_STRING;
4704 rettv->vval.v_string = NULL;
4705
4706 if (buf != NULL && varname != NULL)
4707 {
4708 /* set curbuf to be our buf, temporarily */
4709 save_curbuf = curbuf;
4710 curbuf = buf;
4711
Bram Moolenaar30567352016-08-27 21:25:44 +02004712 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004713 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004714 if (varname[1] == NUL)
4715 {
4716 /* get all buffer-local options in a dict */
4717 dict_T *opts = get_winbuf_options(TRUE);
4718
4719 if (opts != NULL)
4720 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004721 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004722 done = TRUE;
4723 }
4724 }
4725 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4726 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004727 done = TRUE;
4728 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 else
4730 {
4731 /* Look up the variable. */
4732 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4733 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4734 'b', varname, FALSE);
4735 if (v != NULL)
4736 {
4737 copy_tv(&v->di_tv, rettv);
4738 done = TRUE;
4739 }
4740 }
4741
4742 /* restore previous notion of curbuf */
4743 curbuf = save_curbuf;
4744 }
4745
4746 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4747 /* use the default value */
4748 copy_tv(&argvars[2], rettv);
4749
4750 --emsg_off;
4751}
4752
4753/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004754 * "getchangelist()" function
4755 */
4756 static void
4757f_getchangelist(typval_T *argvars, typval_T *rettv)
4758{
4759#ifdef FEAT_JUMPLIST
4760 buf_T *buf;
4761 int i;
4762 list_T *l;
4763 dict_T *d;
4764#endif
4765
4766 if (rettv_list_alloc(rettv) != OK)
4767 return;
4768
4769#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004770 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004771 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004772 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004773 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004774 if (buf == NULL)
4775 return;
4776
4777 l = list_alloc();
4778 if (l == NULL)
4779 return;
4780
4781 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4782 return;
4783 /*
4784 * The current window change list index tracks only the position in the
4785 * current buffer change list. For other buffers, use the change list
4786 * length as the current index.
4787 */
4788 list_append_number(rettv->vval.v_list,
4789 (varnumber_T)((buf == curwin->w_buffer)
4790 ? curwin->w_changelistidx : buf->b_changelistlen));
4791
4792 for (i = 0; i < buf->b_changelistlen; ++i)
4793 {
4794 if (buf->b_changelist[i].lnum == 0)
4795 continue;
4796 if ((d = dict_alloc()) == NULL)
4797 return;
4798 if (list_append_dict(l, d) == FAIL)
4799 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004800 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4801 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004802 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004803 }
4804#endif
4805}
4806/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004807 * "getchar()" function
4808 */
4809 static void
4810f_getchar(typval_T *argvars, typval_T *rettv)
4811{
4812 varnumber_T n;
4813 int error = FALSE;
Bram Moolenaarf0fab302019-03-05 12:24:10 +01004814 int save_reg_executing = reg_executing;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815
Bram Moolenaar84d93902018-09-11 20:10:20 +02004816#ifdef MESSAGE_QUEUE
4817 // vpeekc() used to check for messages, but that caused problems, invoking
4818 // a callback where it was not expected. Some plugins use getchar(1) in a
4819 // loop to await a message, therefore make sure we check for messages here.
4820 parse_queued_messages();
4821#endif
4822
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004823 /* Position the cursor. Needed after a message that ends in a space. */
4824 windgoto(msg_row, msg_col);
4825
4826 ++no_mapping;
4827 ++allow_keys;
4828 for (;;)
4829 {
4830 if (argvars[0].v_type == VAR_UNKNOWN)
4831 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004832 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004833 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004834 /* getchar(1): only check if char avail */
4835 n = vpeekc_any();
4836 else if (error || vpeekc_any() == NUL)
4837 /* illegal argument or getchar(0) and no char avail: return zero */
4838 n = 0;
4839 else
4840 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004841 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004842
4843 if (n == K_IGNORE)
4844 continue;
4845 break;
4846 }
4847 --no_mapping;
4848 --allow_keys;
Bram Moolenaarf0fab302019-03-05 12:24:10 +01004849 reg_executing = save_reg_executing;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850
4851 set_vim_var_nr(VV_MOUSE_WIN, 0);
4852 set_vim_var_nr(VV_MOUSE_WINID, 0);
4853 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4854 set_vim_var_nr(VV_MOUSE_COL, 0);
4855
4856 rettv->vval.v_number = n;
4857 if (IS_SPECIAL(n) || mod_mask != 0)
4858 {
4859 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4860 int i = 0;
4861
4862 /* Turn a special key into three bytes, plus modifier. */
4863 if (mod_mask != 0)
4864 {
4865 temp[i++] = K_SPECIAL;
4866 temp[i++] = KS_MODIFIER;
4867 temp[i++] = mod_mask;
4868 }
4869 if (IS_SPECIAL(n))
4870 {
4871 temp[i++] = K_SPECIAL;
4872 temp[i++] = K_SECOND(n);
4873 temp[i++] = K_THIRD(n);
4874 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004875 else if (has_mbyte)
4876 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004877 else
4878 temp[i++] = n;
4879 temp[i++] = NUL;
4880 rettv->v_type = VAR_STRING;
4881 rettv->vval.v_string = vim_strsave(temp);
4882
4883#ifdef FEAT_MOUSE
4884 if (is_mouse_key(n))
4885 {
4886 int row = mouse_row;
4887 int col = mouse_col;
4888 win_T *win;
4889 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004890 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004891 int winnr = 1;
4892
4893 if (row >= 0 && col >= 0)
4894 {
4895 /* Find the window at the mouse coordinates and compute the
4896 * text position. */
4897 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004898 if (win == NULL)
4899 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004900 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004901 for (wp = firstwin; wp != win; wp = wp->w_next)
4902 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4904 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4905 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4906 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4907 }
4908 }
4909#endif
4910 }
4911}
4912
4913/*
4914 * "getcharmod()" function
4915 */
4916 static void
4917f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4918{
4919 rettv->vval.v_number = mod_mask;
4920}
4921
4922/*
4923 * "getcharsearch()" function
4924 */
4925 static void
4926f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4927{
4928 if (rettv_dict_alloc(rettv) != FAIL)
4929 {
4930 dict_T *dict = rettv->vval.v_dict;
4931
Bram Moolenaare0be1672018-07-08 16:50:37 +02004932 dict_add_string(dict, "char", last_csearch());
4933 dict_add_number(dict, "forward", last_csearch_forward());
4934 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935 }
4936}
4937
4938/*
4939 * "getcmdline()" function
4940 */
4941 static void
4942f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4943{
4944 rettv->v_type = VAR_STRING;
4945 rettv->vval.v_string = get_cmdline_str();
4946}
4947
4948/*
4949 * "getcmdpos()" function
4950 */
4951 static void
4952f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4953{
4954 rettv->vval.v_number = get_cmdline_pos() + 1;
4955}
4956
4957/*
4958 * "getcmdtype()" function
4959 */
4960 static void
4961f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4962{
4963 rettv->v_type = VAR_STRING;
4964 rettv->vval.v_string = alloc(2);
4965 if (rettv->vval.v_string != NULL)
4966 {
4967 rettv->vval.v_string[0] = get_cmdline_type();
4968 rettv->vval.v_string[1] = NUL;
4969 }
4970}
4971
4972/*
4973 * "getcmdwintype()" function
4974 */
4975 static void
4976f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4977{
4978 rettv->v_type = VAR_STRING;
4979 rettv->vval.v_string = NULL;
4980#ifdef FEAT_CMDWIN
4981 rettv->vval.v_string = alloc(2);
4982 if (rettv->vval.v_string != NULL)
4983 {
4984 rettv->vval.v_string[0] = cmdwin_type;
4985 rettv->vval.v_string[1] = NUL;
4986 }
4987#endif
4988}
4989
4990#if defined(FEAT_CMDL_COMPL)
4991/*
4992 * "getcompletion()" function
4993 */
4994 static void
4995f_getcompletion(typval_T *argvars, typval_T *rettv)
4996{
4997 char_u *pat;
4998 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004999 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005000 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5001 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005002
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005003 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005004 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005005
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005006 if (p_wic)
5007 options |= WILD_ICASE;
5008
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005009 /* For filtered results, 'wildignore' is used */
5010 if (!filtered)
5011 options |= WILD_KEEP_ALL;
5012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005013 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005014 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005015 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005016 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005017 if (xpc.xp_context == EXPAND_NOTHING)
5018 {
5019 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005020 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005021 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005022 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005023 return;
5024 }
5025
5026# if defined(FEAT_MENU)
5027 if (xpc.xp_context == EXPAND_MENUS)
5028 {
5029 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5030 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5031 }
5032# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005033#ifdef FEAT_CSCOPE
5034 if (xpc.xp_context == EXPAND_CSCOPE)
5035 {
5036 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5037 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5038 }
5039#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005040#ifdef FEAT_SIGNS
5041 if (xpc.xp_context == EXPAND_SIGN)
5042 {
5043 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5044 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5045 }
5046#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005047
5048 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5049 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5050 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005051 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005052
5053 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5054
5055 for (i = 0; i < xpc.xp_numfiles; i++)
5056 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5057 }
5058 vim_free(pat);
5059 ExpandCleanup(&xpc);
5060}
5061#endif
5062
5063/*
5064 * "getcwd()" function
5065 */
5066 static void
5067f_getcwd(typval_T *argvars, typval_T *rettv)
5068{
5069 win_T *wp = NULL;
5070 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005071 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005072
5073 rettv->v_type = VAR_STRING;
5074 rettv->vval.v_string = NULL;
5075
Bram Moolenaar54591292018-02-09 20:53:59 +01005076 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5077 global = TRUE;
5078 else
5079 wp = find_tabwin(&argvars[0], &argvars[1]);
5080
5081 if (wp != NULL && wp->w_localdir != NULL)
5082 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5083 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005084 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005085 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005086 rettv->vval.v_string = vim_strsave(globaldir);
5087 else
5088 {
5089 cwd = alloc(MAXPATHL);
5090 if (cwd != NULL)
5091 {
5092 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5093 rettv->vval.v_string = vim_strsave(cwd);
5094 vim_free(cwd);
5095 }
5096 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005098#ifdef BACKSLASH_IN_FILENAME
5099 if (rettv->vval.v_string != NULL)
5100 slash_adjust(rettv->vval.v_string);
5101#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102}
5103
5104/*
5105 * "getfontname()" function
5106 */
5107 static void
5108f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5109{
5110 rettv->v_type = VAR_STRING;
5111 rettv->vval.v_string = NULL;
5112#ifdef FEAT_GUI
5113 if (gui.in_use)
5114 {
5115 GuiFont font;
5116 char_u *name = NULL;
5117
5118 if (argvars[0].v_type == VAR_UNKNOWN)
5119 {
5120 /* Get the "Normal" font. Either the name saved by
5121 * hl_set_font_name() or from the font ID. */
5122 font = gui.norm_font;
5123 name = hl_get_font_name();
5124 }
5125 else
5126 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005127 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005128 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5129 return;
5130 font = gui_mch_get_font(name, FALSE);
5131 if (font == NOFONT)
5132 return; /* Invalid font name, return empty string. */
5133 }
5134 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5135 if (argvars[0].v_type != VAR_UNKNOWN)
5136 gui_mch_free_font(font);
5137 }
5138#endif
5139}
5140
5141/*
5142 * "getfperm({fname})" function
5143 */
5144 static void
5145f_getfperm(typval_T *argvars, typval_T *rettv)
5146{
5147 char_u *fname;
5148 stat_T st;
5149 char_u *perm = NULL;
5150 char_u flags[] = "rwx";
5151 int i;
5152
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005153 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005154
5155 rettv->v_type = VAR_STRING;
5156 if (mch_stat((char *)fname, &st) >= 0)
5157 {
5158 perm = vim_strsave((char_u *)"---------");
5159 if (perm != NULL)
5160 {
5161 for (i = 0; i < 9; i++)
5162 {
5163 if (st.st_mode & (1 << (8 - i)))
5164 perm[i] = flags[i % 3];
5165 }
5166 }
5167 }
5168 rettv->vval.v_string = perm;
5169}
5170
5171/*
5172 * "getfsize({fname})" function
5173 */
5174 static void
5175f_getfsize(typval_T *argvars, typval_T *rettv)
5176{
5177 char_u *fname;
5178 stat_T st;
5179
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005180 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005181
5182 rettv->v_type = VAR_NUMBER;
5183
5184 if (mch_stat((char *)fname, &st) >= 0)
5185 {
5186 if (mch_isdir(fname))
5187 rettv->vval.v_number = 0;
5188 else
5189 {
5190 rettv->vval.v_number = (varnumber_T)st.st_size;
5191
5192 /* non-perfect check for overflow */
5193 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5194 rettv->vval.v_number = -2;
5195 }
5196 }
5197 else
5198 rettv->vval.v_number = -1;
5199}
5200
5201/*
5202 * "getftime({fname})" function
5203 */
5204 static void
5205f_getftime(typval_T *argvars, typval_T *rettv)
5206{
5207 char_u *fname;
5208 stat_T st;
5209
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005210 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005211
5212 if (mch_stat((char *)fname, &st) >= 0)
5213 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5214 else
5215 rettv->vval.v_number = -1;
5216}
5217
5218/*
5219 * "getftype({fname})" function
5220 */
5221 static void
5222f_getftype(typval_T *argvars, typval_T *rettv)
5223{
5224 char_u *fname;
5225 stat_T st;
5226 char_u *type = NULL;
5227 char *t;
5228
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005229 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005230
5231 rettv->v_type = VAR_STRING;
5232 if (mch_lstat((char *)fname, &st) >= 0)
5233 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005234 if (S_ISREG(st.st_mode))
5235 t = "file";
5236 else if (S_ISDIR(st.st_mode))
5237 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005238 else if (S_ISLNK(st.st_mode))
5239 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005240 else if (S_ISBLK(st.st_mode))
5241 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242 else if (S_ISCHR(st.st_mode))
5243 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244 else if (S_ISFIFO(st.st_mode))
5245 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005246 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005247 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005248 else
5249 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005250 type = vim_strsave((char_u *)t);
5251 }
5252 rettv->vval.v_string = type;
5253}
5254
5255/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005256 * "getjumplist()" function
5257 */
5258 static void
5259f_getjumplist(typval_T *argvars, typval_T *rettv)
5260{
5261#ifdef FEAT_JUMPLIST
5262 win_T *wp;
5263 int i;
5264 list_T *l;
5265 dict_T *d;
5266#endif
5267
5268 if (rettv_list_alloc(rettv) != OK)
5269 return;
5270
5271#ifdef FEAT_JUMPLIST
5272 wp = find_tabwin(&argvars[0], &argvars[1]);
5273 if (wp == NULL)
5274 return;
5275
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005276 cleanup_jumplist(wp, TRUE);
5277
Bram Moolenaar4f505882018-02-10 21:06:32 +01005278 l = list_alloc();
5279 if (l == NULL)
5280 return;
5281
5282 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5283 return;
5284 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5285
5286 for (i = 0; i < wp->w_jumplistlen; ++i)
5287 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005288 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5289 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005290 if ((d = dict_alloc()) == NULL)
5291 return;
5292 if (list_append_dict(l, d) == FAIL)
5293 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005294 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5295 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005296 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005297 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005298 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005299 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005300 }
5301#endif
5302}
5303
5304/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005305 * "getline(lnum, [end])" function
5306 */
5307 static void
5308f_getline(typval_T *argvars, typval_T *rettv)
5309{
5310 linenr_T lnum;
5311 linenr_T end;
5312 int retlist;
5313
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005314 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005315 if (argvars[1].v_type == VAR_UNKNOWN)
5316 {
5317 end = 0;
5318 retlist = FALSE;
5319 }
5320 else
5321 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005322 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005323 retlist = TRUE;
5324 }
5325
5326 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5327}
5328
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005329#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005330 static void
5331get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5332{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005333 if (what_arg->v_type == VAR_UNKNOWN)
5334 {
5335 if (rettv_list_alloc(rettv) == OK)
5336 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005337 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005338 }
5339 else
5340 {
5341 if (rettv_dict_alloc(rettv) == OK)
5342 if (is_qf || (wp != NULL))
5343 {
5344 if (what_arg->v_type == VAR_DICT)
5345 {
5346 dict_T *d = what_arg->vval.v_dict;
5347
5348 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005349 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005350 }
5351 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005352 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005353 }
5354 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005355}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005356#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005357
5358/*
5359 * "getloclist()" function
5360 */
5361 static void
5362f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5363{
5364#ifdef FEAT_QUICKFIX
5365 win_T *wp;
5366
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005367 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005368 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5369#endif
5370}
5371
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005372/*
5373 * "getmatches()" function
5374 */
5375 static void
5376f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5377{
5378#ifdef FEAT_SEARCH_EXTRA
5379 dict_T *dict;
5380 matchitem_T *cur = curwin->w_match_head;
5381 int i;
5382
5383 if (rettv_list_alloc(rettv) == OK)
5384 {
5385 while (cur != NULL)
5386 {
5387 dict = dict_alloc();
5388 if (dict == NULL)
5389 return;
5390 if (cur->match.regprog == NULL)
5391 {
5392 /* match added with matchaddpos() */
5393 for (i = 0; i < MAXPOSMATCH; ++i)
5394 {
5395 llpos_T *llpos;
5396 char buf[6];
5397 list_T *l;
5398
5399 llpos = &cur->pos.pos[i];
5400 if (llpos->lnum == 0)
5401 break;
5402 l = list_alloc();
5403 if (l == NULL)
5404 break;
5405 list_append_number(l, (varnumber_T)llpos->lnum);
5406 if (llpos->col > 0)
5407 {
5408 list_append_number(l, (varnumber_T)llpos->col);
5409 list_append_number(l, (varnumber_T)llpos->len);
5410 }
5411 sprintf(buf, "pos%d", i + 1);
5412 dict_add_list(dict, buf, l);
5413 }
5414 }
5415 else
5416 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005417 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005418 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005419 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5420 dict_add_number(dict, "priority", (long)cur->priority);
5421 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar13505972019-01-24 15:04:48 +01005422# if defined(FEAT_CONCEAL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005423 if (cur->conceal_char)
5424 {
5425 char_u buf[MB_MAXBYTES + 1];
5426
5427 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005428 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005429 }
5430# endif
5431 list_append_dict(rettv->vval.v_list, dict);
5432 cur = cur->next;
5433 }
5434 }
5435#endif
5436}
5437
5438/*
5439 * "getpid()" function
5440 */
5441 static void
5442f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5443{
5444 rettv->vval.v_number = mch_get_pid();
5445}
5446
5447 static void
5448getpos_both(
5449 typval_T *argvars,
5450 typval_T *rettv,
5451 int getcurpos)
5452{
5453 pos_T *fp;
5454 list_T *l;
5455 int fnum = -1;
5456
5457 if (rettv_list_alloc(rettv) == OK)
5458 {
5459 l = rettv->vval.v_list;
5460 if (getcurpos)
5461 fp = &curwin->w_cursor;
5462 else
5463 fp = var2fpos(&argvars[0], TRUE, &fnum);
5464 if (fnum != -1)
5465 list_append_number(l, (varnumber_T)fnum);
5466 else
5467 list_append_number(l, (varnumber_T)0);
5468 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5469 : (varnumber_T)0);
5470 list_append_number(l, (fp != NULL)
5471 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5472 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005473 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005474 (varnumber_T)0);
5475 if (getcurpos)
5476 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005477 int save_set_curswant = curwin->w_set_curswant;
5478 colnr_T save_curswant = curwin->w_curswant;
5479 colnr_T save_virtcol = curwin->w_virtcol;
5480
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005481 update_curswant();
5482 list_append_number(l, curwin->w_curswant == MAXCOL ?
5483 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005484
5485 // Do not change "curswant", as it is unexpected that a get
5486 // function has a side effect.
5487 if (save_set_curswant)
5488 {
5489 curwin->w_set_curswant = save_set_curswant;
5490 curwin->w_curswant = save_curswant;
5491 curwin->w_virtcol = save_virtcol;
5492 curwin->w_valid &= ~VALID_VIRTCOL;
5493 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005494 }
5495 }
5496 else
5497 rettv->vval.v_number = FALSE;
5498}
5499
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005500/*
5501 * "getcurpos()" function
5502 */
5503 static void
5504f_getcurpos(typval_T *argvars, typval_T *rettv)
5505{
5506 getpos_both(argvars, rettv, TRUE);
5507}
5508
5509/*
5510 * "getpos(string)" function
5511 */
5512 static void
5513f_getpos(typval_T *argvars, typval_T *rettv)
5514{
5515 getpos_both(argvars, rettv, FALSE);
5516}
5517
5518/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005519 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005520 */
5521 static void
5522f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5523{
5524#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005525 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005526#endif
5527}
5528
5529/*
5530 * "getreg()" function
5531 */
5532 static void
5533f_getreg(typval_T *argvars, typval_T *rettv)
5534{
5535 char_u *strregname;
5536 int regname;
5537 int arg2 = FALSE;
5538 int return_list = FALSE;
5539 int error = FALSE;
5540
5541 if (argvars[0].v_type != VAR_UNKNOWN)
5542 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005543 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544 error = strregname == NULL;
5545 if (argvars[1].v_type != VAR_UNKNOWN)
5546 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005547 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005549 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005550 }
5551 }
5552 else
5553 strregname = get_vim_var_str(VV_REG);
5554
5555 if (error)
5556 return;
5557
5558 regname = (strregname == NULL ? '"' : *strregname);
5559 if (regname == 0)
5560 regname = '"';
5561
5562 if (return_list)
5563 {
5564 rettv->v_type = VAR_LIST;
5565 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5566 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5567 if (rettv->vval.v_list == NULL)
5568 (void)rettv_list_alloc(rettv);
5569 else
5570 ++rettv->vval.v_list->lv_refcount;
5571 }
5572 else
5573 {
5574 rettv->v_type = VAR_STRING;
5575 rettv->vval.v_string = get_reg_contents(regname,
5576 arg2 ? GREG_EXPR_SRC : 0);
5577 }
5578}
5579
5580/*
5581 * "getregtype()" function
5582 */
5583 static void
5584f_getregtype(typval_T *argvars, typval_T *rettv)
5585{
5586 char_u *strregname;
5587 int regname;
5588 char_u buf[NUMBUFLEN + 2];
5589 long reglen = 0;
5590
5591 if (argvars[0].v_type != VAR_UNKNOWN)
5592 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005593 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005594 if (strregname == NULL) /* type error; errmsg already given */
5595 {
5596 rettv->v_type = VAR_STRING;
5597 rettv->vval.v_string = NULL;
5598 return;
5599 }
5600 }
5601 else
5602 /* Default to v:register */
5603 strregname = get_vim_var_str(VV_REG);
5604
5605 regname = (strregname == NULL ? '"' : *strregname);
5606 if (regname == 0)
5607 regname = '"';
5608
5609 buf[0] = NUL;
5610 buf[1] = NUL;
5611 switch (get_reg_type(regname, &reglen))
5612 {
5613 case MLINE: buf[0] = 'V'; break;
5614 case MCHAR: buf[0] = 'v'; break;
5615 case MBLOCK:
5616 buf[0] = Ctrl_V;
5617 sprintf((char *)buf + 1, "%ld", reglen + 1);
5618 break;
5619 }
5620 rettv->v_type = VAR_STRING;
5621 rettv->vval.v_string = vim_strsave(buf);
5622}
5623
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005624/*
5625 * Returns information (variables, options, etc.) about a tab page
5626 * as a dictionary.
5627 */
5628 static dict_T *
5629get_tabpage_info(tabpage_T *tp, int tp_idx)
5630{
5631 win_T *wp;
5632 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005633 list_T *l;
5634
5635 dict = dict_alloc();
5636 if (dict == NULL)
5637 return NULL;
5638
Bram Moolenaare0be1672018-07-08 16:50:37 +02005639 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005640
5641 l = list_alloc();
5642 if (l != NULL)
5643 {
5644 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5645 wp; wp = wp->w_next)
5646 list_append_number(l, (varnumber_T)wp->w_id);
5647 dict_add_list(dict, "windows", l);
5648 }
5649
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005650 /* Make a reference to tabpage variables */
5651 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005652
5653 return dict;
5654}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005655
5656/*
5657 * "gettabinfo()" function
5658 */
5659 static void
5660f_gettabinfo(typval_T *argvars, typval_T *rettv)
5661{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005662 tabpage_T *tp, *tparg = NULL;
5663 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005664 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005665
5666 if (rettv_list_alloc(rettv) != OK)
5667 return;
5668
5669 if (argvars[0].v_type != VAR_UNKNOWN)
5670 {
5671 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005672 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005673 if (tparg == NULL)
5674 return;
5675 }
5676
5677 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005678 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005679 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005680 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005681 if (tparg != NULL && tp != tparg)
5682 continue;
5683 d = get_tabpage_info(tp, tpnr);
5684 if (d != NULL)
5685 list_append_dict(rettv->vval.v_list, d);
5686 if (tparg != NULL)
5687 return;
5688 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005689}
5690
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691/*
5692 * "gettabvar()" function
5693 */
5694 static void
5695f_gettabvar(typval_T *argvars, typval_T *rettv)
5696{
5697 win_T *oldcurwin;
5698 tabpage_T *tp, *oldtabpage;
5699 dictitem_T *v;
5700 char_u *varname;
5701 int done = FALSE;
5702
5703 rettv->v_type = VAR_STRING;
5704 rettv->vval.v_string = NULL;
5705
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005706 varname = tv_get_string_chk(&argvars[1]);
5707 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005708 if (tp != NULL && varname != NULL)
5709 {
5710 /* Set tp to be our tabpage, temporarily. Also set the window to the
5711 * first window in the tabpage, otherwise the window is not valid. */
5712 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005713 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5714 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005715 {
5716 /* look up the variable */
5717 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5718 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5719 if (v != NULL)
5720 {
5721 copy_tv(&v->di_tv, rettv);
5722 done = TRUE;
5723 }
5724 }
5725
5726 /* restore previous notion of curwin */
5727 restore_win(oldcurwin, oldtabpage, TRUE);
5728 }
5729
5730 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5731 copy_tv(&argvars[2], rettv);
5732}
5733
5734/*
5735 * "gettabwinvar()" function
5736 */
5737 static void
5738f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5739{
5740 getwinvar(argvars, rettv, 1);
5741}
5742
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005743/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005744 * "gettagstack()" function
5745 */
5746 static void
5747f_gettagstack(typval_T *argvars, typval_T *rettv)
5748{
5749 win_T *wp = curwin; // default is current window
5750
5751 if (rettv_dict_alloc(rettv) != OK)
5752 return;
5753
5754 if (argvars[0].v_type != VAR_UNKNOWN)
5755 {
5756 wp = find_win_by_nr_or_id(&argvars[0]);
5757 if (wp == NULL)
5758 return;
5759 }
5760
5761 get_tagstack(wp, rettv->vval.v_dict);
5762}
5763
5764/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005765 * Returns information about a window as a dictionary.
5766 */
5767 static dict_T *
5768get_win_info(win_T *wp, short tpnr, short winnr)
5769{
5770 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005771
5772 dict = dict_alloc();
5773 if (dict == NULL)
5774 return NULL;
5775
Bram Moolenaare0be1672018-07-08 16:50:37 +02005776 dict_add_number(dict, "tabnr", tpnr);
5777 dict_add_number(dict, "winnr", winnr);
5778 dict_add_number(dict, "winid", wp->w_id);
5779 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005780 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005781 dict_add_number(dict, "topline", wp->w_topline);
5782 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005783#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005784 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005785#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005786 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005787 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005788 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005789
Bram Moolenaar69905d12017-08-13 18:14:47 +02005790#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005791 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005792#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005793#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005794 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5795 dict_add_number(dict, "loclist",
5796 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005797#endif
5798
Bram Moolenaar30567352016-08-27 21:25:44 +02005799 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005800 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005801
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005802 return dict;
5803}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005804
5805/*
5806 * "getwininfo()" function
5807 */
5808 static void
5809f_getwininfo(typval_T *argvars, typval_T *rettv)
5810{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005811 tabpage_T *tp;
5812 win_T *wp = NULL, *wparg = NULL;
5813 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005814 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005815
5816 if (rettv_list_alloc(rettv) != OK)
5817 return;
5818
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005819 if (argvars[0].v_type != VAR_UNKNOWN)
5820 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005821 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005822 if (wparg == NULL)
5823 return;
5824 }
5825
5826 /* Collect information about either all the windows across all the tab
5827 * pages or one particular window.
5828 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005829 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005830 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005831 tabnr++;
5832 winnr = 0;
5833 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005834 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005835 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005836 if (wparg != NULL && wp != wparg)
5837 continue;
5838 d = get_win_info(wp, tabnr, winnr);
5839 if (d != NULL)
5840 list_append_dict(rettv->vval.v_list, d);
5841 if (wparg != NULL)
5842 /* found information about a specific window */
5843 return;
5844 }
5845 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005846}
5847
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005848/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005849 * "win_findbuf()" function
5850 */
5851 static void
5852f_win_findbuf(typval_T *argvars, typval_T *rettv)
5853{
5854 if (rettv_list_alloc(rettv) != FAIL)
5855 win_findbuf(argvars, rettv->vval.v_list);
5856}
5857
5858/*
5859 * "win_getid()" function
5860 */
5861 static void
5862f_win_getid(typval_T *argvars, typval_T *rettv)
5863{
5864 rettv->vval.v_number = win_getid(argvars);
5865}
5866
5867/*
5868 * "win_gotoid()" function
5869 */
5870 static void
5871f_win_gotoid(typval_T *argvars, typval_T *rettv)
5872{
5873 rettv->vval.v_number = win_gotoid(argvars);
5874}
5875
5876/*
5877 * "win_id2tabwin()" function
5878 */
5879 static void
5880f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5881{
5882 if (rettv_list_alloc(rettv) != FAIL)
5883 win_id2tabwin(argvars, rettv->vval.v_list);
5884}
5885
5886/*
5887 * "win_id2win()" function
5888 */
5889 static void
5890f_win_id2win(typval_T *argvars, typval_T *rettv)
5891{
5892 rettv->vval.v_number = win_id2win(argvars);
5893}
5894
5895/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005896 * "win_screenpos()" function
5897 */
5898 static void
5899f_win_screenpos(typval_T *argvars, typval_T *rettv)
5900{
5901 win_T *wp;
5902
5903 if (rettv_list_alloc(rettv) == FAIL)
5904 return;
5905
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005906 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005907 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5908 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5909}
5910
5911/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005912 * "getwinpos({timeout})" function
5913 */
5914 static void
5915f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5916{
5917 int x = -1;
5918 int y = -1;
5919
5920 if (rettv_list_alloc(rettv) == FAIL)
5921 return;
5922#ifdef FEAT_GUI
5923 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005924 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005925# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5926 else
5927# endif
5928#endif
5929#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5930 {
5931 varnumber_T timeout = 100;
5932
5933 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005934 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005935 term_get_winpos(&x, &y, timeout);
5936 }
5937#endif
5938 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5939 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5940}
5941
5942
5943/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005944 * "getwinposx()" function
5945 */
5946 static void
5947f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5948{
5949 rettv->vval.v_number = -1;
5950#ifdef FEAT_GUI
5951 if (gui.in_use)
5952 {
5953 int x, y;
5954
5955 if (gui_mch_get_winpos(&x, &y) == OK)
5956 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005957 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005958 }
5959#endif
5960#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5961 {
5962 int x, y;
5963
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005964 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005965 rettv->vval.v_number = x;
5966 }
5967#endif
5968}
5969
5970/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005971 * "getwinposy()" function
5972 */
5973 static void
5974f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5975{
5976 rettv->vval.v_number = -1;
5977#ifdef FEAT_GUI
5978 if (gui.in_use)
5979 {
5980 int x, y;
5981
5982 if (gui_mch_get_winpos(&x, &y) == OK)
5983 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005984 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005985 }
5986#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005987#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5988 {
5989 int x, y;
5990
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005991 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005992 rettv->vval.v_number = y;
5993 }
5994#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005995}
5996
5997/*
5998 * "getwinvar()" function
5999 */
6000 static void
6001f_getwinvar(typval_T *argvars, typval_T *rettv)
6002{
6003 getwinvar(argvars, rettv, 0);
6004}
6005
6006/*
6007 * "glob()" function
6008 */
6009 static void
6010f_glob(typval_T *argvars, typval_T *rettv)
6011{
6012 int options = WILD_SILENT|WILD_USE_NL;
6013 expand_T xpc;
6014 int error = FALSE;
6015
6016 /* When the optional second argument is non-zero, don't remove matches
6017 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6018 rettv->v_type = VAR_STRING;
6019 if (argvars[1].v_type != VAR_UNKNOWN)
6020 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006021 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006022 options |= WILD_KEEP_ALL;
6023 if (argvars[2].v_type != VAR_UNKNOWN)
6024 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006025 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006026 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006027 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006028 }
6029 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006030 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006031 options |= WILD_ALLLINKS;
6032 }
6033 }
6034 if (!error)
6035 {
6036 ExpandInit(&xpc);
6037 xpc.xp_context = EXPAND_FILES;
6038 if (p_wic)
6039 options += WILD_ICASE;
6040 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006041 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006042 NULL, options, WILD_ALL);
6043 else if (rettv_list_alloc(rettv) != FAIL)
6044 {
6045 int i;
6046
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006047 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006048 NULL, options, WILD_ALL_KEEP);
6049 for (i = 0; i < xpc.xp_numfiles; i++)
6050 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6051
6052 ExpandCleanup(&xpc);
6053 }
6054 }
6055 else
6056 rettv->vval.v_string = NULL;
6057}
6058
6059/*
6060 * "globpath()" function
6061 */
6062 static void
6063f_globpath(typval_T *argvars, typval_T *rettv)
6064{
6065 int flags = 0;
6066 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006067 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006068 int error = FALSE;
6069 garray_T ga;
6070 int i;
6071
6072 /* When the optional second argument is non-zero, don't remove matches
6073 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6074 rettv->v_type = VAR_STRING;
6075 if (argvars[2].v_type != VAR_UNKNOWN)
6076 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006077 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006078 flags |= WILD_KEEP_ALL;
6079 if (argvars[3].v_type != VAR_UNKNOWN)
6080 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006081 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006082 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006083 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006084 }
6085 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006086 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087 flags |= WILD_ALLLINKS;
6088 }
6089 }
6090 if (file != NULL && !error)
6091 {
6092 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006093 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006094 if (rettv->v_type == VAR_STRING)
6095 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6096 else if (rettv_list_alloc(rettv) != FAIL)
6097 for (i = 0; i < ga.ga_len; ++i)
6098 list_append_string(rettv->vval.v_list,
6099 ((char_u **)(ga.ga_data))[i], -1);
6100 ga_clear_strings(&ga);
6101 }
6102 else
6103 rettv->vval.v_string = NULL;
6104}
6105
6106/*
6107 * "glob2regpat()" function
6108 */
6109 static void
6110f_glob2regpat(typval_T *argvars, typval_T *rettv)
6111{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006112 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006113
6114 rettv->v_type = VAR_STRING;
6115 rettv->vval.v_string = (pat == NULL)
6116 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6117}
6118
6119/* for VIM_VERSION_ defines */
6120#include "version.h"
6121
6122/*
6123 * "has()" function
6124 */
6125 static void
6126f_has(typval_T *argvars, typval_T *rettv)
6127{
6128 int i;
6129 char_u *name;
6130 int n = FALSE;
6131 static char *(has_list[]) =
6132 {
6133#ifdef AMIGA
6134 "amiga",
6135# ifdef FEAT_ARP
6136 "arp",
6137# endif
6138#endif
6139#ifdef __BEOS__
6140 "beos",
6141#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006142#if defined(BSD) && !defined(MACOS_X)
6143 "bsd",
6144#endif
6145#ifdef hpux
6146 "hpux",
6147#endif
6148#ifdef __linux__
6149 "linux",
6150#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006151#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006152 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6153 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006154# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006155 "macunix", /* Mac OS X, with the darwin feature */
6156 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006157# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006158#endif
6159#ifdef __QNX__
6160 "qnx",
6161#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006162#ifdef SUN_SYSTEM
6163 "sun",
6164#else
6165 "moon",
6166#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006167#ifdef UNIX
6168 "unix",
6169#endif
6170#ifdef VMS
6171 "vms",
6172#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006173#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006174 "win32",
6175#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006176#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006177 "win32unix",
6178#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006179#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006180 "win64",
6181#endif
6182#ifdef EBCDIC
6183 "ebcdic",
6184#endif
6185#ifndef CASE_INSENSITIVE_FILENAME
6186 "fname_case",
6187#endif
6188#ifdef HAVE_ACL
6189 "acl",
6190#endif
6191#ifdef FEAT_ARABIC
6192 "arabic",
6193#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006195#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006196 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006197#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006198#ifdef FEAT_AUTOSERVERNAME
6199 "autoservername",
6200#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006201#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006202 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006203# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006204 "balloon_multiline",
6205# endif
6206#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006207#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006208 "balloon_eval_term",
6209#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006210#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6211 "builtin_terms",
6212# ifdef ALL_BUILTIN_TCAPS
6213 "all_builtin_terms",
6214# endif
6215#endif
6216#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006217 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218 || defined(FEAT_GUI_MOTIF))
6219 "browsefilter",
6220#endif
6221#ifdef FEAT_BYTEOFF
6222 "byte_offset",
6223#endif
6224#ifdef FEAT_JOB_CHANNEL
6225 "channel",
6226#endif
6227#ifdef FEAT_CINDENT
6228 "cindent",
6229#endif
6230#ifdef FEAT_CLIENTSERVER
6231 "clientserver",
6232#endif
6233#ifdef FEAT_CLIPBOARD
6234 "clipboard",
6235#endif
6236#ifdef FEAT_CMDL_COMPL
6237 "cmdline_compl",
6238#endif
6239#ifdef FEAT_CMDHIST
6240 "cmdline_hist",
6241#endif
6242#ifdef FEAT_COMMENTS
6243 "comments",
6244#endif
6245#ifdef FEAT_CONCEAL
6246 "conceal",
6247#endif
6248#ifdef FEAT_CRYPT
6249 "cryptv",
6250 "crypt-blowfish",
6251 "crypt-blowfish2",
6252#endif
6253#ifdef FEAT_CSCOPE
6254 "cscope",
6255#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006256 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006257#ifdef CURSOR_SHAPE
6258 "cursorshape",
6259#endif
6260#ifdef DEBUG
6261 "debug",
6262#endif
6263#ifdef FEAT_CON_DIALOG
6264 "dialog_con",
6265#endif
6266#ifdef FEAT_GUI_DIALOG
6267 "dialog_gui",
6268#endif
6269#ifdef FEAT_DIFF
6270 "diff",
6271#endif
6272#ifdef FEAT_DIGRAPHS
6273 "digraphs",
6274#endif
6275#ifdef FEAT_DIRECTX
6276 "directx",
6277#endif
6278#ifdef FEAT_DND
6279 "dnd",
6280#endif
6281#ifdef FEAT_EMACS_TAGS
6282 "emacs_tags",
6283#endif
6284 "eval", /* always present, of course! */
6285 "ex_extra", /* graduated feature */
6286#ifdef FEAT_SEARCH_EXTRA
6287 "extra_search",
6288#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006289#ifdef FEAT_SEARCHPATH
6290 "file_in_path",
6291#endif
6292#ifdef FEAT_FILTERPIPE
6293 "filterpipe",
6294#endif
6295#ifdef FEAT_FIND_ID
6296 "find_in_path",
6297#endif
6298#ifdef FEAT_FLOAT
6299 "float",
6300#endif
6301#ifdef FEAT_FOLDING
6302 "folding",
6303#endif
6304#ifdef FEAT_FOOTER
6305 "footer",
6306#endif
6307#if !defined(USE_SYSTEM) && defined(UNIX)
6308 "fork",
6309#endif
6310#ifdef FEAT_GETTEXT
6311 "gettext",
6312#endif
6313#ifdef FEAT_GUI
6314 "gui",
6315#endif
6316#ifdef FEAT_GUI_ATHENA
6317# ifdef FEAT_GUI_NEXTAW
6318 "gui_neXtaw",
6319# else
6320 "gui_athena",
6321# endif
6322#endif
6323#ifdef FEAT_GUI_GTK
6324 "gui_gtk",
6325# ifdef USE_GTK3
6326 "gui_gtk3",
6327# else
6328 "gui_gtk2",
6329# endif
6330#endif
6331#ifdef FEAT_GUI_GNOME
6332 "gui_gnome",
6333#endif
6334#ifdef FEAT_GUI_MAC
6335 "gui_mac",
6336#endif
6337#ifdef FEAT_GUI_MOTIF
6338 "gui_motif",
6339#endif
6340#ifdef FEAT_GUI_PHOTON
6341 "gui_photon",
6342#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006343#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006344 "gui_win32",
6345#endif
6346#ifdef FEAT_HANGULIN
6347 "hangul_input",
6348#endif
6349#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6350 "iconv",
6351#endif
6352#ifdef FEAT_INS_EXPAND
6353 "insert_expand",
6354#endif
6355#ifdef FEAT_JOB_CHANNEL
6356 "job",
6357#endif
6358#ifdef FEAT_JUMPLIST
6359 "jumplist",
6360#endif
6361#ifdef FEAT_KEYMAP
6362 "keymap",
6363#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006364 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365#ifdef FEAT_LANGMAP
6366 "langmap",
6367#endif
6368#ifdef FEAT_LIBCALL
6369 "libcall",
6370#endif
6371#ifdef FEAT_LINEBREAK
6372 "linebreak",
6373#endif
6374#ifdef FEAT_LISP
6375 "lispindent",
6376#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006377 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006378#ifdef FEAT_LOCALMAP
6379 "localmap",
6380#endif
6381#ifdef FEAT_LUA
6382# ifndef DYNAMIC_LUA
6383 "lua",
6384# endif
6385#endif
6386#ifdef FEAT_MENU
6387 "menu",
6388#endif
6389#ifdef FEAT_SESSION
6390 "mksession",
6391#endif
6392#ifdef FEAT_MODIFY_FNAME
6393 "modify_fname",
6394#endif
6395#ifdef FEAT_MOUSE
6396 "mouse",
6397#endif
6398#ifdef FEAT_MOUSESHAPE
6399 "mouseshape",
6400#endif
6401#if defined(UNIX) || defined(VMS)
6402# ifdef FEAT_MOUSE_DEC
6403 "mouse_dec",
6404# endif
6405# ifdef FEAT_MOUSE_GPM
6406 "mouse_gpm",
6407# endif
6408# ifdef FEAT_MOUSE_JSB
6409 "mouse_jsbterm",
6410# endif
6411# ifdef FEAT_MOUSE_NET
6412 "mouse_netterm",
6413# endif
6414# ifdef FEAT_MOUSE_PTERM
6415 "mouse_pterm",
6416# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006417# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006418 "mouse_sgr",
6419# endif
6420# ifdef FEAT_SYSMOUSE
6421 "mouse_sysmouse",
6422# endif
6423# ifdef FEAT_MOUSE_URXVT
6424 "mouse_urxvt",
6425# endif
6426# ifdef FEAT_MOUSE_XTERM
6427 "mouse_xterm",
6428# endif
6429#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006431#ifdef FEAT_MBYTE_IME
6432 "multi_byte_ime",
6433#endif
6434#ifdef FEAT_MULTI_LANG
6435 "multi_lang",
6436#endif
6437#ifdef FEAT_MZSCHEME
6438#ifndef DYNAMIC_MZSCHEME
6439 "mzscheme",
6440#endif
6441#endif
6442#ifdef FEAT_NUM64
6443 "num64",
6444#endif
6445#ifdef FEAT_OLE
6446 "ole",
6447#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006448#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006449 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006450#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451#ifdef FEAT_PATH_EXTRA
6452 "path_extra",
6453#endif
6454#ifdef FEAT_PERL
6455#ifndef DYNAMIC_PERL
6456 "perl",
6457#endif
6458#endif
6459#ifdef FEAT_PERSISTENT_UNDO
6460 "persistent_undo",
6461#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006462#if defined(FEAT_PYTHON)
6463 "python_compiled",
6464# if defined(DYNAMIC_PYTHON)
6465 "python_dynamic",
6466# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006467 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006468 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006469# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006470#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006471#if defined(FEAT_PYTHON3)
6472 "python3_compiled",
6473# if defined(DYNAMIC_PYTHON3)
6474 "python3_dynamic",
6475# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006477 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006478# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006479#endif
6480#ifdef FEAT_POSTSCRIPT
6481 "postscript",
6482#endif
6483#ifdef FEAT_PRINTER
6484 "printer",
6485#endif
6486#ifdef FEAT_PROFILE
6487 "profile",
6488#endif
6489#ifdef FEAT_RELTIME
6490 "reltime",
6491#endif
6492#ifdef FEAT_QUICKFIX
6493 "quickfix",
6494#endif
6495#ifdef FEAT_RIGHTLEFT
6496 "rightleft",
6497#endif
6498#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6499 "ruby",
6500#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502#ifdef FEAT_CMDL_INFO
6503 "showcmd",
6504 "cmdline_info",
6505#endif
6506#ifdef FEAT_SIGNS
6507 "signs",
6508#endif
6509#ifdef FEAT_SMARTINDENT
6510 "smartindent",
6511#endif
6512#ifdef STARTUPTIME
6513 "startuptime",
6514#endif
6515#ifdef FEAT_STL_OPT
6516 "statusline",
6517#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006518#ifdef FEAT_NETBEANS_INTG
6519 "netbeans_intg",
6520#endif
6521#ifdef FEAT_SPELL
6522 "spell",
6523#endif
6524#ifdef FEAT_SYN_HL
6525 "syntax",
6526#endif
6527#if defined(USE_SYSTEM) || !defined(UNIX)
6528 "system",
6529#endif
6530#ifdef FEAT_TAG_BINS
6531 "tag_binary",
6532#endif
6533#ifdef FEAT_TAG_OLDSTATIC
6534 "tag_old_static",
6535#endif
6536#ifdef FEAT_TAG_ANYWHITE
6537 "tag_any_white",
6538#endif
6539#ifdef FEAT_TCL
6540# ifndef DYNAMIC_TCL
6541 "tcl",
6542# endif
6543#endif
6544#ifdef FEAT_TERMGUICOLORS
6545 "termguicolors",
6546#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006547#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006548 "terminal",
6549#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550#ifdef TERMINFO
6551 "terminfo",
6552#endif
6553#ifdef FEAT_TERMRESPONSE
6554 "termresponse",
6555#endif
6556#ifdef FEAT_TEXTOBJ
6557 "textobjects",
6558#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006559#ifdef FEAT_TEXT_PROP
6560 "textprop",
6561#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562#ifdef HAVE_TGETENT
6563 "tgetent",
6564#endif
6565#ifdef FEAT_TIMERS
6566 "timers",
6567#endif
6568#ifdef FEAT_TITLE
6569 "title",
6570#endif
6571#ifdef FEAT_TOOLBAR
6572 "toolbar",
6573#endif
6574#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6575 "unnamedplus",
6576#endif
6577#ifdef FEAT_USR_CMDS
6578 "user-commands", /* was accidentally included in 5.4 */
6579 "user_commands",
6580#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006581#ifdef FEAT_VARTABS
6582 "vartabs",
6583#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006584#ifdef FEAT_VIMINFO
6585 "viminfo",
6586#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006587 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006591 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006592#ifdef FEAT_VTP
6593 "vtp",
6594#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006595#ifdef FEAT_WILDIGN
6596 "wildignore",
6597#endif
6598#ifdef FEAT_WILDMENU
6599 "wildmenu",
6600#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006601 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602#ifdef FEAT_WAK
6603 "winaltkeys",
6604#endif
6605#ifdef FEAT_WRITEBACKUP
6606 "writebackup",
6607#endif
6608#ifdef FEAT_XIM
6609 "xim",
6610#endif
6611#ifdef FEAT_XFONTSET
6612 "xfontset",
6613#endif
6614#ifdef FEAT_XPM_W32
6615 "xpm",
6616 "xpm_w32", /* for backward compatibility */
6617#else
6618# if defined(HAVE_XPM)
6619 "xpm",
6620# endif
6621#endif
6622#ifdef USE_XSMP
6623 "xsmp",
6624#endif
6625#ifdef USE_XSMP_INTERACT
6626 "xsmp_interact",
6627#endif
6628#ifdef FEAT_XCLIPBOARD
6629 "xterm_clipboard",
6630#endif
6631#ifdef FEAT_XTERM_SAVE
6632 "xterm_save",
6633#endif
6634#if defined(UNIX) && defined(FEAT_X11)
6635 "X11",
6636#endif
6637 NULL
6638 };
6639
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006640 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 for (i = 0; has_list[i] != NULL; ++i)
6642 if (STRICMP(name, has_list[i]) == 0)
6643 {
6644 n = TRUE;
6645 break;
6646 }
6647
6648 if (n == FALSE)
6649 {
6650 if (STRNICMP(name, "patch", 5) == 0)
6651 {
6652 if (name[5] == '-'
6653 && STRLEN(name) >= 11
6654 && vim_isdigit(name[6])
6655 && vim_isdigit(name[8])
6656 && vim_isdigit(name[10]))
6657 {
6658 int major = atoi((char *)name + 6);
6659 int minor = atoi((char *)name + 8);
6660
6661 /* Expect "patch-9.9.01234". */
6662 n = (major < VIM_VERSION_MAJOR
6663 || (major == VIM_VERSION_MAJOR
6664 && (minor < VIM_VERSION_MINOR
6665 || (minor == VIM_VERSION_MINOR
6666 && has_patch(atoi((char *)name + 10))))));
6667 }
6668 else
6669 n = has_patch(atoi((char *)name + 5));
6670 }
6671 else if (STRICMP(name, "vim_starting") == 0)
6672 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006673 else if (STRICMP(name, "ttyin") == 0)
6674 n = mch_input_isatty();
6675 else if (STRICMP(name, "ttyout") == 0)
6676 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006677 else if (STRICMP(name, "multi_byte_encoding") == 0)
6678 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006679#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006680 else if (STRICMP(name, "balloon_multiline") == 0)
6681 n = multiline_balloon_available();
6682#endif
6683#ifdef DYNAMIC_TCL
6684 else if (STRICMP(name, "tcl") == 0)
6685 n = tcl_enabled(FALSE);
6686#endif
6687#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6688 else if (STRICMP(name, "iconv") == 0)
6689 n = iconv_enabled(FALSE);
6690#endif
6691#ifdef DYNAMIC_LUA
6692 else if (STRICMP(name, "lua") == 0)
6693 n = lua_enabled(FALSE);
6694#endif
6695#ifdef DYNAMIC_MZSCHEME
6696 else if (STRICMP(name, "mzscheme") == 0)
6697 n = mzscheme_enabled(FALSE);
6698#endif
6699#ifdef DYNAMIC_RUBY
6700 else if (STRICMP(name, "ruby") == 0)
6701 n = ruby_enabled(FALSE);
6702#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006703#ifdef DYNAMIC_PYTHON
6704 else if (STRICMP(name, "python") == 0)
6705 n = python_enabled(FALSE);
6706#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006707#ifdef DYNAMIC_PYTHON3
6708 else if (STRICMP(name, "python3") == 0)
6709 n = python3_enabled(FALSE);
6710#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006711#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6712 else if (STRICMP(name, "pythonx") == 0)
6713 {
6714# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6715 if (p_pyx == 0)
6716 n = python3_enabled(FALSE) || python_enabled(FALSE);
6717 else if (p_pyx == 3)
6718 n = python3_enabled(FALSE);
6719 else if (p_pyx == 2)
6720 n = python_enabled(FALSE);
6721# elif defined(DYNAMIC_PYTHON)
6722 n = python_enabled(FALSE);
6723# elif defined(DYNAMIC_PYTHON3)
6724 n = python3_enabled(FALSE);
6725# endif
6726 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006727#endif
6728#ifdef DYNAMIC_PERL
6729 else if (STRICMP(name, "perl") == 0)
6730 n = perl_enabled(FALSE);
6731#endif
6732#ifdef FEAT_GUI
6733 else if (STRICMP(name, "gui_running") == 0)
6734 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006735# ifdef FEAT_BROWSE
6736 else if (STRICMP(name, "browse") == 0)
6737 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6738# endif
6739#endif
6740#ifdef FEAT_SYN_HL
6741 else if (STRICMP(name, "syntax_items") == 0)
6742 n = syntax_present(curwin);
6743#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006744#ifdef FEAT_VTP
6745 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006746 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006747#endif
6748#ifdef FEAT_NETBEANS_INTG
6749 else if (STRICMP(name, "netbeans_enabled") == 0)
6750 n = netbeans_active();
6751#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006752#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006753 else if (STRICMP(name, "terminal") == 0)
6754 n = terminal_enabled();
6755#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006756#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006757 else if (STRICMP(name, "conpty") == 0)
6758 n = use_conpty();
6759#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006760 }
6761
6762 rettv->vval.v_number = n;
6763}
6764
6765/*
6766 * "has_key()" function
6767 */
6768 static void
6769f_has_key(typval_T *argvars, typval_T *rettv)
6770{
6771 if (argvars[0].v_type != VAR_DICT)
6772 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006773 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774 return;
6775 }
6776 if (argvars[0].vval.v_dict == NULL)
6777 return;
6778
6779 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006780 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006781}
6782
6783/*
6784 * "haslocaldir()" function
6785 */
6786 static void
6787f_haslocaldir(typval_T *argvars, typval_T *rettv)
6788{
6789 win_T *wp = NULL;
6790
6791 wp = find_tabwin(&argvars[0], &argvars[1]);
6792 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6793}
6794
6795/*
6796 * "hasmapto()" function
6797 */
6798 static void
6799f_hasmapto(typval_T *argvars, typval_T *rettv)
6800{
6801 char_u *name;
6802 char_u *mode;
6803 char_u buf[NUMBUFLEN];
6804 int abbr = FALSE;
6805
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006806 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006807 if (argvars[1].v_type == VAR_UNKNOWN)
6808 mode = (char_u *)"nvo";
6809 else
6810 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006811 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006813 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006814 }
6815
6816 if (map_to_exists(name, mode, abbr))
6817 rettv->vval.v_number = TRUE;
6818 else
6819 rettv->vval.v_number = FALSE;
6820}
6821
6822/*
6823 * "histadd()" function
6824 */
6825 static void
6826f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6827{
6828#ifdef FEAT_CMDHIST
6829 int histype;
6830 char_u *str;
6831 char_u buf[NUMBUFLEN];
6832#endif
6833
6834 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006835 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836 return;
6837#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006838 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006839 histype = str != NULL ? get_histtype(str) : -1;
6840 if (histype >= 0)
6841 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006842 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006843 if (*str != NUL)
6844 {
6845 init_history();
6846 add_to_history(histype, str, FALSE, NUL);
6847 rettv->vval.v_number = TRUE;
6848 return;
6849 }
6850 }
6851#endif
6852}
6853
6854/*
6855 * "histdel()" function
6856 */
6857 static void
6858f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6859{
6860#ifdef FEAT_CMDHIST
6861 int n;
6862 char_u buf[NUMBUFLEN];
6863 char_u *str;
6864
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006865 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 if (str == NULL)
6867 n = 0;
6868 else if (argvars[1].v_type == VAR_UNKNOWN)
6869 /* only one argument: clear entire history */
6870 n = clr_history(get_histtype(str));
6871 else if (argvars[1].v_type == VAR_NUMBER)
6872 /* index given: remove that entry */
6873 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006874 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006875 else
6876 /* string given: remove all matching entries */
6877 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006878 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879 rettv->vval.v_number = n;
6880#endif
6881}
6882
6883/*
6884 * "histget()" function
6885 */
6886 static void
6887f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6888{
6889#ifdef FEAT_CMDHIST
6890 int type;
6891 int idx;
6892 char_u *str;
6893
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006894 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006895 if (str == NULL)
6896 rettv->vval.v_string = NULL;
6897 else
6898 {
6899 type = get_histtype(str);
6900 if (argvars[1].v_type == VAR_UNKNOWN)
6901 idx = get_history_idx(type);
6902 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006903 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006904 /* -1 on type error */
6905 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6906 }
6907#else
6908 rettv->vval.v_string = NULL;
6909#endif
6910 rettv->v_type = VAR_STRING;
6911}
6912
6913/*
6914 * "histnr()" function
6915 */
6916 static void
6917f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6918{
6919 int i;
6920
6921#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006922 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006923
6924 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6925 if (i >= HIST_CMD && i < HIST_COUNT)
6926 i = get_history_idx(i);
6927 else
6928#endif
6929 i = -1;
6930 rettv->vval.v_number = i;
6931}
6932
6933/*
6934 * "highlightID(name)" function
6935 */
6936 static void
6937f_hlID(typval_T *argvars, typval_T *rettv)
6938{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006939 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006940}
6941
6942/*
6943 * "highlight_exists()" function
6944 */
6945 static void
6946f_hlexists(typval_T *argvars, typval_T *rettv)
6947{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006948 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006949}
6950
6951/*
6952 * "hostname()" function
6953 */
6954 static void
6955f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6956{
6957 char_u hostname[256];
6958
6959 mch_get_host_name(hostname, 256);
6960 rettv->v_type = VAR_STRING;
6961 rettv->vval.v_string = vim_strsave(hostname);
6962}
6963
6964/*
6965 * iconv() function
6966 */
6967 static void
6968f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6969{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 char_u buf1[NUMBUFLEN];
6971 char_u buf2[NUMBUFLEN];
6972 char_u *from, *to, *str;
6973 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974
6975 rettv->v_type = VAR_STRING;
6976 rettv->vval.v_string = NULL;
6977
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006978 str = tv_get_string(&argvars[0]);
6979 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6980 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981 vimconv.vc_type = CONV_NONE;
6982 convert_setup(&vimconv, from, to);
6983
6984 /* If the encodings are equal, no conversion needed. */
6985 if (vimconv.vc_type == CONV_NONE)
6986 rettv->vval.v_string = vim_strsave(str);
6987 else
6988 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6989
6990 convert_setup(&vimconv, NULL, NULL);
6991 vim_free(from);
6992 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006993}
6994
6995/*
6996 * "indent()" function
6997 */
6998 static void
6999f_indent(typval_T *argvars, typval_T *rettv)
7000{
7001 linenr_T lnum;
7002
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007003 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007004 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7005 rettv->vval.v_number = get_indent_lnum(lnum);
7006 else
7007 rettv->vval.v_number = -1;
7008}
7009
7010/*
7011 * "index()" function
7012 */
7013 static void
7014f_index(typval_T *argvars, typval_T *rettv)
7015{
7016 list_T *l;
7017 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007018 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007019 long idx = 0;
7020 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007021 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007022
7023 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007024 if (argvars[0].v_type == VAR_BLOB)
7025 {
7026 typval_T tv;
7027 int start = 0;
7028
7029 if (argvars[2].v_type != VAR_UNKNOWN)
7030 {
7031 start = tv_get_number_chk(&argvars[2], &error);
7032 if (error)
7033 return;
7034 }
7035 b = argvars[0].vval.v_blob;
7036 if (b == NULL)
7037 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007038 if (start < 0)
7039 {
7040 start = blob_len(b) + start;
7041 if (start < 0)
7042 start = 0;
7043 }
7044
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007045 for (idx = start; idx < blob_len(b); ++idx)
7046 {
7047 tv.v_type = VAR_NUMBER;
7048 tv.vval.v_number = blob_get(b, idx);
7049 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7050 {
7051 rettv->vval.v_number = idx;
7052 return;
7053 }
7054 }
7055 return;
7056 }
7057 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007058 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007059 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007060 return;
7061 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007062
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063 l = argvars[0].vval.v_list;
7064 if (l != NULL)
7065 {
7066 item = l->lv_first;
7067 if (argvars[2].v_type != VAR_UNKNOWN)
7068 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069 /* Start at specified item. Use the cached index that list_find()
7070 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007071 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007072 idx = l->lv_idx;
7073 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007074 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 if (error)
7076 item = NULL;
7077 }
7078
7079 for ( ; item != NULL; item = item->li_next, ++idx)
7080 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7081 {
7082 rettv->vval.v_number = idx;
7083 break;
7084 }
7085 }
7086}
7087
7088static int inputsecret_flag = 0;
7089
7090/*
7091 * "input()" function
7092 * Also handles inputsecret() when inputsecret is set.
7093 */
7094 static void
7095f_input(typval_T *argvars, typval_T *rettv)
7096{
7097 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7098}
7099
7100/*
7101 * "inputdialog()" function
7102 */
7103 static void
7104f_inputdialog(typval_T *argvars, typval_T *rettv)
7105{
7106#if defined(FEAT_GUI_TEXTDIALOG)
7107 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7108 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7109 {
7110 char_u *message;
7111 char_u buf[NUMBUFLEN];
7112 char_u *defstr = (char_u *)"";
7113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007114 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007115 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007116 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007117 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7118 else
7119 IObuff[0] = NUL;
7120 if (message != NULL && defstr != NULL
7121 && do_dialog(VIM_QUESTION, NULL, message,
7122 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7123 rettv->vval.v_string = vim_strsave(IObuff);
7124 else
7125 {
7126 if (message != NULL && defstr != NULL
7127 && argvars[1].v_type != VAR_UNKNOWN
7128 && argvars[2].v_type != VAR_UNKNOWN)
7129 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007130 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 else
7132 rettv->vval.v_string = NULL;
7133 }
7134 rettv->v_type = VAR_STRING;
7135 }
7136 else
7137#endif
7138 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7139}
7140
7141/*
7142 * "inputlist()" function
7143 */
7144 static void
7145f_inputlist(typval_T *argvars, typval_T *rettv)
7146{
7147 listitem_T *li;
7148 int selected;
7149 int mouse_used;
7150
7151#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007152 /* While starting up, there is no place to enter text. When running tests
7153 * with --not-a-term we assume feedkeys() will be used. */
7154 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007155 return;
7156#endif
7157 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7158 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007159 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160 return;
7161 }
7162
7163 msg_start();
7164 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7165 lines_left = Rows; /* avoid more prompt */
7166 msg_scroll = TRUE;
7167 msg_clr_eos();
7168
7169 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7170 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007171 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007172 msg_putchar('\n');
7173 }
7174
7175 /* Ask for choice. */
7176 selected = prompt_for_number(&mouse_used);
7177 if (mouse_used)
7178 selected -= lines_left;
7179
7180 rettv->vval.v_number = selected;
7181}
7182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007183static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7184
7185/*
7186 * "inputrestore()" function
7187 */
7188 static void
7189f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7190{
7191 if (ga_userinput.ga_len > 0)
7192 {
7193 --ga_userinput.ga_len;
7194 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7195 + ga_userinput.ga_len);
7196 /* default return is zero == OK */
7197 }
7198 else if (p_verbose > 1)
7199 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007200 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007201 rettv->vval.v_number = 1; /* Failed */
7202 }
7203}
7204
7205/*
7206 * "inputsave()" function
7207 */
7208 static void
7209f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7210{
7211 /* Add an entry to the stack of typeahead storage. */
7212 if (ga_grow(&ga_userinput, 1) == OK)
7213 {
7214 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7215 + ga_userinput.ga_len);
7216 ++ga_userinput.ga_len;
7217 /* default return is zero == OK */
7218 }
7219 else
7220 rettv->vval.v_number = 1; /* Failed */
7221}
7222
7223/*
7224 * "inputsecret()" function
7225 */
7226 static void
7227f_inputsecret(typval_T *argvars, typval_T *rettv)
7228{
7229 ++cmdline_star;
7230 ++inputsecret_flag;
7231 f_input(argvars, rettv);
7232 --cmdline_star;
7233 --inputsecret_flag;
7234}
7235
7236/*
7237 * "insert()" function
7238 */
7239 static void
7240f_insert(typval_T *argvars, typval_T *rettv)
7241{
7242 long before = 0;
7243 listitem_T *item;
7244 list_T *l;
7245 int error = FALSE;
7246
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007247 if (argvars[0].v_type == VAR_BLOB)
7248 {
7249 int val, len;
7250 char_u *p;
7251
7252 len = blob_len(argvars[0].vval.v_blob);
7253 if (argvars[2].v_type != VAR_UNKNOWN)
7254 {
7255 before = (long)tv_get_number_chk(&argvars[2], &error);
7256 if (error)
7257 return; // type error; errmsg already given
7258 if (before < 0 || before > len)
7259 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007260 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007261 return;
7262 }
7263 }
7264 val = tv_get_number_chk(&argvars[1], &error);
7265 if (error)
7266 return;
7267 if (val < 0 || val > 255)
7268 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007269 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007270 return;
7271 }
7272
7273 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7274 return;
7275 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7276 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7277 *(p + before) = val;
7278 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7279
7280 copy_tv(&argvars[0], rettv);
7281 }
7282 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007283 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007284 else if ((l = argvars[0].vval.v_list) != NULL
7285 && !var_check_lock(l->lv_lock,
7286 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007287 {
7288 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007289 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007290 if (error)
7291 return; /* type error; errmsg already given */
7292
7293 if (before == l->lv_len)
7294 item = NULL;
7295 else
7296 {
7297 item = list_find(l, before);
7298 if (item == NULL)
7299 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007300 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007301 l = NULL;
7302 }
7303 }
7304 if (l != NULL)
7305 {
7306 list_insert_tv(l, &argvars[1], item);
7307 copy_tv(&argvars[0], rettv);
7308 }
7309 }
7310}
7311
7312/*
7313 * "invert(expr)" function
7314 */
7315 static void
7316f_invert(typval_T *argvars, typval_T *rettv)
7317{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007318 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319}
7320
7321/*
7322 * "isdirectory()" function
7323 */
7324 static void
7325f_isdirectory(typval_T *argvars, typval_T *rettv)
7326{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007327 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007328}
7329
7330/*
7331 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7332 * or it refers to a List or Dictionary that is locked.
7333 */
7334 static int
7335tv_islocked(typval_T *tv)
7336{
7337 return (tv->v_lock & VAR_LOCKED)
7338 || (tv->v_type == VAR_LIST
7339 && tv->vval.v_list != NULL
7340 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7341 || (tv->v_type == VAR_DICT
7342 && tv->vval.v_dict != NULL
7343 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7344}
7345
7346/*
7347 * "islocked()" function
7348 */
7349 static void
7350f_islocked(typval_T *argvars, typval_T *rettv)
7351{
7352 lval_T lv;
7353 char_u *end;
7354 dictitem_T *di;
7355
7356 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007357 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007358 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007359 if (end != NULL && lv.ll_name != NULL)
7360 {
7361 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007362 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007363 else
7364 {
7365 if (lv.ll_tv == NULL)
7366 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007367 di = find_var(lv.ll_name, NULL, TRUE);
7368 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007369 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007370 /* Consider a variable locked when:
7371 * 1. the variable itself is locked
7372 * 2. the value of the variable is locked.
7373 * 3. the List or Dict value is locked.
7374 */
7375 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7376 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 }
7378 }
7379 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007380 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007381 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007382 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383 else if (lv.ll_list != NULL)
7384 /* List item. */
7385 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7386 else
7387 /* Dictionary item. */
7388 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7389 }
7390 }
7391
7392 clear_lval(&lv);
7393}
7394
7395#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7396/*
7397 * "isnan()" function
7398 */
7399 static void
7400f_isnan(typval_T *argvars, typval_T *rettv)
7401{
7402 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7403 && isnan(argvars[0].vval.v_float);
7404}
7405#endif
7406
7407/*
7408 * "items(dict)" function
7409 */
7410 static void
7411f_items(typval_T *argvars, typval_T *rettv)
7412{
7413 dict_list(argvars, rettv, 2);
7414}
7415
7416#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7417/*
7418 * Get the job from the argument.
7419 * Returns NULL if the job is invalid.
7420 */
7421 static job_T *
7422get_job_arg(typval_T *tv)
7423{
7424 job_T *job;
7425
7426 if (tv->v_type != VAR_JOB)
7427 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007428 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007429 return NULL;
7430 }
7431 job = tv->vval.v_job;
7432
7433 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007434 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007435 return job;
7436}
7437
7438/*
7439 * "job_getchannel()" function
7440 */
7441 static void
7442f_job_getchannel(typval_T *argvars, typval_T *rettv)
7443{
7444 job_T *job = get_job_arg(&argvars[0]);
7445
7446 if (job != NULL)
7447 {
7448 rettv->v_type = VAR_CHANNEL;
7449 rettv->vval.v_channel = job->jv_channel;
7450 if (job->jv_channel != NULL)
7451 ++job->jv_channel->ch_refcount;
7452 }
7453}
7454
7455/*
7456 * "job_info()" function
7457 */
7458 static void
7459f_job_info(typval_T *argvars, typval_T *rettv)
7460{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007461 if (argvars[0].v_type != VAR_UNKNOWN)
7462 {
7463 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007465 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7466 job_info(job, rettv->vval.v_dict);
7467 }
7468 else if (rettv_list_alloc(rettv) == OK)
7469 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470}
7471
7472/*
7473 * "job_setoptions()" function
7474 */
7475 static void
7476f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7477{
7478 job_T *job = get_job_arg(&argvars[0]);
7479 jobopt_T opt;
7480
7481 if (job == NULL)
7482 return;
7483 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007484 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007485 job_set_options(job, &opt);
7486 free_job_options(&opt);
7487}
7488
7489/*
7490 * "job_start()" function
7491 */
7492 static void
7493f_job_start(typval_T *argvars, typval_T *rettv)
7494{
7495 rettv->v_type = VAR_JOB;
7496 if (check_restricted() || check_secure())
7497 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007498 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007499}
7500
7501/*
7502 * "job_status()" function
7503 */
7504 static void
7505f_job_status(typval_T *argvars, typval_T *rettv)
7506{
7507 job_T *job = get_job_arg(&argvars[0]);
7508
7509 if (job != NULL)
7510 {
7511 rettv->v_type = VAR_STRING;
7512 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7513 }
7514}
7515
7516/*
7517 * "job_stop()" function
7518 */
7519 static void
7520f_job_stop(typval_T *argvars, typval_T *rettv)
7521{
7522 job_T *job = get_job_arg(&argvars[0]);
7523
7524 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007525 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526}
7527#endif
7528
7529/*
7530 * "join()" function
7531 */
7532 static void
7533f_join(typval_T *argvars, typval_T *rettv)
7534{
7535 garray_T ga;
7536 char_u *sep;
7537
7538 if (argvars[0].v_type != VAR_LIST)
7539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007540 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007541 return;
7542 }
7543 if (argvars[0].vval.v_list == NULL)
7544 return;
7545 if (argvars[1].v_type == VAR_UNKNOWN)
7546 sep = (char_u *)" ";
7547 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007548 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007549
7550 rettv->v_type = VAR_STRING;
7551
7552 if (sep != NULL)
7553 {
7554 ga_init2(&ga, (int)sizeof(char), 80);
7555 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7556 ga_append(&ga, NUL);
7557 rettv->vval.v_string = (char_u *)ga.ga_data;
7558 }
7559 else
7560 rettv->vval.v_string = NULL;
7561}
7562
7563/*
7564 * "js_decode()" function
7565 */
7566 static void
7567f_js_decode(typval_T *argvars, typval_T *rettv)
7568{
7569 js_read_T reader;
7570
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007571 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007572 reader.js_fill = NULL;
7573 reader.js_used = 0;
7574 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007575 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007576}
7577
7578/*
7579 * "js_encode()" function
7580 */
7581 static void
7582f_js_encode(typval_T *argvars, typval_T *rettv)
7583{
7584 rettv->v_type = VAR_STRING;
7585 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7586}
7587
7588/*
7589 * "json_decode()" function
7590 */
7591 static void
7592f_json_decode(typval_T *argvars, typval_T *rettv)
7593{
7594 js_read_T reader;
7595
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007596 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007597 reader.js_fill = NULL;
7598 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007599 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600}
7601
7602/*
7603 * "json_encode()" function
7604 */
7605 static void
7606f_json_encode(typval_T *argvars, typval_T *rettv)
7607{
7608 rettv->v_type = VAR_STRING;
7609 rettv->vval.v_string = json_encode(&argvars[0], 0);
7610}
7611
7612/*
7613 * "keys()" function
7614 */
7615 static void
7616f_keys(typval_T *argvars, typval_T *rettv)
7617{
7618 dict_list(argvars, rettv, 0);
7619}
7620
7621/*
7622 * "last_buffer_nr()" function.
7623 */
7624 static void
7625f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7626{
7627 int n = 0;
7628 buf_T *buf;
7629
Bram Moolenaar29323592016-07-24 22:04:11 +02007630 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007631 if (n < buf->b_fnum)
7632 n = buf->b_fnum;
7633
7634 rettv->vval.v_number = n;
7635}
7636
7637/*
7638 * "len()" function
7639 */
7640 static void
7641f_len(typval_T *argvars, typval_T *rettv)
7642{
7643 switch (argvars[0].v_type)
7644 {
7645 case VAR_STRING:
7646 case VAR_NUMBER:
7647 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007648 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007650 case VAR_BLOB:
7651 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7652 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653 case VAR_LIST:
7654 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7655 break;
7656 case VAR_DICT:
7657 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7658 break;
7659 case VAR_UNKNOWN:
7660 case VAR_SPECIAL:
7661 case VAR_FLOAT:
7662 case VAR_FUNC:
7663 case VAR_PARTIAL:
7664 case VAR_JOB:
7665 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007666 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667 break;
7668 }
7669}
7670
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007671 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007672libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007673{
7674#ifdef FEAT_LIBCALL
7675 char_u *string_in;
7676 char_u **string_result;
7677 int nr_result;
7678#endif
7679
7680 rettv->v_type = type;
7681 if (type != VAR_NUMBER)
7682 rettv->vval.v_string = NULL;
7683
7684 if (check_restricted() || check_secure())
7685 return;
7686
7687#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007688 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007689 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7690 {
7691 string_in = NULL;
7692 if (argvars[2].v_type == VAR_STRING)
7693 string_in = argvars[2].vval.v_string;
7694 if (type == VAR_NUMBER)
7695 string_result = NULL;
7696 else
7697 string_result = &rettv->vval.v_string;
7698 if (mch_libcall(argvars[0].vval.v_string,
7699 argvars[1].vval.v_string,
7700 string_in,
7701 argvars[2].vval.v_number,
7702 string_result,
7703 &nr_result) == OK
7704 && type == VAR_NUMBER)
7705 rettv->vval.v_number = nr_result;
7706 }
7707#endif
7708}
7709
7710/*
7711 * "libcall()" function
7712 */
7713 static void
7714f_libcall(typval_T *argvars, typval_T *rettv)
7715{
7716 libcall_common(argvars, rettv, VAR_STRING);
7717}
7718
7719/*
7720 * "libcallnr()" function
7721 */
7722 static void
7723f_libcallnr(typval_T *argvars, typval_T *rettv)
7724{
7725 libcall_common(argvars, rettv, VAR_NUMBER);
7726}
7727
7728/*
7729 * "line(string)" function
7730 */
7731 static void
7732f_line(typval_T *argvars, typval_T *rettv)
7733{
7734 linenr_T lnum = 0;
7735 pos_T *fp;
7736 int fnum;
7737
7738 fp = var2fpos(&argvars[0], TRUE, &fnum);
7739 if (fp != NULL)
7740 lnum = fp->lnum;
7741 rettv->vval.v_number = lnum;
7742}
7743
7744/*
7745 * "line2byte(lnum)" function
7746 */
7747 static void
7748f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7749{
7750#ifndef FEAT_BYTEOFF
7751 rettv->vval.v_number = -1;
7752#else
7753 linenr_T lnum;
7754
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007755 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7757 rettv->vval.v_number = -1;
7758 else
7759 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7760 if (rettv->vval.v_number >= 0)
7761 ++rettv->vval.v_number;
7762#endif
7763}
7764
7765/*
7766 * "lispindent(lnum)" function
7767 */
7768 static void
7769f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7770{
7771#ifdef FEAT_LISP
7772 pos_T pos;
7773 linenr_T lnum;
7774
7775 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007776 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7778 {
7779 curwin->w_cursor.lnum = lnum;
7780 rettv->vval.v_number = get_lisp_indent();
7781 curwin->w_cursor = pos;
7782 }
7783 else
7784#endif
7785 rettv->vval.v_number = -1;
7786}
7787
7788/*
7789 * "localtime()" function
7790 */
7791 static void
7792f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7793{
7794 rettv->vval.v_number = (varnumber_T)time(NULL);
7795}
7796
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007797 static void
7798get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7799{
7800 char_u *keys;
7801 char_u *which;
7802 char_u buf[NUMBUFLEN];
7803 char_u *keys_buf = NULL;
7804 char_u *rhs;
7805 int mode;
7806 int abbr = FALSE;
7807 int get_dict = FALSE;
7808 mapblock_T *mp;
7809 int buffer_local;
7810
7811 /* return empty string for failure */
7812 rettv->v_type = VAR_STRING;
7813 rettv->vval.v_string = NULL;
7814
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007815 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007816 if (*keys == NUL)
7817 return;
7818
7819 if (argvars[1].v_type != VAR_UNKNOWN)
7820 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007821 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007822 if (argvars[2].v_type != VAR_UNKNOWN)
7823 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007824 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007826 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007827 }
7828 }
7829 else
7830 which = (char_u *)"";
7831 if (which == NULL)
7832 return;
7833
7834 mode = get_map_mode(&which, 0);
7835
7836 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7837 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7838 vim_free(keys_buf);
7839
7840 if (!get_dict)
7841 {
7842 /* Return a string. */
7843 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007844 {
7845 if (*rhs == NUL)
7846 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7847 else
7848 rettv->vval.v_string = str2special_save(rhs, FALSE);
7849 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007850
7851 }
7852 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7853 {
7854 /* Return a dictionary. */
7855 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7856 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7857 dict_T *dict = rettv->vval.v_dict;
7858
Bram Moolenaare0be1672018-07-08 16:50:37 +02007859 dict_add_string(dict, "lhs", lhs);
7860 dict_add_string(dict, "rhs", mp->m_orig_str);
7861 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7862 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7863 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007864 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7865 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007866 dict_add_number(dict, "buffer", (long)buffer_local);
7867 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7868 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007869
7870 vim_free(lhs);
7871 vim_free(mapmode);
7872 }
7873}
7874
7875#ifdef FEAT_FLOAT
7876/*
7877 * "log()" function
7878 */
7879 static void
7880f_log(typval_T *argvars, typval_T *rettv)
7881{
7882 float_T f = 0.0;
7883
7884 rettv->v_type = VAR_FLOAT;
7885 if (get_float_arg(argvars, &f) == OK)
7886 rettv->vval.v_float = log(f);
7887 else
7888 rettv->vval.v_float = 0.0;
7889}
7890
7891/*
7892 * "log10()" function
7893 */
7894 static void
7895f_log10(typval_T *argvars, typval_T *rettv)
7896{
7897 float_T f = 0.0;
7898
7899 rettv->v_type = VAR_FLOAT;
7900 if (get_float_arg(argvars, &f) == OK)
7901 rettv->vval.v_float = log10(f);
7902 else
7903 rettv->vval.v_float = 0.0;
7904}
7905#endif
7906
7907#ifdef FEAT_LUA
7908/*
7909 * "luaeval()" function
7910 */
7911 static void
7912f_luaeval(typval_T *argvars, typval_T *rettv)
7913{
7914 char_u *str;
7915 char_u buf[NUMBUFLEN];
7916
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007917 if (check_restricted() || check_secure())
7918 return;
7919
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007920 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 do_luaeval(str, argvars + 1, rettv);
7922}
7923#endif
7924
7925/*
7926 * "map()" function
7927 */
7928 static void
7929f_map(typval_T *argvars, typval_T *rettv)
7930{
7931 filter_map(argvars, rettv, TRUE);
7932}
7933
7934/*
7935 * "maparg()" function
7936 */
7937 static void
7938f_maparg(typval_T *argvars, typval_T *rettv)
7939{
7940 get_maparg(argvars, rettv, TRUE);
7941}
7942
7943/*
7944 * "mapcheck()" function
7945 */
7946 static void
7947f_mapcheck(typval_T *argvars, typval_T *rettv)
7948{
7949 get_maparg(argvars, rettv, FALSE);
7950}
7951
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007952typedef enum
7953{
7954 MATCH_END, /* matchend() */
7955 MATCH_MATCH, /* match() */
7956 MATCH_STR, /* matchstr() */
7957 MATCH_LIST, /* matchlist() */
7958 MATCH_POS /* matchstrpos() */
7959} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960
7961 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007962find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963{
7964 char_u *str = NULL;
7965 long len = 0;
7966 char_u *expr = NULL;
7967 char_u *pat;
7968 regmatch_T regmatch;
7969 char_u patbuf[NUMBUFLEN];
7970 char_u strbuf[NUMBUFLEN];
7971 char_u *save_cpo;
7972 long start = 0;
7973 long nth = 1;
7974 colnr_T startcol = 0;
7975 int match = 0;
7976 list_T *l = NULL;
7977 listitem_T *li = NULL;
7978 long idx = 0;
7979 char_u *tofree = NULL;
7980
7981 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7982 save_cpo = p_cpo;
7983 p_cpo = (char_u *)"";
7984
7985 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007986 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007988 /* type MATCH_LIST: return empty list when there are no matches.
7989 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007990 if (rettv_list_alloc(rettv) == FAIL)
7991 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007992 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 && (list_append_string(rettv->vval.v_list,
7994 (char_u *)"", 0) == FAIL
7995 || list_append_number(rettv->vval.v_list,
7996 (varnumber_T)-1) == FAIL
7997 || list_append_number(rettv->vval.v_list,
7998 (varnumber_T)-1) == FAIL
7999 || list_append_number(rettv->vval.v_list,
8000 (varnumber_T)-1) == FAIL))
8001 {
8002 list_free(rettv->vval.v_list);
8003 rettv->vval.v_list = NULL;
8004 goto theend;
8005 }
8006 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008007 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008 {
8009 rettv->v_type = VAR_STRING;
8010 rettv->vval.v_string = NULL;
8011 }
8012
8013 if (argvars[0].v_type == VAR_LIST)
8014 {
8015 if ((l = argvars[0].vval.v_list) == NULL)
8016 goto theend;
8017 li = l->lv_first;
8018 }
8019 else
8020 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008021 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008022 len = (long)STRLEN(str);
8023 }
8024
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008025 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008026 if (pat == NULL)
8027 goto theend;
8028
8029 if (argvars[2].v_type != VAR_UNKNOWN)
8030 {
8031 int error = FALSE;
8032
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008033 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008034 if (error)
8035 goto theend;
8036 if (l != NULL)
8037 {
8038 li = list_find(l, start);
8039 if (li == NULL)
8040 goto theend;
8041 idx = l->lv_idx; /* use the cached index */
8042 }
8043 else
8044 {
8045 if (start < 0)
8046 start = 0;
8047 if (start > len)
8048 goto theend;
8049 /* When "count" argument is there ignore matches before "start",
8050 * otherwise skip part of the string. Differs when pattern is "^"
8051 * or "\<". */
8052 if (argvars[3].v_type != VAR_UNKNOWN)
8053 startcol = start;
8054 else
8055 {
8056 str += start;
8057 len -= start;
8058 }
8059 }
8060
8061 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008062 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063 if (error)
8064 goto theend;
8065 }
8066
8067 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8068 if (regmatch.regprog != NULL)
8069 {
8070 regmatch.rm_ic = p_ic;
8071
8072 for (;;)
8073 {
8074 if (l != NULL)
8075 {
8076 if (li == NULL)
8077 {
8078 match = FALSE;
8079 break;
8080 }
8081 vim_free(tofree);
8082 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8083 if (str == NULL)
8084 break;
8085 }
8086
8087 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8088
8089 if (match && --nth <= 0)
8090 break;
8091 if (l == NULL && !match)
8092 break;
8093
8094 /* Advance to just after the match. */
8095 if (l != NULL)
8096 {
8097 li = li->li_next;
8098 ++idx;
8099 }
8100 else
8101 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102 startcol = (colnr_T)(regmatch.startp[0]
8103 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008104 if (startcol > (colnr_T)len
8105 || str + startcol <= regmatch.startp[0])
8106 {
8107 match = FALSE;
8108 break;
8109 }
8110 }
8111 }
8112
8113 if (match)
8114 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008115 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116 {
8117 listitem_T *li1 = rettv->vval.v_list->lv_first;
8118 listitem_T *li2 = li1->li_next;
8119 listitem_T *li3 = li2->li_next;
8120 listitem_T *li4 = li3->li_next;
8121
8122 vim_free(li1->li_tv.vval.v_string);
8123 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8124 (int)(regmatch.endp[0] - regmatch.startp[0]));
8125 li3->li_tv.vval.v_number =
8126 (varnumber_T)(regmatch.startp[0] - expr);
8127 li4->li_tv.vval.v_number =
8128 (varnumber_T)(regmatch.endp[0] - expr);
8129 if (l != NULL)
8130 li2->li_tv.vval.v_number = (varnumber_T)idx;
8131 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008132 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133 {
8134 int i;
8135
8136 /* return list with matched string and submatches */
8137 for (i = 0; i < NSUBEXP; ++i)
8138 {
8139 if (regmatch.endp[i] == NULL)
8140 {
8141 if (list_append_string(rettv->vval.v_list,
8142 (char_u *)"", 0) == FAIL)
8143 break;
8144 }
8145 else if (list_append_string(rettv->vval.v_list,
8146 regmatch.startp[i],
8147 (int)(regmatch.endp[i] - regmatch.startp[i]))
8148 == FAIL)
8149 break;
8150 }
8151 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008152 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153 {
8154 /* return matched string */
8155 if (l != NULL)
8156 copy_tv(&li->li_tv, rettv);
8157 else
8158 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8159 (int)(regmatch.endp[0] - regmatch.startp[0]));
8160 }
8161 else if (l != NULL)
8162 rettv->vval.v_number = idx;
8163 else
8164 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008165 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008166 rettv->vval.v_number =
8167 (varnumber_T)(regmatch.startp[0] - str);
8168 else
8169 rettv->vval.v_number =
8170 (varnumber_T)(regmatch.endp[0] - str);
8171 rettv->vval.v_number += (varnumber_T)(str - expr);
8172 }
8173 }
8174 vim_regfree(regmatch.regprog);
8175 }
8176
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008177theend:
8178 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 /* matchstrpos() without a list: drop the second item. */
8180 listitem_remove(rettv->vval.v_list,
8181 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 vim_free(tofree);
8183 p_cpo = save_cpo;
8184}
8185
8186/*
8187 * "match()" function
8188 */
8189 static void
8190f_match(typval_T *argvars, typval_T *rettv)
8191{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008192 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008193}
8194
Bram Moolenaar95e51472018-07-28 16:55:56 +02008195#ifdef FEAT_SEARCH_EXTRA
8196 static int
8197matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8198{
8199 dictitem_T *di;
8200
8201 if (tv->v_type != VAR_DICT)
8202 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008203 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008204 return FAIL;
8205 }
8206
8207 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008208 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008209 (char_u *)"conceal", FALSE);
8210
8211 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8212 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008213 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008214 if (*win == NULL)
8215 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008216 emsg(_("E957: Invalid window number"));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008217 return FAIL;
8218 }
8219 }
8220
8221 return OK;
8222}
8223#endif
8224
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225/*
8226 * "matchadd()" function
8227 */
8228 static void
8229f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8230{
8231#ifdef FEAT_SEARCH_EXTRA
8232 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008233 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8234 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008235 int prio = 10; /* default priority */
8236 int id = -1;
8237 int error = FALSE;
8238 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008239 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008240
8241 rettv->vval.v_number = -1;
8242
8243 if (grp == NULL || pat == NULL)
8244 return;
8245 if (argvars[2].v_type != VAR_UNKNOWN)
8246 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008247 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008248 if (argvars[3].v_type != VAR_UNKNOWN)
8249 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008250 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008251 if (argvars[4].v_type != VAR_UNKNOWN
8252 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8253 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008254 }
8255 }
8256 if (error == TRUE)
8257 return;
8258 if (id >= 1 && id <= 3)
8259 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008260 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008261 return;
8262 }
8263
Bram Moolenaar95e51472018-07-28 16:55:56 +02008264 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 conceal_char);
8266#endif
8267}
8268
8269/*
8270 * "matchaddpos()" function
8271 */
8272 static void
8273f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8274{
8275#ifdef FEAT_SEARCH_EXTRA
8276 char_u buf[NUMBUFLEN];
8277 char_u *group;
8278 int prio = 10;
8279 int id = -1;
8280 int error = FALSE;
8281 list_T *l;
8282 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008283 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008284
8285 rettv->vval.v_number = -1;
8286
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008287 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008288 if (group == NULL)
8289 return;
8290
8291 if (argvars[1].v_type != VAR_LIST)
8292 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008293 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008294 return;
8295 }
8296 l = argvars[1].vval.v_list;
8297 if (l == NULL)
8298 return;
8299
8300 if (argvars[2].v_type != VAR_UNKNOWN)
8301 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008302 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008303 if (argvars[3].v_type != VAR_UNKNOWN)
8304 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008305 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008306
8307 if (argvars[4].v_type != VAR_UNKNOWN
8308 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8309 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008310 }
8311 }
8312 if (error == TRUE)
8313 return;
8314
8315 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8316 if (id == 1 || id == 2)
8317 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008318 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319 return;
8320 }
8321
Bram Moolenaar95e51472018-07-28 16:55:56 +02008322 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008323 conceal_char);
8324#endif
8325}
8326
8327/*
8328 * "matcharg()" function
8329 */
8330 static void
8331f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8332{
8333 if (rettv_list_alloc(rettv) == OK)
8334 {
8335#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008336 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008337 matchitem_T *m;
8338
8339 if (id >= 1 && id <= 3)
8340 {
8341 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8342 {
8343 list_append_string(rettv->vval.v_list,
8344 syn_id2name(m->hlg_id), -1);
8345 list_append_string(rettv->vval.v_list, m->pattern, -1);
8346 }
8347 else
8348 {
8349 list_append_string(rettv->vval.v_list, NULL, -1);
8350 list_append_string(rettv->vval.v_list, NULL, -1);
8351 }
8352 }
8353#endif
8354 }
8355}
8356
8357/*
8358 * "matchdelete()" function
8359 */
8360 static void
8361f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8362{
8363#ifdef FEAT_SEARCH_EXTRA
8364 rettv->vval.v_number = match_delete(curwin,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008365 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008366#endif
8367}
8368
8369/*
8370 * "matchend()" function
8371 */
8372 static void
8373f_matchend(typval_T *argvars, typval_T *rettv)
8374{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008375 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376}
8377
8378/*
8379 * "matchlist()" function
8380 */
8381 static void
8382f_matchlist(typval_T *argvars, typval_T *rettv)
8383{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008384 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008385}
8386
8387/*
8388 * "matchstr()" function
8389 */
8390 static void
8391f_matchstr(typval_T *argvars, typval_T *rettv)
8392{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008393 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394}
8395
8396/*
8397 * "matchstrpos()" function
8398 */
8399 static void
8400f_matchstrpos(typval_T *argvars, typval_T *rettv)
8401{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008402 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008403}
8404
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008405 static void
8406max_min(typval_T *argvars, typval_T *rettv, int domax)
8407{
8408 varnumber_T n = 0;
8409 varnumber_T i;
8410 int error = FALSE;
8411
8412 if (argvars[0].v_type == VAR_LIST)
8413 {
8414 list_T *l;
8415 listitem_T *li;
8416
8417 l = argvars[0].vval.v_list;
8418 if (l != NULL)
8419 {
8420 li = l->lv_first;
8421 if (li != NULL)
8422 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008423 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008424 for (;;)
8425 {
8426 li = li->li_next;
8427 if (li == NULL)
8428 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008429 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008430 if (domax ? i > n : i < n)
8431 n = i;
8432 }
8433 }
8434 }
8435 }
8436 else if (argvars[0].v_type == VAR_DICT)
8437 {
8438 dict_T *d;
8439 int first = TRUE;
8440 hashitem_T *hi;
8441 int todo;
8442
8443 d = argvars[0].vval.v_dict;
8444 if (d != NULL)
8445 {
8446 todo = (int)d->dv_hashtab.ht_used;
8447 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8448 {
8449 if (!HASHITEM_EMPTY(hi))
8450 {
8451 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008452 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008453 if (first)
8454 {
8455 n = i;
8456 first = FALSE;
8457 }
8458 else if (domax ? i > n : i < n)
8459 n = i;
8460 }
8461 }
8462 }
8463 }
8464 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008465 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008466 rettv->vval.v_number = error ? 0 : n;
8467}
8468
8469/*
8470 * "max()" function
8471 */
8472 static void
8473f_max(typval_T *argvars, typval_T *rettv)
8474{
8475 max_min(argvars, rettv, TRUE);
8476}
8477
8478/*
8479 * "min()" function
8480 */
8481 static void
8482f_min(typval_T *argvars, typval_T *rettv)
8483{
8484 max_min(argvars, rettv, FALSE);
8485}
8486
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008487/*
8488 * Create the directory in which "dir" is located, and higher levels when
8489 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008490 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008491 */
8492 static int
8493mkdir_recurse(char_u *dir, int prot)
8494{
8495 char_u *p;
8496 char_u *updir;
8497 int r = FAIL;
8498
8499 /* Get end of directory name in "dir".
8500 * We're done when it's "/" or "c:/". */
8501 p = gettail_sep(dir);
8502 if (p <= get_past_head(dir))
8503 return OK;
8504
8505 /* If the directory exists we're done. Otherwise: create it.*/
8506 updir = vim_strnsave(dir, (int)(p - dir));
8507 if (updir == NULL)
8508 return FAIL;
8509 if (mch_isdir(updir))
8510 r = OK;
8511 else if (mkdir_recurse(updir, prot) == OK)
8512 r = vim_mkdir_emsg(updir, prot);
8513 vim_free(updir);
8514 return r;
8515}
8516
8517#ifdef vim_mkdir
8518/*
8519 * "mkdir()" function
8520 */
8521 static void
8522f_mkdir(typval_T *argvars, typval_T *rettv)
8523{
8524 char_u *dir;
8525 char_u buf[NUMBUFLEN];
8526 int prot = 0755;
8527
8528 rettv->vval.v_number = FAIL;
8529 if (check_restricted() || check_secure())
8530 return;
8531
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008532 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008533 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008534 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008535
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008536 if (*gettail(dir) == NUL)
8537 /* remove trailing slashes */
8538 *gettail_sep(dir) = NUL;
8539
8540 if (argvars[1].v_type != VAR_UNKNOWN)
8541 {
8542 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008543 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008544 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008545 if (prot == -1)
8546 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008548 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008549 {
8550 if (mch_isdir(dir))
8551 {
8552 /* With the "p" flag it's OK if the dir already exists. */
8553 rettv->vval.v_number = OK;
8554 return;
8555 }
8556 mkdir_recurse(dir, prot);
8557 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008559 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008560}
8561#endif
8562
8563/*
8564 * "mode()" function
8565 */
8566 static void
8567f_mode(typval_T *argvars, typval_T *rettv)
8568{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008569 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008570
Bram Moolenaar612cc382018-07-29 15:34:26 +02008571 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008572
8573 if (time_for_testing == 93784)
8574 {
8575 /* Testing the two-character code. */
8576 buf[0] = 'x';
8577 buf[1] = '!';
8578 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008579#ifdef FEAT_TERMINAL
8580 else if (term_use_loop())
8581 buf[0] = 't';
8582#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008583 else if (VIsual_active)
8584 {
8585 if (VIsual_select)
8586 buf[0] = VIsual_mode + 's' - 'v';
8587 else
8588 buf[0] = VIsual_mode;
8589 }
8590 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8591 || State == CONFIRM)
8592 {
8593 buf[0] = 'r';
8594 if (State == ASKMORE)
8595 buf[1] = 'm';
8596 else if (State == CONFIRM)
8597 buf[1] = '?';
8598 }
8599 else if (State == EXTERNCMD)
8600 buf[0] = '!';
8601 else if (State & INSERT)
8602 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008603 if (State & VREPLACE_FLAG)
8604 {
8605 buf[0] = 'R';
8606 buf[1] = 'v';
8607 }
8608 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008609 {
8610 if (State & REPLACE_FLAG)
8611 buf[0] = 'R';
8612 else
8613 buf[0] = 'i';
8614#ifdef FEAT_INS_EXPAND
8615 if (ins_compl_active())
8616 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008617 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008618 buf[1] = 'x';
8619#endif
8620 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008621 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008622 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008623 {
8624 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008625 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008626 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008627 else if (exmode_active == EXMODE_NORMAL)
8628 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008629 }
8630 else
8631 {
8632 buf[0] = 'n';
8633 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008634 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008635 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008636 // to be able to detect force-linewise/blockwise/characterwise operations
8637 buf[2] = motion_force;
8638 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008639 else if (restart_edit == 'I' || restart_edit == 'R'
8640 || restart_edit == 'V')
8641 {
8642 buf[1] = 'i';
8643 buf[2] = restart_edit;
8644 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008645 }
8646
8647 /* Clear out the minor mode when the argument is not a non-zero number or
8648 * non-empty string. */
8649 if (!non_zero_arg(&argvars[0]))
8650 buf[1] = NUL;
8651
8652 rettv->vval.v_string = vim_strsave(buf);
8653 rettv->v_type = VAR_STRING;
8654}
8655
8656#if defined(FEAT_MZSCHEME) || defined(PROTO)
8657/*
8658 * "mzeval()" function
8659 */
8660 static void
8661f_mzeval(typval_T *argvars, typval_T *rettv)
8662{
8663 char_u *str;
8664 char_u buf[NUMBUFLEN];
8665
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008666 if (check_restricted() || check_secure())
8667 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008668 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008669 do_mzeval(str, rettv);
8670}
8671
8672 void
8673mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8674{
8675 typval_T argvars[3];
8676
8677 argvars[0].v_type = VAR_STRING;
8678 argvars[0].vval.v_string = name;
8679 copy_tv(args, &argvars[1]);
8680 argvars[2].v_type = VAR_UNKNOWN;
8681 f_call(argvars, rettv);
8682 clear_tv(&argvars[1]);
8683}
8684#endif
8685
8686/*
8687 * "nextnonblank()" function
8688 */
8689 static void
8690f_nextnonblank(typval_T *argvars, typval_T *rettv)
8691{
8692 linenr_T lnum;
8693
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008694 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008695 {
8696 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8697 {
8698 lnum = 0;
8699 break;
8700 }
8701 if (*skipwhite(ml_get(lnum)) != NUL)
8702 break;
8703 }
8704 rettv->vval.v_number = lnum;
8705}
8706
8707/*
8708 * "nr2char()" function
8709 */
8710 static void
8711f_nr2char(typval_T *argvars, typval_T *rettv)
8712{
8713 char_u buf[NUMBUFLEN];
8714
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008715 if (has_mbyte)
8716 {
8717 int utf8 = 0;
8718
8719 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008720 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008722 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008723 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008724 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725 }
8726 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008727 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008728 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008729 buf[1] = NUL;
8730 }
8731 rettv->v_type = VAR_STRING;
8732 rettv->vval.v_string = vim_strsave(buf);
8733}
8734
8735/*
8736 * "or(expr, expr)" function
8737 */
8738 static void
8739f_or(typval_T *argvars, typval_T *rettv)
8740{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008741 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8742 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008743}
8744
8745/*
8746 * "pathshorten()" function
8747 */
8748 static void
8749f_pathshorten(typval_T *argvars, typval_T *rettv)
8750{
8751 char_u *p;
8752
8753 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008754 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008755 if (p == NULL)
8756 rettv->vval.v_string = NULL;
8757 else
8758 {
8759 p = vim_strsave(p);
8760 rettv->vval.v_string = p;
8761 if (p != NULL)
8762 shorten_dir(p);
8763 }
8764}
8765
8766#ifdef FEAT_PERL
8767/*
8768 * "perleval()" function
8769 */
8770 static void
8771f_perleval(typval_T *argvars, typval_T *rettv)
8772{
8773 char_u *str;
8774 char_u buf[NUMBUFLEN];
8775
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008776 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008777 do_perleval(str, rettv);
8778}
8779#endif
8780
8781#ifdef FEAT_FLOAT
8782/*
8783 * "pow()" function
8784 */
8785 static void
8786f_pow(typval_T *argvars, typval_T *rettv)
8787{
8788 float_T fx = 0.0, fy = 0.0;
8789
8790 rettv->v_type = VAR_FLOAT;
8791 if (get_float_arg(argvars, &fx) == OK
8792 && get_float_arg(&argvars[1], &fy) == OK)
8793 rettv->vval.v_float = pow(fx, fy);
8794 else
8795 rettv->vval.v_float = 0.0;
8796}
8797#endif
8798
8799/*
8800 * "prevnonblank()" function
8801 */
8802 static void
8803f_prevnonblank(typval_T *argvars, typval_T *rettv)
8804{
8805 linenr_T lnum;
8806
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008807 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008808 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8809 lnum = 0;
8810 else
8811 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8812 --lnum;
8813 rettv->vval.v_number = lnum;
8814}
8815
8816/* This dummy va_list is here because:
8817 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8818 * - locally in the function results in a "used before set" warning
8819 * - using va_start() to initialize it gives "function with fixed args" error */
8820static va_list ap;
8821
8822/*
8823 * "printf()" function
8824 */
8825 static void
8826f_printf(typval_T *argvars, typval_T *rettv)
8827{
8828 char_u buf[NUMBUFLEN];
8829 int len;
8830 char_u *s;
8831 int saved_did_emsg = did_emsg;
8832 char *fmt;
8833
8834 rettv->v_type = VAR_STRING;
8835 rettv->vval.v_string = NULL;
8836
8837 /* Get the required length, allocate the buffer and do it for real. */
8838 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008839 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008840 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008841 if (!did_emsg)
8842 {
8843 s = alloc(len + 1);
8844 if (s != NULL)
8845 {
8846 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008847 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8848 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008849 }
8850 }
8851 did_emsg |= saved_did_emsg;
8852}
8853
Bram Moolenaarf2732452018-06-03 14:47:35 +02008854#ifdef FEAT_JOB_CHANNEL
8855/*
8856 * "prompt_setcallback({buffer}, {callback})" function
8857 */
8858 static void
8859f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8860{
8861 buf_T *buf;
8862 char_u *callback;
8863 partial_T *partial;
8864
8865 if (check_secure())
8866 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008867 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008868 if (buf == NULL)
8869 return;
8870
8871 callback = get_callback(&argvars[1], &partial);
8872 if (callback == NULL)
8873 return;
8874
8875 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8876 if (partial == NULL)
8877 buf->b_prompt_callback = vim_strsave(callback);
8878 else
8879 /* pointer into the partial */
8880 buf->b_prompt_callback = callback;
8881 buf->b_prompt_partial = partial;
8882}
8883
8884/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008885 * "prompt_setinterrupt({buffer}, {callback})" function
8886 */
8887 static void
8888f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8889{
8890 buf_T *buf;
8891 char_u *callback;
8892 partial_T *partial;
8893
8894 if (check_secure())
8895 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008896 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008897 if (buf == NULL)
8898 return;
8899
8900 callback = get_callback(&argvars[1], &partial);
8901 if (callback == NULL)
8902 return;
8903
8904 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8905 if (partial == NULL)
8906 buf->b_prompt_interrupt = vim_strsave(callback);
8907 else
8908 /* pointer into the partial */
8909 buf->b_prompt_interrupt = callback;
8910 buf->b_prompt_int_partial = partial;
8911}
8912
8913/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008914 * "prompt_setprompt({buffer}, {text})" function
8915 */
8916 static void
8917f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8918{
8919 buf_T *buf;
8920 char_u *text;
8921
8922 if (check_secure())
8923 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008924 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008925 if (buf == NULL)
8926 return;
8927
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008928 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008929 vim_free(buf->b_prompt_text);
8930 buf->b_prompt_text = vim_strsave(text);
8931}
8932#endif
8933
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008934/*
8935 * "pumvisible()" function
8936 */
8937 static void
8938f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8939{
8940#ifdef FEAT_INS_EXPAND
8941 if (pum_visible())
8942 rettv->vval.v_number = 1;
8943#endif
8944}
8945
8946#ifdef FEAT_PYTHON3
8947/*
8948 * "py3eval()" function
8949 */
8950 static void
8951f_py3eval(typval_T *argvars, typval_T *rettv)
8952{
8953 char_u *str;
8954 char_u buf[NUMBUFLEN];
8955
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008956 if (check_restricted() || check_secure())
8957 return;
8958
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008959 if (p_pyx == 0)
8960 p_pyx = 3;
8961
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008962 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008963 do_py3eval(str, rettv);
8964}
8965#endif
8966
8967#ifdef FEAT_PYTHON
8968/*
8969 * "pyeval()" function
8970 */
8971 static void
8972f_pyeval(typval_T *argvars, typval_T *rettv)
8973{
8974 char_u *str;
8975 char_u buf[NUMBUFLEN];
8976
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008977 if (check_restricted() || check_secure())
8978 return;
8979
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008980 if (p_pyx == 0)
8981 p_pyx = 2;
8982
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008983 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008984 do_pyeval(str, rettv);
8985}
8986#endif
8987
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008988#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8989/*
8990 * "pyxeval()" function
8991 */
8992 static void
8993f_pyxeval(typval_T *argvars, typval_T *rettv)
8994{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008995 if (check_restricted() || check_secure())
8996 return;
8997
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008998# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8999 init_pyxversion();
9000 if (p_pyx == 2)
9001 f_pyeval(argvars, rettv);
9002 else
9003 f_py3eval(argvars, rettv);
9004# elif defined(FEAT_PYTHON)
9005 f_pyeval(argvars, rettv);
9006# elif defined(FEAT_PYTHON3)
9007 f_py3eval(argvars, rettv);
9008# endif
9009}
9010#endif
9011
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009012/*
9013 * "range()" function
9014 */
9015 static void
9016f_range(typval_T *argvars, typval_T *rettv)
9017{
9018 varnumber_T start;
9019 varnumber_T end;
9020 varnumber_T stride = 1;
9021 varnumber_T i;
9022 int error = FALSE;
9023
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009024 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009025 if (argvars[1].v_type == VAR_UNKNOWN)
9026 {
9027 end = start - 1;
9028 start = 0;
9029 }
9030 else
9031 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009032 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009033 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009034 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009035 }
9036
9037 if (error)
9038 return; /* type error; errmsg already given */
9039 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009040 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009041 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009042 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009043 else
9044 {
9045 if (rettv_list_alloc(rettv) == OK)
9046 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9047 if (list_append_number(rettv->vval.v_list,
9048 (varnumber_T)i) == FAIL)
9049 break;
9050 }
9051}
9052
9053/*
9054 * "readfile()" function
9055 */
9056 static void
9057f_readfile(typval_T *argvars, typval_T *rettv)
9058{
9059 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009060 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009061 int failed = FALSE;
9062 char_u *fname;
9063 FILE *fd;
9064 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9065 int io_size = sizeof(buf);
9066 int readlen; /* size of last fread() */
9067 char_u *prev = NULL; /* previously read bytes, if any */
9068 long prevlen = 0; /* length of data in prev */
9069 long prevsize = 0; /* size of prev buffer */
9070 long maxline = MAXLNUM;
9071 long cnt = 0;
9072 char_u *p; /* position in buf */
9073 char_u *start; /* start of current line */
9074
9075 if (argvars[1].v_type != VAR_UNKNOWN)
9076 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009077 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009078 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009079 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9080 blob = TRUE;
9081
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009082 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009083 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009084 }
9085
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009086 if (blob)
9087 {
9088 if (rettv_blob_alloc(rettv) == FAIL)
9089 return;
9090 }
9091 else
9092 {
9093 if (rettv_list_alloc(rettv) == FAIL)
9094 return;
9095 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009096
9097 /* Always open the file in binary mode, library functions have a mind of
9098 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009099 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009100 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9101 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009102 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009103 return;
9104 }
9105
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009106 if (blob)
9107 {
9108 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9109 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009110 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009111 blob_free(rettv->vval.v_blob);
9112 }
9113 fclose(fd);
9114 return;
9115 }
9116
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009117 while (cnt < maxline || maxline < 0)
9118 {
9119 readlen = (int)fread(buf, 1, io_size, fd);
9120
9121 /* This for loop processes what was read, but is also entered at end
9122 * of file so that either:
9123 * - an incomplete line gets written
9124 * - a "binary" file gets an empty line at the end if it ends in a
9125 * newline. */
9126 for (p = buf, start = buf;
9127 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9128 ++p)
9129 {
9130 if (*p == '\n' || readlen <= 0)
9131 {
9132 listitem_T *li;
9133 char_u *s = NULL;
9134 long_u len = p - start;
9135
9136 /* Finished a line. Remove CRs before NL. */
9137 if (readlen > 0 && !binary)
9138 {
9139 while (len > 0 && start[len - 1] == '\r')
9140 --len;
9141 /* removal may cross back to the "prev" string */
9142 if (len == 0)
9143 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9144 --prevlen;
9145 }
9146 if (prevlen == 0)
9147 s = vim_strnsave(start, (int)len);
9148 else
9149 {
9150 /* Change "prev" buffer to be the right size. This way
9151 * the bytes are only copied once, and very long lines are
9152 * allocated only once. */
9153 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9154 {
9155 mch_memmove(s + prevlen, start, len);
9156 s[prevlen + len] = NUL;
9157 prev = NULL; /* the list will own the string */
9158 prevlen = prevsize = 0;
9159 }
9160 }
9161 if (s == NULL)
9162 {
9163 do_outofmem_msg((long_u) prevlen + len + 1);
9164 failed = TRUE;
9165 break;
9166 }
9167
9168 if ((li = listitem_alloc()) == NULL)
9169 {
9170 vim_free(s);
9171 failed = TRUE;
9172 break;
9173 }
9174 li->li_tv.v_type = VAR_STRING;
9175 li->li_tv.v_lock = 0;
9176 li->li_tv.vval.v_string = s;
9177 list_append(rettv->vval.v_list, li);
9178
9179 start = p + 1; /* step over newline */
9180 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9181 break;
9182 }
9183 else if (*p == NUL)
9184 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009185 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9186 * when finding the BF and check the previous two bytes. */
9187 else if (*p == 0xbf && enc_utf8 && !binary)
9188 {
9189 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9190 * + 1, these may be in the "prev" string. */
9191 char_u back1 = p >= buf + 1 ? p[-1]
9192 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9193 char_u back2 = p >= buf + 2 ? p[-2]
9194 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9195 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9196
9197 if (back2 == 0xef && back1 == 0xbb)
9198 {
9199 char_u *dest = p - 2;
9200
9201 /* Usually a BOM is at the beginning of a file, and so at
9202 * the beginning of a line; then we can just step over it.
9203 */
9204 if (start == dest)
9205 start = p + 1;
9206 else
9207 {
9208 /* have to shuffle buf to close gap */
9209 int adjust_prevlen = 0;
9210
9211 if (dest < buf)
9212 {
9213 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9214 dest = buf;
9215 }
9216 if (readlen > p - buf + 1)
9217 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9218 readlen -= 3 - adjust_prevlen;
9219 prevlen -= adjust_prevlen;
9220 p = dest - 1;
9221 }
9222 }
9223 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009224 } /* for */
9225
9226 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9227 break;
9228 if (start < p)
9229 {
9230 /* There's part of a line in buf, store it in "prev". */
9231 if (p - start + prevlen >= prevsize)
9232 {
9233 /* need bigger "prev" buffer */
9234 char_u *newprev;
9235
9236 /* A common use case is ordinary text files and "prev" gets a
9237 * fragment of a line, so the first allocation is made
9238 * small, to avoid repeatedly 'allocing' large and
9239 * 'reallocing' small. */
9240 if (prevsize == 0)
9241 prevsize = (long)(p - start);
9242 else
9243 {
9244 long grow50pc = (prevsize * 3) / 2;
9245 long growmin = (long)((p - start) * 2 + prevlen);
9246 prevsize = grow50pc > growmin ? grow50pc : growmin;
9247 }
9248 newprev = prev == NULL ? alloc(prevsize)
9249 : vim_realloc(prev, prevsize);
9250 if (newprev == NULL)
9251 {
9252 do_outofmem_msg((long_u)prevsize);
9253 failed = TRUE;
9254 break;
9255 }
9256 prev = newprev;
9257 }
9258 /* Add the line part to end of "prev". */
9259 mch_memmove(prev + prevlen, start, p - start);
9260 prevlen += (long)(p - start);
9261 }
9262 } /* while */
9263
9264 /*
9265 * For a negative line count use only the lines at the end of the file,
9266 * free the rest.
9267 */
9268 if (!failed && maxline < 0)
9269 while (cnt > -maxline)
9270 {
9271 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9272 --cnt;
9273 }
9274
9275 if (failed)
9276 {
9277 list_free(rettv->vval.v_list);
9278 /* readfile doc says an empty list is returned on error */
9279 rettv->vval.v_list = list_alloc();
9280 }
9281
9282 vim_free(prev);
9283 fclose(fd);
9284}
9285
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009286 static void
9287return_register(int regname, typval_T *rettv)
9288{
9289 char_u buf[2] = {0, 0};
9290
9291 buf[0] = (char_u)regname;
9292 rettv->v_type = VAR_STRING;
9293 rettv->vval.v_string = vim_strsave(buf);
9294}
9295
9296/*
9297 * "reg_executing()" function
9298 */
9299 static void
9300f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9301{
9302 return_register(reg_executing, rettv);
9303}
9304
9305/*
9306 * "reg_recording()" function
9307 */
9308 static void
9309f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9310{
9311 return_register(reg_recording, rettv);
9312}
9313
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009314#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009315/*
9316 * Convert a List to proftime_T.
9317 * Return FAIL when there is something wrong.
9318 */
9319 static int
9320list2proftime(typval_T *arg, proftime_T *tm)
9321{
9322 long n1, n2;
9323 int error = FALSE;
9324
9325 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9326 || arg->vval.v_list->lv_len != 2)
9327 return FAIL;
9328 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9329 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009330# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009331 tm->HighPart = n1;
9332 tm->LowPart = n2;
9333# else
9334 tm->tv_sec = n1;
9335 tm->tv_usec = n2;
9336# endif
9337 return error ? FAIL : OK;
9338}
9339#endif /* FEAT_RELTIME */
9340
9341/*
9342 * "reltime()" function
9343 */
9344 static void
9345f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9346{
9347#ifdef FEAT_RELTIME
9348 proftime_T res;
9349 proftime_T start;
9350
9351 if (argvars[0].v_type == VAR_UNKNOWN)
9352 {
9353 /* No arguments: get current time. */
9354 profile_start(&res);
9355 }
9356 else if (argvars[1].v_type == VAR_UNKNOWN)
9357 {
9358 if (list2proftime(&argvars[0], &res) == FAIL)
9359 return;
9360 profile_end(&res);
9361 }
9362 else
9363 {
9364 /* Two arguments: compute the difference. */
9365 if (list2proftime(&argvars[0], &start) == FAIL
9366 || list2proftime(&argvars[1], &res) == FAIL)
9367 return;
9368 profile_sub(&res, &start);
9369 }
9370
9371 if (rettv_list_alloc(rettv) == OK)
9372 {
9373 long n1, n2;
9374
Bram Moolenaar4f974752019-02-17 17:44:42 +01009375# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009376 n1 = res.HighPart;
9377 n2 = res.LowPart;
9378# else
9379 n1 = res.tv_sec;
9380 n2 = res.tv_usec;
9381# endif
9382 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9383 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9384 }
9385#endif
9386}
9387
9388#ifdef FEAT_FLOAT
9389/*
9390 * "reltimefloat()" function
9391 */
9392 static void
9393f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9394{
9395# ifdef FEAT_RELTIME
9396 proftime_T tm;
9397# endif
9398
9399 rettv->v_type = VAR_FLOAT;
9400 rettv->vval.v_float = 0;
9401# ifdef FEAT_RELTIME
9402 if (list2proftime(&argvars[0], &tm) == OK)
9403 rettv->vval.v_float = profile_float(&tm);
9404# endif
9405}
9406#endif
9407
9408/*
9409 * "reltimestr()" function
9410 */
9411 static void
9412f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9413{
9414#ifdef FEAT_RELTIME
9415 proftime_T tm;
9416#endif
9417
9418 rettv->v_type = VAR_STRING;
9419 rettv->vval.v_string = NULL;
9420#ifdef FEAT_RELTIME
9421 if (list2proftime(&argvars[0], &tm) == OK)
9422 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9423#endif
9424}
9425
9426#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009427 static void
9428make_connection(void)
9429{
9430 if (X_DISPLAY == NULL
9431# ifdef FEAT_GUI
9432 && !gui.in_use
9433# endif
9434 )
9435 {
9436 x_force_connect = TRUE;
9437 setup_term_clip();
9438 x_force_connect = FALSE;
9439 }
9440}
9441
9442 static int
9443check_connection(void)
9444{
9445 make_connection();
9446 if (X_DISPLAY == NULL)
9447 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009448 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009449 return FAIL;
9450 }
9451 return OK;
9452}
9453#endif
9454
9455#ifdef FEAT_CLIENTSERVER
9456 static void
9457remote_common(typval_T *argvars, typval_T *rettv, int expr)
9458{
9459 char_u *server_name;
9460 char_u *keys;
9461 char_u *r = NULL;
9462 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009463 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009464# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009465 HWND w;
9466# else
9467 Window w;
9468# endif
9469
9470 if (check_restricted() || check_secure())
9471 return;
9472
9473# ifdef FEAT_X11
9474 if (check_connection() == FAIL)
9475 return;
9476# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009477 if (argvars[2].v_type != VAR_UNKNOWN
9478 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009479 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009480
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009481 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009482 if (server_name == NULL)
9483 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009484 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009485# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009486 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009488 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9489 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009490# endif
9491 {
9492 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009493 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009494 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009495 vim_free(r);
9496 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009497 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009498 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009499 return;
9500 }
9501
9502 rettv->vval.v_string = r;
9503
9504 if (argvars[2].v_type != VAR_UNKNOWN)
9505 {
9506 dictitem_T v;
9507 char_u str[30];
9508 char_u *idvar;
9509
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009510 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009511 if (idvar != NULL && *idvar != NUL)
9512 {
9513 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9514 v.di_tv.v_type = VAR_STRING;
9515 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009516 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009517 vim_free(v.di_tv.vval.v_string);
9518 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009519 }
9520}
9521#endif
9522
9523/*
9524 * "remote_expr()" function
9525 */
9526 static void
9527f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9528{
9529 rettv->v_type = VAR_STRING;
9530 rettv->vval.v_string = NULL;
9531#ifdef FEAT_CLIENTSERVER
9532 remote_common(argvars, rettv, TRUE);
9533#endif
9534}
9535
9536/*
9537 * "remote_foreground()" function
9538 */
9539 static void
9540f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9541{
9542#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009543# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009544 /* On Win32 it's done in this application. */
9545 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009546 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009547
9548 if (server_name != NULL)
9549 serverForeground(server_name);
9550 }
9551# else
9552 /* Send a foreground() expression to the server. */
9553 argvars[1].v_type = VAR_STRING;
9554 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9555 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009556 rettv->v_type = VAR_STRING;
9557 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009558 remote_common(argvars, rettv, TRUE);
9559 vim_free(argvars[1].vval.v_string);
9560# endif
9561#endif
9562}
9563
9564 static void
9565f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9566{
9567#ifdef FEAT_CLIENTSERVER
9568 dictitem_T v;
9569 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009570# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009571 long_u n = 0;
9572# endif
9573 char_u *serverid;
9574
9575 if (check_restricted() || check_secure())
9576 {
9577 rettv->vval.v_number = -1;
9578 return;
9579 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009580 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009581 if (serverid == NULL)
9582 {
9583 rettv->vval.v_number = -1;
9584 return; /* type error; errmsg already given */
9585 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009586# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009587 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9588 if (n == 0)
9589 rettv->vval.v_number = -1;
9590 else
9591 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009592 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009593 rettv->vval.v_number = (s != NULL);
9594 }
9595# else
9596 if (check_connection() == FAIL)
9597 return;
9598
9599 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9600 serverStrToWin(serverid), &s);
9601# endif
9602
9603 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9604 {
9605 char_u *retvar;
9606
9607 v.di_tv.v_type = VAR_STRING;
9608 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009609 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009610 if (retvar != NULL)
9611 set_var(retvar, &v.di_tv, FALSE);
9612 vim_free(v.di_tv.vval.v_string);
9613 }
9614#else
9615 rettv->vval.v_number = -1;
9616#endif
9617}
9618
9619 static void
9620f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9621{
9622 char_u *r = NULL;
9623
9624#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009625 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009626
9627 if (serverid != NULL && !check_restricted() && !check_secure())
9628 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009629 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009630# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009631 /* The server's HWND is encoded in the 'id' parameter */
9632 long_u n = 0;
9633# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009634
9635 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009636 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009637
Bram Moolenaar4f974752019-02-17 17:44:42 +01009638# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009639 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9640 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009641 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009642 if (r == NULL)
9643# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009644 if (check_connection() == FAIL
9645 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9646 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009647# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009648 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009649 }
9650#endif
9651 rettv->v_type = VAR_STRING;
9652 rettv->vval.v_string = r;
9653}
9654
9655/*
9656 * "remote_send()" function
9657 */
9658 static void
9659f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9660{
9661 rettv->v_type = VAR_STRING;
9662 rettv->vval.v_string = NULL;
9663#ifdef FEAT_CLIENTSERVER
9664 remote_common(argvars, rettv, FALSE);
9665#endif
9666}
9667
9668/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009669 * "remote_startserver()" function
9670 */
9671 static void
9672f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9673{
9674#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009675 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009676
9677 if (server == NULL)
9678 return; /* type error; errmsg already given */
9679 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009680 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009681 else
9682 {
9683# ifdef FEAT_X11
9684 if (check_connection() == OK)
9685 serverRegisterName(X_DISPLAY, server);
9686# else
9687 serverSetName(server);
9688# endif
9689 }
9690#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009691 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009692#endif
9693}
9694
9695/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009696 * "remove()" function
9697 */
9698 static void
9699f_remove(typval_T *argvars, typval_T *rettv)
9700{
9701 list_T *l;
9702 listitem_T *item, *item2;
9703 listitem_T *li;
9704 long idx;
9705 long end;
9706 char_u *key;
9707 dict_T *d;
9708 dictitem_T *di;
9709 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009710 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009711
9712 if (argvars[0].v_type == VAR_DICT)
9713 {
9714 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009715 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009716 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009717 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009719 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009720 if (key != NULL)
9721 {
9722 di = dict_find(d, key, -1);
9723 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009724 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009725 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9726 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9727 {
9728 *rettv = di->di_tv;
9729 init_tv(&di->di_tv);
9730 dictitem_remove(d, di);
9731 }
9732 }
9733 }
9734 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009735 else if (argvars[0].v_type == VAR_BLOB)
9736 {
9737 idx = (long)tv_get_number_chk(&argvars[1], &error);
9738 if (!error)
9739 {
9740 blob_T *b = argvars[0].vval.v_blob;
9741 int len = blob_len(b);
9742 char_u *p;
9743
9744 if (idx < 0)
9745 // count from the end
9746 idx = len + idx;
9747 if (idx < 0 || idx >= len)
9748 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009749 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009750 return;
9751 }
9752 if (argvars[2].v_type == VAR_UNKNOWN)
9753 {
9754 // Remove one item, return its value.
9755 p = (char_u *)b->bv_ga.ga_data;
9756 rettv->vval.v_number = (varnumber_T) *(p + idx);
9757 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9758 --b->bv_ga.ga_len;
9759 }
9760 else
9761 {
9762 blob_T *blob;
9763
9764 // Remove range of items, return list with values.
9765 end = (long)tv_get_number_chk(&argvars[2], &error);
9766 if (error)
9767 return;
9768 if (end < 0)
9769 // count from the end
9770 end = len + end;
9771 if (end >= len || idx > end)
9772 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009773 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009774 return;
9775 }
9776 blob = blob_alloc();
9777 if (blob == NULL)
9778 return;
9779 blob->bv_ga.ga_len = end - idx + 1;
9780 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9781 {
9782 vim_free(blob);
9783 return;
9784 }
9785 p = (char_u *)b->bv_ga.ga_data;
9786 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9787 (size_t)(end - idx + 1));
9788 ++blob->bv_refcount;
9789 rettv->v_type = VAR_BLOB;
9790 rettv->vval.v_blob = blob;
9791
9792 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9793 b->bv_ga.ga_len -= end - idx + 1;
9794 }
9795 }
9796 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009797 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009798 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009799 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009800 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009801 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009802 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009803 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009804 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009805 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009806 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009807 else
9808 {
9809 if (argvars[2].v_type == VAR_UNKNOWN)
9810 {
9811 /* Remove one item, return its value. */
9812 vimlist_remove(l, item, item);
9813 *rettv = item->li_tv;
9814 vim_free(item);
9815 }
9816 else
9817 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009818 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009819 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009820 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009821 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009822 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009823 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009824 else
9825 {
9826 int cnt = 0;
9827
9828 for (li = item; li != NULL; li = li->li_next)
9829 {
9830 ++cnt;
9831 if (li == item2)
9832 break;
9833 }
9834 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009835 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009836 else
9837 {
9838 vimlist_remove(l, item, item2);
9839 if (rettv_list_alloc(rettv) == OK)
9840 {
9841 l = rettv->vval.v_list;
9842 l->lv_first = item;
9843 l->lv_last = item2;
9844 item->li_prev = NULL;
9845 item2->li_next = NULL;
9846 l->lv_len = cnt;
9847 }
9848 }
9849 }
9850 }
9851 }
9852 }
9853}
9854
9855/*
9856 * "rename({from}, {to})" function
9857 */
9858 static void
9859f_rename(typval_T *argvars, typval_T *rettv)
9860{
9861 char_u buf[NUMBUFLEN];
9862
9863 if (check_restricted() || check_secure())
9864 rettv->vval.v_number = -1;
9865 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009866 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9867 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009868}
9869
9870/*
9871 * "repeat()" function
9872 */
9873 static void
9874f_repeat(typval_T *argvars, typval_T *rettv)
9875{
9876 char_u *p;
9877 int n;
9878 int slen;
9879 int len;
9880 char_u *r;
9881 int i;
9882
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009883 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009884 if (argvars[0].v_type == VAR_LIST)
9885 {
9886 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9887 while (n-- > 0)
9888 if (list_extend(rettv->vval.v_list,
9889 argvars[0].vval.v_list, NULL) == FAIL)
9890 break;
9891 }
9892 else
9893 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009894 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009895 rettv->v_type = VAR_STRING;
9896 rettv->vval.v_string = NULL;
9897
9898 slen = (int)STRLEN(p);
9899 len = slen * n;
9900 if (len <= 0)
9901 return;
9902
9903 r = alloc(len + 1);
9904 if (r != NULL)
9905 {
9906 for (i = 0; i < n; i++)
9907 mch_memmove(r + i * slen, p, (size_t)slen);
9908 r[len] = NUL;
9909 }
9910
9911 rettv->vval.v_string = r;
9912 }
9913}
9914
9915/*
9916 * "resolve()" function
9917 */
9918 static void
9919f_resolve(typval_T *argvars, typval_T *rettv)
9920{
9921 char_u *p;
9922#ifdef HAVE_READLINK
9923 char_u *buf = NULL;
9924#endif
9925
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009926 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009927#ifdef FEAT_SHORTCUT
9928 {
9929 char_u *v = NULL;
9930
Bram Moolenaardce1e892019-02-10 23:18:53 +01009931 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009932 if (v != NULL)
9933 rettv->vval.v_string = v;
9934 else
9935 rettv->vval.v_string = vim_strsave(p);
9936 }
9937#else
9938# ifdef HAVE_READLINK
9939 {
9940 char_u *cpy;
9941 int len;
9942 char_u *remain = NULL;
9943 char_u *q;
9944 int is_relative_to_current = FALSE;
9945 int has_trailing_pathsep = FALSE;
9946 int limit = 100;
9947
9948 p = vim_strsave(p);
9949
9950 if (p[0] == '.' && (vim_ispathsep(p[1])
9951 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9952 is_relative_to_current = TRUE;
9953
9954 len = STRLEN(p);
9955 if (len > 0 && after_pathsep(p, p + len))
9956 {
9957 has_trailing_pathsep = TRUE;
9958 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9959 }
9960
9961 q = getnextcomp(p);
9962 if (*q != NUL)
9963 {
9964 /* Separate the first path component in "p", and keep the
9965 * remainder (beginning with the path separator). */
9966 remain = vim_strsave(q - 1);
9967 q[-1] = NUL;
9968 }
9969
9970 buf = alloc(MAXPATHL + 1);
9971 if (buf == NULL)
9972 goto fail;
9973
9974 for (;;)
9975 {
9976 for (;;)
9977 {
9978 len = readlink((char *)p, (char *)buf, MAXPATHL);
9979 if (len <= 0)
9980 break;
9981 buf[len] = NUL;
9982
9983 if (limit-- == 0)
9984 {
9985 vim_free(p);
9986 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009987 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009988 rettv->vval.v_string = NULL;
9989 goto fail;
9990 }
9991
9992 /* Ensure that the result will have a trailing path separator
9993 * if the argument has one. */
9994 if (remain == NULL && has_trailing_pathsep)
9995 add_pathsep(buf);
9996
9997 /* Separate the first path component in the link value and
9998 * concatenate the remainders. */
9999 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10000 if (*q != NUL)
10001 {
10002 if (remain == NULL)
10003 remain = vim_strsave(q - 1);
10004 else
10005 {
10006 cpy = concat_str(q - 1, remain);
10007 if (cpy != NULL)
10008 {
10009 vim_free(remain);
10010 remain = cpy;
10011 }
10012 }
10013 q[-1] = NUL;
10014 }
10015
10016 q = gettail(p);
10017 if (q > p && *q == NUL)
10018 {
10019 /* Ignore trailing path separator. */
10020 q[-1] = NUL;
10021 q = gettail(p);
10022 }
10023 if (q > p && !mch_isFullName(buf))
10024 {
10025 /* symlink is relative to directory of argument */
10026 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10027 if (cpy != NULL)
10028 {
10029 STRCPY(cpy, p);
10030 STRCPY(gettail(cpy), buf);
10031 vim_free(p);
10032 p = cpy;
10033 }
10034 }
10035 else
10036 {
10037 vim_free(p);
10038 p = vim_strsave(buf);
10039 }
10040 }
10041
10042 if (remain == NULL)
10043 break;
10044
10045 /* Append the first path component of "remain" to "p". */
10046 q = getnextcomp(remain + 1);
10047 len = q - remain - (*q != NUL);
10048 cpy = vim_strnsave(p, STRLEN(p) + len);
10049 if (cpy != NULL)
10050 {
10051 STRNCAT(cpy, remain, len);
10052 vim_free(p);
10053 p = cpy;
10054 }
10055 /* Shorten "remain". */
10056 if (*q != NUL)
10057 STRMOVE(remain, q - 1);
10058 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010059 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010060 }
10061
10062 /* If the result is a relative path name, make it explicitly relative to
10063 * the current directory if and only if the argument had this form. */
10064 if (!vim_ispathsep(*p))
10065 {
10066 if (is_relative_to_current
10067 && *p != NUL
10068 && !(p[0] == '.'
10069 && (p[1] == NUL
10070 || vim_ispathsep(p[1])
10071 || (p[1] == '.'
10072 && (p[2] == NUL
10073 || vim_ispathsep(p[2]))))))
10074 {
10075 /* Prepend "./". */
10076 cpy = concat_str((char_u *)"./", p);
10077 if (cpy != NULL)
10078 {
10079 vim_free(p);
10080 p = cpy;
10081 }
10082 }
10083 else if (!is_relative_to_current)
10084 {
10085 /* Strip leading "./". */
10086 q = p;
10087 while (q[0] == '.' && vim_ispathsep(q[1]))
10088 q += 2;
10089 if (q > p)
10090 STRMOVE(p, p + 2);
10091 }
10092 }
10093
10094 /* Ensure that the result will have no trailing path separator
10095 * if the argument had none. But keep "/" or "//". */
10096 if (!has_trailing_pathsep)
10097 {
10098 q = p + STRLEN(p);
10099 if (after_pathsep(p, q))
10100 *gettail_sep(p) = NUL;
10101 }
10102
10103 rettv->vval.v_string = p;
10104 }
10105# else
10106 rettv->vval.v_string = vim_strsave(p);
10107# endif
10108#endif
10109
10110 simplify_filename(rettv->vval.v_string);
10111
10112#ifdef HAVE_READLINK
10113fail:
10114 vim_free(buf);
10115#endif
10116 rettv->v_type = VAR_STRING;
10117}
10118
10119/*
10120 * "reverse({list})" function
10121 */
10122 static void
10123f_reverse(typval_T *argvars, typval_T *rettv)
10124{
10125 list_T *l;
10126 listitem_T *li, *ni;
10127
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010128 if (argvars[0].v_type == VAR_BLOB)
10129 {
10130 blob_T *b = argvars[0].vval.v_blob;
10131 int i, len = blob_len(b);
10132
10133 for (i = 0; i < len / 2; i++)
10134 {
10135 int tmp = blob_get(b, i);
10136
10137 blob_set(b, i, blob_get(b, len - i - 1));
10138 blob_set(b, len - i - 1, tmp);
10139 }
10140 rettv_blob_set(rettv, b);
10141 return;
10142 }
10143
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010144 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010145 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010146 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010147 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010148 (char_u *)N_("reverse() argument"), TRUE))
10149 {
10150 li = l->lv_last;
10151 l->lv_first = l->lv_last = NULL;
10152 l->lv_len = 0;
10153 while (li != NULL)
10154 {
10155 ni = li->li_prev;
10156 list_append(l, li);
10157 li = ni;
10158 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010159 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010160 l->lv_idx = l->lv_len - l->lv_idx - 1;
10161 }
10162}
10163
10164#define SP_NOMOVE 0x01 /* don't move cursor */
10165#define SP_REPEAT 0x02 /* repeat to find outer pair */
10166#define SP_RETCOUNT 0x04 /* return matchcount */
10167#define SP_SETPCMARK 0x08 /* set previous context mark */
10168#define SP_START 0x10 /* accept match at start position */
10169#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10170#define SP_END 0x40 /* leave cursor at end of match */
10171#define SP_COLUMN 0x80 /* start at cursor column */
10172
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010173/*
10174 * Get flags for a search function.
10175 * Possibly sets "p_ws".
10176 * Returns BACKWARD, FORWARD or zero (for an error).
10177 */
10178 static int
10179get_search_arg(typval_T *varp, int *flagsp)
10180{
10181 int dir = FORWARD;
10182 char_u *flags;
10183 char_u nbuf[NUMBUFLEN];
10184 int mask;
10185
10186 if (varp->v_type != VAR_UNKNOWN)
10187 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010188 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010189 if (flags == NULL)
10190 return 0; /* type error; errmsg already given */
10191 while (*flags != NUL)
10192 {
10193 switch (*flags)
10194 {
10195 case 'b': dir = BACKWARD; break;
10196 case 'w': p_ws = TRUE; break;
10197 case 'W': p_ws = FALSE; break;
10198 default: mask = 0;
10199 if (flagsp != NULL)
10200 switch (*flags)
10201 {
10202 case 'c': mask = SP_START; break;
10203 case 'e': mask = SP_END; break;
10204 case 'm': mask = SP_RETCOUNT; break;
10205 case 'n': mask = SP_NOMOVE; break;
10206 case 'p': mask = SP_SUBPAT; break;
10207 case 'r': mask = SP_REPEAT; break;
10208 case 's': mask = SP_SETPCMARK; break;
10209 case 'z': mask = SP_COLUMN; break;
10210 }
10211 if (mask == 0)
10212 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010213 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010214 dir = 0;
10215 }
10216 else
10217 *flagsp |= mask;
10218 }
10219 if (dir == 0)
10220 break;
10221 ++flags;
10222 }
10223 }
10224 return dir;
10225}
10226
10227/*
10228 * Shared by search() and searchpos() functions.
10229 */
10230 static int
10231search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10232{
10233 int flags;
10234 char_u *pat;
10235 pos_T pos;
10236 pos_T save_cursor;
10237 int save_p_ws = p_ws;
10238 int dir;
10239 int retval = 0; /* default: FAIL */
10240 long lnum_stop = 0;
10241 proftime_T tm;
10242#ifdef FEAT_RELTIME
10243 long time_limit = 0;
10244#endif
10245 int options = SEARCH_KEEP;
10246 int subpatnum;
10247
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010248 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010249 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10250 if (dir == 0)
10251 goto theend;
10252 flags = *flagsp;
10253 if (flags & SP_START)
10254 options |= SEARCH_START;
10255 if (flags & SP_END)
10256 options |= SEARCH_END;
10257 if (flags & SP_COLUMN)
10258 options |= SEARCH_COL;
10259
10260 /* Optional arguments: line number to stop searching and timeout. */
10261 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10262 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010263 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010264 if (lnum_stop < 0)
10265 goto theend;
10266#ifdef FEAT_RELTIME
10267 if (argvars[3].v_type != VAR_UNKNOWN)
10268 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010269 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010270 if (time_limit < 0)
10271 goto theend;
10272 }
10273#endif
10274 }
10275
10276#ifdef FEAT_RELTIME
10277 /* Set the time limit, if there is one. */
10278 profile_setlimit(time_limit, &tm);
10279#endif
10280
10281 /*
10282 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10283 * Check to make sure only those flags are set.
10284 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10285 * flags cannot be set. Check for that condition also.
10286 */
10287 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10288 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10289 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010290 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010291 goto theend;
10292 }
10293
10294 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010295 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010296 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010297 if (subpatnum != FAIL)
10298 {
10299 if (flags & SP_SUBPAT)
10300 retval = subpatnum;
10301 else
10302 retval = pos.lnum;
10303 if (flags & SP_SETPCMARK)
10304 setpcmark();
10305 curwin->w_cursor = pos;
10306 if (match_pos != NULL)
10307 {
10308 /* Store the match cursor position */
10309 match_pos->lnum = pos.lnum;
10310 match_pos->col = pos.col + 1;
10311 }
10312 /* "/$" will put the cursor after the end of the line, may need to
10313 * correct that here */
10314 check_cursor();
10315 }
10316
10317 /* If 'n' flag is used: restore cursor position. */
10318 if (flags & SP_NOMOVE)
10319 curwin->w_cursor = save_cursor;
10320 else
10321 curwin->w_set_curswant = TRUE;
10322theend:
10323 p_ws = save_p_ws;
10324
10325 return retval;
10326}
10327
10328#ifdef FEAT_FLOAT
10329
10330/*
10331 * round() is not in C90, use ceil() or floor() instead.
10332 */
10333 float_T
10334vim_round(float_T f)
10335{
10336 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10337}
10338
10339/*
10340 * "round({float})" function
10341 */
10342 static void
10343f_round(typval_T *argvars, typval_T *rettv)
10344{
10345 float_T f = 0.0;
10346
10347 rettv->v_type = VAR_FLOAT;
10348 if (get_float_arg(argvars, &f) == OK)
10349 rettv->vval.v_float = vim_round(f);
10350 else
10351 rettv->vval.v_float = 0.0;
10352}
10353#endif
10354
10355/*
10356 * "screenattr()" function
10357 */
10358 static void
10359f_screenattr(typval_T *argvars, typval_T *rettv)
10360{
10361 int row;
10362 int col;
10363 int c;
10364
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010365 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10366 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010367 if (row < 0 || row >= screen_Rows
10368 || col < 0 || col >= screen_Columns)
10369 c = -1;
10370 else
10371 c = ScreenAttrs[LineOffset[row] + col];
10372 rettv->vval.v_number = c;
10373}
10374
10375/*
10376 * "screenchar()" function
10377 */
10378 static void
10379f_screenchar(typval_T *argvars, typval_T *rettv)
10380{
10381 int row;
10382 int col;
10383 int off;
10384 int c;
10385
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010386 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10387 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010388 if (row < 0 || row >= screen_Rows
10389 || col < 0 || col >= screen_Columns)
10390 c = -1;
10391 else
10392 {
10393 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010394 if (enc_utf8 && ScreenLinesUC[off] != 0)
10395 c = ScreenLinesUC[off];
10396 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010397 c = ScreenLines[off];
10398 }
10399 rettv->vval.v_number = c;
10400}
10401
10402/*
10403 * "screencol()" function
10404 *
10405 * First column is 1 to be consistent with virtcol().
10406 */
10407 static void
10408f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10409{
10410 rettv->vval.v_number = screen_screencol() + 1;
10411}
10412
10413/*
10414 * "screenrow()" function
10415 */
10416 static void
10417f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10418{
10419 rettv->vval.v_number = screen_screenrow() + 1;
10420}
10421
10422/*
10423 * "search()" function
10424 */
10425 static void
10426f_search(typval_T *argvars, typval_T *rettv)
10427{
10428 int flags = 0;
10429
10430 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10431}
10432
10433/*
10434 * "searchdecl()" function
10435 */
10436 static void
10437f_searchdecl(typval_T *argvars, typval_T *rettv)
10438{
10439 int locally = 1;
10440 int thisblock = 0;
10441 int error = FALSE;
10442 char_u *name;
10443
10444 rettv->vval.v_number = 1; /* default: FAIL */
10445
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010446 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010447 if (argvars[1].v_type != VAR_UNKNOWN)
10448 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010449 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010450 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010451 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010452 }
10453 if (!error && name != NULL)
10454 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10455 locally, thisblock, SEARCH_KEEP) == FAIL;
10456}
10457
10458/*
10459 * Used by searchpair() and searchpairpos()
10460 */
10461 static int
10462searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10463{
10464 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010465 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010466 int save_p_ws = p_ws;
10467 int dir;
10468 int flags = 0;
10469 char_u nbuf1[NUMBUFLEN];
10470 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010471 int retval = 0; /* default: FAIL */
10472 long lnum_stop = 0;
10473 long time_limit = 0;
10474
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010475 /* Get the three pattern arguments: start, middle, end. Will result in an
10476 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010477 spat = tv_get_string_chk(&argvars[0]);
10478 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10479 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010480 if (spat == NULL || mpat == NULL || epat == NULL)
10481 goto theend; /* type error */
10482
10483 /* Handle the optional fourth argument: flags */
10484 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10485 if (dir == 0)
10486 goto theend;
10487
10488 /* Don't accept SP_END or SP_SUBPAT.
10489 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10490 */
10491 if ((flags & (SP_END | SP_SUBPAT)) != 0
10492 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10493 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010494 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010495 goto theend;
10496 }
10497
10498 /* Using 'r' implies 'W', otherwise it doesn't work. */
10499 if (flags & SP_REPEAT)
10500 p_ws = FALSE;
10501
10502 /* Optional fifth argument: skip expression */
10503 if (argvars[3].v_type == VAR_UNKNOWN
10504 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010505 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010506 else
10507 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010508 skip = &argvars[4];
10509 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10510 && skip->v_type != VAR_STRING)
10511 {
10512 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010513 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010514 goto theend;
10515 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010516 if (argvars[5].v_type != VAR_UNKNOWN)
10517 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010518 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010519 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010520 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010521 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010522 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010523 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010524#ifdef FEAT_RELTIME
10525 if (argvars[6].v_type != VAR_UNKNOWN)
10526 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010527 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010528 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010529 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010530 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010531 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010532 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010533 }
10534#endif
10535 }
10536 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010537
10538 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10539 match_pos, lnum_stop, time_limit);
10540
10541theend:
10542 p_ws = save_p_ws;
10543
10544 return retval;
10545}
10546
10547/*
10548 * "searchpair()" function
10549 */
10550 static void
10551f_searchpair(typval_T *argvars, typval_T *rettv)
10552{
10553 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10554}
10555
10556/*
10557 * "searchpairpos()" function
10558 */
10559 static void
10560f_searchpairpos(typval_T *argvars, typval_T *rettv)
10561{
10562 pos_T match_pos;
10563 int lnum = 0;
10564 int col = 0;
10565
10566 if (rettv_list_alloc(rettv) == FAIL)
10567 return;
10568
10569 if (searchpair_cmn(argvars, &match_pos) > 0)
10570 {
10571 lnum = match_pos.lnum;
10572 col = match_pos.col;
10573 }
10574
10575 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10576 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10577}
10578
10579/*
10580 * Search for a start/middle/end thing.
10581 * Used by searchpair(), see its documentation for the details.
10582 * Returns 0 or -1 for no match,
10583 */
10584 long
10585do_searchpair(
10586 char_u *spat, /* start pattern */
10587 char_u *mpat, /* middle pattern */
10588 char_u *epat, /* end pattern */
10589 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010590 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010591 int flags, /* SP_SETPCMARK and other SP_ values */
10592 pos_T *match_pos,
10593 linenr_T lnum_stop, /* stop at this line if not zero */
10594 long time_limit UNUSED) /* stop after this many msec */
10595{
10596 char_u *save_cpo;
10597 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10598 long retval = 0;
10599 pos_T pos;
10600 pos_T firstpos;
10601 pos_T foundpos;
10602 pos_T save_cursor;
10603 pos_T save_pos;
10604 int n;
10605 int r;
10606 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010607 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010608 int err;
10609 int options = SEARCH_KEEP;
10610 proftime_T tm;
10611
10612 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10613 save_cpo = p_cpo;
10614 p_cpo = empty_option;
10615
10616#ifdef FEAT_RELTIME
10617 /* Set the time limit, if there is one. */
10618 profile_setlimit(time_limit, &tm);
10619#endif
10620
10621 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10622 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010623 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10624 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010625 if (pat2 == NULL || pat3 == NULL)
10626 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010627 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010628 if (*mpat == NUL)
10629 STRCPY(pat3, pat2);
10630 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010631 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010632 spat, epat, mpat);
10633 if (flags & SP_START)
10634 options |= SEARCH_START;
10635
Bram Moolenaar48570482017-10-30 21:48:41 +010010636 if (skip != NULL)
10637 {
10638 /* Empty string means to not use the skip expression. */
10639 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10640 use_skip = skip->vval.v_string != NULL
10641 && *skip->vval.v_string != NUL;
10642 }
10643
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 save_cursor = curwin->w_cursor;
10645 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010646 CLEAR_POS(&firstpos);
10647 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010648 pat = pat3;
10649 for (;;)
10650 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010651 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010652 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010653 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010654 /* didn't find it or found the first match again: FAIL */
10655 break;
10656
10657 if (firstpos.lnum == 0)
10658 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010659 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010660 {
10661 /* Found the same position again. Can happen with a pattern that
10662 * has "\zs" at the end and searching backwards. Advance one
10663 * character and try again. */
10664 if (dir == BACKWARD)
10665 decl(&pos);
10666 else
10667 incl(&pos);
10668 }
10669 foundpos = pos;
10670
10671 /* clear the start flag to avoid getting stuck here */
10672 options &= ~SEARCH_START;
10673
10674 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010675 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010676 {
10677 save_pos = curwin->w_cursor;
10678 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010679 err = FALSE;
10680 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010681 curwin->w_cursor = save_pos;
10682 if (err)
10683 {
10684 /* Evaluating {skip} caused an error, break here. */
10685 curwin->w_cursor = save_cursor;
10686 retval = -1;
10687 break;
10688 }
10689 if (r)
10690 continue;
10691 }
10692
10693 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10694 {
10695 /* Found end when searching backwards or start when searching
10696 * forward: nested pair. */
10697 ++nest;
10698 pat = pat2; /* nested, don't search for middle */
10699 }
10700 else
10701 {
10702 /* Found end when searching forward or start when searching
10703 * backward: end of (nested) pair; or found middle in outer pair. */
10704 if (--nest == 1)
10705 pat = pat3; /* outer level, search for middle */
10706 }
10707
10708 if (nest == 0)
10709 {
10710 /* Found the match: return matchcount or line number. */
10711 if (flags & SP_RETCOUNT)
10712 ++retval;
10713 else
10714 retval = pos.lnum;
10715 if (flags & SP_SETPCMARK)
10716 setpcmark();
10717 curwin->w_cursor = pos;
10718 if (!(flags & SP_REPEAT))
10719 break;
10720 nest = 1; /* search for next unmatched */
10721 }
10722 }
10723
10724 if (match_pos != NULL)
10725 {
10726 /* Store the match cursor position */
10727 match_pos->lnum = curwin->w_cursor.lnum;
10728 match_pos->col = curwin->w_cursor.col + 1;
10729 }
10730
10731 /* If 'n' flag is used or search failed: restore cursor position. */
10732 if ((flags & SP_NOMOVE) || retval == 0)
10733 curwin->w_cursor = save_cursor;
10734
10735theend:
10736 vim_free(pat2);
10737 vim_free(pat3);
10738 if (p_cpo == empty_option)
10739 p_cpo = save_cpo;
10740 else
10741 /* Darn, evaluating the {skip} expression changed the value. */
10742 free_string_option(save_cpo);
10743
10744 return retval;
10745}
10746
10747/*
10748 * "searchpos()" function
10749 */
10750 static void
10751f_searchpos(typval_T *argvars, typval_T *rettv)
10752{
10753 pos_T match_pos;
10754 int lnum = 0;
10755 int col = 0;
10756 int n;
10757 int flags = 0;
10758
10759 if (rettv_list_alloc(rettv) == FAIL)
10760 return;
10761
10762 n = search_cmn(argvars, &match_pos, &flags);
10763 if (n > 0)
10764 {
10765 lnum = match_pos.lnum;
10766 col = match_pos.col;
10767 }
10768
10769 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10770 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10771 if (flags & SP_SUBPAT)
10772 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10773}
10774
10775 static void
10776f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10777{
10778#ifdef FEAT_CLIENTSERVER
10779 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010780 char_u *server = tv_get_string_chk(&argvars[0]);
10781 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782
10783 rettv->vval.v_number = -1;
10784 if (server == NULL || reply == NULL)
10785 return;
10786 if (check_restricted() || check_secure())
10787 return;
10788# ifdef FEAT_X11
10789 if (check_connection() == FAIL)
10790 return;
10791# endif
10792
10793 if (serverSendReply(server, reply) < 0)
10794 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010795 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010796 return;
10797 }
10798 rettv->vval.v_number = 0;
10799#else
10800 rettv->vval.v_number = -1;
10801#endif
10802}
10803
10804 static void
10805f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10806{
10807 char_u *r = NULL;
10808
10809#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010810# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010811 r = serverGetVimNames();
10812# else
10813 make_connection();
10814 if (X_DISPLAY != NULL)
10815 r = serverGetVimNames(X_DISPLAY);
10816# endif
10817#endif
10818 rettv->v_type = VAR_STRING;
10819 rettv->vval.v_string = r;
10820}
10821
10822/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010823 * "setbufline()" function
10824 */
10825 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010826f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010827{
10828 linenr_T lnum;
10829 buf_T *buf;
10830
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010831 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010832 if (buf == NULL)
10833 rettv->vval.v_number = 1; /* FAIL */
10834 else
10835 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010836 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010837 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010838 }
10839}
10840
10841/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010842 * "setbufvar()" function
10843 */
10844 static void
10845f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10846{
10847 buf_T *buf;
10848 char_u *varname, *bufvarname;
10849 typval_T *varp;
10850 char_u nbuf[NUMBUFLEN];
10851
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010852 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010853 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010854 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10855 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010856 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010857 varp = &argvars[2];
10858
10859 if (buf != NULL && varname != NULL && varp != NULL)
10860 {
10861 if (*varname == '&')
10862 {
10863 long numval;
10864 char_u *strval;
10865 int error = FALSE;
10866 aco_save_T aco;
10867
10868 /* set curbuf to be our buf, temporarily */
10869 aucmd_prepbuf(&aco, buf);
10870
10871 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010872 numval = (long)tv_get_number_chk(varp, &error);
10873 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010874 if (!error && strval != NULL)
10875 set_option_value(varname, numval, strval, OPT_LOCAL);
10876
10877 /* reset notion of buffer */
10878 aucmd_restbuf(&aco);
10879 }
10880 else
10881 {
10882 buf_T *save_curbuf = curbuf;
10883
10884 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10885 if (bufvarname != NULL)
10886 {
10887 curbuf = buf;
10888 STRCPY(bufvarname, "b:");
10889 STRCPY(bufvarname + 2, varname);
10890 set_var(bufvarname, varp, TRUE);
10891 vim_free(bufvarname);
10892 curbuf = save_curbuf;
10893 }
10894 }
10895 }
10896}
10897
10898 static void
10899f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10900{
10901 dict_T *d;
10902 dictitem_T *di;
10903 char_u *csearch;
10904
10905 if (argvars[0].v_type != VAR_DICT)
10906 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010907 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010908 return;
10909 }
10910
10911 if ((d = argvars[0].vval.v_dict) != NULL)
10912 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010913 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010914 if (csearch != NULL)
10915 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010916 if (enc_utf8)
10917 {
10918 int pcc[MAX_MCO];
10919 int c = utfc_ptr2char(csearch, pcc);
10920
10921 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10922 }
10923 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010924 set_last_csearch(PTR2CHAR(csearch),
10925 csearch, MB_PTR2LEN(csearch));
10926 }
10927
10928 di = dict_find(d, (char_u *)"forward", -1);
10929 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010930 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010931 ? FORWARD : BACKWARD);
10932
10933 di = dict_find(d, (char_u *)"until", -1);
10934 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010935 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010936 }
10937}
10938
10939/*
10940 * "setcmdpos()" function
10941 */
10942 static void
10943f_setcmdpos(typval_T *argvars, typval_T *rettv)
10944{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010945 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010946
10947 if (pos >= 0)
10948 rettv->vval.v_number = set_cmdline_pos(pos);
10949}
10950
10951/*
10952 * "setfperm({fname}, {mode})" function
10953 */
10954 static void
10955f_setfperm(typval_T *argvars, typval_T *rettv)
10956{
10957 char_u *fname;
10958 char_u modebuf[NUMBUFLEN];
10959 char_u *mode_str;
10960 int i;
10961 int mask;
10962 int mode = 0;
10963
10964 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010965 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010966 if (fname == NULL)
10967 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010968 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010969 if (mode_str == NULL)
10970 return;
10971 if (STRLEN(mode_str) != 9)
10972 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010973 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010974 return;
10975 }
10976
10977 mask = 1;
10978 for (i = 8; i >= 0; --i)
10979 {
10980 if (mode_str[i] != '-')
10981 mode |= mask;
10982 mask = mask << 1;
10983 }
10984 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10985}
10986
10987/*
10988 * "setline()" function
10989 */
10990 static void
10991f_setline(typval_T *argvars, typval_T *rettv)
10992{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010993 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010994
Bram Moolenaarca851592018-06-06 21:04:07 +020010995 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010996}
10997
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010998/*
10999 * Used by "setqflist()" and "setloclist()" functions
11000 */
11001 static void
11002set_qf_ll_list(
11003 win_T *wp UNUSED,
11004 typval_T *list_arg UNUSED,
11005 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011006 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011007 typval_T *rettv)
11008{
11009#ifdef FEAT_QUICKFIX
11010 static char *e_invact = N_("E927: Invalid action: '%s'");
11011 char_u *act;
11012 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011013 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011014#endif
11015
11016 rettv->vval.v_number = -1;
11017
11018#ifdef FEAT_QUICKFIX
11019 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011020 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011021 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011022 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011023 else
11024 {
11025 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011026 dict_T *d = NULL;
11027 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011028
11029 if (action_arg->v_type == VAR_STRING)
11030 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011031 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011032 if (act == NULL)
11033 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011034 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11035 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011036 action = *act;
11037 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011038 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011039 }
11040 else if (action_arg->v_type == VAR_UNKNOWN)
11041 action = ' ';
11042 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011043 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011044
Bram Moolenaard823fa92016-08-12 16:29:27 +020011045 if (action_arg->v_type != VAR_UNKNOWN
11046 && what_arg->v_type != VAR_UNKNOWN)
11047 {
11048 if (what_arg->v_type == VAR_DICT)
11049 d = what_arg->vval.v_dict;
11050 else
11051 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011052 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011053 valid_dict = FALSE;
11054 }
11055 }
11056
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011057 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011058 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011059 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11060 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011061 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011062 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063 }
11064#endif
11065}
11066
11067/*
11068 * "setloclist()" function
11069 */
11070 static void
11071f_setloclist(typval_T *argvars, typval_T *rettv)
11072{
11073 win_T *win;
11074
11075 rettv->vval.v_number = -1;
11076
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011077 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011078 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011079 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080}
11081
11082/*
11083 * "setmatches()" function
11084 */
11085 static void
11086f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11087{
11088#ifdef FEAT_SEARCH_EXTRA
11089 list_T *l;
11090 listitem_T *li;
11091 dict_T *d;
11092 list_T *s = NULL;
11093
11094 rettv->vval.v_number = -1;
11095 if (argvars[0].v_type != VAR_LIST)
11096 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011097 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011098 return;
11099 }
11100 if ((l = argvars[0].vval.v_list) != NULL)
11101 {
11102
11103 /* To some extent make sure that we are dealing with a list from
11104 * "getmatches()". */
11105 li = l->lv_first;
11106 while (li != NULL)
11107 {
11108 if (li->li_tv.v_type != VAR_DICT
11109 || (d = li->li_tv.vval.v_dict) == NULL)
11110 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011111 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011112 return;
11113 }
11114 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11115 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11116 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11117 && dict_find(d, (char_u *)"priority", -1) != NULL
11118 && dict_find(d, (char_u *)"id", -1) != NULL))
11119 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011120 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011121 return;
11122 }
11123 li = li->li_next;
11124 }
11125
11126 clear_matches(curwin);
11127 li = l->lv_first;
11128 while (li != NULL)
11129 {
11130 int i = 0;
11131 char_u buf[5];
11132 dictitem_T *di;
11133 char_u *group;
11134 int priority;
11135 int id;
11136 char_u *conceal;
11137
11138 d = li->li_tv.vval.v_dict;
11139 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11140 {
11141 if (s == NULL)
11142 {
11143 s = list_alloc();
11144 if (s == NULL)
11145 return;
11146 }
11147
11148 /* match from matchaddpos() */
11149 for (i = 1; i < 9; i++)
11150 {
11151 sprintf((char *)buf, (char *)"pos%d", i);
11152 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11153 {
11154 if (di->di_tv.v_type != VAR_LIST)
11155 return;
11156
11157 list_append_tv(s, &di->di_tv);
11158 s->lv_refcount++;
11159 }
11160 else
11161 break;
11162 }
11163 }
11164
Bram Moolenaar8f667172018-12-14 15:38:31 +010011165 group = dict_get_string(d, (char_u *)"group", TRUE);
11166 priority = (int)dict_get_number(d, (char_u *)"priority");
11167 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011168 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011169 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011170 : NULL;
11171 if (i == 0)
11172 {
11173 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011174 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011175 priority, id, NULL, conceal);
11176 }
11177 else
11178 {
11179 match_add(curwin, group, NULL, priority, id, s, conceal);
11180 list_unref(s);
11181 s = NULL;
11182 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011183 vim_free(group);
11184 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011185
11186 li = li->li_next;
11187 }
11188 rettv->vval.v_number = 0;
11189 }
11190#endif
11191}
11192
11193/*
11194 * "setpos()" function
11195 */
11196 static void
11197f_setpos(typval_T *argvars, typval_T *rettv)
11198{
11199 pos_T pos;
11200 int fnum;
11201 char_u *name;
11202 colnr_T curswant = -1;
11203
11204 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011205 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011206 if (name != NULL)
11207 {
11208 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11209 {
11210 if (--pos.col < 0)
11211 pos.col = 0;
11212 if (name[0] == '.' && name[1] == NUL)
11213 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011214 /* set cursor; "fnum" is ignored */
11215 curwin->w_cursor = pos;
11216 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011217 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011218 curwin->w_curswant = curswant - 1;
11219 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011220 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011221 check_cursor();
11222 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011223 }
11224 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11225 {
11226 /* set mark */
11227 if (setmark_pos(name[1], &pos, fnum) == OK)
11228 rettv->vval.v_number = 0;
11229 }
11230 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011231 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011232 }
11233 }
11234}
11235
11236/*
11237 * "setqflist()" function
11238 */
11239 static void
11240f_setqflist(typval_T *argvars, typval_T *rettv)
11241{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011242 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011243}
11244
11245/*
11246 * "setreg()" function
11247 */
11248 static void
11249f_setreg(typval_T *argvars, typval_T *rettv)
11250{
11251 int regname;
11252 char_u *strregname;
11253 char_u *stropt;
11254 char_u *strval;
11255 int append;
11256 char_u yank_type;
11257 long block_len;
11258
11259 block_len = -1;
11260 yank_type = MAUTO;
11261 append = FALSE;
11262
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011263 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011264 rettv->vval.v_number = 1; /* FAIL is default */
11265
11266 if (strregname == NULL)
11267 return; /* type error; errmsg already given */
11268 regname = *strregname;
11269 if (regname == 0 || regname == '@')
11270 regname = '"';
11271
11272 if (argvars[2].v_type != VAR_UNKNOWN)
11273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011274 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011275 if (stropt == NULL)
11276 return; /* type error */
11277 for (; *stropt != NUL; ++stropt)
11278 switch (*stropt)
11279 {
11280 case 'a': case 'A': /* append */
11281 append = TRUE;
11282 break;
11283 case 'v': case 'c': /* character-wise selection */
11284 yank_type = MCHAR;
11285 break;
11286 case 'V': case 'l': /* line-wise selection */
11287 yank_type = MLINE;
11288 break;
11289 case 'b': case Ctrl_V: /* block-wise selection */
11290 yank_type = MBLOCK;
11291 if (VIM_ISDIGIT(stropt[1]))
11292 {
11293 ++stropt;
11294 block_len = getdigits(&stropt) - 1;
11295 --stropt;
11296 }
11297 break;
11298 }
11299 }
11300
11301 if (argvars[1].v_type == VAR_LIST)
11302 {
11303 char_u **lstval;
11304 char_u **allocval;
11305 char_u buf[NUMBUFLEN];
11306 char_u **curval;
11307 char_u **curallocval;
11308 list_T *ll = argvars[1].vval.v_list;
11309 listitem_T *li;
11310 int len;
11311
11312 /* If the list is NULL handle like an empty list. */
11313 len = ll == NULL ? 0 : ll->lv_len;
11314
11315 /* First half: use for pointers to result lines; second half: use for
11316 * pointers to allocated copies. */
11317 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11318 if (lstval == NULL)
11319 return;
11320 curval = lstval;
11321 allocval = lstval + len + 2;
11322 curallocval = allocval;
11323
11324 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11325 li = li->li_next)
11326 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011327 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011328 if (strval == NULL)
11329 goto free_lstval;
11330 if (strval == buf)
11331 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011332 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011333 * overwrite the string. */
11334 strval = vim_strsave(buf);
11335 if (strval == NULL)
11336 goto free_lstval;
11337 *curallocval++ = strval;
11338 }
11339 *curval++ = strval;
11340 }
11341 *curval++ = NULL;
11342
11343 write_reg_contents_lst(regname, lstval, -1,
11344 append, yank_type, block_len);
11345free_lstval:
11346 while (curallocval > allocval)
11347 vim_free(*--curallocval);
11348 vim_free(lstval);
11349 }
11350 else
11351 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011352 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011353 if (strval == NULL)
11354 return;
11355 write_reg_contents_ex(regname, strval, -1,
11356 append, yank_type, block_len);
11357 }
11358 rettv->vval.v_number = 0;
11359}
11360
11361/*
11362 * "settabvar()" function
11363 */
11364 static void
11365f_settabvar(typval_T *argvars, typval_T *rettv)
11366{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011367 tabpage_T *save_curtab;
11368 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011369 char_u *varname, *tabvarname;
11370 typval_T *varp;
11371
11372 rettv->vval.v_number = 0;
11373
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011374 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011375 return;
11376
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011377 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11378 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011379 varp = &argvars[2];
11380
Bram Moolenaar4033c552017-09-16 20:54:51 +020011381 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011382 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011383 save_curtab = curtab;
11384 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011385
11386 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11387 if (tabvarname != NULL)
11388 {
11389 STRCPY(tabvarname, "t:");
11390 STRCPY(tabvarname + 2, varname);
11391 set_var(tabvarname, varp, TRUE);
11392 vim_free(tabvarname);
11393 }
11394
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011395 /* Restore current tabpage */
11396 if (valid_tabpage(save_curtab))
11397 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011398 }
11399}
11400
11401/*
11402 * "settabwinvar()" function
11403 */
11404 static void
11405f_settabwinvar(typval_T *argvars, typval_T *rettv)
11406{
11407 setwinvar(argvars, rettv, 1);
11408}
11409
11410/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011411 * "settagstack()" function
11412 */
11413 static void
11414f_settagstack(typval_T *argvars, typval_T *rettv)
11415{
11416 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11417 win_T *wp;
11418 dict_T *d;
11419 int action = 'r';
11420
11421 rettv->vval.v_number = -1;
11422
11423 // first argument: window number or id
11424 wp = find_win_by_nr_or_id(&argvars[0]);
11425 if (wp == NULL)
11426 return;
11427
11428 // second argument: dict with items to set in the tag stack
11429 if (argvars[1].v_type != VAR_DICT)
11430 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011431 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011432 return;
11433 }
11434 d = argvars[1].vval.v_dict;
11435 if (d == NULL)
11436 return;
11437
11438 // third argument: action - 'a' for append and 'r' for replace.
11439 // default is to replace the stack.
11440 if (argvars[2].v_type == VAR_UNKNOWN)
11441 action = 'r';
11442 else if (argvars[2].v_type == VAR_STRING)
11443 {
11444 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011445 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011446 if (actstr == NULL)
11447 return;
11448 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11449 action = *actstr;
11450 else
11451 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011452 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011453 return;
11454 }
11455 }
11456 else
11457 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011458 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011459 return;
11460 }
11461
11462 if (set_tagstack(wp, d, action) == OK)
11463 rettv->vval.v_number = 0;
11464}
11465
11466/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011467 * "setwinvar()" function
11468 */
11469 static void
11470f_setwinvar(typval_T *argvars, typval_T *rettv)
11471{
11472 setwinvar(argvars, rettv, 0);
11473}
11474
11475#ifdef FEAT_CRYPT
11476/*
11477 * "sha256({string})" function
11478 */
11479 static void
11480f_sha256(typval_T *argvars, typval_T *rettv)
11481{
11482 char_u *p;
11483
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011484 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011485 rettv->vval.v_string = vim_strsave(
11486 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11487 rettv->v_type = VAR_STRING;
11488}
11489#endif /* FEAT_CRYPT */
11490
11491/*
11492 * "shellescape({string})" function
11493 */
11494 static void
11495f_shellescape(typval_T *argvars, typval_T *rettv)
11496{
Bram Moolenaar20615522017-06-05 18:46:26 +020011497 int do_special = non_zero_arg(&argvars[1]);
11498
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011499 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011500 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011501 rettv->v_type = VAR_STRING;
11502}
11503
11504/*
11505 * shiftwidth() function
11506 */
11507 static void
11508f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11509{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011510 rettv->vval.v_number = 0;
11511
11512 if (argvars[0].v_type != VAR_UNKNOWN)
11513 {
11514 long col;
11515
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011516 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011517 if (col < 0)
11518 return; // type error; errmsg already given
11519#ifdef FEAT_VARTABS
11520 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11521 return;
11522#endif
11523 }
11524
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011525 rettv->vval.v_number = get_sw_value(curbuf);
11526}
11527
Bram Moolenaar162b7142018-12-21 15:17:36 +010011528#ifdef FEAT_SIGNS
11529/*
11530 * "sign_define()" function
11531 */
11532 static void
11533f_sign_define(typval_T *argvars, typval_T *rettv)
11534{
11535 char_u *name;
11536 dict_T *dict;
11537 char_u *icon = NULL;
11538 char_u *linehl = NULL;
11539 char_u *text = NULL;
11540 char_u *texthl = NULL;
11541
11542 rettv->vval.v_number = -1;
11543
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011544 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011545 if (name == NULL)
11546 return;
11547
11548 if (argvars[1].v_type != VAR_UNKNOWN)
11549 {
11550 if (argvars[1].v_type != VAR_DICT)
11551 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011552 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011553 return;
11554 }
11555
11556 // sign attributes
11557 dict = argvars[1].vval.v_dict;
11558 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11559 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11560 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11561 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11562 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11563 text = dict_get_string(dict, (char_u *)"text", TRUE);
11564 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11565 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11566 }
11567
11568 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11569 rettv->vval.v_number = 0;
11570
11571 vim_free(icon);
11572 vim_free(linehl);
11573 vim_free(text);
11574 vim_free(texthl);
11575}
11576
11577/*
11578 * "sign_getdefined()" function
11579 */
11580 static void
11581f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11582{
11583 char_u *name = NULL;
11584
11585 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11586 return;
11587
11588 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011589 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011590
11591 sign_getlist(name, rettv->vval.v_list);
11592}
11593
11594/*
11595 * "sign_getplaced()" function
11596 */
11597 static void
11598f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11599{
11600 buf_T *buf = NULL;
11601 dict_T *dict;
11602 dictitem_T *di;
11603 linenr_T lnum = 0;
11604 int sign_id = 0;
11605 char_u *group = NULL;
11606 int notanum = FALSE;
11607
11608 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11609 return;
11610
11611 if (argvars[0].v_type != VAR_UNKNOWN)
11612 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011613 // get signs placed in the specified buffer
11614 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011615 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011616 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011617
11618 if (argvars[1].v_type != VAR_UNKNOWN)
11619 {
11620 if (argvars[1].v_type != VAR_DICT ||
11621 ((dict = argvars[1].vval.v_dict) == NULL))
11622 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011623 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011624 return;
11625 }
11626 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11627 {
11628 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011629 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011630 if (notanum)
11631 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011632 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011633 }
11634 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11635 {
11636 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011637 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011638 if (notanum)
11639 return;
11640 }
11641 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11642 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011643 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011644 if (group == NULL)
11645 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011646 if (*group == '\0') // empty string means global group
11647 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011648 }
11649 }
11650 }
11651
11652 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11653}
11654
11655/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011656 * "sign_jump()" function
11657 */
11658 static void
11659f_sign_jump(typval_T *argvars, typval_T *rettv)
11660{
11661 int sign_id;
11662 char_u *sign_group = NULL;
11663 buf_T *buf;
11664 int notanum = FALSE;
11665
11666 rettv->vval.v_number = -1;
11667
Bram Moolenaarbdace832019-03-02 10:13:42 +010011668 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011669 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11670 if (notanum)
11671 return;
11672 if (sign_id <= 0)
11673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011674 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011675 return;
11676 }
11677
11678 // Sign group
11679 sign_group = tv_get_string_chk(&argvars[1]);
11680 if (sign_group == NULL)
11681 return;
11682 if (sign_group[0] == '\0')
11683 sign_group = NULL; // global sign group
11684 else
11685 {
11686 sign_group = vim_strsave(sign_group);
11687 if (sign_group == NULL)
11688 return;
11689 }
11690
11691 // Buffer to place the sign
11692 buf = get_buf_arg(&argvars[2]);
11693 if (buf == NULL)
11694 goto cleanup;
11695
11696 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11697
11698cleanup:
11699 vim_free(sign_group);
11700}
11701
11702/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011703 * "sign_place()" function
11704 */
11705 static void
11706f_sign_place(typval_T *argvars, typval_T *rettv)
11707{
11708 int sign_id;
11709 char_u *group = NULL;
11710 char_u *sign_name;
11711 buf_T *buf;
11712 dict_T *dict;
11713 dictitem_T *di;
11714 linenr_T lnum = 0;
11715 int prio = SIGN_DEF_PRIO;
11716 int notanum = FALSE;
11717
11718 rettv->vval.v_number = -1;
11719
Bram Moolenaarbdace832019-03-02 10:13:42 +010011720 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011721 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011722 if (notanum)
11723 return;
11724 if (sign_id < 0)
11725 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011726 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011727 return;
11728 }
11729
11730 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011731 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011732 if (group == NULL)
11733 return;
11734 if (group[0] == '\0')
11735 group = NULL; // global sign group
11736 else
11737 {
11738 group = vim_strsave(group);
11739 if (group == NULL)
11740 return;
11741 }
11742
11743 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011744 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011745 if (sign_name == NULL)
11746 goto cleanup;
11747
11748 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011749 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011750 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011751 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011752
11753 if (argvars[4].v_type != VAR_UNKNOWN)
11754 {
11755 if (argvars[4].v_type != VAR_DICT ||
11756 ((dict = argvars[4].vval.v_dict) == NULL))
11757 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011758 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011759 goto cleanup;
11760 }
11761
11762 // Line number where the sign is to be placed
11763 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11764 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011765 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011766 if (notanum)
11767 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011768 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011769 }
11770 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11771 {
11772 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011773 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011774 if (notanum)
11775 goto cleanup;
11776 }
11777 }
11778
11779 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11780 rettv->vval.v_number = sign_id;
11781
11782cleanup:
11783 vim_free(group);
11784}
11785
11786/*
11787 * "sign_undefine()" function
11788 */
11789 static void
11790f_sign_undefine(typval_T *argvars, typval_T *rettv)
11791{
11792 char_u *name;
11793
11794 rettv->vval.v_number = -1;
11795
11796 if (argvars[0].v_type == VAR_UNKNOWN)
11797 {
11798 // Free all the signs
11799 free_signs();
11800 rettv->vval.v_number = 0;
11801 }
11802 else
11803 {
11804 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011805 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011806 if (name == NULL)
11807 return;
11808
11809 if (sign_undefine_by_name(name) == OK)
11810 rettv->vval.v_number = 0;
11811 }
11812}
11813
11814/*
11815 * "sign_unplace()" function
11816 */
11817 static void
11818f_sign_unplace(typval_T *argvars, typval_T *rettv)
11819{
11820 dict_T *dict;
11821 dictitem_T *di;
11822 int sign_id = 0;
11823 buf_T *buf = NULL;
11824 char_u *group = NULL;
11825
11826 rettv->vval.v_number = -1;
11827
11828 if (argvars[0].v_type != VAR_STRING)
11829 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011830 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011831 return;
11832 }
11833
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011834 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011835 if (group[0] == '\0')
11836 group = NULL; // global sign group
11837 else
11838 {
11839 group = vim_strsave(group);
11840 if (group == NULL)
11841 return;
11842 }
11843
11844 if (argvars[1].v_type != VAR_UNKNOWN)
11845 {
11846 if (argvars[1].v_type != VAR_DICT)
11847 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011848 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011849 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011850 }
11851 dict = argvars[1].vval.v_dict;
11852
11853 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11854 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011855 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011856 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011857 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011858 }
11859 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11860 sign_id = dict_get_number(dict, (char_u *)"id");
11861 }
11862
11863 if (buf == NULL)
11864 {
11865 // Delete the sign in all the buffers
11866 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011867 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011868 rettv->vval.v_number = 0;
11869 }
11870 else
11871 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011872 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011873 rettv->vval.v_number = 0;
11874 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011875
11876cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010011877 vim_free(group);
11878}
11879#endif
11880
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011881/*
11882 * "simplify()" function
11883 */
11884 static void
11885f_simplify(typval_T *argvars, typval_T *rettv)
11886{
11887 char_u *p;
11888
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011889 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011890 rettv->vval.v_string = vim_strsave(p);
11891 simplify_filename(rettv->vval.v_string); /* simplify in place */
11892 rettv->v_type = VAR_STRING;
11893}
11894
11895#ifdef FEAT_FLOAT
11896/*
11897 * "sin()" function
11898 */
11899 static void
11900f_sin(typval_T *argvars, typval_T *rettv)
11901{
11902 float_T f = 0.0;
11903
11904 rettv->v_type = VAR_FLOAT;
11905 if (get_float_arg(argvars, &f) == OK)
11906 rettv->vval.v_float = sin(f);
11907 else
11908 rettv->vval.v_float = 0.0;
11909}
11910
11911/*
11912 * "sinh()" function
11913 */
11914 static void
11915f_sinh(typval_T *argvars, typval_T *rettv)
11916{
11917 float_T f = 0.0;
11918
11919 rettv->v_type = VAR_FLOAT;
11920 if (get_float_arg(argvars, &f) == OK)
11921 rettv->vval.v_float = sinh(f);
11922 else
11923 rettv->vval.v_float = 0.0;
11924}
11925#endif
11926
11927static int
11928#ifdef __BORLANDC__
11929 _RTLENTRYF
11930#endif
11931 item_compare(const void *s1, const void *s2);
11932static int
11933#ifdef __BORLANDC__
11934 _RTLENTRYF
11935#endif
11936 item_compare2(const void *s1, const void *s2);
11937
11938/* struct used in the array that's given to qsort() */
11939typedef struct
11940{
11941 listitem_T *item;
11942 int idx;
11943} sortItem_T;
11944
11945/* struct storing information about current sort */
11946typedef struct
11947{
11948 int item_compare_ic;
11949 int item_compare_numeric;
11950 int item_compare_numbers;
11951#ifdef FEAT_FLOAT
11952 int item_compare_float;
11953#endif
11954 char_u *item_compare_func;
11955 partial_T *item_compare_partial;
11956 dict_T *item_compare_selfdict;
11957 int item_compare_func_err;
11958 int item_compare_keep_zero;
11959} sortinfo_T;
11960static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011961#define ITEM_COMPARE_FAIL 999
11962
11963/*
11964 * Compare functions for f_sort() and f_uniq() below.
11965 */
11966 static int
11967#ifdef __BORLANDC__
11968_RTLENTRYF
11969#endif
11970item_compare(const void *s1, const void *s2)
11971{
11972 sortItem_T *si1, *si2;
11973 typval_T *tv1, *tv2;
11974 char_u *p1, *p2;
11975 char_u *tofree1 = NULL, *tofree2 = NULL;
11976 int res;
11977 char_u numbuf1[NUMBUFLEN];
11978 char_u numbuf2[NUMBUFLEN];
11979
11980 si1 = (sortItem_T *)s1;
11981 si2 = (sortItem_T *)s2;
11982 tv1 = &si1->item->li_tv;
11983 tv2 = &si2->item->li_tv;
11984
11985 if (sortinfo->item_compare_numbers)
11986 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011987 varnumber_T v1 = tv_get_number(tv1);
11988 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011989
11990 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11991 }
11992
11993#ifdef FEAT_FLOAT
11994 if (sortinfo->item_compare_float)
11995 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011996 float_T v1 = tv_get_float(tv1);
11997 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011998
11999 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12000 }
12001#endif
12002
12003 /* tv2string() puts quotes around a string and allocates memory. Don't do
12004 * that for string variables. Use a single quote when comparing with a
12005 * non-string to do what the docs promise. */
12006 if (tv1->v_type == VAR_STRING)
12007 {
12008 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12009 p1 = (char_u *)"'";
12010 else
12011 p1 = tv1->vval.v_string;
12012 }
12013 else
12014 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12015 if (tv2->v_type == VAR_STRING)
12016 {
12017 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12018 p2 = (char_u *)"'";
12019 else
12020 p2 = tv2->vval.v_string;
12021 }
12022 else
12023 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12024 if (p1 == NULL)
12025 p1 = (char_u *)"";
12026 if (p2 == NULL)
12027 p2 = (char_u *)"";
12028 if (!sortinfo->item_compare_numeric)
12029 {
12030 if (sortinfo->item_compare_ic)
12031 res = STRICMP(p1, p2);
12032 else
12033 res = STRCMP(p1, p2);
12034 }
12035 else
12036 {
12037 double n1, n2;
12038 n1 = strtod((char *)p1, (char **)&p1);
12039 n2 = strtod((char *)p2, (char **)&p2);
12040 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12041 }
12042
12043 /* When the result would be zero, compare the item indexes. Makes the
12044 * sort stable. */
12045 if (res == 0 && !sortinfo->item_compare_keep_zero)
12046 res = si1->idx > si2->idx ? 1 : -1;
12047
12048 vim_free(tofree1);
12049 vim_free(tofree2);
12050 return res;
12051}
12052
12053 static int
12054#ifdef __BORLANDC__
12055_RTLENTRYF
12056#endif
12057item_compare2(const void *s1, const void *s2)
12058{
12059 sortItem_T *si1, *si2;
12060 int res;
12061 typval_T rettv;
12062 typval_T argv[3];
12063 int dummy;
12064 char_u *func_name;
12065 partial_T *partial = sortinfo->item_compare_partial;
12066
12067 /* shortcut after failure in previous call; compare all items equal */
12068 if (sortinfo->item_compare_func_err)
12069 return 0;
12070
12071 si1 = (sortItem_T *)s1;
12072 si2 = (sortItem_T *)s2;
12073
12074 if (partial == NULL)
12075 func_name = sortinfo->item_compare_func;
12076 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012077 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012078
12079 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12080 * in the copy without changing the original list items. */
12081 copy_tv(&si1->item->li_tv, &argv[0]);
12082 copy_tv(&si2->item->li_tv, &argv[1]);
12083
12084 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12085 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012086 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012087 partial, sortinfo->item_compare_selfdict);
12088 clear_tv(&argv[0]);
12089 clear_tv(&argv[1]);
12090
12091 if (res == FAIL)
12092 res = ITEM_COMPARE_FAIL;
12093 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012094 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012095 if (sortinfo->item_compare_func_err)
12096 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12097 clear_tv(&rettv);
12098
12099 /* When the result would be zero, compare the pointers themselves. Makes
12100 * the sort stable. */
12101 if (res == 0 && !sortinfo->item_compare_keep_zero)
12102 res = si1->idx > si2->idx ? 1 : -1;
12103
12104 return res;
12105}
12106
12107/*
12108 * "sort({list})" function
12109 */
12110 static void
12111do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12112{
12113 list_T *l;
12114 listitem_T *li;
12115 sortItem_T *ptrs;
12116 sortinfo_T *old_sortinfo;
12117 sortinfo_T info;
12118 long len;
12119 long i;
12120
12121 /* Pointer to current info struct used in compare function. Save and
12122 * restore the current one for nested calls. */
12123 old_sortinfo = sortinfo;
12124 sortinfo = &info;
12125
12126 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012127 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012128 else
12129 {
12130 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012131 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012132 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12133 TRUE))
12134 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012135 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012136
12137 len = list_len(l);
12138 if (len <= 1)
12139 goto theend; /* short list sorts pretty quickly */
12140
12141 info.item_compare_ic = FALSE;
12142 info.item_compare_numeric = FALSE;
12143 info.item_compare_numbers = FALSE;
12144#ifdef FEAT_FLOAT
12145 info.item_compare_float = FALSE;
12146#endif
12147 info.item_compare_func = NULL;
12148 info.item_compare_partial = NULL;
12149 info.item_compare_selfdict = NULL;
12150 if (argvars[1].v_type != VAR_UNKNOWN)
12151 {
12152 /* optional second argument: {func} */
12153 if (argvars[1].v_type == VAR_FUNC)
12154 info.item_compare_func = argvars[1].vval.v_string;
12155 else if (argvars[1].v_type == VAR_PARTIAL)
12156 info.item_compare_partial = argvars[1].vval.v_partial;
12157 else
12158 {
12159 int error = FALSE;
12160
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012161 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012162 if (error)
12163 goto theend; /* type error; errmsg already given */
12164 if (i == 1)
12165 info.item_compare_ic = TRUE;
12166 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012167 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012168 else if (i != 0)
12169 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012170 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012171 goto theend;
12172 }
12173 if (info.item_compare_func != NULL)
12174 {
12175 if (*info.item_compare_func == NUL)
12176 {
12177 /* empty string means default sort */
12178 info.item_compare_func = NULL;
12179 }
12180 else if (STRCMP(info.item_compare_func, "n") == 0)
12181 {
12182 info.item_compare_func = NULL;
12183 info.item_compare_numeric = TRUE;
12184 }
12185 else if (STRCMP(info.item_compare_func, "N") == 0)
12186 {
12187 info.item_compare_func = NULL;
12188 info.item_compare_numbers = TRUE;
12189 }
12190#ifdef FEAT_FLOAT
12191 else if (STRCMP(info.item_compare_func, "f") == 0)
12192 {
12193 info.item_compare_func = NULL;
12194 info.item_compare_float = TRUE;
12195 }
12196#endif
12197 else if (STRCMP(info.item_compare_func, "i") == 0)
12198 {
12199 info.item_compare_func = NULL;
12200 info.item_compare_ic = TRUE;
12201 }
12202 }
12203 }
12204
12205 if (argvars[2].v_type != VAR_UNKNOWN)
12206 {
12207 /* optional third argument: {dict} */
12208 if (argvars[2].v_type != VAR_DICT)
12209 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012210 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012211 goto theend;
12212 }
12213 info.item_compare_selfdict = argvars[2].vval.v_dict;
12214 }
12215 }
12216
12217 /* Make an array with each entry pointing to an item in the List. */
12218 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12219 if (ptrs == NULL)
12220 goto theend;
12221
12222 i = 0;
12223 if (sort)
12224 {
12225 /* sort(): ptrs will be the list to sort */
12226 for (li = l->lv_first; li != NULL; li = li->li_next)
12227 {
12228 ptrs[i].item = li;
12229 ptrs[i].idx = i;
12230 ++i;
12231 }
12232
12233 info.item_compare_func_err = FALSE;
12234 info.item_compare_keep_zero = FALSE;
12235 /* test the compare function */
12236 if ((info.item_compare_func != NULL
12237 || info.item_compare_partial != NULL)
12238 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12239 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012240 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012241 else
12242 {
12243 /* Sort the array with item pointers. */
12244 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12245 info.item_compare_func == NULL
12246 && info.item_compare_partial == NULL
12247 ? item_compare : item_compare2);
12248
12249 if (!info.item_compare_func_err)
12250 {
12251 /* Clear the List and append the items in sorted order. */
12252 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12253 l->lv_len = 0;
12254 for (i = 0; i < len; ++i)
12255 list_append(l, ptrs[i].item);
12256 }
12257 }
12258 }
12259 else
12260 {
12261 int (*item_compare_func_ptr)(const void *, const void *);
12262
12263 /* f_uniq(): ptrs will be a stack of items to remove */
12264 info.item_compare_func_err = FALSE;
12265 info.item_compare_keep_zero = TRUE;
12266 item_compare_func_ptr = info.item_compare_func != NULL
12267 || info.item_compare_partial != NULL
12268 ? item_compare2 : item_compare;
12269
12270 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12271 li = li->li_next)
12272 {
12273 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12274 == 0)
12275 ptrs[i++].item = li;
12276 if (info.item_compare_func_err)
12277 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012278 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012279 break;
12280 }
12281 }
12282
12283 if (!info.item_compare_func_err)
12284 {
12285 while (--i >= 0)
12286 {
12287 li = ptrs[i].item->li_next;
12288 ptrs[i].item->li_next = li->li_next;
12289 if (li->li_next != NULL)
12290 li->li_next->li_prev = ptrs[i].item;
12291 else
12292 l->lv_last = ptrs[i].item;
12293 list_fix_watch(l, li);
12294 listitem_free(li);
12295 l->lv_len--;
12296 }
12297 }
12298 }
12299
12300 vim_free(ptrs);
12301 }
12302theend:
12303 sortinfo = old_sortinfo;
12304}
12305
12306/*
12307 * "sort({list})" function
12308 */
12309 static void
12310f_sort(typval_T *argvars, typval_T *rettv)
12311{
12312 do_sort_uniq(argvars, rettv, TRUE);
12313}
12314
12315/*
12316 * "uniq({list})" function
12317 */
12318 static void
12319f_uniq(typval_T *argvars, typval_T *rettv)
12320{
12321 do_sort_uniq(argvars, rettv, FALSE);
12322}
12323
12324/*
12325 * "soundfold({word})" function
12326 */
12327 static void
12328f_soundfold(typval_T *argvars, typval_T *rettv)
12329{
12330 char_u *s;
12331
12332 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012333 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012334#ifdef FEAT_SPELL
12335 rettv->vval.v_string = eval_soundfold(s);
12336#else
12337 rettv->vval.v_string = vim_strsave(s);
12338#endif
12339}
12340
12341/*
12342 * "spellbadword()" function
12343 */
12344 static void
12345f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12346{
12347 char_u *word = (char_u *)"";
12348 hlf_T attr = HLF_COUNT;
12349 int len = 0;
12350
12351 if (rettv_list_alloc(rettv) == FAIL)
12352 return;
12353
12354#ifdef FEAT_SPELL
12355 if (argvars[0].v_type == VAR_UNKNOWN)
12356 {
12357 /* Find the start and length of the badly spelled word. */
12358 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12359 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012360 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012361 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012362 curwin->w_set_curswant = TRUE;
12363 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012364 }
12365 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12366 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012367 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012368 int capcol = -1;
12369
12370 if (str != NULL)
12371 {
12372 /* Check the argument for spelling. */
12373 while (*str != NUL)
12374 {
12375 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12376 if (attr != HLF_COUNT)
12377 {
12378 word = str;
12379 break;
12380 }
12381 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012382 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012383 }
12384 }
12385 }
12386#endif
12387
12388 list_append_string(rettv->vval.v_list, word, len);
12389 list_append_string(rettv->vval.v_list, (char_u *)(
12390 attr == HLF_SPB ? "bad" :
12391 attr == HLF_SPR ? "rare" :
12392 attr == HLF_SPL ? "local" :
12393 attr == HLF_SPC ? "caps" :
12394 ""), -1);
12395}
12396
12397/*
12398 * "spellsuggest()" function
12399 */
12400 static void
12401f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12402{
12403#ifdef FEAT_SPELL
12404 char_u *str;
12405 int typeerr = FALSE;
12406 int maxcount;
12407 garray_T ga;
12408 int i;
12409 listitem_T *li;
12410 int need_capital = FALSE;
12411#endif
12412
12413 if (rettv_list_alloc(rettv) == FAIL)
12414 return;
12415
12416#ifdef FEAT_SPELL
12417 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12418 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012419 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012420 if (argvars[1].v_type != VAR_UNKNOWN)
12421 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012422 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012423 if (maxcount <= 0)
12424 return;
12425 if (argvars[2].v_type != VAR_UNKNOWN)
12426 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012427 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012428 if (typeerr)
12429 return;
12430 }
12431 }
12432 else
12433 maxcount = 25;
12434
12435 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12436
12437 for (i = 0; i < ga.ga_len; ++i)
12438 {
12439 str = ((char_u **)ga.ga_data)[i];
12440
12441 li = listitem_alloc();
12442 if (li == NULL)
12443 vim_free(str);
12444 else
12445 {
12446 li->li_tv.v_type = VAR_STRING;
12447 li->li_tv.v_lock = 0;
12448 li->li_tv.vval.v_string = str;
12449 list_append(rettv->vval.v_list, li);
12450 }
12451 }
12452 ga_clear(&ga);
12453 }
12454#endif
12455}
12456
12457 static void
12458f_split(typval_T *argvars, typval_T *rettv)
12459{
12460 char_u *str;
12461 char_u *end;
12462 char_u *pat = NULL;
12463 regmatch_T regmatch;
12464 char_u patbuf[NUMBUFLEN];
12465 char_u *save_cpo;
12466 int match;
12467 colnr_T col = 0;
12468 int keepempty = FALSE;
12469 int typeerr = FALSE;
12470
12471 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12472 save_cpo = p_cpo;
12473 p_cpo = (char_u *)"";
12474
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012475 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012476 if (argvars[1].v_type != VAR_UNKNOWN)
12477 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012478 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012479 if (pat == NULL)
12480 typeerr = TRUE;
12481 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012482 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012483 }
12484 if (pat == NULL || *pat == NUL)
12485 pat = (char_u *)"[\\x01- ]\\+";
12486
12487 if (rettv_list_alloc(rettv) == FAIL)
12488 return;
12489 if (typeerr)
12490 return;
12491
12492 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12493 if (regmatch.regprog != NULL)
12494 {
12495 regmatch.rm_ic = FALSE;
12496 while (*str != NUL || keepempty)
12497 {
12498 if (*str == NUL)
12499 match = FALSE; /* empty item at the end */
12500 else
12501 match = vim_regexec_nl(&regmatch, str, col);
12502 if (match)
12503 end = regmatch.startp[0];
12504 else
12505 end = str + STRLEN(str);
12506 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12507 && *str != NUL && match && end < regmatch.endp[0]))
12508 {
12509 if (list_append_string(rettv->vval.v_list, str,
12510 (int)(end - str)) == FAIL)
12511 break;
12512 }
12513 if (!match)
12514 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012515 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012516 if (regmatch.endp[0] > str)
12517 col = 0;
12518 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012519 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012520 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012521 str = regmatch.endp[0];
12522 }
12523
12524 vim_regfree(regmatch.regprog);
12525 }
12526
12527 p_cpo = save_cpo;
12528}
12529
12530#ifdef FEAT_FLOAT
12531/*
12532 * "sqrt()" function
12533 */
12534 static void
12535f_sqrt(typval_T *argvars, typval_T *rettv)
12536{
12537 float_T f = 0.0;
12538
12539 rettv->v_type = VAR_FLOAT;
12540 if (get_float_arg(argvars, &f) == OK)
12541 rettv->vval.v_float = sqrt(f);
12542 else
12543 rettv->vval.v_float = 0.0;
12544}
12545
12546/*
12547 * "str2float()" function
12548 */
12549 static void
12550f_str2float(typval_T *argvars, typval_T *rettv)
12551{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012552 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012553 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012554
Bram Moolenaar08243d22017-01-10 16:12:29 +010012555 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012556 p = skipwhite(p + 1);
12557 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012558 if (isneg)
12559 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012560 rettv->v_type = VAR_FLOAT;
12561}
12562#endif
12563
12564/*
12565 * "str2nr()" function
12566 */
12567 static void
12568f_str2nr(typval_T *argvars, typval_T *rettv)
12569{
12570 int base = 10;
12571 char_u *p;
12572 varnumber_T n;
12573 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012574 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575
12576 if (argvars[1].v_type != VAR_UNKNOWN)
12577 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012578 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012579 if (base != 2 && base != 8 && base != 10 && base != 16)
12580 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012581 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012582 return;
12583 }
12584 }
12585
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012586 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012587 isneg = (*p == '-');
12588 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012589 p = skipwhite(p + 1);
12590 switch (base)
12591 {
12592 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12593 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12594 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12595 default: what = 0;
12596 }
12597 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012598 if (isneg)
12599 rettv->vval.v_number = -n;
12600 else
12601 rettv->vval.v_number = n;
12602
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012603}
12604
12605#ifdef HAVE_STRFTIME
12606/*
12607 * "strftime({format}[, {time}])" function
12608 */
12609 static void
12610f_strftime(typval_T *argvars, typval_T *rettv)
12611{
12612 char_u result_buf[256];
12613 struct tm *curtime;
12614 time_t seconds;
12615 char_u *p;
12616
12617 rettv->v_type = VAR_STRING;
12618
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012619 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012620 if (argvars[1].v_type == VAR_UNKNOWN)
12621 seconds = time(NULL);
12622 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012623 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012624 curtime = localtime(&seconds);
12625 /* MSVC returns NULL for an invalid value of seconds. */
12626 if (curtime == NULL)
12627 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12628 else
12629 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012630 vimconv_T conv;
12631 char_u *enc;
12632
12633 conv.vc_type = CONV_NONE;
12634 enc = enc_locale();
12635 convert_setup(&conv, p_enc, enc);
12636 if (conv.vc_type != CONV_NONE)
12637 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012638 if (p != NULL)
12639 (void)strftime((char *)result_buf, sizeof(result_buf),
12640 (char *)p, curtime);
12641 else
12642 result_buf[0] = NUL;
12643
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012644 if (conv.vc_type != CONV_NONE)
12645 vim_free(p);
12646 convert_setup(&conv, enc, p_enc);
12647 if (conv.vc_type != CONV_NONE)
12648 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12649 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012650 rettv->vval.v_string = vim_strsave(result_buf);
12651
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012652 /* Release conversion descriptors */
12653 convert_setup(&conv, NULL, NULL);
12654 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012655 }
12656}
12657#endif
12658
12659/*
12660 * "strgetchar()" function
12661 */
12662 static void
12663f_strgetchar(typval_T *argvars, typval_T *rettv)
12664{
12665 char_u *str;
12666 int len;
12667 int error = FALSE;
12668 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012669 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012670
12671 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012672 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012673 if (str == NULL)
12674 return;
12675 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012676 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012677 if (error)
12678 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012679
Bram Moolenaar13505972019-01-24 15:04:48 +010012680 while (charidx >= 0 && byteidx < len)
12681 {
12682 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012683 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012684 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12685 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012686 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012687 --charidx;
12688 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012689 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012690}
12691
12692/*
12693 * "stridx()" function
12694 */
12695 static void
12696f_stridx(typval_T *argvars, typval_T *rettv)
12697{
12698 char_u buf[NUMBUFLEN];
12699 char_u *needle;
12700 char_u *haystack;
12701 char_u *save_haystack;
12702 char_u *pos;
12703 int start_idx;
12704
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012705 needle = tv_get_string_chk(&argvars[1]);
12706 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012707 rettv->vval.v_number = -1;
12708 if (needle == NULL || haystack == NULL)
12709 return; /* type error; errmsg already given */
12710
12711 if (argvars[2].v_type != VAR_UNKNOWN)
12712 {
12713 int error = FALSE;
12714
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012715 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012716 if (error || start_idx >= (int)STRLEN(haystack))
12717 return;
12718 if (start_idx >= 0)
12719 haystack += start_idx;
12720 }
12721
12722 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12723 if (pos != NULL)
12724 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12725}
12726
12727/*
12728 * "string()" function
12729 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012730 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012731f_string(typval_T *argvars, typval_T *rettv)
12732{
12733 char_u *tofree;
12734 char_u numbuf[NUMBUFLEN];
12735
12736 rettv->v_type = VAR_STRING;
12737 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12738 get_copyID());
12739 /* Make a copy if we have a value but it's not in allocated memory. */
12740 if (rettv->vval.v_string != NULL && tofree == NULL)
12741 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12742}
12743
12744/*
12745 * "strlen()" function
12746 */
12747 static void
12748f_strlen(typval_T *argvars, typval_T *rettv)
12749{
12750 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012751 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012752}
12753
12754/*
12755 * "strchars()" function
12756 */
12757 static void
12758f_strchars(typval_T *argvars, typval_T *rettv)
12759{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012760 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012762 varnumber_T len = 0;
12763 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012764
12765 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012766 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012767 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012768 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012769 else
12770 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12772 while (*s != NUL)
12773 {
12774 func_mb_ptr2char_adv(&s);
12775 ++len;
12776 }
12777 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012778 }
12779}
12780
12781/*
12782 * "strdisplaywidth()" function
12783 */
12784 static void
12785f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12786{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012787 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012788 int col = 0;
12789
12790 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012791 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012792
12793 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12794}
12795
12796/*
12797 * "strwidth()" function
12798 */
12799 static void
12800f_strwidth(typval_T *argvars, typval_T *rettv)
12801{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012802 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012803
Bram Moolenaar13505972019-01-24 15:04:48 +010012804 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012805}
12806
12807/*
12808 * "strcharpart()" function
12809 */
12810 static void
12811f_strcharpart(typval_T *argvars, typval_T *rettv)
12812{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012813 char_u *p;
12814 int nchar;
12815 int nbyte = 0;
12816 int charlen;
12817 int len = 0;
12818 int slen;
12819 int error = FALSE;
12820
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012821 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012822 slen = (int)STRLEN(p);
12823
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012824 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012825 if (!error)
12826 {
12827 if (nchar > 0)
12828 while (nchar > 0 && nbyte < slen)
12829 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012830 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012831 --nchar;
12832 }
12833 else
12834 nbyte = nchar;
12835 if (argvars[2].v_type != VAR_UNKNOWN)
12836 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012837 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012838 while (charlen > 0 && nbyte + len < slen)
12839 {
12840 int off = nbyte + len;
12841
12842 if (off < 0)
12843 len += 1;
12844 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012845 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012846 --charlen;
12847 }
12848 }
12849 else
12850 len = slen - nbyte; /* default: all bytes that are available. */
12851 }
12852
12853 /*
12854 * Only return the overlap between the specified part and the actual
12855 * string.
12856 */
12857 if (nbyte < 0)
12858 {
12859 len += nbyte;
12860 nbyte = 0;
12861 }
12862 else if (nbyte > slen)
12863 nbyte = slen;
12864 if (len < 0)
12865 len = 0;
12866 else if (nbyte + len > slen)
12867 len = slen - nbyte;
12868
12869 rettv->v_type = VAR_STRING;
12870 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012871}
12872
12873/*
12874 * "strpart()" function
12875 */
12876 static void
12877f_strpart(typval_T *argvars, typval_T *rettv)
12878{
12879 char_u *p;
12880 int n;
12881 int len;
12882 int slen;
12883 int error = FALSE;
12884
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012885 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012886 slen = (int)STRLEN(p);
12887
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012888 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012889 if (error)
12890 len = 0;
12891 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012892 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012893 else
12894 len = slen - n; /* default len: all bytes that are available. */
12895
12896 /*
12897 * Only return the overlap between the specified part and the actual
12898 * string.
12899 */
12900 if (n < 0)
12901 {
12902 len += n;
12903 n = 0;
12904 }
12905 else if (n > slen)
12906 n = slen;
12907 if (len < 0)
12908 len = 0;
12909 else if (n + len > slen)
12910 len = slen - n;
12911
12912 rettv->v_type = VAR_STRING;
12913 rettv->vval.v_string = vim_strnsave(p + n, len);
12914}
12915
12916/*
12917 * "strridx()" function
12918 */
12919 static void
12920f_strridx(typval_T *argvars, typval_T *rettv)
12921{
12922 char_u buf[NUMBUFLEN];
12923 char_u *needle;
12924 char_u *haystack;
12925 char_u *rest;
12926 char_u *lastmatch = NULL;
12927 int haystack_len, end_idx;
12928
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012929 needle = tv_get_string_chk(&argvars[1]);
12930 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012931
12932 rettv->vval.v_number = -1;
12933 if (needle == NULL || haystack == NULL)
12934 return; /* type error; errmsg already given */
12935
12936 haystack_len = (int)STRLEN(haystack);
12937 if (argvars[2].v_type != VAR_UNKNOWN)
12938 {
12939 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012940 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012941 if (end_idx < 0)
12942 return; /* can never find a match */
12943 }
12944 else
12945 end_idx = haystack_len;
12946
12947 if (*needle == NUL)
12948 {
12949 /* Empty string matches past the end. */
12950 lastmatch = haystack + end_idx;
12951 }
12952 else
12953 {
12954 for (rest = haystack; *rest != '\0'; ++rest)
12955 {
12956 rest = (char_u *)strstr((char *)rest, (char *)needle);
12957 if (rest == NULL || rest > haystack + end_idx)
12958 break;
12959 lastmatch = rest;
12960 }
12961 }
12962
12963 if (lastmatch == NULL)
12964 rettv->vval.v_number = -1;
12965 else
12966 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12967}
12968
12969/*
12970 * "strtrans()" function
12971 */
12972 static void
12973f_strtrans(typval_T *argvars, typval_T *rettv)
12974{
12975 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012976 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012977}
12978
12979/*
12980 * "submatch()" function
12981 */
12982 static void
12983f_submatch(typval_T *argvars, typval_T *rettv)
12984{
12985 int error = FALSE;
12986 int no;
12987 int retList = 0;
12988
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012989 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012990 if (error)
12991 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012992 if (no < 0 || no >= NSUBEXP)
12993 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012994 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010012995 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012996 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012997 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012998 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012999 if (error)
13000 return;
13001
13002 if (retList == 0)
13003 {
13004 rettv->v_type = VAR_STRING;
13005 rettv->vval.v_string = reg_submatch(no);
13006 }
13007 else
13008 {
13009 rettv->v_type = VAR_LIST;
13010 rettv->vval.v_list = reg_submatch_list(no);
13011 }
13012}
13013
13014/*
13015 * "substitute()" function
13016 */
13017 static void
13018f_substitute(typval_T *argvars, typval_T *rettv)
13019{
13020 char_u patbuf[NUMBUFLEN];
13021 char_u subbuf[NUMBUFLEN];
13022 char_u flagsbuf[NUMBUFLEN];
13023
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013024 char_u *str = tv_get_string_chk(&argvars[0]);
13025 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013026 char_u *sub = NULL;
13027 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013028 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013029
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013030 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13031 expr = &argvars[2];
13032 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013033 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013034
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013035 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013036 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13037 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013038 rettv->vval.v_string = NULL;
13039 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013040 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013041}
13042
13043/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013044 * "swapinfo(swap_filename)" function
13045 */
13046 static void
13047f_swapinfo(typval_T *argvars, typval_T *rettv)
13048{
13049 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013050 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013051}
13052
13053/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013054 * "swapname(expr)" function
13055 */
13056 static void
13057f_swapname(typval_T *argvars, typval_T *rettv)
13058{
13059 buf_T *buf;
13060
13061 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013062 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013063 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13064 || buf->b_ml.ml_mfp->mf_fname == NULL)
13065 rettv->vval.v_string = NULL;
13066 else
13067 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13068}
13069
13070/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013071 * "synID(lnum, col, trans)" function
13072 */
13073 static void
13074f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13075{
13076 int id = 0;
13077#ifdef FEAT_SYN_HL
13078 linenr_T lnum;
13079 colnr_T col;
13080 int trans;
13081 int transerr = FALSE;
13082
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013083 lnum = tv_get_lnum(argvars); /* -1 on type error */
13084 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13085 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013086
13087 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13088 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13089 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13090#endif
13091
13092 rettv->vval.v_number = id;
13093}
13094
13095/*
13096 * "synIDattr(id, what [, mode])" function
13097 */
13098 static void
13099f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13100{
13101 char_u *p = NULL;
13102#ifdef FEAT_SYN_HL
13103 int id;
13104 char_u *what;
13105 char_u *mode;
13106 char_u modebuf[NUMBUFLEN];
13107 int modec;
13108
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013109 id = (int)tv_get_number(&argvars[0]);
13110 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013111 if (argvars[2].v_type != VAR_UNKNOWN)
13112 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013113 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013114 modec = TOLOWER_ASC(mode[0]);
13115 if (modec != 't' && modec != 'c' && modec != 'g')
13116 modec = 0; /* replace invalid with current */
13117 }
13118 else
13119 {
13120#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13121 if (USE_24BIT)
13122 modec = 'g';
13123 else
13124#endif
13125 if (t_colors > 1)
13126 modec = 'c';
13127 else
13128 modec = 't';
13129 }
13130
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013131 switch (TOLOWER_ASC(what[0]))
13132 {
13133 case 'b':
13134 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13135 p = highlight_color(id, what, modec);
13136 else /* bold */
13137 p = highlight_has_attr(id, HL_BOLD, modec);
13138 break;
13139
13140 case 'f': /* fg[#] or font */
13141 p = highlight_color(id, what, modec);
13142 break;
13143
13144 case 'i':
13145 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13146 p = highlight_has_attr(id, HL_INVERSE, modec);
13147 else /* italic */
13148 p = highlight_has_attr(id, HL_ITALIC, modec);
13149 break;
13150
13151 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013152 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013153 break;
13154
13155 case 'r': /* reverse */
13156 p = highlight_has_attr(id, HL_INVERSE, modec);
13157 break;
13158
13159 case 's':
13160 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13161 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013162 /* strikeout */
13163 else if (TOLOWER_ASC(what[1]) == 't' &&
13164 TOLOWER_ASC(what[2]) == 'r')
13165 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013166 else /* standout */
13167 p = highlight_has_attr(id, HL_STANDOUT, modec);
13168 break;
13169
13170 case 'u':
13171 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13172 /* underline */
13173 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13174 else
13175 /* undercurl */
13176 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13177 break;
13178 }
13179
13180 if (p != NULL)
13181 p = vim_strsave(p);
13182#endif
13183 rettv->v_type = VAR_STRING;
13184 rettv->vval.v_string = p;
13185}
13186
13187/*
13188 * "synIDtrans(id)" function
13189 */
13190 static void
13191f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13192{
13193 int id;
13194
13195#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013196 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013197
13198 if (id > 0)
13199 id = syn_get_final_id(id);
13200 else
13201#endif
13202 id = 0;
13203
13204 rettv->vval.v_number = id;
13205}
13206
13207/*
13208 * "synconcealed(lnum, col)" function
13209 */
13210 static void
13211f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13212{
13213#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13214 linenr_T lnum;
13215 colnr_T col;
13216 int syntax_flags = 0;
13217 int cchar;
13218 int matchid = 0;
13219 char_u str[NUMBUFLEN];
13220#endif
13221
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013222 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013223
13224#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013225 lnum = tv_get_lnum(argvars); /* -1 on type error */
13226 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013227
13228 vim_memset(str, NUL, sizeof(str));
13229
13230 if (rettv_list_alloc(rettv) != FAIL)
13231 {
13232 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13233 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13234 && curwin->w_p_cole > 0)
13235 {
13236 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13237 syntax_flags = get_syntax_info(&matchid);
13238
13239 /* get the conceal character */
13240 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13241 {
13242 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013243 if (cchar == NUL && curwin->w_p_cole == 1)
13244 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013245 if (cchar != NUL)
13246 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013247 if (has_mbyte)
13248 (*mb_char2bytes)(cchar, str);
13249 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013250 str[0] = cchar;
13251 }
13252 }
13253 }
13254
13255 list_append_number(rettv->vval.v_list,
13256 (syntax_flags & HL_CONCEAL) != 0);
13257 /* -1 to auto-determine strlen */
13258 list_append_string(rettv->vval.v_list, str, -1);
13259 list_append_number(rettv->vval.v_list, matchid);
13260 }
13261#endif
13262}
13263
13264/*
13265 * "synstack(lnum, col)" function
13266 */
13267 static void
13268f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13269{
13270#ifdef FEAT_SYN_HL
13271 linenr_T lnum;
13272 colnr_T col;
13273 int i;
13274 int id;
13275#endif
13276
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013277 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013278
13279#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013280 lnum = tv_get_lnum(argvars); /* -1 on type error */
13281 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013282
13283 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13284 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13285 && rettv_list_alloc(rettv) != FAIL)
13286 {
13287 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13288 for (i = 0; ; ++i)
13289 {
13290 id = syn_get_stack_item(i);
13291 if (id < 0)
13292 break;
13293 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13294 break;
13295 }
13296 }
13297#endif
13298}
13299
13300 static void
13301get_cmd_output_as_rettv(
13302 typval_T *argvars,
13303 typval_T *rettv,
13304 int retlist)
13305{
13306 char_u *res = NULL;
13307 char_u *p;
13308 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013309 int err = FALSE;
13310 FILE *fd;
13311 list_T *list = NULL;
13312 int flags = SHELL_SILENT;
13313
13314 rettv->v_type = VAR_STRING;
13315 rettv->vval.v_string = NULL;
13316 if (check_restricted() || check_secure())
13317 goto errret;
13318
13319 if (argvars[1].v_type != VAR_UNKNOWN)
13320 {
13321 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013322 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013323 * command.
13324 */
13325 if ((infile = vim_tempname('i', TRUE)) == NULL)
13326 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013327 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013328 goto errret;
13329 }
13330
13331 fd = mch_fopen((char *)infile, WRITEBIN);
13332 if (fd == NULL)
13333 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013334 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013335 goto errret;
13336 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013337 if (argvars[1].v_type == VAR_NUMBER)
13338 {
13339 linenr_T lnum;
13340 buf_T *buf;
13341
13342 buf = buflist_findnr(argvars[1].vval.v_number);
13343 if (buf == NULL)
13344 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013345 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013346 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013347 goto errret;
13348 }
13349
13350 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13351 {
13352 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13353 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13354 {
13355 err = TRUE;
13356 break;
13357 }
13358 if (putc(NL, fd) == EOF)
13359 {
13360 err = TRUE;
13361 break;
13362 }
13363 }
13364 }
13365 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013366 {
13367 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13368 err = TRUE;
13369 }
13370 else
13371 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013372 size_t len;
13373 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013374
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013375 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013376 if (p == NULL)
13377 {
13378 fclose(fd);
13379 goto errret; /* type error; errmsg already given */
13380 }
13381 len = STRLEN(p);
13382 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13383 err = TRUE;
13384 }
13385 if (fclose(fd) != 0)
13386 err = TRUE;
13387 if (err)
13388 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013389 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013390 goto errret;
13391 }
13392 }
13393
13394 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13395 * echoes typeahead, that messes up the display. */
13396 if (!msg_silent)
13397 flags += SHELL_COOKED;
13398
13399 if (retlist)
13400 {
13401 int len;
13402 listitem_T *li;
13403 char_u *s = NULL;
13404 char_u *start;
13405 char_u *end;
13406 int i;
13407
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013408 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013409 if (res == NULL)
13410 goto errret;
13411
13412 list = list_alloc();
13413 if (list == NULL)
13414 goto errret;
13415
13416 for (i = 0; i < len; ++i)
13417 {
13418 start = res + i;
13419 while (i < len && res[i] != NL)
13420 ++i;
13421 end = res + i;
13422
13423 s = alloc((unsigned)(end - start + 1));
13424 if (s == NULL)
13425 goto errret;
13426
13427 for (p = s; start < end; ++p, ++start)
13428 *p = *start == NUL ? NL : *start;
13429 *p = NUL;
13430
13431 li = listitem_alloc();
13432 if (li == NULL)
13433 {
13434 vim_free(s);
13435 goto errret;
13436 }
13437 li->li_tv.v_type = VAR_STRING;
13438 li->li_tv.v_lock = 0;
13439 li->li_tv.vval.v_string = s;
13440 list_append(list, li);
13441 }
13442
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013443 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013444 list = NULL;
13445 }
13446 else
13447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013448 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013449#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013450 /* translate <CR><NL> into <NL> */
13451 if (res != NULL)
13452 {
13453 char_u *s, *d;
13454
13455 d = res;
13456 for (s = res; *s; ++s)
13457 {
13458 if (s[0] == CAR && s[1] == NL)
13459 ++s;
13460 *d++ = *s;
13461 }
13462 *d = NUL;
13463 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013464#endif
13465 rettv->vval.v_string = res;
13466 res = NULL;
13467 }
13468
13469errret:
13470 if (infile != NULL)
13471 {
13472 mch_remove(infile);
13473 vim_free(infile);
13474 }
13475 if (res != NULL)
13476 vim_free(res);
13477 if (list != NULL)
13478 list_free(list);
13479}
13480
13481/*
13482 * "system()" function
13483 */
13484 static void
13485f_system(typval_T *argvars, typval_T *rettv)
13486{
13487 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13488}
13489
13490/*
13491 * "systemlist()" function
13492 */
13493 static void
13494f_systemlist(typval_T *argvars, typval_T *rettv)
13495{
13496 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13497}
13498
13499/*
13500 * "tabpagebuflist()" function
13501 */
13502 static void
13503f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13504{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013505 tabpage_T *tp;
13506 win_T *wp = NULL;
13507
13508 if (argvars[0].v_type == VAR_UNKNOWN)
13509 wp = firstwin;
13510 else
13511 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013512 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013513 if (tp != NULL)
13514 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13515 }
13516 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13517 {
13518 for (; wp != NULL; wp = wp->w_next)
13519 if (list_append_number(rettv->vval.v_list,
13520 wp->w_buffer->b_fnum) == FAIL)
13521 break;
13522 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013523}
13524
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013525/*
13526 * "tabpagenr()" function
13527 */
13528 static void
13529f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13530{
13531 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013532 char_u *arg;
13533
13534 if (argvars[0].v_type != VAR_UNKNOWN)
13535 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013536 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013537 nr = 0;
13538 if (arg != NULL)
13539 {
13540 if (STRCMP(arg, "$") == 0)
13541 nr = tabpage_index(NULL) - 1;
13542 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013543 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013544 }
13545 }
13546 else
13547 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013548 rettv->vval.v_number = nr;
13549}
13550
13551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013552/*
13553 * Common code for tabpagewinnr() and winnr().
13554 */
13555 static int
13556get_winnr(tabpage_T *tp, typval_T *argvar)
13557{
13558 win_T *twin;
13559 int nr = 1;
13560 win_T *wp;
13561 char_u *arg;
13562
13563 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13564 if (argvar->v_type != VAR_UNKNOWN)
13565 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013566 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013567 if (arg == NULL)
13568 nr = 0; /* type error; errmsg already given */
13569 else if (STRCMP(arg, "$") == 0)
13570 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13571 else if (STRCMP(arg, "#") == 0)
13572 {
13573 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13574 if (twin == NULL)
13575 nr = 0;
13576 }
13577 else
13578 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013579 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013580 nr = 0;
13581 }
13582 }
13583
13584 if (nr > 0)
13585 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13586 wp != twin; wp = wp->w_next)
13587 {
13588 if (wp == NULL)
13589 {
13590 /* didn't find it in this tabpage */
13591 nr = 0;
13592 break;
13593 }
13594 ++nr;
13595 }
13596 return nr;
13597}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013598
13599/*
13600 * "tabpagewinnr()" function
13601 */
13602 static void
13603f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13604{
13605 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013606 tabpage_T *tp;
13607
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013608 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013609 if (tp == NULL)
13610 nr = 0;
13611 else
13612 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013613 rettv->vval.v_number = nr;
13614}
13615
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013616/*
13617 * "tagfiles()" function
13618 */
13619 static void
13620f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13621{
13622 char_u *fname;
13623 tagname_T tn;
13624 int first;
13625
13626 if (rettv_list_alloc(rettv) == FAIL)
13627 return;
13628 fname = alloc(MAXPATHL);
13629 if (fname == NULL)
13630 return;
13631
13632 for (first = TRUE; ; first = FALSE)
13633 if (get_tagfname(&tn, first, fname) == FAIL
13634 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13635 break;
13636 tagname_free(&tn);
13637 vim_free(fname);
13638}
13639
13640/*
13641 * "taglist()" function
13642 */
13643 static void
13644f_taglist(typval_T *argvars, typval_T *rettv)
13645{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013646 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013647 char_u *tag_pattern;
13648
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013649 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013650
13651 rettv->vval.v_number = FALSE;
13652 if (*tag_pattern == NUL)
13653 return;
13654
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013655 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013656 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013657 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013658 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013659}
13660
13661/*
13662 * "tempname()" function
13663 */
13664 static void
13665f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13666{
13667 static int x = 'A';
13668
13669 rettv->v_type = VAR_STRING;
13670 rettv->vval.v_string = vim_tempname(x, FALSE);
13671
13672 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13673 * names. Skip 'I' and 'O', they are used for shell redirection. */
13674 do
13675 {
13676 if (x == 'Z')
13677 x = '0';
13678 else if (x == '9')
13679 x = 'A';
13680 else
13681 {
13682#ifdef EBCDIC
13683 if (x == 'I')
13684 x = 'J';
13685 else if (x == 'R')
13686 x = 'S';
13687 else
13688#endif
13689 ++x;
13690 }
13691 } while (x == 'I' || x == 'O');
13692}
13693
13694#ifdef FEAT_FLOAT
13695/*
13696 * "tan()" function
13697 */
13698 static void
13699f_tan(typval_T *argvars, typval_T *rettv)
13700{
13701 float_T f = 0.0;
13702
13703 rettv->v_type = VAR_FLOAT;
13704 if (get_float_arg(argvars, &f) == OK)
13705 rettv->vval.v_float = tan(f);
13706 else
13707 rettv->vval.v_float = 0.0;
13708}
13709
13710/*
13711 * "tanh()" function
13712 */
13713 static void
13714f_tanh(typval_T *argvars, typval_T *rettv)
13715{
13716 float_T f = 0.0;
13717
13718 rettv->v_type = VAR_FLOAT;
13719 if (get_float_arg(argvars, &f) == OK)
13720 rettv->vval.v_float = tanh(f);
13721 else
13722 rettv->vval.v_float = 0.0;
13723}
13724#endif
13725
13726/*
13727 * "test_alloc_fail(id, countdown, repeat)" function
13728 */
13729 static void
13730f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13731{
13732 if (argvars[0].v_type != VAR_NUMBER
13733 || argvars[0].vval.v_number <= 0
13734 || argvars[1].v_type != VAR_NUMBER
13735 || argvars[1].vval.v_number < 0
13736 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013737 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013738 else
13739 {
13740 alloc_fail_id = argvars[0].vval.v_number;
13741 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013742 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013743 alloc_fail_countdown = argvars[1].vval.v_number;
13744 alloc_fail_repeat = argvars[2].vval.v_number;
13745 did_outofmem_msg = FALSE;
13746 }
13747}
13748
13749/*
13750 * "test_autochdir()"
13751 */
13752 static void
13753f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13754{
13755#if defined(FEAT_AUTOCHDIR)
13756 test_autochdir = TRUE;
13757#endif
13758}
13759
13760/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013761 * "test_feedinput()"
13762 */
13763 static void
13764f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13765{
13766#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013767 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013768
13769 if (val != NULL)
13770 {
13771 trash_input_buf();
13772 add_to_input_buf_csi(val, (int)STRLEN(val));
13773 }
13774#endif
13775}
13776
13777/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013778 * "test_option_not_set({name})" function
13779 */
13780 static void
13781f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13782{
13783 char_u *name = (char_u *)"";
13784
13785 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013786 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013787 else
13788 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013789 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013790 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013791 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013792 }
13793}
13794
13795/*
13796 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013797 */
13798 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013799f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013800{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013801 char_u *name = (char_u *)"";
13802 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013803 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013804
13805 if (argvars[0].v_type != VAR_STRING
13806 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013807 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013808 else
13809 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013810 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013811 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013812
13813 if (STRCMP(name, (char_u *)"redraw") == 0)
13814 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013815 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13816 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013817 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13818 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013819 else if (STRCMP(name, (char_u *)"starting") == 0)
13820 {
13821 if (val)
13822 {
13823 if (save_starting < 0)
13824 save_starting = starting;
13825 starting = 0;
13826 }
13827 else
13828 {
13829 starting = save_starting;
13830 save_starting = -1;
13831 }
13832 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013833 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13834 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013835 else if (STRCMP(name, (char_u *)"ALL") == 0)
13836 {
13837 disable_char_avail_for_testing = FALSE;
13838 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013839 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013840 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013841 if (save_starting >= 0)
13842 {
13843 starting = save_starting;
13844 save_starting = -1;
13845 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013846 }
13847 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013848 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013849 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013850}
13851
13852/*
13853 * "test_garbagecollect_now()" function
13854 */
13855 static void
13856f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13857{
13858 /* This is dangerous, any Lists and Dicts used internally may be freed
13859 * while still in use. */
13860 garbage_collect(TRUE);
13861}
13862
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013863/*
13864 * "test_ignore_error()" function
13865 */
13866 static void
13867f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13868{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013869 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013870}
13871
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010013872 static void
13873f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
13874{
13875 rettv->v_type = VAR_BLOB;
13876 rettv->vval.v_blob = NULL;
13877}
13878
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013879#ifdef FEAT_JOB_CHANNEL
13880 static void
13881f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13882{
13883 rettv->v_type = VAR_CHANNEL;
13884 rettv->vval.v_channel = NULL;
13885}
13886#endif
13887
13888 static void
13889f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13890{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013891 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013892}
13893
13894#ifdef FEAT_JOB_CHANNEL
13895 static void
13896f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13897{
13898 rettv->v_type = VAR_JOB;
13899 rettv->vval.v_job = NULL;
13900}
13901#endif
13902
13903 static void
13904f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13905{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013906 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013907}
13908
13909 static void
13910f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13911{
13912 rettv->v_type = VAR_PARTIAL;
13913 rettv->vval.v_partial = NULL;
13914}
13915
13916 static void
13917f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13918{
13919 rettv->v_type = VAR_STRING;
13920 rettv->vval.v_string = NULL;
13921}
13922
Bram Moolenaarab186732018-09-14 21:27:06 +020013923#ifdef FEAT_GUI
13924 static void
13925f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13926{
13927 char_u *which;
13928 long value;
13929 int dragging;
13930 scrollbar_T *sb = NULL;
13931
13932 if (argvars[0].v_type != VAR_STRING
13933 || (argvars[1].v_type) != VAR_NUMBER
13934 || (argvars[2].v_type) != VAR_NUMBER)
13935 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013936 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020013937 return;
13938 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013939 which = tv_get_string(&argvars[0]);
13940 value = tv_get_number(&argvars[1]);
13941 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020013942
13943 if (STRCMP(which, "left") == 0)
13944 sb = &curwin->w_scrollbars[SBAR_LEFT];
13945 else if (STRCMP(which, "right") == 0)
13946 sb = &curwin->w_scrollbars[SBAR_RIGHT];
13947 else if (STRCMP(which, "hor") == 0)
13948 sb = &gui.bottom_sbar;
13949 if (sb == NULL)
13950 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013951 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020013952 return;
13953 }
13954 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020013955# ifndef USE_ON_FLY_SCROLL
13956 // need to loop through normal_cmd() to handle the scroll events
13957 exec_normal(FALSE, TRUE, FALSE);
13958# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020013959}
13960#endif
13961
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013962 static void
13963f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13964{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013965 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013966}
13967
13968#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13969/*
13970 * Get a callback from "arg". It can be a Funcref or a function name.
13971 * When "arg" is zero return an empty string.
13972 * Return NULL for an invalid argument.
13973 */
13974 char_u *
13975get_callback(typval_T *arg, partial_T **pp)
13976{
13977 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13978 {
13979 *pp = arg->vval.v_partial;
13980 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013981 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013982 }
13983 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020013984 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013985 {
13986 func_ref(arg->vval.v_string);
13987 return arg->vval.v_string;
13988 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013989 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13990 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013991 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013992 return NULL;
13993}
13994
13995/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020013996 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013997 */
13998 void
13999free_callback(char_u *callback, partial_T *partial)
14000{
14001 if (partial != NULL)
14002 partial_unref(partial);
14003 else if (callback != NULL)
14004 {
14005 func_unref(callback);
14006 vim_free(callback);
14007 }
14008}
14009#endif
14010
14011#ifdef FEAT_TIMERS
14012/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014013 * "timer_info([timer])" function
14014 */
14015 static void
14016f_timer_info(typval_T *argvars, typval_T *rettv)
14017{
14018 timer_T *timer = NULL;
14019
14020 if (rettv_list_alloc(rettv) != OK)
14021 return;
14022 if (argvars[0].v_type != VAR_UNKNOWN)
14023 {
14024 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014025 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014026 else
14027 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014028 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014029 if (timer != NULL)
14030 add_timer_info(rettv, timer);
14031 }
14032 }
14033 else
14034 add_timer_info_all(rettv);
14035}
14036
14037/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014038 * "timer_pause(timer, paused)" function
14039 */
14040 static void
14041f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14042{
14043 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014044 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014045
14046 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014047 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014048 else
14049 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014050 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014051 if (timer != NULL)
14052 timer->tr_paused = paused;
14053 }
14054}
14055
14056/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014057 * "timer_start(time, callback [, options])" function
14058 */
14059 static void
14060f_timer_start(typval_T *argvars, typval_T *rettv)
14061{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014062 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014063 timer_T *timer;
14064 int repeat = 0;
14065 char_u *callback;
14066 dict_T *dict;
14067 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014068
Bram Moolenaar75537a92016-09-05 22:45:28 +020014069 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014070 if (check_secure())
14071 return;
14072 if (argvars[2].v_type != VAR_UNKNOWN)
14073 {
14074 if (argvars[2].v_type != VAR_DICT
14075 || (dict = argvars[2].vval.v_dict) == NULL)
14076 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014077 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014078 return;
14079 }
14080 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014081 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014082 }
14083
Bram Moolenaar75537a92016-09-05 22:45:28 +020014084 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014085 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014086 return;
14087
14088 timer = create_timer(msec, repeat);
14089 if (timer == NULL)
14090 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014091 else
14092 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014093 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014094 timer->tr_callback = vim_strsave(callback);
14095 else
14096 /* pointer into the partial */
14097 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014098 timer->tr_partial = partial;
14099 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014100 }
14101}
14102
14103/*
14104 * "timer_stop(timer)" function
14105 */
14106 static void
14107f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14108{
14109 timer_T *timer;
14110
14111 if (argvars[0].v_type != VAR_NUMBER)
14112 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014113 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014114 return;
14115 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014116 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014117 if (timer != NULL)
14118 stop_timer(timer);
14119}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014120
14121/*
14122 * "timer_stopall()" function
14123 */
14124 static void
14125f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14126{
14127 stop_all_timers();
14128}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014129#endif
14130
14131/*
14132 * "tolower(string)" function
14133 */
14134 static void
14135f_tolower(typval_T *argvars, typval_T *rettv)
14136{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014137 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014138 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014139}
14140
14141/*
14142 * "toupper(string)" function
14143 */
14144 static void
14145f_toupper(typval_T *argvars, typval_T *rettv)
14146{
14147 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014148 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014149}
14150
14151/*
14152 * "tr(string, fromstr, tostr)" function
14153 */
14154 static void
14155f_tr(typval_T *argvars, typval_T *rettv)
14156{
14157 char_u *in_str;
14158 char_u *fromstr;
14159 char_u *tostr;
14160 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014161 int inlen;
14162 int fromlen;
14163 int tolen;
14164 int idx;
14165 char_u *cpstr;
14166 int cplen;
14167 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014168 char_u buf[NUMBUFLEN];
14169 char_u buf2[NUMBUFLEN];
14170 garray_T ga;
14171
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014172 in_str = tv_get_string(&argvars[0]);
14173 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14174 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014175
14176 /* Default return value: empty string. */
14177 rettv->v_type = VAR_STRING;
14178 rettv->vval.v_string = NULL;
14179 if (fromstr == NULL || tostr == NULL)
14180 return; /* type error; errmsg already given */
14181 ga_init2(&ga, (int)sizeof(char), 80);
14182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014183 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014184 /* not multi-byte: fromstr and tostr must be the same length */
14185 if (STRLEN(fromstr) != STRLEN(tostr))
14186 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014187error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014188 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014189 ga_clear(&ga);
14190 return;
14191 }
14192
14193 /* fromstr and tostr have to contain the same number of chars */
14194 while (*in_str != NUL)
14195 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014196 if (has_mbyte)
14197 {
14198 inlen = (*mb_ptr2len)(in_str);
14199 cpstr = in_str;
14200 cplen = inlen;
14201 idx = 0;
14202 for (p = fromstr; *p != NUL; p += fromlen)
14203 {
14204 fromlen = (*mb_ptr2len)(p);
14205 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14206 {
14207 for (p = tostr; *p != NUL; p += tolen)
14208 {
14209 tolen = (*mb_ptr2len)(p);
14210 if (idx-- == 0)
14211 {
14212 cplen = tolen;
14213 cpstr = p;
14214 break;
14215 }
14216 }
14217 if (*p == NUL) /* tostr is shorter than fromstr */
14218 goto error;
14219 break;
14220 }
14221 ++idx;
14222 }
14223
14224 if (first && cpstr == in_str)
14225 {
14226 /* Check that fromstr and tostr have the same number of
14227 * (multi-byte) characters. Done only once when a character
14228 * of in_str doesn't appear in fromstr. */
14229 first = FALSE;
14230 for (p = tostr; *p != NUL; p += tolen)
14231 {
14232 tolen = (*mb_ptr2len)(p);
14233 --idx;
14234 }
14235 if (idx != 0)
14236 goto error;
14237 }
14238
14239 (void)ga_grow(&ga, cplen);
14240 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14241 ga.ga_len += cplen;
14242
14243 in_str += inlen;
14244 }
14245 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014246 {
14247 /* When not using multi-byte chars we can do it faster. */
14248 p = vim_strchr(fromstr, *in_str);
14249 if (p != NULL)
14250 ga_append(&ga, tostr[p - fromstr]);
14251 else
14252 ga_append(&ga, *in_str);
14253 ++in_str;
14254 }
14255 }
14256
14257 /* add a terminating NUL */
14258 (void)ga_grow(&ga, 1);
14259 ga_append(&ga, NUL);
14260
14261 rettv->vval.v_string = ga.ga_data;
14262}
14263
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014264/*
14265 * "trim({expr})" function
14266 */
14267 static void
14268f_trim(typval_T *argvars, typval_T *rettv)
14269{
14270 char_u buf1[NUMBUFLEN];
14271 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014272 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014273 char_u *mask = NULL;
14274 char_u *tail;
14275 char_u *prev;
14276 char_u *p;
14277 int c1;
14278
14279 rettv->v_type = VAR_STRING;
14280 if (head == NULL)
14281 {
14282 rettv->vval.v_string = NULL;
14283 return;
14284 }
14285
14286 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014287 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014288
14289 while (*head != NUL)
14290 {
14291 c1 = PTR2CHAR(head);
14292 if (mask == NULL)
14293 {
14294 if (c1 > ' ' && c1 != 0xa0)
14295 break;
14296 }
14297 else
14298 {
14299 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14300 if (c1 == PTR2CHAR(p))
14301 break;
14302 if (*p == NUL)
14303 break;
14304 }
14305 MB_PTR_ADV(head);
14306 }
14307
14308 for (tail = head + STRLEN(head); tail > head; tail = prev)
14309 {
14310 prev = tail;
14311 MB_PTR_BACK(head, prev);
14312 c1 = PTR2CHAR(prev);
14313 if (mask == NULL)
14314 {
14315 if (c1 > ' ' && c1 != 0xa0)
14316 break;
14317 }
14318 else
14319 {
14320 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14321 if (c1 == PTR2CHAR(p))
14322 break;
14323 if (*p == NUL)
14324 break;
14325 }
14326 }
14327 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14328}
14329
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014330#ifdef FEAT_FLOAT
14331/*
14332 * "trunc({float})" function
14333 */
14334 static void
14335f_trunc(typval_T *argvars, typval_T *rettv)
14336{
14337 float_T f = 0.0;
14338
14339 rettv->v_type = VAR_FLOAT;
14340 if (get_float_arg(argvars, &f) == OK)
14341 /* trunc() is not in C90, use floor() or ceil() instead. */
14342 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14343 else
14344 rettv->vval.v_float = 0.0;
14345}
14346#endif
14347
14348/*
14349 * "type(expr)" function
14350 */
14351 static void
14352f_type(typval_T *argvars, typval_T *rettv)
14353{
14354 int n = -1;
14355
14356 switch (argvars[0].v_type)
14357 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014358 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14359 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014360 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014361 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14362 case VAR_LIST: n = VAR_TYPE_LIST; break;
14363 case VAR_DICT: n = VAR_TYPE_DICT; break;
14364 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014365 case VAR_SPECIAL:
14366 if (argvars[0].vval.v_number == VVAL_FALSE
14367 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014368 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014369 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014370 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014371 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014372 case VAR_JOB: n = VAR_TYPE_JOB; break;
14373 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014374 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014375 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014376 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014377 n = -1;
14378 break;
14379 }
14380 rettv->vval.v_number = n;
14381}
14382
14383/*
14384 * "undofile(name)" function
14385 */
14386 static void
14387f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14388{
14389 rettv->v_type = VAR_STRING;
14390#ifdef FEAT_PERSISTENT_UNDO
14391 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014392 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014393
14394 if (*fname == NUL)
14395 {
14396 /* If there is no file name there will be no undo file. */
14397 rettv->vval.v_string = NULL;
14398 }
14399 else
14400 {
14401 char_u *ffname = FullName_save(fname, FALSE);
14402
14403 if (ffname != NULL)
14404 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14405 vim_free(ffname);
14406 }
14407 }
14408#else
14409 rettv->vval.v_string = NULL;
14410#endif
14411}
14412
14413/*
14414 * "undotree()" function
14415 */
14416 static void
14417f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14418{
14419 if (rettv_dict_alloc(rettv) == OK)
14420 {
14421 dict_T *dict = rettv->vval.v_dict;
14422 list_T *list;
14423
Bram Moolenaare0be1672018-07-08 16:50:37 +020014424 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14425 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14426 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14427 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14428 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14429 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014430
14431 list = list_alloc();
14432 if (list != NULL)
14433 {
14434 u_eval_tree(curbuf->b_u_oldhead, list);
14435 dict_add_list(dict, "entries", list);
14436 }
14437 }
14438}
14439
14440/*
14441 * "values(dict)" function
14442 */
14443 static void
14444f_values(typval_T *argvars, typval_T *rettv)
14445{
14446 dict_list(argvars, rettv, 1);
14447}
14448
14449/*
14450 * "virtcol(string)" function
14451 */
14452 static void
14453f_virtcol(typval_T *argvars, typval_T *rettv)
14454{
14455 colnr_T vcol = 0;
14456 pos_T *fp;
14457 int fnum = curbuf->b_fnum;
14458
14459 fp = var2fpos(&argvars[0], FALSE, &fnum);
14460 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14461 && fnum == curbuf->b_fnum)
14462 {
14463 getvvcol(curwin, fp, NULL, NULL, &vcol);
14464 ++vcol;
14465 }
14466
14467 rettv->vval.v_number = vcol;
14468}
14469
14470/*
14471 * "visualmode()" function
14472 */
14473 static void
14474f_visualmode(typval_T *argvars, typval_T *rettv)
14475{
14476 char_u str[2];
14477
14478 rettv->v_type = VAR_STRING;
14479 str[0] = curbuf->b_visual_mode_eval;
14480 str[1] = NUL;
14481 rettv->vval.v_string = vim_strsave(str);
14482
14483 /* A non-zero number or non-empty string argument: reset mode. */
14484 if (non_zero_arg(&argvars[0]))
14485 curbuf->b_visual_mode_eval = NUL;
14486}
14487
14488/*
14489 * "wildmenumode()" function
14490 */
14491 static void
14492f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14493{
14494#ifdef FEAT_WILDMENU
14495 if (wild_menu_showing)
14496 rettv->vval.v_number = 1;
14497#endif
14498}
14499
14500/*
14501 * "winbufnr(nr)" function
14502 */
14503 static void
14504f_winbufnr(typval_T *argvars, typval_T *rettv)
14505{
14506 win_T *wp;
14507
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014508 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014509 if (wp == NULL)
14510 rettv->vval.v_number = -1;
14511 else
14512 rettv->vval.v_number = wp->w_buffer->b_fnum;
14513}
14514
14515/*
14516 * "wincol()" function
14517 */
14518 static void
14519f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14520{
14521 validate_cursor();
14522 rettv->vval.v_number = curwin->w_wcol + 1;
14523}
14524
14525/*
14526 * "winheight(nr)" function
14527 */
14528 static void
14529f_winheight(typval_T *argvars, typval_T *rettv)
14530{
14531 win_T *wp;
14532
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014533 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014534 if (wp == NULL)
14535 rettv->vval.v_number = -1;
14536 else
14537 rettv->vval.v_number = wp->w_height;
14538}
14539
14540/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014541 * "winlayout()" function
14542 */
14543 static void
14544f_winlayout(typval_T *argvars, typval_T *rettv)
14545{
14546 tabpage_T *tp;
14547
14548 if (rettv_list_alloc(rettv) != OK)
14549 return;
14550
14551 if (argvars[0].v_type == VAR_UNKNOWN)
14552 tp = curtab;
14553 else
14554 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014555 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014556 if (tp == NULL)
14557 return;
14558 }
14559
14560 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14561}
14562
14563/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014564 * "winline()" function
14565 */
14566 static void
14567f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14568{
14569 validate_cursor();
14570 rettv->vval.v_number = curwin->w_wrow + 1;
14571}
14572
14573/*
14574 * "winnr()" function
14575 */
14576 static void
14577f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14578{
14579 int nr = 1;
14580
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014581 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014582 rettv->vval.v_number = nr;
14583}
14584
14585/*
14586 * "winrestcmd()" function
14587 */
14588 static void
14589f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14590{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014591 win_T *wp;
14592 int winnr = 1;
14593 garray_T ga;
14594 char_u buf[50];
14595
14596 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014597 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014598 {
14599 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14600 ga_concat(&ga, buf);
14601 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14602 ga_concat(&ga, buf);
14603 ++winnr;
14604 }
14605 ga_append(&ga, NUL);
14606
14607 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014608 rettv->v_type = VAR_STRING;
14609}
14610
14611/*
14612 * "winrestview()" function
14613 */
14614 static void
14615f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14616{
14617 dict_T *dict;
14618
14619 if (argvars[0].v_type != VAR_DICT
14620 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014621 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014622 else
14623 {
14624 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014625 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014626 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014627 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014628 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014629 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014630 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14631 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014632 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014633 curwin->w_set_curswant = FALSE;
14634 }
14635
14636 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014637 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014638#ifdef FEAT_DIFF
14639 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014640 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014641#endif
14642 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014643 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014644 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014645 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014646
14647 check_cursor();
14648 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014649 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014650 changed_window_setting();
14651
14652 if (curwin->w_topline <= 0)
14653 curwin->w_topline = 1;
14654 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14655 curwin->w_topline = curbuf->b_ml.ml_line_count;
14656#ifdef FEAT_DIFF
14657 check_topfill(curwin, TRUE);
14658#endif
14659 }
14660}
14661
14662/*
14663 * "winsaveview()" function
14664 */
14665 static void
14666f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14667{
14668 dict_T *dict;
14669
14670 if (rettv_dict_alloc(rettv) == FAIL)
14671 return;
14672 dict = rettv->vval.v_dict;
14673
Bram Moolenaare0be1672018-07-08 16:50:37 +020014674 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14675 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014676 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014677 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014678 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014679
Bram Moolenaare0be1672018-07-08 16:50:37 +020014680 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014681#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014682 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014683#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014684 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14685 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014686}
14687
14688/*
14689 * "winwidth(nr)" function
14690 */
14691 static void
14692f_winwidth(typval_T *argvars, typval_T *rettv)
14693{
14694 win_T *wp;
14695
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014696 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014697 if (wp == NULL)
14698 rettv->vval.v_number = -1;
14699 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014700 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014701}
14702
14703/*
14704 * "wordcount()" function
14705 */
14706 static void
14707f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14708{
14709 if (rettv_dict_alloc(rettv) == FAIL)
14710 return;
14711 cursor_pos_info(rettv->vval.v_dict);
14712}
14713
14714/*
14715 * "writefile()" function
14716 */
14717 static void
14718f_writefile(typval_T *argvars, typval_T *rettv)
14719{
14720 int binary = FALSE;
14721 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014722#ifdef HAVE_FSYNC
14723 int do_fsync = p_fs;
14724#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014725 char_u *fname;
14726 FILE *fd;
14727 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014728 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014729 list_T *list = NULL;
14730 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014731
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014732 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014733 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014734 return;
14735
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014736 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014737 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014738 list = argvars[0].vval.v_list;
14739 if (list == NULL)
14740 return;
14741 for (li = list->lv_first; li != NULL; li = li->li_next)
14742 if (tv_get_string_chk(&li->li_tv) == NULL)
14743 return;
14744 }
14745 else if (argvars[0].v_type == VAR_BLOB)
14746 {
14747 blob = argvars[0].vval.v_blob;
14748 if (blob == NULL)
14749 return;
14750 }
14751 else
14752 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014753 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014754 return;
14755 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014756
14757 if (argvars[2].v_type != VAR_UNKNOWN)
14758 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014759 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014760
14761 if (arg2 == NULL)
14762 return;
14763 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014764 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014765 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014766 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014767#ifdef HAVE_FSYNC
14768 if (vim_strchr(arg2, 's') != NULL)
14769 do_fsync = TRUE;
14770 else if (vim_strchr(arg2, 'S') != NULL)
14771 do_fsync = FALSE;
14772#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014773 }
14774
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014775 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014776 if (fname == NULL)
14777 return;
14778
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014779 /* Always open the file in binary mode, library functions have a mind of
14780 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014781 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14782 append ? APPENDBIN : WRITEBIN)) == NULL)
14783 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014784 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014785 ret = -1;
14786 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014787 else if (blob)
14788 {
14789 if (write_blob(fd, blob) == FAIL)
14790 ret = -1;
14791#ifdef HAVE_FSYNC
14792 else if (do_fsync)
14793 // Ignore the error, the user wouldn't know what to do about it.
14794 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010014795 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014796#endif
14797 fclose(fd);
14798 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014799 else
14800 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014801 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014802 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014803#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014804 else if (do_fsync)
14805 /* Ignore the error, the user wouldn't know what to do about it.
14806 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010014807 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014808#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014809 fclose(fd);
14810 }
14811
14812 rettv->vval.v_number = ret;
14813}
14814
14815/*
14816 * "xor(expr, expr)" function
14817 */
14818 static void
14819f_xor(typval_T *argvars, typval_T *rettv)
14820{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014821 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14822 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014823}
14824
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014825#endif /* FEAT_EVAL */