blob: 733d45aa505f913bfd3d77e0853cd81b69c4f241 [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 Moolenaarc3e92c12019-03-23 14:23:07 +0100431static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200432static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100433static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100434static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_JOB_CHANNEL
436static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
437#endif
438static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
439#ifdef FEAT_JOB_CHANNEL
440static void f_test_null_job(typval_T *argvars, typval_T *rettv);
441#endif
442static void f_test_null_list(typval_T *argvars, typval_T *rettv);
443static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
444static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200445#ifdef FEAT_GUI
446static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
447#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200448static void f_test_settime(typval_T *argvars, typval_T *rettv);
449#ifdef FEAT_FLOAT
450static void f_tan(typval_T *argvars, typval_T *rettv);
451static void f_tanh(typval_T *argvars, typval_T *rettv);
452#endif
453#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200454static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200455static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200456static void f_timer_start(typval_T *argvars, typval_T *rettv);
457static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200458static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200459#endif
460static void f_tolower(typval_T *argvars, typval_T *rettv);
461static void f_toupper(typval_T *argvars, typval_T *rettv);
462static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100463static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200464#ifdef FEAT_FLOAT
465static void f_trunc(typval_T *argvars, typval_T *rettv);
466#endif
467static void f_type(typval_T *argvars, typval_T *rettv);
468static void f_undofile(typval_T *argvars, typval_T *rettv);
469static void f_undotree(typval_T *argvars, typval_T *rettv);
470static void f_uniq(typval_T *argvars, typval_T *rettv);
471static void f_values(typval_T *argvars, typval_T *rettv);
472static void f_virtcol(typval_T *argvars, typval_T *rettv);
473static void f_visualmode(typval_T *argvars, typval_T *rettv);
474static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
475static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
476static void f_win_getid(typval_T *argvars, typval_T *rettv);
477static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
478static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
479static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100480static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200481static void f_winbufnr(typval_T *argvars, typval_T *rettv);
482static void f_wincol(typval_T *argvars, typval_T *rettv);
483static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200484static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200485static void f_winline(typval_T *argvars, typval_T *rettv);
486static void f_winnr(typval_T *argvars, typval_T *rettv);
487static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
488static void f_winrestview(typval_T *argvars, typval_T *rettv);
489static void f_winsaveview(typval_T *argvars, typval_T *rettv);
490static void f_winwidth(typval_T *argvars, typval_T *rettv);
491static void f_writefile(typval_T *argvars, typval_T *rettv);
492static void f_wordcount(typval_T *argvars, typval_T *rettv);
493static void f_xor(typval_T *argvars, typval_T *rettv);
494
495/*
496 * Array with names and number of arguments of all internal functions
497 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
498 */
499static struct fst
500{
501 char *f_name; /* function name */
502 char f_min_argc; /* minimal number of arguments */
503 char f_max_argc; /* maximal number of arguments */
504 void (*f_func)(typval_T *args, typval_T *rvar);
505 /* implementation of function */
506} functions[] =
507{
508#ifdef FEAT_FLOAT
509 {"abs", 1, 1, f_abs},
510 {"acos", 1, 1, f_acos}, /* WJMc */
511#endif
512 {"add", 2, 2, f_add},
513 {"and", 2, 2, f_and},
514 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200515 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200516 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517 {"argidx", 0, 0, f_argidx},
518 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200519 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520#ifdef FEAT_FLOAT
521 {"asin", 1, 1, f_asin}, /* WJMc */
522#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100523 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200524 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100525 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200527 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100529 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200530 {"assert_match", 2, 3, f_assert_match},
531 {"assert_notequal", 2, 3, f_assert_notequal},
532 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100533 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200534 {"assert_true", 1, 2, f_assert_true},
535#ifdef FEAT_FLOAT
536 {"atan", 1, 1, f_atan},
537 {"atan2", 2, 2, f_atan2},
538#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100539#ifdef FEAT_BEVAL
540 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100541# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100542 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100543# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100544#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200545 {"browse", 4, 4, f_browse},
546 {"browsedir", 2, 2, f_browsedir},
547 {"bufexists", 1, 1, f_bufexists},
548 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
549 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
550 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
551 {"buflisted", 1, 1, f_buflisted},
552 {"bufloaded", 1, 1, f_bufloaded},
553 {"bufname", 1, 1, f_bufname},
554 {"bufnr", 1, 2, f_bufnr},
555 {"bufwinid", 1, 1, f_bufwinid},
556 {"bufwinnr", 1, 1, f_bufwinnr},
557 {"byte2line", 1, 1, f_byte2line},
558 {"byteidx", 2, 2, f_byteidx},
559 {"byteidxcomp", 2, 2, f_byteidxcomp},
560 {"call", 2, 3, f_call},
561#ifdef FEAT_FLOAT
562 {"ceil", 1, 1, f_ceil},
563#endif
564#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100565 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200566 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200567 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200568 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
569 {"ch_evalraw", 2, 3, f_ch_evalraw},
570 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
571 {"ch_getjob", 1, 1, f_ch_getjob},
572 {"ch_info", 1, 1, f_ch_info},
573 {"ch_log", 1, 2, f_ch_log},
574 {"ch_logfile", 1, 2, f_ch_logfile},
575 {"ch_open", 1, 2, f_ch_open},
576 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100577 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200578 {"ch_readraw", 1, 2, f_ch_readraw},
579 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
580 {"ch_sendraw", 2, 3, f_ch_sendraw},
581 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200582 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200583#endif
584 {"changenr", 0, 0, f_changenr},
585 {"char2nr", 1, 2, f_char2nr},
586 {"cindent", 1, 1, f_cindent},
587 {"clearmatches", 0, 0, f_clearmatches},
588 {"col", 1, 1, f_col},
589#if defined(FEAT_INS_EXPAND)
590 {"complete", 2, 2, f_complete},
591 {"complete_add", 1, 1, f_complete_add},
592 {"complete_check", 0, 0, f_complete_check},
593#endif
594 {"confirm", 1, 4, f_confirm},
595 {"copy", 1, 1, f_copy},
596#ifdef FEAT_FLOAT
597 {"cos", 1, 1, f_cos},
598 {"cosh", 1, 1, f_cosh},
599#endif
600 {"count", 2, 4, f_count},
601 {"cscope_connection",0,3, f_cscope_connection},
602 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100603#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200604 {"debugbreak", 1, 1, f_debugbreak},
605#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200606 {"deepcopy", 1, 2, f_deepcopy},
607 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200608 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200609 {"did_filetype", 0, 0, f_did_filetype},
610 {"diff_filler", 1, 1, f_diff_filler},
611 {"diff_hlID", 2, 2, f_diff_hlID},
612 {"empty", 1, 1, f_empty},
613 {"escape", 2, 2, f_escape},
614 {"eval", 1, 1, f_eval},
615 {"eventhandler", 0, 0, f_eventhandler},
616 {"executable", 1, 1, f_executable},
617 {"execute", 1, 2, f_execute},
618 {"exepath", 1, 1, f_exepath},
619 {"exists", 1, 1, f_exists},
620#ifdef FEAT_FLOAT
621 {"exp", 1, 1, f_exp},
622#endif
623 {"expand", 1, 3, f_expand},
624 {"extend", 2, 3, f_extend},
625 {"feedkeys", 1, 2, f_feedkeys},
626 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
627 {"filereadable", 1, 1, f_filereadable},
628 {"filewritable", 1, 1, f_filewritable},
629 {"filter", 2, 2, f_filter},
630 {"finddir", 1, 3, f_finddir},
631 {"findfile", 1, 3, f_findfile},
632#ifdef FEAT_FLOAT
633 {"float2nr", 1, 1, f_float2nr},
634 {"floor", 1, 1, f_floor},
635 {"fmod", 2, 2, f_fmod},
636#endif
637 {"fnameescape", 1, 1, f_fnameescape},
638 {"fnamemodify", 2, 2, f_fnamemodify},
639 {"foldclosed", 1, 1, f_foldclosed},
640 {"foldclosedend", 1, 1, f_foldclosedend},
641 {"foldlevel", 1, 1, f_foldlevel},
642 {"foldtext", 0, 0, f_foldtext},
643 {"foldtextresult", 1, 1, f_foldtextresult},
644 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200645 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200646 {"function", 1, 3, f_function},
647 {"garbagecollect", 0, 1, f_garbagecollect},
648 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200649 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200650 {"getbufline", 2, 3, f_getbufline},
651 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100652 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"getchar", 0, 1, f_getchar},
654 {"getcharmod", 0, 0, f_getcharmod},
655 {"getcharsearch", 0, 0, f_getcharsearch},
656 {"getcmdline", 0, 0, f_getcmdline},
657 {"getcmdpos", 0, 0, f_getcmdpos},
658 {"getcmdtype", 0, 0, f_getcmdtype},
659 {"getcmdwintype", 0, 0, f_getcmdwintype},
660#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200661 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662#endif
663 {"getcurpos", 0, 0, f_getcurpos},
664 {"getcwd", 0, 2, f_getcwd},
665 {"getfontname", 0, 1, f_getfontname},
666 {"getfperm", 1, 1, f_getfperm},
667 {"getfsize", 1, 1, f_getfsize},
668 {"getftime", 1, 1, f_getftime},
669 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100670 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200671 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200672 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200673 {"getmatches", 0, 0, f_getmatches},
674 {"getpid", 0, 0, f_getpid},
675 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200676 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200677 {"getreg", 0, 3, f_getreg},
678 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200679 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680 {"gettabvar", 2, 3, f_gettabvar},
681 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100682 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200683 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100684 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685 {"getwinposx", 0, 0, f_getwinposx},
686 {"getwinposy", 0, 0, f_getwinposy},
687 {"getwinvar", 2, 3, f_getwinvar},
688 {"glob", 1, 4, f_glob},
689 {"glob2regpat", 1, 1, f_glob2regpat},
690 {"globpath", 2, 5, f_globpath},
691 {"has", 1, 1, f_has},
692 {"has_key", 2, 2, f_has_key},
693 {"haslocaldir", 0, 2, f_haslocaldir},
694 {"hasmapto", 1, 3, f_hasmapto},
695 {"highlightID", 1, 1, f_hlID}, /* obsolete */
696 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
697 {"histadd", 2, 2, f_histadd},
698 {"histdel", 1, 2, f_histdel},
699 {"histget", 1, 2, f_histget},
700 {"histnr", 1, 1, f_histnr},
701 {"hlID", 1, 1, f_hlID},
702 {"hlexists", 1, 1, f_hlexists},
703 {"hostname", 0, 0, f_hostname},
704 {"iconv", 3, 3, f_iconv},
705 {"indent", 1, 1, f_indent},
706 {"index", 2, 4, f_index},
707 {"input", 1, 3, f_input},
708 {"inputdialog", 1, 3, f_inputdialog},
709 {"inputlist", 1, 1, f_inputlist},
710 {"inputrestore", 0, 0, f_inputrestore},
711 {"inputsave", 0, 0, f_inputsave},
712 {"inputsecret", 1, 2, f_inputsecret},
713 {"insert", 2, 3, f_insert},
714 {"invert", 1, 1, f_invert},
715 {"isdirectory", 1, 1, f_isdirectory},
716 {"islocked", 1, 1, f_islocked},
717#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
718 {"isnan", 1, 1, f_isnan},
719#endif
720 {"items", 1, 1, f_items},
721#ifdef FEAT_JOB_CHANNEL
722 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200723 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200724 {"job_setoptions", 2, 2, f_job_setoptions},
725 {"job_start", 1, 2, f_job_start},
726 {"job_status", 1, 1, f_job_status},
727 {"job_stop", 1, 2, f_job_stop},
728#endif
729 {"join", 1, 2, f_join},
730 {"js_decode", 1, 1, f_js_decode},
731 {"js_encode", 1, 1, f_js_encode},
732 {"json_decode", 1, 1, f_json_decode},
733 {"json_encode", 1, 1, f_json_encode},
734 {"keys", 1, 1, f_keys},
735 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
736 {"len", 1, 1, f_len},
737 {"libcall", 3, 3, f_libcall},
738 {"libcallnr", 3, 3, f_libcallnr},
739 {"line", 1, 1, f_line},
740 {"line2byte", 1, 1, f_line2byte},
741 {"lispindent", 1, 1, f_lispindent},
742 {"localtime", 0, 0, f_localtime},
743#ifdef FEAT_FLOAT
744 {"log", 1, 1, f_log},
745 {"log10", 1, 1, f_log10},
746#endif
747#ifdef FEAT_LUA
748 {"luaeval", 1, 2, f_luaeval},
749#endif
750 {"map", 2, 2, f_map},
751 {"maparg", 1, 4, f_maparg},
752 {"mapcheck", 1, 3, f_mapcheck},
753 {"match", 2, 4, f_match},
754 {"matchadd", 2, 5, f_matchadd},
755 {"matchaddpos", 2, 5, f_matchaddpos},
756 {"matcharg", 1, 1, f_matcharg},
757 {"matchdelete", 1, 1, f_matchdelete},
758 {"matchend", 2, 4, f_matchend},
759 {"matchlist", 2, 4, f_matchlist},
760 {"matchstr", 2, 4, f_matchstr},
761 {"matchstrpos", 2, 4, f_matchstrpos},
762 {"max", 1, 1, f_max},
763 {"min", 1, 1, f_min},
764#ifdef vim_mkdir
765 {"mkdir", 1, 3, f_mkdir},
766#endif
767 {"mode", 0, 1, f_mode},
768#ifdef FEAT_MZSCHEME
769 {"mzeval", 1, 1, f_mzeval},
770#endif
771 {"nextnonblank", 1, 1, f_nextnonblank},
772 {"nr2char", 1, 2, f_nr2char},
773 {"or", 2, 2, f_or},
774 {"pathshorten", 1, 1, f_pathshorten},
775#ifdef FEAT_PERL
776 {"perleval", 1, 1, f_perleval},
777#endif
778#ifdef FEAT_FLOAT
779 {"pow", 2, 2, f_pow},
780#endif
781 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100782 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200783#ifdef FEAT_JOB_CHANNEL
784 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200785 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200786 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
787#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100788#ifdef FEAT_TEXT_PROP
789 {"prop_add", 3, 3, f_prop_add},
790 {"prop_clear", 1, 3, f_prop_clear},
791 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100792 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100793 {"prop_type_add", 2, 2, f_prop_type_add},
794 {"prop_type_change", 2, 2, f_prop_type_change},
795 {"prop_type_delete", 1, 2, f_prop_type_delete},
796 {"prop_type_get", 1, 2, f_prop_type_get},
797 {"prop_type_list", 0, 1, f_prop_type_list},
798#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200799 {"pumvisible", 0, 0, f_pumvisible},
800#ifdef FEAT_PYTHON3
801 {"py3eval", 1, 1, f_py3eval},
802#endif
803#ifdef FEAT_PYTHON
804 {"pyeval", 1, 1, f_pyeval},
805#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100806#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
807 {"pyxeval", 1, 1, f_pyxeval},
808#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200809 {"range", 1, 3, f_range},
810 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200811 {"reg_executing", 0, 0, f_reg_executing},
812 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200813 {"reltime", 0, 2, f_reltime},
814#ifdef FEAT_FLOAT
815 {"reltimefloat", 1, 1, f_reltimefloat},
816#endif
817 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100818 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819 {"remote_foreground", 1, 1, f_remote_foreground},
820 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100821 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100823 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824 {"remove", 2, 3, f_remove},
825 {"rename", 2, 2, f_rename},
826 {"repeat", 2, 2, f_repeat},
827 {"resolve", 1, 1, f_resolve},
828 {"reverse", 1, 1, f_reverse},
829#ifdef FEAT_FLOAT
830 {"round", 1, 1, f_round},
831#endif
832 {"screenattr", 2, 2, f_screenattr},
833 {"screenchar", 2, 2, f_screenchar},
834 {"screencol", 0, 0, f_screencol},
835 {"screenrow", 0, 0, f_screenrow},
836 {"search", 1, 4, f_search},
837 {"searchdecl", 1, 3, f_searchdecl},
838 {"searchpair", 3, 7, f_searchpair},
839 {"searchpairpos", 3, 7, f_searchpairpos},
840 {"searchpos", 1, 4, f_searchpos},
841 {"server2client", 2, 2, f_server2client},
842 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200843 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200844 {"setbufvar", 3, 3, f_setbufvar},
845 {"setcharsearch", 1, 1, f_setcharsearch},
846 {"setcmdpos", 1, 1, f_setcmdpos},
847 {"setfperm", 2, 2, f_setfperm},
848 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200849 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850 {"setmatches", 1, 1, f_setmatches},
851 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200852 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853 {"setreg", 2, 3, f_setreg},
854 {"settabvar", 3, 3, f_settabvar},
855 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100856 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200857 {"setwinvar", 3, 3, f_setwinvar},
858#ifdef FEAT_CRYPT
859 {"sha256", 1, 1, f_sha256},
860#endif
861 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100862 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100863#ifdef FEAT_SIGNS
864 {"sign_define", 1, 2, f_sign_define},
865 {"sign_getdefined", 0, 1, f_sign_getdefined},
866 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100867 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100868 {"sign_place", 4, 5, f_sign_place},
869 {"sign_undefine", 0, 1, f_sign_undefine},
870 {"sign_unplace", 1, 2, f_sign_unplace},
871#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200872 {"simplify", 1, 1, f_simplify},
873#ifdef FEAT_FLOAT
874 {"sin", 1, 1, f_sin},
875 {"sinh", 1, 1, f_sinh},
876#endif
877 {"sort", 1, 3, f_sort},
878 {"soundfold", 1, 1, f_soundfold},
879 {"spellbadword", 0, 1, f_spellbadword},
880 {"spellsuggest", 1, 3, f_spellsuggest},
881 {"split", 1, 3, f_split},
882#ifdef FEAT_FLOAT
883 {"sqrt", 1, 1, f_sqrt},
884 {"str2float", 1, 1, f_str2float},
885#endif
886 {"str2nr", 1, 2, f_str2nr},
887 {"strcharpart", 2, 3, f_strcharpart},
888 {"strchars", 1, 2, f_strchars},
889 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
890#ifdef HAVE_STRFTIME
891 {"strftime", 1, 2, f_strftime},
892#endif
893 {"strgetchar", 2, 2, f_strgetchar},
894 {"stridx", 2, 3, f_stridx},
895 {"string", 1, 1, f_string},
896 {"strlen", 1, 1, f_strlen},
897 {"strpart", 2, 3, f_strpart},
898 {"strridx", 2, 3, f_strridx},
899 {"strtrans", 1, 1, f_strtrans},
900 {"strwidth", 1, 1, f_strwidth},
901 {"submatch", 1, 2, f_submatch},
902 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200903 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200904 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200905 {"synID", 3, 3, f_synID},
906 {"synIDattr", 2, 3, f_synIDattr},
907 {"synIDtrans", 1, 1, f_synIDtrans},
908 {"synconcealed", 2, 2, f_synconcealed},
909 {"synstack", 2, 2, f_synstack},
910 {"system", 1, 2, f_system},
911 {"systemlist", 1, 2, f_systemlist},
912 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
913 {"tabpagenr", 0, 1, f_tabpagenr},
914 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
915 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100916 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917#ifdef FEAT_FLOAT
918 {"tan", 1, 1, f_tan},
919 {"tanh", 1, 1, f_tanh},
920#endif
921 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200922#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100923 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
924 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100925 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200926 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200927# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
928 {"term_getansicolors", 1, 1, f_term_getansicolors},
929# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200930 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200931 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200932 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200933 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200934 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200935 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200936 {"term_getstatus", 1, 1, f_term_getstatus},
937 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200938 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200939 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200940 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200941 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200942# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
943 {"term_setansicolors", 2, 2, f_term_setansicolors},
944# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100945 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100946 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200947 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200948 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200949 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200950#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
952 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200953 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200954 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100955 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100956 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200957#ifdef FEAT_JOB_CHANNEL
958 {"test_null_channel", 0, 0, f_test_null_channel},
959#endif
960 {"test_null_dict", 0, 0, f_test_null_dict},
961#ifdef FEAT_JOB_CHANNEL
962 {"test_null_job", 0, 0, f_test_null_job},
963#endif
964 {"test_null_list", 0, 0, f_test_null_list},
965 {"test_null_partial", 0, 0, f_test_null_partial},
966 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200967 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100968 {"test_override", 2, 2, f_test_override},
969 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200970#ifdef FEAT_GUI
971 {"test_scrollbar", 3, 3, f_test_scrollbar},
972#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973 {"test_settime", 1, 1, f_test_settime},
974#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200975 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200976 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200977 {"timer_start", 2, 3, f_timer_start},
978 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200979 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200980#endif
981 {"tolower", 1, 1, f_tolower},
982 {"toupper", 1, 1, f_toupper},
983 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100984 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200985#ifdef FEAT_FLOAT
986 {"trunc", 1, 1, f_trunc},
987#endif
988 {"type", 1, 1, f_type},
989 {"undofile", 1, 1, f_undofile},
990 {"undotree", 0, 0, f_undotree},
991 {"uniq", 1, 3, f_uniq},
992 {"values", 1, 1, f_values},
993 {"virtcol", 1, 1, f_virtcol},
994 {"visualmode", 0, 1, f_visualmode},
995 {"wildmenumode", 0, 0, f_wildmenumode},
996 {"win_findbuf", 1, 1, f_win_findbuf},
997 {"win_getid", 0, 2, f_win_getid},
998 {"win_gotoid", 1, 1, f_win_gotoid},
999 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1000 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001001 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001002 {"winbufnr", 1, 1, f_winbufnr},
1003 {"wincol", 0, 0, f_wincol},
1004 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001005 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001006 {"winline", 0, 0, f_winline},
1007 {"winnr", 0, 1, f_winnr},
1008 {"winrestcmd", 0, 0, f_winrestcmd},
1009 {"winrestview", 1, 1, f_winrestview},
1010 {"winsaveview", 0, 0, f_winsaveview},
1011 {"winwidth", 1, 1, f_winwidth},
1012 {"wordcount", 0, 0, f_wordcount},
1013 {"writefile", 2, 3, f_writefile},
1014 {"xor", 2, 2, f_xor},
1015};
1016
1017#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1018
1019/*
1020 * Function given to ExpandGeneric() to obtain the list of internal
1021 * or user defined function names.
1022 */
1023 char_u *
1024get_function_name(expand_T *xp, int idx)
1025{
1026 static int intidx = -1;
1027 char_u *name;
1028
1029 if (idx == 0)
1030 intidx = -1;
1031 if (intidx < 0)
1032 {
1033 name = get_user_func_name(xp, idx);
1034 if (name != NULL)
1035 return name;
1036 }
1037 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1038 {
1039 STRCPY(IObuff, functions[intidx].f_name);
1040 STRCAT(IObuff, "(");
1041 if (functions[intidx].f_max_argc == 0)
1042 STRCAT(IObuff, ")");
1043 return IObuff;
1044 }
1045
1046 return NULL;
1047}
1048
1049/*
1050 * Function given to ExpandGeneric() to obtain the list of internal or
1051 * user defined variable or function names.
1052 */
1053 char_u *
1054get_expr_name(expand_T *xp, int idx)
1055{
1056 static int intidx = -1;
1057 char_u *name;
1058
1059 if (idx == 0)
1060 intidx = -1;
1061 if (intidx < 0)
1062 {
1063 name = get_function_name(xp, idx);
1064 if (name != NULL)
1065 return name;
1066 }
1067 return get_user_var_name(xp, ++intidx);
1068}
1069
1070#endif /* FEAT_CMDL_COMPL */
1071
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001072/*
1073 * Find internal function in table above.
1074 * Return index, or -1 if not found
1075 */
1076 int
1077find_internal_func(
1078 char_u *name) /* name of the function */
1079{
1080 int first = 0;
1081 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1082 int cmp;
1083 int x;
1084
1085 /*
1086 * Find the function name in the table. Binary search.
1087 */
1088 while (first <= last)
1089 {
1090 x = first + ((unsigned)(last - first) >> 1);
1091 cmp = STRCMP(name, functions[x].f_name);
1092 if (cmp < 0)
1093 last = x - 1;
1094 else if (cmp > 0)
1095 first = x + 1;
1096 else
1097 return x;
1098 }
1099 return -1;
1100}
1101
1102 int
1103call_internal_func(
1104 char_u *name,
1105 int argcount,
1106 typval_T *argvars,
1107 typval_T *rettv)
1108{
1109 int i;
1110
1111 i = find_internal_func(name);
1112 if (i < 0)
1113 return ERROR_UNKNOWN;
1114 if (argcount < functions[i].f_min_argc)
1115 return ERROR_TOOFEW;
1116 if (argcount > functions[i].f_max_argc)
1117 return ERROR_TOOMANY;
1118 argvars[argcount].v_type = VAR_UNKNOWN;
1119 functions[i].f_func(argvars, rettv);
1120 return ERROR_NONE;
1121}
1122
1123/*
1124 * Return TRUE for a non-zero Number and a non-empty String.
1125 */
1126 static int
1127non_zero_arg(typval_T *argvars)
1128{
1129 return ((argvars[0].v_type == VAR_NUMBER
1130 && argvars[0].vval.v_number != 0)
1131 || (argvars[0].v_type == VAR_SPECIAL
1132 && argvars[0].vval.v_number == VVAL_TRUE)
1133 || (argvars[0].v_type == VAR_STRING
1134 && argvars[0].vval.v_string != NULL
1135 && *argvars[0].vval.v_string != NUL));
1136}
1137
1138/*
1139 * Get the lnum from the first argument.
1140 * Also accepts ".", "$", etc., but that only works for the current buffer.
1141 * Returns -1 on error.
1142 */
1143 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001144tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001145{
1146 typval_T rettv;
1147 linenr_T lnum;
1148
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001149 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001150 if (lnum == 0) /* no valid number, try using line() */
1151 {
1152 rettv.v_type = VAR_NUMBER;
1153 f_line(argvars, &rettv);
1154 lnum = (linenr_T)rettv.vval.v_number;
1155 clear_tv(&rettv);
1156 }
1157 return lnum;
1158}
1159
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001160/*
1161 * Get the lnum from the first argument.
1162 * Also accepts "$", then "buf" is used.
1163 * Returns 0 on error.
1164 */
1165 static linenr_T
1166tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1167{
1168 if (argvars[0].v_type == VAR_STRING
1169 && argvars[0].vval.v_string != NULL
1170 && argvars[0].vval.v_string[0] == '$'
1171 && buf != NULL)
1172 return buf->b_ml.ml_line_count;
1173 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1174}
1175
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001176#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001177/*
1178 * Get the float value of "argvars[0]" into "f".
1179 * Returns FAIL when the argument is not a Number or Float.
1180 */
1181 static int
1182get_float_arg(typval_T *argvars, float_T *f)
1183{
1184 if (argvars[0].v_type == VAR_FLOAT)
1185 {
1186 *f = argvars[0].vval.v_float;
1187 return OK;
1188 }
1189 if (argvars[0].v_type == VAR_NUMBER)
1190 {
1191 *f = (float_T)argvars[0].vval.v_number;
1192 return OK;
1193 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001194 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001195 return FAIL;
1196}
1197
1198/*
1199 * "abs(expr)" function
1200 */
1201 static void
1202f_abs(typval_T *argvars, typval_T *rettv)
1203{
1204 if (argvars[0].v_type == VAR_FLOAT)
1205 {
1206 rettv->v_type = VAR_FLOAT;
1207 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1208 }
1209 else
1210 {
1211 varnumber_T n;
1212 int error = FALSE;
1213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001214 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001215 if (error)
1216 rettv->vval.v_number = -1;
1217 else if (n > 0)
1218 rettv->vval.v_number = n;
1219 else
1220 rettv->vval.v_number = -n;
1221 }
1222}
1223
1224/*
1225 * "acos()" function
1226 */
1227 static void
1228f_acos(typval_T *argvars, typval_T *rettv)
1229{
1230 float_T f = 0.0;
1231
1232 rettv->v_type = VAR_FLOAT;
1233 if (get_float_arg(argvars, &f) == OK)
1234 rettv->vval.v_float = acos(f);
1235 else
1236 rettv->vval.v_float = 0.0;
1237}
1238#endif
1239
1240/*
1241 * "add(list, item)" function
1242 */
1243 static void
1244f_add(typval_T *argvars, typval_T *rettv)
1245{
1246 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001247 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001248
1249 rettv->vval.v_number = 1; /* Default: Failed */
1250 if (argvars[0].v_type == VAR_LIST)
1251 {
1252 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001253 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254 (char_u *)N_("add() argument"), TRUE)
1255 && list_append_tv(l, &argvars[1]) == OK)
1256 copy_tv(&argvars[0], rettv);
1257 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001258 else if (argvars[0].v_type == VAR_BLOB)
1259 {
1260 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001261 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001262 (char_u *)N_("add() argument"), TRUE))
1263 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001264 int error = FALSE;
1265 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1266
1267 if (!error)
1268 {
1269 ga_append(&b->bv_ga, (int)n);
1270 copy_tv(&argvars[0], rettv);
1271 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001272 }
1273 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001274 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001275 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001276}
1277
1278/*
1279 * "and(expr, expr)" function
1280 */
1281 static void
1282f_and(typval_T *argvars, typval_T *rettv)
1283{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001284 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1285 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001286}
1287
1288/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001289 * If there is a window for "curbuf", make it the current window.
1290 */
1291 static void
1292find_win_for_curbuf(void)
1293{
1294 wininfo_T *wip;
1295
1296 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1297 {
1298 if (wip->wi_win != NULL)
1299 {
1300 curwin = wip->wi_win;
1301 break;
1302 }
1303 }
1304}
1305
1306/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001307 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001308 */
1309 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001310set_buffer_lines(
1311 buf_T *buf,
1312 linenr_T lnum_arg,
1313 int append,
1314 typval_T *lines,
1315 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001316{
Bram Moolenaarca851592018-06-06 21:04:07 +02001317 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1318 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001319 list_T *l = NULL;
1320 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001321 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001322 linenr_T append_lnum;
1323 buf_T *curbuf_save = NULL;
1324 win_T *curwin_save = NULL;
1325 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001326
Bram Moolenaarca851592018-06-06 21:04:07 +02001327 /* When using the current buffer ml_mfp will be set if needed. Useful when
1328 * setline() is used on startup. For other buffers the buffer must be
1329 * loaded. */
1330 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001331 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001332 rettv->vval.v_number = 1; /* FAIL */
1333 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001334 }
1335
Bram Moolenaarca851592018-06-06 21:04:07 +02001336 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001337 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001338 curbuf_save = curbuf;
1339 curwin_save = curwin;
1340 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001341 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001342 }
1343
1344 if (append)
1345 // appendbufline() uses the line number below which we insert
1346 append_lnum = lnum - 1;
1347 else
1348 // setbufline() uses the line number above which we insert, we only
1349 // append if it's below the last line
1350 append_lnum = curbuf->b_ml.ml_line_count;
1351
1352 if (lines->v_type == VAR_LIST)
1353 {
1354 l = lines->vval.v_list;
1355 li = l->lv_first;
1356 }
1357 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001358 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001359
1360 /* default result is zero == OK */
1361 for (;;)
1362 {
1363 if (l != NULL)
1364 {
1365 /* list argument, get next string */
1366 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001368 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001369 li = li->li_next;
1370 }
1371
Bram Moolenaarca851592018-06-06 21:04:07 +02001372 rettv->vval.v_number = 1; /* FAIL */
1373 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1374 break;
1375
1376 /* When coming here from Insert mode, sync undo, so that this can be
1377 * undone separately from what was previously inserted. */
1378 if (u_sync_once == 2)
1379 {
1380 u_sync_once = 1; /* notify that u_sync() was called */
1381 u_sync(TRUE);
1382 }
1383
1384 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1385 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001386 // Existing line, replace it.
1387 // Removes any existing text properties.
1388 if (u_savesub(lnum) == OK && ml_replace_len(
1389 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001390 {
1391 changed_bytes(lnum, 0);
1392 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1393 check_cursor_col();
1394 rettv->vval.v_number = 0; /* OK */
1395 }
1396 }
1397 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1398 {
1399 /* append the line */
1400 ++added;
1401 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1402 rettv->vval.v_number = 0; /* OK */
1403 }
1404
1405 if (l == NULL) /* only one string argument */
1406 break;
1407 ++lnum;
1408 }
1409
1410 if (added > 0)
1411 {
1412 win_T *wp;
1413 tabpage_T *tp;
1414
1415 appended_lines_mark(append_lnum, added);
1416 FOR_ALL_TAB_WINDOWS(tp, wp)
1417 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1418 wp->w_cursor.lnum += added;
1419 check_cursor_col();
1420
Bram Moolenaarf2732452018-06-03 14:47:35 +02001421#ifdef FEAT_JOB_CHANNEL
1422 if (bt_prompt(curbuf) && (State & INSERT))
1423 // show the line with the prompt
1424 update_topline();
1425#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001426 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001427
1428 if (!is_curbuf)
1429 {
1430 curbuf = curbuf_save;
1431 curwin = curwin_save;
1432 }
1433}
1434
1435/*
1436 * "append(lnum, string/list)" function
1437 */
1438 static void
1439f_append(typval_T *argvars, typval_T *rettv)
1440{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001441 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001442
1443 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1444}
1445
1446/*
1447 * "appendbufline(buf, lnum, string/list)" function
1448 */
1449 static void
1450f_appendbufline(typval_T *argvars, typval_T *rettv)
1451{
1452 linenr_T lnum;
1453 buf_T *buf;
1454
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001455 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001456 if (buf == NULL)
1457 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001458 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001459 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001460 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001461 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1462 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001463}
1464
1465/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001466 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001467 */
1468 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001469f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001470{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001471 win_T *wp;
1472
1473 if (argvars[0].v_type == VAR_UNKNOWN)
1474 // use the current window
1475 rettv->vval.v_number = ARGCOUNT;
1476 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001477 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001478 // use the global argument list
1479 rettv->vval.v_number = GARGCOUNT;
1480 else
1481 {
1482 // use the argument list of the specified window
1483 wp = find_win_by_nr_or_id(&argvars[0]);
1484 if (wp != NULL)
1485 rettv->vval.v_number = WARGCOUNT(wp);
1486 else
1487 rettv->vval.v_number = -1;
1488 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001489}
1490
1491/*
1492 * "argidx()" function
1493 */
1494 static void
1495f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1496{
1497 rettv->vval.v_number = curwin->w_arg_idx;
1498}
1499
1500/*
1501 * "arglistid()" function
1502 */
1503 static void
1504f_arglistid(typval_T *argvars, typval_T *rettv)
1505{
1506 win_T *wp;
1507
1508 rettv->vval.v_number = -1;
1509 wp = find_tabwin(&argvars[0], &argvars[1]);
1510 if (wp != NULL)
1511 rettv->vval.v_number = wp->w_alist->id;
1512}
1513
1514/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001515 * Get the argument list for a given window
1516 */
1517 static void
1518get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1519{
1520 int idx;
1521
1522 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1523 for (idx = 0; idx < argcount; ++idx)
1524 list_append_string(rettv->vval.v_list,
1525 alist_name(&arglist[idx]), -1);
1526}
1527
1528/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529 * "argv(nr)" function
1530 */
1531 static void
1532f_argv(typval_T *argvars, typval_T *rettv)
1533{
1534 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001535 aentry_T *arglist = NULL;
1536 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001537
1538 if (argvars[0].v_type != VAR_UNKNOWN)
1539 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001540 if (argvars[1].v_type == VAR_UNKNOWN)
1541 {
1542 arglist = ARGLIST;
1543 argcount = ARGCOUNT;
1544 }
1545 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001546 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001547 {
1548 arglist = GARGLIST;
1549 argcount = GARGCOUNT;
1550 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001551 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001552 {
1553 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1554
1555 if (wp != NULL)
1556 {
1557 /* Use the argument list of the specified window */
1558 arglist = WARGLIST(wp);
1559 argcount = WARGCOUNT(wp);
1560 }
1561 }
1562
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001563 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001564 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001565 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001566 if (arglist != NULL && idx >= 0 && idx < argcount)
1567 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1568 else if (idx == -1)
1569 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001571 else
1572 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001573}
1574
1575/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001576 * "assert_beeps(cmd [, error])" function
1577 */
1578 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001579f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001580{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001581 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001582}
1583
1584/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001585 * "assert_equal(expected, actual[, msg])" function
1586 */
1587 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001588f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001589{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001590 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001591}
1592
1593/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001594 * "assert_equalfile(fname-one, fname-two)" function
1595 */
1596 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001597f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001598{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001599 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001600}
1601
1602/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603 * "assert_notequal(expected, actual[, msg])" function
1604 */
1605 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001606f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001608 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609}
1610
1611/*
1612 * "assert_exception(string[, msg])" function
1613 */
1614 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001615f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001617 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001618}
1619
1620/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001621 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622 */
1623 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001624f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001626 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627}
1628
1629/*
1630 * "assert_false(actual[, msg])" function
1631 */
1632 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001633f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001634{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001635 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001636}
1637
1638/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001639 * "assert_inrange(lower, upper[, msg])" function
1640 */
1641 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001642f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001643{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001644 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001645}
1646
1647/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648 * "assert_match(pattern, actual[, msg])" function
1649 */
1650 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001651f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001652{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001653 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001654}
1655
1656/*
1657 * "assert_notmatch(pattern, actual[, msg])" function
1658 */
1659 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001660f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001662 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001663}
1664
1665/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001666 * "assert_report(msg)" function
1667 */
1668 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001669f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001670{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001671 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001672}
1673
1674/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 * "assert_true(actual[, msg])" function
1676 */
1677 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001678f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001679{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001680 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681}
1682
1683#ifdef FEAT_FLOAT
1684/*
1685 * "asin()" function
1686 */
1687 static void
1688f_asin(typval_T *argvars, typval_T *rettv)
1689{
1690 float_T f = 0.0;
1691
1692 rettv->v_type = VAR_FLOAT;
1693 if (get_float_arg(argvars, &f) == OK)
1694 rettv->vval.v_float = asin(f);
1695 else
1696 rettv->vval.v_float = 0.0;
1697}
1698
1699/*
1700 * "atan()" function
1701 */
1702 static void
1703f_atan(typval_T *argvars, typval_T *rettv)
1704{
1705 float_T f = 0.0;
1706
1707 rettv->v_type = VAR_FLOAT;
1708 if (get_float_arg(argvars, &f) == OK)
1709 rettv->vval.v_float = atan(f);
1710 else
1711 rettv->vval.v_float = 0.0;
1712}
1713
1714/*
1715 * "atan2()" function
1716 */
1717 static void
1718f_atan2(typval_T *argvars, typval_T *rettv)
1719{
1720 float_T fx = 0.0, fy = 0.0;
1721
1722 rettv->v_type = VAR_FLOAT;
1723 if (get_float_arg(argvars, &fx) == OK
1724 && get_float_arg(&argvars[1], &fy) == OK)
1725 rettv->vval.v_float = atan2(fx, fy);
1726 else
1727 rettv->vval.v_float = 0.0;
1728}
1729#endif
1730
1731/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001732 * "balloon_show()" function
1733 */
1734#ifdef FEAT_BEVAL
1735 static void
1736f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1737{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001738 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001739 {
1740 if (argvars[0].v_type == VAR_LIST
1741# ifdef FEAT_GUI
1742 && !gui.in_use
1743# endif
1744 )
1745 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1746 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001747 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001748 }
1749}
1750
Bram Moolenaar669a8282017-11-19 20:13:05 +01001751# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001752 static void
1753f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1754{
1755 if (rettv_list_alloc(rettv) == OK)
1756 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001757 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001758
1759 if (msg != NULL)
1760 {
1761 pumitem_T *array;
1762 int size = split_message(msg, &array);
1763 int i;
1764
1765 /* Skip the first and last item, they are always empty. */
1766 for (i = 1; i < size - 1; ++i)
1767 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001768 while (size > 0)
1769 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001770 vim_free(array);
1771 }
1772 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001773}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001774# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001775#endif
1776
1777/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001778 * "browse(save, title, initdir, default)" function
1779 */
1780 static void
1781f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1782{
1783#ifdef FEAT_BROWSE
1784 int save;
1785 char_u *title;
1786 char_u *initdir;
1787 char_u *defname;
1788 char_u buf[NUMBUFLEN];
1789 char_u buf2[NUMBUFLEN];
1790 int error = FALSE;
1791
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001792 save = (int)tv_get_number_chk(&argvars[0], &error);
1793 title = tv_get_string_chk(&argvars[1]);
1794 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1795 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001796
1797 if (error || title == NULL || initdir == NULL || defname == NULL)
1798 rettv->vval.v_string = NULL;
1799 else
1800 rettv->vval.v_string =
1801 do_browse(save ? BROWSE_SAVE : 0,
1802 title, defname, NULL, initdir, NULL, curbuf);
1803#else
1804 rettv->vval.v_string = NULL;
1805#endif
1806 rettv->v_type = VAR_STRING;
1807}
1808
1809/*
1810 * "browsedir(title, initdir)" function
1811 */
1812 static void
1813f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1814{
1815#ifdef FEAT_BROWSE
1816 char_u *title;
1817 char_u *initdir;
1818 char_u buf[NUMBUFLEN];
1819
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001820 title = tv_get_string_chk(&argvars[0]);
1821 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822
1823 if (title == NULL || initdir == NULL)
1824 rettv->vval.v_string = NULL;
1825 else
1826 rettv->vval.v_string = do_browse(BROWSE_DIR,
1827 title, NULL, NULL, initdir, NULL, curbuf);
1828#else
1829 rettv->vval.v_string = NULL;
1830#endif
1831 rettv->v_type = VAR_STRING;
1832}
1833
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834/*
1835 * Find a buffer by number or exact name.
1836 */
1837 static buf_T *
1838find_buffer(typval_T *avar)
1839{
1840 buf_T *buf = NULL;
1841
1842 if (avar->v_type == VAR_NUMBER)
1843 buf = buflist_findnr((int)avar->vval.v_number);
1844 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1845 {
1846 buf = buflist_findname_exp(avar->vval.v_string);
1847 if (buf == NULL)
1848 {
1849 /* No full path name match, try a match with a URL or a "nofile"
1850 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001851 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001852 if (buf->b_fname != NULL
1853 && (path_with_url(buf->b_fname)
1854#ifdef FEAT_QUICKFIX
1855 || bt_nofile(buf)
1856#endif
1857 )
1858 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1859 break;
1860 }
1861 }
1862 return buf;
1863}
1864
1865/*
1866 * "bufexists(expr)" function
1867 */
1868 static void
1869f_bufexists(typval_T *argvars, typval_T *rettv)
1870{
1871 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1872}
1873
1874/*
1875 * "buflisted(expr)" function
1876 */
1877 static void
1878f_buflisted(typval_T *argvars, typval_T *rettv)
1879{
1880 buf_T *buf;
1881
1882 buf = find_buffer(&argvars[0]);
1883 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1884}
1885
1886/*
1887 * "bufloaded(expr)" function
1888 */
1889 static void
1890f_bufloaded(typval_T *argvars, typval_T *rettv)
1891{
1892 buf_T *buf;
1893
1894 buf = find_buffer(&argvars[0]);
1895 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1896}
1897
1898 buf_T *
1899buflist_find_by_name(char_u *name, int curtab_only)
1900{
1901 int save_magic;
1902 char_u *save_cpo;
1903 buf_T *buf;
1904
1905 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1906 save_magic = p_magic;
1907 p_magic = TRUE;
1908 save_cpo = p_cpo;
1909 p_cpo = (char_u *)"";
1910
1911 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1912 TRUE, FALSE, curtab_only));
1913
1914 p_magic = save_magic;
1915 p_cpo = save_cpo;
1916 return buf;
1917}
1918
1919/*
1920 * Get buffer by number or pattern.
1921 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001922 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001923tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001924{
1925 char_u *name = tv->vval.v_string;
1926 buf_T *buf;
1927
1928 if (tv->v_type == VAR_NUMBER)
1929 return buflist_findnr((int)tv->vval.v_number);
1930 if (tv->v_type != VAR_STRING)
1931 return NULL;
1932 if (name == NULL || *name == NUL)
1933 return curbuf;
1934 if (name[0] == '$' && name[1] == NUL)
1935 return lastbuf;
1936
1937 buf = buflist_find_by_name(name, curtab_only);
1938
1939 /* If not found, try expanding the name, like done for bufexists(). */
1940 if (buf == NULL)
1941 buf = find_buffer(tv);
1942
1943 return buf;
1944}
1945
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001946#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001947/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001948 * Get the buffer from "arg" and give an error and return NULL if it is not
1949 * valid.
1950 */
1951 static buf_T *
1952get_buf_arg(typval_T *arg)
1953{
1954 buf_T *buf;
1955
1956 ++emsg_off;
1957 buf = tv_get_buf(arg, FALSE);
1958 --emsg_off;
1959 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001960 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001961 return buf;
1962}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001963#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001964
1965/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001966 * "bufname(expr)" function
1967 */
1968 static void
1969f_bufname(typval_T *argvars, typval_T *rettv)
1970{
1971 buf_T *buf;
1972
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001973 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001974 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001975 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 rettv->v_type = VAR_STRING;
1977 if (buf != NULL && buf->b_fname != NULL)
1978 rettv->vval.v_string = vim_strsave(buf->b_fname);
1979 else
1980 rettv->vval.v_string = NULL;
1981 --emsg_off;
1982}
1983
1984/*
1985 * "bufnr(expr)" function
1986 */
1987 static void
1988f_bufnr(typval_T *argvars, typval_T *rettv)
1989{
1990 buf_T *buf;
1991 int error = FALSE;
1992 char_u *name;
1993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001994 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001996 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001997 --emsg_off;
1998
1999 /* If the buffer isn't found and the second argument is not zero create a
2000 * new buffer. */
2001 if (buf == NULL
2002 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002003 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002005 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006 && !error)
2007 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2008
2009 if (buf != NULL)
2010 rettv->vval.v_number = buf->b_fnum;
2011 else
2012 rettv->vval.v_number = -1;
2013}
2014
2015 static void
2016buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2017{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002018 win_T *wp;
2019 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002020 buf_T *buf;
2021
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002022 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002024 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002025 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002026 {
2027 ++winnr;
2028 if (wp->w_buffer == buf)
2029 break;
2030 }
2031 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002032 --emsg_off;
2033}
2034
2035/*
2036 * "bufwinid(nr)" function
2037 */
2038 static void
2039f_bufwinid(typval_T *argvars, typval_T *rettv)
2040{
2041 buf_win_common(argvars, rettv, FALSE);
2042}
2043
2044/*
2045 * "bufwinnr(nr)" function
2046 */
2047 static void
2048f_bufwinnr(typval_T *argvars, typval_T *rettv)
2049{
2050 buf_win_common(argvars, rettv, TRUE);
2051}
2052
2053/*
2054 * "byte2line(byte)" function
2055 */
2056 static void
2057f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2058{
2059#ifndef FEAT_BYTEOFF
2060 rettv->vval.v_number = -1;
2061#else
2062 long boff = 0;
2063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002064 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002065 if (boff < 0)
2066 rettv->vval.v_number = -1;
2067 else
2068 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2069 (linenr_T)0, &boff);
2070#endif
2071}
2072
2073 static void
2074byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2075{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002076 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077 char_u *str;
2078 varnumber_T idx;
2079
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002080 str = tv_get_string_chk(&argvars[0]);
2081 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082 rettv->vval.v_number = -1;
2083 if (str == NULL || idx < 0)
2084 return;
2085
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086 t = str;
2087 for ( ; idx > 0; idx--)
2088 {
2089 if (*t == NUL) /* EOL reached */
2090 return;
2091 if (enc_utf8 && comp)
2092 t += utf_ptr2len(t);
2093 else
2094 t += (*mb_ptr2len)(t);
2095 }
2096 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097}
2098
2099/*
2100 * "byteidx()" function
2101 */
2102 static void
2103f_byteidx(typval_T *argvars, typval_T *rettv)
2104{
2105 byteidx(argvars, rettv, FALSE);
2106}
2107
2108/*
2109 * "byteidxcomp()" function
2110 */
2111 static void
2112f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2113{
2114 byteidx(argvars, rettv, TRUE);
2115}
2116
2117/*
2118 * "call(func, arglist [, dict])" function
2119 */
2120 static void
2121f_call(typval_T *argvars, typval_T *rettv)
2122{
2123 char_u *func;
2124 partial_T *partial = NULL;
2125 dict_T *selfdict = NULL;
2126
2127 if (argvars[1].v_type != VAR_LIST)
2128 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002129 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002130 return;
2131 }
2132 if (argvars[1].vval.v_list == NULL)
2133 return;
2134
2135 if (argvars[0].v_type == VAR_FUNC)
2136 func = argvars[0].vval.v_string;
2137 else if (argvars[0].v_type == VAR_PARTIAL)
2138 {
2139 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002140 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002141 }
2142 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002143 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002144 if (*func == NUL)
2145 return; /* type error or empty name */
2146
2147 if (argvars[2].v_type != VAR_UNKNOWN)
2148 {
2149 if (argvars[2].v_type != VAR_DICT)
2150 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002151 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002152 return;
2153 }
2154 selfdict = argvars[2].vval.v_dict;
2155 }
2156
2157 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2158}
2159
2160#ifdef FEAT_FLOAT
2161/*
2162 * "ceil({float})" function
2163 */
2164 static void
2165f_ceil(typval_T *argvars, typval_T *rettv)
2166{
2167 float_T f = 0.0;
2168
2169 rettv->v_type = VAR_FLOAT;
2170 if (get_float_arg(argvars, &f) == OK)
2171 rettv->vval.v_float = ceil(f);
2172 else
2173 rettv->vval.v_float = 0.0;
2174}
2175#endif
2176
2177#ifdef FEAT_JOB_CHANNEL
2178/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002179 * "ch_canread()" function
2180 */
2181 static void
2182f_ch_canread(typval_T *argvars, typval_T *rettv)
2183{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002184 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002185
2186 rettv->vval.v_number = 0;
2187 if (channel != NULL)
2188 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2189 || channel_has_readahead(channel, PART_OUT)
2190 || channel_has_readahead(channel, PART_ERR);
2191}
2192
2193/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002194 * "ch_close()" function
2195 */
2196 static void
2197f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2198{
2199 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2200
2201 if (channel != NULL)
2202 {
2203 channel_close(channel, FALSE);
2204 channel_clear(channel);
2205 }
2206}
2207
2208/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002209 * "ch_close()" function
2210 */
2211 static void
2212f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2213{
2214 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2215
2216 if (channel != NULL)
2217 channel_close_in(channel);
2218}
2219
2220/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002221 * "ch_getbufnr()" function
2222 */
2223 static void
2224f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2225{
2226 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2227
2228 rettv->vval.v_number = -1;
2229 if (channel != NULL)
2230 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002231 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002232 int part;
2233
2234 if (STRCMP(what, "err") == 0)
2235 part = PART_ERR;
2236 else if (STRCMP(what, "out") == 0)
2237 part = PART_OUT;
2238 else if (STRCMP(what, "in") == 0)
2239 part = PART_IN;
2240 else
2241 part = PART_SOCK;
2242 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2243 rettv->vval.v_number =
2244 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2245 }
2246}
2247
2248/*
2249 * "ch_getjob()" function
2250 */
2251 static void
2252f_ch_getjob(typval_T *argvars, typval_T *rettv)
2253{
2254 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2255
2256 if (channel != NULL)
2257 {
2258 rettv->v_type = VAR_JOB;
2259 rettv->vval.v_job = channel->ch_job;
2260 if (channel->ch_job != NULL)
2261 ++channel->ch_job->jv_refcount;
2262 }
2263}
2264
2265/*
2266 * "ch_info()" function
2267 */
2268 static void
2269f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2270{
2271 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2272
2273 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2274 channel_info(channel, rettv->vval.v_dict);
2275}
2276
2277/*
2278 * "ch_log()" function
2279 */
2280 static void
2281f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2282{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002283 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002284 channel_T *channel = NULL;
2285
2286 if (argvars[1].v_type != VAR_UNKNOWN)
2287 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2288
Bram Moolenaard5359b22018-04-05 22:44:39 +02002289 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290}
2291
2292/*
2293 * "ch_logfile()" function
2294 */
2295 static void
2296f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2297{
2298 char_u *fname;
2299 char_u *opt = (char_u *)"";
2300 char_u buf[NUMBUFLEN];
2301
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002302 /* Don't open a file in restricted mode. */
2303 if (check_restricted() || check_secure())
2304 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002305 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002306 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002307 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 ch_logfile(fname, opt);
2309}
2310
2311/*
2312 * "ch_open()" function
2313 */
2314 static void
2315f_ch_open(typval_T *argvars, typval_T *rettv)
2316{
2317 rettv->v_type = VAR_CHANNEL;
2318 if (check_restricted() || check_secure())
2319 return;
2320 rettv->vval.v_channel = channel_open_func(argvars);
2321}
2322
2323/*
2324 * "ch_read()" function
2325 */
2326 static void
2327f_ch_read(typval_T *argvars, typval_T *rettv)
2328{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002329 common_channel_read(argvars, rettv, FALSE, FALSE);
2330}
2331
2332/*
2333 * "ch_readblob()" function
2334 */
2335 static void
2336f_ch_readblob(typval_T *argvars, typval_T *rettv)
2337{
2338 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002339}
2340
2341/*
2342 * "ch_readraw()" function
2343 */
2344 static void
2345f_ch_readraw(typval_T *argvars, typval_T *rettv)
2346{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002347 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002348}
2349
2350/*
2351 * "ch_evalexpr()" function
2352 */
2353 static void
2354f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2355{
2356 ch_expr_common(argvars, rettv, TRUE);
2357}
2358
2359/*
2360 * "ch_sendexpr()" function
2361 */
2362 static void
2363f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2364{
2365 ch_expr_common(argvars, rettv, FALSE);
2366}
2367
2368/*
2369 * "ch_evalraw()" function
2370 */
2371 static void
2372f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2373{
2374 ch_raw_common(argvars, rettv, TRUE);
2375}
2376
2377/*
2378 * "ch_sendraw()" function
2379 */
2380 static void
2381f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2382{
2383 ch_raw_common(argvars, rettv, FALSE);
2384}
2385
2386/*
2387 * "ch_setoptions()" function
2388 */
2389 static void
2390f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2391{
2392 channel_T *channel;
2393 jobopt_T opt;
2394
2395 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2396 if (channel == NULL)
2397 return;
2398 clear_job_options(&opt);
2399 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002400 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002401 channel_set_options(channel, &opt);
2402 free_job_options(&opt);
2403}
2404
2405/*
2406 * "ch_status()" function
2407 */
2408 static void
2409f_ch_status(typval_T *argvars, typval_T *rettv)
2410{
2411 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002412 jobopt_T opt;
2413 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414
2415 /* return an empty string by default */
2416 rettv->v_type = VAR_STRING;
2417 rettv->vval.v_string = NULL;
2418
2419 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002420
2421 if (argvars[1].v_type != VAR_UNKNOWN)
2422 {
2423 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002424 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002425 && (opt.jo_set & JO_PART))
2426 part = opt.jo_part;
2427 }
2428
2429 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002430}
2431#endif
2432
2433/*
2434 * "changenr()" function
2435 */
2436 static void
2437f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2438{
2439 rettv->vval.v_number = curbuf->b_u_seq_cur;
2440}
2441
2442/*
2443 * "char2nr(string)" function
2444 */
2445 static void
2446f_char2nr(typval_T *argvars, typval_T *rettv)
2447{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 if (has_mbyte)
2449 {
2450 int utf8 = 0;
2451
2452 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002453 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002454
2455 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002456 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002458 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 }
2460 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002461 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002462}
2463
2464/*
2465 * "cindent(lnum)" function
2466 */
2467 static void
2468f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2469{
2470#ifdef FEAT_CINDENT
2471 pos_T pos;
2472 linenr_T lnum;
2473
2474 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002475 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2477 {
2478 curwin->w_cursor.lnum = lnum;
2479 rettv->vval.v_number = get_c_indent();
2480 curwin->w_cursor = pos;
2481 }
2482 else
2483#endif
2484 rettv->vval.v_number = -1;
2485}
2486
2487/*
2488 * "clearmatches()" function
2489 */
2490 static void
2491f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2492{
2493#ifdef FEAT_SEARCH_EXTRA
2494 clear_matches(curwin);
2495#endif
2496}
2497
2498/*
2499 * "col(string)" function
2500 */
2501 static void
2502f_col(typval_T *argvars, typval_T *rettv)
2503{
2504 colnr_T col = 0;
2505 pos_T *fp;
2506 int fnum = curbuf->b_fnum;
2507
2508 fp = var2fpos(&argvars[0], FALSE, &fnum);
2509 if (fp != NULL && fnum == curbuf->b_fnum)
2510 {
2511 if (fp->col == MAXCOL)
2512 {
2513 /* '> can be MAXCOL, get the length of the line then */
2514 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2515 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2516 else
2517 col = MAXCOL;
2518 }
2519 else
2520 {
2521 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002522 /* col(".") when the cursor is on the NUL at the end of the line
2523 * because of "coladd" can be seen as an extra column. */
2524 if (virtual_active() && fp == &curwin->w_cursor)
2525 {
2526 char_u *p = ml_get_cursor();
2527
2528 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2529 curwin->w_virtcol - curwin->w_cursor.coladd))
2530 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002531 int l;
2532
2533 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2534 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002535 }
2536 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 }
2538 }
2539 rettv->vval.v_number = col;
2540}
2541
2542#if defined(FEAT_INS_EXPAND)
2543/*
2544 * "complete()" function
2545 */
2546 static void
2547f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2548{
2549 int startcol;
2550
2551 if ((State & INSERT) == 0)
2552 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002553 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 return;
2555 }
2556
2557 /* Check for undo allowed here, because if something was already inserted
2558 * the line was already saved for undo and this check isn't done. */
2559 if (!undo_allowed())
2560 return;
2561
2562 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2563 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002564 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002565 return;
2566 }
2567
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002568 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002569 if (startcol <= 0)
2570 return;
2571
2572 set_completion(startcol - 1, argvars[1].vval.v_list);
2573}
2574
2575/*
2576 * "complete_add()" function
2577 */
2578 static void
2579f_complete_add(typval_T *argvars, typval_T *rettv)
2580{
2581 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2582}
2583
2584/*
2585 * "complete_check()" function
2586 */
2587 static void
2588f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2589{
2590 int saved = RedrawingDisabled;
2591
2592 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002593 ins_compl_check_keys(0, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 rettv->vval.v_number = compl_interrupted;
2595 RedrawingDisabled = saved;
2596}
2597#endif
2598
2599/*
2600 * "confirm(message, buttons[, default [, type]])" function
2601 */
2602 static void
2603f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2604{
2605#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2606 char_u *message;
2607 char_u *buttons = NULL;
2608 char_u buf[NUMBUFLEN];
2609 char_u buf2[NUMBUFLEN];
2610 int def = 1;
2611 int type = VIM_GENERIC;
2612 char_u *typestr;
2613 int error = FALSE;
2614
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002615 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002616 if (message == NULL)
2617 error = TRUE;
2618 if (argvars[1].v_type != VAR_UNKNOWN)
2619 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002620 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 if (buttons == NULL)
2622 error = TRUE;
2623 if (argvars[2].v_type != VAR_UNKNOWN)
2624 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002625 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002626 if (argvars[3].v_type != VAR_UNKNOWN)
2627 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002628 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002629 if (typestr == NULL)
2630 error = TRUE;
2631 else
2632 {
2633 switch (TOUPPER_ASC(*typestr))
2634 {
2635 case 'E': type = VIM_ERROR; break;
2636 case 'Q': type = VIM_QUESTION; break;
2637 case 'I': type = VIM_INFO; break;
2638 case 'W': type = VIM_WARNING; break;
2639 case 'G': type = VIM_GENERIC; break;
2640 }
2641 }
2642 }
2643 }
2644 }
2645
2646 if (buttons == NULL || *buttons == NUL)
2647 buttons = (char_u *)_("&Ok");
2648
2649 if (!error)
2650 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2651 def, NULL, FALSE);
2652#endif
2653}
2654
2655/*
2656 * "copy()" function
2657 */
2658 static void
2659f_copy(typval_T *argvars, typval_T *rettv)
2660{
2661 item_copy(&argvars[0], rettv, FALSE, 0);
2662}
2663
2664#ifdef FEAT_FLOAT
2665/*
2666 * "cos()" function
2667 */
2668 static void
2669f_cos(typval_T *argvars, typval_T *rettv)
2670{
2671 float_T f = 0.0;
2672
2673 rettv->v_type = VAR_FLOAT;
2674 if (get_float_arg(argvars, &f) == OK)
2675 rettv->vval.v_float = cos(f);
2676 else
2677 rettv->vval.v_float = 0.0;
2678}
2679
2680/*
2681 * "cosh()" function
2682 */
2683 static void
2684f_cosh(typval_T *argvars, typval_T *rettv)
2685{
2686 float_T f = 0.0;
2687
2688 rettv->v_type = VAR_FLOAT;
2689 if (get_float_arg(argvars, &f) == OK)
2690 rettv->vval.v_float = cosh(f);
2691 else
2692 rettv->vval.v_float = 0.0;
2693}
2694#endif
2695
2696/*
2697 * "count()" function
2698 */
2699 static void
2700f_count(typval_T *argvars, typval_T *rettv)
2701{
2702 long n = 0;
2703 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002704 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705
Bram Moolenaar9966b212017-07-28 16:46:57 +02002706 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002707 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002708
2709 if (argvars[0].v_type == VAR_STRING)
2710 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002711 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002712 char_u *p = argvars[0].vval.v_string;
2713 char_u *next;
2714
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002715 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002716 {
2717 if (ic)
2718 {
2719 size_t len = STRLEN(expr);
2720
2721 while (*p != NUL)
2722 {
2723 if (MB_STRNICMP(p, expr, len) == 0)
2724 {
2725 ++n;
2726 p += len;
2727 }
2728 else
2729 MB_PTR_ADV(p);
2730 }
2731 }
2732 else
2733 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2734 != NULL)
2735 {
2736 ++n;
2737 p = next + STRLEN(expr);
2738 }
2739 }
2740
2741 }
2742 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002743 {
2744 listitem_T *li;
2745 list_T *l;
2746 long idx;
2747
2748 if ((l = argvars[0].vval.v_list) != NULL)
2749 {
2750 li = l->lv_first;
2751 if (argvars[2].v_type != VAR_UNKNOWN)
2752 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002753 if (argvars[3].v_type != VAR_UNKNOWN)
2754 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002755 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 if (!error)
2757 {
2758 li = list_find(l, idx);
2759 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002760 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002761 }
2762 }
2763 if (error)
2764 li = NULL;
2765 }
2766
2767 for ( ; li != NULL; li = li->li_next)
2768 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2769 ++n;
2770 }
2771 }
2772 else if (argvars[0].v_type == VAR_DICT)
2773 {
2774 int todo;
2775 dict_T *d;
2776 hashitem_T *hi;
2777
2778 if ((d = argvars[0].vval.v_dict) != NULL)
2779 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002780 if (argvars[2].v_type != VAR_UNKNOWN)
2781 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002782 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002783 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002784 }
2785
2786 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2787 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2788 {
2789 if (!HASHITEM_EMPTY(hi))
2790 {
2791 --todo;
2792 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2793 ++n;
2794 }
2795 }
2796 }
2797 }
2798 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002799 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002800 rettv->vval.v_number = n;
2801}
2802
2803/*
2804 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2805 *
2806 * Checks the existence of a cscope connection.
2807 */
2808 static void
2809f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2810{
2811#ifdef FEAT_CSCOPE
2812 int num = 0;
2813 char_u *dbpath = NULL;
2814 char_u *prepend = NULL;
2815 char_u buf[NUMBUFLEN];
2816
2817 if (argvars[0].v_type != VAR_UNKNOWN
2818 && argvars[1].v_type != VAR_UNKNOWN)
2819 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002820 num = (int)tv_get_number(&argvars[0]);
2821 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002822 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002823 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002824 }
2825
2826 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2827#endif
2828}
2829
2830/*
2831 * "cursor(lnum, col)" function, or
2832 * "cursor(list)"
2833 *
2834 * Moves the cursor to the specified line and column.
2835 * Returns 0 when the position could be set, -1 otherwise.
2836 */
2837 static void
2838f_cursor(typval_T *argvars, typval_T *rettv)
2839{
2840 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002841 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002842 int set_curswant = TRUE;
2843
2844 rettv->vval.v_number = -1;
2845 if (argvars[1].v_type == VAR_UNKNOWN)
2846 {
2847 pos_T pos;
2848 colnr_T curswant = -1;
2849
2850 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2851 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002852 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002853 return;
2854 }
2855 line = pos.lnum;
2856 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002857 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002858 if (curswant >= 0)
2859 {
2860 curwin->w_curswant = curswant - 1;
2861 set_curswant = FALSE;
2862 }
2863 }
2864 else
2865 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002866 line = tv_get_lnum(argvars);
2867 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002868 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002869 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002870 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002871 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002872 return; /* type error; errmsg already given */
2873 if (line > 0)
2874 curwin->w_cursor.lnum = line;
2875 if (col > 0)
2876 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002877 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878
2879 /* Make sure the cursor is in a valid position. */
2880 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002881 /* Correct cursor for multi-byte character. */
2882 if (has_mbyte)
2883 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002884
2885 curwin->w_set_curswant = set_curswant;
2886 rettv->vval.v_number = 0;
2887}
2888
Bram Moolenaar4f974752019-02-17 17:44:42 +01002889#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002890/*
2891 * "debugbreak()" function
2892 */
2893 static void
2894f_debugbreak(typval_T *argvars, typval_T *rettv)
2895{
2896 int pid;
2897
2898 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002899 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002900 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002901 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002902 else
2903 {
2904 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2905
2906 if (hProcess != NULL)
2907 {
2908 DebugBreakProcess(hProcess);
2909 CloseHandle(hProcess);
2910 rettv->vval.v_number = OK;
2911 }
2912 }
2913}
2914#endif
2915
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002916/*
2917 * "deepcopy()" function
2918 */
2919 static void
2920f_deepcopy(typval_T *argvars, typval_T *rettv)
2921{
2922 int noref = 0;
2923 int copyID;
2924
2925 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002926 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002927 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002928 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002929 else
2930 {
2931 copyID = get_copyID();
2932 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2933 }
2934}
2935
2936/*
2937 * "delete()" function
2938 */
2939 static void
2940f_delete(typval_T *argvars, typval_T *rettv)
2941{
2942 char_u nbuf[NUMBUFLEN];
2943 char_u *name;
2944 char_u *flags;
2945
2946 rettv->vval.v_number = -1;
2947 if (check_restricted() || check_secure())
2948 return;
2949
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002950 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002951 if (name == NULL || *name == NUL)
2952 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002953 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002954 return;
2955 }
2956
2957 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002958 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002959 else
2960 flags = (char_u *)"";
2961
2962 if (*flags == NUL)
2963 /* delete a file */
2964 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2965 else if (STRCMP(flags, "d") == 0)
2966 /* delete an empty directory */
2967 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2968 else if (STRCMP(flags, "rf") == 0)
2969 /* delete a directory recursively */
2970 rettv->vval.v_number = delete_recursive(name);
2971 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002972 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002973}
2974
2975/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002976 * "deletebufline()" function
2977 */
2978 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002979f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002980{
2981 buf_T *buf;
2982 linenr_T first, last;
2983 linenr_T lnum;
2984 long count;
2985 int is_curbuf;
2986 buf_T *curbuf_save = NULL;
2987 win_T *curwin_save = NULL;
2988 tabpage_T *tp;
2989 win_T *wp;
2990
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002991 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002992 if (buf == NULL)
2993 {
2994 rettv->vval.v_number = 1; /* FAIL */
2995 return;
2996 }
2997 is_curbuf = buf == curbuf;
2998
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002999 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003000 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003001 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003002 else
3003 last = first;
3004
3005 if (buf->b_ml.ml_mfp == NULL || first < 1
3006 || first > buf->b_ml.ml_line_count || last < first)
3007 {
3008 rettv->vval.v_number = 1; /* FAIL */
3009 return;
3010 }
3011
3012 if (!is_curbuf)
3013 {
3014 curbuf_save = curbuf;
3015 curwin_save = curwin;
3016 curbuf = buf;
3017 find_win_for_curbuf();
3018 }
3019 if (last > curbuf->b_ml.ml_line_count)
3020 last = curbuf->b_ml.ml_line_count;
3021 count = last - first + 1;
3022
3023 // When coming here from Insert mode, sync undo, so that this can be
3024 // undone separately from what was previously inserted.
3025 if (u_sync_once == 2)
3026 {
3027 u_sync_once = 1; // notify that u_sync() was called
3028 u_sync(TRUE);
3029 }
3030
3031 if (u_save(first - 1, last + 1) == FAIL)
3032 {
3033 rettv->vval.v_number = 1; /* FAIL */
3034 return;
3035 }
3036
3037 for (lnum = first; lnum <= last; ++lnum)
3038 ml_delete(first, TRUE);
3039
3040 FOR_ALL_TAB_WINDOWS(tp, wp)
3041 if (wp->w_buffer == buf)
3042 {
3043 if (wp->w_cursor.lnum > last)
3044 wp->w_cursor.lnum -= count;
3045 else if (wp->w_cursor.lnum> first)
3046 wp->w_cursor.lnum = first;
3047 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3048 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3049 }
3050 check_cursor_col();
3051 deleted_lines_mark(first, count);
3052
3053 if (!is_curbuf)
3054 {
3055 curbuf = curbuf_save;
3056 curwin = curwin_save;
3057 }
3058}
3059
3060/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003061 * "did_filetype()" function
3062 */
3063 static void
3064f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3065{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003066 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003067}
3068
3069/*
3070 * "diff_filler()" function
3071 */
3072 static void
3073f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3074{
3075#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003076 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077#endif
3078}
3079
3080/*
3081 * "diff_hlID()" function
3082 */
3083 static void
3084f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3085{
3086#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003087 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003088 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003089 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003090 static int fnum = 0;
3091 static int change_start = 0;
3092 static int change_end = 0;
3093 static hlf_T hlID = (hlf_T)0;
3094 int filler_lines;
3095 int col;
3096
3097 if (lnum < 0) /* ignore type error in {lnum} arg */
3098 lnum = 0;
3099 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003100 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003101 || fnum != curbuf->b_fnum)
3102 {
3103 /* New line, buffer, change: need to get the values. */
3104 filler_lines = diff_check(curwin, lnum);
3105 if (filler_lines < 0)
3106 {
3107 if (filler_lines == -1)
3108 {
3109 change_start = MAXCOL;
3110 change_end = -1;
3111 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3112 hlID = HLF_ADD; /* added line */
3113 else
3114 hlID = HLF_CHD; /* changed line */
3115 }
3116 else
3117 hlID = HLF_ADD; /* added line */
3118 }
3119 else
3120 hlID = (hlf_T)0;
3121 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003122 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003123 fnum = curbuf->b_fnum;
3124 }
3125
3126 if (hlID == HLF_CHD || hlID == HLF_TXD)
3127 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003128 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003129 if (col >= change_start && col <= change_end)
3130 hlID = HLF_TXD; /* changed text */
3131 else
3132 hlID = HLF_CHD; /* changed line */
3133 }
3134 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3135#endif
3136}
3137
3138/*
3139 * "empty({expr})" function
3140 */
3141 static void
3142f_empty(typval_T *argvars, typval_T *rettv)
3143{
3144 int n = FALSE;
3145
3146 switch (argvars[0].v_type)
3147 {
3148 case VAR_STRING:
3149 case VAR_FUNC:
3150 n = argvars[0].vval.v_string == NULL
3151 || *argvars[0].vval.v_string == NUL;
3152 break;
3153 case VAR_PARTIAL:
3154 n = FALSE;
3155 break;
3156 case VAR_NUMBER:
3157 n = argvars[0].vval.v_number == 0;
3158 break;
3159 case VAR_FLOAT:
3160#ifdef FEAT_FLOAT
3161 n = argvars[0].vval.v_float == 0.0;
3162 break;
3163#endif
3164 case VAR_LIST:
3165 n = argvars[0].vval.v_list == NULL
3166 || argvars[0].vval.v_list->lv_first == NULL;
3167 break;
3168 case VAR_DICT:
3169 n = argvars[0].vval.v_dict == NULL
3170 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3171 break;
3172 case VAR_SPECIAL:
3173 n = argvars[0].vval.v_number != VVAL_TRUE;
3174 break;
3175
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003176 case VAR_BLOB:
3177 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003178 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3179 break;
3180
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003181 case VAR_JOB:
3182#ifdef FEAT_JOB_CHANNEL
3183 n = argvars[0].vval.v_job == NULL
3184 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3185 break;
3186#endif
3187 case VAR_CHANNEL:
3188#ifdef FEAT_JOB_CHANNEL
3189 n = argvars[0].vval.v_channel == NULL
3190 || !channel_is_open(argvars[0].vval.v_channel);
3191 break;
3192#endif
3193 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003194 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003195 n = TRUE;
3196 break;
3197 }
3198
3199 rettv->vval.v_number = n;
3200}
3201
3202/*
3203 * "escape({string}, {chars})" function
3204 */
3205 static void
3206f_escape(typval_T *argvars, typval_T *rettv)
3207{
3208 char_u buf[NUMBUFLEN];
3209
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003210 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3211 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003212 rettv->v_type = VAR_STRING;
3213}
3214
3215/*
3216 * "eval()" function
3217 */
3218 static void
3219f_eval(typval_T *argvars, typval_T *rettv)
3220{
3221 char_u *s, *p;
3222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003223 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003224 if (s != NULL)
3225 s = skipwhite(s);
3226
3227 p = s;
3228 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3229 {
3230 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003231 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003232 need_clr_eos = FALSE;
3233 rettv->v_type = VAR_NUMBER;
3234 rettv->vval.v_number = 0;
3235 }
3236 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003237 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238}
3239
3240/*
3241 * "eventhandler()" function
3242 */
3243 static void
3244f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3245{
3246 rettv->vval.v_number = vgetc_busy;
3247}
3248
3249/*
3250 * "executable()" function
3251 */
3252 static void
3253f_executable(typval_T *argvars, typval_T *rettv)
3254{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003255 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003256
3257 /* Check in $PATH and also check directly if there is a directory name. */
3258 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3259 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3260}
3261
3262static garray_T redir_execute_ga;
3263
3264/*
3265 * Append "value[value_len]" to the execute() output.
3266 */
3267 void
3268execute_redir_str(char_u *value, int value_len)
3269{
3270 int len;
3271
3272 if (value_len == -1)
3273 len = (int)STRLEN(value); /* Append the entire string */
3274 else
3275 len = value_len; /* Append only "value_len" characters */
3276 if (ga_grow(&redir_execute_ga, len) == OK)
3277 {
3278 mch_memmove((char *)redir_execute_ga.ga_data
3279 + redir_execute_ga.ga_len, value, len);
3280 redir_execute_ga.ga_len += len;
3281 }
3282}
3283
3284/*
3285 * Get next line from a list.
3286 * Called by do_cmdline() to get the next line.
3287 * Returns allocated string, or NULL for end of function.
3288 */
3289
3290 static char_u *
3291get_list_line(
3292 int c UNUSED,
3293 void *cookie,
3294 int indent UNUSED)
3295{
3296 listitem_T **p = (listitem_T **)cookie;
3297 listitem_T *item = *p;
3298 char_u buf[NUMBUFLEN];
3299 char_u *s;
3300
3301 if (item == NULL)
3302 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003303 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003304 *p = item->li_next;
3305 return s == NULL ? NULL : vim_strsave(s);
3306}
3307
3308/*
3309 * "execute()" function
3310 */
3311 static void
3312f_execute(typval_T *argvars, typval_T *rettv)
3313{
3314 char_u *cmd = NULL;
3315 list_T *list = NULL;
3316 int save_msg_silent = msg_silent;
3317 int save_emsg_silent = emsg_silent;
3318 int save_emsg_noredir = emsg_noredir;
3319 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003320 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003322 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003323 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003324
3325 rettv->vval.v_string = NULL;
3326 rettv->v_type = VAR_STRING;
3327
3328 if (argvars[0].v_type == VAR_LIST)
3329 {
3330 list = argvars[0].vval.v_list;
3331 if (list == NULL || list->lv_first == NULL)
3332 /* empty list, no commands, empty output */
3333 return;
3334 ++list->lv_refcount;
3335 }
3336 else
3337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003338 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003339 if (cmd == NULL)
3340 return;
3341 }
3342
3343 if (argvars[1].v_type != VAR_UNKNOWN)
3344 {
3345 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003346 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003347
3348 if (s == NULL)
3349 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003350 if (*s == NUL)
3351 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003352 if (STRNCMP(s, "silent", 6) == 0)
3353 ++msg_silent;
3354 if (STRCMP(s, "silent!") == 0)
3355 {
3356 emsg_silent = TRUE;
3357 emsg_noredir = TRUE;
3358 }
3359 }
3360 else
3361 ++msg_silent;
3362
3363 if (redir_execute)
3364 save_ga = redir_execute_ga;
3365 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3366 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003367 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003368 if (!echo_output)
3369 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003370
3371 if (cmd != NULL)
3372 do_cmdline_cmd(cmd);
3373 else
3374 {
3375 listitem_T *item = list->lv_first;
3376
3377 do_cmdline(NULL, get_list_line, (void *)&item,
3378 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3379 --list->lv_refcount;
3380 }
3381
Bram Moolenaard297f352017-01-29 20:31:21 +01003382 /* Need to append a NUL to the result. */
3383 if (ga_grow(&redir_execute_ga, 1) == OK)
3384 {
3385 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3386 rettv->vval.v_string = redir_execute_ga.ga_data;
3387 }
3388 else
3389 {
3390 ga_clear(&redir_execute_ga);
3391 rettv->vval.v_string = NULL;
3392 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003393 msg_silent = save_msg_silent;
3394 emsg_silent = save_emsg_silent;
3395 emsg_noredir = save_emsg_noredir;
3396
3397 redir_execute = save_redir_execute;
3398 if (redir_execute)
3399 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003400 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003401
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003402 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003403 if (echo_output)
3404 // When not working silently: put it in column zero. A following
3405 // "echon" will overwrite the message, unavoidably.
3406 msg_col = 0;
3407 else
3408 // When working silently: Put it back where it was, since nothing
3409 // should have been written.
3410 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003411}
3412
3413/*
3414 * "exepath()" function
3415 */
3416 static void
3417f_exepath(typval_T *argvars, typval_T *rettv)
3418{
3419 char_u *p = NULL;
3420
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003421 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422 rettv->v_type = VAR_STRING;
3423 rettv->vval.v_string = p;
3424}
3425
3426/*
3427 * "exists()" function
3428 */
3429 static void
3430f_exists(typval_T *argvars, typval_T *rettv)
3431{
3432 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003433 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003435 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436 if (*p == '$') /* environment variable */
3437 {
3438 /* first try "normal" environment variables (fast) */
3439 if (mch_getenv(p + 1) != NULL)
3440 n = TRUE;
3441 else
3442 {
3443 /* try expanding things like $VIM and ${HOME} */
3444 p = expand_env_save(p);
3445 if (p != NULL && *p != '$')
3446 n = TRUE;
3447 vim_free(p);
3448 }
3449 }
3450 else if (*p == '&' || *p == '+') /* option */
3451 {
3452 n = (get_option_tv(&p, NULL, TRUE) == OK);
3453 if (*skipwhite(p) != NUL)
3454 n = FALSE; /* trailing garbage */
3455 }
3456 else if (*p == '*') /* internal or user defined function */
3457 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003458 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003459 }
3460 else if (*p == ':')
3461 {
3462 n = cmd_exists(p + 1);
3463 }
3464 else if (*p == '#')
3465 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003466 if (p[1] == '#')
3467 n = autocmd_supported(p + 2);
3468 else
3469 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470 }
3471 else /* internal variable */
3472 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003473 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474 }
3475
3476 rettv->vval.v_number = n;
3477}
3478
3479#ifdef FEAT_FLOAT
3480/*
3481 * "exp()" function
3482 */
3483 static void
3484f_exp(typval_T *argvars, typval_T *rettv)
3485{
3486 float_T f = 0.0;
3487
3488 rettv->v_type = VAR_FLOAT;
3489 if (get_float_arg(argvars, &f) == OK)
3490 rettv->vval.v_float = exp(f);
3491 else
3492 rettv->vval.v_float = 0.0;
3493}
3494#endif
3495
3496/*
3497 * "expand()" function
3498 */
3499 static void
3500f_expand(typval_T *argvars, typval_T *rettv)
3501{
3502 char_u *s;
3503 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003504 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3506 expand_T xpc;
3507 int error = FALSE;
3508 char_u *result;
3509
3510 rettv->v_type = VAR_STRING;
3511 if (argvars[1].v_type != VAR_UNKNOWN
3512 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003513 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514 && !error)
3515 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003516 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517 }
3518
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003519 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 if (*s == '%' || *s == '#' || *s == '<')
3521 {
3522 ++emsg_off;
3523 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3524 --emsg_off;
3525 if (rettv->v_type == VAR_LIST)
3526 {
3527 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3528 list_append_string(rettv->vval.v_list, result, -1);
3529 else
3530 vim_free(result);
3531 }
3532 else
3533 rettv->vval.v_string = result;
3534 }
3535 else
3536 {
3537 /* When the optional second argument is non-zero, don't remove matches
3538 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3539 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003540 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003541 options |= WILD_KEEP_ALL;
3542 if (!error)
3543 {
3544 ExpandInit(&xpc);
3545 xpc.xp_context = EXPAND_FILES;
3546 if (p_wic)
3547 options += WILD_ICASE;
3548 if (rettv->v_type == VAR_STRING)
3549 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3550 options, WILD_ALL);
3551 else if (rettv_list_alloc(rettv) != FAIL)
3552 {
3553 int i;
3554
3555 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3556 for (i = 0; i < xpc.xp_numfiles; i++)
3557 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3558 ExpandCleanup(&xpc);
3559 }
3560 }
3561 else
3562 rettv->vval.v_string = NULL;
3563 }
3564}
3565
3566/*
3567 * "extend(list, list [, idx])" function
3568 * "extend(dict, dict [, action])" function
3569 */
3570 static void
3571f_extend(typval_T *argvars, typval_T *rettv)
3572{
3573 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3574
3575 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3576 {
3577 list_T *l1, *l2;
3578 listitem_T *item;
3579 long before;
3580 int error = FALSE;
3581
3582 l1 = argvars[0].vval.v_list;
3583 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003584 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003585 && l2 != NULL)
3586 {
3587 if (argvars[2].v_type != VAR_UNKNOWN)
3588 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003589 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590 if (error)
3591 return; /* type error; errmsg already given */
3592
3593 if (before == l1->lv_len)
3594 item = NULL;
3595 else
3596 {
3597 item = list_find(l1, before);
3598 if (item == NULL)
3599 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003600 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003601 return;
3602 }
3603 }
3604 }
3605 else
3606 item = NULL;
3607 list_extend(l1, l2, item);
3608
3609 copy_tv(&argvars[0], rettv);
3610 }
3611 }
3612 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3613 {
3614 dict_T *d1, *d2;
3615 char_u *action;
3616 int i;
3617
3618 d1 = argvars[0].vval.v_dict;
3619 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003620 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003621 && d2 != NULL)
3622 {
3623 /* Check the third argument. */
3624 if (argvars[2].v_type != VAR_UNKNOWN)
3625 {
3626 static char *(av[]) = {"keep", "force", "error"};
3627
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003628 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003629 if (action == NULL)
3630 return; /* type error; errmsg already given */
3631 for (i = 0; i < 3; ++i)
3632 if (STRCMP(action, av[i]) == 0)
3633 break;
3634 if (i == 3)
3635 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003636 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 return;
3638 }
3639 }
3640 else
3641 action = (char_u *)"force";
3642
3643 dict_extend(d1, d2, action);
3644
3645 copy_tv(&argvars[0], rettv);
3646 }
3647 }
3648 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003649 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003650}
3651
3652/*
3653 * "feedkeys()" function
3654 */
3655 static void
3656f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3657{
3658 int remap = TRUE;
3659 int insert = FALSE;
3660 char_u *keys, *flags;
3661 char_u nbuf[NUMBUFLEN];
3662 int typed = FALSE;
3663 int execute = FALSE;
3664 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003665 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003666 char_u *keys_esc;
3667
3668 /* This is not allowed in the sandbox. If the commands would still be
3669 * executed in the sandbox it would be OK, but it probably happens later,
3670 * when "sandbox" is no longer set. */
3671 if (check_secure())
3672 return;
3673
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003674 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003675
3676 if (argvars[1].v_type != VAR_UNKNOWN)
3677 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003678 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003679 for ( ; *flags != NUL; ++flags)
3680 {
3681 switch (*flags)
3682 {
3683 case 'n': remap = FALSE; break;
3684 case 'm': remap = TRUE; break;
3685 case 't': typed = TRUE; break;
3686 case 'i': insert = TRUE; break;
3687 case 'x': execute = TRUE; break;
3688 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003689 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003690 }
3691 }
3692 }
3693
3694 if (*keys != NUL || execute)
3695 {
3696 /* Need to escape K_SPECIAL and CSI before putting the string in the
3697 * typeahead buffer. */
3698 keys_esc = vim_strsave_escape_csi(keys);
3699 if (keys_esc != NULL)
3700 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003701 if (lowlevel)
3702 {
3703#ifdef USE_INPUT_BUF
3704 add_to_input_buf(keys, (int)STRLEN(keys));
3705#else
3706 emsg(_("E980: lowlevel input not supported"));
3707#endif
3708 }
3709 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003710 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003711 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003712 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003713 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003714#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003715 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003716#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003717 )
3718 typebuf_was_filled = TRUE;
3719 }
3720 vim_free(keys_esc);
3721
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722 if (execute)
3723 {
3724 int save_msg_scroll = msg_scroll;
3725
3726 /* Avoid a 1 second delay when the keys start Insert mode. */
3727 msg_scroll = FALSE;
3728
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003729 if (!dangerous)
3730 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003731 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003732 if (!dangerous)
3733 --ex_normal_busy;
3734
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735 msg_scroll |= save_msg_scroll;
3736 }
3737 }
3738 }
3739}
3740
3741/*
3742 * "filereadable()" function
3743 */
3744 static void
3745f_filereadable(typval_T *argvars, typval_T *rettv)
3746{
3747 int fd;
3748 char_u *p;
3749 int n;
3750
3751#ifndef O_NONBLOCK
3752# define O_NONBLOCK 0
3753#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003754 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003755 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3756 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3757 {
3758 n = TRUE;
3759 close(fd);
3760 }
3761 else
3762 n = FALSE;
3763
3764 rettv->vval.v_number = n;
3765}
3766
3767/*
3768 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3769 * rights to write into.
3770 */
3771 static void
3772f_filewritable(typval_T *argvars, typval_T *rettv)
3773{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003774 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775}
3776
3777 static void
3778findfilendir(
3779 typval_T *argvars UNUSED,
3780 typval_T *rettv,
3781 int find_what UNUSED)
3782{
3783#ifdef FEAT_SEARCHPATH
3784 char_u *fname;
3785 char_u *fresult = NULL;
3786 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3787 char_u *p;
3788 char_u pathbuf[NUMBUFLEN];
3789 int count = 1;
3790 int first = TRUE;
3791 int error = FALSE;
3792#endif
3793
3794 rettv->vval.v_string = NULL;
3795 rettv->v_type = VAR_STRING;
3796
3797#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003798 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003799
3800 if (argvars[1].v_type != VAR_UNKNOWN)
3801 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003802 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003803 if (p == NULL)
3804 error = TRUE;
3805 else
3806 {
3807 if (*p != NUL)
3808 path = p;
3809
3810 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003811 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003812 }
3813 }
3814
3815 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3816 error = TRUE;
3817
3818 if (*fname != NUL && !error)
3819 {
3820 do
3821 {
3822 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3823 vim_free(fresult);
3824 fresult = find_file_in_path_option(first ? fname : NULL,
3825 first ? (int)STRLEN(fname) : 0,
3826 0, first, path,
3827 find_what,
3828 curbuf->b_ffname,
3829 find_what == FINDFILE_DIR
3830 ? (char_u *)"" : curbuf->b_p_sua);
3831 first = FALSE;
3832
3833 if (fresult != NULL && rettv->v_type == VAR_LIST)
3834 list_append_string(rettv->vval.v_list, fresult, -1);
3835
3836 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3837 }
3838
3839 if (rettv->v_type == VAR_STRING)
3840 rettv->vval.v_string = fresult;
3841#endif
3842}
3843
3844/*
3845 * "filter()" function
3846 */
3847 static void
3848f_filter(typval_T *argvars, typval_T *rettv)
3849{
3850 filter_map(argvars, rettv, FALSE);
3851}
3852
3853/*
3854 * "finddir({fname}[, {path}[, {count}]])" function
3855 */
3856 static void
3857f_finddir(typval_T *argvars, typval_T *rettv)
3858{
3859 findfilendir(argvars, rettv, FINDFILE_DIR);
3860}
3861
3862/*
3863 * "findfile({fname}[, {path}[, {count}]])" function
3864 */
3865 static void
3866f_findfile(typval_T *argvars, typval_T *rettv)
3867{
3868 findfilendir(argvars, rettv, FINDFILE_FILE);
3869}
3870
3871#ifdef FEAT_FLOAT
3872/*
3873 * "float2nr({float})" function
3874 */
3875 static void
3876f_float2nr(typval_T *argvars, typval_T *rettv)
3877{
3878 float_T f = 0.0;
3879
3880 if (get_float_arg(argvars, &f) == OK)
3881 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003882 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003883 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003884 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003885 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003886 else
3887 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003888 }
3889}
3890
3891/*
3892 * "floor({float})" function
3893 */
3894 static void
3895f_floor(typval_T *argvars, typval_T *rettv)
3896{
3897 float_T f = 0.0;
3898
3899 rettv->v_type = VAR_FLOAT;
3900 if (get_float_arg(argvars, &f) == OK)
3901 rettv->vval.v_float = floor(f);
3902 else
3903 rettv->vval.v_float = 0.0;
3904}
3905
3906/*
3907 * "fmod()" function
3908 */
3909 static void
3910f_fmod(typval_T *argvars, typval_T *rettv)
3911{
3912 float_T fx = 0.0, fy = 0.0;
3913
3914 rettv->v_type = VAR_FLOAT;
3915 if (get_float_arg(argvars, &fx) == OK
3916 && get_float_arg(&argvars[1], &fy) == OK)
3917 rettv->vval.v_float = fmod(fx, fy);
3918 else
3919 rettv->vval.v_float = 0.0;
3920}
3921#endif
3922
3923/*
3924 * "fnameescape({string})" function
3925 */
3926 static void
3927f_fnameescape(typval_T *argvars, typval_T *rettv)
3928{
3929 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003930 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931 rettv->v_type = VAR_STRING;
3932}
3933
3934/*
3935 * "fnamemodify({fname}, {mods})" function
3936 */
3937 static void
3938f_fnamemodify(typval_T *argvars, typval_T *rettv)
3939{
3940 char_u *fname;
3941 char_u *mods;
3942 int usedlen = 0;
3943 int len;
3944 char_u *fbuf = NULL;
3945 char_u buf[NUMBUFLEN];
3946
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003947 fname = tv_get_string_chk(&argvars[0]);
3948 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003949 if (fname == NULL || mods == NULL)
3950 fname = NULL;
3951 else
3952 {
3953 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003954 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003955 }
3956
3957 rettv->v_type = VAR_STRING;
3958 if (fname == NULL)
3959 rettv->vval.v_string = NULL;
3960 else
3961 rettv->vval.v_string = vim_strnsave(fname, len);
3962 vim_free(fbuf);
3963}
3964
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003965/*
3966 * "foldclosed()" function
3967 */
3968 static void
3969foldclosed_both(
3970 typval_T *argvars UNUSED,
3971 typval_T *rettv,
3972 int end UNUSED)
3973{
3974#ifdef FEAT_FOLDING
3975 linenr_T lnum;
3976 linenr_T first, last;
3977
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003978 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003979 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3980 {
3981 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3982 {
3983 if (end)
3984 rettv->vval.v_number = (varnumber_T)last;
3985 else
3986 rettv->vval.v_number = (varnumber_T)first;
3987 return;
3988 }
3989 }
3990#endif
3991 rettv->vval.v_number = -1;
3992}
3993
3994/*
3995 * "foldclosed()" function
3996 */
3997 static void
3998f_foldclosed(typval_T *argvars, typval_T *rettv)
3999{
4000 foldclosed_both(argvars, rettv, FALSE);
4001}
4002
4003/*
4004 * "foldclosedend()" function
4005 */
4006 static void
4007f_foldclosedend(typval_T *argvars, typval_T *rettv)
4008{
4009 foldclosed_both(argvars, rettv, TRUE);
4010}
4011
4012/*
4013 * "foldlevel()" function
4014 */
4015 static void
4016f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4017{
4018#ifdef FEAT_FOLDING
4019 linenr_T lnum;
4020
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004021 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004022 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4023 rettv->vval.v_number = foldLevel(lnum);
4024#endif
4025}
4026
4027/*
4028 * "foldtext()" function
4029 */
4030 static void
4031f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4032{
4033#ifdef FEAT_FOLDING
4034 linenr_T foldstart;
4035 linenr_T foldend;
4036 char_u *dashes;
4037 linenr_T lnum;
4038 char_u *s;
4039 char_u *r;
4040 int len;
4041 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004042 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004043#endif
4044
4045 rettv->v_type = VAR_STRING;
4046 rettv->vval.v_string = NULL;
4047#ifdef FEAT_FOLDING
4048 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4049 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4050 dashes = get_vim_var_str(VV_FOLDDASHES);
4051 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4052 && dashes != NULL)
4053 {
4054 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004055 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004056 if (!linewhite(lnum))
4057 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004058
4059 /* Find interesting text in this line. */
4060 s = skipwhite(ml_get(lnum));
4061 /* skip C comment-start */
4062 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4063 {
4064 s = skipwhite(s + 2);
4065 if (*skipwhite(s) == NUL
4066 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4067 {
4068 s = skipwhite(ml_get(lnum + 1));
4069 if (*s == '*')
4070 s = skipwhite(s + 1);
4071 }
4072 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004073 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004074 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004075 r = alloc((unsigned)(STRLEN(txt)
4076 + STRLEN(dashes) /* for %s */
4077 + 20 /* for %3ld */
4078 + STRLEN(s))); /* concatenated */
4079 if (r != NULL)
4080 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004081 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004082 len = (int)STRLEN(r);
4083 STRCAT(r, s);
4084 /* remove 'foldmarker' and 'commentstring' */
4085 foldtext_cleanup(r + len);
4086 rettv->vval.v_string = r;
4087 }
4088 }
4089#endif
4090}
4091
4092/*
4093 * "foldtextresult(lnum)" function
4094 */
4095 static void
4096f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4097{
4098#ifdef FEAT_FOLDING
4099 linenr_T lnum;
4100 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004101 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004102 foldinfo_T foldinfo;
4103 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004104 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004105#endif
4106
4107 rettv->v_type = VAR_STRING;
4108 rettv->vval.v_string = NULL;
4109#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004110 if (entered)
4111 return; /* reject recursive use */
4112 entered = TRUE;
4113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004114 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004115 /* treat illegal types and illegal string values for {lnum} the same */
4116 if (lnum < 0)
4117 lnum = 0;
4118 fold_count = foldedCount(curwin, lnum, &foldinfo);
4119 if (fold_count > 0)
4120 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004121 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4122 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004123 if (text == buf)
4124 text = vim_strsave(text);
4125 rettv->vval.v_string = text;
4126 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004127
4128 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004129#endif
4130}
4131
4132/*
4133 * "foreground()" function
4134 */
4135 static void
4136f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4137{
4138#ifdef FEAT_GUI
4139 if (gui.in_use)
4140 gui_mch_set_foreground();
4141#else
Bram Moolenaar4f974752019-02-17 17:44:42 +01004142# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004143 win32_set_foreground();
4144# endif
4145#endif
4146}
4147
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004149common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004150{
4151 char_u *s;
4152 char_u *name;
4153 int use_string = FALSE;
4154 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004155 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156
4157 if (argvars[0].v_type == VAR_FUNC)
4158 {
4159 /* function(MyFunc, [arg], dict) */
4160 s = argvars[0].vval.v_string;
4161 }
4162 else if (argvars[0].v_type == VAR_PARTIAL
4163 && argvars[0].vval.v_partial != NULL)
4164 {
4165 /* function(dict.MyFunc, [arg]) */
4166 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004167 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004168 }
4169 else
4170 {
4171 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004172 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004173 use_string = TRUE;
4174 }
4175
Bram Moolenaar843b8842016-08-21 14:36:15 +02004176 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004177 {
4178 name = s;
4179 trans_name = trans_function_name(&name, FALSE,
4180 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4181 if (*name != NUL)
4182 s = NULL;
4183 }
4184
Bram Moolenaar843b8842016-08-21 14:36:15 +02004185 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4186 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004187 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004188 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004189 else if (trans_name != NULL && (is_funcref
4190 ? find_func(trans_name) == NULL
4191 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004192 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004193 else
4194 {
4195 int dict_idx = 0;
4196 int arg_idx = 0;
4197 list_T *list = NULL;
4198
4199 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4200 {
4201 char sid_buf[25];
4202 int off = *s == 's' ? 2 : 5;
4203
4204 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4205 * also be called from another script. Using trans_function_name()
4206 * would also work, but some plugins depend on the name being
4207 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004208 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004209 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4210 if (name != NULL)
4211 {
4212 STRCPY(name, sid_buf);
4213 STRCAT(name, s + off);
4214 }
4215 }
4216 else
4217 name = vim_strsave(s);
4218
4219 if (argvars[1].v_type != VAR_UNKNOWN)
4220 {
4221 if (argvars[2].v_type != VAR_UNKNOWN)
4222 {
4223 /* function(name, [args], dict) */
4224 arg_idx = 1;
4225 dict_idx = 2;
4226 }
4227 else if (argvars[1].v_type == VAR_DICT)
4228 /* function(name, dict) */
4229 dict_idx = 1;
4230 else
4231 /* function(name, [args]) */
4232 arg_idx = 1;
4233 if (dict_idx > 0)
4234 {
4235 if (argvars[dict_idx].v_type != VAR_DICT)
4236 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004237 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004238 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004239 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004240 }
4241 if (argvars[dict_idx].vval.v_dict == NULL)
4242 dict_idx = 0;
4243 }
4244 if (arg_idx > 0)
4245 {
4246 if (argvars[arg_idx].v_type != VAR_LIST)
4247 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004248 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004249 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004250 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004251 }
4252 list = argvars[arg_idx].vval.v_list;
4253 if (list == NULL || list->lv_len == 0)
4254 arg_idx = 0;
4255 }
4256 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004257 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004258 {
4259 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4260
4261 /* result is a VAR_PARTIAL */
4262 if (pt == NULL)
4263 vim_free(name);
4264 else
4265 {
4266 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4267 {
4268 listitem_T *li;
4269 int i = 0;
4270 int arg_len = 0;
4271 int lv_len = 0;
4272
4273 if (arg_pt != NULL)
4274 arg_len = arg_pt->pt_argc;
4275 if (list != NULL)
4276 lv_len = list->lv_len;
4277 pt->pt_argc = arg_len + lv_len;
4278 pt->pt_argv = (typval_T *)alloc(
4279 sizeof(typval_T) * pt->pt_argc);
4280 if (pt->pt_argv == NULL)
4281 {
4282 vim_free(pt);
4283 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004284 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004285 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004286 for (i = 0; i < arg_len; i++)
4287 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4288 if (lv_len > 0)
4289 for (li = list->lv_first; li != NULL;
4290 li = li->li_next)
4291 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004292 }
4293
4294 /* For "function(dict.func, [], dict)" and "func" is a partial
4295 * use "dict". That is backwards compatible. */
4296 if (dict_idx > 0)
4297 {
4298 /* The dict is bound explicitly, pt_auto is FALSE. */
4299 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4300 ++pt->pt_dict->dv_refcount;
4301 }
4302 else if (arg_pt != NULL)
4303 {
4304 /* If the dict was bound automatically the result is also
4305 * bound automatically. */
4306 pt->pt_dict = arg_pt->pt_dict;
4307 pt->pt_auto = arg_pt->pt_auto;
4308 if (pt->pt_dict != NULL)
4309 ++pt->pt_dict->dv_refcount;
4310 }
4311
4312 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004313 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4314 {
4315 pt->pt_func = arg_pt->pt_func;
4316 func_ptr_ref(pt->pt_func);
4317 vim_free(name);
4318 }
4319 else if (is_funcref)
4320 {
4321 pt->pt_func = find_func(trans_name);
4322 func_ptr_ref(pt->pt_func);
4323 vim_free(name);
4324 }
4325 else
4326 {
4327 pt->pt_name = name;
4328 func_ref(name);
4329 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004330 }
4331 rettv->v_type = VAR_PARTIAL;
4332 rettv->vval.v_partial = pt;
4333 }
4334 else
4335 {
4336 /* result is a VAR_FUNC */
4337 rettv->v_type = VAR_FUNC;
4338 rettv->vval.v_string = name;
4339 func_ref(name);
4340 }
4341 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004342theend:
4343 vim_free(trans_name);
4344}
4345
4346/*
4347 * "funcref()" function
4348 */
4349 static void
4350f_funcref(typval_T *argvars, typval_T *rettv)
4351{
4352 common_function(argvars, rettv, TRUE);
4353}
4354
4355/*
4356 * "function()" function
4357 */
4358 static void
4359f_function(typval_T *argvars, typval_T *rettv)
4360{
4361 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004362}
4363
4364/*
4365 * "garbagecollect()" function
4366 */
4367 static void
4368f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4369{
4370 /* This is postponed until we are back at the toplevel, because we may be
4371 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4372 want_garbage_collect = TRUE;
4373
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004374 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004375 garbage_collect_at_exit = TRUE;
4376}
4377
4378/*
4379 * "get()" function
4380 */
4381 static void
4382f_get(typval_T *argvars, typval_T *rettv)
4383{
4384 listitem_T *li;
4385 list_T *l;
4386 dictitem_T *di;
4387 dict_T *d;
4388 typval_T *tv = NULL;
4389
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004390 if (argvars[0].v_type == VAR_BLOB)
4391 {
4392 int error = FALSE;
4393 int idx = tv_get_number_chk(&argvars[1], &error);
4394
4395 if (!error)
4396 {
4397 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004398 if (idx < 0)
4399 idx = blob_len(argvars[0].vval.v_blob) + idx;
4400 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4401 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004402 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004403 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004404 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004405 tv = rettv;
4406 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004407 }
4408 }
4409 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004410 {
4411 if ((l = argvars[0].vval.v_list) != NULL)
4412 {
4413 int error = FALSE;
4414
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004415 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416 if (!error && li != NULL)
4417 tv = &li->li_tv;
4418 }
4419 }
4420 else if (argvars[0].v_type == VAR_DICT)
4421 {
4422 if ((d = argvars[0].vval.v_dict) != NULL)
4423 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004424 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004425 if (di != NULL)
4426 tv = &di->di_tv;
4427 }
4428 }
4429 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4430 {
4431 partial_T *pt;
4432 partial_T fref_pt;
4433
4434 if (argvars[0].v_type == VAR_PARTIAL)
4435 pt = argvars[0].vval.v_partial;
4436 else
4437 {
4438 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4439 fref_pt.pt_name = argvars[0].vval.v_string;
4440 pt = &fref_pt;
4441 }
4442
4443 if (pt != NULL)
4444 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004445 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004446 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004447
4448 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4449 {
4450 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004451 n = partial_name(pt);
4452 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004453 rettv->vval.v_string = NULL;
4454 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004455 {
4456 rettv->vval.v_string = vim_strsave(n);
4457 if (rettv->v_type == VAR_FUNC)
4458 func_ref(rettv->vval.v_string);
4459 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004460 }
4461 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004462 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004463 else if (STRCMP(what, "args") == 0)
4464 {
4465 rettv->v_type = VAR_LIST;
4466 if (rettv_list_alloc(rettv) == OK)
4467 {
4468 int i;
4469
4470 for (i = 0; i < pt->pt_argc; ++i)
4471 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4472 }
4473 }
4474 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004475 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476 return;
4477 }
4478 }
4479 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004480 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004481
4482 if (tv == NULL)
4483 {
4484 if (argvars[2].v_type != VAR_UNKNOWN)
4485 copy_tv(&argvars[2], rettv);
4486 }
4487 else
4488 copy_tv(tv, rettv);
4489}
4490
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004491/*
4492 * Returns buffer options, variables and other attributes in a dictionary.
4493 */
4494 static dict_T *
4495get_buffer_info(buf_T *buf)
4496{
4497 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004498 tabpage_T *tp;
4499 win_T *wp;
4500 list_T *windows;
4501
4502 dict = dict_alloc();
4503 if (dict == NULL)
4504 return NULL;
4505
Bram Moolenaare0be1672018-07-08 16:50:37 +02004506 dict_add_number(dict, "bufnr", buf->b_fnum);
4507 dict_add_string(dict, "name", buf->b_ffname);
4508 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4509 : buflist_findlnum(buf));
4510 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4511 dict_add_number(dict, "listed", buf->b_p_bl);
4512 dict_add_number(dict, "changed", bufIsChanged(buf));
4513 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4514 dict_add_number(dict, "hidden",
4515 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004516
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004517 /* Get a reference to buffer variables */
4518 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004519
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004520 /* List of windows displaying this buffer */
4521 windows = list_alloc();
4522 if (windows != NULL)
4523 {
4524 FOR_ALL_TAB_WINDOWS(tp, wp)
4525 if (wp->w_buffer == buf)
4526 list_append_number(windows, (varnumber_T)wp->w_id);
4527 dict_add_list(dict, "windows", windows);
4528 }
4529
4530#ifdef FEAT_SIGNS
4531 if (buf->b_signlist != NULL)
4532 {
4533 /* List of signs placed in this buffer */
4534 list_T *signs = list_alloc();
4535 if (signs != NULL)
4536 {
4537 get_buffer_signs(buf, signs);
4538 dict_add_list(dict, "signs", signs);
4539 }
4540 }
4541#endif
4542
4543 return dict;
4544}
4545
4546/*
4547 * "getbufinfo()" function
4548 */
4549 static void
4550f_getbufinfo(typval_T *argvars, typval_T *rettv)
4551{
4552 buf_T *buf = NULL;
4553 buf_T *argbuf = NULL;
4554 dict_T *d;
4555 int filtered = FALSE;
4556 int sel_buflisted = FALSE;
4557 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004558 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004559
4560 if (rettv_list_alloc(rettv) != OK)
4561 return;
4562
4563 /* List of all the buffers or selected buffers */
4564 if (argvars[0].v_type == VAR_DICT)
4565 {
4566 dict_T *sel_d = argvars[0].vval.v_dict;
4567
4568 if (sel_d != NULL)
4569 {
4570 dictitem_T *di;
4571
4572 filtered = TRUE;
4573
4574 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004575 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004576 sel_buflisted = TRUE;
4577
4578 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004579 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004580 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004581
4582 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004583 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004584 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004585 }
4586 }
4587 else if (argvars[0].v_type != VAR_UNKNOWN)
4588 {
4589 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004590 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004591 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004592 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004593 --emsg_off;
4594 if (argbuf == NULL)
4595 return;
4596 }
4597
4598 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004599 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004600 {
4601 if (argbuf != NULL && argbuf != buf)
4602 continue;
4603 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004604 || (sel_buflisted && !buf->b_p_bl)
4605 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004606 continue;
4607
4608 d = get_buffer_info(buf);
4609 if (d != NULL)
4610 list_append_dict(rettv->vval.v_list, d);
4611 if (argbuf != NULL)
4612 return;
4613 }
4614}
4615
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004616/*
4617 * Get line or list of lines from buffer "buf" into "rettv".
4618 * Return a range (from start to end) of lines in rettv from the specified
4619 * buffer.
4620 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4621 */
4622 static void
4623get_buffer_lines(
4624 buf_T *buf,
4625 linenr_T start,
4626 linenr_T end,
4627 int retlist,
4628 typval_T *rettv)
4629{
4630 char_u *p;
4631
4632 rettv->v_type = VAR_STRING;
4633 rettv->vval.v_string = NULL;
4634 if (retlist && rettv_list_alloc(rettv) == FAIL)
4635 return;
4636
4637 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4638 return;
4639
4640 if (!retlist)
4641 {
4642 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4643 p = ml_get_buf(buf, start, FALSE);
4644 else
4645 p = (char_u *)"";
4646 rettv->vval.v_string = vim_strsave(p);
4647 }
4648 else
4649 {
4650 if (end < start)
4651 return;
4652
4653 if (start < 1)
4654 start = 1;
4655 if (end > buf->b_ml.ml_line_count)
4656 end = buf->b_ml.ml_line_count;
4657 while (start <= end)
4658 if (list_append_string(rettv->vval.v_list,
4659 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4660 break;
4661 }
4662}
4663
4664/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004665 * "getbufline()" function
4666 */
4667 static void
4668f_getbufline(typval_T *argvars, typval_T *rettv)
4669{
4670 linenr_T lnum;
4671 linenr_T end;
4672 buf_T *buf;
4673
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004674 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004676 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004677 --emsg_off;
4678
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004679 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680 if (argvars[2].v_type == VAR_UNKNOWN)
4681 end = lnum;
4682 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004683 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004684
4685 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4686}
4687
4688/*
4689 * "getbufvar()" function
4690 */
4691 static void
4692f_getbufvar(typval_T *argvars, typval_T *rettv)
4693{
4694 buf_T *buf;
4695 buf_T *save_curbuf;
4696 char_u *varname;
4697 dictitem_T *v;
4698 int done = FALSE;
4699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004700 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4701 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004703 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004704
4705 rettv->v_type = VAR_STRING;
4706 rettv->vval.v_string = NULL;
4707
4708 if (buf != NULL && varname != NULL)
4709 {
4710 /* set curbuf to be our buf, temporarily */
4711 save_curbuf = curbuf;
4712 curbuf = buf;
4713
Bram Moolenaar30567352016-08-27 21:25:44 +02004714 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004715 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004716 if (varname[1] == NUL)
4717 {
4718 /* get all buffer-local options in a dict */
4719 dict_T *opts = get_winbuf_options(TRUE);
4720
4721 if (opts != NULL)
4722 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004723 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004724 done = TRUE;
4725 }
4726 }
4727 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4728 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 done = TRUE;
4730 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004731 else
4732 {
4733 /* Look up the variable. */
4734 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4735 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4736 'b', varname, FALSE);
4737 if (v != NULL)
4738 {
4739 copy_tv(&v->di_tv, rettv);
4740 done = TRUE;
4741 }
4742 }
4743
4744 /* restore previous notion of curbuf */
4745 curbuf = save_curbuf;
4746 }
4747
4748 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4749 /* use the default value */
4750 copy_tv(&argvars[2], rettv);
4751
4752 --emsg_off;
4753}
4754
4755/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004756 * "getchangelist()" function
4757 */
4758 static void
4759f_getchangelist(typval_T *argvars, typval_T *rettv)
4760{
4761#ifdef FEAT_JUMPLIST
4762 buf_T *buf;
4763 int i;
4764 list_T *l;
4765 dict_T *d;
4766#endif
4767
4768 if (rettv_list_alloc(rettv) != OK)
4769 return;
4770
4771#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004772 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004773 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004774 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004775 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004776 if (buf == NULL)
4777 return;
4778
4779 l = list_alloc();
4780 if (l == NULL)
4781 return;
4782
4783 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4784 return;
4785 /*
4786 * The current window change list index tracks only the position in the
4787 * current buffer change list. For other buffers, use the change list
4788 * length as the current index.
4789 */
4790 list_append_number(rettv->vval.v_list,
4791 (varnumber_T)((buf == curwin->w_buffer)
4792 ? curwin->w_changelistidx : buf->b_changelistlen));
4793
4794 for (i = 0; i < buf->b_changelistlen; ++i)
4795 {
4796 if (buf->b_changelist[i].lnum == 0)
4797 continue;
4798 if ((d = dict_alloc()) == NULL)
4799 return;
4800 if (list_append_dict(l, d) == FAIL)
4801 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004802 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4803 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004804 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004805 }
4806#endif
4807}
4808/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004809 * "getchar()" function
4810 */
4811 static void
4812f_getchar(typval_T *argvars, typval_T *rettv)
4813{
4814 varnumber_T n;
4815 int error = FALSE;
Bram Moolenaarf0fab302019-03-05 12:24:10 +01004816 int save_reg_executing = reg_executing;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004817
Bram Moolenaar84d93902018-09-11 20:10:20 +02004818#ifdef MESSAGE_QUEUE
4819 // vpeekc() used to check for messages, but that caused problems, invoking
4820 // a callback where it was not expected. Some plugins use getchar(1) in a
4821 // loop to await a message, therefore make sure we check for messages here.
4822 parse_queued_messages();
4823#endif
4824
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004825 /* Position the cursor. Needed after a message that ends in a space. */
4826 windgoto(msg_row, msg_col);
4827
4828 ++no_mapping;
4829 ++allow_keys;
4830 for (;;)
4831 {
4832 if (argvars[0].v_type == VAR_UNKNOWN)
4833 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004834 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004835 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004836 /* getchar(1): only check if char avail */
4837 n = vpeekc_any();
4838 else if (error || vpeekc_any() == NUL)
4839 /* illegal argument or getchar(0) and no char avail: return zero */
4840 n = 0;
4841 else
4842 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004843 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844
4845 if (n == K_IGNORE)
4846 continue;
4847 break;
4848 }
4849 --no_mapping;
4850 --allow_keys;
Bram Moolenaarf0fab302019-03-05 12:24:10 +01004851 reg_executing = save_reg_executing;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852
4853 set_vim_var_nr(VV_MOUSE_WIN, 0);
4854 set_vim_var_nr(VV_MOUSE_WINID, 0);
4855 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4856 set_vim_var_nr(VV_MOUSE_COL, 0);
4857
4858 rettv->vval.v_number = n;
4859 if (IS_SPECIAL(n) || mod_mask != 0)
4860 {
4861 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4862 int i = 0;
4863
4864 /* Turn a special key into three bytes, plus modifier. */
4865 if (mod_mask != 0)
4866 {
4867 temp[i++] = K_SPECIAL;
4868 temp[i++] = KS_MODIFIER;
4869 temp[i++] = mod_mask;
4870 }
4871 if (IS_SPECIAL(n))
4872 {
4873 temp[i++] = K_SPECIAL;
4874 temp[i++] = K_SECOND(n);
4875 temp[i++] = K_THIRD(n);
4876 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004877 else if (has_mbyte)
4878 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004879 else
4880 temp[i++] = n;
4881 temp[i++] = NUL;
4882 rettv->v_type = VAR_STRING;
4883 rettv->vval.v_string = vim_strsave(temp);
4884
4885#ifdef FEAT_MOUSE
4886 if (is_mouse_key(n))
4887 {
4888 int row = mouse_row;
4889 int col = mouse_col;
4890 win_T *win;
4891 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004892 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004893 int winnr = 1;
4894
4895 if (row >= 0 && col >= 0)
4896 {
4897 /* Find the window at the mouse coordinates and compute the
4898 * text position. */
4899 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004900 if (win == NULL)
4901 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004902 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 for (wp = firstwin; wp != win; wp = wp->w_next)
4904 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004905 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4906 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4907 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4908 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4909 }
4910 }
4911#endif
4912 }
4913}
4914
4915/*
4916 * "getcharmod()" function
4917 */
4918 static void
4919f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4920{
4921 rettv->vval.v_number = mod_mask;
4922}
4923
4924/*
4925 * "getcharsearch()" function
4926 */
4927 static void
4928f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4929{
4930 if (rettv_dict_alloc(rettv) != FAIL)
4931 {
4932 dict_T *dict = rettv->vval.v_dict;
4933
Bram Moolenaare0be1672018-07-08 16:50:37 +02004934 dict_add_string(dict, "char", last_csearch());
4935 dict_add_number(dict, "forward", last_csearch_forward());
4936 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004937 }
4938}
4939
4940/*
4941 * "getcmdline()" function
4942 */
4943 static void
4944f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4945{
4946 rettv->v_type = VAR_STRING;
4947 rettv->vval.v_string = get_cmdline_str();
4948}
4949
4950/*
4951 * "getcmdpos()" function
4952 */
4953 static void
4954f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4955{
4956 rettv->vval.v_number = get_cmdline_pos() + 1;
4957}
4958
4959/*
4960 * "getcmdtype()" function
4961 */
4962 static void
4963f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4964{
4965 rettv->v_type = VAR_STRING;
4966 rettv->vval.v_string = alloc(2);
4967 if (rettv->vval.v_string != NULL)
4968 {
4969 rettv->vval.v_string[0] = get_cmdline_type();
4970 rettv->vval.v_string[1] = NUL;
4971 }
4972}
4973
4974/*
4975 * "getcmdwintype()" function
4976 */
4977 static void
4978f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4979{
4980 rettv->v_type = VAR_STRING;
4981 rettv->vval.v_string = NULL;
4982#ifdef FEAT_CMDWIN
4983 rettv->vval.v_string = alloc(2);
4984 if (rettv->vval.v_string != NULL)
4985 {
4986 rettv->vval.v_string[0] = cmdwin_type;
4987 rettv->vval.v_string[1] = NUL;
4988 }
4989#endif
4990}
4991
4992#if defined(FEAT_CMDL_COMPL)
4993/*
4994 * "getcompletion()" function
4995 */
4996 static void
4997f_getcompletion(typval_T *argvars, typval_T *rettv)
4998{
4999 char_u *pat;
5000 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005001 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005002 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5003 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005004
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005005 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005006 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005007
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005008 if (p_wic)
5009 options |= WILD_ICASE;
5010
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005011 /* For filtered results, 'wildignore' is used */
5012 if (!filtered)
5013 options |= WILD_KEEP_ALL;
5014
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005015 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005016 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005017 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005018 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005019 if (xpc.xp_context == EXPAND_NOTHING)
5020 {
5021 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005022 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005023 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005024 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 return;
5026 }
5027
5028# if defined(FEAT_MENU)
5029 if (xpc.xp_context == EXPAND_MENUS)
5030 {
5031 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5032 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5033 }
5034# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005035#ifdef FEAT_CSCOPE
5036 if (xpc.xp_context == EXPAND_CSCOPE)
5037 {
5038 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5039 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5040 }
5041#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005042#ifdef FEAT_SIGNS
5043 if (xpc.xp_context == EXPAND_SIGN)
5044 {
5045 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5046 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5047 }
5048#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005049
5050 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5051 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5052 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005053 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005054
5055 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5056
5057 for (i = 0; i < xpc.xp_numfiles; i++)
5058 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5059 }
5060 vim_free(pat);
5061 ExpandCleanup(&xpc);
5062}
5063#endif
5064
5065/*
5066 * "getcwd()" function
5067 */
5068 static void
5069f_getcwd(typval_T *argvars, typval_T *rettv)
5070{
5071 win_T *wp = NULL;
5072 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005073 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005074
5075 rettv->v_type = VAR_STRING;
5076 rettv->vval.v_string = NULL;
5077
Bram Moolenaar54591292018-02-09 20:53:59 +01005078 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5079 global = TRUE;
5080 else
5081 wp = find_tabwin(&argvars[0], &argvars[1]);
5082
5083 if (wp != NULL && wp->w_localdir != NULL)
5084 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5085 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005086 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005087 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005088 rettv->vval.v_string = vim_strsave(globaldir);
5089 else
5090 {
5091 cwd = alloc(MAXPATHL);
5092 if (cwd != NULL)
5093 {
5094 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5095 rettv->vval.v_string = vim_strsave(cwd);
5096 vim_free(cwd);
5097 }
5098 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005100#ifdef BACKSLASH_IN_FILENAME
5101 if (rettv->vval.v_string != NULL)
5102 slash_adjust(rettv->vval.v_string);
5103#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104}
5105
5106/*
5107 * "getfontname()" function
5108 */
5109 static void
5110f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5111{
5112 rettv->v_type = VAR_STRING;
5113 rettv->vval.v_string = NULL;
5114#ifdef FEAT_GUI
5115 if (gui.in_use)
5116 {
5117 GuiFont font;
5118 char_u *name = NULL;
5119
5120 if (argvars[0].v_type == VAR_UNKNOWN)
5121 {
5122 /* Get the "Normal" font. Either the name saved by
5123 * hl_set_font_name() or from the font ID. */
5124 font = gui.norm_font;
5125 name = hl_get_font_name();
5126 }
5127 else
5128 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005129 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005130 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5131 return;
5132 font = gui_mch_get_font(name, FALSE);
5133 if (font == NOFONT)
5134 return; /* Invalid font name, return empty string. */
5135 }
5136 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5137 if (argvars[0].v_type != VAR_UNKNOWN)
5138 gui_mch_free_font(font);
5139 }
5140#endif
5141}
5142
5143/*
5144 * "getfperm({fname})" function
5145 */
5146 static void
5147f_getfperm(typval_T *argvars, typval_T *rettv)
5148{
5149 char_u *fname;
5150 stat_T st;
5151 char_u *perm = NULL;
5152 char_u flags[] = "rwx";
5153 int i;
5154
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005155 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005156
5157 rettv->v_type = VAR_STRING;
5158 if (mch_stat((char *)fname, &st) >= 0)
5159 {
5160 perm = vim_strsave((char_u *)"---------");
5161 if (perm != NULL)
5162 {
5163 for (i = 0; i < 9; i++)
5164 {
5165 if (st.st_mode & (1 << (8 - i)))
5166 perm[i] = flags[i % 3];
5167 }
5168 }
5169 }
5170 rettv->vval.v_string = perm;
5171}
5172
5173/*
5174 * "getfsize({fname})" function
5175 */
5176 static void
5177f_getfsize(typval_T *argvars, typval_T *rettv)
5178{
5179 char_u *fname;
5180 stat_T st;
5181
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005182 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005183
5184 rettv->v_type = VAR_NUMBER;
5185
5186 if (mch_stat((char *)fname, &st) >= 0)
5187 {
5188 if (mch_isdir(fname))
5189 rettv->vval.v_number = 0;
5190 else
5191 {
5192 rettv->vval.v_number = (varnumber_T)st.st_size;
5193
5194 /* non-perfect check for overflow */
5195 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5196 rettv->vval.v_number = -2;
5197 }
5198 }
5199 else
5200 rettv->vval.v_number = -1;
5201}
5202
5203/*
5204 * "getftime({fname})" function
5205 */
5206 static void
5207f_getftime(typval_T *argvars, typval_T *rettv)
5208{
5209 char_u *fname;
5210 stat_T st;
5211
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005212 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005213
5214 if (mch_stat((char *)fname, &st) >= 0)
5215 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5216 else
5217 rettv->vval.v_number = -1;
5218}
5219
5220/*
5221 * "getftype({fname})" function
5222 */
5223 static void
5224f_getftype(typval_T *argvars, typval_T *rettv)
5225{
5226 char_u *fname;
5227 stat_T st;
5228 char_u *type = NULL;
5229 char *t;
5230
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005231 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005232
5233 rettv->v_type = VAR_STRING;
5234 if (mch_lstat((char *)fname, &st) >= 0)
5235 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005236 if (S_ISREG(st.st_mode))
5237 t = "file";
5238 else if (S_ISDIR(st.st_mode))
5239 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005240 else if (S_ISLNK(st.st_mode))
5241 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242 else if (S_ISBLK(st.st_mode))
5243 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244 else if (S_ISCHR(st.st_mode))
5245 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005246 else if (S_ISFIFO(st.st_mode))
5247 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005248 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005249 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005250 else
5251 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005252 type = vim_strsave((char_u *)t);
5253 }
5254 rettv->vval.v_string = type;
5255}
5256
5257/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005258 * "getjumplist()" function
5259 */
5260 static void
5261f_getjumplist(typval_T *argvars, typval_T *rettv)
5262{
5263#ifdef FEAT_JUMPLIST
5264 win_T *wp;
5265 int i;
5266 list_T *l;
5267 dict_T *d;
5268#endif
5269
5270 if (rettv_list_alloc(rettv) != OK)
5271 return;
5272
5273#ifdef FEAT_JUMPLIST
5274 wp = find_tabwin(&argvars[0], &argvars[1]);
5275 if (wp == NULL)
5276 return;
5277
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005278 cleanup_jumplist(wp, TRUE);
5279
Bram Moolenaar4f505882018-02-10 21:06:32 +01005280 l = list_alloc();
5281 if (l == NULL)
5282 return;
5283
5284 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5285 return;
5286 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5287
5288 for (i = 0; i < wp->w_jumplistlen; ++i)
5289 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005290 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5291 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005292 if ((d = dict_alloc()) == NULL)
5293 return;
5294 if (list_append_dict(l, d) == FAIL)
5295 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005296 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5297 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005298 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005299 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005300 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005301 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005302 }
5303#endif
5304}
5305
5306/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005307 * "getline(lnum, [end])" function
5308 */
5309 static void
5310f_getline(typval_T *argvars, typval_T *rettv)
5311{
5312 linenr_T lnum;
5313 linenr_T end;
5314 int retlist;
5315
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005316 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005317 if (argvars[1].v_type == VAR_UNKNOWN)
5318 {
5319 end = 0;
5320 retlist = FALSE;
5321 }
5322 else
5323 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005324 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005325 retlist = TRUE;
5326 }
5327
5328 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5329}
5330
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005331#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005332 static void
5333get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5334{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005335 if (what_arg->v_type == VAR_UNKNOWN)
5336 {
5337 if (rettv_list_alloc(rettv) == OK)
5338 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005339 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005340 }
5341 else
5342 {
5343 if (rettv_dict_alloc(rettv) == OK)
5344 if (is_qf || (wp != NULL))
5345 {
5346 if (what_arg->v_type == VAR_DICT)
5347 {
5348 dict_T *d = what_arg->vval.v_dict;
5349
5350 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005351 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005352 }
5353 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005354 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005355 }
5356 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005357}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005358#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005359
5360/*
5361 * "getloclist()" function
5362 */
5363 static void
5364f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5365{
5366#ifdef FEAT_QUICKFIX
5367 win_T *wp;
5368
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005369 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005370 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5371#endif
5372}
5373
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005374/*
5375 * "getmatches()" function
5376 */
5377 static void
5378f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5379{
5380#ifdef FEAT_SEARCH_EXTRA
5381 dict_T *dict;
5382 matchitem_T *cur = curwin->w_match_head;
5383 int i;
5384
5385 if (rettv_list_alloc(rettv) == OK)
5386 {
5387 while (cur != NULL)
5388 {
5389 dict = dict_alloc();
5390 if (dict == NULL)
5391 return;
5392 if (cur->match.regprog == NULL)
5393 {
5394 /* match added with matchaddpos() */
5395 for (i = 0; i < MAXPOSMATCH; ++i)
5396 {
5397 llpos_T *llpos;
5398 char buf[6];
5399 list_T *l;
5400
5401 llpos = &cur->pos.pos[i];
5402 if (llpos->lnum == 0)
5403 break;
5404 l = list_alloc();
5405 if (l == NULL)
5406 break;
5407 list_append_number(l, (varnumber_T)llpos->lnum);
5408 if (llpos->col > 0)
5409 {
5410 list_append_number(l, (varnumber_T)llpos->col);
5411 list_append_number(l, (varnumber_T)llpos->len);
5412 }
5413 sprintf(buf, "pos%d", i + 1);
5414 dict_add_list(dict, buf, l);
5415 }
5416 }
5417 else
5418 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005419 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005420 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005421 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5422 dict_add_number(dict, "priority", (long)cur->priority);
5423 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar13505972019-01-24 15:04:48 +01005424# if defined(FEAT_CONCEAL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005425 if (cur->conceal_char)
5426 {
5427 char_u buf[MB_MAXBYTES + 1];
5428
5429 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005430 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005431 }
5432# endif
5433 list_append_dict(rettv->vval.v_list, dict);
5434 cur = cur->next;
5435 }
5436 }
5437#endif
5438}
5439
5440/*
5441 * "getpid()" function
5442 */
5443 static void
5444f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5445{
5446 rettv->vval.v_number = mch_get_pid();
5447}
5448
5449 static void
5450getpos_both(
5451 typval_T *argvars,
5452 typval_T *rettv,
5453 int getcurpos)
5454{
5455 pos_T *fp;
5456 list_T *l;
5457 int fnum = -1;
5458
5459 if (rettv_list_alloc(rettv) == OK)
5460 {
5461 l = rettv->vval.v_list;
5462 if (getcurpos)
5463 fp = &curwin->w_cursor;
5464 else
5465 fp = var2fpos(&argvars[0], TRUE, &fnum);
5466 if (fnum != -1)
5467 list_append_number(l, (varnumber_T)fnum);
5468 else
5469 list_append_number(l, (varnumber_T)0);
5470 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5471 : (varnumber_T)0);
5472 list_append_number(l, (fp != NULL)
5473 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5474 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005475 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005476 (varnumber_T)0);
5477 if (getcurpos)
5478 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005479 int save_set_curswant = curwin->w_set_curswant;
5480 colnr_T save_curswant = curwin->w_curswant;
5481 colnr_T save_virtcol = curwin->w_virtcol;
5482
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005483 update_curswant();
5484 list_append_number(l, curwin->w_curswant == MAXCOL ?
5485 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005486
5487 // Do not change "curswant", as it is unexpected that a get
5488 // function has a side effect.
5489 if (save_set_curswant)
5490 {
5491 curwin->w_set_curswant = save_set_curswant;
5492 curwin->w_curswant = save_curswant;
5493 curwin->w_virtcol = save_virtcol;
5494 curwin->w_valid &= ~VALID_VIRTCOL;
5495 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005496 }
5497 }
5498 else
5499 rettv->vval.v_number = FALSE;
5500}
5501
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502/*
5503 * "getcurpos()" function
5504 */
5505 static void
5506f_getcurpos(typval_T *argvars, typval_T *rettv)
5507{
5508 getpos_both(argvars, rettv, TRUE);
5509}
5510
5511/*
5512 * "getpos(string)" function
5513 */
5514 static void
5515f_getpos(typval_T *argvars, typval_T *rettv)
5516{
5517 getpos_both(argvars, rettv, FALSE);
5518}
5519
5520/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005521 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005522 */
5523 static void
5524f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5525{
5526#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005527 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005528#endif
5529}
5530
5531/*
5532 * "getreg()" function
5533 */
5534 static void
5535f_getreg(typval_T *argvars, typval_T *rettv)
5536{
5537 char_u *strregname;
5538 int regname;
5539 int arg2 = FALSE;
5540 int return_list = FALSE;
5541 int error = FALSE;
5542
5543 if (argvars[0].v_type != VAR_UNKNOWN)
5544 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005545 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005546 error = strregname == NULL;
5547 if (argvars[1].v_type != VAR_UNKNOWN)
5548 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005549 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005550 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005551 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005552 }
5553 }
5554 else
5555 strregname = get_vim_var_str(VV_REG);
5556
5557 if (error)
5558 return;
5559
5560 regname = (strregname == NULL ? '"' : *strregname);
5561 if (regname == 0)
5562 regname = '"';
5563
5564 if (return_list)
5565 {
5566 rettv->v_type = VAR_LIST;
5567 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5568 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5569 if (rettv->vval.v_list == NULL)
5570 (void)rettv_list_alloc(rettv);
5571 else
5572 ++rettv->vval.v_list->lv_refcount;
5573 }
5574 else
5575 {
5576 rettv->v_type = VAR_STRING;
5577 rettv->vval.v_string = get_reg_contents(regname,
5578 arg2 ? GREG_EXPR_SRC : 0);
5579 }
5580}
5581
5582/*
5583 * "getregtype()" function
5584 */
5585 static void
5586f_getregtype(typval_T *argvars, typval_T *rettv)
5587{
5588 char_u *strregname;
5589 int regname;
5590 char_u buf[NUMBUFLEN + 2];
5591 long reglen = 0;
5592
5593 if (argvars[0].v_type != VAR_UNKNOWN)
5594 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005595 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596 if (strregname == NULL) /* type error; errmsg already given */
5597 {
5598 rettv->v_type = VAR_STRING;
5599 rettv->vval.v_string = NULL;
5600 return;
5601 }
5602 }
5603 else
5604 /* Default to v:register */
5605 strregname = get_vim_var_str(VV_REG);
5606
5607 regname = (strregname == NULL ? '"' : *strregname);
5608 if (regname == 0)
5609 regname = '"';
5610
5611 buf[0] = NUL;
5612 buf[1] = NUL;
5613 switch (get_reg_type(regname, &reglen))
5614 {
5615 case MLINE: buf[0] = 'V'; break;
5616 case MCHAR: buf[0] = 'v'; break;
5617 case MBLOCK:
5618 buf[0] = Ctrl_V;
5619 sprintf((char *)buf + 1, "%ld", reglen + 1);
5620 break;
5621 }
5622 rettv->v_type = VAR_STRING;
5623 rettv->vval.v_string = vim_strsave(buf);
5624}
5625
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005626/*
5627 * Returns information (variables, options, etc.) about a tab page
5628 * as a dictionary.
5629 */
5630 static dict_T *
5631get_tabpage_info(tabpage_T *tp, int tp_idx)
5632{
5633 win_T *wp;
5634 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005635 list_T *l;
5636
5637 dict = dict_alloc();
5638 if (dict == NULL)
5639 return NULL;
5640
Bram Moolenaare0be1672018-07-08 16:50:37 +02005641 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005642
5643 l = list_alloc();
5644 if (l != NULL)
5645 {
5646 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5647 wp; wp = wp->w_next)
5648 list_append_number(l, (varnumber_T)wp->w_id);
5649 dict_add_list(dict, "windows", l);
5650 }
5651
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005652 /* Make a reference to tabpage variables */
5653 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005654
5655 return dict;
5656}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005657
5658/*
5659 * "gettabinfo()" function
5660 */
5661 static void
5662f_gettabinfo(typval_T *argvars, typval_T *rettv)
5663{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005664 tabpage_T *tp, *tparg = NULL;
5665 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005666 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005667
5668 if (rettv_list_alloc(rettv) != OK)
5669 return;
5670
5671 if (argvars[0].v_type != VAR_UNKNOWN)
5672 {
5673 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005674 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005675 if (tparg == NULL)
5676 return;
5677 }
5678
5679 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005680 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005681 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005682 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005683 if (tparg != NULL && tp != tparg)
5684 continue;
5685 d = get_tabpage_info(tp, tpnr);
5686 if (d != NULL)
5687 list_append_dict(rettv->vval.v_list, d);
5688 if (tparg != NULL)
5689 return;
5690 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005691}
5692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005693/*
5694 * "gettabvar()" function
5695 */
5696 static void
5697f_gettabvar(typval_T *argvars, typval_T *rettv)
5698{
5699 win_T *oldcurwin;
5700 tabpage_T *tp, *oldtabpage;
5701 dictitem_T *v;
5702 char_u *varname;
5703 int done = FALSE;
5704
5705 rettv->v_type = VAR_STRING;
5706 rettv->vval.v_string = NULL;
5707
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005708 varname = tv_get_string_chk(&argvars[1]);
5709 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005710 if (tp != NULL && varname != NULL)
5711 {
5712 /* Set tp to be our tabpage, temporarily. Also set the window to the
5713 * first window in the tabpage, otherwise the window is not valid. */
5714 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005715 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5716 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005717 {
5718 /* look up the variable */
5719 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5720 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5721 if (v != NULL)
5722 {
5723 copy_tv(&v->di_tv, rettv);
5724 done = TRUE;
5725 }
5726 }
5727
5728 /* restore previous notion of curwin */
5729 restore_win(oldcurwin, oldtabpage, TRUE);
5730 }
5731
5732 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5733 copy_tv(&argvars[2], rettv);
5734}
5735
5736/*
5737 * "gettabwinvar()" function
5738 */
5739 static void
5740f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5741{
5742 getwinvar(argvars, rettv, 1);
5743}
5744
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005745/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005746 * "gettagstack()" function
5747 */
5748 static void
5749f_gettagstack(typval_T *argvars, typval_T *rettv)
5750{
5751 win_T *wp = curwin; // default is current window
5752
5753 if (rettv_dict_alloc(rettv) != OK)
5754 return;
5755
5756 if (argvars[0].v_type != VAR_UNKNOWN)
5757 {
5758 wp = find_win_by_nr_or_id(&argvars[0]);
5759 if (wp == NULL)
5760 return;
5761 }
5762
5763 get_tagstack(wp, rettv->vval.v_dict);
5764}
5765
5766/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005767 * Returns information about a window as a dictionary.
5768 */
5769 static dict_T *
5770get_win_info(win_T *wp, short tpnr, short winnr)
5771{
5772 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005773
5774 dict = dict_alloc();
5775 if (dict == NULL)
5776 return NULL;
5777
Bram Moolenaare0be1672018-07-08 16:50:37 +02005778 dict_add_number(dict, "tabnr", tpnr);
5779 dict_add_number(dict, "winnr", winnr);
5780 dict_add_number(dict, "winid", wp->w_id);
5781 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005782 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005783 dict_add_number(dict, "topline", wp->w_topline);
5784 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005785#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005786 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005787#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005788 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005789 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005790 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005791
Bram Moolenaar69905d12017-08-13 18:14:47 +02005792#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005793 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005794#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005795#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005796 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5797 dict_add_number(dict, "loclist",
5798 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005799#endif
5800
Bram Moolenaar30567352016-08-27 21:25:44 +02005801 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005802 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005803
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005804 return dict;
5805}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005806
5807/*
5808 * "getwininfo()" function
5809 */
5810 static void
5811f_getwininfo(typval_T *argvars, typval_T *rettv)
5812{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005813 tabpage_T *tp;
5814 win_T *wp = NULL, *wparg = NULL;
5815 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005816 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005817
5818 if (rettv_list_alloc(rettv) != OK)
5819 return;
5820
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005821 if (argvars[0].v_type != VAR_UNKNOWN)
5822 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005823 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005824 if (wparg == NULL)
5825 return;
5826 }
5827
5828 /* Collect information about either all the windows across all the tab
5829 * pages or one particular window.
5830 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005831 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005832 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005833 tabnr++;
5834 winnr = 0;
5835 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005836 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005837 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005838 if (wparg != NULL && wp != wparg)
5839 continue;
5840 d = get_win_info(wp, tabnr, winnr);
5841 if (d != NULL)
5842 list_append_dict(rettv->vval.v_list, d);
5843 if (wparg != NULL)
5844 /* found information about a specific window */
5845 return;
5846 }
5847 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005848}
5849
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005851 * "win_findbuf()" function
5852 */
5853 static void
5854f_win_findbuf(typval_T *argvars, typval_T *rettv)
5855{
5856 if (rettv_list_alloc(rettv) != FAIL)
5857 win_findbuf(argvars, rettv->vval.v_list);
5858}
5859
5860/*
5861 * "win_getid()" function
5862 */
5863 static void
5864f_win_getid(typval_T *argvars, typval_T *rettv)
5865{
5866 rettv->vval.v_number = win_getid(argvars);
5867}
5868
5869/*
5870 * "win_gotoid()" function
5871 */
5872 static void
5873f_win_gotoid(typval_T *argvars, typval_T *rettv)
5874{
5875 rettv->vval.v_number = win_gotoid(argvars);
5876}
5877
5878/*
5879 * "win_id2tabwin()" function
5880 */
5881 static void
5882f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5883{
5884 if (rettv_list_alloc(rettv) != FAIL)
5885 win_id2tabwin(argvars, rettv->vval.v_list);
5886}
5887
5888/*
5889 * "win_id2win()" function
5890 */
5891 static void
5892f_win_id2win(typval_T *argvars, typval_T *rettv)
5893{
5894 rettv->vval.v_number = win_id2win(argvars);
5895}
5896
5897/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005898 * "win_screenpos()" function
5899 */
5900 static void
5901f_win_screenpos(typval_T *argvars, typval_T *rettv)
5902{
5903 win_T *wp;
5904
5905 if (rettv_list_alloc(rettv) == FAIL)
5906 return;
5907
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005908 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005909 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5910 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5911}
5912
5913/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005914 * "getwinpos({timeout})" function
5915 */
5916 static void
5917f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5918{
5919 int x = -1;
5920 int y = -1;
5921
5922 if (rettv_list_alloc(rettv) == FAIL)
5923 return;
5924#ifdef FEAT_GUI
5925 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005926 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005927# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5928 else
5929# endif
5930#endif
5931#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5932 {
5933 varnumber_T timeout = 100;
5934
5935 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005936 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005937 term_get_winpos(&x, &y, timeout);
5938 }
5939#endif
5940 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5941 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5942}
5943
5944
5945/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005946 * "getwinposx()" function
5947 */
5948 static void
5949f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5950{
5951 rettv->vval.v_number = -1;
5952#ifdef FEAT_GUI
5953 if (gui.in_use)
5954 {
5955 int x, y;
5956
5957 if (gui_mch_get_winpos(&x, &y) == OK)
5958 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005959 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005960 }
5961#endif
5962#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5963 {
5964 int x, y;
5965
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005966 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005967 rettv->vval.v_number = x;
5968 }
5969#endif
5970}
5971
5972/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005973 * "getwinposy()" function
5974 */
5975 static void
5976f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5977{
5978 rettv->vval.v_number = -1;
5979#ifdef FEAT_GUI
5980 if (gui.in_use)
5981 {
5982 int x, y;
5983
5984 if (gui_mch_get_winpos(&x, &y) == OK)
5985 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005986 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005987 }
5988#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005989#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5990 {
5991 int x, y;
5992
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005993 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005994 rettv->vval.v_number = y;
5995 }
5996#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997}
5998
5999/*
6000 * "getwinvar()" function
6001 */
6002 static void
6003f_getwinvar(typval_T *argvars, typval_T *rettv)
6004{
6005 getwinvar(argvars, rettv, 0);
6006}
6007
6008/*
6009 * "glob()" function
6010 */
6011 static void
6012f_glob(typval_T *argvars, typval_T *rettv)
6013{
6014 int options = WILD_SILENT|WILD_USE_NL;
6015 expand_T xpc;
6016 int error = FALSE;
6017
6018 /* When the optional second argument is non-zero, don't remove matches
6019 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6020 rettv->v_type = VAR_STRING;
6021 if (argvars[1].v_type != VAR_UNKNOWN)
6022 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006023 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024 options |= WILD_KEEP_ALL;
6025 if (argvars[2].v_type != VAR_UNKNOWN)
6026 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006027 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006028 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006029 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030 }
6031 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006032 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006033 options |= WILD_ALLLINKS;
6034 }
6035 }
6036 if (!error)
6037 {
6038 ExpandInit(&xpc);
6039 xpc.xp_context = EXPAND_FILES;
6040 if (p_wic)
6041 options += WILD_ICASE;
6042 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006043 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006044 NULL, options, WILD_ALL);
6045 else if (rettv_list_alloc(rettv) != FAIL)
6046 {
6047 int i;
6048
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006049 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050 NULL, options, WILD_ALL_KEEP);
6051 for (i = 0; i < xpc.xp_numfiles; i++)
6052 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6053
6054 ExpandCleanup(&xpc);
6055 }
6056 }
6057 else
6058 rettv->vval.v_string = NULL;
6059}
6060
6061/*
6062 * "globpath()" function
6063 */
6064 static void
6065f_globpath(typval_T *argvars, typval_T *rettv)
6066{
6067 int flags = 0;
6068 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006069 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006070 int error = FALSE;
6071 garray_T ga;
6072 int i;
6073
6074 /* When the optional second argument is non-zero, don't remove matches
6075 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6076 rettv->v_type = VAR_STRING;
6077 if (argvars[2].v_type != VAR_UNKNOWN)
6078 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006079 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006080 flags |= WILD_KEEP_ALL;
6081 if (argvars[3].v_type != VAR_UNKNOWN)
6082 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006083 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006084 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006085 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006086 }
6087 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006088 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006089 flags |= WILD_ALLLINKS;
6090 }
6091 }
6092 if (file != NULL && !error)
6093 {
6094 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006095 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006096 if (rettv->v_type == VAR_STRING)
6097 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6098 else if (rettv_list_alloc(rettv) != FAIL)
6099 for (i = 0; i < ga.ga_len; ++i)
6100 list_append_string(rettv->vval.v_list,
6101 ((char_u **)(ga.ga_data))[i], -1);
6102 ga_clear_strings(&ga);
6103 }
6104 else
6105 rettv->vval.v_string = NULL;
6106}
6107
6108/*
6109 * "glob2regpat()" function
6110 */
6111 static void
6112f_glob2regpat(typval_T *argvars, typval_T *rettv)
6113{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006114 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006115
6116 rettv->v_type = VAR_STRING;
6117 rettv->vval.v_string = (pat == NULL)
6118 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6119}
6120
6121/* for VIM_VERSION_ defines */
6122#include "version.h"
6123
6124/*
6125 * "has()" function
6126 */
6127 static void
6128f_has(typval_T *argvars, typval_T *rettv)
6129{
6130 int i;
6131 char_u *name;
6132 int n = FALSE;
6133 static char *(has_list[]) =
6134 {
6135#ifdef AMIGA
6136 "amiga",
6137# ifdef FEAT_ARP
6138 "arp",
6139# endif
6140#endif
6141#ifdef __BEOS__
6142 "beos",
6143#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006144#if defined(BSD) && !defined(MACOS_X)
6145 "bsd",
6146#endif
6147#ifdef hpux
6148 "hpux",
6149#endif
6150#ifdef __linux__
6151 "linux",
6152#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006153#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006154 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6155 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006156# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006157 "macunix", /* Mac OS X, with the darwin feature */
6158 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006159# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160#endif
6161#ifdef __QNX__
6162 "qnx",
6163#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006164#ifdef SUN_SYSTEM
6165 "sun",
6166#else
6167 "moon",
6168#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006169#ifdef UNIX
6170 "unix",
6171#endif
6172#ifdef VMS
6173 "vms",
6174#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006175#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006176 "win32",
6177#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006178#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006179 "win32unix",
6180#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006181#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182 "win64",
6183#endif
6184#ifdef EBCDIC
6185 "ebcdic",
6186#endif
6187#ifndef CASE_INSENSITIVE_FILENAME
6188 "fname_case",
6189#endif
6190#ifdef HAVE_ACL
6191 "acl",
6192#endif
6193#ifdef FEAT_ARABIC
6194 "arabic",
6195#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006197#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006198 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006199#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006200#ifdef FEAT_AUTOSERVERNAME
6201 "autoservername",
6202#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006203#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006204 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006205# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006206 "balloon_multiline",
6207# endif
6208#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006209#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006210 "balloon_eval_term",
6211#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6213 "builtin_terms",
6214# ifdef ALL_BUILTIN_TCAPS
6215 "all_builtin_terms",
6216# endif
6217#endif
6218#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006219 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006220 || defined(FEAT_GUI_MOTIF))
6221 "browsefilter",
6222#endif
6223#ifdef FEAT_BYTEOFF
6224 "byte_offset",
6225#endif
6226#ifdef FEAT_JOB_CHANNEL
6227 "channel",
6228#endif
6229#ifdef FEAT_CINDENT
6230 "cindent",
6231#endif
6232#ifdef FEAT_CLIENTSERVER
6233 "clientserver",
6234#endif
6235#ifdef FEAT_CLIPBOARD
6236 "clipboard",
6237#endif
6238#ifdef FEAT_CMDL_COMPL
6239 "cmdline_compl",
6240#endif
6241#ifdef FEAT_CMDHIST
6242 "cmdline_hist",
6243#endif
6244#ifdef FEAT_COMMENTS
6245 "comments",
6246#endif
6247#ifdef FEAT_CONCEAL
6248 "conceal",
6249#endif
6250#ifdef FEAT_CRYPT
6251 "cryptv",
6252 "crypt-blowfish",
6253 "crypt-blowfish2",
6254#endif
6255#ifdef FEAT_CSCOPE
6256 "cscope",
6257#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006258 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006259#ifdef CURSOR_SHAPE
6260 "cursorshape",
6261#endif
6262#ifdef DEBUG
6263 "debug",
6264#endif
6265#ifdef FEAT_CON_DIALOG
6266 "dialog_con",
6267#endif
6268#ifdef FEAT_GUI_DIALOG
6269 "dialog_gui",
6270#endif
6271#ifdef FEAT_DIFF
6272 "diff",
6273#endif
6274#ifdef FEAT_DIGRAPHS
6275 "digraphs",
6276#endif
6277#ifdef FEAT_DIRECTX
6278 "directx",
6279#endif
6280#ifdef FEAT_DND
6281 "dnd",
6282#endif
6283#ifdef FEAT_EMACS_TAGS
6284 "emacs_tags",
6285#endif
6286 "eval", /* always present, of course! */
6287 "ex_extra", /* graduated feature */
6288#ifdef FEAT_SEARCH_EXTRA
6289 "extra_search",
6290#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291#ifdef FEAT_SEARCHPATH
6292 "file_in_path",
6293#endif
6294#ifdef FEAT_FILTERPIPE
6295 "filterpipe",
6296#endif
6297#ifdef FEAT_FIND_ID
6298 "find_in_path",
6299#endif
6300#ifdef FEAT_FLOAT
6301 "float",
6302#endif
6303#ifdef FEAT_FOLDING
6304 "folding",
6305#endif
6306#ifdef FEAT_FOOTER
6307 "footer",
6308#endif
6309#if !defined(USE_SYSTEM) && defined(UNIX)
6310 "fork",
6311#endif
6312#ifdef FEAT_GETTEXT
6313 "gettext",
6314#endif
6315#ifdef FEAT_GUI
6316 "gui",
6317#endif
6318#ifdef FEAT_GUI_ATHENA
6319# ifdef FEAT_GUI_NEXTAW
6320 "gui_neXtaw",
6321# else
6322 "gui_athena",
6323# endif
6324#endif
6325#ifdef FEAT_GUI_GTK
6326 "gui_gtk",
6327# ifdef USE_GTK3
6328 "gui_gtk3",
6329# else
6330 "gui_gtk2",
6331# endif
6332#endif
6333#ifdef FEAT_GUI_GNOME
6334 "gui_gnome",
6335#endif
6336#ifdef FEAT_GUI_MAC
6337 "gui_mac",
6338#endif
6339#ifdef FEAT_GUI_MOTIF
6340 "gui_motif",
6341#endif
6342#ifdef FEAT_GUI_PHOTON
6343 "gui_photon",
6344#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006345#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006346 "gui_win32",
6347#endif
6348#ifdef FEAT_HANGULIN
6349 "hangul_input",
6350#endif
6351#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6352 "iconv",
6353#endif
6354#ifdef FEAT_INS_EXPAND
6355 "insert_expand",
6356#endif
6357#ifdef FEAT_JOB_CHANNEL
6358 "job",
6359#endif
6360#ifdef FEAT_JUMPLIST
6361 "jumplist",
6362#endif
6363#ifdef FEAT_KEYMAP
6364 "keymap",
6365#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006366 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006367#ifdef FEAT_LANGMAP
6368 "langmap",
6369#endif
6370#ifdef FEAT_LIBCALL
6371 "libcall",
6372#endif
6373#ifdef FEAT_LINEBREAK
6374 "linebreak",
6375#endif
6376#ifdef FEAT_LISP
6377 "lispindent",
6378#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006379 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006380#ifdef FEAT_LOCALMAP
6381 "localmap",
6382#endif
6383#ifdef FEAT_LUA
6384# ifndef DYNAMIC_LUA
6385 "lua",
6386# endif
6387#endif
6388#ifdef FEAT_MENU
6389 "menu",
6390#endif
6391#ifdef FEAT_SESSION
6392 "mksession",
6393#endif
6394#ifdef FEAT_MODIFY_FNAME
6395 "modify_fname",
6396#endif
6397#ifdef FEAT_MOUSE
6398 "mouse",
6399#endif
6400#ifdef FEAT_MOUSESHAPE
6401 "mouseshape",
6402#endif
6403#if defined(UNIX) || defined(VMS)
6404# ifdef FEAT_MOUSE_DEC
6405 "mouse_dec",
6406# endif
6407# ifdef FEAT_MOUSE_GPM
6408 "mouse_gpm",
6409# endif
6410# ifdef FEAT_MOUSE_JSB
6411 "mouse_jsbterm",
6412# endif
6413# ifdef FEAT_MOUSE_NET
6414 "mouse_netterm",
6415# endif
6416# ifdef FEAT_MOUSE_PTERM
6417 "mouse_pterm",
6418# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006419# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420 "mouse_sgr",
6421# endif
6422# ifdef FEAT_SYSMOUSE
6423 "mouse_sysmouse",
6424# endif
6425# ifdef FEAT_MOUSE_URXVT
6426 "mouse_urxvt",
6427# endif
6428# ifdef FEAT_MOUSE_XTERM
6429 "mouse_xterm",
6430# endif
6431#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006432 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006433#ifdef FEAT_MBYTE_IME
6434 "multi_byte_ime",
6435#endif
6436#ifdef FEAT_MULTI_LANG
6437 "multi_lang",
6438#endif
6439#ifdef FEAT_MZSCHEME
6440#ifndef DYNAMIC_MZSCHEME
6441 "mzscheme",
6442#endif
6443#endif
6444#ifdef FEAT_NUM64
6445 "num64",
6446#endif
6447#ifdef FEAT_OLE
6448 "ole",
6449#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006450#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006452#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006453#ifdef FEAT_PATH_EXTRA
6454 "path_extra",
6455#endif
6456#ifdef FEAT_PERL
6457#ifndef DYNAMIC_PERL
6458 "perl",
6459#endif
6460#endif
6461#ifdef FEAT_PERSISTENT_UNDO
6462 "persistent_undo",
6463#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006464#if defined(FEAT_PYTHON)
6465 "python_compiled",
6466# if defined(DYNAMIC_PYTHON)
6467 "python_dynamic",
6468# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006469 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006470 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006471# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006473#if defined(FEAT_PYTHON3)
6474 "python3_compiled",
6475# if defined(DYNAMIC_PYTHON3)
6476 "python3_dynamic",
6477# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006479 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006480# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006481#endif
6482#ifdef FEAT_POSTSCRIPT
6483 "postscript",
6484#endif
6485#ifdef FEAT_PRINTER
6486 "printer",
6487#endif
6488#ifdef FEAT_PROFILE
6489 "profile",
6490#endif
6491#ifdef FEAT_RELTIME
6492 "reltime",
6493#endif
6494#ifdef FEAT_QUICKFIX
6495 "quickfix",
6496#endif
6497#ifdef FEAT_RIGHTLEFT
6498 "rightleft",
6499#endif
6500#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6501 "ruby",
6502#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504#ifdef FEAT_CMDL_INFO
6505 "showcmd",
6506 "cmdline_info",
6507#endif
6508#ifdef FEAT_SIGNS
6509 "signs",
6510#endif
6511#ifdef FEAT_SMARTINDENT
6512 "smartindent",
6513#endif
6514#ifdef STARTUPTIME
6515 "startuptime",
6516#endif
6517#ifdef FEAT_STL_OPT
6518 "statusline",
6519#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006520#ifdef FEAT_NETBEANS_INTG
6521 "netbeans_intg",
6522#endif
6523#ifdef FEAT_SPELL
6524 "spell",
6525#endif
6526#ifdef FEAT_SYN_HL
6527 "syntax",
6528#endif
6529#if defined(USE_SYSTEM) || !defined(UNIX)
6530 "system",
6531#endif
6532#ifdef FEAT_TAG_BINS
6533 "tag_binary",
6534#endif
6535#ifdef FEAT_TAG_OLDSTATIC
6536 "tag_old_static",
6537#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538#ifdef FEAT_TCL
6539# ifndef DYNAMIC_TCL
6540 "tcl",
6541# endif
6542#endif
6543#ifdef FEAT_TERMGUICOLORS
6544 "termguicolors",
6545#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006546#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006547 "terminal",
6548#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006549#ifdef TERMINFO
6550 "terminfo",
6551#endif
6552#ifdef FEAT_TERMRESPONSE
6553 "termresponse",
6554#endif
6555#ifdef FEAT_TEXTOBJ
6556 "textobjects",
6557#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006558#ifdef FEAT_TEXT_PROP
6559 "textprop",
6560#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006561#ifdef HAVE_TGETENT
6562 "tgetent",
6563#endif
6564#ifdef FEAT_TIMERS
6565 "timers",
6566#endif
6567#ifdef FEAT_TITLE
6568 "title",
6569#endif
6570#ifdef FEAT_TOOLBAR
6571 "toolbar",
6572#endif
6573#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6574 "unnamedplus",
6575#endif
6576#ifdef FEAT_USR_CMDS
6577 "user-commands", /* was accidentally included in 5.4 */
6578 "user_commands",
6579#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006580#ifdef FEAT_VARTABS
6581 "vartabs",
6582#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583#ifdef FEAT_VIMINFO
6584 "viminfo",
6585#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006587 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006591#ifdef FEAT_VTP
6592 "vtp",
6593#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594#ifdef FEAT_WILDIGN
6595 "wildignore",
6596#endif
6597#ifdef FEAT_WILDMENU
6598 "wildmenu",
6599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006601#ifdef FEAT_WAK
6602 "winaltkeys",
6603#endif
6604#ifdef FEAT_WRITEBACKUP
6605 "writebackup",
6606#endif
6607#ifdef FEAT_XIM
6608 "xim",
6609#endif
6610#ifdef FEAT_XFONTSET
6611 "xfontset",
6612#endif
6613#ifdef FEAT_XPM_W32
6614 "xpm",
6615 "xpm_w32", /* for backward compatibility */
6616#else
6617# if defined(HAVE_XPM)
6618 "xpm",
6619# endif
6620#endif
6621#ifdef USE_XSMP
6622 "xsmp",
6623#endif
6624#ifdef USE_XSMP_INTERACT
6625 "xsmp_interact",
6626#endif
6627#ifdef FEAT_XCLIPBOARD
6628 "xterm_clipboard",
6629#endif
6630#ifdef FEAT_XTERM_SAVE
6631 "xterm_save",
6632#endif
6633#if defined(UNIX) && defined(FEAT_X11)
6634 "X11",
6635#endif
6636 NULL
6637 };
6638
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006639 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640 for (i = 0; has_list[i] != NULL; ++i)
6641 if (STRICMP(name, has_list[i]) == 0)
6642 {
6643 n = TRUE;
6644 break;
6645 }
6646
6647 if (n == FALSE)
6648 {
6649 if (STRNICMP(name, "patch", 5) == 0)
6650 {
6651 if (name[5] == '-'
6652 && STRLEN(name) >= 11
6653 && vim_isdigit(name[6])
6654 && vim_isdigit(name[8])
6655 && vim_isdigit(name[10]))
6656 {
6657 int major = atoi((char *)name + 6);
6658 int minor = atoi((char *)name + 8);
6659
6660 /* Expect "patch-9.9.01234". */
6661 n = (major < VIM_VERSION_MAJOR
6662 || (major == VIM_VERSION_MAJOR
6663 && (minor < VIM_VERSION_MINOR
6664 || (minor == VIM_VERSION_MINOR
6665 && has_patch(atoi((char *)name + 10))))));
6666 }
6667 else
6668 n = has_patch(atoi((char *)name + 5));
6669 }
6670 else if (STRICMP(name, "vim_starting") == 0)
6671 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006672 else if (STRICMP(name, "ttyin") == 0)
6673 n = mch_input_isatty();
6674 else if (STRICMP(name, "ttyout") == 0)
6675 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006676 else if (STRICMP(name, "multi_byte_encoding") == 0)
6677 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006678#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006679 else if (STRICMP(name, "balloon_multiline") == 0)
6680 n = multiline_balloon_available();
6681#endif
6682#ifdef DYNAMIC_TCL
6683 else if (STRICMP(name, "tcl") == 0)
6684 n = tcl_enabled(FALSE);
6685#endif
6686#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6687 else if (STRICMP(name, "iconv") == 0)
6688 n = iconv_enabled(FALSE);
6689#endif
6690#ifdef DYNAMIC_LUA
6691 else if (STRICMP(name, "lua") == 0)
6692 n = lua_enabled(FALSE);
6693#endif
6694#ifdef DYNAMIC_MZSCHEME
6695 else if (STRICMP(name, "mzscheme") == 0)
6696 n = mzscheme_enabled(FALSE);
6697#endif
6698#ifdef DYNAMIC_RUBY
6699 else if (STRICMP(name, "ruby") == 0)
6700 n = ruby_enabled(FALSE);
6701#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006702#ifdef DYNAMIC_PYTHON
6703 else if (STRICMP(name, "python") == 0)
6704 n = python_enabled(FALSE);
6705#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006706#ifdef DYNAMIC_PYTHON3
6707 else if (STRICMP(name, "python3") == 0)
6708 n = python3_enabled(FALSE);
6709#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006710#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6711 else if (STRICMP(name, "pythonx") == 0)
6712 {
6713# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6714 if (p_pyx == 0)
6715 n = python3_enabled(FALSE) || python_enabled(FALSE);
6716 else if (p_pyx == 3)
6717 n = python3_enabled(FALSE);
6718 else if (p_pyx == 2)
6719 n = python_enabled(FALSE);
6720# elif defined(DYNAMIC_PYTHON)
6721 n = python_enabled(FALSE);
6722# elif defined(DYNAMIC_PYTHON3)
6723 n = python3_enabled(FALSE);
6724# endif
6725 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726#endif
6727#ifdef DYNAMIC_PERL
6728 else if (STRICMP(name, "perl") == 0)
6729 n = perl_enabled(FALSE);
6730#endif
6731#ifdef FEAT_GUI
6732 else if (STRICMP(name, "gui_running") == 0)
6733 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006734# ifdef FEAT_BROWSE
6735 else if (STRICMP(name, "browse") == 0)
6736 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6737# endif
6738#endif
6739#ifdef FEAT_SYN_HL
6740 else if (STRICMP(name, "syntax_items") == 0)
6741 n = syntax_present(curwin);
6742#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006743#ifdef FEAT_VTP
6744 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006745 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746#endif
6747#ifdef FEAT_NETBEANS_INTG
6748 else if (STRICMP(name, "netbeans_enabled") == 0)
6749 n = netbeans_active();
6750#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006751#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006752 else if (STRICMP(name, "terminal") == 0)
6753 n = terminal_enabled();
6754#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006755#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006756 else if (STRICMP(name, "conpty") == 0)
6757 n = use_conpty();
6758#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759 }
6760
6761 rettv->vval.v_number = n;
6762}
6763
6764/*
6765 * "has_key()" function
6766 */
6767 static void
6768f_has_key(typval_T *argvars, typval_T *rettv)
6769{
6770 if (argvars[0].v_type != VAR_DICT)
6771 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006772 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 return;
6774 }
6775 if (argvars[0].vval.v_dict == NULL)
6776 return;
6777
6778 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006779 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006780}
6781
6782/*
6783 * "haslocaldir()" function
6784 */
6785 static void
6786f_haslocaldir(typval_T *argvars, typval_T *rettv)
6787{
6788 win_T *wp = NULL;
6789
6790 wp = find_tabwin(&argvars[0], &argvars[1]);
6791 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6792}
6793
6794/*
6795 * "hasmapto()" function
6796 */
6797 static void
6798f_hasmapto(typval_T *argvars, typval_T *rettv)
6799{
6800 char_u *name;
6801 char_u *mode;
6802 char_u buf[NUMBUFLEN];
6803 int abbr = FALSE;
6804
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006805 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006806 if (argvars[1].v_type == VAR_UNKNOWN)
6807 mode = (char_u *)"nvo";
6808 else
6809 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006810 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006811 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006812 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006813 }
6814
6815 if (map_to_exists(name, mode, abbr))
6816 rettv->vval.v_number = TRUE;
6817 else
6818 rettv->vval.v_number = FALSE;
6819}
6820
6821/*
6822 * "histadd()" function
6823 */
6824 static void
6825f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6826{
6827#ifdef FEAT_CMDHIST
6828 int histype;
6829 char_u *str;
6830 char_u buf[NUMBUFLEN];
6831#endif
6832
6833 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006834 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006835 return;
6836#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006837 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006838 histype = str != NULL ? get_histtype(str) : -1;
6839 if (histype >= 0)
6840 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006841 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842 if (*str != NUL)
6843 {
6844 init_history();
6845 add_to_history(histype, str, FALSE, NUL);
6846 rettv->vval.v_number = TRUE;
6847 return;
6848 }
6849 }
6850#endif
6851}
6852
6853/*
6854 * "histdel()" function
6855 */
6856 static void
6857f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6858{
6859#ifdef FEAT_CMDHIST
6860 int n;
6861 char_u buf[NUMBUFLEN];
6862 char_u *str;
6863
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006864 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865 if (str == NULL)
6866 n = 0;
6867 else if (argvars[1].v_type == VAR_UNKNOWN)
6868 /* only one argument: clear entire history */
6869 n = clr_history(get_histtype(str));
6870 else if (argvars[1].v_type == VAR_NUMBER)
6871 /* index given: remove that entry */
6872 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006873 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874 else
6875 /* string given: remove all matching entries */
6876 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006877 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 rettv->vval.v_number = n;
6879#endif
6880}
6881
6882/*
6883 * "histget()" function
6884 */
6885 static void
6886f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6887{
6888#ifdef FEAT_CMDHIST
6889 int type;
6890 int idx;
6891 char_u *str;
6892
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006893 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006894 if (str == NULL)
6895 rettv->vval.v_string = NULL;
6896 else
6897 {
6898 type = get_histtype(str);
6899 if (argvars[1].v_type == VAR_UNKNOWN)
6900 idx = get_history_idx(type);
6901 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006902 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006903 /* -1 on type error */
6904 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6905 }
6906#else
6907 rettv->vval.v_string = NULL;
6908#endif
6909 rettv->v_type = VAR_STRING;
6910}
6911
6912/*
6913 * "histnr()" function
6914 */
6915 static void
6916f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6917{
6918 int i;
6919
6920#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006921 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922
6923 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6924 if (i >= HIST_CMD && i < HIST_COUNT)
6925 i = get_history_idx(i);
6926 else
6927#endif
6928 i = -1;
6929 rettv->vval.v_number = i;
6930}
6931
6932/*
6933 * "highlightID(name)" function
6934 */
6935 static void
6936f_hlID(typval_T *argvars, typval_T *rettv)
6937{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006938 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006939}
6940
6941/*
6942 * "highlight_exists()" function
6943 */
6944 static void
6945f_hlexists(typval_T *argvars, typval_T *rettv)
6946{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006947 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948}
6949
6950/*
6951 * "hostname()" function
6952 */
6953 static void
6954f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6955{
6956 char_u hostname[256];
6957
6958 mch_get_host_name(hostname, 256);
6959 rettv->v_type = VAR_STRING;
6960 rettv->vval.v_string = vim_strsave(hostname);
6961}
6962
6963/*
6964 * iconv() function
6965 */
6966 static void
6967f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6968{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006969 char_u buf1[NUMBUFLEN];
6970 char_u buf2[NUMBUFLEN];
6971 char_u *from, *to, *str;
6972 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006973
6974 rettv->v_type = VAR_STRING;
6975 rettv->vval.v_string = NULL;
6976
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006977 str = tv_get_string(&argvars[0]);
6978 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6979 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006980 vimconv.vc_type = CONV_NONE;
6981 convert_setup(&vimconv, from, to);
6982
6983 /* If the encodings are equal, no conversion needed. */
6984 if (vimconv.vc_type == CONV_NONE)
6985 rettv->vval.v_string = vim_strsave(str);
6986 else
6987 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6988
6989 convert_setup(&vimconv, NULL, NULL);
6990 vim_free(from);
6991 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006992}
6993
6994/*
6995 * "indent()" function
6996 */
6997 static void
6998f_indent(typval_T *argvars, typval_T *rettv)
6999{
7000 linenr_T lnum;
7001
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007002 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007003 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7004 rettv->vval.v_number = get_indent_lnum(lnum);
7005 else
7006 rettv->vval.v_number = -1;
7007}
7008
7009/*
7010 * "index()" function
7011 */
7012 static void
7013f_index(typval_T *argvars, typval_T *rettv)
7014{
7015 list_T *l;
7016 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007017 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007018 long idx = 0;
7019 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007020 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007021
7022 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007023 if (argvars[0].v_type == VAR_BLOB)
7024 {
7025 typval_T tv;
7026 int start = 0;
7027
7028 if (argvars[2].v_type != VAR_UNKNOWN)
7029 {
7030 start = tv_get_number_chk(&argvars[2], &error);
7031 if (error)
7032 return;
7033 }
7034 b = argvars[0].vval.v_blob;
7035 if (b == NULL)
7036 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007037 if (start < 0)
7038 {
7039 start = blob_len(b) + start;
7040 if (start < 0)
7041 start = 0;
7042 }
7043
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007044 for (idx = start; idx < blob_len(b); ++idx)
7045 {
7046 tv.v_type = VAR_NUMBER;
7047 tv.vval.v_number = blob_get(b, idx);
7048 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7049 {
7050 rettv->vval.v_number = idx;
7051 return;
7052 }
7053 }
7054 return;
7055 }
7056 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007057 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007058 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007059 return;
7060 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 l = argvars[0].vval.v_list;
7063 if (l != NULL)
7064 {
7065 item = l->lv_first;
7066 if (argvars[2].v_type != VAR_UNKNOWN)
7067 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068 /* Start at specified item. Use the cached index that list_find()
7069 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007070 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 idx = l->lv_idx;
7072 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007073 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074 if (error)
7075 item = NULL;
7076 }
7077
7078 for ( ; item != NULL; item = item->li_next, ++idx)
7079 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7080 {
7081 rettv->vval.v_number = idx;
7082 break;
7083 }
7084 }
7085}
7086
7087static int inputsecret_flag = 0;
7088
7089/*
7090 * "input()" function
7091 * Also handles inputsecret() when inputsecret is set.
7092 */
7093 static void
7094f_input(typval_T *argvars, typval_T *rettv)
7095{
7096 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7097}
7098
7099/*
7100 * "inputdialog()" function
7101 */
7102 static void
7103f_inputdialog(typval_T *argvars, typval_T *rettv)
7104{
7105#if defined(FEAT_GUI_TEXTDIALOG)
7106 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7107 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7108 {
7109 char_u *message;
7110 char_u buf[NUMBUFLEN];
7111 char_u *defstr = (char_u *)"";
7112
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007113 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007114 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007115 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007116 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7117 else
7118 IObuff[0] = NUL;
7119 if (message != NULL && defstr != NULL
7120 && do_dialog(VIM_QUESTION, NULL, message,
7121 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7122 rettv->vval.v_string = vim_strsave(IObuff);
7123 else
7124 {
7125 if (message != NULL && defstr != NULL
7126 && argvars[1].v_type != VAR_UNKNOWN
7127 && argvars[2].v_type != VAR_UNKNOWN)
7128 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007129 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007130 else
7131 rettv->vval.v_string = NULL;
7132 }
7133 rettv->v_type = VAR_STRING;
7134 }
7135 else
7136#endif
7137 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7138}
7139
7140/*
7141 * "inputlist()" function
7142 */
7143 static void
7144f_inputlist(typval_T *argvars, typval_T *rettv)
7145{
7146 listitem_T *li;
7147 int selected;
7148 int mouse_used;
7149
7150#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007151 /* While starting up, there is no place to enter text. When running tests
7152 * with --not-a-term we assume feedkeys() will be used. */
7153 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007154 return;
7155#endif
7156 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7157 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007158 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007159 return;
7160 }
7161
7162 msg_start();
7163 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7164 lines_left = Rows; /* avoid more prompt */
7165 msg_scroll = TRUE;
7166 msg_clr_eos();
7167
7168 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7169 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007170 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007171 msg_putchar('\n');
7172 }
7173
7174 /* Ask for choice. */
7175 selected = prompt_for_number(&mouse_used);
7176 if (mouse_used)
7177 selected -= lines_left;
7178
7179 rettv->vval.v_number = selected;
7180}
7181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007182static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7183
7184/*
7185 * "inputrestore()" function
7186 */
7187 static void
7188f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7189{
7190 if (ga_userinput.ga_len > 0)
7191 {
7192 --ga_userinput.ga_len;
7193 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7194 + ga_userinput.ga_len);
7195 /* default return is zero == OK */
7196 }
7197 else if (p_verbose > 1)
7198 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007199 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007200 rettv->vval.v_number = 1; /* Failed */
7201 }
7202}
7203
7204/*
7205 * "inputsave()" function
7206 */
7207 static void
7208f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7209{
7210 /* Add an entry to the stack of typeahead storage. */
7211 if (ga_grow(&ga_userinput, 1) == OK)
7212 {
7213 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7214 + ga_userinput.ga_len);
7215 ++ga_userinput.ga_len;
7216 /* default return is zero == OK */
7217 }
7218 else
7219 rettv->vval.v_number = 1; /* Failed */
7220}
7221
7222/*
7223 * "inputsecret()" function
7224 */
7225 static void
7226f_inputsecret(typval_T *argvars, typval_T *rettv)
7227{
7228 ++cmdline_star;
7229 ++inputsecret_flag;
7230 f_input(argvars, rettv);
7231 --cmdline_star;
7232 --inputsecret_flag;
7233}
7234
7235/*
7236 * "insert()" function
7237 */
7238 static void
7239f_insert(typval_T *argvars, typval_T *rettv)
7240{
7241 long before = 0;
7242 listitem_T *item;
7243 list_T *l;
7244 int error = FALSE;
7245
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007246 if (argvars[0].v_type == VAR_BLOB)
7247 {
7248 int val, len;
7249 char_u *p;
7250
7251 len = blob_len(argvars[0].vval.v_blob);
7252 if (argvars[2].v_type != VAR_UNKNOWN)
7253 {
7254 before = (long)tv_get_number_chk(&argvars[2], &error);
7255 if (error)
7256 return; // type error; errmsg already given
7257 if (before < 0 || before > len)
7258 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007259 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007260 return;
7261 }
7262 }
7263 val = tv_get_number_chk(&argvars[1], &error);
7264 if (error)
7265 return;
7266 if (val < 0 || val > 255)
7267 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007268 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007269 return;
7270 }
7271
7272 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7273 return;
7274 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7275 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7276 *(p + before) = val;
7277 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7278
7279 copy_tv(&argvars[0], rettv);
7280 }
7281 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007282 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007283 else if ((l = argvars[0].vval.v_list) != NULL
7284 && !var_check_lock(l->lv_lock,
7285 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007286 {
7287 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007288 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007289 if (error)
7290 return; /* type error; errmsg already given */
7291
7292 if (before == l->lv_len)
7293 item = NULL;
7294 else
7295 {
7296 item = list_find(l, before);
7297 if (item == NULL)
7298 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007299 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007300 l = NULL;
7301 }
7302 }
7303 if (l != NULL)
7304 {
7305 list_insert_tv(l, &argvars[1], item);
7306 copy_tv(&argvars[0], rettv);
7307 }
7308 }
7309}
7310
7311/*
7312 * "invert(expr)" function
7313 */
7314 static void
7315f_invert(typval_T *argvars, typval_T *rettv)
7316{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007317 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007318}
7319
7320/*
7321 * "isdirectory()" function
7322 */
7323 static void
7324f_isdirectory(typval_T *argvars, typval_T *rettv)
7325{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007326 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007327}
7328
7329/*
7330 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7331 * or it refers to a List or Dictionary that is locked.
7332 */
7333 static int
7334tv_islocked(typval_T *tv)
7335{
7336 return (tv->v_lock & VAR_LOCKED)
7337 || (tv->v_type == VAR_LIST
7338 && tv->vval.v_list != NULL
7339 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7340 || (tv->v_type == VAR_DICT
7341 && tv->vval.v_dict != NULL
7342 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7343}
7344
7345/*
7346 * "islocked()" function
7347 */
7348 static void
7349f_islocked(typval_T *argvars, typval_T *rettv)
7350{
7351 lval_T lv;
7352 char_u *end;
7353 dictitem_T *di;
7354
7355 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007356 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007357 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358 if (end != NULL && lv.ll_name != NULL)
7359 {
7360 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007361 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362 else
7363 {
7364 if (lv.ll_tv == NULL)
7365 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007366 di = find_var(lv.ll_name, NULL, TRUE);
7367 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007369 /* Consider a variable locked when:
7370 * 1. the variable itself is locked
7371 * 2. the value of the variable is locked.
7372 * 3. the List or Dict value is locked.
7373 */
7374 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7375 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007376 }
7377 }
7378 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007379 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007380 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007381 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 else if (lv.ll_list != NULL)
7383 /* List item. */
7384 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7385 else
7386 /* Dictionary item. */
7387 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7388 }
7389 }
7390
7391 clear_lval(&lv);
7392}
7393
7394#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7395/*
7396 * "isnan()" function
7397 */
7398 static void
7399f_isnan(typval_T *argvars, typval_T *rettv)
7400{
7401 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7402 && isnan(argvars[0].vval.v_float);
7403}
7404#endif
7405
7406/*
7407 * "items(dict)" function
7408 */
7409 static void
7410f_items(typval_T *argvars, typval_T *rettv)
7411{
7412 dict_list(argvars, rettv, 2);
7413}
7414
7415#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7416/*
7417 * Get the job from the argument.
7418 * Returns NULL if the job is invalid.
7419 */
7420 static job_T *
7421get_job_arg(typval_T *tv)
7422{
7423 job_T *job;
7424
7425 if (tv->v_type != VAR_JOB)
7426 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007427 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 return NULL;
7429 }
7430 job = tv->vval.v_job;
7431
7432 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007433 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 return job;
7435}
7436
7437/*
7438 * "job_getchannel()" function
7439 */
7440 static void
7441f_job_getchannel(typval_T *argvars, typval_T *rettv)
7442{
7443 job_T *job = get_job_arg(&argvars[0]);
7444
7445 if (job != NULL)
7446 {
7447 rettv->v_type = VAR_CHANNEL;
7448 rettv->vval.v_channel = job->jv_channel;
7449 if (job->jv_channel != NULL)
7450 ++job->jv_channel->ch_refcount;
7451 }
7452}
7453
7454/*
7455 * "job_info()" function
7456 */
7457 static void
7458f_job_info(typval_T *argvars, typval_T *rettv)
7459{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007460 if (argvars[0].v_type != VAR_UNKNOWN)
7461 {
7462 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007463
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007464 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7465 job_info(job, rettv->vval.v_dict);
7466 }
7467 else if (rettv_list_alloc(rettv) == OK)
7468 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007469}
7470
7471/*
7472 * "job_setoptions()" function
7473 */
7474 static void
7475f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7476{
7477 job_T *job = get_job_arg(&argvars[0]);
7478 jobopt_T opt;
7479
7480 if (job == NULL)
7481 return;
7482 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007483 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007484 job_set_options(job, &opt);
7485 free_job_options(&opt);
7486}
7487
7488/*
7489 * "job_start()" function
7490 */
7491 static void
7492f_job_start(typval_T *argvars, typval_T *rettv)
7493{
7494 rettv->v_type = VAR_JOB;
7495 if (check_restricted() || check_secure())
7496 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007497 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498}
7499
7500/*
7501 * "job_status()" function
7502 */
7503 static void
7504f_job_status(typval_T *argvars, typval_T *rettv)
7505{
7506 job_T *job = get_job_arg(&argvars[0]);
7507
7508 if (job != NULL)
7509 {
7510 rettv->v_type = VAR_STRING;
7511 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7512 }
7513}
7514
7515/*
7516 * "job_stop()" function
7517 */
7518 static void
7519f_job_stop(typval_T *argvars, typval_T *rettv)
7520{
7521 job_T *job = get_job_arg(&argvars[0]);
7522
7523 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007524 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525}
7526#endif
7527
7528/*
7529 * "join()" function
7530 */
7531 static void
7532f_join(typval_T *argvars, typval_T *rettv)
7533{
7534 garray_T ga;
7535 char_u *sep;
7536
7537 if (argvars[0].v_type != VAR_LIST)
7538 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007539 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540 return;
7541 }
7542 if (argvars[0].vval.v_list == NULL)
7543 return;
7544 if (argvars[1].v_type == VAR_UNKNOWN)
7545 sep = (char_u *)" ";
7546 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007547 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007548
7549 rettv->v_type = VAR_STRING;
7550
7551 if (sep != NULL)
7552 {
7553 ga_init2(&ga, (int)sizeof(char), 80);
7554 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7555 ga_append(&ga, NUL);
7556 rettv->vval.v_string = (char_u *)ga.ga_data;
7557 }
7558 else
7559 rettv->vval.v_string = NULL;
7560}
7561
7562/*
7563 * "js_decode()" function
7564 */
7565 static void
7566f_js_decode(typval_T *argvars, typval_T *rettv)
7567{
7568 js_read_T reader;
7569
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007570 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007571 reader.js_fill = NULL;
7572 reader.js_used = 0;
7573 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007574 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575}
7576
7577/*
7578 * "js_encode()" function
7579 */
7580 static void
7581f_js_encode(typval_T *argvars, typval_T *rettv)
7582{
7583 rettv->v_type = VAR_STRING;
7584 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7585}
7586
7587/*
7588 * "json_decode()" function
7589 */
7590 static void
7591f_json_decode(typval_T *argvars, typval_T *rettv)
7592{
7593 js_read_T reader;
7594
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007595 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007596 reader.js_fill = NULL;
7597 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007598 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007599}
7600
7601/*
7602 * "json_encode()" function
7603 */
7604 static void
7605f_json_encode(typval_T *argvars, typval_T *rettv)
7606{
7607 rettv->v_type = VAR_STRING;
7608 rettv->vval.v_string = json_encode(&argvars[0], 0);
7609}
7610
7611/*
7612 * "keys()" function
7613 */
7614 static void
7615f_keys(typval_T *argvars, typval_T *rettv)
7616{
7617 dict_list(argvars, rettv, 0);
7618}
7619
7620/*
7621 * "last_buffer_nr()" function.
7622 */
7623 static void
7624f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7625{
7626 int n = 0;
7627 buf_T *buf;
7628
Bram Moolenaar29323592016-07-24 22:04:11 +02007629 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630 if (n < buf->b_fnum)
7631 n = buf->b_fnum;
7632
7633 rettv->vval.v_number = n;
7634}
7635
7636/*
7637 * "len()" function
7638 */
7639 static void
7640f_len(typval_T *argvars, typval_T *rettv)
7641{
7642 switch (argvars[0].v_type)
7643 {
7644 case VAR_STRING:
7645 case VAR_NUMBER:
7646 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007647 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007649 case VAR_BLOB:
7650 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7651 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652 case VAR_LIST:
7653 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7654 break;
7655 case VAR_DICT:
7656 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7657 break;
7658 case VAR_UNKNOWN:
7659 case VAR_SPECIAL:
7660 case VAR_FLOAT:
7661 case VAR_FUNC:
7662 case VAR_PARTIAL:
7663 case VAR_JOB:
7664 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007665 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007666 break;
7667 }
7668}
7669
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007671libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672{
7673#ifdef FEAT_LIBCALL
7674 char_u *string_in;
7675 char_u **string_result;
7676 int nr_result;
7677#endif
7678
7679 rettv->v_type = type;
7680 if (type != VAR_NUMBER)
7681 rettv->vval.v_string = NULL;
7682
7683 if (check_restricted() || check_secure())
7684 return;
7685
7686#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007687 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007688 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7689 {
7690 string_in = NULL;
7691 if (argvars[2].v_type == VAR_STRING)
7692 string_in = argvars[2].vval.v_string;
7693 if (type == VAR_NUMBER)
7694 string_result = NULL;
7695 else
7696 string_result = &rettv->vval.v_string;
7697 if (mch_libcall(argvars[0].vval.v_string,
7698 argvars[1].vval.v_string,
7699 string_in,
7700 argvars[2].vval.v_number,
7701 string_result,
7702 &nr_result) == OK
7703 && type == VAR_NUMBER)
7704 rettv->vval.v_number = nr_result;
7705 }
7706#endif
7707}
7708
7709/*
7710 * "libcall()" function
7711 */
7712 static void
7713f_libcall(typval_T *argvars, typval_T *rettv)
7714{
7715 libcall_common(argvars, rettv, VAR_STRING);
7716}
7717
7718/*
7719 * "libcallnr()" function
7720 */
7721 static void
7722f_libcallnr(typval_T *argvars, typval_T *rettv)
7723{
7724 libcall_common(argvars, rettv, VAR_NUMBER);
7725}
7726
7727/*
7728 * "line(string)" function
7729 */
7730 static void
7731f_line(typval_T *argvars, typval_T *rettv)
7732{
7733 linenr_T lnum = 0;
7734 pos_T *fp;
7735 int fnum;
7736
7737 fp = var2fpos(&argvars[0], TRUE, &fnum);
7738 if (fp != NULL)
7739 lnum = fp->lnum;
7740 rettv->vval.v_number = lnum;
7741}
7742
7743/*
7744 * "line2byte(lnum)" function
7745 */
7746 static void
7747f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7748{
7749#ifndef FEAT_BYTEOFF
7750 rettv->vval.v_number = -1;
7751#else
7752 linenr_T lnum;
7753
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007754 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007755 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7756 rettv->vval.v_number = -1;
7757 else
7758 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7759 if (rettv->vval.v_number >= 0)
7760 ++rettv->vval.v_number;
7761#endif
7762}
7763
7764/*
7765 * "lispindent(lnum)" function
7766 */
7767 static void
7768f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7769{
7770#ifdef FEAT_LISP
7771 pos_T pos;
7772 linenr_T lnum;
7773
7774 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007775 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7777 {
7778 curwin->w_cursor.lnum = lnum;
7779 rettv->vval.v_number = get_lisp_indent();
7780 curwin->w_cursor = pos;
7781 }
7782 else
7783#endif
7784 rettv->vval.v_number = -1;
7785}
7786
7787/*
7788 * "localtime()" function
7789 */
7790 static void
7791f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7792{
7793 rettv->vval.v_number = (varnumber_T)time(NULL);
7794}
7795
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007796 static void
7797get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7798{
7799 char_u *keys;
7800 char_u *which;
7801 char_u buf[NUMBUFLEN];
7802 char_u *keys_buf = NULL;
7803 char_u *rhs;
7804 int mode;
7805 int abbr = FALSE;
7806 int get_dict = FALSE;
7807 mapblock_T *mp;
7808 int buffer_local;
7809
7810 /* return empty string for failure */
7811 rettv->v_type = VAR_STRING;
7812 rettv->vval.v_string = NULL;
7813
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007814 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007815 if (*keys == NUL)
7816 return;
7817
7818 if (argvars[1].v_type != VAR_UNKNOWN)
7819 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007820 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007821 if (argvars[2].v_type != VAR_UNKNOWN)
7822 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007823 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007824 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007825 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 }
7827 }
7828 else
7829 which = (char_u *)"";
7830 if (which == NULL)
7831 return;
7832
7833 mode = get_map_mode(&which, 0);
7834
7835 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7836 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7837 vim_free(keys_buf);
7838
7839 if (!get_dict)
7840 {
7841 /* Return a string. */
7842 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007843 {
7844 if (*rhs == NUL)
7845 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7846 else
7847 rettv->vval.v_string = str2special_save(rhs, FALSE);
7848 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007849
7850 }
7851 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7852 {
7853 /* Return a dictionary. */
7854 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7855 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7856 dict_T *dict = rettv->vval.v_dict;
7857
Bram Moolenaare0be1672018-07-08 16:50:37 +02007858 dict_add_string(dict, "lhs", lhs);
7859 dict_add_string(dict, "rhs", mp->m_orig_str);
7860 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7861 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7862 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007863 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7864 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007865 dict_add_number(dict, "buffer", (long)buffer_local);
7866 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7867 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868
7869 vim_free(lhs);
7870 vim_free(mapmode);
7871 }
7872}
7873
7874#ifdef FEAT_FLOAT
7875/*
7876 * "log()" function
7877 */
7878 static void
7879f_log(typval_T *argvars, typval_T *rettv)
7880{
7881 float_T f = 0.0;
7882
7883 rettv->v_type = VAR_FLOAT;
7884 if (get_float_arg(argvars, &f) == OK)
7885 rettv->vval.v_float = log(f);
7886 else
7887 rettv->vval.v_float = 0.0;
7888}
7889
7890/*
7891 * "log10()" function
7892 */
7893 static void
7894f_log10(typval_T *argvars, typval_T *rettv)
7895{
7896 float_T f = 0.0;
7897
7898 rettv->v_type = VAR_FLOAT;
7899 if (get_float_arg(argvars, &f) == OK)
7900 rettv->vval.v_float = log10(f);
7901 else
7902 rettv->vval.v_float = 0.0;
7903}
7904#endif
7905
7906#ifdef FEAT_LUA
7907/*
7908 * "luaeval()" function
7909 */
7910 static void
7911f_luaeval(typval_T *argvars, typval_T *rettv)
7912{
7913 char_u *str;
7914 char_u buf[NUMBUFLEN];
7915
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007916 if (check_restricted() || check_secure())
7917 return;
7918
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007919 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007920 do_luaeval(str, argvars + 1, rettv);
7921}
7922#endif
7923
7924/*
7925 * "map()" function
7926 */
7927 static void
7928f_map(typval_T *argvars, typval_T *rettv)
7929{
7930 filter_map(argvars, rettv, TRUE);
7931}
7932
7933/*
7934 * "maparg()" function
7935 */
7936 static void
7937f_maparg(typval_T *argvars, typval_T *rettv)
7938{
7939 get_maparg(argvars, rettv, TRUE);
7940}
7941
7942/*
7943 * "mapcheck()" function
7944 */
7945 static void
7946f_mapcheck(typval_T *argvars, typval_T *rettv)
7947{
7948 get_maparg(argvars, rettv, FALSE);
7949}
7950
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007951typedef enum
7952{
7953 MATCH_END, /* matchend() */
7954 MATCH_MATCH, /* match() */
7955 MATCH_STR, /* matchstr() */
7956 MATCH_LIST, /* matchlist() */
7957 MATCH_POS /* matchstrpos() */
7958} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007959
7960 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007961find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007962{
7963 char_u *str = NULL;
7964 long len = 0;
7965 char_u *expr = NULL;
7966 char_u *pat;
7967 regmatch_T regmatch;
7968 char_u patbuf[NUMBUFLEN];
7969 char_u strbuf[NUMBUFLEN];
7970 char_u *save_cpo;
7971 long start = 0;
7972 long nth = 1;
7973 colnr_T startcol = 0;
7974 int match = 0;
7975 list_T *l = NULL;
7976 listitem_T *li = NULL;
7977 long idx = 0;
7978 char_u *tofree = NULL;
7979
7980 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7981 save_cpo = p_cpo;
7982 p_cpo = (char_u *)"";
7983
7984 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007985 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007986 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007987 /* type MATCH_LIST: return empty list when there are no matches.
7988 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007989 if (rettv_list_alloc(rettv) == FAIL)
7990 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007991 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992 && (list_append_string(rettv->vval.v_list,
7993 (char_u *)"", 0) == FAIL
7994 || list_append_number(rettv->vval.v_list,
7995 (varnumber_T)-1) == FAIL
7996 || list_append_number(rettv->vval.v_list,
7997 (varnumber_T)-1) == FAIL
7998 || list_append_number(rettv->vval.v_list,
7999 (varnumber_T)-1) == FAIL))
8000 {
8001 list_free(rettv->vval.v_list);
8002 rettv->vval.v_list = NULL;
8003 goto theend;
8004 }
8005 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008006 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007 {
8008 rettv->v_type = VAR_STRING;
8009 rettv->vval.v_string = NULL;
8010 }
8011
8012 if (argvars[0].v_type == VAR_LIST)
8013 {
8014 if ((l = argvars[0].vval.v_list) == NULL)
8015 goto theend;
8016 li = l->lv_first;
8017 }
8018 else
8019 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008020 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008021 len = (long)STRLEN(str);
8022 }
8023
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008024 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008025 if (pat == NULL)
8026 goto theend;
8027
8028 if (argvars[2].v_type != VAR_UNKNOWN)
8029 {
8030 int error = FALSE;
8031
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008032 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033 if (error)
8034 goto theend;
8035 if (l != NULL)
8036 {
8037 li = list_find(l, start);
8038 if (li == NULL)
8039 goto theend;
8040 idx = l->lv_idx; /* use the cached index */
8041 }
8042 else
8043 {
8044 if (start < 0)
8045 start = 0;
8046 if (start > len)
8047 goto theend;
8048 /* When "count" argument is there ignore matches before "start",
8049 * otherwise skip part of the string. Differs when pattern is "^"
8050 * or "\<". */
8051 if (argvars[3].v_type != VAR_UNKNOWN)
8052 startcol = start;
8053 else
8054 {
8055 str += start;
8056 len -= start;
8057 }
8058 }
8059
8060 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008061 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008062 if (error)
8063 goto theend;
8064 }
8065
8066 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8067 if (regmatch.regprog != NULL)
8068 {
8069 regmatch.rm_ic = p_ic;
8070
8071 for (;;)
8072 {
8073 if (l != NULL)
8074 {
8075 if (li == NULL)
8076 {
8077 match = FALSE;
8078 break;
8079 }
8080 vim_free(tofree);
8081 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8082 if (str == NULL)
8083 break;
8084 }
8085
8086 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8087
8088 if (match && --nth <= 0)
8089 break;
8090 if (l == NULL && !match)
8091 break;
8092
8093 /* Advance to just after the match. */
8094 if (l != NULL)
8095 {
8096 li = li->li_next;
8097 ++idx;
8098 }
8099 else
8100 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008101 startcol = (colnr_T)(regmatch.startp[0]
8102 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008103 if (startcol > (colnr_T)len
8104 || str + startcol <= regmatch.startp[0])
8105 {
8106 match = FALSE;
8107 break;
8108 }
8109 }
8110 }
8111
8112 if (match)
8113 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008114 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008115 {
8116 listitem_T *li1 = rettv->vval.v_list->lv_first;
8117 listitem_T *li2 = li1->li_next;
8118 listitem_T *li3 = li2->li_next;
8119 listitem_T *li4 = li3->li_next;
8120
8121 vim_free(li1->li_tv.vval.v_string);
8122 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8123 (int)(regmatch.endp[0] - regmatch.startp[0]));
8124 li3->li_tv.vval.v_number =
8125 (varnumber_T)(regmatch.startp[0] - expr);
8126 li4->li_tv.vval.v_number =
8127 (varnumber_T)(regmatch.endp[0] - expr);
8128 if (l != NULL)
8129 li2->li_tv.vval.v_number = (varnumber_T)idx;
8130 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008131 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008132 {
8133 int i;
8134
8135 /* return list with matched string and submatches */
8136 for (i = 0; i < NSUBEXP; ++i)
8137 {
8138 if (regmatch.endp[i] == NULL)
8139 {
8140 if (list_append_string(rettv->vval.v_list,
8141 (char_u *)"", 0) == FAIL)
8142 break;
8143 }
8144 else if (list_append_string(rettv->vval.v_list,
8145 regmatch.startp[i],
8146 (int)(regmatch.endp[i] - regmatch.startp[i]))
8147 == FAIL)
8148 break;
8149 }
8150 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008151 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008152 {
8153 /* return matched string */
8154 if (l != NULL)
8155 copy_tv(&li->li_tv, rettv);
8156 else
8157 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8158 (int)(regmatch.endp[0] - regmatch.startp[0]));
8159 }
8160 else if (l != NULL)
8161 rettv->vval.v_number = idx;
8162 else
8163 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008164 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165 rettv->vval.v_number =
8166 (varnumber_T)(regmatch.startp[0] - str);
8167 else
8168 rettv->vval.v_number =
8169 (varnumber_T)(regmatch.endp[0] - str);
8170 rettv->vval.v_number += (varnumber_T)(str - expr);
8171 }
8172 }
8173 vim_regfree(regmatch.regprog);
8174 }
8175
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008176theend:
8177 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008178 /* matchstrpos() without a list: drop the second item. */
8179 listitem_remove(rettv->vval.v_list,
8180 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008181 vim_free(tofree);
8182 p_cpo = save_cpo;
8183}
8184
8185/*
8186 * "match()" function
8187 */
8188 static void
8189f_match(typval_T *argvars, typval_T *rettv)
8190{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008191 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192}
8193
Bram Moolenaar95e51472018-07-28 16:55:56 +02008194#ifdef FEAT_SEARCH_EXTRA
8195 static int
8196matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8197{
8198 dictitem_T *di;
8199
8200 if (tv->v_type != VAR_DICT)
8201 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008202 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008203 return FAIL;
8204 }
8205
8206 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008207 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008208 (char_u *)"conceal", FALSE);
8209
8210 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8211 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008212 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008213 if (*win == NULL)
8214 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008215 emsg(_("E957: Invalid window number"));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008216 return FAIL;
8217 }
8218 }
8219
8220 return OK;
8221}
8222#endif
8223
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008224/*
8225 * "matchadd()" function
8226 */
8227 static void
8228f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8229{
8230#ifdef FEAT_SEARCH_EXTRA
8231 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008232 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8233 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008234 int prio = 10; /* default priority */
8235 int id = -1;
8236 int error = FALSE;
8237 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008238 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239
8240 rettv->vval.v_number = -1;
8241
8242 if (grp == NULL || pat == NULL)
8243 return;
8244 if (argvars[2].v_type != VAR_UNKNOWN)
8245 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008246 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008247 if (argvars[3].v_type != VAR_UNKNOWN)
8248 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008249 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008250 if (argvars[4].v_type != VAR_UNKNOWN
8251 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8252 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008253 }
8254 }
8255 if (error == TRUE)
8256 return;
8257 if (id >= 1 && id <= 3)
8258 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008259 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008260 return;
8261 }
8262
Bram Moolenaar95e51472018-07-28 16:55:56 +02008263 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008264 conceal_char);
8265#endif
8266}
8267
8268/*
8269 * "matchaddpos()" function
8270 */
8271 static void
8272f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8273{
8274#ifdef FEAT_SEARCH_EXTRA
8275 char_u buf[NUMBUFLEN];
8276 char_u *group;
8277 int prio = 10;
8278 int id = -1;
8279 int error = FALSE;
8280 list_T *l;
8281 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008282 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283
8284 rettv->vval.v_number = -1;
8285
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008286 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008287 if (group == NULL)
8288 return;
8289
8290 if (argvars[1].v_type != VAR_LIST)
8291 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008292 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008293 return;
8294 }
8295 l = argvars[1].vval.v_list;
8296 if (l == NULL)
8297 return;
8298
8299 if (argvars[2].v_type != VAR_UNKNOWN)
8300 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008301 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302 if (argvars[3].v_type != VAR_UNKNOWN)
8303 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008304 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008305
8306 if (argvars[4].v_type != VAR_UNKNOWN
8307 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8308 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008309 }
8310 }
8311 if (error == TRUE)
8312 return;
8313
8314 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8315 if (id == 1 || id == 2)
8316 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008317 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008318 return;
8319 }
8320
Bram Moolenaar95e51472018-07-28 16:55:56 +02008321 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008322 conceal_char);
8323#endif
8324}
8325
8326/*
8327 * "matcharg()" function
8328 */
8329 static void
8330f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8331{
8332 if (rettv_list_alloc(rettv) == OK)
8333 {
8334#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008335 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008336 matchitem_T *m;
8337
8338 if (id >= 1 && id <= 3)
8339 {
8340 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8341 {
8342 list_append_string(rettv->vval.v_list,
8343 syn_id2name(m->hlg_id), -1);
8344 list_append_string(rettv->vval.v_list, m->pattern, -1);
8345 }
8346 else
8347 {
8348 list_append_string(rettv->vval.v_list, NULL, -1);
8349 list_append_string(rettv->vval.v_list, NULL, -1);
8350 }
8351 }
8352#endif
8353 }
8354}
8355
8356/*
8357 * "matchdelete()" function
8358 */
8359 static void
8360f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8361{
8362#ifdef FEAT_SEARCH_EXTRA
8363 rettv->vval.v_number = match_delete(curwin,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008364 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008365#endif
8366}
8367
8368/*
8369 * "matchend()" function
8370 */
8371 static void
8372f_matchend(typval_T *argvars, typval_T *rettv)
8373{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008374 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008375}
8376
8377/*
8378 * "matchlist()" function
8379 */
8380 static void
8381f_matchlist(typval_T *argvars, typval_T *rettv)
8382{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008383 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384}
8385
8386/*
8387 * "matchstr()" function
8388 */
8389 static void
8390f_matchstr(typval_T *argvars, typval_T *rettv)
8391{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008392 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008393}
8394
8395/*
8396 * "matchstrpos()" function
8397 */
8398 static void
8399f_matchstrpos(typval_T *argvars, typval_T *rettv)
8400{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008401 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402}
8403
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 static void
8405max_min(typval_T *argvars, typval_T *rettv, int domax)
8406{
8407 varnumber_T n = 0;
8408 varnumber_T i;
8409 int error = FALSE;
8410
8411 if (argvars[0].v_type == VAR_LIST)
8412 {
8413 list_T *l;
8414 listitem_T *li;
8415
8416 l = argvars[0].vval.v_list;
8417 if (l != NULL)
8418 {
8419 li = l->lv_first;
8420 if (li != NULL)
8421 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008422 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008423 for (;;)
8424 {
8425 li = li->li_next;
8426 if (li == NULL)
8427 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008428 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008429 if (domax ? i > n : i < n)
8430 n = i;
8431 }
8432 }
8433 }
8434 }
8435 else if (argvars[0].v_type == VAR_DICT)
8436 {
8437 dict_T *d;
8438 int first = TRUE;
8439 hashitem_T *hi;
8440 int todo;
8441
8442 d = argvars[0].vval.v_dict;
8443 if (d != NULL)
8444 {
8445 todo = (int)d->dv_hashtab.ht_used;
8446 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8447 {
8448 if (!HASHITEM_EMPTY(hi))
8449 {
8450 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008451 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008452 if (first)
8453 {
8454 n = i;
8455 first = FALSE;
8456 }
8457 else if (domax ? i > n : i < n)
8458 n = i;
8459 }
8460 }
8461 }
8462 }
8463 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008464 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008465 rettv->vval.v_number = error ? 0 : n;
8466}
8467
8468/*
8469 * "max()" function
8470 */
8471 static void
8472f_max(typval_T *argvars, typval_T *rettv)
8473{
8474 max_min(argvars, rettv, TRUE);
8475}
8476
8477/*
8478 * "min()" function
8479 */
8480 static void
8481f_min(typval_T *argvars, typval_T *rettv)
8482{
8483 max_min(argvars, rettv, FALSE);
8484}
8485
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008486/*
8487 * Create the directory in which "dir" is located, and higher levels when
8488 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008489 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490 */
8491 static int
8492mkdir_recurse(char_u *dir, int prot)
8493{
8494 char_u *p;
8495 char_u *updir;
8496 int r = FAIL;
8497
8498 /* Get end of directory name in "dir".
8499 * We're done when it's "/" or "c:/". */
8500 p = gettail_sep(dir);
8501 if (p <= get_past_head(dir))
8502 return OK;
8503
8504 /* If the directory exists we're done. Otherwise: create it.*/
8505 updir = vim_strnsave(dir, (int)(p - dir));
8506 if (updir == NULL)
8507 return FAIL;
8508 if (mch_isdir(updir))
8509 r = OK;
8510 else if (mkdir_recurse(updir, prot) == OK)
8511 r = vim_mkdir_emsg(updir, prot);
8512 vim_free(updir);
8513 return r;
8514}
8515
8516#ifdef vim_mkdir
8517/*
8518 * "mkdir()" function
8519 */
8520 static void
8521f_mkdir(typval_T *argvars, typval_T *rettv)
8522{
8523 char_u *dir;
8524 char_u buf[NUMBUFLEN];
8525 int prot = 0755;
8526
8527 rettv->vval.v_number = FAIL;
8528 if (check_restricted() || check_secure())
8529 return;
8530
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008531 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008532 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008533 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008534
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008535 if (*gettail(dir) == NUL)
8536 /* remove trailing slashes */
8537 *gettail_sep(dir) = NUL;
8538
8539 if (argvars[1].v_type != VAR_UNKNOWN)
8540 {
8541 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008542 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008543 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008544 if (prot == -1)
8545 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008546 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008547 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008548 {
8549 if (mch_isdir(dir))
8550 {
8551 /* With the "p" flag it's OK if the dir already exists. */
8552 rettv->vval.v_number = OK;
8553 return;
8554 }
8555 mkdir_recurse(dir, prot);
8556 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008557 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008558 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008559}
8560#endif
8561
8562/*
8563 * "mode()" function
8564 */
8565 static void
8566f_mode(typval_T *argvars, typval_T *rettv)
8567{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008568 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008569
Bram Moolenaar612cc382018-07-29 15:34:26 +02008570 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008571
8572 if (time_for_testing == 93784)
8573 {
8574 /* Testing the two-character code. */
8575 buf[0] = 'x';
8576 buf[1] = '!';
8577 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008578#ifdef FEAT_TERMINAL
8579 else if (term_use_loop())
8580 buf[0] = 't';
8581#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008582 else if (VIsual_active)
8583 {
8584 if (VIsual_select)
8585 buf[0] = VIsual_mode + 's' - 'v';
8586 else
8587 buf[0] = VIsual_mode;
8588 }
8589 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8590 || State == CONFIRM)
8591 {
8592 buf[0] = 'r';
8593 if (State == ASKMORE)
8594 buf[1] = 'm';
8595 else if (State == CONFIRM)
8596 buf[1] = '?';
8597 }
8598 else if (State == EXTERNCMD)
8599 buf[0] = '!';
8600 else if (State & INSERT)
8601 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008602 if (State & VREPLACE_FLAG)
8603 {
8604 buf[0] = 'R';
8605 buf[1] = 'v';
8606 }
8607 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008608 {
8609 if (State & REPLACE_FLAG)
8610 buf[0] = 'R';
8611 else
8612 buf[0] = 'i';
8613#ifdef FEAT_INS_EXPAND
8614 if (ins_compl_active())
8615 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008616 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008617 buf[1] = 'x';
8618#endif
8619 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008620 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008621 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008622 {
8623 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008624 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008625 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008626 else if (exmode_active == EXMODE_NORMAL)
8627 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008628 }
8629 else
8630 {
8631 buf[0] = 'n';
8632 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008633 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008634 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008635 // to be able to detect force-linewise/blockwise/characterwise operations
8636 buf[2] = motion_force;
8637 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008638 else if (restart_edit == 'I' || restart_edit == 'R'
8639 || restart_edit == 'V')
8640 {
8641 buf[1] = 'i';
8642 buf[2] = restart_edit;
8643 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644 }
8645
8646 /* Clear out the minor mode when the argument is not a non-zero number or
8647 * non-empty string. */
8648 if (!non_zero_arg(&argvars[0]))
8649 buf[1] = NUL;
8650
8651 rettv->vval.v_string = vim_strsave(buf);
8652 rettv->v_type = VAR_STRING;
8653}
8654
8655#if defined(FEAT_MZSCHEME) || defined(PROTO)
8656/*
8657 * "mzeval()" function
8658 */
8659 static void
8660f_mzeval(typval_T *argvars, typval_T *rettv)
8661{
8662 char_u *str;
8663 char_u buf[NUMBUFLEN];
8664
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008665 if (check_restricted() || check_secure())
8666 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008667 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008668 do_mzeval(str, rettv);
8669}
8670
8671 void
8672mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8673{
8674 typval_T argvars[3];
8675
8676 argvars[0].v_type = VAR_STRING;
8677 argvars[0].vval.v_string = name;
8678 copy_tv(args, &argvars[1]);
8679 argvars[2].v_type = VAR_UNKNOWN;
8680 f_call(argvars, rettv);
8681 clear_tv(&argvars[1]);
8682}
8683#endif
8684
8685/*
8686 * "nextnonblank()" function
8687 */
8688 static void
8689f_nextnonblank(typval_T *argvars, typval_T *rettv)
8690{
8691 linenr_T lnum;
8692
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008693 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008694 {
8695 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8696 {
8697 lnum = 0;
8698 break;
8699 }
8700 if (*skipwhite(ml_get(lnum)) != NUL)
8701 break;
8702 }
8703 rettv->vval.v_number = lnum;
8704}
8705
8706/*
8707 * "nr2char()" function
8708 */
8709 static void
8710f_nr2char(typval_T *argvars, typval_T *rettv)
8711{
8712 char_u buf[NUMBUFLEN];
8713
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008714 if (has_mbyte)
8715 {
8716 int utf8 = 0;
8717
8718 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008719 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008721 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008722 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008723 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724 }
8725 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008727 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008728 buf[1] = NUL;
8729 }
8730 rettv->v_type = VAR_STRING;
8731 rettv->vval.v_string = vim_strsave(buf);
8732}
8733
8734/*
8735 * "or(expr, expr)" function
8736 */
8737 static void
8738f_or(typval_T *argvars, typval_T *rettv)
8739{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008740 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8741 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008742}
8743
8744/*
8745 * "pathshorten()" function
8746 */
8747 static void
8748f_pathshorten(typval_T *argvars, typval_T *rettv)
8749{
8750 char_u *p;
8751
8752 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008753 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008754 if (p == NULL)
8755 rettv->vval.v_string = NULL;
8756 else
8757 {
8758 p = vim_strsave(p);
8759 rettv->vval.v_string = p;
8760 if (p != NULL)
8761 shorten_dir(p);
8762 }
8763}
8764
8765#ifdef FEAT_PERL
8766/*
8767 * "perleval()" function
8768 */
8769 static void
8770f_perleval(typval_T *argvars, typval_T *rettv)
8771{
8772 char_u *str;
8773 char_u buf[NUMBUFLEN];
8774
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008775 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008776 do_perleval(str, rettv);
8777}
8778#endif
8779
8780#ifdef FEAT_FLOAT
8781/*
8782 * "pow()" function
8783 */
8784 static void
8785f_pow(typval_T *argvars, typval_T *rettv)
8786{
8787 float_T fx = 0.0, fy = 0.0;
8788
8789 rettv->v_type = VAR_FLOAT;
8790 if (get_float_arg(argvars, &fx) == OK
8791 && get_float_arg(&argvars[1], &fy) == OK)
8792 rettv->vval.v_float = pow(fx, fy);
8793 else
8794 rettv->vval.v_float = 0.0;
8795}
8796#endif
8797
8798/*
8799 * "prevnonblank()" function
8800 */
8801 static void
8802f_prevnonblank(typval_T *argvars, typval_T *rettv)
8803{
8804 linenr_T lnum;
8805
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008806 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008807 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8808 lnum = 0;
8809 else
8810 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8811 --lnum;
8812 rettv->vval.v_number = lnum;
8813}
8814
8815/* This dummy va_list is here because:
8816 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8817 * - locally in the function results in a "used before set" warning
8818 * - using va_start() to initialize it gives "function with fixed args" error */
8819static va_list ap;
8820
8821/*
8822 * "printf()" function
8823 */
8824 static void
8825f_printf(typval_T *argvars, typval_T *rettv)
8826{
8827 char_u buf[NUMBUFLEN];
8828 int len;
8829 char_u *s;
8830 int saved_did_emsg = did_emsg;
8831 char *fmt;
8832
8833 rettv->v_type = VAR_STRING;
8834 rettv->vval.v_string = NULL;
8835
8836 /* Get the required length, allocate the buffer and do it for real. */
8837 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008838 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008839 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008840 if (!did_emsg)
8841 {
8842 s = alloc(len + 1);
8843 if (s != NULL)
8844 {
8845 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008846 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8847 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008848 }
8849 }
8850 did_emsg |= saved_did_emsg;
8851}
8852
Bram Moolenaarf2732452018-06-03 14:47:35 +02008853#ifdef FEAT_JOB_CHANNEL
8854/*
8855 * "prompt_setcallback({buffer}, {callback})" function
8856 */
8857 static void
8858f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8859{
8860 buf_T *buf;
8861 char_u *callback;
8862 partial_T *partial;
8863
8864 if (check_secure())
8865 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008866 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008867 if (buf == NULL)
8868 return;
8869
8870 callback = get_callback(&argvars[1], &partial);
8871 if (callback == NULL)
8872 return;
8873
8874 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8875 if (partial == NULL)
8876 buf->b_prompt_callback = vim_strsave(callback);
8877 else
8878 /* pointer into the partial */
8879 buf->b_prompt_callback = callback;
8880 buf->b_prompt_partial = partial;
8881}
8882
8883/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008884 * "prompt_setinterrupt({buffer}, {callback})" function
8885 */
8886 static void
8887f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8888{
8889 buf_T *buf;
8890 char_u *callback;
8891 partial_T *partial;
8892
8893 if (check_secure())
8894 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008895 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008896 if (buf == NULL)
8897 return;
8898
8899 callback = get_callback(&argvars[1], &partial);
8900 if (callback == NULL)
8901 return;
8902
8903 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8904 if (partial == NULL)
8905 buf->b_prompt_interrupt = vim_strsave(callback);
8906 else
8907 /* pointer into the partial */
8908 buf->b_prompt_interrupt = callback;
8909 buf->b_prompt_int_partial = partial;
8910}
8911
8912/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008913 * "prompt_setprompt({buffer}, {text})" function
8914 */
8915 static void
8916f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8917{
8918 buf_T *buf;
8919 char_u *text;
8920
8921 if (check_secure())
8922 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008923 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008924 if (buf == NULL)
8925 return;
8926
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008927 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008928 vim_free(buf->b_prompt_text);
8929 buf->b_prompt_text = vim_strsave(text);
8930}
8931#endif
8932
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008933/*
8934 * "pumvisible()" function
8935 */
8936 static void
8937f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8938{
8939#ifdef FEAT_INS_EXPAND
8940 if (pum_visible())
8941 rettv->vval.v_number = 1;
8942#endif
8943}
8944
8945#ifdef FEAT_PYTHON3
8946/*
8947 * "py3eval()" function
8948 */
8949 static void
8950f_py3eval(typval_T *argvars, typval_T *rettv)
8951{
8952 char_u *str;
8953 char_u buf[NUMBUFLEN];
8954
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008955 if (check_restricted() || check_secure())
8956 return;
8957
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008958 if (p_pyx == 0)
8959 p_pyx = 3;
8960
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008961 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008962 do_py3eval(str, rettv);
8963}
8964#endif
8965
8966#ifdef FEAT_PYTHON
8967/*
8968 * "pyeval()" function
8969 */
8970 static void
8971f_pyeval(typval_T *argvars, typval_T *rettv)
8972{
8973 char_u *str;
8974 char_u buf[NUMBUFLEN];
8975
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008976 if (check_restricted() || check_secure())
8977 return;
8978
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008979 if (p_pyx == 0)
8980 p_pyx = 2;
8981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008982 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008983 do_pyeval(str, rettv);
8984}
8985#endif
8986
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008987#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8988/*
8989 * "pyxeval()" function
8990 */
8991 static void
8992f_pyxeval(typval_T *argvars, typval_T *rettv)
8993{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008994 if (check_restricted() || check_secure())
8995 return;
8996
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008997# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8998 init_pyxversion();
8999 if (p_pyx == 2)
9000 f_pyeval(argvars, rettv);
9001 else
9002 f_py3eval(argvars, rettv);
9003# elif defined(FEAT_PYTHON)
9004 f_pyeval(argvars, rettv);
9005# elif defined(FEAT_PYTHON3)
9006 f_py3eval(argvars, rettv);
9007# endif
9008}
9009#endif
9010
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009011/*
9012 * "range()" function
9013 */
9014 static void
9015f_range(typval_T *argvars, typval_T *rettv)
9016{
9017 varnumber_T start;
9018 varnumber_T end;
9019 varnumber_T stride = 1;
9020 varnumber_T i;
9021 int error = FALSE;
9022
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009023 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009024 if (argvars[1].v_type == VAR_UNKNOWN)
9025 {
9026 end = start - 1;
9027 start = 0;
9028 }
9029 else
9030 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009031 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009032 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009033 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009034 }
9035
9036 if (error)
9037 return; /* type error; errmsg already given */
9038 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009039 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009040 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009041 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009042 else
9043 {
9044 if (rettv_list_alloc(rettv) == OK)
9045 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9046 if (list_append_number(rettv->vval.v_list,
9047 (varnumber_T)i) == FAIL)
9048 break;
9049 }
9050}
9051
9052/*
9053 * "readfile()" function
9054 */
9055 static void
9056f_readfile(typval_T *argvars, typval_T *rettv)
9057{
9058 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009059 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009060 int failed = FALSE;
9061 char_u *fname;
9062 FILE *fd;
9063 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9064 int io_size = sizeof(buf);
9065 int readlen; /* size of last fread() */
9066 char_u *prev = NULL; /* previously read bytes, if any */
9067 long prevlen = 0; /* length of data in prev */
9068 long prevsize = 0; /* size of prev buffer */
9069 long maxline = MAXLNUM;
9070 long cnt = 0;
9071 char_u *p; /* position in buf */
9072 char_u *start; /* start of current line */
9073
9074 if (argvars[1].v_type != VAR_UNKNOWN)
9075 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009076 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009077 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009078 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9079 blob = TRUE;
9080
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009081 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009082 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009083 }
9084
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009085 if (blob)
9086 {
9087 if (rettv_blob_alloc(rettv) == FAIL)
9088 return;
9089 }
9090 else
9091 {
9092 if (rettv_list_alloc(rettv) == FAIL)
9093 return;
9094 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009095
9096 /* Always open the file in binary mode, library functions have a mind of
9097 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009098 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009099 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9100 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009101 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009102 return;
9103 }
9104
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009105 if (blob)
9106 {
9107 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9108 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009109 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009110 blob_free(rettv->vval.v_blob);
9111 }
9112 fclose(fd);
9113 return;
9114 }
9115
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009116 while (cnt < maxline || maxline < 0)
9117 {
9118 readlen = (int)fread(buf, 1, io_size, fd);
9119
9120 /* This for loop processes what was read, but is also entered at end
9121 * of file so that either:
9122 * - an incomplete line gets written
9123 * - a "binary" file gets an empty line at the end if it ends in a
9124 * newline. */
9125 for (p = buf, start = buf;
9126 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9127 ++p)
9128 {
9129 if (*p == '\n' || readlen <= 0)
9130 {
9131 listitem_T *li;
9132 char_u *s = NULL;
9133 long_u len = p - start;
9134
9135 /* Finished a line. Remove CRs before NL. */
9136 if (readlen > 0 && !binary)
9137 {
9138 while (len > 0 && start[len - 1] == '\r')
9139 --len;
9140 /* removal may cross back to the "prev" string */
9141 if (len == 0)
9142 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9143 --prevlen;
9144 }
9145 if (prevlen == 0)
9146 s = vim_strnsave(start, (int)len);
9147 else
9148 {
9149 /* Change "prev" buffer to be the right size. This way
9150 * the bytes are only copied once, and very long lines are
9151 * allocated only once. */
9152 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9153 {
9154 mch_memmove(s + prevlen, start, len);
9155 s[prevlen + len] = NUL;
9156 prev = NULL; /* the list will own the string */
9157 prevlen = prevsize = 0;
9158 }
9159 }
9160 if (s == NULL)
9161 {
9162 do_outofmem_msg((long_u) prevlen + len + 1);
9163 failed = TRUE;
9164 break;
9165 }
9166
9167 if ((li = listitem_alloc()) == NULL)
9168 {
9169 vim_free(s);
9170 failed = TRUE;
9171 break;
9172 }
9173 li->li_tv.v_type = VAR_STRING;
9174 li->li_tv.v_lock = 0;
9175 li->li_tv.vval.v_string = s;
9176 list_append(rettv->vval.v_list, li);
9177
9178 start = p + 1; /* step over newline */
9179 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9180 break;
9181 }
9182 else if (*p == NUL)
9183 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009184 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9185 * when finding the BF and check the previous two bytes. */
9186 else if (*p == 0xbf && enc_utf8 && !binary)
9187 {
9188 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9189 * + 1, these may be in the "prev" string. */
9190 char_u back1 = p >= buf + 1 ? p[-1]
9191 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9192 char_u back2 = p >= buf + 2 ? p[-2]
9193 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9194 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9195
9196 if (back2 == 0xef && back1 == 0xbb)
9197 {
9198 char_u *dest = p - 2;
9199
9200 /* Usually a BOM is at the beginning of a file, and so at
9201 * the beginning of a line; then we can just step over it.
9202 */
9203 if (start == dest)
9204 start = p + 1;
9205 else
9206 {
9207 /* have to shuffle buf to close gap */
9208 int adjust_prevlen = 0;
9209
9210 if (dest < buf)
9211 {
9212 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9213 dest = buf;
9214 }
9215 if (readlen > p - buf + 1)
9216 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9217 readlen -= 3 - adjust_prevlen;
9218 prevlen -= adjust_prevlen;
9219 p = dest - 1;
9220 }
9221 }
9222 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009223 } /* for */
9224
9225 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9226 break;
9227 if (start < p)
9228 {
9229 /* There's part of a line in buf, store it in "prev". */
9230 if (p - start + prevlen >= prevsize)
9231 {
9232 /* need bigger "prev" buffer */
9233 char_u *newprev;
9234
9235 /* A common use case is ordinary text files and "prev" gets a
9236 * fragment of a line, so the first allocation is made
9237 * small, to avoid repeatedly 'allocing' large and
9238 * 'reallocing' small. */
9239 if (prevsize == 0)
9240 prevsize = (long)(p - start);
9241 else
9242 {
9243 long grow50pc = (prevsize * 3) / 2;
9244 long growmin = (long)((p - start) * 2 + prevlen);
9245 prevsize = grow50pc > growmin ? grow50pc : growmin;
9246 }
9247 newprev = prev == NULL ? alloc(prevsize)
9248 : vim_realloc(prev, prevsize);
9249 if (newprev == NULL)
9250 {
9251 do_outofmem_msg((long_u)prevsize);
9252 failed = TRUE;
9253 break;
9254 }
9255 prev = newprev;
9256 }
9257 /* Add the line part to end of "prev". */
9258 mch_memmove(prev + prevlen, start, p - start);
9259 prevlen += (long)(p - start);
9260 }
9261 } /* while */
9262
9263 /*
9264 * For a negative line count use only the lines at the end of the file,
9265 * free the rest.
9266 */
9267 if (!failed && maxline < 0)
9268 while (cnt > -maxline)
9269 {
9270 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9271 --cnt;
9272 }
9273
9274 if (failed)
9275 {
9276 list_free(rettv->vval.v_list);
9277 /* readfile doc says an empty list is returned on error */
9278 rettv->vval.v_list = list_alloc();
9279 }
9280
9281 vim_free(prev);
9282 fclose(fd);
9283}
9284
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009285 static void
9286return_register(int regname, typval_T *rettv)
9287{
9288 char_u buf[2] = {0, 0};
9289
9290 buf[0] = (char_u)regname;
9291 rettv->v_type = VAR_STRING;
9292 rettv->vval.v_string = vim_strsave(buf);
9293}
9294
9295/*
9296 * "reg_executing()" function
9297 */
9298 static void
9299f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9300{
9301 return_register(reg_executing, rettv);
9302}
9303
9304/*
9305 * "reg_recording()" function
9306 */
9307 static void
9308f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9309{
9310 return_register(reg_recording, rettv);
9311}
9312
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009313#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009314/*
9315 * Convert a List to proftime_T.
9316 * Return FAIL when there is something wrong.
9317 */
9318 static int
9319list2proftime(typval_T *arg, proftime_T *tm)
9320{
9321 long n1, n2;
9322 int error = FALSE;
9323
9324 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9325 || arg->vval.v_list->lv_len != 2)
9326 return FAIL;
9327 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9328 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009329# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009330 tm->HighPart = n1;
9331 tm->LowPart = n2;
9332# else
9333 tm->tv_sec = n1;
9334 tm->tv_usec = n2;
9335# endif
9336 return error ? FAIL : OK;
9337}
9338#endif /* FEAT_RELTIME */
9339
9340/*
9341 * "reltime()" function
9342 */
9343 static void
9344f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9345{
9346#ifdef FEAT_RELTIME
9347 proftime_T res;
9348 proftime_T start;
9349
9350 if (argvars[0].v_type == VAR_UNKNOWN)
9351 {
9352 /* No arguments: get current time. */
9353 profile_start(&res);
9354 }
9355 else if (argvars[1].v_type == VAR_UNKNOWN)
9356 {
9357 if (list2proftime(&argvars[0], &res) == FAIL)
9358 return;
9359 profile_end(&res);
9360 }
9361 else
9362 {
9363 /* Two arguments: compute the difference. */
9364 if (list2proftime(&argvars[0], &start) == FAIL
9365 || list2proftime(&argvars[1], &res) == FAIL)
9366 return;
9367 profile_sub(&res, &start);
9368 }
9369
9370 if (rettv_list_alloc(rettv) == OK)
9371 {
9372 long n1, n2;
9373
Bram Moolenaar4f974752019-02-17 17:44:42 +01009374# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009375 n1 = res.HighPart;
9376 n2 = res.LowPart;
9377# else
9378 n1 = res.tv_sec;
9379 n2 = res.tv_usec;
9380# endif
9381 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9382 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9383 }
9384#endif
9385}
9386
9387#ifdef FEAT_FLOAT
9388/*
9389 * "reltimefloat()" function
9390 */
9391 static void
9392f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9393{
9394# ifdef FEAT_RELTIME
9395 proftime_T tm;
9396# endif
9397
9398 rettv->v_type = VAR_FLOAT;
9399 rettv->vval.v_float = 0;
9400# ifdef FEAT_RELTIME
9401 if (list2proftime(&argvars[0], &tm) == OK)
9402 rettv->vval.v_float = profile_float(&tm);
9403# endif
9404}
9405#endif
9406
9407/*
9408 * "reltimestr()" function
9409 */
9410 static void
9411f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9412{
9413#ifdef FEAT_RELTIME
9414 proftime_T tm;
9415#endif
9416
9417 rettv->v_type = VAR_STRING;
9418 rettv->vval.v_string = NULL;
9419#ifdef FEAT_RELTIME
9420 if (list2proftime(&argvars[0], &tm) == OK)
9421 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9422#endif
9423}
9424
9425#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009426 static void
9427make_connection(void)
9428{
9429 if (X_DISPLAY == NULL
9430# ifdef FEAT_GUI
9431 && !gui.in_use
9432# endif
9433 )
9434 {
9435 x_force_connect = TRUE;
9436 setup_term_clip();
9437 x_force_connect = FALSE;
9438 }
9439}
9440
9441 static int
9442check_connection(void)
9443{
9444 make_connection();
9445 if (X_DISPLAY == NULL)
9446 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009447 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009448 return FAIL;
9449 }
9450 return OK;
9451}
9452#endif
9453
9454#ifdef FEAT_CLIENTSERVER
9455 static void
9456remote_common(typval_T *argvars, typval_T *rettv, int expr)
9457{
9458 char_u *server_name;
9459 char_u *keys;
9460 char_u *r = NULL;
9461 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009462 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009463# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009464 HWND w;
9465# else
9466 Window w;
9467# endif
9468
9469 if (check_restricted() || check_secure())
9470 return;
9471
9472# ifdef FEAT_X11
9473 if (check_connection() == FAIL)
9474 return;
9475# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009476 if (argvars[2].v_type != VAR_UNKNOWN
9477 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009478 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009479
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009480 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009481 if (server_name == NULL)
9482 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009483 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009484# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009485 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009486# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009487 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9488 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009489# endif
9490 {
9491 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009492 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009493 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009494 vim_free(r);
9495 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009496 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009497 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009498 return;
9499 }
9500
9501 rettv->vval.v_string = r;
9502
9503 if (argvars[2].v_type != VAR_UNKNOWN)
9504 {
9505 dictitem_T v;
9506 char_u str[30];
9507 char_u *idvar;
9508
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009509 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009510 if (idvar != NULL && *idvar != NUL)
9511 {
9512 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9513 v.di_tv.v_type = VAR_STRING;
9514 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009515 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009516 vim_free(v.di_tv.vval.v_string);
9517 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009518 }
9519}
9520#endif
9521
9522/*
9523 * "remote_expr()" function
9524 */
9525 static void
9526f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9527{
9528 rettv->v_type = VAR_STRING;
9529 rettv->vval.v_string = NULL;
9530#ifdef FEAT_CLIENTSERVER
9531 remote_common(argvars, rettv, TRUE);
9532#endif
9533}
9534
9535/*
9536 * "remote_foreground()" function
9537 */
9538 static void
9539f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9540{
9541#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009542# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009543 /* On Win32 it's done in this application. */
9544 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009545 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009546
9547 if (server_name != NULL)
9548 serverForeground(server_name);
9549 }
9550# else
9551 /* Send a foreground() expression to the server. */
9552 argvars[1].v_type = VAR_STRING;
9553 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9554 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009555 rettv->v_type = VAR_STRING;
9556 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009557 remote_common(argvars, rettv, TRUE);
9558 vim_free(argvars[1].vval.v_string);
9559# endif
9560#endif
9561}
9562
9563 static void
9564f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9565{
9566#ifdef FEAT_CLIENTSERVER
9567 dictitem_T v;
9568 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009569# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009570 long_u n = 0;
9571# endif
9572 char_u *serverid;
9573
9574 if (check_restricted() || check_secure())
9575 {
9576 rettv->vval.v_number = -1;
9577 return;
9578 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009579 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009580 if (serverid == NULL)
9581 {
9582 rettv->vval.v_number = -1;
9583 return; /* type error; errmsg already given */
9584 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009585# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009586 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9587 if (n == 0)
9588 rettv->vval.v_number = -1;
9589 else
9590 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009591 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009592 rettv->vval.v_number = (s != NULL);
9593 }
9594# else
9595 if (check_connection() == FAIL)
9596 return;
9597
9598 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9599 serverStrToWin(serverid), &s);
9600# endif
9601
9602 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9603 {
9604 char_u *retvar;
9605
9606 v.di_tv.v_type = VAR_STRING;
9607 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009608 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009609 if (retvar != NULL)
9610 set_var(retvar, &v.di_tv, FALSE);
9611 vim_free(v.di_tv.vval.v_string);
9612 }
9613#else
9614 rettv->vval.v_number = -1;
9615#endif
9616}
9617
9618 static void
9619f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9620{
9621 char_u *r = NULL;
9622
9623#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009624 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009625
9626 if (serverid != NULL && !check_restricted() && !check_secure())
9627 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009628 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009629# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009630 /* The server's HWND is encoded in the 'id' parameter */
9631 long_u n = 0;
9632# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009633
9634 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009635 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009636
Bram Moolenaar4f974752019-02-17 17:44:42 +01009637# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009638 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9639 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009640 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009641 if (r == NULL)
9642# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009643 if (check_connection() == FAIL
9644 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9645 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009646# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009647 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009648 }
9649#endif
9650 rettv->v_type = VAR_STRING;
9651 rettv->vval.v_string = r;
9652}
9653
9654/*
9655 * "remote_send()" function
9656 */
9657 static void
9658f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9659{
9660 rettv->v_type = VAR_STRING;
9661 rettv->vval.v_string = NULL;
9662#ifdef FEAT_CLIENTSERVER
9663 remote_common(argvars, rettv, FALSE);
9664#endif
9665}
9666
9667/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009668 * "remote_startserver()" function
9669 */
9670 static void
9671f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9672{
9673#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009674 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009675
9676 if (server == NULL)
9677 return; /* type error; errmsg already given */
9678 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009679 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009680 else
9681 {
9682# ifdef FEAT_X11
9683 if (check_connection() == OK)
9684 serverRegisterName(X_DISPLAY, server);
9685# else
9686 serverSetName(server);
9687# endif
9688 }
9689#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009690 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009691#endif
9692}
9693
9694/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009695 * "remove()" function
9696 */
9697 static void
9698f_remove(typval_T *argvars, typval_T *rettv)
9699{
9700 list_T *l;
9701 listitem_T *item, *item2;
9702 listitem_T *li;
9703 long idx;
9704 long end;
9705 char_u *key;
9706 dict_T *d;
9707 dictitem_T *di;
9708 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009709 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009710
9711 if (argvars[0].v_type == VAR_DICT)
9712 {
9713 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009714 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009715 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009716 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009718 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009719 if (key != NULL)
9720 {
9721 di = dict_find(d, key, -1);
9722 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009723 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009724 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9725 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9726 {
9727 *rettv = di->di_tv;
9728 init_tv(&di->di_tv);
9729 dictitem_remove(d, di);
9730 }
9731 }
9732 }
9733 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009734 else if (argvars[0].v_type == VAR_BLOB)
9735 {
9736 idx = (long)tv_get_number_chk(&argvars[1], &error);
9737 if (!error)
9738 {
9739 blob_T *b = argvars[0].vval.v_blob;
9740 int len = blob_len(b);
9741 char_u *p;
9742
9743 if (idx < 0)
9744 // count from the end
9745 idx = len + idx;
9746 if (idx < 0 || idx >= len)
9747 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009748 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009749 return;
9750 }
9751 if (argvars[2].v_type == VAR_UNKNOWN)
9752 {
9753 // Remove one item, return its value.
9754 p = (char_u *)b->bv_ga.ga_data;
9755 rettv->vval.v_number = (varnumber_T) *(p + idx);
9756 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9757 --b->bv_ga.ga_len;
9758 }
9759 else
9760 {
9761 blob_T *blob;
9762
9763 // Remove range of items, return list with values.
9764 end = (long)tv_get_number_chk(&argvars[2], &error);
9765 if (error)
9766 return;
9767 if (end < 0)
9768 // count from the end
9769 end = len + end;
9770 if (end >= len || idx > end)
9771 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009772 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009773 return;
9774 }
9775 blob = blob_alloc();
9776 if (blob == NULL)
9777 return;
9778 blob->bv_ga.ga_len = end - idx + 1;
9779 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9780 {
9781 vim_free(blob);
9782 return;
9783 }
9784 p = (char_u *)b->bv_ga.ga_data;
9785 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9786 (size_t)(end - idx + 1));
9787 ++blob->bv_refcount;
9788 rettv->v_type = VAR_BLOB;
9789 rettv->vval.v_blob = blob;
9790
9791 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9792 b->bv_ga.ga_len -= end - idx + 1;
9793 }
9794 }
9795 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009796 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009797 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009798 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009799 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009800 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009801 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009802 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009803 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009804 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009805 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009806 else
9807 {
9808 if (argvars[2].v_type == VAR_UNKNOWN)
9809 {
9810 /* Remove one item, return its value. */
9811 vimlist_remove(l, item, item);
9812 *rettv = item->li_tv;
9813 vim_free(item);
9814 }
9815 else
9816 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009817 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009818 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009819 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009820 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009821 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009822 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009823 else
9824 {
9825 int cnt = 0;
9826
9827 for (li = item; li != NULL; li = li->li_next)
9828 {
9829 ++cnt;
9830 if (li == item2)
9831 break;
9832 }
9833 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009834 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009835 else
9836 {
9837 vimlist_remove(l, item, item2);
9838 if (rettv_list_alloc(rettv) == OK)
9839 {
9840 l = rettv->vval.v_list;
9841 l->lv_first = item;
9842 l->lv_last = item2;
9843 item->li_prev = NULL;
9844 item2->li_next = NULL;
9845 l->lv_len = cnt;
9846 }
9847 }
9848 }
9849 }
9850 }
9851 }
9852}
9853
9854/*
9855 * "rename({from}, {to})" function
9856 */
9857 static void
9858f_rename(typval_T *argvars, typval_T *rettv)
9859{
9860 char_u buf[NUMBUFLEN];
9861
9862 if (check_restricted() || check_secure())
9863 rettv->vval.v_number = -1;
9864 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009865 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9866 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009867}
9868
9869/*
9870 * "repeat()" function
9871 */
9872 static void
9873f_repeat(typval_T *argvars, typval_T *rettv)
9874{
9875 char_u *p;
9876 int n;
9877 int slen;
9878 int len;
9879 char_u *r;
9880 int i;
9881
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009882 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009883 if (argvars[0].v_type == VAR_LIST)
9884 {
9885 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9886 while (n-- > 0)
9887 if (list_extend(rettv->vval.v_list,
9888 argvars[0].vval.v_list, NULL) == FAIL)
9889 break;
9890 }
9891 else
9892 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009893 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009894 rettv->v_type = VAR_STRING;
9895 rettv->vval.v_string = NULL;
9896
9897 slen = (int)STRLEN(p);
9898 len = slen * n;
9899 if (len <= 0)
9900 return;
9901
9902 r = alloc(len + 1);
9903 if (r != NULL)
9904 {
9905 for (i = 0; i < n; i++)
9906 mch_memmove(r + i * slen, p, (size_t)slen);
9907 r[len] = NUL;
9908 }
9909
9910 rettv->vval.v_string = r;
9911 }
9912}
9913
9914/*
9915 * "resolve()" function
9916 */
9917 static void
9918f_resolve(typval_T *argvars, typval_T *rettv)
9919{
9920 char_u *p;
9921#ifdef HAVE_READLINK
9922 char_u *buf = NULL;
9923#endif
9924
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009925 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009926#ifdef FEAT_SHORTCUT
9927 {
9928 char_u *v = NULL;
9929
Bram Moolenaardce1e892019-02-10 23:18:53 +01009930 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009931 if (v != NULL)
9932 rettv->vval.v_string = v;
9933 else
9934 rettv->vval.v_string = vim_strsave(p);
9935 }
9936#else
9937# ifdef HAVE_READLINK
9938 {
9939 char_u *cpy;
9940 int len;
9941 char_u *remain = NULL;
9942 char_u *q;
9943 int is_relative_to_current = FALSE;
9944 int has_trailing_pathsep = FALSE;
9945 int limit = 100;
9946
9947 p = vim_strsave(p);
9948
9949 if (p[0] == '.' && (vim_ispathsep(p[1])
9950 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9951 is_relative_to_current = TRUE;
9952
9953 len = STRLEN(p);
9954 if (len > 0 && after_pathsep(p, p + len))
9955 {
9956 has_trailing_pathsep = TRUE;
9957 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9958 }
9959
9960 q = getnextcomp(p);
9961 if (*q != NUL)
9962 {
9963 /* Separate the first path component in "p", and keep the
9964 * remainder (beginning with the path separator). */
9965 remain = vim_strsave(q - 1);
9966 q[-1] = NUL;
9967 }
9968
9969 buf = alloc(MAXPATHL + 1);
9970 if (buf == NULL)
9971 goto fail;
9972
9973 for (;;)
9974 {
9975 for (;;)
9976 {
9977 len = readlink((char *)p, (char *)buf, MAXPATHL);
9978 if (len <= 0)
9979 break;
9980 buf[len] = NUL;
9981
9982 if (limit-- == 0)
9983 {
9984 vim_free(p);
9985 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009986 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009987 rettv->vval.v_string = NULL;
9988 goto fail;
9989 }
9990
9991 /* Ensure that the result will have a trailing path separator
9992 * if the argument has one. */
9993 if (remain == NULL && has_trailing_pathsep)
9994 add_pathsep(buf);
9995
9996 /* Separate the first path component in the link value and
9997 * concatenate the remainders. */
9998 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9999 if (*q != NUL)
10000 {
10001 if (remain == NULL)
10002 remain = vim_strsave(q - 1);
10003 else
10004 {
10005 cpy = concat_str(q - 1, remain);
10006 if (cpy != NULL)
10007 {
10008 vim_free(remain);
10009 remain = cpy;
10010 }
10011 }
10012 q[-1] = NUL;
10013 }
10014
10015 q = gettail(p);
10016 if (q > p && *q == NUL)
10017 {
10018 /* Ignore trailing path separator. */
10019 q[-1] = NUL;
10020 q = gettail(p);
10021 }
10022 if (q > p && !mch_isFullName(buf))
10023 {
10024 /* symlink is relative to directory of argument */
10025 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10026 if (cpy != NULL)
10027 {
10028 STRCPY(cpy, p);
10029 STRCPY(gettail(cpy), buf);
10030 vim_free(p);
10031 p = cpy;
10032 }
10033 }
10034 else
10035 {
10036 vim_free(p);
10037 p = vim_strsave(buf);
10038 }
10039 }
10040
10041 if (remain == NULL)
10042 break;
10043
10044 /* Append the first path component of "remain" to "p". */
10045 q = getnextcomp(remain + 1);
10046 len = q - remain - (*q != NUL);
10047 cpy = vim_strnsave(p, STRLEN(p) + len);
10048 if (cpy != NULL)
10049 {
10050 STRNCAT(cpy, remain, len);
10051 vim_free(p);
10052 p = cpy;
10053 }
10054 /* Shorten "remain". */
10055 if (*q != NUL)
10056 STRMOVE(remain, q - 1);
10057 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010058 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010059 }
10060
10061 /* If the result is a relative path name, make it explicitly relative to
10062 * the current directory if and only if the argument had this form. */
10063 if (!vim_ispathsep(*p))
10064 {
10065 if (is_relative_to_current
10066 && *p != NUL
10067 && !(p[0] == '.'
10068 && (p[1] == NUL
10069 || vim_ispathsep(p[1])
10070 || (p[1] == '.'
10071 && (p[2] == NUL
10072 || vim_ispathsep(p[2]))))))
10073 {
10074 /* Prepend "./". */
10075 cpy = concat_str((char_u *)"./", p);
10076 if (cpy != NULL)
10077 {
10078 vim_free(p);
10079 p = cpy;
10080 }
10081 }
10082 else if (!is_relative_to_current)
10083 {
10084 /* Strip leading "./". */
10085 q = p;
10086 while (q[0] == '.' && vim_ispathsep(q[1]))
10087 q += 2;
10088 if (q > p)
10089 STRMOVE(p, p + 2);
10090 }
10091 }
10092
10093 /* Ensure that the result will have no trailing path separator
10094 * if the argument had none. But keep "/" or "//". */
10095 if (!has_trailing_pathsep)
10096 {
10097 q = p + STRLEN(p);
10098 if (after_pathsep(p, q))
10099 *gettail_sep(p) = NUL;
10100 }
10101
10102 rettv->vval.v_string = p;
10103 }
10104# else
10105 rettv->vval.v_string = vim_strsave(p);
10106# endif
10107#endif
10108
10109 simplify_filename(rettv->vval.v_string);
10110
10111#ifdef HAVE_READLINK
10112fail:
10113 vim_free(buf);
10114#endif
10115 rettv->v_type = VAR_STRING;
10116}
10117
10118/*
10119 * "reverse({list})" function
10120 */
10121 static void
10122f_reverse(typval_T *argvars, typval_T *rettv)
10123{
10124 list_T *l;
10125 listitem_T *li, *ni;
10126
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010127 if (argvars[0].v_type == VAR_BLOB)
10128 {
10129 blob_T *b = argvars[0].vval.v_blob;
10130 int i, len = blob_len(b);
10131
10132 for (i = 0; i < len / 2; i++)
10133 {
10134 int tmp = blob_get(b, i);
10135
10136 blob_set(b, i, blob_get(b, len - i - 1));
10137 blob_set(b, len - i - 1, tmp);
10138 }
10139 rettv_blob_set(rettv, b);
10140 return;
10141 }
10142
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010143 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010144 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010145 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010146 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010147 (char_u *)N_("reverse() argument"), TRUE))
10148 {
10149 li = l->lv_last;
10150 l->lv_first = l->lv_last = NULL;
10151 l->lv_len = 0;
10152 while (li != NULL)
10153 {
10154 ni = li->li_prev;
10155 list_append(l, li);
10156 li = ni;
10157 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010158 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010159 l->lv_idx = l->lv_len - l->lv_idx - 1;
10160 }
10161}
10162
10163#define SP_NOMOVE 0x01 /* don't move cursor */
10164#define SP_REPEAT 0x02 /* repeat to find outer pair */
10165#define SP_RETCOUNT 0x04 /* return matchcount */
10166#define SP_SETPCMARK 0x08 /* set previous context mark */
10167#define SP_START 0x10 /* accept match at start position */
10168#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10169#define SP_END 0x40 /* leave cursor at end of match */
10170#define SP_COLUMN 0x80 /* start at cursor column */
10171
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010172/*
10173 * Get flags for a search function.
10174 * Possibly sets "p_ws".
10175 * Returns BACKWARD, FORWARD or zero (for an error).
10176 */
10177 static int
10178get_search_arg(typval_T *varp, int *flagsp)
10179{
10180 int dir = FORWARD;
10181 char_u *flags;
10182 char_u nbuf[NUMBUFLEN];
10183 int mask;
10184
10185 if (varp->v_type != VAR_UNKNOWN)
10186 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010187 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010188 if (flags == NULL)
10189 return 0; /* type error; errmsg already given */
10190 while (*flags != NUL)
10191 {
10192 switch (*flags)
10193 {
10194 case 'b': dir = BACKWARD; break;
10195 case 'w': p_ws = TRUE; break;
10196 case 'W': p_ws = FALSE; break;
10197 default: mask = 0;
10198 if (flagsp != NULL)
10199 switch (*flags)
10200 {
10201 case 'c': mask = SP_START; break;
10202 case 'e': mask = SP_END; break;
10203 case 'm': mask = SP_RETCOUNT; break;
10204 case 'n': mask = SP_NOMOVE; break;
10205 case 'p': mask = SP_SUBPAT; break;
10206 case 'r': mask = SP_REPEAT; break;
10207 case 's': mask = SP_SETPCMARK; break;
10208 case 'z': mask = SP_COLUMN; break;
10209 }
10210 if (mask == 0)
10211 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010212 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010213 dir = 0;
10214 }
10215 else
10216 *flagsp |= mask;
10217 }
10218 if (dir == 0)
10219 break;
10220 ++flags;
10221 }
10222 }
10223 return dir;
10224}
10225
10226/*
10227 * Shared by search() and searchpos() functions.
10228 */
10229 static int
10230search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10231{
10232 int flags;
10233 char_u *pat;
10234 pos_T pos;
10235 pos_T save_cursor;
10236 int save_p_ws = p_ws;
10237 int dir;
10238 int retval = 0; /* default: FAIL */
10239 long lnum_stop = 0;
10240 proftime_T tm;
10241#ifdef FEAT_RELTIME
10242 long time_limit = 0;
10243#endif
10244 int options = SEARCH_KEEP;
10245 int subpatnum;
10246
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010247 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010248 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10249 if (dir == 0)
10250 goto theend;
10251 flags = *flagsp;
10252 if (flags & SP_START)
10253 options |= SEARCH_START;
10254 if (flags & SP_END)
10255 options |= SEARCH_END;
10256 if (flags & SP_COLUMN)
10257 options |= SEARCH_COL;
10258
10259 /* Optional arguments: line number to stop searching and timeout. */
10260 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10261 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010262 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010263 if (lnum_stop < 0)
10264 goto theend;
10265#ifdef FEAT_RELTIME
10266 if (argvars[3].v_type != VAR_UNKNOWN)
10267 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010268 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010269 if (time_limit < 0)
10270 goto theend;
10271 }
10272#endif
10273 }
10274
10275#ifdef FEAT_RELTIME
10276 /* Set the time limit, if there is one. */
10277 profile_setlimit(time_limit, &tm);
10278#endif
10279
10280 /*
10281 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10282 * Check to make sure only those flags are set.
10283 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10284 * flags cannot be set. Check for that condition also.
10285 */
10286 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10287 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10288 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010289 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010290 goto theend;
10291 }
10292
10293 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010294 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010295 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 if (subpatnum != FAIL)
10297 {
10298 if (flags & SP_SUBPAT)
10299 retval = subpatnum;
10300 else
10301 retval = pos.lnum;
10302 if (flags & SP_SETPCMARK)
10303 setpcmark();
10304 curwin->w_cursor = pos;
10305 if (match_pos != NULL)
10306 {
10307 /* Store the match cursor position */
10308 match_pos->lnum = pos.lnum;
10309 match_pos->col = pos.col + 1;
10310 }
10311 /* "/$" will put the cursor after the end of the line, may need to
10312 * correct that here */
10313 check_cursor();
10314 }
10315
10316 /* If 'n' flag is used: restore cursor position. */
10317 if (flags & SP_NOMOVE)
10318 curwin->w_cursor = save_cursor;
10319 else
10320 curwin->w_set_curswant = TRUE;
10321theend:
10322 p_ws = save_p_ws;
10323
10324 return retval;
10325}
10326
10327#ifdef FEAT_FLOAT
10328
10329/*
10330 * round() is not in C90, use ceil() or floor() instead.
10331 */
10332 float_T
10333vim_round(float_T f)
10334{
10335 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10336}
10337
10338/*
10339 * "round({float})" function
10340 */
10341 static void
10342f_round(typval_T *argvars, typval_T *rettv)
10343{
10344 float_T f = 0.0;
10345
10346 rettv->v_type = VAR_FLOAT;
10347 if (get_float_arg(argvars, &f) == OK)
10348 rettv->vval.v_float = vim_round(f);
10349 else
10350 rettv->vval.v_float = 0.0;
10351}
10352#endif
10353
10354/*
10355 * "screenattr()" function
10356 */
10357 static void
10358f_screenattr(typval_T *argvars, typval_T *rettv)
10359{
10360 int row;
10361 int col;
10362 int c;
10363
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010364 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10365 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010366 if (row < 0 || row >= screen_Rows
10367 || col < 0 || col >= screen_Columns)
10368 c = -1;
10369 else
10370 c = ScreenAttrs[LineOffset[row] + col];
10371 rettv->vval.v_number = c;
10372}
10373
10374/*
10375 * "screenchar()" function
10376 */
10377 static void
10378f_screenchar(typval_T *argvars, typval_T *rettv)
10379{
10380 int row;
10381 int col;
10382 int off;
10383 int c;
10384
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010385 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10386 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010387 if (row < 0 || row >= screen_Rows
10388 || col < 0 || col >= screen_Columns)
10389 c = -1;
10390 else
10391 {
10392 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010393 if (enc_utf8 && ScreenLinesUC[off] != 0)
10394 c = ScreenLinesUC[off];
10395 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010396 c = ScreenLines[off];
10397 }
10398 rettv->vval.v_number = c;
10399}
10400
10401/*
10402 * "screencol()" function
10403 *
10404 * First column is 1 to be consistent with virtcol().
10405 */
10406 static void
10407f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10408{
10409 rettv->vval.v_number = screen_screencol() + 1;
10410}
10411
10412/*
10413 * "screenrow()" function
10414 */
10415 static void
10416f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10417{
10418 rettv->vval.v_number = screen_screenrow() + 1;
10419}
10420
10421/*
10422 * "search()" function
10423 */
10424 static void
10425f_search(typval_T *argvars, typval_T *rettv)
10426{
10427 int flags = 0;
10428
10429 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10430}
10431
10432/*
10433 * "searchdecl()" function
10434 */
10435 static void
10436f_searchdecl(typval_T *argvars, typval_T *rettv)
10437{
10438 int locally = 1;
10439 int thisblock = 0;
10440 int error = FALSE;
10441 char_u *name;
10442
10443 rettv->vval.v_number = 1; /* default: FAIL */
10444
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010445 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010446 if (argvars[1].v_type != VAR_UNKNOWN)
10447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010448 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010449 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010450 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010451 }
10452 if (!error && name != NULL)
10453 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10454 locally, thisblock, SEARCH_KEEP) == FAIL;
10455}
10456
10457/*
10458 * Used by searchpair() and searchpairpos()
10459 */
10460 static int
10461searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10462{
10463 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010464 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010465 int save_p_ws = p_ws;
10466 int dir;
10467 int flags = 0;
10468 char_u nbuf1[NUMBUFLEN];
10469 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010470 int retval = 0; /* default: FAIL */
10471 long lnum_stop = 0;
10472 long time_limit = 0;
10473
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010474 /* Get the three pattern arguments: start, middle, end. Will result in an
10475 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010476 spat = tv_get_string_chk(&argvars[0]);
10477 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10478 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010479 if (spat == NULL || mpat == NULL || epat == NULL)
10480 goto theend; /* type error */
10481
10482 /* Handle the optional fourth argument: flags */
10483 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10484 if (dir == 0)
10485 goto theend;
10486
10487 /* Don't accept SP_END or SP_SUBPAT.
10488 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10489 */
10490 if ((flags & (SP_END | SP_SUBPAT)) != 0
10491 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10492 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010493 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010494 goto theend;
10495 }
10496
10497 /* Using 'r' implies 'W', otherwise it doesn't work. */
10498 if (flags & SP_REPEAT)
10499 p_ws = FALSE;
10500
10501 /* Optional fifth argument: skip expression */
10502 if (argvars[3].v_type == VAR_UNKNOWN
10503 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010504 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010505 else
10506 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010507 skip = &argvars[4];
10508 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10509 && skip->v_type != VAR_STRING)
10510 {
10511 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010512 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010513 goto theend;
10514 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010515 if (argvars[5].v_type != VAR_UNKNOWN)
10516 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010517 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010518 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010519 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010520 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010521 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010522 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010523#ifdef FEAT_RELTIME
10524 if (argvars[6].v_type != VAR_UNKNOWN)
10525 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010526 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010527 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010528 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010529 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010530 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010531 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010532 }
10533#endif
10534 }
10535 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010536
10537 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10538 match_pos, lnum_stop, time_limit);
10539
10540theend:
10541 p_ws = save_p_ws;
10542
10543 return retval;
10544}
10545
10546/*
10547 * "searchpair()" function
10548 */
10549 static void
10550f_searchpair(typval_T *argvars, typval_T *rettv)
10551{
10552 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10553}
10554
10555/*
10556 * "searchpairpos()" function
10557 */
10558 static void
10559f_searchpairpos(typval_T *argvars, typval_T *rettv)
10560{
10561 pos_T match_pos;
10562 int lnum = 0;
10563 int col = 0;
10564
10565 if (rettv_list_alloc(rettv) == FAIL)
10566 return;
10567
10568 if (searchpair_cmn(argvars, &match_pos) > 0)
10569 {
10570 lnum = match_pos.lnum;
10571 col = match_pos.col;
10572 }
10573
10574 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10575 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10576}
10577
10578/*
10579 * Search for a start/middle/end thing.
10580 * Used by searchpair(), see its documentation for the details.
10581 * Returns 0 or -1 for no match,
10582 */
10583 long
10584do_searchpair(
10585 char_u *spat, /* start pattern */
10586 char_u *mpat, /* middle pattern */
10587 char_u *epat, /* end pattern */
10588 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010589 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010590 int flags, /* SP_SETPCMARK and other SP_ values */
10591 pos_T *match_pos,
10592 linenr_T lnum_stop, /* stop at this line if not zero */
10593 long time_limit UNUSED) /* stop after this many msec */
10594{
10595 char_u *save_cpo;
10596 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10597 long retval = 0;
10598 pos_T pos;
10599 pos_T firstpos;
10600 pos_T foundpos;
10601 pos_T save_cursor;
10602 pos_T save_pos;
10603 int n;
10604 int r;
10605 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010606 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010607 int err;
10608 int options = SEARCH_KEEP;
10609 proftime_T tm;
10610
10611 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10612 save_cpo = p_cpo;
10613 p_cpo = empty_option;
10614
10615#ifdef FEAT_RELTIME
10616 /* Set the time limit, if there is one. */
10617 profile_setlimit(time_limit, &tm);
10618#endif
10619
10620 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10621 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010622 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10623 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010624 if (pat2 == NULL || pat3 == NULL)
10625 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010626 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010627 if (*mpat == NUL)
10628 STRCPY(pat3, pat2);
10629 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010630 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010631 spat, epat, mpat);
10632 if (flags & SP_START)
10633 options |= SEARCH_START;
10634
Bram Moolenaar48570482017-10-30 21:48:41 +010010635 if (skip != NULL)
10636 {
10637 /* Empty string means to not use the skip expression. */
10638 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10639 use_skip = skip->vval.v_string != NULL
10640 && *skip->vval.v_string != NUL;
10641 }
10642
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010643 save_cursor = curwin->w_cursor;
10644 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010645 CLEAR_POS(&firstpos);
10646 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010647 pat = pat3;
10648 for (;;)
10649 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010650 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010651 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010652 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010653 /* didn't find it or found the first match again: FAIL */
10654 break;
10655
10656 if (firstpos.lnum == 0)
10657 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010658 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010659 {
10660 /* Found the same position again. Can happen with a pattern that
10661 * has "\zs" at the end and searching backwards. Advance one
10662 * character and try again. */
10663 if (dir == BACKWARD)
10664 decl(&pos);
10665 else
10666 incl(&pos);
10667 }
10668 foundpos = pos;
10669
10670 /* clear the start flag to avoid getting stuck here */
10671 options &= ~SEARCH_START;
10672
10673 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010674 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010675 {
10676 save_pos = curwin->w_cursor;
10677 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010678 err = FALSE;
10679 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010680 curwin->w_cursor = save_pos;
10681 if (err)
10682 {
10683 /* Evaluating {skip} caused an error, break here. */
10684 curwin->w_cursor = save_cursor;
10685 retval = -1;
10686 break;
10687 }
10688 if (r)
10689 continue;
10690 }
10691
10692 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10693 {
10694 /* Found end when searching backwards or start when searching
10695 * forward: nested pair. */
10696 ++nest;
10697 pat = pat2; /* nested, don't search for middle */
10698 }
10699 else
10700 {
10701 /* Found end when searching forward or start when searching
10702 * backward: end of (nested) pair; or found middle in outer pair. */
10703 if (--nest == 1)
10704 pat = pat3; /* outer level, search for middle */
10705 }
10706
10707 if (nest == 0)
10708 {
10709 /* Found the match: return matchcount or line number. */
10710 if (flags & SP_RETCOUNT)
10711 ++retval;
10712 else
10713 retval = pos.lnum;
10714 if (flags & SP_SETPCMARK)
10715 setpcmark();
10716 curwin->w_cursor = pos;
10717 if (!(flags & SP_REPEAT))
10718 break;
10719 nest = 1; /* search for next unmatched */
10720 }
10721 }
10722
10723 if (match_pos != NULL)
10724 {
10725 /* Store the match cursor position */
10726 match_pos->lnum = curwin->w_cursor.lnum;
10727 match_pos->col = curwin->w_cursor.col + 1;
10728 }
10729
10730 /* If 'n' flag is used or search failed: restore cursor position. */
10731 if ((flags & SP_NOMOVE) || retval == 0)
10732 curwin->w_cursor = save_cursor;
10733
10734theend:
10735 vim_free(pat2);
10736 vim_free(pat3);
10737 if (p_cpo == empty_option)
10738 p_cpo = save_cpo;
10739 else
10740 /* Darn, evaluating the {skip} expression changed the value. */
10741 free_string_option(save_cpo);
10742
10743 return retval;
10744}
10745
10746/*
10747 * "searchpos()" function
10748 */
10749 static void
10750f_searchpos(typval_T *argvars, typval_T *rettv)
10751{
10752 pos_T match_pos;
10753 int lnum = 0;
10754 int col = 0;
10755 int n;
10756 int flags = 0;
10757
10758 if (rettv_list_alloc(rettv) == FAIL)
10759 return;
10760
10761 n = search_cmn(argvars, &match_pos, &flags);
10762 if (n > 0)
10763 {
10764 lnum = match_pos.lnum;
10765 col = match_pos.col;
10766 }
10767
10768 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10769 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10770 if (flags & SP_SUBPAT)
10771 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10772}
10773
10774 static void
10775f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10776{
10777#ifdef FEAT_CLIENTSERVER
10778 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010779 char_u *server = tv_get_string_chk(&argvars[0]);
10780 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010781
10782 rettv->vval.v_number = -1;
10783 if (server == NULL || reply == NULL)
10784 return;
10785 if (check_restricted() || check_secure())
10786 return;
10787# ifdef FEAT_X11
10788 if (check_connection() == FAIL)
10789 return;
10790# endif
10791
10792 if (serverSendReply(server, reply) < 0)
10793 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010794 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010795 return;
10796 }
10797 rettv->vval.v_number = 0;
10798#else
10799 rettv->vval.v_number = -1;
10800#endif
10801}
10802
10803 static void
10804f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10805{
10806 char_u *r = NULL;
10807
10808#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010809# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010810 r = serverGetVimNames();
10811# else
10812 make_connection();
10813 if (X_DISPLAY != NULL)
10814 r = serverGetVimNames(X_DISPLAY);
10815# endif
10816#endif
10817 rettv->v_type = VAR_STRING;
10818 rettv->vval.v_string = r;
10819}
10820
10821/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010822 * "setbufline()" function
10823 */
10824 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010825f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010826{
10827 linenr_T lnum;
10828 buf_T *buf;
10829
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010830 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010831 if (buf == NULL)
10832 rettv->vval.v_number = 1; /* FAIL */
10833 else
10834 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010835 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010836 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010837 }
10838}
10839
10840/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010841 * "setbufvar()" function
10842 */
10843 static void
10844f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10845{
10846 buf_T *buf;
10847 char_u *varname, *bufvarname;
10848 typval_T *varp;
10849 char_u nbuf[NUMBUFLEN];
10850
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010851 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010852 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010853 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10854 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010855 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010856 varp = &argvars[2];
10857
10858 if (buf != NULL && varname != NULL && varp != NULL)
10859 {
10860 if (*varname == '&')
10861 {
10862 long numval;
10863 char_u *strval;
10864 int error = FALSE;
10865 aco_save_T aco;
10866
10867 /* set curbuf to be our buf, temporarily */
10868 aucmd_prepbuf(&aco, buf);
10869
10870 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010871 numval = (long)tv_get_number_chk(varp, &error);
10872 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010873 if (!error && strval != NULL)
10874 set_option_value(varname, numval, strval, OPT_LOCAL);
10875
10876 /* reset notion of buffer */
10877 aucmd_restbuf(&aco);
10878 }
10879 else
10880 {
10881 buf_T *save_curbuf = curbuf;
10882
10883 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10884 if (bufvarname != NULL)
10885 {
10886 curbuf = buf;
10887 STRCPY(bufvarname, "b:");
10888 STRCPY(bufvarname + 2, varname);
10889 set_var(bufvarname, varp, TRUE);
10890 vim_free(bufvarname);
10891 curbuf = save_curbuf;
10892 }
10893 }
10894 }
10895}
10896
10897 static void
10898f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10899{
10900 dict_T *d;
10901 dictitem_T *di;
10902 char_u *csearch;
10903
10904 if (argvars[0].v_type != VAR_DICT)
10905 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010906 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010907 return;
10908 }
10909
10910 if ((d = argvars[0].vval.v_dict) != NULL)
10911 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010912 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010913 if (csearch != NULL)
10914 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010915 if (enc_utf8)
10916 {
10917 int pcc[MAX_MCO];
10918 int c = utfc_ptr2char(csearch, pcc);
10919
10920 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10921 }
10922 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010923 set_last_csearch(PTR2CHAR(csearch),
10924 csearch, MB_PTR2LEN(csearch));
10925 }
10926
10927 di = dict_find(d, (char_u *)"forward", -1);
10928 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010929 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010930 ? FORWARD : BACKWARD);
10931
10932 di = dict_find(d, (char_u *)"until", -1);
10933 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010934 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010935 }
10936}
10937
10938/*
10939 * "setcmdpos()" function
10940 */
10941 static void
10942f_setcmdpos(typval_T *argvars, typval_T *rettv)
10943{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010944 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010945
10946 if (pos >= 0)
10947 rettv->vval.v_number = set_cmdline_pos(pos);
10948}
10949
10950/*
10951 * "setfperm({fname}, {mode})" function
10952 */
10953 static void
10954f_setfperm(typval_T *argvars, typval_T *rettv)
10955{
10956 char_u *fname;
10957 char_u modebuf[NUMBUFLEN];
10958 char_u *mode_str;
10959 int i;
10960 int mask;
10961 int mode = 0;
10962
10963 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010964 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010965 if (fname == NULL)
10966 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010967 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010968 if (mode_str == NULL)
10969 return;
10970 if (STRLEN(mode_str) != 9)
10971 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010972 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010973 return;
10974 }
10975
10976 mask = 1;
10977 for (i = 8; i >= 0; --i)
10978 {
10979 if (mode_str[i] != '-')
10980 mode |= mask;
10981 mask = mask << 1;
10982 }
10983 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10984}
10985
10986/*
10987 * "setline()" function
10988 */
10989 static void
10990f_setline(typval_T *argvars, typval_T *rettv)
10991{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010992 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010993
Bram Moolenaarca851592018-06-06 21:04:07 +020010994 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010995}
10996
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997/*
10998 * Used by "setqflist()" and "setloclist()" functions
10999 */
11000 static void
11001set_qf_ll_list(
11002 win_T *wp UNUSED,
11003 typval_T *list_arg UNUSED,
11004 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011005 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011006 typval_T *rettv)
11007{
11008#ifdef FEAT_QUICKFIX
11009 static char *e_invact = N_("E927: Invalid action: '%s'");
11010 char_u *act;
11011 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011012 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011013#endif
11014
11015 rettv->vval.v_number = -1;
11016
11017#ifdef FEAT_QUICKFIX
11018 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011019 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011020 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011021 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011022 else
11023 {
11024 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011025 dict_T *d = NULL;
11026 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011027
11028 if (action_arg->v_type == VAR_STRING)
11029 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011030 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011031 if (act == NULL)
11032 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011033 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11034 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011035 action = *act;
11036 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011037 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038 }
11039 else if (action_arg->v_type == VAR_UNKNOWN)
11040 action = ' ';
11041 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011042 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011043
Bram Moolenaard823fa92016-08-12 16:29:27 +020011044 if (action_arg->v_type != VAR_UNKNOWN
11045 && what_arg->v_type != VAR_UNKNOWN)
11046 {
11047 if (what_arg->v_type == VAR_DICT)
11048 d = what_arg->vval.v_dict;
11049 else
11050 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011051 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011052 valid_dict = FALSE;
11053 }
11054 }
11055
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011056 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011057 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011058 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11059 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011060 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011061 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011062 }
11063#endif
11064}
11065
11066/*
11067 * "setloclist()" function
11068 */
11069 static void
11070f_setloclist(typval_T *argvars, typval_T *rettv)
11071{
11072 win_T *win;
11073
11074 rettv->vval.v_number = -1;
11075
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011076 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011077 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011078 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011079}
11080
11081/*
11082 * "setmatches()" function
11083 */
11084 static void
11085f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11086{
11087#ifdef FEAT_SEARCH_EXTRA
11088 list_T *l;
11089 listitem_T *li;
11090 dict_T *d;
11091 list_T *s = NULL;
11092
11093 rettv->vval.v_number = -1;
11094 if (argvars[0].v_type != VAR_LIST)
11095 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011096 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011097 return;
11098 }
11099 if ((l = argvars[0].vval.v_list) != NULL)
11100 {
11101
11102 /* To some extent make sure that we are dealing with a list from
11103 * "getmatches()". */
11104 li = l->lv_first;
11105 while (li != NULL)
11106 {
11107 if (li->li_tv.v_type != VAR_DICT
11108 || (d = li->li_tv.vval.v_dict) == NULL)
11109 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011110 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011111 return;
11112 }
11113 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11114 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11115 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11116 && dict_find(d, (char_u *)"priority", -1) != NULL
11117 && dict_find(d, (char_u *)"id", -1) != NULL))
11118 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011119 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011120 return;
11121 }
11122 li = li->li_next;
11123 }
11124
11125 clear_matches(curwin);
11126 li = l->lv_first;
11127 while (li != NULL)
11128 {
11129 int i = 0;
11130 char_u buf[5];
11131 dictitem_T *di;
11132 char_u *group;
11133 int priority;
11134 int id;
11135 char_u *conceal;
11136
11137 d = li->li_tv.vval.v_dict;
11138 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11139 {
11140 if (s == NULL)
11141 {
11142 s = list_alloc();
11143 if (s == NULL)
11144 return;
11145 }
11146
11147 /* match from matchaddpos() */
11148 for (i = 1; i < 9; i++)
11149 {
11150 sprintf((char *)buf, (char *)"pos%d", i);
11151 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11152 {
11153 if (di->di_tv.v_type != VAR_LIST)
11154 return;
11155
11156 list_append_tv(s, &di->di_tv);
11157 s->lv_refcount++;
11158 }
11159 else
11160 break;
11161 }
11162 }
11163
Bram Moolenaar8f667172018-12-14 15:38:31 +010011164 group = dict_get_string(d, (char_u *)"group", TRUE);
11165 priority = (int)dict_get_number(d, (char_u *)"priority");
11166 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011167 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011168 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011169 : NULL;
11170 if (i == 0)
11171 {
11172 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011173 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011174 priority, id, NULL, conceal);
11175 }
11176 else
11177 {
11178 match_add(curwin, group, NULL, priority, id, s, conceal);
11179 list_unref(s);
11180 s = NULL;
11181 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011182 vim_free(group);
11183 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011184
11185 li = li->li_next;
11186 }
11187 rettv->vval.v_number = 0;
11188 }
11189#endif
11190}
11191
11192/*
11193 * "setpos()" function
11194 */
11195 static void
11196f_setpos(typval_T *argvars, typval_T *rettv)
11197{
11198 pos_T pos;
11199 int fnum;
11200 char_u *name;
11201 colnr_T curswant = -1;
11202
11203 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011204 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011205 if (name != NULL)
11206 {
11207 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11208 {
11209 if (--pos.col < 0)
11210 pos.col = 0;
11211 if (name[0] == '.' && name[1] == NUL)
11212 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011213 /* set cursor; "fnum" is ignored */
11214 curwin->w_cursor = pos;
11215 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011216 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011217 curwin->w_curswant = curswant - 1;
11218 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011219 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011220 check_cursor();
11221 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011222 }
11223 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11224 {
11225 /* set mark */
11226 if (setmark_pos(name[1], &pos, fnum) == OK)
11227 rettv->vval.v_number = 0;
11228 }
11229 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011230 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011231 }
11232 }
11233}
11234
11235/*
11236 * "setqflist()" function
11237 */
11238 static void
11239f_setqflist(typval_T *argvars, typval_T *rettv)
11240{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011241 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011242}
11243
11244/*
11245 * "setreg()" function
11246 */
11247 static void
11248f_setreg(typval_T *argvars, typval_T *rettv)
11249{
11250 int regname;
11251 char_u *strregname;
11252 char_u *stropt;
11253 char_u *strval;
11254 int append;
11255 char_u yank_type;
11256 long block_len;
11257
11258 block_len = -1;
11259 yank_type = MAUTO;
11260 append = FALSE;
11261
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011262 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011263 rettv->vval.v_number = 1; /* FAIL is default */
11264
11265 if (strregname == NULL)
11266 return; /* type error; errmsg already given */
11267 regname = *strregname;
11268 if (regname == 0 || regname == '@')
11269 regname = '"';
11270
11271 if (argvars[2].v_type != VAR_UNKNOWN)
11272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011273 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011274 if (stropt == NULL)
11275 return; /* type error */
11276 for (; *stropt != NUL; ++stropt)
11277 switch (*stropt)
11278 {
11279 case 'a': case 'A': /* append */
11280 append = TRUE;
11281 break;
11282 case 'v': case 'c': /* character-wise selection */
11283 yank_type = MCHAR;
11284 break;
11285 case 'V': case 'l': /* line-wise selection */
11286 yank_type = MLINE;
11287 break;
11288 case 'b': case Ctrl_V: /* block-wise selection */
11289 yank_type = MBLOCK;
11290 if (VIM_ISDIGIT(stropt[1]))
11291 {
11292 ++stropt;
11293 block_len = getdigits(&stropt) - 1;
11294 --stropt;
11295 }
11296 break;
11297 }
11298 }
11299
11300 if (argvars[1].v_type == VAR_LIST)
11301 {
11302 char_u **lstval;
11303 char_u **allocval;
11304 char_u buf[NUMBUFLEN];
11305 char_u **curval;
11306 char_u **curallocval;
11307 list_T *ll = argvars[1].vval.v_list;
11308 listitem_T *li;
11309 int len;
11310
11311 /* If the list is NULL handle like an empty list. */
11312 len = ll == NULL ? 0 : ll->lv_len;
11313
11314 /* First half: use for pointers to result lines; second half: use for
11315 * pointers to allocated copies. */
11316 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11317 if (lstval == NULL)
11318 return;
11319 curval = lstval;
11320 allocval = lstval + len + 2;
11321 curallocval = allocval;
11322
11323 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11324 li = li->li_next)
11325 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011326 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011327 if (strval == NULL)
11328 goto free_lstval;
11329 if (strval == buf)
11330 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011331 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011332 * overwrite the string. */
11333 strval = vim_strsave(buf);
11334 if (strval == NULL)
11335 goto free_lstval;
11336 *curallocval++ = strval;
11337 }
11338 *curval++ = strval;
11339 }
11340 *curval++ = NULL;
11341
11342 write_reg_contents_lst(regname, lstval, -1,
11343 append, yank_type, block_len);
11344free_lstval:
11345 while (curallocval > allocval)
11346 vim_free(*--curallocval);
11347 vim_free(lstval);
11348 }
11349 else
11350 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011351 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011352 if (strval == NULL)
11353 return;
11354 write_reg_contents_ex(regname, strval, -1,
11355 append, yank_type, block_len);
11356 }
11357 rettv->vval.v_number = 0;
11358}
11359
11360/*
11361 * "settabvar()" function
11362 */
11363 static void
11364f_settabvar(typval_T *argvars, typval_T *rettv)
11365{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011366 tabpage_T *save_curtab;
11367 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011368 char_u *varname, *tabvarname;
11369 typval_T *varp;
11370
11371 rettv->vval.v_number = 0;
11372
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011373 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011374 return;
11375
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011376 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11377 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011378 varp = &argvars[2];
11379
Bram Moolenaar4033c552017-09-16 20:54:51 +020011380 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011381 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011382 save_curtab = curtab;
11383 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384
11385 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11386 if (tabvarname != NULL)
11387 {
11388 STRCPY(tabvarname, "t:");
11389 STRCPY(tabvarname + 2, varname);
11390 set_var(tabvarname, varp, TRUE);
11391 vim_free(tabvarname);
11392 }
11393
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011394 /* Restore current tabpage */
11395 if (valid_tabpage(save_curtab))
11396 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011397 }
11398}
11399
11400/*
11401 * "settabwinvar()" function
11402 */
11403 static void
11404f_settabwinvar(typval_T *argvars, typval_T *rettv)
11405{
11406 setwinvar(argvars, rettv, 1);
11407}
11408
11409/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011410 * "settagstack()" function
11411 */
11412 static void
11413f_settagstack(typval_T *argvars, typval_T *rettv)
11414{
11415 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11416 win_T *wp;
11417 dict_T *d;
11418 int action = 'r';
11419
11420 rettv->vval.v_number = -1;
11421
11422 // first argument: window number or id
11423 wp = find_win_by_nr_or_id(&argvars[0]);
11424 if (wp == NULL)
11425 return;
11426
11427 // second argument: dict with items to set in the tag stack
11428 if (argvars[1].v_type != VAR_DICT)
11429 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011430 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011431 return;
11432 }
11433 d = argvars[1].vval.v_dict;
11434 if (d == NULL)
11435 return;
11436
11437 // third argument: action - 'a' for append and 'r' for replace.
11438 // default is to replace the stack.
11439 if (argvars[2].v_type == VAR_UNKNOWN)
11440 action = 'r';
11441 else if (argvars[2].v_type == VAR_STRING)
11442 {
11443 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011444 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011445 if (actstr == NULL)
11446 return;
11447 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11448 action = *actstr;
11449 else
11450 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011451 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011452 return;
11453 }
11454 }
11455 else
11456 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011457 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011458 return;
11459 }
11460
11461 if (set_tagstack(wp, d, action) == OK)
11462 rettv->vval.v_number = 0;
11463}
11464
11465/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011466 * "setwinvar()" function
11467 */
11468 static void
11469f_setwinvar(typval_T *argvars, typval_T *rettv)
11470{
11471 setwinvar(argvars, rettv, 0);
11472}
11473
11474#ifdef FEAT_CRYPT
11475/*
11476 * "sha256({string})" function
11477 */
11478 static void
11479f_sha256(typval_T *argvars, typval_T *rettv)
11480{
11481 char_u *p;
11482
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011483 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011484 rettv->vval.v_string = vim_strsave(
11485 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11486 rettv->v_type = VAR_STRING;
11487}
11488#endif /* FEAT_CRYPT */
11489
11490/*
11491 * "shellescape({string})" function
11492 */
11493 static void
11494f_shellescape(typval_T *argvars, typval_T *rettv)
11495{
Bram Moolenaar20615522017-06-05 18:46:26 +020011496 int do_special = non_zero_arg(&argvars[1]);
11497
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011498 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011499 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011500 rettv->v_type = VAR_STRING;
11501}
11502
11503/*
11504 * shiftwidth() function
11505 */
11506 static void
11507f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11508{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011509 rettv->vval.v_number = 0;
11510
11511 if (argvars[0].v_type != VAR_UNKNOWN)
11512 {
11513 long col;
11514
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011515 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011516 if (col < 0)
11517 return; // type error; errmsg already given
11518#ifdef FEAT_VARTABS
11519 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11520 return;
11521#endif
11522 }
11523
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011524 rettv->vval.v_number = get_sw_value(curbuf);
11525}
11526
Bram Moolenaar162b7142018-12-21 15:17:36 +010011527#ifdef FEAT_SIGNS
11528/*
11529 * "sign_define()" function
11530 */
11531 static void
11532f_sign_define(typval_T *argvars, typval_T *rettv)
11533{
11534 char_u *name;
11535 dict_T *dict;
11536 char_u *icon = NULL;
11537 char_u *linehl = NULL;
11538 char_u *text = NULL;
11539 char_u *texthl = NULL;
11540
11541 rettv->vval.v_number = -1;
11542
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011543 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011544 if (name == NULL)
11545 return;
11546
11547 if (argvars[1].v_type != VAR_UNKNOWN)
11548 {
11549 if (argvars[1].v_type != VAR_DICT)
11550 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011551 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011552 return;
11553 }
11554
11555 // sign attributes
11556 dict = argvars[1].vval.v_dict;
11557 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11558 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11559 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11560 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11561 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11562 text = dict_get_string(dict, (char_u *)"text", TRUE);
11563 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11564 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11565 }
11566
11567 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11568 rettv->vval.v_number = 0;
11569
11570 vim_free(icon);
11571 vim_free(linehl);
11572 vim_free(text);
11573 vim_free(texthl);
11574}
11575
11576/*
11577 * "sign_getdefined()" function
11578 */
11579 static void
11580f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11581{
11582 char_u *name = NULL;
11583
11584 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11585 return;
11586
11587 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011588 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011589
11590 sign_getlist(name, rettv->vval.v_list);
11591}
11592
11593/*
11594 * "sign_getplaced()" function
11595 */
11596 static void
11597f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11598{
11599 buf_T *buf = NULL;
11600 dict_T *dict;
11601 dictitem_T *di;
11602 linenr_T lnum = 0;
11603 int sign_id = 0;
11604 char_u *group = NULL;
11605 int notanum = FALSE;
11606
11607 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11608 return;
11609
11610 if (argvars[0].v_type != VAR_UNKNOWN)
11611 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011612 // get signs placed in the specified buffer
11613 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011614 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011615 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011616
11617 if (argvars[1].v_type != VAR_UNKNOWN)
11618 {
11619 if (argvars[1].v_type != VAR_DICT ||
11620 ((dict = argvars[1].vval.v_dict) == NULL))
11621 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011622 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011623 return;
11624 }
11625 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11626 {
11627 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011628 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011629 if (notanum)
11630 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011631 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011632 }
11633 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11634 {
11635 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011636 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011637 if (notanum)
11638 return;
11639 }
11640 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11641 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011642 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011643 if (group == NULL)
11644 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011645 if (*group == '\0') // empty string means global group
11646 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011647 }
11648 }
11649 }
11650
11651 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11652}
11653
11654/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011655 * "sign_jump()" function
11656 */
11657 static void
11658f_sign_jump(typval_T *argvars, typval_T *rettv)
11659{
11660 int sign_id;
11661 char_u *sign_group = NULL;
11662 buf_T *buf;
11663 int notanum = FALSE;
11664
11665 rettv->vval.v_number = -1;
11666
Bram Moolenaarbdace832019-03-02 10:13:42 +010011667 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011668 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11669 if (notanum)
11670 return;
11671 if (sign_id <= 0)
11672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011673 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011674 return;
11675 }
11676
11677 // Sign group
11678 sign_group = tv_get_string_chk(&argvars[1]);
11679 if (sign_group == NULL)
11680 return;
11681 if (sign_group[0] == '\0')
11682 sign_group = NULL; // global sign group
11683 else
11684 {
11685 sign_group = vim_strsave(sign_group);
11686 if (sign_group == NULL)
11687 return;
11688 }
11689
11690 // Buffer to place the sign
11691 buf = get_buf_arg(&argvars[2]);
11692 if (buf == NULL)
11693 goto cleanup;
11694
11695 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11696
11697cleanup:
11698 vim_free(sign_group);
11699}
11700
11701/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011702 * "sign_place()" function
11703 */
11704 static void
11705f_sign_place(typval_T *argvars, typval_T *rettv)
11706{
11707 int sign_id;
11708 char_u *group = NULL;
11709 char_u *sign_name;
11710 buf_T *buf;
11711 dict_T *dict;
11712 dictitem_T *di;
11713 linenr_T lnum = 0;
11714 int prio = SIGN_DEF_PRIO;
11715 int notanum = FALSE;
11716
11717 rettv->vval.v_number = -1;
11718
Bram Moolenaarbdace832019-03-02 10:13:42 +010011719 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011720 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011721 if (notanum)
11722 return;
11723 if (sign_id < 0)
11724 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011725 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011726 return;
11727 }
11728
11729 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011730 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011731 if (group == NULL)
11732 return;
11733 if (group[0] == '\0')
11734 group = NULL; // global sign group
11735 else
11736 {
11737 group = vim_strsave(group);
11738 if (group == NULL)
11739 return;
11740 }
11741
11742 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011743 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011744 if (sign_name == NULL)
11745 goto cleanup;
11746
11747 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011748 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011749 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011750 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011751
11752 if (argvars[4].v_type != VAR_UNKNOWN)
11753 {
11754 if (argvars[4].v_type != VAR_DICT ||
11755 ((dict = argvars[4].vval.v_dict) == NULL))
11756 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011757 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011758 goto cleanup;
11759 }
11760
11761 // Line number where the sign is to be placed
11762 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11763 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011764 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011765 if (notanum)
11766 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011767 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011768 }
11769 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11770 {
11771 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011772 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011773 if (notanum)
11774 goto cleanup;
11775 }
11776 }
11777
11778 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11779 rettv->vval.v_number = sign_id;
11780
11781cleanup:
11782 vim_free(group);
11783}
11784
11785/*
11786 * "sign_undefine()" function
11787 */
11788 static void
11789f_sign_undefine(typval_T *argvars, typval_T *rettv)
11790{
11791 char_u *name;
11792
11793 rettv->vval.v_number = -1;
11794
11795 if (argvars[0].v_type == VAR_UNKNOWN)
11796 {
11797 // Free all the signs
11798 free_signs();
11799 rettv->vval.v_number = 0;
11800 }
11801 else
11802 {
11803 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011804 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011805 if (name == NULL)
11806 return;
11807
11808 if (sign_undefine_by_name(name) == OK)
11809 rettv->vval.v_number = 0;
11810 }
11811}
11812
11813/*
11814 * "sign_unplace()" function
11815 */
11816 static void
11817f_sign_unplace(typval_T *argvars, typval_T *rettv)
11818{
11819 dict_T *dict;
11820 dictitem_T *di;
11821 int sign_id = 0;
11822 buf_T *buf = NULL;
11823 char_u *group = NULL;
11824
11825 rettv->vval.v_number = -1;
11826
11827 if (argvars[0].v_type != VAR_STRING)
11828 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011829 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011830 return;
11831 }
11832
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011833 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011834 if (group[0] == '\0')
11835 group = NULL; // global sign group
11836 else
11837 {
11838 group = vim_strsave(group);
11839 if (group == NULL)
11840 return;
11841 }
11842
11843 if (argvars[1].v_type != VAR_UNKNOWN)
11844 {
11845 if (argvars[1].v_type != VAR_DICT)
11846 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011847 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011848 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011849 }
11850 dict = argvars[1].vval.v_dict;
11851
11852 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11853 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011854 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011855 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011856 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011857 }
11858 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11859 sign_id = dict_get_number(dict, (char_u *)"id");
11860 }
11861
11862 if (buf == NULL)
11863 {
11864 // Delete the sign in all the buffers
11865 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011866 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011867 rettv->vval.v_number = 0;
11868 }
11869 else
11870 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011871 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011872 rettv->vval.v_number = 0;
11873 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011874
11875cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010011876 vim_free(group);
11877}
11878#endif
11879
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011880/*
11881 * "simplify()" function
11882 */
11883 static void
11884f_simplify(typval_T *argvars, typval_T *rettv)
11885{
11886 char_u *p;
11887
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011888 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011889 rettv->vval.v_string = vim_strsave(p);
11890 simplify_filename(rettv->vval.v_string); /* simplify in place */
11891 rettv->v_type = VAR_STRING;
11892}
11893
11894#ifdef FEAT_FLOAT
11895/*
11896 * "sin()" function
11897 */
11898 static void
11899f_sin(typval_T *argvars, typval_T *rettv)
11900{
11901 float_T f = 0.0;
11902
11903 rettv->v_type = VAR_FLOAT;
11904 if (get_float_arg(argvars, &f) == OK)
11905 rettv->vval.v_float = sin(f);
11906 else
11907 rettv->vval.v_float = 0.0;
11908}
11909
11910/*
11911 * "sinh()" function
11912 */
11913 static void
11914f_sinh(typval_T *argvars, typval_T *rettv)
11915{
11916 float_T f = 0.0;
11917
11918 rettv->v_type = VAR_FLOAT;
11919 if (get_float_arg(argvars, &f) == OK)
11920 rettv->vval.v_float = sinh(f);
11921 else
11922 rettv->vval.v_float = 0.0;
11923}
11924#endif
11925
11926static int
11927#ifdef __BORLANDC__
11928 _RTLENTRYF
11929#endif
11930 item_compare(const void *s1, const void *s2);
11931static int
11932#ifdef __BORLANDC__
11933 _RTLENTRYF
11934#endif
11935 item_compare2(const void *s1, const void *s2);
11936
11937/* struct used in the array that's given to qsort() */
11938typedef struct
11939{
11940 listitem_T *item;
11941 int idx;
11942} sortItem_T;
11943
11944/* struct storing information about current sort */
11945typedef struct
11946{
11947 int item_compare_ic;
11948 int item_compare_numeric;
11949 int item_compare_numbers;
11950#ifdef FEAT_FLOAT
11951 int item_compare_float;
11952#endif
11953 char_u *item_compare_func;
11954 partial_T *item_compare_partial;
11955 dict_T *item_compare_selfdict;
11956 int item_compare_func_err;
11957 int item_compare_keep_zero;
11958} sortinfo_T;
11959static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011960#define ITEM_COMPARE_FAIL 999
11961
11962/*
11963 * Compare functions for f_sort() and f_uniq() below.
11964 */
11965 static int
11966#ifdef __BORLANDC__
11967_RTLENTRYF
11968#endif
11969item_compare(const void *s1, const void *s2)
11970{
11971 sortItem_T *si1, *si2;
11972 typval_T *tv1, *tv2;
11973 char_u *p1, *p2;
11974 char_u *tofree1 = NULL, *tofree2 = NULL;
11975 int res;
11976 char_u numbuf1[NUMBUFLEN];
11977 char_u numbuf2[NUMBUFLEN];
11978
11979 si1 = (sortItem_T *)s1;
11980 si2 = (sortItem_T *)s2;
11981 tv1 = &si1->item->li_tv;
11982 tv2 = &si2->item->li_tv;
11983
11984 if (sortinfo->item_compare_numbers)
11985 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011986 varnumber_T v1 = tv_get_number(tv1);
11987 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011988
11989 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11990 }
11991
11992#ifdef FEAT_FLOAT
11993 if (sortinfo->item_compare_float)
11994 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011995 float_T v1 = tv_get_float(tv1);
11996 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011997
11998 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11999 }
12000#endif
12001
12002 /* tv2string() puts quotes around a string and allocates memory. Don't do
12003 * that for string variables. Use a single quote when comparing with a
12004 * non-string to do what the docs promise. */
12005 if (tv1->v_type == VAR_STRING)
12006 {
12007 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12008 p1 = (char_u *)"'";
12009 else
12010 p1 = tv1->vval.v_string;
12011 }
12012 else
12013 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12014 if (tv2->v_type == VAR_STRING)
12015 {
12016 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12017 p2 = (char_u *)"'";
12018 else
12019 p2 = tv2->vval.v_string;
12020 }
12021 else
12022 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12023 if (p1 == NULL)
12024 p1 = (char_u *)"";
12025 if (p2 == NULL)
12026 p2 = (char_u *)"";
12027 if (!sortinfo->item_compare_numeric)
12028 {
12029 if (sortinfo->item_compare_ic)
12030 res = STRICMP(p1, p2);
12031 else
12032 res = STRCMP(p1, p2);
12033 }
12034 else
12035 {
12036 double n1, n2;
12037 n1 = strtod((char *)p1, (char **)&p1);
12038 n2 = strtod((char *)p2, (char **)&p2);
12039 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12040 }
12041
12042 /* When the result would be zero, compare the item indexes. Makes the
12043 * sort stable. */
12044 if (res == 0 && !sortinfo->item_compare_keep_zero)
12045 res = si1->idx > si2->idx ? 1 : -1;
12046
12047 vim_free(tofree1);
12048 vim_free(tofree2);
12049 return res;
12050}
12051
12052 static int
12053#ifdef __BORLANDC__
12054_RTLENTRYF
12055#endif
12056item_compare2(const void *s1, const void *s2)
12057{
12058 sortItem_T *si1, *si2;
12059 int res;
12060 typval_T rettv;
12061 typval_T argv[3];
12062 int dummy;
12063 char_u *func_name;
12064 partial_T *partial = sortinfo->item_compare_partial;
12065
12066 /* shortcut after failure in previous call; compare all items equal */
12067 if (sortinfo->item_compare_func_err)
12068 return 0;
12069
12070 si1 = (sortItem_T *)s1;
12071 si2 = (sortItem_T *)s2;
12072
12073 if (partial == NULL)
12074 func_name = sortinfo->item_compare_func;
12075 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012076 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012077
12078 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12079 * in the copy without changing the original list items. */
12080 copy_tv(&si1->item->li_tv, &argv[0]);
12081 copy_tv(&si2->item->li_tv, &argv[1]);
12082
12083 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12084 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012085 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012086 partial, sortinfo->item_compare_selfdict);
12087 clear_tv(&argv[0]);
12088 clear_tv(&argv[1]);
12089
12090 if (res == FAIL)
12091 res = ITEM_COMPARE_FAIL;
12092 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012093 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012094 if (sortinfo->item_compare_func_err)
12095 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12096 clear_tv(&rettv);
12097
12098 /* When the result would be zero, compare the pointers themselves. Makes
12099 * the sort stable. */
12100 if (res == 0 && !sortinfo->item_compare_keep_zero)
12101 res = si1->idx > si2->idx ? 1 : -1;
12102
12103 return res;
12104}
12105
12106/*
12107 * "sort({list})" function
12108 */
12109 static void
12110do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12111{
12112 list_T *l;
12113 listitem_T *li;
12114 sortItem_T *ptrs;
12115 sortinfo_T *old_sortinfo;
12116 sortinfo_T info;
12117 long len;
12118 long i;
12119
12120 /* Pointer to current info struct used in compare function. Save and
12121 * restore the current one for nested calls. */
12122 old_sortinfo = sortinfo;
12123 sortinfo = &info;
12124
12125 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012126 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012127 else
12128 {
12129 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012130 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012131 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12132 TRUE))
12133 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012134 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012135
12136 len = list_len(l);
12137 if (len <= 1)
12138 goto theend; /* short list sorts pretty quickly */
12139
12140 info.item_compare_ic = FALSE;
12141 info.item_compare_numeric = FALSE;
12142 info.item_compare_numbers = FALSE;
12143#ifdef FEAT_FLOAT
12144 info.item_compare_float = FALSE;
12145#endif
12146 info.item_compare_func = NULL;
12147 info.item_compare_partial = NULL;
12148 info.item_compare_selfdict = NULL;
12149 if (argvars[1].v_type != VAR_UNKNOWN)
12150 {
12151 /* optional second argument: {func} */
12152 if (argvars[1].v_type == VAR_FUNC)
12153 info.item_compare_func = argvars[1].vval.v_string;
12154 else if (argvars[1].v_type == VAR_PARTIAL)
12155 info.item_compare_partial = argvars[1].vval.v_partial;
12156 else
12157 {
12158 int error = FALSE;
12159
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012160 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012161 if (error)
12162 goto theend; /* type error; errmsg already given */
12163 if (i == 1)
12164 info.item_compare_ic = TRUE;
12165 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012166 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012167 else if (i != 0)
12168 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012169 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012170 goto theend;
12171 }
12172 if (info.item_compare_func != NULL)
12173 {
12174 if (*info.item_compare_func == NUL)
12175 {
12176 /* empty string means default sort */
12177 info.item_compare_func = NULL;
12178 }
12179 else if (STRCMP(info.item_compare_func, "n") == 0)
12180 {
12181 info.item_compare_func = NULL;
12182 info.item_compare_numeric = TRUE;
12183 }
12184 else if (STRCMP(info.item_compare_func, "N") == 0)
12185 {
12186 info.item_compare_func = NULL;
12187 info.item_compare_numbers = TRUE;
12188 }
12189#ifdef FEAT_FLOAT
12190 else if (STRCMP(info.item_compare_func, "f") == 0)
12191 {
12192 info.item_compare_func = NULL;
12193 info.item_compare_float = TRUE;
12194 }
12195#endif
12196 else if (STRCMP(info.item_compare_func, "i") == 0)
12197 {
12198 info.item_compare_func = NULL;
12199 info.item_compare_ic = TRUE;
12200 }
12201 }
12202 }
12203
12204 if (argvars[2].v_type != VAR_UNKNOWN)
12205 {
12206 /* optional third argument: {dict} */
12207 if (argvars[2].v_type != VAR_DICT)
12208 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012209 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012210 goto theend;
12211 }
12212 info.item_compare_selfdict = argvars[2].vval.v_dict;
12213 }
12214 }
12215
12216 /* Make an array with each entry pointing to an item in the List. */
12217 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12218 if (ptrs == NULL)
12219 goto theend;
12220
12221 i = 0;
12222 if (sort)
12223 {
12224 /* sort(): ptrs will be the list to sort */
12225 for (li = l->lv_first; li != NULL; li = li->li_next)
12226 {
12227 ptrs[i].item = li;
12228 ptrs[i].idx = i;
12229 ++i;
12230 }
12231
12232 info.item_compare_func_err = FALSE;
12233 info.item_compare_keep_zero = FALSE;
12234 /* test the compare function */
12235 if ((info.item_compare_func != NULL
12236 || info.item_compare_partial != NULL)
12237 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12238 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012239 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012240 else
12241 {
12242 /* Sort the array with item pointers. */
12243 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12244 info.item_compare_func == NULL
12245 && info.item_compare_partial == NULL
12246 ? item_compare : item_compare2);
12247
12248 if (!info.item_compare_func_err)
12249 {
12250 /* Clear the List and append the items in sorted order. */
12251 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12252 l->lv_len = 0;
12253 for (i = 0; i < len; ++i)
12254 list_append(l, ptrs[i].item);
12255 }
12256 }
12257 }
12258 else
12259 {
12260 int (*item_compare_func_ptr)(const void *, const void *);
12261
12262 /* f_uniq(): ptrs will be a stack of items to remove */
12263 info.item_compare_func_err = FALSE;
12264 info.item_compare_keep_zero = TRUE;
12265 item_compare_func_ptr = info.item_compare_func != NULL
12266 || info.item_compare_partial != NULL
12267 ? item_compare2 : item_compare;
12268
12269 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12270 li = li->li_next)
12271 {
12272 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12273 == 0)
12274 ptrs[i++].item = li;
12275 if (info.item_compare_func_err)
12276 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012277 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012278 break;
12279 }
12280 }
12281
12282 if (!info.item_compare_func_err)
12283 {
12284 while (--i >= 0)
12285 {
12286 li = ptrs[i].item->li_next;
12287 ptrs[i].item->li_next = li->li_next;
12288 if (li->li_next != NULL)
12289 li->li_next->li_prev = ptrs[i].item;
12290 else
12291 l->lv_last = ptrs[i].item;
12292 list_fix_watch(l, li);
12293 listitem_free(li);
12294 l->lv_len--;
12295 }
12296 }
12297 }
12298
12299 vim_free(ptrs);
12300 }
12301theend:
12302 sortinfo = old_sortinfo;
12303}
12304
12305/*
12306 * "sort({list})" function
12307 */
12308 static void
12309f_sort(typval_T *argvars, typval_T *rettv)
12310{
12311 do_sort_uniq(argvars, rettv, TRUE);
12312}
12313
12314/*
12315 * "uniq({list})" function
12316 */
12317 static void
12318f_uniq(typval_T *argvars, typval_T *rettv)
12319{
12320 do_sort_uniq(argvars, rettv, FALSE);
12321}
12322
12323/*
12324 * "soundfold({word})" function
12325 */
12326 static void
12327f_soundfold(typval_T *argvars, typval_T *rettv)
12328{
12329 char_u *s;
12330
12331 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012332 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012333#ifdef FEAT_SPELL
12334 rettv->vval.v_string = eval_soundfold(s);
12335#else
12336 rettv->vval.v_string = vim_strsave(s);
12337#endif
12338}
12339
12340/*
12341 * "spellbadword()" function
12342 */
12343 static void
12344f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12345{
12346 char_u *word = (char_u *)"";
12347 hlf_T attr = HLF_COUNT;
12348 int len = 0;
12349
12350 if (rettv_list_alloc(rettv) == FAIL)
12351 return;
12352
12353#ifdef FEAT_SPELL
12354 if (argvars[0].v_type == VAR_UNKNOWN)
12355 {
12356 /* Find the start and length of the badly spelled word. */
12357 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12358 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012359 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012360 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012361 curwin->w_set_curswant = TRUE;
12362 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012363 }
12364 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12365 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012366 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012367 int capcol = -1;
12368
12369 if (str != NULL)
12370 {
12371 /* Check the argument for spelling. */
12372 while (*str != NUL)
12373 {
12374 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12375 if (attr != HLF_COUNT)
12376 {
12377 word = str;
12378 break;
12379 }
12380 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012381 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012382 }
12383 }
12384 }
12385#endif
12386
12387 list_append_string(rettv->vval.v_list, word, len);
12388 list_append_string(rettv->vval.v_list, (char_u *)(
12389 attr == HLF_SPB ? "bad" :
12390 attr == HLF_SPR ? "rare" :
12391 attr == HLF_SPL ? "local" :
12392 attr == HLF_SPC ? "caps" :
12393 ""), -1);
12394}
12395
12396/*
12397 * "spellsuggest()" function
12398 */
12399 static void
12400f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12401{
12402#ifdef FEAT_SPELL
12403 char_u *str;
12404 int typeerr = FALSE;
12405 int maxcount;
12406 garray_T ga;
12407 int i;
12408 listitem_T *li;
12409 int need_capital = FALSE;
12410#endif
12411
12412 if (rettv_list_alloc(rettv) == FAIL)
12413 return;
12414
12415#ifdef FEAT_SPELL
12416 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12417 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012418 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012419 if (argvars[1].v_type != VAR_UNKNOWN)
12420 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012421 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012422 if (maxcount <= 0)
12423 return;
12424 if (argvars[2].v_type != VAR_UNKNOWN)
12425 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012426 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012427 if (typeerr)
12428 return;
12429 }
12430 }
12431 else
12432 maxcount = 25;
12433
12434 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12435
12436 for (i = 0; i < ga.ga_len; ++i)
12437 {
12438 str = ((char_u **)ga.ga_data)[i];
12439
12440 li = listitem_alloc();
12441 if (li == NULL)
12442 vim_free(str);
12443 else
12444 {
12445 li->li_tv.v_type = VAR_STRING;
12446 li->li_tv.v_lock = 0;
12447 li->li_tv.vval.v_string = str;
12448 list_append(rettv->vval.v_list, li);
12449 }
12450 }
12451 ga_clear(&ga);
12452 }
12453#endif
12454}
12455
12456 static void
12457f_split(typval_T *argvars, typval_T *rettv)
12458{
12459 char_u *str;
12460 char_u *end;
12461 char_u *pat = NULL;
12462 regmatch_T regmatch;
12463 char_u patbuf[NUMBUFLEN];
12464 char_u *save_cpo;
12465 int match;
12466 colnr_T col = 0;
12467 int keepempty = FALSE;
12468 int typeerr = FALSE;
12469
12470 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12471 save_cpo = p_cpo;
12472 p_cpo = (char_u *)"";
12473
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012474 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012475 if (argvars[1].v_type != VAR_UNKNOWN)
12476 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012477 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012478 if (pat == NULL)
12479 typeerr = TRUE;
12480 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012481 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012482 }
12483 if (pat == NULL || *pat == NUL)
12484 pat = (char_u *)"[\\x01- ]\\+";
12485
12486 if (rettv_list_alloc(rettv) == FAIL)
12487 return;
12488 if (typeerr)
12489 return;
12490
12491 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12492 if (regmatch.regprog != NULL)
12493 {
12494 regmatch.rm_ic = FALSE;
12495 while (*str != NUL || keepempty)
12496 {
12497 if (*str == NUL)
12498 match = FALSE; /* empty item at the end */
12499 else
12500 match = vim_regexec_nl(&regmatch, str, col);
12501 if (match)
12502 end = regmatch.startp[0];
12503 else
12504 end = str + STRLEN(str);
12505 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12506 && *str != NUL && match && end < regmatch.endp[0]))
12507 {
12508 if (list_append_string(rettv->vval.v_list, str,
12509 (int)(end - str)) == FAIL)
12510 break;
12511 }
12512 if (!match)
12513 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012514 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012515 if (regmatch.endp[0] > str)
12516 col = 0;
12517 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012518 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012519 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012520 str = regmatch.endp[0];
12521 }
12522
12523 vim_regfree(regmatch.regprog);
12524 }
12525
12526 p_cpo = save_cpo;
12527}
12528
12529#ifdef FEAT_FLOAT
12530/*
12531 * "sqrt()" function
12532 */
12533 static void
12534f_sqrt(typval_T *argvars, typval_T *rettv)
12535{
12536 float_T f = 0.0;
12537
12538 rettv->v_type = VAR_FLOAT;
12539 if (get_float_arg(argvars, &f) == OK)
12540 rettv->vval.v_float = sqrt(f);
12541 else
12542 rettv->vval.v_float = 0.0;
12543}
12544
12545/*
12546 * "str2float()" function
12547 */
12548 static void
12549f_str2float(typval_T *argvars, typval_T *rettv)
12550{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012551 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012552 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012553
Bram Moolenaar08243d22017-01-10 16:12:29 +010012554 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012555 p = skipwhite(p + 1);
12556 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012557 if (isneg)
12558 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012559 rettv->v_type = VAR_FLOAT;
12560}
12561#endif
12562
12563/*
12564 * "str2nr()" function
12565 */
12566 static void
12567f_str2nr(typval_T *argvars, typval_T *rettv)
12568{
12569 int base = 10;
12570 char_u *p;
12571 varnumber_T n;
12572 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012573 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012574
12575 if (argvars[1].v_type != VAR_UNKNOWN)
12576 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012577 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012578 if (base != 2 && base != 8 && base != 10 && base != 16)
12579 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012580 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012581 return;
12582 }
12583 }
12584
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012585 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012586 isneg = (*p == '-');
12587 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012588 p = skipwhite(p + 1);
12589 switch (base)
12590 {
12591 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12592 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12593 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12594 default: what = 0;
12595 }
12596 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012597 if (isneg)
12598 rettv->vval.v_number = -n;
12599 else
12600 rettv->vval.v_number = n;
12601
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012602}
12603
12604#ifdef HAVE_STRFTIME
12605/*
12606 * "strftime({format}[, {time}])" function
12607 */
12608 static void
12609f_strftime(typval_T *argvars, typval_T *rettv)
12610{
12611 char_u result_buf[256];
12612 struct tm *curtime;
12613 time_t seconds;
12614 char_u *p;
12615
12616 rettv->v_type = VAR_STRING;
12617
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012618 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012619 if (argvars[1].v_type == VAR_UNKNOWN)
12620 seconds = time(NULL);
12621 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012622 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012623 curtime = localtime(&seconds);
12624 /* MSVC returns NULL for an invalid value of seconds. */
12625 if (curtime == NULL)
12626 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12627 else
12628 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012629 vimconv_T conv;
12630 char_u *enc;
12631
12632 conv.vc_type = CONV_NONE;
12633 enc = enc_locale();
12634 convert_setup(&conv, p_enc, enc);
12635 if (conv.vc_type != CONV_NONE)
12636 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012637 if (p != NULL)
12638 (void)strftime((char *)result_buf, sizeof(result_buf),
12639 (char *)p, curtime);
12640 else
12641 result_buf[0] = NUL;
12642
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012643 if (conv.vc_type != CONV_NONE)
12644 vim_free(p);
12645 convert_setup(&conv, enc, p_enc);
12646 if (conv.vc_type != CONV_NONE)
12647 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12648 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012649 rettv->vval.v_string = vim_strsave(result_buf);
12650
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012651 /* Release conversion descriptors */
12652 convert_setup(&conv, NULL, NULL);
12653 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012654 }
12655}
12656#endif
12657
12658/*
12659 * "strgetchar()" function
12660 */
12661 static void
12662f_strgetchar(typval_T *argvars, typval_T *rettv)
12663{
12664 char_u *str;
12665 int len;
12666 int error = FALSE;
12667 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012668 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012669
12670 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012671 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012672 if (str == NULL)
12673 return;
12674 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012675 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012676 if (error)
12677 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012678
Bram Moolenaar13505972019-01-24 15:04:48 +010012679 while (charidx >= 0 && byteidx < len)
12680 {
12681 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012682 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012683 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12684 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012685 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012686 --charidx;
12687 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012688 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012689}
12690
12691/*
12692 * "stridx()" function
12693 */
12694 static void
12695f_stridx(typval_T *argvars, typval_T *rettv)
12696{
12697 char_u buf[NUMBUFLEN];
12698 char_u *needle;
12699 char_u *haystack;
12700 char_u *save_haystack;
12701 char_u *pos;
12702 int start_idx;
12703
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012704 needle = tv_get_string_chk(&argvars[1]);
12705 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012706 rettv->vval.v_number = -1;
12707 if (needle == NULL || haystack == NULL)
12708 return; /* type error; errmsg already given */
12709
12710 if (argvars[2].v_type != VAR_UNKNOWN)
12711 {
12712 int error = FALSE;
12713
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012714 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012715 if (error || start_idx >= (int)STRLEN(haystack))
12716 return;
12717 if (start_idx >= 0)
12718 haystack += start_idx;
12719 }
12720
12721 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12722 if (pos != NULL)
12723 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12724}
12725
12726/*
12727 * "string()" function
12728 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012729 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012730f_string(typval_T *argvars, typval_T *rettv)
12731{
12732 char_u *tofree;
12733 char_u numbuf[NUMBUFLEN];
12734
12735 rettv->v_type = VAR_STRING;
12736 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12737 get_copyID());
12738 /* Make a copy if we have a value but it's not in allocated memory. */
12739 if (rettv->vval.v_string != NULL && tofree == NULL)
12740 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12741}
12742
12743/*
12744 * "strlen()" function
12745 */
12746 static void
12747f_strlen(typval_T *argvars, typval_T *rettv)
12748{
12749 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012750 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012751}
12752
12753/*
12754 * "strchars()" function
12755 */
12756 static void
12757f_strchars(typval_T *argvars, typval_T *rettv)
12758{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012759 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012760 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 varnumber_T len = 0;
12762 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012763
12764 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012765 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012766 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012767 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012768 else
12769 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012770 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12771 while (*s != NUL)
12772 {
12773 func_mb_ptr2char_adv(&s);
12774 ++len;
12775 }
12776 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012777 }
12778}
12779
12780/*
12781 * "strdisplaywidth()" function
12782 */
12783 static void
12784f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12785{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012786 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012787 int col = 0;
12788
12789 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012790 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791
12792 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12793}
12794
12795/*
12796 * "strwidth()" function
12797 */
12798 static void
12799f_strwidth(typval_T *argvars, typval_T *rettv)
12800{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012801 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012802
Bram Moolenaar13505972019-01-24 15:04:48 +010012803 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012804}
12805
12806/*
12807 * "strcharpart()" function
12808 */
12809 static void
12810f_strcharpart(typval_T *argvars, typval_T *rettv)
12811{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012812 char_u *p;
12813 int nchar;
12814 int nbyte = 0;
12815 int charlen;
12816 int len = 0;
12817 int slen;
12818 int error = FALSE;
12819
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012820 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012821 slen = (int)STRLEN(p);
12822
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012823 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012824 if (!error)
12825 {
12826 if (nchar > 0)
12827 while (nchar > 0 && nbyte < slen)
12828 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012829 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012830 --nchar;
12831 }
12832 else
12833 nbyte = nchar;
12834 if (argvars[2].v_type != VAR_UNKNOWN)
12835 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012836 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012837 while (charlen > 0 && nbyte + len < slen)
12838 {
12839 int off = nbyte + len;
12840
12841 if (off < 0)
12842 len += 1;
12843 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012844 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012845 --charlen;
12846 }
12847 }
12848 else
12849 len = slen - nbyte; /* default: all bytes that are available. */
12850 }
12851
12852 /*
12853 * Only return the overlap between the specified part and the actual
12854 * string.
12855 */
12856 if (nbyte < 0)
12857 {
12858 len += nbyte;
12859 nbyte = 0;
12860 }
12861 else if (nbyte > slen)
12862 nbyte = slen;
12863 if (len < 0)
12864 len = 0;
12865 else if (nbyte + len > slen)
12866 len = slen - nbyte;
12867
12868 rettv->v_type = VAR_STRING;
12869 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012870}
12871
12872/*
12873 * "strpart()" function
12874 */
12875 static void
12876f_strpart(typval_T *argvars, typval_T *rettv)
12877{
12878 char_u *p;
12879 int n;
12880 int len;
12881 int slen;
12882 int error = FALSE;
12883
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012884 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012885 slen = (int)STRLEN(p);
12886
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012887 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012888 if (error)
12889 len = 0;
12890 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012891 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012892 else
12893 len = slen - n; /* default len: all bytes that are available. */
12894
12895 /*
12896 * Only return the overlap between the specified part and the actual
12897 * string.
12898 */
12899 if (n < 0)
12900 {
12901 len += n;
12902 n = 0;
12903 }
12904 else if (n > slen)
12905 n = slen;
12906 if (len < 0)
12907 len = 0;
12908 else if (n + len > slen)
12909 len = slen - n;
12910
12911 rettv->v_type = VAR_STRING;
12912 rettv->vval.v_string = vim_strnsave(p + n, len);
12913}
12914
12915/*
12916 * "strridx()" function
12917 */
12918 static void
12919f_strridx(typval_T *argvars, typval_T *rettv)
12920{
12921 char_u buf[NUMBUFLEN];
12922 char_u *needle;
12923 char_u *haystack;
12924 char_u *rest;
12925 char_u *lastmatch = NULL;
12926 int haystack_len, end_idx;
12927
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012928 needle = tv_get_string_chk(&argvars[1]);
12929 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012930
12931 rettv->vval.v_number = -1;
12932 if (needle == NULL || haystack == NULL)
12933 return; /* type error; errmsg already given */
12934
12935 haystack_len = (int)STRLEN(haystack);
12936 if (argvars[2].v_type != VAR_UNKNOWN)
12937 {
12938 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012939 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012940 if (end_idx < 0)
12941 return; /* can never find a match */
12942 }
12943 else
12944 end_idx = haystack_len;
12945
12946 if (*needle == NUL)
12947 {
12948 /* Empty string matches past the end. */
12949 lastmatch = haystack + end_idx;
12950 }
12951 else
12952 {
12953 for (rest = haystack; *rest != '\0'; ++rest)
12954 {
12955 rest = (char_u *)strstr((char *)rest, (char *)needle);
12956 if (rest == NULL || rest > haystack + end_idx)
12957 break;
12958 lastmatch = rest;
12959 }
12960 }
12961
12962 if (lastmatch == NULL)
12963 rettv->vval.v_number = -1;
12964 else
12965 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12966}
12967
12968/*
12969 * "strtrans()" function
12970 */
12971 static void
12972f_strtrans(typval_T *argvars, typval_T *rettv)
12973{
12974 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012975 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012976}
12977
12978/*
12979 * "submatch()" function
12980 */
12981 static void
12982f_submatch(typval_T *argvars, typval_T *rettv)
12983{
12984 int error = FALSE;
12985 int no;
12986 int retList = 0;
12987
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012988 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012989 if (error)
12990 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012991 if (no < 0 || no >= NSUBEXP)
12992 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012993 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010012994 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012995 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012996 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012997 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012998 if (error)
12999 return;
13000
13001 if (retList == 0)
13002 {
13003 rettv->v_type = VAR_STRING;
13004 rettv->vval.v_string = reg_submatch(no);
13005 }
13006 else
13007 {
13008 rettv->v_type = VAR_LIST;
13009 rettv->vval.v_list = reg_submatch_list(no);
13010 }
13011}
13012
13013/*
13014 * "substitute()" function
13015 */
13016 static void
13017f_substitute(typval_T *argvars, typval_T *rettv)
13018{
13019 char_u patbuf[NUMBUFLEN];
13020 char_u subbuf[NUMBUFLEN];
13021 char_u flagsbuf[NUMBUFLEN];
13022
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013023 char_u *str = tv_get_string_chk(&argvars[0]);
13024 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013025 char_u *sub = NULL;
13026 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013027 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013028
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013029 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13030 expr = &argvars[2];
13031 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013032 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013033
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013034 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013035 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13036 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013037 rettv->vval.v_string = NULL;
13038 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013039 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013040}
13041
13042/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013043 * "swapinfo(swap_filename)" function
13044 */
13045 static void
13046f_swapinfo(typval_T *argvars, typval_T *rettv)
13047{
13048 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013049 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013050}
13051
13052/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013053 * "swapname(expr)" function
13054 */
13055 static void
13056f_swapname(typval_T *argvars, typval_T *rettv)
13057{
13058 buf_T *buf;
13059
13060 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013061 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013062 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13063 || buf->b_ml.ml_mfp->mf_fname == NULL)
13064 rettv->vval.v_string = NULL;
13065 else
13066 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13067}
13068
13069/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013070 * "synID(lnum, col, trans)" function
13071 */
13072 static void
13073f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13074{
13075 int id = 0;
13076#ifdef FEAT_SYN_HL
13077 linenr_T lnum;
13078 colnr_T col;
13079 int trans;
13080 int transerr = FALSE;
13081
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013082 lnum = tv_get_lnum(argvars); /* -1 on type error */
13083 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13084 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013085
13086 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13087 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13088 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13089#endif
13090
13091 rettv->vval.v_number = id;
13092}
13093
13094/*
13095 * "synIDattr(id, what [, mode])" function
13096 */
13097 static void
13098f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13099{
13100 char_u *p = NULL;
13101#ifdef FEAT_SYN_HL
13102 int id;
13103 char_u *what;
13104 char_u *mode;
13105 char_u modebuf[NUMBUFLEN];
13106 int modec;
13107
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013108 id = (int)tv_get_number(&argvars[0]);
13109 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013110 if (argvars[2].v_type != VAR_UNKNOWN)
13111 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013112 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013113 modec = TOLOWER_ASC(mode[0]);
13114 if (modec != 't' && modec != 'c' && modec != 'g')
13115 modec = 0; /* replace invalid with current */
13116 }
13117 else
13118 {
13119#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13120 if (USE_24BIT)
13121 modec = 'g';
13122 else
13123#endif
13124 if (t_colors > 1)
13125 modec = 'c';
13126 else
13127 modec = 't';
13128 }
13129
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013130 switch (TOLOWER_ASC(what[0]))
13131 {
13132 case 'b':
13133 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13134 p = highlight_color(id, what, modec);
13135 else /* bold */
13136 p = highlight_has_attr(id, HL_BOLD, modec);
13137 break;
13138
13139 case 'f': /* fg[#] or font */
13140 p = highlight_color(id, what, modec);
13141 break;
13142
13143 case 'i':
13144 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13145 p = highlight_has_attr(id, HL_INVERSE, modec);
13146 else /* italic */
13147 p = highlight_has_attr(id, HL_ITALIC, modec);
13148 break;
13149
13150 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013151 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013152 break;
13153
13154 case 'r': /* reverse */
13155 p = highlight_has_attr(id, HL_INVERSE, modec);
13156 break;
13157
13158 case 's':
13159 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13160 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013161 /* strikeout */
13162 else if (TOLOWER_ASC(what[1]) == 't' &&
13163 TOLOWER_ASC(what[2]) == 'r')
13164 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013165 else /* standout */
13166 p = highlight_has_attr(id, HL_STANDOUT, modec);
13167 break;
13168
13169 case 'u':
13170 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13171 /* underline */
13172 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13173 else
13174 /* undercurl */
13175 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13176 break;
13177 }
13178
13179 if (p != NULL)
13180 p = vim_strsave(p);
13181#endif
13182 rettv->v_type = VAR_STRING;
13183 rettv->vval.v_string = p;
13184}
13185
13186/*
13187 * "synIDtrans(id)" function
13188 */
13189 static void
13190f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13191{
13192 int id;
13193
13194#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013195 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013196
13197 if (id > 0)
13198 id = syn_get_final_id(id);
13199 else
13200#endif
13201 id = 0;
13202
13203 rettv->vval.v_number = id;
13204}
13205
13206/*
13207 * "synconcealed(lnum, col)" function
13208 */
13209 static void
13210f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13211{
13212#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13213 linenr_T lnum;
13214 colnr_T col;
13215 int syntax_flags = 0;
13216 int cchar;
13217 int matchid = 0;
13218 char_u str[NUMBUFLEN];
13219#endif
13220
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013221 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013222
13223#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013224 lnum = tv_get_lnum(argvars); /* -1 on type error */
13225 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013226
13227 vim_memset(str, NUL, sizeof(str));
13228
13229 if (rettv_list_alloc(rettv) != FAIL)
13230 {
13231 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13232 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13233 && curwin->w_p_cole > 0)
13234 {
13235 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13236 syntax_flags = get_syntax_info(&matchid);
13237
13238 /* get the conceal character */
13239 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13240 {
13241 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013242 if (cchar == NUL && curwin->w_p_cole == 1)
13243 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013244 if (cchar != NUL)
13245 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013246 if (has_mbyte)
13247 (*mb_char2bytes)(cchar, str);
13248 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013249 str[0] = cchar;
13250 }
13251 }
13252 }
13253
13254 list_append_number(rettv->vval.v_list,
13255 (syntax_flags & HL_CONCEAL) != 0);
13256 /* -1 to auto-determine strlen */
13257 list_append_string(rettv->vval.v_list, str, -1);
13258 list_append_number(rettv->vval.v_list, matchid);
13259 }
13260#endif
13261}
13262
13263/*
13264 * "synstack(lnum, col)" function
13265 */
13266 static void
13267f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13268{
13269#ifdef FEAT_SYN_HL
13270 linenr_T lnum;
13271 colnr_T col;
13272 int i;
13273 int id;
13274#endif
13275
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013276 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013277
13278#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013279 lnum = tv_get_lnum(argvars); /* -1 on type error */
13280 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013281
13282 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13283 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13284 && rettv_list_alloc(rettv) != FAIL)
13285 {
13286 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13287 for (i = 0; ; ++i)
13288 {
13289 id = syn_get_stack_item(i);
13290 if (id < 0)
13291 break;
13292 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13293 break;
13294 }
13295 }
13296#endif
13297}
13298
13299 static void
13300get_cmd_output_as_rettv(
13301 typval_T *argvars,
13302 typval_T *rettv,
13303 int retlist)
13304{
13305 char_u *res = NULL;
13306 char_u *p;
13307 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013308 int err = FALSE;
13309 FILE *fd;
13310 list_T *list = NULL;
13311 int flags = SHELL_SILENT;
13312
13313 rettv->v_type = VAR_STRING;
13314 rettv->vval.v_string = NULL;
13315 if (check_restricted() || check_secure())
13316 goto errret;
13317
13318 if (argvars[1].v_type != VAR_UNKNOWN)
13319 {
13320 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013321 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013322 * command.
13323 */
13324 if ((infile = vim_tempname('i', TRUE)) == NULL)
13325 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013326 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013327 goto errret;
13328 }
13329
13330 fd = mch_fopen((char *)infile, WRITEBIN);
13331 if (fd == NULL)
13332 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013333 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013334 goto errret;
13335 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013336 if (argvars[1].v_type == VAR_NUMBER)
13337 {
13338 linenr_T lnum;
13339 buf_T *buf;
13340
13341 buf = buflist_findnr(argvars[1].vval.v_number);
13342 if (buf == NULL)
13343 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013344 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013345 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013346 goto errret;
13347 }
13348
13349 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13350 {
13351 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13352 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13353 {
13354 err = TRUE;
13355 break;
13356 }
13357 if (putc(NL, fd) == EOF)
13358 {
13359 err = TRUE;
13360 break;
13361 }
13362 }
13363 }
13364 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013365 {
13366 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13367 err = TRUE;
13368 }
13369 else
13370 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013371 size_t len;
13372 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013373
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013374 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013375 if (p == NULL)
13376 {
13377 fclose(fd);
13378 goto errret; /* type error; errmsg already given */
13379 }
13380 len = STRLEN(p);
13381 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13382 err = TRUE;
13383 }
13384 if (fclose(fd) != 0)
13385 err = TRUE;
13386 if (err)
13387 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013388 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013389 goto errret;
13390 }
13391 }
13392
13393 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13394 * echoes typeahead, that messes up the display. */
13395 if (!msg_silent)
13396 flags += SHELL_COOKED;
13397
13398 if (retlist)
13399 {
13400 int len;
13401 listitem_T *li;
13402 char_u *s = NULL;
13403 char_u *start;
13404 char_u *end;
13405 int i;
13406
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013407 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013408 if (res == NULL)
13409 goto errret;
13410
13411 list = list_alloc();
13412 if (list == NULL)
13413 goto errret;
13414
13415 for (i = 0; i < len; ++i)
13416 {
13417 start = res + i;
13418 while (i < len && res[i] != NL)
13419 ++i;
13420 end = res + i;
13421
13422 s = alloc((unsigned)(end - start + 1));
13423 if (s == NULL)
13424 goto errret;
13425
13426 for (p = s; start < end; ++p, ++start)
13427 *p = *start == NUL ? NL : *start;
13428 *p = NUL;
13429
13430 li = listitem_alloc();
13431 if (li == NULL)
13432 {
13433 vim_free(s);
13434 goto errret;
13435 }
13436 li->li_tv.v_type = VAR_STRING;
13437 li->li_tv.v_lock = 0;
13438 li->li_tv.vval.v_string = s;
13439 list_append(list, li);
13440 }
13441
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013442 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013443 list = NULL;
13444 }
13445 else
13446 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013447 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013448#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013449 /* translate <CR><NL> into <NL> */
13450 if (res != NULL)
13451 {
13452 char_u *s, *d;
13453
13454 d = res;
13455 for (s = res; *s; ++s)
13456 {
13457 if (s[0] == CAR && s[1] == NL)
13458 ++s;
13459 *d++ = *s;
13460 }
13461 *d = NUL;
13462 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013463#endif
13464 rettv->vval.v_string = res;
13465 res = NULL;
13466 }
13467
13468errret:
13469 if (infile != NULL)
13470 {
13471 mch_remove(infile);
13472 vim_free(infile);
13473 }
13474 if (res != NULL)
13475 vim_free(res);
13476 if (list != NULL)
13477 list_free(list);
13478}
13479
13480/*
13481 * "system()" function
13482 */
13483 static void
13484f_system(typval_T *argvars, typval_T *rettv)
13485{
13486 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13487}
13488
13489/*
13490 * "systemlist()" function
13491 */
13492 static void
13493f_systemlist(typval_T *argvars, typval_T *rettv)
13494{
13495 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13496}
13497
13498/*
13499 * "tabpagebuflist()" function
13500 */
13501 static void
13502f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13503{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013504 tabpage_T *tp;
13505 win_T *wp = NULL;
13506
13507 if (argvars[0].v_type == VAR_UNKNOWN)
13508 wp = firstwin;
13509 else
13510 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013511 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013512 if (tp != NULL)
13513 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13514 }
13515 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13516 {
13517 for (; wp != NULL; wp = wp->w_next)
13518 if (list_append_number(rettv->vval.v_list,
13519 wp->w_buffer->b_fnum) == FAIL)
13520 break;
13521 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013522}
13523
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013524/*
13525 * "tabpagenr()" function
13526 */
13527 static void
13528f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13529{
13530 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013531 char_u *arg;
13532
13533 if (argvars[0].v_type != VAR_UNKNOWN)
13534 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013535 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013536 nr = 0;
13537 if (arg != NULL)
13538 {
13539 if (STRCMP(arg, "$") == 0)
13540 nr = tabpage_index(NULL) - 1;
13541 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013542 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013543 }
13544 }
13545 else
13546 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013547 rettv->vval.v_number = nr;
13548}
13549
13550
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013551/*
13552 * Common code for tabpagewinnr() and winnr().
13553 */
13554 static int
13555get_winnr(tabpage_T *tp, typval_T *argvar)
13556{
13557 win_T *twin;
13558 int nr = 1;
13559 win_T *wp;
13560 char_u *arg;
13561
13562 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13563 if (argvar->v_type != VAR_UNKNOWN)
13564 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013565 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013566 if (arg == NULL)
13567 nr = 0; /* type error; errmsg already given */
13568 else if (STRCMP(arg, "$") == 0)
13569 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13570 else if (STRCMP(arg, "#") == 0)
13571 {
13572 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13573 if (twin == NULL)
13574 nr = 0;
13575 }
13576 else
13577 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013578 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013579 nr = 0;
13580 }
13581 }
13582
13583 if (nr > 0)
13584 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13585 wp != twin; wp = wp->w_next)
13586 {
13587 if (wp == NULL)
13588 {
13589 /* didn't find it in this tabpage */
13590 nr = 0;
13591 break;
13592 }
13593 ++nr;
13594 }
13595 return nr;
13596}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013597
13598/*
13599 * "tabpagewinnr()" function
13600 */
13601 static void
13602f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13603{
13604 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013605 tabpage_T *tp;
13606
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013607 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013608 if (tp == NULL)
13609 nr = 0;
13610 else
13611 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013612 rettv->vval.v_number = nr;
13613}
13614
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013615/*
13616 * "tagfiles()" function
13617 */
13618 static void
13619f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13620{
13621 char_u *fname;
13622 tagname_T tn;
13623 int first;
13624
13625 if (rettv_list_alloc(rettv) == FAIL)
13626 return;
13627 fname = alloc(MAXPATHL);
13628 if (fname == NULL)
13629 return;
13630
13631 for (first = TRUE; ; first = FALSE)
13632 if (get_tagfname(&tn, first, fname) == FAIL
13633 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13634 break;
13635 tagname_free(&tn);
13636 vim_free(fname);
13637}
13638
13639/*
13640 * "taglist()" function
13641 */
13642 static void
13643f_taglist(typval_T *argvars, typval_T *rettv)
13644{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013645 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013646 char_u *tag_pattern;
13647
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013648 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013649
13650 rettv->vval.v_number = FALSE;
13651 if (*tag_pattern == NUL)
13652 return;
13653
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013654 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013655 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013656 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013657 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013658}
13659
13660/*
13661 * "tempname()" function
13662 */
13663 static void
13664f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13665{
13666 static int x = 'A';
13667
13668 rettv->v_type = VAR_STRING;
13669 rettv->vval.v_string = vim_tempname(x, FALSE);
13670
13671 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13672 * names. Skip 'I' and 'O', they are used for shell redirection. */
13673 do
13674 {
13675 if (x == 'Z')
13676 x = '0';
13677 else if (x == '9')
13678 x = 'A';
13679 else
13680 {
13681#ifdef EBCDIC
13682 if (x == 'I')
13683 x = 'J';
13684 else if (x == 'R')
13685 x = 'S';
13686 else
13687#endif
13688 ++x;
13689 }
13690 } while (x == 'I' || x == 'O');
13691}
13692
13693#ifdef FEAT_FLOAT
13694/*
13695 * "tan()" function
13696 */
13697 static void
13698f_tan(typval_T *argvars, typval_T *rettv)
13699{
13700 float_T f = 0.0;
13701
13702 rettv->v_type = VAR_FLOAT;
13703 if (get_float_arg(argvars, &f) == OK)
13704 rettv->vval.v_float = tan(f);
13705 else
13706 rettv->vval.v_float = 0.0;
13707}
13708
13709/*
13710 * "tanh()" function
13711 */
13712 static void
13713f_tanh(typval_T *argvars, typval_T *rettv)
13714{
13715 float_T f = 0.0;
13716
13717 rettv->v_type = VAR_FLOAT;
13718 if (get_float_arg(argvars, &f) == OK)
13719 rettv->vval.v_float = tanh(f);
13720 else
13721 rettv->vval.v_float = 0.0;
13722}
13723#endif
13724
13725/*
13726 * "test_alloc_fail(id, countdown, repeat)" function
13727 */
13728 static void
13729f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13730{
13731 if (argvars[0].v_type != VAR_NUMBER
13732 || argvars[0].vval.v_number <= 0
13733 || argvars[1].v_type != VAR_NUMBER
13734 || argvars[1].vval.v_number < 0
13735 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013736 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013737 else
13738 {
13739 alloc_fail_id = argvars[0].vval.v_number;
13740 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013741 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013742 alloc_fail_countdown = argvars[1].vval.v_number;
13743 alloc_fail_repeat = argvars[2].vval.v_number;
13744 did_outofmem_msg = FALSE;
13745 }
13746}
13747
13748/*
13749 * "test_autochdir()"
13750 */
13751 static void
13752f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13753{
13754#if defined(FEAT_AUTOCHDIR)
13755 test_autochdir = TRUE;
13756#endif
13757}
13758
13759/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013760 * "test_feedinput()"
13761 */
13762 static void
13763f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13764{
13765#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013766 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013767
13768 if (val != NULL)
13769 {
13770 trash_input_buf();
13771 add_to_input_buf_csi(val, (int)STRLEN(val));
13772 }
13773#endif
13774}
13775
13776/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013777 * "test_option_not_set({name})" function
13778 */
13779 static void
13780f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13781{
13782 char_u *name = (char_u *)"";
13783
13784 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013785 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013786 else
13787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013788 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013789 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013790 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013791 }
13792}
13793
13794/*
13795 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013796 */
13797 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013798f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013799{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013800 char_u *name = (char_u *)"";
13801 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013802 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013803
13804 if (argvars[0].v_type != VAR_STRING
13805 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013806 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013807 else
13808 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013809 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013810 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013811
13812 if (STRCMP(name, (char_u *)"redraw") == 0)
13813 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013814 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13815 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013816 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13817 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013818 else if (STRCMP(name, (char_u *)"starting") == 0)
13819 {
13820 if (val)
13821 {
13822 if (save_starting < 0)
13823 save_starting = starting;
13824 starting = 0;
13825 }
13826 else
13827 {
13828 starting = save_starting;
13829 save_starting = -1;
13830 }
13831 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013832 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13833 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013834 else if (STRCMP(name, (char_u *)"ALL") == 0)
13835 {
13836 disable_char_avail_for_testing = FALSE;
13837 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013838 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013839 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013840 if (save_starting >= 0)
13841 {
13842 starting = save_starting;
13843 save_starting = -1;
13844 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013845 }
13846 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013847 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013848 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013849}
13850
13851/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010013852 * "test_refcount({expr})" function
13853 */
13854 static void
13855f_test_refcount(typval_T *argvars, typval_T *rettv)
13856{
13857 int retval = -1;
13858
13859 switch (argvars[0].v_type)
13860 {
13861 case VAR_UNKNOWN:
13862 case VAR_NUMBER:
13863 case VAR_FLOAT:
13864 case VAR_SPECIAL:
13865 case VAR_STRING:
13866 break;
13867 case VAR_JOB:
13868#ifdef FEAT_JOB_CHANNEL
13869 if (argvars[0].vval.v_job != NULL)
13870 retval = argvars[0].vval.v_job->jv_refcount - 1;
13871#endif
13872 break;
13873 case VAR_CHANNEL:
13874#ifdef FEAT_JOB_CHANNEL
13875 if (argvars[0].vval.v_channel != NULL)
13876 retval = argvars[0].vval.v_channel->ch_refcount - 1;
13877#endif
13878 break;
13879 case VAR_FUNC:
13880 if (argvars[0].vval.v_string != NULL)
13881 {
13882 ufunc_T *fp;
13883
13884 fp = find_func(argvars[0].vval.v_string);
13885 if (fp != NULL)
13886 retval = fp->uf_refcount;
13887 }
13888 break;
13889 case VAR_PARTIAL:
13890 if (argvars[0].vval.v_partial != NULL)
13891 retval = argvars[0].vval.v_partial->pt_refcount - 1;
13892 break;
13893 case VAR_BLOB:
13894 if (argvars[0].vval.v_blob != NULL)
13895 retval = argvars[0].vval.v_blob->bv_refcount - 1;
13896 break;
13897 case VAR_LIST:
13898 if (argvars[0].vval.v_list != NULL)
13899 retval = argvars[0].vval.v_list->lv_refcount - 1;
13900 break;
13901 case VAR_DICT:
13902 if (argvars[0].vval.v_dict != NULL)
13903 retval = argvars[0].vval.v_dict->dv_refcount - 1;
13904 break;
13905 }
13906
13907 rettv->v_type = VAR_NUMBER;
13908 rettv->vval.v_number = retval;
13909
13910}
13911
13912/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013913 * "test_garbagecollect_now()" function
13914 */
13915 static void
13916f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13917{
13918 /* This is dangerous, any Lists and Dicts used internally may be freed
13919 * while still in use. */
13920 garbage_collect(TRUE);
13921}
13922
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013923/*
13924 * "test_ignore_error()" function
13925 */
13926 static void
13927f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13928{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013929 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013930}
13931
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010013932 static void
13933f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
13934{
13935 rettv->v_type = VAR_BLOB;
13936 rettv->vval.v_blob = NULL;
13937}
13938
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013939#ifdef FEAT_JOB_CHANNEL
13940 static void
13941f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13942{
13943 rettv->v_type = VAR_CHANNEL;
13944 rettv->vval.v_channel = NULL;
13945}
13946#endif
13947
13948 static void
13949f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13950{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013951 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013952}
13953
13954#ifdef FEAT_JOB_CHANNEL
13955 static void
13956f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13957{
13958 rettv->v_type = VAR_JOB;
13959 rettv->vval.v_job = NULL;
13960}
13961#endif
13962
13963 static void
13964f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13965{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013966 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013967}
13968
13969 static void
13970f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13971{
13972 rettv->v_type = VAR_PARTIAL;
13973 rettv->vval.v_partial = NULL;
13974}
13975
13976 static void
13977f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13978{
13979 rettv->v_type = VAR_STRING;
13980 rettv->vval.v_string = NULL;
13981}
13982
Bram Moolenaarab186732018-09-14 21:27:06 +020013983#ifdef FEAT_GUI
13984 static void
13985f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13986{
13987 char_u *which;
13988 long value;
13989 int dragging;
13990 scrollbar_T *sb = NULL;
13991
13992 if (argvars[0].v_type != VAR_STRING
13993 || (argvars[1].v_type) != VAR_NUMBER
13994 || (argvars[2].v_type) != VAR_NUMBER)
13995 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013996 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020013997 return;
13998 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013999 which = tv_get_string(&argvars[0]);
14000 value = tv_get_number(&argvars[1]);
14001 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014002
14003 if (STRCMP(which, "left") == 0)
14004 sb = &curwin->w_scrollbars[SBAR_LEFT];
14005 else if (STRCMP(which, "right") == 0)
14006 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14007 else if (STRCMP(which, "hor") == 0)
14008 sb = &gui.bottom_sbar;
14009 if (sb == NULL)
14010 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014011 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014012 return;
14013 }
14014 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014015# ifndef USE_ON_FLY_SCROLL
14016 // need to loop through normal_cmd() to handle the scroll events
14017 exec_normal(FALSE, TRUE, FALSE);
14018# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014019}
14020#endif
14021
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014022 static void
14023f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14024{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014025 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014026}
14027
14028#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14029/*
14030 * Get a callback from "arg". It can be a Funcref or a function name.
14031 * When "arg" is zero return an empty string.
14032 * Return NULL for an invalid argument.
14033 */
14034 char_u *
14035get_callback(typval_T *arg, partial_T **pp)
14036{
14037 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14038 {
14039 *pp = arg->vval.v_partial;
14040 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014041 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014042 }
14043 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014044 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014045 {
14046 func_ref(arg->vval.v_string);
14047 return arg->vval.v_string;
14048 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014049 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14050 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014051 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014052 return NULL;
14053}
14054
14055/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014056 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014057 */
14058 void
14059free_callback(char_u *callback, partial_T *partial)
14060{
14061 if (partial != NULL)
14062 partial_unref(partial);
14063 else if (callback != NULL)
14064 {
14065 func_unref(callback);
14066 vim_free(callback);
14067 }
14068}
14069#endif
14070
14071#ifdef FEAT_TIMERS
14072/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014073 * "timer_info([timer])" function
14074 */
14075 static void
14076f_timer_info(typval_T *argvars, typval_T *rettv)
14077{
14078 timer_T *timer = NULL;
14079
14080 if (rettv_list_alloc(rettv) != OK)
14081 return;
14082 if (argvars[0].v_type != VAR_UNKNOWN)
14083 {
14084 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014085 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014086 else
14087 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014088 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014089 if (timer != NULL)
14090 add_timer_info(rettv, timer);
14091 }
14092 }
14093 else
14094 add_timer_info_all(rettv);
14095}
14096
14097/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014098 * "timer_pause(timer, paused)" function
14099 */
14100 static void
14101f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14102{
14103 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014104 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014105
14106 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014107 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014108 else
14109 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014110 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014111 if (timer != NULL)
14112 timer->tr_paused = paused;
14113 }
14114}
14115
14116/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014117 * "timer_start(time, callback [, options])" function
14118 */
14119 static void
14120f_timer_start(typval_T *argvars, typval_T *rettv)
14121{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014122 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014123 timer_T *timer;
14124 int repeat = 0;
14125 char_u *callback;
14126 dict_T *dict;
14127 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014128
Bram Moolenaar75537a92016-09-05 22:45:28 +020014129 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014130 if (check_secure())
14131 return;
14132 if (argvars[2].v_type != VAR_UNKNOWN)
14133 {
14134 if (argvars[2].v_type != VAR_DICT
14135 || (dict = argvars[2].vval.v_dict) == NULL)
14136 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014137 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014138 return;
14139 }
14140 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014141 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014142 }
14143
Bram Moolenaar75537a92016-09-05 22:45:28 +020014144 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014145 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014146 return;
14147
14148 timer = create_timer(msec, repeat);
14149 if (timer == NULL)
14150 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014151 else
14152 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014153 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014154 timer->tr_callback = vim_strsave(callback);
14155 else
14156 /* pointer into the partial */
14157 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014158 timer->tr_partial = partial;
14159 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014160 }
14161}
14162
14163/*
14164 * "timer_stop(timer)" function
14165 */
14166 static void
14167f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14168{
14169 timer_T *timer;
14170
14171 if (argvars[0].v_type != VAR_NUMBER)
14172 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014173 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014174 return;
14175 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014176 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014177 if (timer != NULL)
14178 stop_timer(timer);
14179}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014180
14181/*
14182 * "timer_stopall()" function
14183 */
14184 static void
14185f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14186{
14187 stop_all_timers();
14188}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014189#endif
14190
14191/*
14192 * "tolower(string)" function
14193 */
14194 static void
14195f_tolower(typval_T *argvars, typval_T *rettv)
14196{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014197 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014198 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014199}
14200
14201/*
14202 * "toupper(string)" function
14203 */
14204 static void
14205f_toupper(typval_T *argvars, typval_T *rettv)
14206{
14207 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014208 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014209}
14210
14211/*
14212 * "tr(string, fromstr, tostr)" function
14213 */
14214 static void
14215f_tr(typval_T *argvars, typval_T *rettv)
14216{
14217 char_u *in_str;
14218 char_u *fromstr;
14219 char_u *tostr;
14220 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014221 int inlen;
14222 int fromlen;
14223 int tolen;
14224 int idx;
14225 char_u *cpstr;
14226 int cplen;
14227 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014228 char_u buf[NUMBUFLEN];
14229 char_u buf2[NUMBUFLEN];
14230 garray_T ga;
14231
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014232 in_str = tv_get_string(&argvars[0]);
14233 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14234 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014235
14236 /* Default return value: empty string. */
14237 rettv->v_type = VAR_STRING;
14238 rettv->vval.v_string = NULL;
14239 if (fromstr == NULL || tostr == NULL)
14240 return; /* type error; errmsg already given */
14241 ga_init2(&ga, (int)sizeof(char), 80);
14242
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014243 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014244 /* not multi-byte: fromstr and tostr must be the same length */
14245 if (STRLEN(fromstr) != STRLEN(tostr))
14246 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014247error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014248 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014249 ga_clear(&ga);
14250 return;
14251 }
14252
14253 /* fromstr and tostr have to contain the same number of chars */
14254 while (*in_str != NUL)
14255 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014256 if (has_mbyte)
14257 {
14258 inlen = (*mb_ptr2len)(in_str);
14259 cpstr = in_str;
14260 cplen = inlen;
14261 idx = 0;
14262 for (p = fromstr; *p != NUL; p += fromlen)
14263 {
14264 fromlen = (*mb_ptr2len)(p);
14265 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14266 {
14267 for (p = tostr; *p != NUL; p += tolen)
14268 {
14269 tolen = (*mb_ptr2len)(p);
14270 if (idx-- == 0)
14271 {
14272 cplen = tolen;
14273 cpstr = p;
14274 break;
14275 }
14276 }
14277 if (*p == NUL) /* tostr is shorter than fromstr */
14278 goto error;
14279 break;
14280 }
14281 ++idx;
14282 }
14283
14284 if (first && cpstr == in_str)
14285 {
14286 /* Check that fromstr and tostr have the same number of
14287 * (multi-byte) characters. Done only once when a character
14288 * of in_str doesn't appear in fromstr. */
14289 first = FALSE;
14290 for (p = tostr; *p != NUL; p += tolen)
14291 {
14292 tolen = (*mb_ptr2len)(p);
14293 --idx;
14294 }
14295 if (idx != 0)
14296 goto error;
14297 }
14298
14299 (void)ga_grow(&ga, cplen);
14300 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14301 ga.ga_len += cplen;
14302
14303 in_str += inlen;
14304 }
14305 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014306 {
14307 /* When not using multi-byte chars we can do it faster. */
14308 p = vim_strchr(fromstr, *in_str);
14309 if (p != NULL)
14310 ga_append(&ga, tostr[p - fromstr]);
14311 else
14312 ga_append(&ga, *in_str);
14313 ++in_str;
14314 }
14315 }
14316
14317 /* add a terminating NUL */
14318 (void)ga_grow(&ga, 1);
14319 ga_append(&ga, NUL);
14320
14321 rettv->vval.v_string = ga.ga_data;
14322}
14323
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014324/*
14325 * "trim({expr})" function
14326 */
14327 static void
14328f_trim(typval_T *argvars, typval_T *rettv)
14329{
14330 char_u buf1[NUMBUFLEN];
14331 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014332 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014333 char_u *mask = NULL;
14334 char_u *tail;
14335 char_u *prev;
14336 char_u *p;
14337 int c1;
14338
14339 rettv->v_type = VAR_STRING;
14340 if (head == NULL)
14341 {
14342 rettv->vval.v_string = NULL;
14343 return;
14344 }
14345
14346 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014347 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014348
14349 while (*head != NUL)
14350 {
14351 c1 = PTR2CHAR(head);
14352 if (mask == NULL)
14353 {
14354 if (c1 > ' ' && c1 != 0xa0)
14355 break;
14356 }
14357 else
14358 {
14359 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14360 if (c1 == PTR2CHAR(p))
14361 break;
14362 if (*p == NUL)
14363 break;
14364 }
14365 MB_PTR_ADV(head);
14366 }
14367
14368 for (tail = head + STRLEN(head); tail > head; tail = prev)
14369 {
14370 prev = tail;
14371 MB_PTR_BACK(head, prev);
14372 c1 = PTR2CHAR(prev);
14373 if (mask == NULL)
14374 {
14375 if (c1 > ' ' && c1 != 0xa0)
14376 break;
14377 }
14378 else
14379 {
14380 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14381 if (c1 == PTR2CHAR(p))
14382 break;
14383 if (*p == NUL)
14384 break;
14385 }
14386 }
14387 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14388}
14389
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014390#ifdef FEAT_FLOAT
14391/*
14392 * "trunc({float})" function
14393 */
14394 static void
14395f_trunc(typval_T *argvars, typval_T *rettv)
14396{
14397 float_T f = 0.0;
14398
14399 rettv->v_type = VAR_FLOAT;
14400 if (get_float_arg(argvars, &f) == OK)
14401 /* trunc() is not in C90, use floor() or ceil() instead. */
14402 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14403 else
14404 rettv->vval.v_float = 0.0;
14405}
14406#endif
14407
14408/*
14409 * "type(expr)" function
14410 */
14411 static void
14412f_type(typval_T *argvars, typval_T *rettv)
14413{
14414 int n = -1;
14415
14416 switch (argvars[0].v_type)
14417 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014418 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14419 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014420 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014421 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14422 case VAR_LIST: n = VAR_TYPE_LIST; break;
14423 case VAR_DICT: n = VAR_TYPE_DICT; break;
14424 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014425 case VAR_SPECIAL:
14426 if (argvars[0].vval.v_number == VVAL_FALSE
14427 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014428 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014429 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014430 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014431 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014432 case VAR_JOB: n = VAR_TYPE_JOB; break;
14433 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014434 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014435 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014436 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014437 n = -1;
14438 break;
14439 }
14440 rettv->vval.v_number = n;
14441}
14442
14443/*
14444 * "undofile(name)" function
14445 */
14446 static void
14447f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14448{
14449 rettv->v_type = VAR_STRING;
14450#ifdef FEAT_PERSISTENT_UNDO
14451 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014452 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014453
14454 if (*fname == NUL)
14455 {
14456 /* If there is no file name there will be no undo file. */
14457 rettv->vval.v_string = NULL;
14458 }
14459 else
14460 {
14461 char_u *ffname = FullName_save(fname, FALSE);
14462
14463 if (ffname != NULL)
14464 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14465 vim_free(ffname);
14466 }
14467 }
14468#else
14469 rettv->vval.v_string = NULL;
14470#endif
14471}
14472
14473/*
14474 * "undotree()" function
14475 */
14476 static void
14477f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14478{
14479 if (rettv_dict_alloc(rettv) == OK)
14480 {
14481 dict_T *dict = rettv->vval.v_dict;
14482 list_T *list;
14483
Bram Moolenaare0be1672018-07-08 16:50:37 +020014484 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14485 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14486 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14487 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14488 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14489 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014490
14491 list = list_alloc();
14492 if (list != NULL)
14493 {
14494 u_eval_tree(curbuf->b_u_oldhead, list);
14495 dict_add_list(dict, "entries", list);
14496 }
14497 }
14498}
14499
14500/*
14501 * "values(dict)" function
14502 */
14503 static void
14504f_values(typval_T *argvars, typval_T *rettv)
14505{
14506 dict_list(argvars, rettv, 1);
14507}
14508
14509/*
14510 * "virtcol(string)" function
14511 */
14512 static void
14513f_virtcol(typval_T *argvars, typval_T *rettv)
14514{
14515 colnr_T vcol = 0;
14516 pos_T *fp;
14517 int fnum = curbuf->b_fnum;
14518
14519 fp = var2fpos(&argvars[0], FALSE, &fnum);
14520 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14521 && fnum == curbuf->b_fnum)
14522 {
14523 getvvcol(curwin, fp, NULL, NULL, &vcol);
14524 ++vcol;
14525 }
14526
14527 rettv->vval.v_number = vcol;
14528}
14529
14530/*
14531 * "visualmode()" function
14532 */
14533 static void
14534f_visualmode(typval_T *argvars, typval_T *rettv)
14535{
14536 char_u str[2];
14537
14538 rettv->v_type = VAR_STRING;
14539 str[0] = curbuf->b_visual_mode_eval;
14540 str[1] = NUL;
14541 rettv->vval.v_string = vim_strsave(str);
14542
14543 /* A non-zero number or non-empty string argument: reset mode. */
14544 if (non_zero_arg(&argvars[0]))
14545 curbuf->b_visual_mode_eval = NUL;
14546}
14547
14548/*
14549 * "wildmenumode()" function
14550 */
14551 static void
14552f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14553{
14554#ifdef FEAT_WILDMENU
14555 if (wild_menu_showing)
14556 rettv->vval.v_number = 1;
14557#endif
14558}
14559
14560/*
14561 * "winbufnr(nr)" function
14562 */
14563 static void
14564f_winbufnr(typval_T *argvars, typval_T *rettv)
14565{
14566 win_T *wp;
14567
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014568 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014569 if (wp == NULL)
14570 rettv->vval.v_number = -1;
14571 else
14572 rettv->vval.v_number = wp->w_buffer->b_fnum;
14573}
14574
14575/*
14576 * "wincol()" function
14577 */
14578 static void
14579f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14580{
14581 validate_cursor();
14582 rettv->vval.v_number = curwin->w_wcol + 1;
14583}
14584
14585/*
14586 * "winheight(nr)" function
14587 */
14588 static void
14589f_winheight(typval_T *argvars, typval_T *rettv)
14590{
14591 win_T *wp;
14592
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014593 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014594 if (wp == NULL)
14595 rettv->vval.v_number = -1;
14596 else
14597 rettv->vval.v_number = wp->w_height;
14598}
14599
14600/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014601 * "winlayout()" function
14602 */
14603 static void
14604f_winlayout(typval_T *argvars, typval_T *rettv)
14605{
14606 tabpage_T *tp;
14607
14608 if (rettv_list_alloc(rettv) != OK)
14609 return;
14610
14611 if (argvars[0].v_type == VAR_UNKNOWN)
14612 tp = curtab;
14613 else
14614 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014615 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014616 if (tp == NULL)
14617 return;
14618 }
14619
14620 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14621}
14622
14623/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014624 * "winline()" function
14625 */
14626 static void
14627f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14628{
14629 validate_cursor();
14630 rettv->vval.v_number = curwin->w_wrow + 1;
14631}
14632
14633/*
14634 * "winnr()" function
14635 */
14636 static void
14637f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14638{
14639 int nr = 1;
14640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014641 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014642 rettv->vval.v_number = nr;
14643}
14644
14645/*
14646 * "winrestcmd()" function
14647 */
14648 static void
14649f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14650{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014651 win_T *wp;
14652 int winnr = 1;
14653 garray_T ga;
14654 char_u buf[50];
14655
14656 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014657 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014658 {
14659 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14660 ga_concat(&ga, buf);
14661 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14662 ga_concat(&ga, buf);
14663 ++winnr;
14664 }
14665 ga_append(&ga, NUL);
14666
14667 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014668 rettv->v_type = VAR_STRING;
14669}
14670
14671/*
14672 * "winrestview()" function
14673 */
14674 static void
14675f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14676{
14677 dict_T *dict;
14678
14679 if (argvars[0].v_type != VAR_DICT
14680 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014681 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014682 else
14683 {
14684 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014685 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014686 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014687 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014688 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014689 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014690 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14691 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014692 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014693 curwin->w_set_curswant = FALSE;
14694 }
14695
14696 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014697 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014698#ifdef FEAT_DIFF
14699 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014700 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014701#endif
14702 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014703 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014704 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014705 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014706
14707 check_cursor();
14708 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014709 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014710 changed_window_setting();
14711
14712 if (curwin->w_topline <= 0)
14713 curwin->w_topline = 1;
14714 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14715 curwin->w_topline = curbuf->b_ml.ml_line_count;
14716#ifdef FEAT_DIFF
14717 check_topfill(curwin, TRUE);
14718#endif
14719 }
14720}
14721
14722/*
14723 * "winsaveview()" function
14724 */
14725 static void
14726f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14727{
14728 dict_T *dict;
14729
14730 if (rettv_dict_alloc(rettv) == FAIL)
14731 return;
14732 dict = rettv->vval.v_dict;
14733
Bram Moolenaare0be1672018-07-08 16:50:37 +020014734 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14735 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014736 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014737 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014738 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014739
Bram Moolenaare0be1672018-07-08 16:50:37 +020014740 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014741#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014742 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014743#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014744 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14745 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014746}
14747
14748/*
14749 * "winwidth(nr)" function
14750 */
14751 static void
14752f_winwidth(typval_T *argvars, typval_T *rettv)
14753{
14754 win_T *wp;
14755
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014756 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014757 if (wp == NULL)
14758 rettv->vval.v_number = -1;
14759 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014760 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014761}
14762
14763/*
14764 * "wordcount()" function
14765 */
14766 static void
14767f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14768{
14769 if (rettv_dict_alloc(rettv) == FAIL)
14770 return;
14771 cursor_pos_info(rettv->vval.v_dict);
14772}
14773
14774/*
14775 * "writefile()" function
14776 */
14777 static void
14778f_writefile(typval_T *argvars, typval_T *rettv)
14779{
14780 int binary = FALSE;
14781 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014782#ifdef HAVE_FSYNC
14783 int do_fsync = p_fs;
14784#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014785 char_u *fname;
14786 FILE *fd;
14787 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014788 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014789 list_T *list = NULL;
14790 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014791
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014792 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014793 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014794 return;
14795
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014796 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014797 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014798 list = argvars[0].vval.v_list;
14799 if (list == NULL)
14800 return;
14801 for (li = list->lv_first; li != NULL; li = li->li_next)
14802 if (tv_get_string_chk(&li->li_tv) == NULL)
14803 return;
14804 }
14805 else if (argvars[0].v_type == VAR_BLOB)
14806 {
14807 blob = argvars[0].vval.v_blob;
14808 if (blob == NULL)
14809 return;
14810 }
14811 else
14812 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014813 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014814 return;
14815 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014816
14817 if (argvars[2].v_type != VAR_UNKNOWN)
14818 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014819 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014820
14821 if (arg2 == NULL)
14822 return;
14823 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014824 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014825 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014826 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014827#ifdef HAVE_FSYNC
14828 if (vim_strchr(arg2, 's') != NULL)
14829 do_fsync = TRUE;
14830 else if (vim_strchr(arg2, 'S') != NULL)
14831 do_fsync = FALSE;
14832#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014833 }
14834
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014835 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014836 if (fname == NULL)
14837 return;
14838
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014839 /* Always open the file in binary mode, library functions have a mind of
14840 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014841 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14842 append ? APPENDBIN : WRITEBIN)) == NULL)
14843 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014844 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014845 ret = -1;
14846 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014847 else if (blob)
14848 {
14849 if (write_blob(fd, blob) == FAIL)
14850 ret = -1;
14851#ifdef HAVE_FSYNC
14852 else if (do_fsync)
14853 // Ignore the error, the user wouldn't know what to do about it.
14854 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010014855 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014856#endif
14857 fclose(fd);
14858 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014859 else
14860 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014861 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014862 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014863#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014864 else if (do_fsync)
14865 /* Ignore the error, the user wouldn't know what to do about it.
14866 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010014867 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014868#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014869 fclose(fd);
14870 }
14871
14872 rettv->vval.v_number = ret;
14873}
14874
14875/*
14876 * "xor(expr, expr)" function
14877 */
14878 static void
14879f_xor(typval_T *argvars, typval_T *rettv)
14880{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014881 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14882 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014883}
14884
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014885#endif /* FEAT_EVAL */